Updated on 2026-08-14
This commit is contained in:
commit
f5b2046666
14 changed files with 160 additions and 24 deletions
|
|
@ -1,6 +1,10 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.windowsize.rememberWindowSize
|
||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseScreen
|
||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseApi
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen
|
||||
|
|
@ -16,6 +20,7 @@ import com.tangem.wallet.R
|
|||
*/
|
||||
internal class OnboardingSeedPhraseStateHandler(
|
||||
private val onboardingSeedPhraseApi: OnboardingSeedPhraseApi = OnboardingSeedPhraseScreen(),
|
||||
private val activity: Activity,
|
||||
) {
|
||||
|
||||
fun newState(
|
||||
|
|
@ -49,11 +54,16 @@ internal class OnboardingSeedPhraseStateHandler(
|
|||
val subScreen = viewModel.currentScreen.collectAsState().value
|
||||
setMainScreenToolbarTitle(walletFragment, subScreen)
|
||||
|
||||
onboardingSeedPhraseApi.ScreenContent(
|
||||
uiState = viewModel.uiState,
|
||||
subScreen = subScreen,
|
||||
progress = viewModel.progress.collectAsState(0).value.toFloat() / onboardingWalletMaxProgress,
|
||||
)
|
||||
TangemTheme(
|
||||
isDark = isSystemInDarkTheme(),
|
||||
windowSize = rememberWindowSize(activity = activity),
|
||||
) {
|
||||
onboardingSeedPhraseApi.ScreenContent(
|
||||
uiState = viewModel.uiState,
|
||||
subScreen = subScreen,
|
||||
progress = viewModel.progress.collectAsState(0).value.toFloat() / onboardingWalletMaxProgress,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ class OnboardingWalletFragment :
|
|||
|
||||
private val canSkipBackup by lazy { arguments?.getBoolean(OnboardingRouter.CAN_SKIP_BACKUP) ?: true }
|
||||
|
||||
private val seedPhraseStateHandler: OnboardingSeedPhraseStateHandler = OnboardingSeedPhraseStateHandler()
|
||||
private lateinit var seedPhraseStateHandler: OnboardingSeedPhraseStateHandler
|
||||
|
||||
private val seedPhraseViewModel by viewModels<SeedPhraseViewModel>()
|
||||
|
||||
private lateinit var cardsWidget: WalletCardsWidget
|
||||
|
|
@ -79,6 +80,7 @@ class OnboardingWalletFragment :
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
seedPhraseStateHandler = OnboardingSeedPhraseStateHandler(activity = requireActivity())
|
||||
|
||||
val newSeedPhraseRouter = makeSeedPhraseRouter()
|
||||
seedPhraseRouter = newSeedPhraseRouter
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ dependencies {
|
|||
implementation(deps.androidx.fragment.ktx)
|
||||
implementation(deps.androidx.paging.runtime)
|
||||
implementation(deps.androidx.palette)
|
||||
implementation(deps.androidx.windowManager) {
|
||||
exclude(
|
||||
deps.kotlin.coroutines.android.get().module.group,
|
||||
deps.kotlin.coroutines.android.get().module.name
|
||||
)
|
||||
}
|
||||
|
||||
/** Compose */
|
||||
implementation(deps.compose.constraintLayout)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemColorPalette.White
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
/**
|
||||
* Travala notification with image background
|
||||
|
|
@ -192,7 +193,7 @@ private fun formatSubtitle(subtitle: String): AnnotatedString {
|
|||
@Preview
|
||||
@Composable
|
||||
private fun TravalaNotificationWithBackgroundPreview() {
|
||||
TangemTheme {
|
||||
TangemThemePreview {
|
||||
TravalaNotificationWithBackground(
|
||||
config = NotificationConfig(
|
||||
title = resourceReference(
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
/**
|
||||
* Snackbar to inform the user about copying text to the clipboard
|
||||
|
|
@ -100,7 +101,7 @@ private fun MessageText(text: TextReference, modifier: Modifier = Modifier) {
|
|||
private fun Preview_CopiedTextSnackbar(
|
||||
@PreviewParameter(CopiedTextSnackbarDataProvider::class) message: TextReference,
|
||||
) {
|
||||
TangemTheme(isDark = false) {
|
||||
TangemThemePreview {
|
||||
CopiedTextSnackbar(message = message)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,12 @@ import androidx.compose.runtime.*
|
|||
import com.tangem.core.ui.haptic.HapticManager
|
||||
import com.tangem.core.ui.haptic.MockHapticManager
|
||||
|
||||
import com.tangem.core.ui.windowsize.WindowSize
|
||||
|
||||
@Composable
|
||||
fun TangemTheme(
|
||||
isDark: Boolean = false,
|
||||
windowSize: WindowSize,
|
||||
typography: TangemTypography = TangemTheme.typography,
|
||||
dimens: TangemDimens = TangemTheme.dimens,
|
||||
hapticManager: HapticManager = MockHapticManager,
|
||||
|
|
@ -33,6 +36,7 @@ fun TangemTheme(
|
|||
LocalIsInDarkTheme provides isDark,
|
||||
LocalHapticManager provides hapticManager,
|
||||
LocalSnackbarHostState provides snackbarHostState,
|
||||
LocalWindowSize provides windowSize,
|
||||
) {
|
||||
ProvideTextStyle(
|
||||
value = TangemTheme.typography.body1,
|
||||
|
|
@ -208,4 +212,8 @@ val LocalHapticManager = staticCompositionLocalOf<HapticManager> {
|
|||
|
||||
val LocalSnackbarHostState = staticCompositionLocalOf<SnackbarHostState> {
|
||||
error("No SnackbarHostState provided")
|
||||
}
|
||||
|
||||
val LocalWindowSize = staticCompositionLocalOf<WindowSize> {
|
||||
error("No WindowSize provided")
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.core.ui.res
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.core.ui.windowsize.rememberWindowSizePreview
|
||||
|
||||
@Composable
|
||||
fun TangemThemePreview(
|
||||
|
|
@ -12,10 +14,13 @@ fun TangemThemePreview(
|
|||
) {
|
||||
val isDarkTheme = isDark ?: isSystemInDarkTheme()
|
||||
|
||||
TangemTheme(
|
||||
isDark = isDarkTheme,
|
||||
typography = typography,
|
||||
dimens = dimens,
|
||||
content = content,
|
||||
)
|
||||
BoxWithConstraints {
|
||||
TangemTheme(
|
||||
isDark = isDarkTheme,
|
||||
typography = typography,
|
||||
dimens = dimens,
|
||||
windowSize = rememberWindowSizePreview(maxWidth, maxHeight),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,6 @@ abstract class ComposeActivity : ComponentActivity(), ComposeScreen {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContentView(createComposeView(context = this))
|
||||
setContentView(createComposeView(context = this, activity = this))
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ abstract class ComposeBottomSheetFragment : BottomSheetDialogFragment(), Compose
|
|||
override fun getTheme(): Int = R.style.AppTheme_TransparentBottomSheetDialog
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return createComposeView(inflater.context)
|
||||
return createComposeView(inflater.context, requireActivity())
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ abstract class ComposeFragment : Fragment(), ComposeScreen {
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val isTransitionsInflated = TransitionInflater.from(requireContext()).inflateTransitions()
|
||||
|
||||
return createComposeView(inflater.context).also {
|
||||
return createComposeView(inflater.context, requireActivity()).also {
|
||||
it.isTransitionGroup = isTransitionsInflated
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.core.ui.screen
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
|
|
@ -10,6 +11,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.ComposeView
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.windowsize.rememberWindowSize
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
|
||||
/**
|
||||
|
|
@ -50,13 +52,15 @@ internal interface ComposeScreen {
|
|||
* @param context The context.
|
||||
* @return A [ComposeView] instance with the defined screen content.
|
||||
*/
|
||||
internal fun ComposeScreen.createComposeView(context: Context): ComposeView {
|
||||
internal fun ComposeScreen.createComposeView(context: Context, activity: Activity): ComposeView {
|
||||
return ComposeView(context).apply {
|
||||
setContent {
|
||||
val appThemeMode by uiDependencies.appThemeModeHolder.appThemeMode
|
||||
val windowSize = rememberWindowSize(activity = activity)
|
||||
|
||||
TangemTheme(
|
||||
isDark = shouldUseDarkTheme(appThemeMode),
|
||||
windowSize = windowSize,
|
||||
hapticManager = uiDependencies.hapticManager,
|
||||
snackbarHostState = uiDependencies.globalSnackbarHostState,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
package com.tangem.core.ui.windowsize
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.toComposeRect
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.window.layout.WindowMetricsCalculator
|
||||
|
||||
/**
|
||||
* The preferred way to determine the window size is because it provides the actual size of the window as opposed to
|
||||
* [LocalConfiguration.current.screenHeightDp]
|
||||
*
|
||||
* @property width actual window width
|
||||
* @property height actual window height
|
||||
* @property widthSizeType window size type based on width
|
||||
* @property heightSizeType window size type based on height
|
||||
* @property smallestSize smallest size of width and height
|
||||
*/
|
||||
data class WindowSize(
|
||||
val width: Dp,
|
||||
val height: Dp,
|
||||
) {
|
||||
val widthSizeType: WindowSizeType = getWidthWindowSizeType(width)
|
||||
val heightSizeType: WindowSizeType = getHeightWindowSizeType(height)
|
||||
val smallestSize: Dp = minOf(width, height)
|
||||
|
||||
fun widthAtLeast(type: WindowSizeType): Boolean = this.widthSizeType.ordinal >= type.ordinal
|
||||
|
||||
fun widthAtLeast(value: Dp): Boolean = this.width >= value
|
||||
|
||||
fun heightAtLeast(type: WindowSizeType): Boolean = this.heightSizeType.ordinal >= type.ordinal
|
||||
|
||||
fun heightAtLeast(value: Dp): Boolean = this.height >= value
|
||||
|
||||
fun widthAtMost(type: WindowSizeType): Boolean = this.widthSizeType.ordinal <= type.ordinal
|
||||
|
||||
fun widthAtMost(value: Dp): Boolean = this.width <= value
|
||||
|
||||
fun heightAtMost(type: WindowSizeType): Boolean = this.heightSizeType.ordinal <= type.ordinal
|
||||
|
||||
fun heightAtMost(value: Dp): Boolean = this.height <= value
|
||||
|
||||
private fun getWidthWindowSizeType(windowDp: Dp): WindowSizeType = when {
|
||||
windowDp < 300.dp -> WindowSizeType.ExtraSmall
|
||||
windowDp < 380.dp -> WindowSizeType.Small
|
||||
windowDp < 540.dp -> WindowSizeType.Normal
|
||||
windowDp < 700.dp -> WindowSizeType.Large
|
||||
else -> WindowSizeType.ExtraLarge
|
||||
}
|
||||
|
||||
private fun getHeightWindowSizeType(heightDp: Dp): WindowSizeType = when {
|
||||
heightDp < 480.dp -> WindowSizeType.ExtraSmall
|
||||
heightDp < 640.dp -> WindowSizeType.Small
|
||||
heightDp < 860.dp -> WindowSizeType.Normal
|
||||
heightDp < 1100.dp -> WindowSizeType.Large
|
||||
else -> WindowSizeType.ExtraLarge
|
||||
}
|
||||
}
|
||||
|
||||
enum class WindowSizeType {
|
||||
ExtraSmall, Small, Normal, Large, ExtraLarge
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberWindowSize(activity: Activity): WindowSize {
|
||||
val windowBoundsSize = rememberWindowBoundsSize(activity)
|
||||
val windowDpSize = with(LocalDensity.current) {
|
||||
windowBoundsSize.toDpSize()
|
||||
}
|
||||
|
||||
return WindowSize(
|
||||
width = windowDpSize.width,
|
||||
height = windowDpSize.height,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun rememberWindowSizePreview(width: Dp, height: Dp): WindowSize {
|
||||
return remember(width, height) {
|
||||
WindowSize(
|
||||
width = width,
|
||||
height = height,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberWindowBoundsSize(activity: Activity): Size {
|
||||
val configuration = LocalConfiguration.current
|
||||
val windowMetrics = remember(configuration) {
|
||||
WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity)
|
||||
}
|
||||
return windowMetrics.bounds.toComposeRect().size
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.feature.onboarding.api
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -19,11 +18,9 @@ class OnboardingSeedPhraseScreen : OnboardingSeedPhraseApi {
|
|||
@Composable
|
||||
override fun ScreenContent(uiState: OnboardingSeedPhraseState, subScreen: SeedPhraseScreen, progress: Float) {
|
||||
BackHandler(onBack = uiState.onBackClick)
|
||||
TangemTheme(isDark = isSystemInDarkTheme()) {
|
||||
Column {
|
||||
ProgressIndicator(progress)
|
||||
Content(subScreen, uiState)
|
||||
}
|
||||
Column {
|
||||
ProgressIndicator(progress)
|
||||
Content(subScreen, uiState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ androidxLifecycle = "2.5.1"
|
|||
androidx-paging = "3.1.1"
|
||||
androidx-palette = "1.0.0"
|
||||
androidx-datastore = "1.0.0"
|
||||
androidxWindowManager = "1.3.0"
|
||||
# endregion AndroidX
|
||||
|
||||
# region Compose
|
||||
|
|
@ -145,6 +146,7 @@ androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref
|
|||
androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "androidx-paging" }
|
||||
androidx-swipeRefreshLayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swipeRefreshLayout" }
|
||||
androidx-palette = { module = "androidx.palette:palette", version.ref = "androidx-palette" }
|
||||
androidx-windowManager = { group = "androidx.window", name = "window", version.ref = "androidxWindowManager" }
|
||||
lifecycle-common-java8 = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "androidxLifecycle" }
|
||||
lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidxLifecycle" }
|
||||
lifecycle-viewModel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidxLifecycle" }
|
||||
|
|
@ -217,6 +219,7 @@ armadillo = { module = "at.favre.lib:armadillo", version.ref = "armadillo" }
|
|||
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
|
||||
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutine" }
|
||||
kotlin-coroutines-rx2 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx2", version.ref = "coroutine" }
|
||||
kotlin-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutine" }
|
||||
kotlin-immutable-collections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlin-immutable-collections" }
|
||||
desugar = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugarJdkLibs" }
|
||||
googlePlay-core = { module = "com.google.android.play:core", version.ref = "googlePlayCore" }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue