add dashboard and navigation menu

This commit is contained in:
2026-05-12 11:23:57 +05:00
parent 7026da9ccd
commit 4d5ff472d2
19 changed files with 613 additions and 49 deletions

View File

@@ -1,6 +1,7 @@
package sh.sar.basedbank
import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.google.android.material.color.DynamicColors
import sh.sar.basedbank.api.mib.MibAccount
@@ -13,5 +14,12 @@ class BasedBankApp : Application() {
override fun onCreate() {
super.onCreate()
DynamicColors.applyToActivitiesIfAvailable(this)
val theme = getSharedPreferences("prefs", MODE_PRIVATE).getString("theme", "system")
AppCompatDelegate.setDefaultNightMode(when (theme) {
"dark" -> AppCompatDelegate.MODE_NIGHT_YES
"light" -> AppCompatDelegate.MODE_NIGHT_NO
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
})
}
}

View File

@@ -0,0 +1,42 @@
package sh.sar.basedbank.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
import sh.sar.basedbank.R
import sh.sar.basedbank.databinding.FragmentAccountsBinding
class AccountsFragment : Fragment() {
private var _binding: FragmentAccountsBinding? = null
private val binding get() = _binding!!
private val viewModel: HomeViewModel by activityViewModels()
private lateinit var adapter: AccountsAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentAccountsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
adapter = AccountsAdapter(emptyList())
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
binding.recyclerView.adapter = adapter
viewModel.accounts.observe(viewLifecycleOwner) { adapter.updateAccounts(it) }
}
override fun onResume() {
super.onResume()
requireActivity().title = getString(R.string.nav_accounts)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -0,0 +1,54 @@
package sh.sar.basedbank.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import sh.sar.basedbank.R
import sh.sar.basedbank.api.mib.MibAccount
import sh.sar.basedbank.databinding.FragmentDashboardBinding
class DashboardFragment : Fragment() {
private var _binding: FragmentDashboardBinding? = null
private val binding get() = _binding!!
private val viewModel: HomeViewModel by activityViewModels()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentDashboardBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.accounts.observe(viewLifecycleOwner) { updateBalances(it) }
val wip = { Toast.makeText(requireContext(), R.string.work_in_progress, Toast.LENGTH_SHORT).show() }
binding.btnTransfer.setOnClickListener { wip() }
binding.btnPayMvQr.setOnClickListener { wip() }
}
override fun onResume() {
super.onResume()
requireActivity().title = getString(R.string.nav_dashboard)
}
private fun updateBalances(accounts: List<MibAccount>) {
val mvrTotal = accounts
.filter { it.currencyName.equals("MVR", ignoreCase = true) }
.sumOf { it.availableBalance.replace(",", "").toDoubleOrNull() ?: 0.0 }
val usdTotal = accounts
.filter { it.currencyName.equals("USD", ignoreCase = true) }
.sumOf { it.availableBalance.replace(",", "").toDoubleOrNull() ?: 0.0 }
binding.tvMvrBalance.text = "MVR %,.2f".format(mvrTotal)
binding.tvUsdBalance.text = "USD %,.2f".format(usdTotal)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -1,23 +1,29 @@
package sh.sar.basedbank.ui.home
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import sh.sar.basedbank.BasedBankApp
import sh.sar.basedbank.R
import sh.sar.basedbank.api.mib.MibLoginFlow
import sh.sar.basedbank.databinding.ActivityHomeBinding
import sh.sar.basedbank.ui.login.LoginActivity
import sh.sar.basedbank.util.AccountCache
import sh.sar.basedbank.util.CredentialStore
class HomeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHomeBinding
private lateinit var adapter: AccountsAdapter
private val viewModel: HomeViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -25,23 +31,50 @@ class HomeActivity : AppCompatActivity() {
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
val toggle = ActionBarDrawerToggle(
this, binding.drawerLayout, binding.toolbar,
R.string.nav_open_drawer, R.string.nav_close_drawer
)
binding.drawerLayout.addDrawerListener(toggle)
toggle.syncState()
binding.navigationView.setNavigationItemSelectedListener { item ->
binding.drawerLayout.closeDrawers()
when (item.itemId) {
R.id.nav_dashboard -> show(DashboardFragment())
R.id.nav_add_account -> startActivity(Intent(this, LoginActivity::class.java))
R.id.nav_accounts -> show(AccountsFragment())
R.id.nav_settings -> show(SettingsFragment())
else -> Toast.makeText(this, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
}
true
}
// Load data
val app = application as BasedBankApp
// If we arrived here from a fresh manual login, accounts are already in memory.
// Otherwise load the last-known cache so the UI is instant.
val initial = if (app.accounts.isNotEmpty()) app.accounts else AccountCache.load(this)
adapter = AccountsAdapter(initial)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
if (app.accounts.isNotEmpty()) {
// Just logged in — persist the fresh data and we're done
// Came from fresh manual login
viewModel.accounts.value = app.accounts
AccountCache.save(this, app.accounts)
} else {
// Came from lock screen — refresh in background
// Came from lock screen — show cache immediately, refresh in background
val cached = AccountCache.load(this)
if (cached.isNotEmpty()) viewModel.accounts.value = cached
val creds = CredentialStore(this).loadMibCredentials()
if (creds != null) autoRefresh(creds)
}
// Show dashboard on first create
if (savedInstanceState == null) {
show(DashboardFragment())
binding.navigationView.setCheckedItem(R.id.nav_dashboard)
}
}
private fun show(fragment: Fragment) {
supportFragmentManager.beginTransaction()
.replace(R.id.contentFrame, fragment)
.commit()
}
private fun autoRefresh(creds: CredentialStore.MibCredentials) {
@@ -55,9 +88,9 @@ class HomeActivity : AppCompatActivity() {
}
(application as BasedBankApp).accounts = accounts
AccountCache.save(this@HomeActivity, accounts)
adapter.updateAccounts(accounts)
viewModel.accounts.postValue(accounts)
} catch (_: Exception) {
// Keep showing cached data silently
// Keep cached data silently
} finally {
binding.refreshIndicator.visibility = View.GONE
}

View File

@@ -0,0 +1,9 @@
package sh.sar.basedbank.ui.home
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import sh.sar.basedbank.api.mib.MibAccount
class HomeViewModel : ViewModel() {
val accounts = MutableLiveData<List<MibAccount>>(emptyList())
}

View File

@@ -0,0 +1,56 @@
package sh.sar.basedbank.ui.home
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatDelegate
import androidx.fragment.app.Fragment
import sh.sar.basedbank.R
import sh.sar.basedbank.databinding.FragmentSettingsBinding
class SettingsFragment : Fragment() {
private var _binding: FragmentSettingsBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentSettingsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
// Set initial selection
val saved = prefs.getString("theme", "system")
val initialId = when (saved) {
"light" -> R.id.btnThemeLight
"dark" -> R.id.btnThemeDark
else -> R.id.btnThemeSystem
}
binding.themeToggle.check(initialId)
binding.themeToggle.addOnButtonCheckedListener { _, checkedId, isChecked ->
if (!isChecked) return@addOnButtonCheckedListener
val (key, mode) = when (checkedId) {
R.id.btnThemeLight -> "light" to AppCompatDelegate.MODE_NIGHT_NO
R.id.btnThemeDark -> "dark" to AppCompatDelegate.MODE_NIGHT_YES
else -> "system" to AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
prefs.edit().putString("theme", key).apply()
AppCompatDelegate.setDefaultNightMode(mode)
}
}
override fun onResume() {
super.onResume()
requireActivity().title = getString(R.string.nav_settings)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -114,8 +114,9 @@ class CredentialsFragment : Fragment() {
CredentialStore(requireContext()).saveMibCredentials(username, passwordHash, otpSeed)
AccountCache.save(requireContext(), accounts)
(requireActivity().application as BasedBankApp).accounts = accounts
startActivity(Intent(requireContext(), HomeActivity::class.java))
requireActivity().finish()
val intent = Intent(requireContext(), HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
} catch (e: Exception) {
Log.e(TAG, "Login failed: ${e.message}", e)
binding.tvError.text = e.message ?: "Login failed"

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="?attr/colorOnSurfaceVariant"
android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16-4H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zm-1,9h-4v4h-2v-4H9V9h4V5h2v4h4v2z"/>
</vector>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="?attr/colorOnSurfaceVariant"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="?attr/colorOnSurfaceVariant"
android:pathData="M3,13h8V3H3v10zm0,8h8v-6H3v6zm10,0h8V11h-8v10zm0-18v6h8V3h-8z"/>
</vector>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="?attr/colorOnSurfaceVariant"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2V7h2v2z"/>
</vector>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="?attr/colorOnSurfaceVariant"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94l-0.36,-2.54c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41l-0.36,2.54c-0.59,0.24 -1.13,0.57 -1.62,0.94l-2.39,-0.96c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87c-0.12,0.21 -0.08,0.47 0.12,0.61l2.03,1.58c-0.05,0.3 -0.09,0.63 -0.09,0.94s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

View File

@@ -1,41 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true"
app:liftOnScrollTargetViewId="@id/recyclerView">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/accounts"
app:titleTextAppearance="?attr/textAppearanceTitleLarge" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/refreshIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:indeterminate="true"
app:trackCornerRadius="0dp" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
<!-- Main content -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="16dp"
android:paddingBottom="16dp"
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
android:background="?attr/colorSurface">
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:titleTextAppearance="?attr/textAppearanceTitleLarge" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/refreshIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone"
app:trackCornerRadius="0dp" />
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="@+id/contentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<!-- Navigation drawer -->
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="16dp"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:clipToPadding="false"
android:background="?attr/colorSurface" />

View File

@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Balance cards row -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.card.MaterialCardView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
app:cardElevation="1dp"
app:cardCornerRadius="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/balance_mvr"
android:textAppearance="?attr/textAppearanceLabelSmall"
android:textColor="?attr/colorOnSurfaceVariant" />
<TextView
android:id="@+id/tvMvrBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="MVR —"
android:textAppearance="?attr/textAppearanceTitleMedium" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
app:cardElevation="1dp"
app:cardCornerRadius="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/balance_usd"
android:textAppearance="?attr/textAppearanceLabelSmall"
android:textColor="?attr/colorOnSurfaceVariant" />
<TextView
android:id="@+id/tvUsdBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="USD —"
android:textAppearance="?attr/textAppearanceTitleMedium" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<!-- Card support WIP -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardElevation="1dp"
app:cardCornerRadius="12dp"
app:strokeWidth="1dp"
app:strokeColor="?attr/colorOutlineVariant">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/card_support_wip"
android:textAppearance="?attr/textAppearanceTitleSmall"
android:textColor="?attr/colorOnSurfaceVariant" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/coming_soon"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorOutline" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Action buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnTransfer"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:text="@string/transfer" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnPayMvQr"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:text="@string/pay_mv_qr" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/theme"
android:textAppearance="?attr/textAppearanceTitleMedium"
android:layout_marginBottom="12dp" />
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/themeToggle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:singleSelection="true"
app:selectionRequired="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnThemeSystem"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/theme_system" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnThemeLight"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/theme_light" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnThemeDark"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/theme_dark" />
</com.google.android.material.button.MaterialButtonToggleGroup>
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group_main" android:checkableBehavior="single">
<item android:id="@+id/nav_dashboard"
android:icon="@drawable/ic_nav_dashboard"
android:title="@string/nav_dashboard" />
<item android:id="@+id/nav_add_account"
android:icon="@drawable/ic_nav_add_account"
android:title="@string/nav_add_account" />
<item android:id="@+id/nav_accounts"
android:icon="@drawable/ic_nav_accounts"
android:title="@string/nav_accounts" />
</group>
<group android:id="@+id/group_finance" android:checkableBehavior="single">
<item android:id="@+id/nav_contacts"
android:icon="@drawable/ic_nav_generic"
android:title="@string/nav_contacts" />
<item android:id="@+id/nav_activities"
android:icon="@drawable/ic_nav_generic"
android:title="@string/nav_activities" />
<item android:id="@+id/nav_transfer_history"
android:icon="@drawable/ic_nav_generic"
android:title="@string/nav_transfer_history" />
<item android:id="@+id/nav_finances"
android:icon="@drawable/ic_nav_generic"
android:title="@string/nav_finances" />
<item android:id="@+id/nav_card_settings"
android:icon="@drawable/ic_nav_generic"
android:title="@string/nav_card_settings" />
</group>
<group android:id="@+id/group_system" android:checkableBehavior="single">
<item android:id="@+id/nav_settings"
android:icon="@drawable/ic_nav_settings"
android:title="@string/nav_settings" />
</group>
</menu>

View File

@@ -60,6 +60,33 @@
<string name="skip_biometrics">ސްކިޕް — PIN/ޕެޓަން ބޭނުން ކުރޭ</string>
<string name="back">ފަހަތަށް</string>
<!-- Navigation -->
<string name="nav_dashboard">ޑޭޝްބޯޑް</string>
<string name="nav_add_account">އެކައުންޓް އިތުރު ކުރޭ</string>
<string name="nav_accounts">އެކައުންޓްތައް</string>
<string name="nav_contacts">ކޮންޓެކްޓްތައް</string>
<string name="nav_activities">ހަރަކާތްތައް</string>
<string name="nav_transfer_history">ޓްރާންސްފަ ތާރީހް</string>
<string name="nav_finances">ފައިނޭންސް</string>
<string name="nav_card_settings">ކާޑް ސެޓިންގ</string>
<string name="nav_settings">ސެޓިންގ</string>
<string name="nav_open_drawer">ނެވިގޭޝަން ހުޅުވާ</string>
<string name="nav_close_drawer">ނެވިގޭޝަން ލައްޕާ</string>
<string name="work_in_progress">ތައްޔާރުވަމުން ދަނީ</string>
<!-- Dashboard -->
<string name="balance_mvr">ޖުމްލަ MVR</string>
<string name="balance_usd">ޖުމްލަ USD</string>
<string name="card_support_wip">ކާޑް ސަޕޯޓް</string>
<string name="transfer">ޓްރާންސްފަ</string>
<string name="pay_mv_qr">PayMV QR</string>
<!-- Settings -->
<string name="theme">ތީމް</string>
<string name="theme_system">ސިސްޓަމް</string>
<string name="theme_light">ލައިޓް</string>
<string name="theme_dark">ޑާކް</string>
<!-- Home -->
<string name="accounts">އެކައުންޓްތައް</string>
<string name="available_balance">ލިބެން ހުރި ބެލެންސް</string>

View File

@@ -59,6 +59,33 @@
<string name="skip_biometrics">Skip — use PIN/Pattern only</string>
<string name="back">Back</string>
<!-- Navigation -->
<string name="nav_dashboard">Dashboard</string>
<string name="nav_add_account">Add Account</string>
<string name="nav_accounts">Accounts</string>
<string name="nav_contacts">Contacts</string>
<string name="nav_activities">Activities</string>
<string name="nav_transfer_history">Transfer History</string>
<string name="nav_finances">Finances</string>
<string name="nav_card_settings">Card Settings</string>
<string name="nav_settings">Settings</string>
<string name="nav_open_drawer">Open navigation</string>
<string name="nav_close_drawer">Close navigation</string>
<string name="work_in_progress">Work in progress</string>
<!-- Dashboard -->
<string name="balance_mvr">MVR Total</string>
<string name="balance_usd">USD Total</string>
<string name="card_support_wip">Card Support</string>
<string name="transfer">Transfer</string>
<string name="pay_mv_qr">PayMV QR</string>
<!-- Settings -->
<string name="theme">Theme</string>
<string name="theme_system">System</string>
<string name="theme_light">Light</string>
<string name="theme_dark">Dark</string>
<!-- Home -->
<string name="accounts">Accounts</string>
<string name="available_balance">Available Balance</string>