-
-
Notifications
You must be signed in to change notification settings - Fork 271
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* desktop: custom time picker * text color * formatting * changes in UI * optimization * desktop: opening SimpleX links inside the app (#3738) * 5.5: ios 194, android 175, desktop 26 * docs: update downloads page * ui: fix chat preview showing incorrect timestamp when chat is empty (#3739) * ui: align call buttons with calls preference (#3740) * ui: deleted item preview (#3726) --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com> Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
- Loading branch information
1 parent
da9a7f4
commit bd30b80
Showing
5 changed files
with
276 additions
and
256 deletions.
There are no files selected for viewing
106 changes: 106 additions & 0 deletions
106
...mmon/src/androidMain/kotlin/chat/simplex/common/views/helpers/CustomTimePicker.android.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package chat.simplex.common.views.helpers | ||
|
||
import androidx.compose.foundation.layout.* | ||
import androidx.compose.material.MaterialTheme | ||
import androidx.compose.material.Text | ||
import androidx.compose.runtime.* | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.unit.dp | ||
import androidx.compose.ui.unit.sp | ||
import chat.simplex.common.model.CustomTimeUnit | ||
import chat.simplex.common.ui.theme.DEFAULT_PADDING | ||
import com.sd.lib.compose.wheel_picker.* | ||
|
||
@Composable | ||
actual fun CustomTimePicker( | ||
selection: MutableState<Int>, | ||
timeUnitsLimits: List<TimeUnitLimits> | ||
) { | ||
fun getUnitValues(unit: CustomTimeUnit, selectedValue: Int): List<Int> { | ||
val unitLimits = timeUnitsLimits.firstOrNull { it.timeUnit == unit } ?: TimeUnitLimits.defaultUnitLimits(unit) | ||
val regularUnitValues = (unitLimits.minValue..unitLimits.maxValue).toList() | ||
return regularUnitValues + if (regularUnitValues.contains(selectedValue)) emptyList() else listOf(selectedValue) | ||
} | ||
|
||
val (unit, duration) = CustomTimeUnit.toTimeUnit(selection.value) | ||
val selectedUnit: MutableState<CustomTimeUnit> = remember { mutableStateOf(unit) } | ||
val selectedDuration = remember { mutableStateOf(duration) } | ||
val selectedUnitValues = remember { mutableStateOf(getUnitValues(selectedUnit.value, selectedDuration.value)) } | ||
val isTriggered = remember { mutableStateOf(false) } | ||
|
||
LaunchedEffect(selectedUnit.value) { | ||
// on initial composition, if passed selection doesn't fit into picker bounds, so that selectedDuration is bigger than selectedUnit maxValue | ||
// (e.g., for selection = 121 seconds: selectedUnit would be Second, selectedDuration would be 121 > selectedUnit maxValue of 120), | ||
// selectedDuration would've been replaced by maxValue - isTriggered check prevents this by skipping LaunchedEffect on initial composition | ||
if (isTriggered.value) { | ||
val maxValue = timeUnitsLimits.firstOrNull { it.timeUnit == selectedUnit.value }?.maxValue | ||
if (maxValue != null && selectedDuration.value > maxValue) { | ||
selectedDuration.value = maxValue | ||
selectedUnitValues.value = getUnitValues(selectedUnit.value, selectedDuration.value) | ||
} else { | ||
selectedUnitValues.value = getUnitValues(selectedUnit.value, selectedDuration.value) | ||
selection.value = selectedUnit.value.toSeconds * selectedDuration.value | ||
} | ||
} else { | ||
isTriggered.value = true | ||
} | ||
} | ||
|
||
LaunchedEffect(selectedDuration.value) { | ||
selection.value = selectedUnit.value.toSeconds * selectedDuration.value | ||
} | ||
|
||
Row( | ||
Modifier | ||
.fillMaxWidth() | ||
.padding(horizontal = DEFAULT_PADDING), | ||
horizontalArrangement = Arrangement.spacedBy(0.dp) | ||
) { | ||
Column(Modifier.weight(1f)) { | ||
val durationPickerState = rememberFWheelPickerState(selectedUnitValues.value.indexOf(selectedDuration.value)) | ||
FVerticalWheelPicker( | ||
count = selectedUnitValues.value.count(), | ||
state = durationPickerState, | ||
unfocusedCount = 2, | ||
focus = { | ||
FWheelPickerFocusVertical(dividerColor = MaterialTheme.colors.primary) | ||
} | ||
) { index -> | ||
Text( | ||
selectedUnitValues.value[index].toString(), | ||
fontSize = 18.sp, | ||
color = MaterialTheme.colors.primary | ||
) | ||
} | ||
LaunchedEffect(durationPickerState) { | ||
snapshotFlow { durationPickerState.currentIndex } | ||
.collect { | ||
selectedDuration.value = selectedUnitValues.value[it] | ||
} | ||
} | ||
} | ||
Column(Modifier.weight(1f)) { | ||
val unitPickerState = rememberFWheelPickerState(timeUnitsLimits.indexOfFirst { it.timeUnit == selectedUnit.value }) | ||
FVerticalWheelPicker( | ||
count = timeUnitsLimits.count(), | ||
state = unitPickerState, | ||
unfocusedCount = 2, | ||
focus = { | ||
FWheelPickerFocusVertical(dividerColor = MaterialTheme.colors.primary) | ||
} | ||
) { index -> | ||
Text( | ||
timeUnitsLimits[index].timeUnit.text, | ||
fontSize = 18.sp, | ||
color = MaterialTheme.colors.primary | ||
) | ||
} | ||
LaunchedEffect(unitPickerState) { | ||
snapshotFlow { unitPickerState.currentIndex } | ||
.collect { | ||
selectedUnit.value = timeUnitsLimits[it].timeUnit | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.