From aa161071ac5a0629f1e5c7e382103bbdbd86e064 Mon Sep 17 00:00:00 2001 From: TheRealPad Date: Sun, 7 Jul 2024 17:56:38 +0200 Subject: [PATCH 1/2] refactor(style travel): update style of travel page --- .../com/eipsaferoad/owl/components/Button.kt | 2 +- .../eipsaferoad/owl/components/Draggeable.kt | 12 +- .../eipsaferoad/owl/presentation/home/Home.kt | 109 ++++++++++-------- .../owl/presentation/settings/Settings.kt | 28 ++++- app/src/main/res/drawable/logout.png | Bin 0 -> 11076 bytes 5 files changed, 94 insertions(+), 57 deletions(-) create mode 100644 app/src/main/res/drawable/logout.png diff --git a/app/src/main/java/com/eipsaferoad/owl/components/Button.kt b/app/src/main/java/com/eipsaferoad/owl/components/Button.kt index e58de08..8fd0d95 100644 --- a/app/src/main/java/com/eipsaferoad/owl/components/Button.kt +++ b/app/src/main/java/com/eipsaferoad/owl/components/Button.kt @@ -38,7 +38,7 @@ fun Button(type: ButtonTypeEnum, content: @Composable () -> Unit, action: () -> Column( modifier = Modifier .fillMaxSize() - .clip(shape = RoundedCornerShape(20.dp)) + .clip(shape = RoundedCornerShape(100.dp)) .background(backgroundColor) .clickable { action() }, verticalArrangement = Arrangement.Center, diff --git a/app/src/main/java/com/eipsaferoad/owl/components/Draggeable.kt b/app/src/main/java/com/eipsaferoad/owl/components/Draggeable.kt index e292b89..a93771f 100644 --- a/app/src/main/java/com/eipsaferoad/owl/components/Draggeable.kt +++ b/app/src/main/java/com/eipsaferoad/owl/components/Draggeable.kt @@ -8,9 +8,9 @@ import androidx.compose.ui.Modifier import com.eipsaferoad.owl.models.Alarm fun Modifier.handleDraggableModifier( - lastPosX: Float, - vibrationVal: Float, - nbrPixelToMove: Int, + lastPosX: MutableState, + vibrationVal: MutableState, + nbrPixelToMove: MutableState, alarms: MutableState, dragLeft: (value: Float) -> Unit, dragRight: (value: Float) -> Unit, @@ -19,12 +19,12 @@ fun Modifier.handleDraggableModifier( return this.pointerInput(Unit) { detectDragGestures { change, dragAmount -> change.consume() - if (lastPosX == 0.0f) { + if (lastPosX.value == 0.0f) { init(change.position.x) } - if (change.previousPosition.x < change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && vibrationVal < alarms.value.vibration.max.toFloat()) { + if (change.previousPosition.x < change.position.x && abs(lastPosX.value - change.position.x) > nbrPixelToMove.value && vibrationVal.value < alarms.value.vibration.max.toFloat()) { dragRight(change.position.x) - } else if (change.previousPosition.x > change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && vibrationVal > alarms.value.vibration.min) { + } else if (change.previousPosition.x > change.position.x && abs(lastPosX.value - change.position.x) > nbrPixelToMove.value && vibrationVal.value > alarms.value.vibration.min) { dragLeft(change.position.x) } println(vibrationVal) diff --git a/app/src/main/java/com/eipsaferoad/owl/presentation/home/Home.kt b/app/src/main/java/com/eipsaferoad/owl/presentation/home/Home.kt index 9f26a7d..3f50cf7 100644 --- a/app/src/main/java/com/eipsaferoad/owl/presentation/home/Home.kt +++ b/app/src/main/java/com/eipsaferoad/owl/presentation/home/Home.kt @@ -8,8 +8,10 @@ import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -19,6 +21,8 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Clear @@ -26,9 +30,11 @@ import androidx.compose.material.icons.rounded.Favorite import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush @@ -58,6 +64,11 @@ import com.eipsaferoad.owl.utils.LocalStorage import com.eipsaferoad.owl.utils.getVibrationEffects import com.eipsaferoad.owl.utils.soundPlayer import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalWindowInfo +import androidx.compose.ui.res.painterResource @Composable fun Home(currentHeartRate: MutableState, context: Context, navController: NavHostController, alarms: MutableState, mVibrator: Vibrator) { @@ -70,16 +81,51 @@ fun Home(currentHeartRate: MutableState, context: Context, navController @Composable fun NoAlarm(currentHeartRate: String, context: Context, navController: NavHostController) { + val lazyListState = rememberLazyListState( + initialFirstVisibleItemIndex = 1 + ) + Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { LazyColumn( + state = lazyListState, modifier = Modifier.height(200.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { + item { + Column( + modifier = Modifier.padding(top = 80.dp, start = 10.dp, end = 10.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Button( + type = ButtonTypeEnum.REDIRECTION, + content = { + Text( + fontSize = 17.sp, + text = "DISCONNECTION", + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(vertical = 10.dp) + ) + }, + action = { + LocalStorage.deleteData(context, EnvEnum.EMAIL.value) + LocalStorage.deleteData(context, EnvEnum.PASSWORD.value) + navController.navigate(PagesEnum.LOGIN.value) + } + ) + Image( + painter = painterResource(id = R.drawable.logout), + contentDescription = "logout", + modifier = Modifier + .size(30.dp) + .padding(top = 10.dp) + ) + } + } item { Column( modifier = Modifier.padding(bottom = 100.dp, top = 70.dp), @@ -98,47 +144,29 @@ fun NoAlarm(currentHeartRate: String, context: Context, navController: NavHostCo } } item { - Buttons(context = context, navController = navController) + Column( + modifier = Modifier.padding(bottom = 60.dp, start = 10.dp, end = 10.dp) + ) { + Button( + type = ButtonTypeEnum.PRIMARY, + content = { + Text( + fontSize = 30.sp, + text = "ALARM", + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(vertical = 15.dp) + ) + }, + action = { + navController.navigate(PagesEnum.SETTINGS.value) + } + ) + } } } } } -@Composable -fun Buttons(context: Context, navController: NavHostController) { - Column( - modifier = Modifier.padding(bottom = 40.dp), - verticalArrangement = Arrangement.spacedBy(10.dp) - ) { - Button( - type = ButtonTypeEnum.PRIMARY, - content = { - Text( - fontSize = 30.sp, - text = "ALARM" - ) - }, - action = { - navController.navigate(PagesEnum.SETTINGS.value) - } - ) - Button( - type = ButtonTypeEnum.REDIRECTION, - content = { - Text( - fontSize = 17.sp, - text = "DISCONNECTION", - ) - }, - action = { - LocalStorage.deleteData(context, EnvEnum.EMAIL.value) - LocalStorage.deleteData(context, EnvEnum.PASSWORD.value) - navController.navigate(PagesEnum.LOGIN.value) - } - ) - } -} - @Composable fun MultiColorBorderCircularColumn( borderColors: List, @@ -301,15 +329,6 @@ fun PreviewHome() { }*/ } -@Composable -@Preview -fun PreviewButtons() { - val navController = rememberSwipeDismissableNavController() - OwlTheme { - Buttons(LocalContext.current, navController) - } -} - @Composable @Preview(device = Devices.WEAR_OS_LARGE_ROUND, showSystemUi = true) fun PreviewAlarm() { diff --git a/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt b/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt index 1da60f4..94373ca 100644 --- a/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt +++ b/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt @@ -85,7 +85,7 @@ fun saveOnServer(apiUrl: String, accessToken: String?, alarms: Alarm) { Request.makeRequest( "$apiUrl/api/alarmPreferences", Request.Companion.REQUEST_TYPE.PUT, - {}, + { println("data save on server") }, headers, jsonBody, ) @@ -128,14 +128,13 @@ fun AlarmButton(context: Context, alarms: MutableState, apiUrl: String, a } } -@OptIn(ExperimentalFoundationApi::class) @Composable fun VibrationButton(context: Context, alarms: MutableState, mVibrator: Vibrator, apiUrl: String, accessToken: String?) { var isVibrationSelected by remember { mutableStateOf(false) } var isVibrationActivate by remember { mutableStateOf(alarms.value.vibration.isActivate) } var vibrationVal by remember { mutableStateOf(alarms.value.vibration.actual) } var lastPosX by remember { mutableStateOf(0.0f) } - val nbrPixelToMove = 70 + val nbrPixelToMove by remember { mutableStateOf(70) } DisposableEffect(isVibrationActivate, vibrationVal) { onDispose { @@ -219,12 +218,12 @@ fun VibrationButton(context: Context, alarms: MutableState, mVibrator: Vi println("up") vibrationVal += 1f lastPosX = change.position.x - /*mVibrator.vibrate(getVibrationEffects()[alarms.value.vibration.actual.toInt()])*/ + mVibrator.vibrate(getVibrationEffects()[alarms.value.vibration.actual.toInt()]) } else if (change.previousPosition.x > change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && vibrationVal > alarms.value.vibration.min.toFloat()) { println("down") vibrationVal -= 1f lastPosX = change.position.x - /*mVibrator.vibrate(getVibrationEffects()[alarms.value.vibration.actual.toInt()])*/ + mVibrator.vibrate(getVibrationEffects()[alarms.value.vibration.actual.toInt()]) } println(vibrationVal) } @@ -257,6 +256,8 @@ fun SoundButton(alarms: MutableState, context: Context, apiUrl: String, a var soundVal by remember { mutableStateOf(alarms.value.sound.actual) } var isVibrationSelected by remember { mutableStateOf(false) } var isSoundSelected by remember { mutableStateOf(false) } + var lastPosX by remember { mutableStateOf(0.0f) } + val nbrPixelToMove by remember { mutableStateOf(40) } DisposableEffect(isSoundActivate, soundVal) { onDispose { @@ -333,6 +334,23 @@ fun SoundButton(alarms: MutableState, context: Context, apiUrl: String, a LinearProgressIndicator( progress = soundVal / (alarms.value.sound.max - alarms.value.sound.min), modifier = Modifier + .pointerInput(Unit) { + detectDragGestures { change, dragAmount -> + change.consume() + if (lastPosX == 0.0f) { + lastPosX = change.position.x + } + if (change.previousPosition.x < change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && soundVal < alarms.value.sound.max.toFloat()) { + soundVal += 0.2f + lastPosX = change.position.x + soundPlayer(context, soundVal, fileId = R.raw.alarm_test) + } else if (change.previousPosition.x > change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && soundVal > alarms.value.sound.min.toFloat()) { + soundVal -= 0.2f + lastPosX = change.position.x + soundPlayer(context, soundVal, fileId = R.raw.alarm_test) + } + } + } .height(5.dp), color = MaterialTheme.colorScheme.secondary ) diff --git a/app/src/main/res/drawable/logout.png b/app/src/main/res/drawable/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..1443cdf29eff4b19f118915bdee955452b4a82f2 GIT binary patch literal 11076 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 Dqj#Aa literal 0 HcmV?d00001 From e6e28dbd85c45b1016f186179e57f522d040c55e Mon Sep 17 00:00:00 2001 From: TheRealPad Date: Wed, 10 Jul 2024 19:52:51 +0200 Subject: [PATCH 2/2] fix(api call): fix api call to save alarms: --- .../owl/components/ToggleSwitch.kt | 10 +- .../owl/presentation/settings/Settings.kt | 103 +++++++++++++----- app/src/main/res/drawable/sound.png | Bin 0 -> 14711 bytes app/src/main/res/drawable/vibration.png | Bin 0 -> 10517 bytes 4 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 app/src/main/res/drawable/sound.png create mode 100644 app/src/main/res/drawable/vibration.png diff --git a/app/src/main/java/com/eipsaferoad/owl/components/ToggleSwitch.kt b/app/src/main/java/com/eipsaferoad/owl/components/ToggleSwitch.kt index a31b280..98f3ecd 100644 --- a/app/src/main/java/com/eipsaferoad/owl/components/ToggleSwitch.kt +++ b/app/src/main/java/com/eipsaferoad/owl/components/ToggleSwitch.kt @@ -12,16 +12,18 @@ import androidx.compose.ui.unit.dp import androidx.wear.compose.material.Switch import androidx.wear.compose.material.SwitchDefaults import com.eipsaferoad.owl.presentation.theme.md_theme_dark_tertiary +import com.eipsaferoad.owl.presentation.theme.md_theme_light_primary +import com.eipsaferoad.owl.presentation.theme.md_theme_light_secondary import com.eipsaferoad.owl.presentation.theme.md_theme_light_surface @Composable fun ToggleSwitch(isActivate: Boolean, action: (it: Boolean) -> Unit) { Switch( colors = SwitchDefaults.colors( - checkedThumbColor = md_theme_light_surface, - checkedTrackColor = md_theme_light_surface, - uncheckedThumbColor = md_theme_light_surface, - uncheckedTrackColor = md_theme_dark_tertiary + checkedThumbColor = md_theme_light_primary, + checkedTrackColor = md_theme_light_secondary, + uncheckedThumbColor = md_theme_light_primary, + uncheckedTrackColor = md_theme_light_secondary ), checked = isActivate, onCheckedChange = { diff --git a/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt b/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt index 94373ca..95bce58 100644 --- a/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt +++ b/app/src/main/java/com/eipsaferoad/owl/presentation/settings/Settings.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Build import android.os.Vibrator import androidx.annotation.RequiresApi +import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.detectDragGestures @@ -15,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape @@ -30,18 +32,23 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.wear.compose.material.Button import androidx.wear.compose.material.ButtonDefaults +import androidx.wear.compose.material.Icon import androidx.wear.compose.material.Text import com.eipsaferoad.owl.R import com.eipsaferoad.owl.api.Request import com.eipsaferoad.owl.components.ToggleSwitch import com.eipsaferoad.owl.components.handleDraggableModifier import com.eipsaferoad.owl.models.Alarm +import com.eipsaferoad.owl.presentation.theme.md_theme_light_onSurfaceVariant import com.eipsaferoad.owl.utils.EnvEnum import com.eipsaferoad.owl.utils.LocalStorage import com.eipsaferoad.owl.utils.getVibrationEffects @@ -77,7 +84,7 @@ fun saveOnServer(apiUrl: String, accessToken: String?, alarms: Alarm) { put("isVibrationActivate", alarms.vibration.isActivate) put("vibrationLevel", alarms.vibration.actual.toInt()) put("isSoundActivate", alarms.sound.isActivate) - put("soundLevel", alarms.sound.actual) + put("soundLevel", alarms.sound.actual.toInt()) put("music", alarms.music) put("iconId", alarms.iconId) }.toString() @@ -106,7 +113,7 @@ fun AlarmButton(context: Context, alarms: MutableState, apiUrl: String, a .width(200.dp) .height(40.dp), shape = RoundedCornerShape(10), - colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colorScheme.primary), + colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent), onClick = { alarms.value.isAlarmActivate = !alarms.value.isAlarmActivate } ) { Row( @@ -135,7 +142,9 @@ fun VibrationButton(context: Context, alarms: MutableState, mVibrator: Vi var vibrationVal by remember { mutableStateOf(alarms.value.vibration.actual) } var lastPosX by remember { mutableStateOf(0.0f) } val nbrPixelToMove by remember { mutableStateOf(70) } - + var heightBar by remember { mutableStateOf(10.dp) } + val animatedHeightBar by animateDpAsState(targetValue = heightBar) + DisposableEffect(isVibrationActivate, vibrationVal) { onDispose { var data = if (isVibrationActivate) "1" else "0" @@ -149,7 +158,7 @@ fun VibrationButton(context: Context, alarms: MutableState, mVibrator: Vi .width(200.dp) .height(if (isVibrationSelected) 80.dp else 40.dp), shape = RoundedCornerShape(10), - colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colorScheme.primary), + colors = ButtonDefaults.buttonColors(backgroundColor = md_theme_light_onSurfaceVariant), onClick = { isVibrationSelected = !isVibrationSelected } @@ -157,7 +166,7 @@ fun VibrationButton(context: Context, alarms: MutableState, mVibrator: Vi Column( modifier = Modifier .fillMaxSize() - .padding(top = if (isVibrationSelected) 0.dp else 10.dp, bottom = 10.dp), + .padding(top = 10.dp, bottom = 10.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.SpaceAround ) { @@ -178,19 +187,23 @@ fun VibrationButton(context: Context, alarms: MutableState, mVibrator: Vi saveOnServer(apiUrl, accessToken, alarms.value) } ) + } else { + Icon(painter = painterResource(id = R.drawable.vibration), contentDescription = "") } } if (isVibrationSelected) { Row( modifier = Modifier - .fillMaxWidth() - .padding(start = 10.dp, end = 10.dp), + .width(180.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { Text( text = "-", - modifier = Modifier.clickable { + fontSize = 30.sp, + modifier = Modifier + .padding(end = 10.dp) + .clickable { alarms.value.vibration.updateAlarm(false) saveOnServer(apiUrl, accessToken, alarms.value) if (vibrationVal > alarms.value.vibration.min.toFloat()) { @@ -201,40 +214,51 @@ fun VibrationButton(context: Context, alarms: MutableState, mVibrator: Vi ) Box( modifier = Modifier - .width(150.dp) - .height(5.dp) + .width(130.dp) + .height(animatedHeightBar) .clip(RoundedCornerShape(8.dp)) ) { LinearProgressIndicator( progress = vibrationVal / (alarms.value.vibration.max - alarms.value.vibration.min), modifier = Modifier .pointerInput(Unit) { - detectDragGestures { change, dragAmount -> + detectDragGestures( + onDragEnd = {heightBar = 10.dp} + ) { change, dragAmount -> change.consume() + heightBar = 20.dp if (lastPosX == 0.0f) { lastPosX = change.position.x } - if (change.previousPosition.x < change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && vibrationVal < alarms.value.vibration.max.toFloat()) { + if (change.previousPosition.x < change.position.x && abs( + lastPosX - change.position.x + ) > nbrPixelToMove && vibrationVal < alarms.value.vibration.max.toFloat() + ) { println("up") vibrationVal += 1f lastPosX = change.position.x mVibrator.vibrate(getVibrationEffects()[alarms.value.vibration.actual.toInt()]) - } else if (change.previousPosition.x > change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && vibrationVal > alarms.value.vibration.min.toFloat()) { + saveOnServer(apiUrl, accessToken, alarms.value) + } else if (change.previousPosition.x > change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && vibrationVal > alarms.value.vibration.min.toFloat() + ) { println("down") vibrationVal -= 1f lastPosX = change.position.x mVibrator.vibrate(getVibrationEffects()[alarms.value.vibration.actual.toInt()]) + saveOnServer(apiUrl, accessToken, alarms.value) } println(vibrationVal) } } - .height(5.dp), + .height(animatedHeightBar), color = MaterialTheme.colorScheme.secondary ) } Text( text = "+", + fontSize = 30.sp, modifier = Modifier + .padding(start = 5.dp) .clickable { alarms.value.vibration.updateAlarm() saveOnServer(apiUrl, accessToken, alarms.value) @@ -258,6 +282,8 @@ fun SoundButton(alarms: MutableState, context: Context, apiUrl: String, a var isSoundSelected by remember { mutableStateOf(false) } var lastPosX by remember { mutableStateOf(0.0f) } val nbrPixelToMove by remember { mutableStateOf(40) } + var heightBar by remember { mutableStateOf(10.dp) } + val animatedHeightBar by animateDpAsState(targetValue = heightBar) DisposableEffect(isSoundActivate, soundVal) { onDispose { @@ -272,7 +298,7 @@ fun SoundButton(alarms: MutableState, context: Context, apiUrl: String, a .width(200.dp) .height(if (isSoundSelected) 80.dp else 40.dp), shape = RoundedCornerShape(10), - colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colorScheme.primary), + colors = ButtonDefaults.buttonColors(backgroundColor = md_theme_light_onSurfaceVariant), onClick = { isSoundSelected = !isSoundSelected if (isVibrationSelected) { @@ -283,7 +309,7 @@ fun SoundButton(alarms: MutableState, context: Context, apiUrl: String, a Column( modifier = Modifier .fillMaxSize() - .padding(top = if (isSoundSelected) 0.dp else 10.dp, bottom = 10.dp), + .padding(top = 10.dp, bottom = 10.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.SpaceAround ) { @@ -304,19 +330,23 @@ fun SoundButton(alarms: MutableState, context: Context, apiUrl: String, a saveOnServer(apiUrl, accessToken, alarms.value) } ) + } else { + Icon(painter = painterResource(id = R.drawable.sound), contentDescription = "") } } if (isSoundSelected) { Row( modifier = Modifier - .fillMaxWidth() - .padding(start = 10.dp, end = 10.dp), + .width(180.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { Text( text = "-", - modifier = Modifier.clickable { + fontSize = 30.sp, + modifier = Modifier + .padding(end = 10.dp) + .clickable { alarms.value.sound.updateAlarm(false) saveOnServer(apiUrl, accessToken, alarms.value) if (soundVal > alarms.value.sound.min) { @@ -327,37 +357,56 @@ fun SoundButton(alarms: MutableState, context: Context, apiUrl: String, a ) Box( modifier = Modifier - .width(150.dp) - .height(5.dp) + .width(130.dp) + .height(animatedHeightBar) .clip(RoundedCornerShape(8.dp)) ) { LinearProgressIndicator( progress = soundVal / (alarms.value.sound.max - alarms.value.sound.min), modifier = Modifier .pointerInput(Unit) { - detectDragGestures { change, dragAmount -> + detectDragGestures( + onDragEnd = {heightBar = 10.dp} + ) { change, dragAmount -> change.consume() + heightBar = 20.dp if (lastPosX == 0.0f) { lastPosX = change.position.x } - if (change.previousPosition.x < change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && soundVal < alarms.value.sound.max.toFloat()) { + if (change.previousPosition.x < change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && soundVal < alarms.value.sound.max.toFloat() + ) { soundVal += 0.2f lastPosX = change.position.x - soundPlayer(context, soundVal, fileId = R.raw.alarm_test) - } else if (change.previousPosition.x > change.position.x && abs(lastPosX - change.position.x) > nbrPixelToMove && soundVal > alarms.value.sound.min.toFloat()) { + soundPlayer( + context, + soundVal, + fileId = R.raw.alarm_test + ) + saveOnServer(apiUrl, accessToken, alarms.value) + } else if (change.previousPosition.x > change.position.x && abs( + lastPosX - change.position.x + ) > nbrPixelToMove && soundVal > alarms.value.sound.min.toFloat() + ) { soundVal -= 0.2f lastPosX = change.position.x - soundPlayer(context, soundVal, fileId = R.raw.alarm_test) + soundPlayer( + context, + soundVal, + fileId = R.raw.alarm_test + ) + saveOnServer(apiUrl, accessToken, alarms.value) } } } - .height(5.dp), + .height(animatedHeightBar), color = MaterialTheme.colorScheme.secondary ) } Text( text = "+", + fontSize = 30.sp, modifier = Modifier + .padding(start = 10.dp) .clickable { alarms.value.sound.updateAlarm() saveOnServer(apiUrl, accessToken, alarms.value) diff --git a/app/src/main/res/drawable/sound.png b/app/src/main/res/drawable/sound.png new file mode 100644 index 0000000000000000000000000000000000000000..8afe81349342a7ceb9939a661c34fd646bc2a22c GIT binary patch literal 14711 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%0D$2_IuZmEx)p;D1OOPqMOX_sdhJUd7u!7u@J67k zcmeyM0?e}40AL77v*k3A9wNcx23|`Xinu z1ppfcrV7o7xN?9rVJn8U?VFxMai`(~ia*jRpCjqkE{+VCuWb}P!~DLr$fqiPubn{_>e^{9(` z`RL)V{mA!DpO+sk2~%Po26V6)Z`^F?Bly%78nt$0ROZb--+Lt8fbY^H7Y1O3jRV%6)j^;4E1SJJ;Nb0%#g2 zdQ|Thjaj3~0E1n{2-DE;j^GnKQYh8lC?d&tr~F7qF-hY_M%`P2&+~DgwG0UWe{c&U zW4yIW19!03`nF8Rd+=?lp2yk=8`*7>fv>Cyd0CxI&0(E`5vJ>Vd+m_rNg&dZt{UJ|OOSnv&S>@Li~(@%QlCc!Xf>-H1T z@US+oY>Ej24=~rRt&417AV|kbZ9sxi_|*m>LGW=#@8kQ+Jo0|S6~AT^O`je#6C9L$ z>S&MI>EQ zJDkZ9J`WA@8ZnbxWvRjLe{5w{fJ|l=^+|3oEBWg?F=6-ocVw_+@YmN#3KaEy}r9|!-n&hgp^Y@&pRnJ4vIuKQ=lL|>V?#hFu?A*22K4T>&x zTw=C}zhNnJ%kKF_6x(XPlbHtoH>OoJ=kk4ou)8uhu02)n@;3WKkGuZWtcX=TFMnHn zFIeNKhmM`U?flluYh$o9RBgWA&R;u5t+y>Q;;Z3)(#X_^y&ql z4${(KzR#OIb?(Cs%QHU(c~0_Ux*jmA96e&s>1wCHBGJ#Ir@%Ikw;I9zbj?PN`=7?W z+S=i#5MHY07Cx5{|2_{L6O^XTQmV5fDo(e2xG-36Zey24$kua~)XXjXEITXd`WY!n zO7fC9+7|r#sE)Sp>NbB#{V-RzbccPiKe&?RlH=3q;&W$*<#0r~CL*?ep*IvlkN&Z7 z(GbGp3ss_T*I(wPR?l1u1Di?KAyqDxO*=*HILX%*jd?oyp8{qgE8ZU#8{;I$ESUC( zJnFc;dfE>((6nMnJC4~s^*d6K8WHu{xg3d%M{Ym&iqg{rJ42FEGwqFLJiaPxkO&4E4nnBMF9BOknVdH`O`h;j^%bcs{{4bo__UW5Fs+rka zJ!CSm4P~(U3eA*F8x3OAjADN)-Di@0CpyI8P35hYPLnJD(|dIhZ!1vwUaE!W)j^9` Ru