From 33651ca107db261acbc8344248f1df93cfb9ca61 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Mon, 18 May 2026 23:12:51 +0500 Subject: [PATCH] redesign the welcome pages --- .../ui/onboarding/OnboardingActivity.kt | 68 ++++-- .../onboarding/OnboardingConfigureFragment.kt | 100 ++++++++ .../ui/onboarding/OnboardingFragment.kt | 18 +- .../ui/onboarding/OnboardingPagerAdapter.kt | 27 ++- .../basedbank/ui/onboarding/PatternView.kt | 8 +- .../ui/onboarding/SecuritySetupFragment.kt | 52 ++--- app/src/main/res/drawable/ic_check_circle.xml | 11 + .../main/res/layout/activity_onboarding.xml | 52 +++-- .../layout/fragment_onboarding_configure.xml | 218 ++++++++++++++++++ .../res/layout/fragment_onboarding_slide.xml | 67 +++--- .../res/layout/fragment_security_setup.xml | 75 +++--- app/src/main/res/values-b+dv/strings.xml | 2 + app/src/main/res/values/strings.xml | 9 +- 13 files changed, 522 insertions(+), 185 deletions(-) create mode 100644 app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingConfigureFragment.kt create mode 100644 app/src/main/res/drawable/ic_check_circle.xml create mode 100644 app/src/main/res/layout/fragment_onboarding_configure.xml diff --git a/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingActivity.kt b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingActivity.kt index 440992f..14eb460 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingActivity.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingActivity.kt @@ -3,6 +3,7 @@ package sh.sar.basedbank.ui.onboarding import android.content.Intent import android.content.SharedPreferences import android.os.Bundle +import android.os.CountDownTimer import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate @@ -17,6 +18,7 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback { private lateinit var binding: ActivityOnboardingBinding private lateinit var prefs: SharedPreferences + private var countDownTimer: CountDownTimer? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -29,34 +31,31 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback { TabLayoutMediator(binding.dotsIndicator, binding.viewPager) { _, _ -> }.attach() - // Pre-select language chip without triggering the listener + // Pre-select language button without triggering the listener val savedLang = prefs.getString("language", null) - binding.languageChipGroup.setOnCheckedStateChangeListener(null) + binding.languageToggle.clearOnButtonCheckedListeners() when (savedLang) { - "en" -> binding.chipEnglish.isChecked = true - "dv" -> binding.chipDhivehi.isChecked = true + "en" -> binding.btnLangEnglish.isChecked = true + "dv" -> binding.btnLangDhivehi.isChecked = true } - binding.languageChipGroup.setOnCheckedStateChangeListener { _, checkedIds -> - if (checkedIds.isNotEmpty()) { - selectLanguage(if (checkedIds[0] == R.id.chipEnglish) "en" else "dv") - } + binding.languageToggle.addOnButtonCheckedListener { _, checkedId, isChecked -> + if (isChecked) selectLanguage(if (checkedId == R.id.btnLangEnglish) "en" else "dv") } binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { - binding.languageChipGroup.visibility = if (position == 0) View.VISIBLE else View.GONE - // Block forward swipe on slide 1 until security is set up - if (position == 1) { - binding.viewPager.isUserInputEnabled = - prefs.getString("security_method", null) != null - } else { - binding.viewPager.isUserInputEnabled = true + binding.languageSection.visibility = if (position == 0) View.VISIBLE else View.GONE + binding.viewPager.isUserInputEnabled = when { + position > 2 -> false + position == 1 -> prefs.getString("security_method", null) != null + else -> true } updateButtons(position, adapter.itemCount) + if (position == adapter.itemCount - 1) startGetStartedCountdown() } }) - binding.languageChipGroup.visibility = View.VISIBLE + binding.languageSection.visibility = View.VISIBLE updateButtons(0, adapter.itemCount) binding.btnNext.setOnClickListener { @@ -71,10 +70,21 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback { } } + override fun onDestroy() { + super.onDestroy() + countDownTimer?.cancel() + } + // Called by SecuritySetupFragment when setup is complete override fun onSecuritySetupComplete() { binding.viewPager.isUserInputEnabled = true - updateButtons(binding.viewPager.currentItem, binding.viewPager.adapter?.itemCount ?: 3) + updateButtons(binding.viewPager.currentItem, binding.viewPager.adapter?.itemCount ?: 4) + } + + // Called by SecuritySetupFragment when user resets to reconfigure + override fun onSecuritySetupReset() { + binding.viewPager.isUserInputEnabled = false + updateButtons(binding.viewPager.currentItem, binding.viewPager.adapter?.itemCount ?: 4) } private fun selectLanguage(lang: String) { @@ -83,6 +93,21 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback { updateButtons(binding.viewPager.currentItem, binding.viewPager.adapter?.itemCount ?: 3) } + private fun startGetStartedCountdown() { + binding.btnGetStarted.isEnabled = false + countDownTimer?.cancel() + countDownTimer = object : CountDownTimer(5000, 1000) { + override fun onTick(millisUntilFinished: Long) { + val seconds = (millisUntilFinished / 1000 + 1).toInt() + binding.btnGetStarted.text = "${getString(R.string.get_started)} ($seconds)" + } + override fun onFinish() { + binding.btnGetStarted.text = getString(R.string.get_started) + binding.btnGetStarted.isEnabled = true + } + }.start() + } + private fun updateButtons(position: Int, count: Int) { val langSelected = prefs.getString("language", null) != null val securityDone = prefs.getString("security_method", null) != null @@ -90,16 +115,11 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback { binding.btnGetStarted.visibility = if (isLast) View.VISIBLE else View.GONE - // Hide Next on slide 1 until security is done (avoids a disabled-button-with-no-explanation) - binding.btnNext.visibility = when { - isLast -> View.GONE - position == 1 && !securityDone -> View.GONE - else -> View.VISIBLE - } + binding.btnNext.visibility = if (isLast) View.GONE else View.VISIBLE binding.btnNext.isEnabled = when (position) { 0 -> langSelected 1 -> securityDone - else -> true + else -> true // position 2 (configure) has no gate } } } diff --git a/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingConfigureFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingConfigureFragment.kt new file mode 100644 index 0000000..4466e2a --- /dev/null +++ b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingConfigureFragment.kt @@ -0,0 +1,100 @@ +package sh.sar.basedbank.ui.onboarding + +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.biometric.BiometricManager +import androidx.fragment.app.Fragment +import sh.sar.basedbank.R +import sh.sar.basedbank.databinding.FragmentOnboardingConfigureBinding + +class OnboardingConfigureFragment : Fragment() { + + private var _binding: FragmentOnboardingConfigureBinding? = null + private val binding get() = _binding!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = FragmentOnboardingConfigureBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) + + // Navigation — default Drawer + val isBottom = prefs.getBoolean("bottom_nav", false) + binding.navModeToggle.check(if (isBottom) R.id.btnNavBottom else R.id.btnNavDrawer) + binding.navModeToggle.addOnButtonCheckedListener { _, checkedId, isChecked -> + if (!isChecked) return@addOnButtonCheckedListener + prefs.edit().putBoolean("bottom_nav", checkedId == R.id.btnNavBottom).apply() + } + + // Theme — default System + val savedTheme = prefs.getString("theme", "system") + binding.themeToggle.check(when (savedTheme) { + "light" -> R.id.btnThemeLight + "dark" -> R.id.btnThemeDark + else -> R.id.btnThemeSystem + }) + 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) + } + + // Biometrics + val canUseBiometrics = BiometricManager.from(requireContext()) + .canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_SUCCESS + if (canUseBiometrics) { + val unlockEnabled = prefs.getBoolean("biometrics_enabled", false) + binding.switchBiometrics.isChecked = unlockEnabled + binding.switchBiometricsTransfer.isChecked = prefs.getBoolean("biometrics_transfer_confirm", false) + binding.switchBiometricsTransfer.isEnabled = unlockEnabled + + binding.switchBiometrics.setOnCheckedChangeListener { _, isChecked -> + prefs.edit().putBoolean("biometrics_enabled", isChecked).apply() + binding.switchBiometricsTransfer.isEnabled = isChecked + if (!isChecked) { + binding.switchBiometricsTransfer.isChecked = false + prefs.edit().putBoolean("biometrics_transfer_confirm", false).apply() + } + } + + binding.switchBiometricsTransfer.setOnCheckedChangeListener { _, isChecked -> + prefs.edit().putBoolean("biometrics_transfer_confirm", isChecked).apply() + } + } else { + binding.tvBiometricsHint.visibility = View.VISIBLE + binding.switchBiometrics.isEnabled = false + binding.switchBiometricsTransfer.isEnabled = false + } + + // Block screenshots — default on + val blockScreenshots = prefs.getBoolean("block_screenshots", true) + binding.switchBlockScreenshots.isChecked = blockScreenshots + applyFlagSecure(blockScreenshots) + binding.switchBlockScreenshots.setOnCheckedChangeListener { _, isChecked -> + prefs.edit().putBoolean("block_screenshots", isChecked).apply() + applyFlagSecure(isChecked) + } + } + + private fun applyFlagSecure(enabled: Boolean) { + val win = activity?.window ?: return + if (enabled) win.addFlags(android.view.WindowManager.LayoutParams.FLAG_SECURE) + else win.clearFlags(android.view.WindowManager.LayoutParams.FLAG_SECURE) + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingFragment.kt index bb038e2..d146418 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingFragment.kt @@ -19,14 +19,16 @@ class OnboardingFragment : Fragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val title = requireArguments().getString(ARG_TITLE, "") - val desc = requireArguments().getString(ARG_DESC, "") + val titleRes = requireArguments().getInt(ARG_TITLE) + val descRes = requireArguments().getInt(ARG_DESC) val icon = requireArguments().getInt(ARG_ICON, 0) val isFirst = requireArguments().getBoolean(ARG_IS_FIRST, false) + val isLast = requireArguments().getBoolean(ARG_IS_LAST, false) binding.icon.setImageResource(icon) - binding.title.text = title - binding.description.text = desc + binding.title.text = getString(titleRes) + binding.description.text = getString(descRes) + binding.description.gravity = if (isLast) android.view.Gravity.START else android.view.Gravity.CENTER // On the first slide, show the two placeholder cards for upcoming banks binding.placeholderCards.visibility = if (isFirst) View.VISIBLE else View.GONE @@ -42,13 +44,15 @@ class OnboardingFragment : Fragment() { private const val ARG_DESC = "desc" private const val ARG_ICON = "icon" private const val ARG_IS_FIRST = "is_first" + private const val ARG_IS_LAST = "is_last" fun newInstance(slide: OnboardingSlide) = OnboardingFragment().apply { arguments = bundleOf( - ARG_TITLE to slide.title, - ARG_DESC to slide.description, + ARG_TITLE to slide.titleRes, + ARG_DESC to slide.descRes, ARG_ICON to slide.iconRes, - ARG_IS_FIRST to slide.isFirst + ARG_IS_FIRST to slide.isFirst, + ARG_IS_LAST to slide.isLast ) } } diff --git a/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingPagerAdapter.kt b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingPagerAdapter.kt index 1a81217..9a4d199 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingPagerAdapter.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/onboarding/OnboardingPagerAdapter.kt @@ -9,36 +9,39 @@ class OnboardingPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter( private val slides = listOf( OnboardingSlide( - title = activity.getString(R.string.onboarding_title_1), - description = activity.getString(R.string.onboarding_desc_1), + titleRes = R.string.onboarding_title_1, + descRes = R.string.onboarding_desc_1, iconRes = R.drawable.ic_launcher_foreground, isFirst = true ), OnboardingSlide( - title = activity.getString(R.string.onboarding_title_2), - description = activity.getString(R.string.onboarding_desc_2), + titleRes = R.string.onboarding_title_2, + descRes = R.string.onboarding_desc_2, iconRes = R.drawable.ic_launcher_foreground, isFirst = false ), OnboardingSlide( - title = activity.getString(R.string.onboarding_title_3), - description = activity.getString(R.string.onboarding_desc_3), + titleRes = R.string.onboarding_title_3, + descRes = R.string.onboarding_desc_3, iconRes = R.drawable.ic_launcher_foreground, - isFirst = false + isFirst = false, + isLast = true ) ) - override fun getItemCount() = slides.size + override fun getItemCount() = slides.size + 1 // +1 for OnboardingConfigureFragment at position 2 override fun createFragment(position: Int): Fragment = when (position) { 1 -> SecuritySetupFragment() - else -> OnboardingFragment.newInstance(slides[position]) + 2 -> OnboardingConfigureFragment() + else -> OnboardingFragment.newInstance(slides[position - if (position > 2) 1 else 0]) } } data class OnboardingSlide( - val title: String, - val description: String, + val titleRes: Int, + val descRes: Int, val iconRes: Int, - val isFirst: Boolean + val isFirst: Boolean, + val isLast: Boolean = false ) diff --git a/app/src/main/java/sh/sar/basedbank/ui/onboarding/PatternView.kt b/app/src/main/java/sh/sar/basedbank/ui/onboarding/PatternView.kt index dd887f1..ab9c6d0 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/onboarding/PatternView.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/onboarding/PatternView.kt @@ -86,17 +86,21 @@ class PatternView @JvmOverloads constructor( if (errorState) return false when (event.action) { MotionEvent.ACTION_DOWN -> { + parent?.requestDisallowInterceptTouchEvent(true) recording = true; selected.clear() hit(event.x, event.y) } MotionEvent.ACTION_MOVE -> { + parent?.requestDisallowInterceptTouchEvent(true) touchX = event.x; touchY = event.y hit(event.x, event.y) } - MotionEvent.ACTION_UP -> { + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + parent?.requestDisallowInterceptTouchEvent(false) recording = false invalidate() - onPatternComplete?.invoke(selected.map { it.index }) + if (event.action == MotionEvent.ACTION_UP) + onPatternComplete?.invoke(selected.map { it.index }) } } invalidate() diff --git a/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt index aeebe70..6bee1c2 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/onboarding/SecuritySetupFragment.kt @@ -7,7 +7,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.LinearLayout -import androidx.biometric.BiometricManager import androidx.fragment.app.Fragment import com.google.android.material.button.MaterialButton import sh.sar.basedbank.R @@ -21,6 +20,7 @@ class SecuritySetupFragment : Fragment() { interface Callback { fun onSecuritySetupComplete() + fun onSecuritySetupReset() } companion object { @@ -33,7 +33,7 @@ class SecuritySetupFragment : Fragment() { private var _b: FragmentSecuritySetupBinding? = null private val b get() = _b!! - private enum class Step { CHOOSE, PIN_ENTER, PIN_CONFIRM, PATTERN_ENTER, PATTERN_CONFIRM, BIOMETRIC } + private enum class Step { CONFIGURED, CHOOSE, PIN_ENTER, PIN_CONFIRM, PATTERN_ENTER, PATTERN_CONFIRM } private var step = Step.CHOOSE private val pinDigits = mutableListOf() @@ -48,9 +48,6 @@ class SecuritySetupFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) val changeMode = arguments?.getBoolean(ARG_CHANGE_MODE, false) ?: false - if (!changeMode && prefs.getString("security_method", null) != null) { - (activity as? Callback)?.onSecuritySetupComplete() - } b.cardPin.setOnClickListener { goTo(Step.PIN_ENTER) } b.cardPattern.setOnClickListener { goTo(Step.PATTERN_ENTER) } @@ -62,20 +59,21 @@ class SecuritySetupFragment : Fragment() { } } b.btnPatternBack.setOnClickListener { goTo(Step.CHOOSE) } + b.btnChangeLock.setOnClickListener { + prefs.edit().remove("security_method").apply() + (activity as? Callback)?.onSecuritySetupReset() + goTo(Step.CHOOSE) + } b.patternView.onPatternComplete = { pattern -> handlePattern(pattern) } - b.btnEnableBiometrics.setOnClickListener { - prefs.edit().putBoolean("biometrics_enabled", true).apply() - finishSetup() - } - b.btnSkipBiometrics.setOnClickListener { - prefs.edit().putBoolean("biometrics_enabled", false).apply() - finishSetup() - } - buildNumpad() - goTo(Step.CHOOSE) + + if (!changeMode && prefs.getString("security_method", null) != null) { + goTo(Step.CONFIGURED) + } else { + goTo(Step.CHOOSE) + } } private fun buildNumpad() { @@ -144,7 +142,7 @@ class SecuritySetupFragment : Fragment() { Step.PIN_CONFIRM -> { if (entered == firstPin) { saveCredential("pin", entered) - goToBiometricOrFinish() + finishSetup() } else { b.tvPinDots.text = getString(R.string.pin_no_match) pinDigits.clear() @@ -172,7 +170,7 @@ class SecuritySetupFragment : Fragment() { Step.PATTERN_CONFIRM -> { if (pattern == firstPattern) { saveCredential("pattern", pattern.joinToString("")) - goToBiometricOrFinish() + finishSetup() } else { b.patternView.showError() b.tvPatternStatus.text = getString(R.string.pattern_no_match) @@ -187,29 +185,12 @@ class SecuritySetupFragment : Fragment() { } } - private fun goToBiometricOrFinish() { - // In change mode, biometrics is managed from Settings — skip this step - if (arguments?.getBoolean(ARG_CHANGE_MODE, false) == true) { - finishSetup() - return - } - val canAuth = BiometricManager.from(requireContext()) - .canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) - if (canAuth == BiometricManager.BIOMETRIC_SUCCESS) { - goTo(Step.BIOMETRIC) - } else { - requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) - .edit().putBoolean("biometrics_enabled", false).apply() - finishSetup() - } - } - private fun goTo(s: Step) { step = s + b.viewConfigured.visibility = if (s == Step.CONFIGURED) View.VISIBLE else View.GONE b.viewChooseMethod.visibility = if (s == Step.CHOOSE) View.VISIBLE else View.GONE b.viewPinSetup.visibility = if (s == Step.PIN_ENTER || s == Step.PIN_CONFIRM) View.VISIBLE else View.GONE b.viewPatternSetup.visibility = if (s == Step.PATTERN_ENTER || s == Step.PATTERN_CONFIRM) View.VISIBLE else View.GONE - b.viewBiometric.visibility = if (s == Step.BIOMETRIC) View.VISIBLE else View.GONE when (s) { Step.PIN_ENTER -> { @@ -256,6 +237,7 @@ class SecuritySetupFragment : Fragment() { private fun finishSetup() { val cb = activity as? Callback if (cb != null) { + goTo(Step.CONFIGURED) cb.onSecuritySetupComplete() } else { parentFragmentManager.popBackStack() diff --git a/app/src/main/res/drawable/ic_check_circle.xml b/app/src/main/res/drawable/ic_check_circle.xml new file mode 100644 index 0000000..0df1754 --- /dev/null +++ b/app/src/main/res/drawable/ic_check_circle.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/layout/activity_onboarding.xml b/app/src/main/res/layout/activity_onboarding.xml index 071e8f4..ba8178f 100644 --- a/app/src/main/res/layout/activity_onboarding.xml +++ b/app/src/main/res/layout/activity_onboarding.xml @@ -27,31 +27,49 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"> - + android:visibility="gone"> - + android:layout_gravity="center_horizontal" + android:text="@string/select_language" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:textColor="?attr/colorOnSurface" + android:layout_marginBottom="8dp" /> - + app:singleSelection="true" + app:selectionRequired="true"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_onboarding_slide.xml b/app/src/main/res/layout/fragment_onboarding_slide.xml index 8004294..2405f08 100644 --- a/app/src/main/res/layout/fragment_onboarding_slide.xml +++ b/app/src/main/res/layout/fragment_onboarding_slide.xml @@ -40,53 +40,46 @@ android:gravity="center" android:lineSpacingMultiplier="1.4" /> - + - + - + - + - - - - - + diff --git a/app/src/main/res/layout/fragment_security_setup.xml b/app/src/main/res/layout/fragment_security_setup.xml index bef4fa1..1bc524f 100644 --- a/app/src/main/res/layout/fragment_security_setup.xml +++ b/app/src/main/res/layout/fragment_security_setup.xml @@ -19,11 +19,12 @@ android:paddingBottom="24dp" android:gravity="center_horizontal"> - - + + + + - - + android:layout_marginBottom="8dp" /> - - - - + android:layout_marginBottom="32dp" /> - - + android:text="@string/settings_change_lock" /> diff --git a/app/src/main/res/values-b+dv/strings.xml b/app/src/main/res/values-b+dv/strings.xml index e4e6485..5bb8e6d 100644 --- a/app/src/main/res/values-b+dv/strings.xml +++ b/app/src/main/res/values-b+dv/strings.xml @@ -3,6 +3,8 @@ BasedBank + ހިދުމަތްތައް + ބަސް ހިޔާލު ކުރޭ ތިޔަ ބޭންކްތައް، އެއް އެޕެއްގައި BasedBank ގެ ސަބަބުން ތިޔަ ދިވެހި ބޭންކު އެކައުންޓްތައް، ހަމައެއް ތަނަކުން ބެލޭ. ބެލެންސް ބެލޭ، ތަފާތު ތަންތަން ބެލޭ — ތަފާތު އެޕްތަކަށް ބަދަލު ނުވެ. އިތުރު ބޭންކްތައް ހިމެނެނީ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 78a92a9..7234cb2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,12 +2,14 @@ BasedBank + Supported services + Select Language Your Banks, One App BasedBank brings all your Maldivian bank accounts together in one place. Check balances, view accounts, and more — without switching between apps. More Banks Coming Support for additional banks is on the way. Stay tuned as we expand coverage across the Maldives. - Get Started - Add your bank credentials and start viewing your accounts. Your data stays on your device. + Before You Begin + BasedBank is an independent, third-party app. It is not affiliated with, endorsed by, or officially supported by any bank or financial institution.\n\nThis app works by logging into your internet banking services directly using your credentials and communicating with bank APIs. It is built using techniques derived from reverse-engineered official bank apps. Behaviour may change or break without notice if banks update their systems.\n\nDhiraagu and Ooredoo APIs are used for phone number and package lookups.\n\nBy tapping Get Started, you acknowledge and accept that:\n\n• Errors, failures, or service interruptions may occur at any time\n• Your bank may detect third-party access and apply restrictions or take other actions against your account\n• The developer of this app is not liable for any loss, damage, or consequences arising from your use of this app\n• You use this app entirely at your own risk Coming Soon Next Get Started @@ -49,6 +51,9 @@ Secure Your App Choose how you want to lock BasedBank when you\'re away. + App Lock Configured + Your app lock is set up. + PIN Code 4–8 digit numeric PIN Draw Pattern