Skip to content

Commit

Permalink
Fix: Timer screen layout
Browse files Browse the repository at this point in the history
  • Loading branch information
SuhasDissa committed Mar 25, 2024
1 parent 09ffb8c commit 2000e8d
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 116 deletions.
12 changes: 8 additions & 4 deletions app/src/main/java/com/bnyro/clock/ui/components/NumberKeypad.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,32 @@ fun NumberKeypad(
verticalArrangement = Arrangement.spacedBy(buttonSpacing)
) {
Row(
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
horizontalArrangement = Arrangement.spacedBy(buttonSpacing),
modifier = Modifier.weight(1f)
) {
NumPadButton(number = "1", buttonSize, onOperation)
NumPadButton(number = "2", buttonSize, onOperation)
NumPadButton(number = "3", buttonSize, onOperation)
}
Row(
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
horizontalArrangement = Arrangement.spacedBy(buttonSpacing),
modifier = Modifier.weight(1f)
) {
NumPadButton(number = "4", buttonSize, onOperation)
NumPadButton(number = "5", buttonSize, onOperation)
NumPadButton(number = "6", buttonSize, onOperation)
}
Row(
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
horizontalArrangement = Arrangement.spacedBy(buttonSpacing),
modifier = Modifier.weight(1f)
) {
NumPadButton(number = "7", buttonSize, onOperation)
NumPadButton(number = "8", buttonSize, onOperation)
NumPadButton(number = "9", buttonSize, onOperation)
}
Row(
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
horizontalArrangement = Arrangement.spacedBy(buttonSpacing),
modifier = Modifier.weight(1f)
) {
NumPadButton(number = "00", buttonSize, onOperation)
NumPadButton(number = "0", buttonSize, onOperation)
Expand Down
253 changes: 141 additions & 112 deletions app/src/main/java/com/bnyro/clock/ui/screens/TimerScreen.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bnyro.clock.ui.screens

import android.content.Context
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
Expand Down Expand Up @@ -28,11 +29,15 @@ import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Save
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.AddAlarm
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
Expand All @@ -58,7 +63,7 @@ import com.bnyro.clock.ui.model.TimerModel
import com.bnyro.clock.ui.nav.TopBarScaffold
import com.bnyro.clock.util.Preferences

@OptIn(ExperimentalFoundationApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimerScreen(onClickSettings: () -> Unit, timerModel: TimerModel) {
val context = LocalContext.current
Expand All @@ -72,129 +77,37 @@ fun TimerScreen(onClickSettings: () -> Unit, timerModel: TimerModel) {
mutableStateOf(false)
}

TopBarScaffold(title = stringResource(R.string.timer), onClickSettings, fab = {
if (timerModel.scheduledObjects.isEmpty() || createNew) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
TopBarScaffold(title = stringResource(R.string.timer), onClickSettings, actions = {
if (timerModel.scheduledObjects.isEmpty()) {
ClickableIcon(
imageVector = Icons.Rounded.AddAlarm,
contentDescription = stringResource(R.string.add_preset_timer)
) {
if (timerModel.scheduledObjects.isNotEmpty()) {
SmallFloatingActionButton(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
onClick = { createNew = false }
) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null)
}
Spacer(Modifier.height(8.dp))
}
FloatingActionButton(
onClick = {
createNew = false
timerModel.startTimer(context)
}
) {
Icon(imageVector = Icons.Default.PlayArrow, contentDescription = null)
}
timerModel.addPersistentTimer(timerModel.timePickerSeconds)
}
} else {
FloatingActionButton(
modifier = Modifier,
onClick = { createNew = true }
) {
Icon(imageVector = Icons.Default.Create, contentDescription = null)
}
}
}, actions = {
if (timerModel.scheduledObjects.isEmpty() || createNew) {
ClickableIcon(
imageVector = Icons.Rounded.AddAlarm,
imageVector = Icons.Rounded.Add,
contentDescription = stringResource(R.string.add_preset_timer)
) {
timerModel.addPersistentTimer(timerModel.timePickerSeconds)
createNew = true
}
}
}) { paddingValues ->
if (timerModel.scheduledObjects.isEmpty() || createNew) {
if (timerModel.scheduledObjects.isEmpty()) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
horizontalAlignment = Alignment.CenterHorizontally
Modifier
.padding(paddingValues)
) {
if (!useScrollPicker) {
Row(
Modifier
.fillMaxWidth()
.weight(2f),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TimePickerDial(timerModel)
}
} else {
Column(
modifier = Modifier.weight(3f),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
FormattedTimerTime(
seconds = timerModel.timePickerFakeUnits,
modifier = Modifier.padding(bottom = 32.dp)
)
NumberKeypad(
onOperation = { operation ->
when (operation) {
is NumberKeypadOperation.AddNumber -> timerModel.addNumber(
operation.number
)

is NumberKeypadOperation.Delete -> timerModel.deleteLastNumber()
is NumberKeypadOperation.Clear -> timerModel.clear()
}
}
)
}
}
if (showExampleTimers) {
val haptic = LocalHapticFeedback.current
LazyVerticalGrid(
modifier = Modifier
.fillMaxWidth(),
columns = GridCells.Adaptive(100.dp),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
itemsIndexed(items = timerModel.persistentTimers) { index, timer ->
Box(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.combinedClickable(
onClick = {
timerModel.timePickerSeconds = timer.seconds
createNew = false
timerModel.startTimer(context)
},
onLongClick = {
haptic.performHapticFeedback(
HapticFeedbackType.LongPress
)
timerModel.removePersistentTimer(index)
}
)
.width(100.dp)
.background(MaterialTheme.colorScheme.secondaryContainer)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
Text(
timer.formattedTime,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
}
}
TimerPicker(
useScrollPicker,
timerModel,
showExampleTimers,
context,
onCreateNew = {
createNew = false
}
}
)
}
} else {
LazyColumn(
Expand All @@ -209,4 +122,120 @@ fun TimerScreen(onClickSettings: () -> Unit, timerModel: TimerModel) {
}
}
}

if (createNew) {
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
ModalBottomSheet(
onDismissRequest = { createNew = false },
sheetState = sheetState
) {
TimerPicker(
useScrollPicker,
timerModel,
showExampleTimers,
context,
onCreateNew = {
createNew = false
}
)
}
}
}

@Composable
@OptIn(ExperimentalFoundationApi::class)
private fun TimerPicker(
useScrollPicker: Boolean,
timerModel: TimerModel,
showExampleTimers: Boolean,
context: Context,
onCreateNew: () -> Unit
) {
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
if (!useScrollPicker) {
Row(
Modifier
.fillMaxWidth()
.weight(2f),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TimePickerDial(timerModel)
}
} else {
Column(
modifier = Modifier.weight(3f),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
FormattedTimerTime(
seconds = timerModel.timePickerFakeUnits,
modifier = Modifier.padding(bottom = 32.dp)
)
NumberKeypad(
onOperation = { operation ->
when (operation) {
is NumberKeypadOperation.AddNumber -> timerModel.addNumber(
operation.number
)

is NumberKeypadOperation.Delete -> timerModel.deleteLastNumber()
is NumberKeypadOperation.Clear -> timerModel.clear()
}
}
)
}
}
if (showExampleTimers) {
val haptic = LocalHapticFeedback.current
LazyVerticalGrid(
modifier = Modifier
.fillMaxWidth(),
columns = GridCells.Adaptive(100.dp),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
itemsIndexed(items = timerModel.persistentTimers) { index, timer ->
Box(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.combinedClickable(
onClick = {
timerModel.timePickerSeconds = timer.seconds
onCreateNew.invoke()
timerModel.startTimer(context)
},
onLongClick = {
haptic.performHapticFeedback(
HapticFeedbackType.LongPress
)
timerModel.removePersistentTimer(index)
}
)
.width(100.dp)
.background(MaterialTheme.colorScheme.secondaryContainer)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
Text(
timer.formattedTime,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
}
}
}
}
Button(modifier = Modifier.padding(vertical = 16.dp), onClick = {
onCreateNew.invoke()
timerModel.startTimer(context)
}) {
Text(text = stringResource(R.string.start), style = MaterialTheme.typography.titleLarge)
}
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,5 @@
<string name="lap_time">Lap Time</string>
<string name="overall_time">Overall Time</string>
<string name="add_preset_timer">Add preset timer</string>
<string name="start">Start</string>
</resources>

0 comments on commit 2000e8d

Please sign in to comment.