countdown now starts after scoll
All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 3s

This commit is contained in:
2026-05-18 23:30:21 +05:00
parent 33651ca107
commit 2dd84ec50a
6 changed files with 111 additions and 66 deletions

View File

@@ -42,6 +42,10 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback {
if (isChecked) selectLanguage(if (checkedId == R.id.btnLangEnglish) "en" else "dv")
}
supportFragmentManager.setFragmentResultListener(OnboardingFragment.RESULT_SCROLLED_TO_BOTTOM, this) { _, _ ->
startGetStartedCountdown()
}
binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
binding.languageSection.visibility = if (position == 0) View.VISIBLE else View.GONE
@@ -51,7 +55,6 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback {
else -> true
}
updateButtons(position, adapter.itemCount)
if (position == adapter.itemCount - 1) startGetStartedCountdown()
}
})
@@ -114,6 +117,7 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback {
val isLast = position == count - 1
binding.btnGetStarted.visibility = if (isLast) View.VISIBLE else View.GONE
if (isLast) binding.btnGetStarted.isEnabled = false
binding.btnNext.visibility = if (isLast) View.GONE else View.VISIBLE
binding.btnNext.isEnabled = when (position) {

View File

@@ -4,6 +4,8 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.ScrollView
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import sh.sar.basedbank.databinding.FragmentOnboardingSlideBinding
@@ -12,6 +14,7 @@ class OnboardingFragment : Fragment() {
private var _binding: FragmentOnboardingSlideBinding? = null
private val binding get() = _binding!!
private var scrolledToBottom = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentOnboardingSlideBinding.inflate(inflater, container, false)
@@ -25,6 +28,7 @@ class OnboardingFragment : Fragment() {
val isFirst = requireArguments().getBoolean(ARG_IS_FIRST, false)
val isLast = requireArguments().getBoolean(ARG_IS_LAST, false)
binding.icon.visibility = if (isLast) View.GONE else View.VISIBLE
binding.icon.setImageResource(icon)
binding.title.text = getString(titleRes)
binding.description.text = getString(descRes)
@@ -32,6 +36,31 @@ class OnboardingFragment : Fragment() {
// On the first slide, show the two placeholder cards for upcoming banks
binding.placeholderCards.visibility = if (isFirst) View.VISIBLE else View.GONE
if (isLast) setupScrollToBottomDetection()
}
private fun setupScrollToBottomDetection() {
val scrollView = binding.scrollView
// If content fits without scrolling, fire immediately after layout
scrollView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
scrollView.viewTreeObserver.removeOnGlobalLayoutListener(this)
val child = scrollView.getChildAt(0) ?: return
if (child.height <= scrollView.height) notifyScrolledToBottom()
}
})
scrollView.setOnScrollChangeListener { v, _, scrollY, _, _ ->
val sv = v as ScrollView
val child = sv.getChildAt(0) ?: return@setOnScrollChangeListener
if (scrollY + sv.height >= child.height) notifyScrolledToBottom()
}
}
private fun notifyScrolledToBottom() {
if (scrolledToBottom) return
scrolledToBottom = true
parentFragmentManager.setFragmentResult(RESULT_SCROLLED_TO_BOTTOM, Bundle.EMPTY)
}
override fun onDestroyView() {
@@ -40,6 +69,7 @@ class OnboardingFragment : Fragment() {
}
companion object {
const val RESULT_SCROLLED_TO_BOTTOM = "scroll_to_bottom"
private const val ARG_TITLE = "title"
private const val ARG_DESC = "desc"
private const val ARG_ICON = "icon"

View File

@@ -79,6 +79,8 @@
android:background="@null"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="24dp"
android:clickable="false"
android:focusable="false"
app:tabBackground="@drawable/tab_indicator_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"

View File

@@ -1,87 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
<LinearLayout
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:fillViewport="true">
android:orientation="vertical"
android:gravity="center_horizontal"
android:paddingHorizontal="32dp"
android:paddingTop="64dp"
android:paddingBottom="16dp">
<LinearLayout
<ImageView
android:id="@+id/icon"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginBottom="40dp"
android:contentDescription="@string/app_name" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:paddingHorizontal="32dp"
android:paddingTop="64dp"
android:paddingBottom="16dp">
android:textAppearance="?attr/textAppearanceHeadlineMedium"
android:textColor="?attr/colorOnSurface"
android:gravity="center"
android:layout_marginBottom="16dp" />
<ImageView
android:id="@+id/icon"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginBottom="40dp"
android:contentDescription="@string/app_name" />
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadlineMedium"
android:textColor="?attr/colorOnSurface"
android:gravity="center"
android:layout_marginBottom="16dp" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodyLarge"
android:textColor="?attr/colorOnSurfaceVariant"
android:gravity="center"
android:lineSpacingMultiplier="1.4" />
<!-- Supported services shown only on first slide -->
<LinearLayout
android:id="@+id/placeholderCards"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="40dp"
android:visibility="gone">
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/onboarding_supported_services"
android:textAppearance="?attr/textAppearanceLabelMedium"
android:textAppearance="?attr/textAppearanceBodyLarge"
android:textColor="?attr/colorOnSurfaceVariant"
android:layout_marginBottom="16dp" />
android:gravity="center"
android:lineSpacingMultiplier="1.4" />
<ImageView
<!-- Supported services shown only on first slide -->
<LinearLayout
android:id="@+id/placeholderCards"
android:layout_width="match_parent"
android:layout_height="40dp"
android:src="@drawable/mib_faisanet_logo"
android:scaleType="centerInside"
android:contentDescription="@string/mib_name" />
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="40dp"
android:visibility="gone">
<ImageView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:src="@drawable/bml_logo_vector"
android:scaleType="centerInside"
android:contentDescription="@string/bml_name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/onboarding_supported_services"
android:textAppearance="?attr/textAppearanceLabelMedium"
android:textColor="?attr/colorOnSurfaceVariant"
android:layout_marginBottom="16dp" />
<ImageView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:src="@drawable/fahipay_logo_long"
android:scaleType="centerInside"
android:contentDescription="@string/fahipay_name" />
<ImageView
android:layout_width="match_parent"
android:layout_height="40dp"
android:src="@drawable/mib_faisanet_logo"
android:scaleType="centerInside"
android:contentDescription="@string/mib_name" />
<ImageView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:src="@drawable/bml_logo_vector"
android:scaleType="centerInside"
android:contentDescription="@string/bml_name" />
<ImageView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:src="@drawable/fahipay_logo_long"
android:scaleType="centerInside"
android:contentDescription="@string/fahipay_name" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -10,7 +10,7 @@
<string name="onboarding_title_2">އިތުރު ބޭންކްތައް ހިމެނެނީ</string>
<string name="onboarding_desc_2">އިތުރު ބޭންކްތަކަށް ސަޕޯޓް ލިބޭ ގޮތަށް ތައްޔާރުވަމުން ދަނީ. ދިވެހިރާއްޖޭގެ ބޭންކްތަކަށް ސަޕޯޓް ފަހި ވަމުން ދިޔަ ވަރަކަށް ހިމަނެމުން ދޭ.</string>
<string name="onboarding_title_3">ފެށޭ ގޮތަށް ތައްޔާރު</string>
<string name="onboarding_desc_3">ތިޔަ ބޭންކު ކްރެޑެންޝަލް ޖެހި، ތިޔަ އެކައުންޓްތައް ބަލާ. ތިޔަ ޑޭޓާ ހިފެހެއްޓޭ ތަނަކީ ހަމައެކަނި ތިޔަ ފޯނު.</string>
<string name="onboarding_desc_3">ތިޔަ ބޭންކު ކްރެޑެންޝަލް ޖެހި، ތިޔަ އެކައުންޓްތައް ބަލާ. ތިޔަ ޑޭޓާ ހިފެހެއްޓޭ ތަނަކީ ހަމައެކަނި ތިޔަ ފޯނު.\n\nDhiraagu އާއި Ooredoo ގެ API ބޭނުންކޮށްގެން ފޯން ނަންބަރުގެ ތަފްސީލު ބެލޭ.\n\nމި އެޕް ތިޔައާ ބެހޭ ތަފްސީލެއް ނެހެދޭ، ޑިވެލޮޕަރަށް ވެސް ނުފޮނުވާ. ހުރިހާ ޑޭޓާ ހިފެހެއްޓޭ ތަނަކީ ހަމައެކަނި ތިޔަ ފޯނު.</string>
<string name="coming_soon">ފަހުން ލިބޭ</string>
<string name="next">ދެން</string>
<string name="get_started">ފަށާ</string>

View File

@@ -9,7 +9,7 @@
<string name="onboarding_title_2">More Banks Coming</string>
<string name="onboarding_desc_2">Support for additional banks is on the way. Stay tuned as we expand coverage across the Maldives.</string>
<string name="onboarding_title_3">Before You Begin</string>
<string name="onboarding_desc_3">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</string>
<string name="onboarding_desc_3">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 to look up details about phone numbers.\n\nThis app does not collect any analytics, telemetry, or personal data, and does not transmit any information about you or your usage to the developer. Everything stays entirely on your device.\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</string>
<string name="coming_soon">Coming Soon</string>
<string name="next">Next</string>
<string name="get_started">Get Started</string>