Split compose screens into multiple smaller sections

This commit is contained in:
Ensar Sarajčić 2023-10-03 09:10:32 +02:00
parent c644def18e
commit 3f901ff290
5 changed files with 281 additions and 206 deletions

View File

@ -22,6 +22,7 @@ import com.simplemobiletools.flashlight.extensions.config
import com.simplemobiletools.flashlight.helpers.SleepTimer
import com.simplemobiletools.flashlight.helpers.stopSleepTimerCountDown
import com.simplemobiletools.flashlight.screens.BrightDisplayScreen
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
@ -63,10 +64,8 @@ class BrightDisplayActivity : ComponentActivity() {
}
}
},
timerVisible = timerVisible,
timerText = timerText,
onTimerClosePress = {
stopSleepTimer()
sleepTimer = {
AnimatedSleepTimer(timerText = timerText, timerVisible = timerVisible, onTimerClosePress = ::stopSleepTimer)
}
)
}

View File

@ -40,7 +40,8 @@ import com.simplemobiletools.flashlight.dialogs.SleepTimerCustomDialog
import com.simplemobiletools.flashlight.extensions.config
import com.simplemobiletools.flashlight.extensions.startAboutActivity
import com.simplemobiletools.flashlight.helpers.*
import com.simplemobiletools.flashlight.screens.MainScreen
import com.simplemobiletools.flashlight.screens.*
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
import kotlinx.coroutines.flow.*
import java.util.*
import kotlin.system.exitProcess
@ -61,25 +62,6 @@ class MainActivity : ComponentActivity() {
setContent {
AppThemeSurface {
val showMoreApps = onEventValue { !resources.getBoolean(R.bool.hide_google_relations) }
val timerVisible by viewModel.timerVisible.collectAsStateWithLifecycle()
val timerText by viewModel.timerText.collectAsStateWithLifecycle()
val flashlightActive by viewModel.flashlightOn.collectAsStateWithLifecycle()
val showBrightDisplayButton by preferences.brightDisplayFlow.collectAsStateWithLifecycle(
config.brightDisplay,
minActiveState = Lifecycle.State.CREATED
)
val showSosButton by preferences.sosFlow.collectAsStateWithLifecycle(config.sos, minActiveState = Lifecycle.State.CREATED)
val sosActive by viewModel.sosActive.collectAsStateWithLifecycle()
val showStroboscopeButton by preferences.stroboscopeFlow.collectAsStateWithLifecycle(
config.stroboscope,
minActiveState = Lifecycle.State.CREATED
)
val stroboscopeActive by viewModel.stroboscopeActive.collectAsStateWithLifecycle()
val brightnessBarVisible by viewModel.brightnessBarVisible.collectAsStateWithLifecycle(false)
val brightnessBarValue by viewModel.brightnessBarValue.collectAsStateWithLifecycle()
val stroboscopeBarVisible by viewModel.stroboscopeBarVisible.collectAsStateWithLifecycle(false)
val stroboscopeBarValue by viewModel.stroboscopeBarValue.collectAsStateWithLifecycle()
val sosPermissionLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = {
@ -102,34 +84,84 @@ class MainActivity : ComponentActivity() {
)
MainScreen(
timerText = timerText,
timerVisible = timerVisible,
onTimerClosePress = { stopSleepTimer() },
onFlashlightPress = { viewModel.toggleFlashlight() },
flashlightActive = flashlightActive,
showBrightDisplayButton = showBrightDisplayButton,
onBrightDisplayPress = {
startActivity(Intent(applicationContext, BrightDisplayActivity::class.java))
flashlightButton = {
val flashlightActive by viewModel.flashlightOn.collectAsStateWithLifecycle()
FlashlightButton(
onFlashlightPress = { viewModel.toggleFlashlight() },
flashlightActive = flashlightActive,
)
},
showSosButton = showSosButton,
sosActive = sosActive,
onSosButtonPress = {
toggleStroboscope(true, sosPermissionLauncher)
brightDisplayButton = {
val showBrightDisplayButton by preferences.brightDisplayFlow.collectAsStateWithLifecycle(
config.brightDisplay,
minActiveState = Lifecycle.State.CREATED
)
if (showBrightDisplayButton) {
BrightDisplayButton(
onBrightDisplayPress = {
startActivity(Intent(applicationContext, BrightDisplayActivity::class.java))
}
)
}
},
showStroboscopeButton = showStroboscopeButton,
stroboscopeActive = stroboscopeActive,
onStroboscopeButtonPress = {
toggleStroboscope(false, stroboscopePermissionLauncher)
sosButton = {
val showSosButton by preferences.sosFlow.collectAsStateWithLifecycle(config.sos, minActiveState = Lifecycle.State.CREATED)
val sosActive by viewModel.sosActive.collectAsStateWithLifecycle()
if (showSosButton) {
SosButton(
sosActive = sosActive,
onSosButtonPress = {
toggleStroboscope(true, sosPermissionLauncher)
},
)
}
},
showBrightnessBar = brightnessBarVisible,
brightnessBarValue = brightnessBarValue,
onBrightnessBarValueChange = {
viewModel.updateBrightnessBarValue(it)
stroboscopeButton = {
val showStroboscopeButton by preferences.stroboscopeFlow.collectAsStateWithLifecycle(
config.stroboscope,
minActiveState = Lifecycle.State.CREATED
)
val stroboscopeActive by viewModel.stroboscopeActive.collectAsStateWithLifecycle()
if (showStroboscopeButton) {
StroboscopeButton(
stroboscopeActive = stroboscopeActive,
onStroboscopeButtonPress = {
toggleStroboscope(false, stroboscopePermissionLauncher)
},
)
}
},
showStroboscopeBar = stroboscopeBarVisible,
stroboscopeBarValue = stroboscopeBarValue,
onStroboscopeBarValueChange = {
viewModel.updateStroboscopeBarValue(it)
slidersSection = {
val brightnessBarVisible by viewModel.brightnessBarVisible.collectAsStateWithLifecycle(false)
val brightnessBarValue by viewModel.brightnessBarValue.collectAsStateWithLifecycle()
val stroboscopeBarVisible by viewModel.stroboscopeBarVisible.collectAsStateWithLifecycle(false)
val stroboscopeBarValue by viewModel.stroboscopeBarValue.collectAsStateWithLifecycle()
MainScreenSlidersSection(
showBrightnessBar = brightnessBarVisible,
brightnessBarValue = brightnessBarValue,
onBrightnessBarValueChange = {
viewModel.updateBrightnessBarValue(it)
},
showStroboscopeBar = stroboscopeBarVisible,
stroboscopeBarValue = stroboscopeBarValue,
onStroboscopeBarValueChange = {
viewModel.updateStroboscopeBarValue(it)
},
)
},
sleepTimer = {
val timerVisible by viewModel.timerVisible.collectAsStateWithLifecycle()
val timerText by viewModel.timerText.collectAsStateWithLifecycle()
AnimatedSleepTimer(
timerText = timerText,
timerVisible = timerVisible,
onTimerClosePress = { stopSleepTimer() },
)
},
showMoreApps = showMoreApps,
openSettings = ::launchSettings,

View File

@ -1,8 +1,5 @@
package com.simplemobiletools.flashlight.screens
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
@ -23,16 +20,14 @@ import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.extensions.getContrastColor
import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.views.SleepTimer
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
@Composable
internal fun BrightDisplayScreen(
backgroundColor: Int,
contrastColor: Int,
timerText: String,
timerVisible: Boolean,
onChangeColorPress: () -> Unit,
onTimerClosePress: () -> Unit
sleepTimer: @Composable () -> Unit
) {
Box(
modifier = Modifier
@ -56,18 +51,12 @@ internal fun BrightDisplayScreen(
)
}
AnimatedVisibility(
Box(
modifier = Modifier
.align(Alignment.BottomEnd)
.navigationBarsPadding(),
visible = timerVisible && timerText.isNotEmpty(),
enter = fadeIn(),
exit = fadeOut()
.navigationBarsPadding()
) {
SleepTimer(
timerText = timerText,
onCloseClick = onTimerClosePress
)
sleepTimer()
}
}
}
@ -79,10 +68,10 @@ private fun BrightDisplayScreenPreview() {
BrightDisplayScreen(
backgroundColor = MaterialTheme.colorScheme.background.toArgb(),
contrastColor = MaterialTheme.colorScheme.background.toArgb().getContrastColor(),
timerText = "00:00",
timerVisible = true,
sleepTimer = {
AnimatedSleepTimer(timerText = "00:00", timerVisible = true, onTimerClosePress = {})
},
onChangeColorPress = {},
onTimerClosePress = {}
)
}
}

View File

@ -1,8 +1,5 @@
package com.simplemobiletools.flashlight.screens
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
@ -32,31 +29,18 @@ import com.simplemobiletools.commons.compose.settings.scaffold.topAppBarInsets
import com.simplemobiletools.commons.compose.settings.scaffold.topAppBarPaddings
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.views.SleepTimer
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
@Composable
internal fun MainScreen(
timerText: String,
timerVisible: Boolean,
onTimerClosePress: () -> Unit,
flashlightActive: Boolean,
onFlashlightPress: () -> Unit,
showBrightDisplayButton: Boolean,
onBrightDisplayPress: () -> Unit,
showSosButton: Boolean,
sosActive: Boolean,
onSosButtonPress: () -> Unit,
showStroboscopeButton: Boolean,
stroboscopeActive: Boolean,
onStroboscopeButtonPress: () -> Unit,
showBrightnessBar: Boolean,
brightnessBarValue: Float,
onBrightnessBarValueChange: (Float) -> Unit,
showStroboscopeBar: Boolean,
stroboscopeBarValue: Float,
onStroboscopeBarValueChange: (Float) -> Unit,
flashlightButton: @Composable () -> Unit,
brightDisplayButton: @Composable () -> Unit,
sosButton: @Composable () -> Unit,
stroboscopeButton: @Composable () -> Unit,
slidersSection: @Composable () -> Unit,
sleepTimer: @Composable () -> Unit,
showMoreApps: Boolean,
openSettings: () -> Unit,
openAbout: () -> Unit,
@ -90,111 +74,138 @@ internal fun MainScreen(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Icon(
modifier = Modifier
.size(dimensionResource(id = R.dimen.main_button_size))
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onFlashlightPress
),
painter = painterResource(id = R.drawable.ic_flashlight_vector),
contentDescription = stringResource(id = R.string.flashlight_short),
tint = if (flashlightActive) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
)
if (showBrightDisplayButton) {
Icon(
modifier = Modifier
.size(dimensionResource(id = R.dimen.smaller_button_size))
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onBrightDisplayPress
),
painter = painterResource(id = R.drawable.ic_bright_display_vector),
contentDescription = stringResource(id = R.string.bright_display),
tint = MaterialTheme.colorScheme.onSurface
)
}
if (showSosButton) {
Text(
modifier = Modifier
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onSosButtonPress
),
text = stringResource(id = R.string.sos),
fontSize = TextUnit(dimensionResource(id = R.dimen.sos_text_size).value, TextUnitType.Sp),
fontWeight = FontWeight.Bold,
color = if (sosActive) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
)
}
if (showStroboscopeButton) {
Icon(
modifier = Modifier
.size(dimensionResource(id = R.dimen.smaller_button_size))
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onStroboscopeButtonPress
),
painter = painterResource(id = R.drawable.ic_stroboscope_vector),
contentDescription = "",
tint = if (stroboscopeActive) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
)
}
val sliderModifier = Modifier
.padding(dimensionResource(id = R.dimen.activity_margin))
.padding(vertical = dimensionResource(R.dimen.medium_margin))
.padding(bottom = dimensionResource(id = R.dimen.activity_margin))
.size(width = dimensionResource(id = R.dimen.seekbar_width), height = dimensionResource(id = R.dimen.seekbar_height))
if (showBrightnessBar) {
Slider(
modifier = sliderModifier,
value = brightnessBarValue,
onValueChange = onBrightnessBarValueChange
)
}
if (showStroboscopeBar) {
Slider(
modifier = sliderModifier,
value = stroboscopeBarValue,
onValueChange = onStroboscopeBarValueChange
)
}
if (!showBrightnessBar && !showStroboscopeBar) {
Spacer(
modifier = sliderModifier,
)
}
flashlightButton()
brightDisplayButton()
sosButton()
stroboscopeButton()
slidersSection()
}
AnimatedVisibility(
Box(
modifier = Modifier.align(Alignment.BottomEnd),
visible = timerVisible && timerText.isNotEmpty(),
enter = fadeIn(),
exit = fadeOut(),
) {
SleepTimer(
timerText = timerText,
onCloseClick = onTimerClosePress
)
sleepTimer()
}
}
}
@Composable
internal fun FlashlightButton(
flashlightActive: Boolean,
onFlashlightPress: () -> Unit,
) {
Icon(
modifier = Modifier
.size(dimensionResource(id = R.dimen.main_button_size))
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onFlashlightPress
),
painter = painterResource(id = R.drawable.ic_flashlight_vector),
contentDescription = stringResource(id = R.string.flashlight_short),
tint = if (flashlightActive) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
)
}
@Composable
internal fun BrightDisplayButton(
onBrightDisplayPress: () -> Unit,
) {
Icon(
modifier = Modifier
.size(dimensionResource(id = R.dimen.smaller_button_size))
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onBrightDisplayPress
),
painter = painterResource(id = R.drawable.ic_bright_display_vector),
contentDescription = stringResource(id = R.string.bright_display),
tint = MaterialTheme.colorScheme.onSurface
)
}
@Composable
internal fun SosButton(
sosActive: Boolean,
onSosButtonPress: () -> Unit,
) {
Text(
modifier = Modifier
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onSosButtonPress
),
text = stringResource(id = R.string.sos),
fontSize = TextUnit(dimensionResource(id = R.dimen.sos_text_size).value, TextUnitType.Sp),
fontWeight = FontWeight.Bold,
color = if (sosActive) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
)
}
@Composable
internal fun StroboscopeButton(
stroboscopeActive: Boolean,
onStroboscopeButtonPress: () -> Unit,
) {
Icon(
modifier = Modifier
.size(dimensionResource(id = R.dimen.smaller_button_size))
.padding(vertical = dimensionResource(id = R.dimen.normal_margin))
.clickable(
indication = null,
interactionSource = rememberMutableInteractionSource(),
onClick = onStroboscopeButtonPress
),
painter = painterResource(id = R.drawable.ic_stroboscope_vector),
contentDescription = "",
tint = if (stroboscopeActive) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
)
}
@Composable
internal fun MainScreenSlidersSection(
showBrightnessBar: Boolean,
brightnessBarValue: Float,
onBrightnessBarValueChange: (Float) -> Unit,
showStroboscopeBar: Boolean,
stroboscopeBarValue: Float,
onStroboscopeBarValueChange: (Float) -> Unit,
) {
val sliderModifier = Modifier
.padding(dimensionResource(id = R.dimen.activity_margin))
.padding(vertical = dimensionResource(R.dimen.medium_margin))
.padding(bottom = dimensionResource(id = R.dimen.activity_margin))
.size(width = dimensionResource(id = R.dimen.seekbar_width), height = dimensionResource(id = R.dimen.seekbar_height))
if (showBrightnessBar) {
Slider(
modifier = sliderModifier,
value = brightnessBarValue,
onValueChange = onBrightnessBarValueChange
)
}
if (showStroboscopeBar) {
Slider(
modifier = sliderModifier,
value = stroboscopeBarValue,
onValueChange = onStroboscopeBarValueChange
)
}
if (!showBrightnessBar && !showStroboscopeBar) {
Spacer(
modifier = sliderModifier,
)
}
}
private fun buildActionMenu(
showMoreApps: Boolean,
openSettings: () -> Unit,
@ -218,25 +229,46 @@ private fun buildActionMenu(
internal fun MainScreenPreview() {
AppThemeSurface {
MainScreen(
timerText = "00:00",
timerVisible = true,
onTimerClosePress = {},
onFlashlightPress = {},
flashlightActive = true,
showBrightDisplayButton = true,
onBrightDisplayPress = {},
showSosButton = true,
sosActive = false,
onSosButtonPress = {},
showStroboscopeButton = true,
stroboscopeActive = false,
onStroboscopeButtonPress = {},
showBrightnessBar = false,
brightnessBarValue = 0f,
onBrightnessBarValueChange = {},
showStroboscopeBar = false,
stroboscopeBarValue = 0f,
onStroboscopeBarValueChange = {},
flashlightButton = {
FlashlightButton(
onFlashlightPress = {},
flashlightActive = true,
)
},
brightDisplayButton = {
BrightDisplayButton(
onBrightDisplayPress = {}
)
},
sosButton = {
SosButton(
sosActive = false,
onSosButtonPress = {},
)
},
stroboscopeButton = {
StroboscopeButton(
stroboscopeActive = false,
onStroboscopeButtonPress = {},
)
},
slidersSection = {
MainScreenSlidersSection(
showBrightnessBar = false,
brightnessBarValue = 0f,
onBrightnessBarValueChange = {},
showStroboscopeBar = false,
stroboscopeBarValue = 0f,
onStroboscopeBarValueChange = {},
)
},
sleepTimer = {
AnimatedSleepTimer(
timerText = "00:00",
timerVisible = true,
onTimerClosePress = {},
)
},
showMoreApps = true,
openSettings = {},
openAbout = {},

View File

@ -1,5 +1,8 @@
package com.simplemobiletools.flashlight.views
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
@ -61,6 +64,26 @@ internal fun SleepTimer(
}
}
@Composable
internal fun AnimatedSleepTimer(
modifier: Modifier = Modifier,
timerText: String,
timerVisible: Boolean,
onTimerClosePress: () -> Unit
) {
AnimatedVisibility(
modifier = modifier,
visible = timerVisible && timerText.isNotEmpty(),
enter = fadeIn(),
exit = fadeOut()
) {
SleepTimer(
timerText = timerText,
onCloseClick = onTimerClosePress
)
}
}
@Composable
@MyDevices
internal fun SleepTimerPreview() {