Conversation
There was a problem hiding this comment.
Pull request overview
Refactors several Compose ModalBottomSheetLayout usages into dedicated MixinComposeBottomSheetDialogFragment bottom sheets, and wires back-press/expand behavior between fragments and Compose screens.
Changes:
- Replaces Compose modal bottom sheets in Alert edit and PIN quiz flows with
MixinComposeBottomSheetDialogFragmentimplementations. - Introduces an address-book bottom sheet dialog and updates transfer destination flow to open it via a callback.
- Adds expansion/back handling for the wallet asset dashboard overlay.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| app/src/main/java/one/mixin/android/ui/wallet/components/AssetDashboardScreen.kt | Adds Compose BackHandler and new parameters to close the expanded dashboard. |
| app/src/main/java/one/mixin/android/ui/wallet/alert/AlertSelectionBottomSheetDialogFragment.kt | New bottom sheet dialog for selecting alert type/frequency. |
| app/src/main/java/one/mixin/android/ui/wallet/alert/AlertFragment.kt | Uses the new alert selection bottom sheet dialog from the edit route. |
| app/src/main/java/one/mixin/android/ui/wallet/alert/AlertEditPage.kt | Removes ModalBottomSheetLayout; delegates selection UI to fragment-provided callbacks. |
| app/src/main/java/one/mixin/android/ui/wallet/WalletListBottomSheetDialogFragment.kt | Adjusts wallet list layout sizing inside the bottom sheet. |
| app/src/main/java/one/mixin/android/ui/wallet/WalletFragment.kt | Tracks dashboard expanded state and closes it via back press. |
| app/src/main/java/one/mixin/android/ui/landing/components/QuizResultBottomSheetDialogFragment.kt | New quiz result bottom sheet dialog. |
| app/src/main/java/one/mixin/android/ui/landing/components/QuizPage.kt | Removes Compose modal sheet; triggers a fragment bottom sheet via callback. |
| app/src/main/java/one/mixin/android/ui/landing/SetupPinFragment.kt | Shows QuizResultBottomSheetDialogFragment from the quiz page callback. |
| app/src/main/java/one/mixin/android/ui/address/page/TransferDestinationInputPage.kt | Removes Compose modal address book; uses onShowAddressBook callback. |
| app/src/main/java/one/mixin/android/ui/address/page/AddressSearchBottomSheet.kt | Updates bottom sheet content to use onDismiss and simplifies back handling. |
| app/src/main/java/one/mixin/android/ui/address/TransferDestinationInputFragment.kt | Shows the new address search bottom sheet dialog fragment. |
| app/src/main/java/one/mixin/android/ui/address/AddressSearchBottomSheetDialogFragment.kt | New bottom sheet dialog fragment hosting AddressSearchBottomSheet. |
Comments suppressed due to low confidence (1)
app/src/main/java/one/mixin/android/ui/address/page/AddressSearchBottomSheet.kt:87
- The computed
actionBarHeightvalue is unused, andscope/kotlinx.coroutines.launchare no longer referenced after removing the modal sheet state logic. Please remove these unused variables/imports to avoid lint/ktlint failures and keep the file minimal.
val scope = rememberCoroutineScope()
val filteredAddresses = remember(searchText, addresses) {
if (searchText.isBlank()) {
addresses
} else {
addresses.filter { address ->
address.label.contains(searchText, ignoreCase = true) ||
address.destination.contains(searchText, ignoreCase = true)
}
}
}
BackHandler(enabled = true) {
if (isDeleteMode) isDeleteMode = false
else onDismiss()
}
val actionBarHeight = with(LocalDensity.current) {
val attrs = intArrayOf(android.R.attr.actionBarSize)
val typedArray = LocalContext.current.obtainStyledAttributes(attrs)
val height = typedArray.getDimensionPixelSize(0, 0)
typedArray.recycle()
height.toDp()
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import androidx.compose.material.ButtonDefaults | ||
| import androidx.compose.material.Icon | ||
| import androidx.compose.material.IconButton | ||
| import androidx.compose.material.ModalBottomSheetLayout | ||
| import androidx.compose.material.ModalBottomSheetValue | ||
| import androidx.compose.material.RadioButton |
There was a problem hiding this comment.
After removing the ModalBottomSheetLayout/coroutine-scope logic, kotlinx.coroutines.launch is no longer used in this file. Please remove the unused import to avoid lint/ktlint failures.
| toWallet: (String?) -> Unit, | ||
| onSend: (String) -> Unit, | ||
| onDeleteAddress: (Address) -> Unit, | ||
| onAddressClick: (Address) -> Unit, | ||
| onShowAddressBook: () -> Unit, |
There was a problem hiding this comment.
toAddAddress, onDeleteAddress, and onAddressClick are still declared as parameters but are no longer used inside TransferDestinationInputPage after moving address-book UI to onShowAddressBook(). Consider removing these parameters (and updating call sites) to keep the composable API minimal and avoid unused-parameter lint warnings.
| onShowAddressBook = { | ||
| val chainId = token?.chainId ?: web3Token?.chainId ?: return@TransferDestinationInputPage | ||
| AddressSearchBottomSheetDialogFragment.newInstance(chainId).apply { | ||
| onAddressClick = { address -> |
There was a problem hiding this comment.
onShowAddressBook directly calls show(...) on a new AddressSearchBottomSheetDialogFragment instance. Since this callback can be triggered both from a user tap and from LaunchedEffect(addressShown) in the composable, it’s possible to attempt to show the dialog multiple times (or after state is saved), leading to overlapping dialogs or IllegalStateException. Consider guarding with parentFragmentManager.findFragmentByTag(TAG) == null and/or checking !parentFragmentManager.isStateSaved before showing.
| private val mode by lazy { requireArguments().getString(ARGS_MODE).orEmpty() } | ||
| private val selectedType by lazy { AlertType.values().first { it.value == requireArguments().getString(ARGS_SELECTED_TYPE) } } | ||
| private val selectedFrequency by lazy { AlertFrequency.values().first { it.value == requireArguments().getString(ARGS_SELECTED_FREQUENCY) } } |
There was a problem hiding this comment.
mode is read with orEmpty() and anything other than MODE_TYPE falls into the frequency branch. If the fragment is ever created with missing/invalid args (e.g., ARGS_MODE absent, or an unknown value), this will attempt to read ARGS_SELECTED_FREQUENCY and first { ... } will throw, crashing the app. Consider validating mode/args (use firstOrNull, provide a safe default, or dismiss early) instead of assuming the arguments are always present and correct.
| private val mode by lazy { requireArguments().getString(ARGS_MODE).orEmpty() } | |
| private val selectedType by lazy { AlertType.values().first { it.value == requireArguments().getString(ARGS_SELECTED_TYPE) } } | |
| private val selectedFrequency by lazy { AlertFrequency.values().first { it.value == requireArguments().getString(ARGS_SELECTED_FREQUENCY) } } | |
| private val mode by lazy { | |
| when (val argMode = requireArguments().getString(ARGS_MODE)) { | |
| MODE_TYPE, MODE_FREQUENCY -> argMode | |
| else -> MODE_TYPE | |
| } | |
| } | |
| private val selectedType by lazy { | |
| val selected = requireArguments().getString(ARGS_SELECTED_TYPE) | |
| AlertType.values().firstOrNull { it.value == selected } ?: AlertType.values().first() | |
| } | |
| private val selectedFrequency by lazy { | |
| val selected = requireArguments().getString(ARGS_SELECTED_FREQUENCY) | |
| AlertFrequency.values().firstOrNull { it.value == selected } ?: AlertFrequency.values().first() | |
| } |
| Column( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height( | ||
| LocalConfiguration.current.screenHeightDp.dp - GetActionBarHeight() - GetStatusBarHeightValue() | ||
| ) | ||
| ) { |
There was a problem hiding this comment.
WalletListScreen hard-codes its own height using LocalConfiguration.screenHeightDp - GetActionBarHeight() - GetStatusBarHeightValue(), but the hosting WalletListBottomSheetDialogFragment.getBottomSheetHeight() already constrains the sheet height (and resolveBottomSheetPeekHeight accounts for insets). This can double-subtract system bars/action bar and leave unused space or truncate content. Prefer Modifier.fillMaxSize() (or weight(1f) inside the sheet) and let the bottom sheet height/insets be handled by the fragment/base bottom sheet utilities.
| if (searchText.isNotEmpty() || isDeleteMode) { | ||
| Text( | ||
| text = stringResource(R.string.Cancel), | ||
| color = MixinAppTheme.colors.textBlue, |
There was a problem hiding this comment.
The "Cancel" action is now only shown when searchText is non-empty or isDeleteMode is true. In the default state (no search / no delete), users lose the obvious in-UI affordance to dismiss/close the bottom sheet (they can only use system back). Consider always showing a dismiss action (e.g., always render Cancel or show a close icon) and have it call onDismiss() when neither search nor delete mode is active.
No description provided.