Updated on 2026-08-14
This commit is contained in:
parent
5f68c41da2
commit
922a8f6706
14 changed files with 160 additions and 24 deletions
|
|
@ -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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue