feat: Implement an alarm sound picker in the Settings screen
Closes: #36
This commit is contained in:
@@ -7,9 +7,18 @@
|
|||||||
|
|
||||||
package org.nsh07.pomodoro.ui.settingsScreen
|
package org.nsh07.pomodoro.ui.settingsScreen
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.RingtoneManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.Settings
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.horizontalScroll
|
import androidx.compose.foundation.horizontalScroll
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -45,6 +54,7 @@ import androidx.compose.material3.TopAppBar
|
|||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberSliderState
|
import androidx.compose.material3.rememberSliderState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -54,6 +64,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.tooling.preview.Devices
|
import androidx.compose.ui.tooling.preview.Devices
|
||||||
@@ -68,7 +79,6 @@ import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
|||||||
import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors
|
import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors
|
||||||
import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors
|
import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors
|
||||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.bottomListItemShape
|
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.bottomListItemShape
|
||||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.cardShape
|
|
||||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.middleListItemShape
|
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.middleListItemShape
|
||||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape
|
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape
|
||||||
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
||||||
@@ -132,6 +142,41 @@ private fun SettingsScreen(
|
|||||||
checkedIconColor = colorScheme.primary,
|
checkedIconColor = colorScheme.primary,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var selectedSoundUri by remember { mutableStateOf<Uri?>(Settings.System.DEFAULT_ALARM_ALERT_URI) }
|
||||||
|
var selectedSoundName by remember { mutableStateOf("...") }
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
// 2. The Activity Result Launcher
|
||||||
|
val ringtonePickerLauncher = rememberLauncherForActivityResult(
|
||||||
|
contract = ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
// This block is executed when the user picks a sound and returns to the app
|
||||||
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
|
val uri =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
result.data?.getParcelableExtra(
|
||||||
|
RingtoneManager.EXTRA_RINGTONE_PICKED_URI,
|
||||||
|
Uri::class.java
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
result.data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
|
||||||
|
}
|
||||||
|
selectedSoundUri = uri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. The Intent to launch the picker
|
||||||
|
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
|
||||||
|
// We want to show only alarm sounds
|
||||||
|
putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM)
|
||||||
|
// A title for the picker
|
||||||
|
putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Alarm sound")
|
||||||
|
|
||||||
|
// If a sound is already selected, show it as checked
|
||||||
|
putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, selectedSoundUri)
|
||||||
|
}
|
||||||
|
|
||||||
val switchItems = remember(alarmEnabled, vibrateEnabled) {
|
val switchItems = remember(alarmEnabled, vibrateEnabled) {
|
||||||
listOf(
|
listOf(
|
||||||
SettingsSwitchItem(
|
SettingsSwitchItem(
|
||||||
@@ -151,6 +196,12 @@ private fun SettingsScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(selectedSoundUri) {
|
||||||
|
selectedSoundName =
|
||||||
|
RingtoneManager.getRingtone(context, selectedSoundUri)
|
||||||
|
.getTitle(context)
|
||||||
|
}
|
||||||
|
|
||||||
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
|
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
@@ -266,7 +317,20 @@ private fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors = listItemColors,
|
colors = listItemColors,
|
||||||
modifier = Modifier.clip(cardShape)
|
modifier = Modifier.clip(topListItemShape)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
leadingContent = {
|
||||||
|
Icon(painterResource(R.drawable.alarm), null)
|
||||||
|
},
|
||||||
|
headlineContent = { Text("Alarm sound") },
|
||||||
|
supportingContent = { Text(selectedSoundName) },
|
||||||
|
colors = listItemColors,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(bottomListItemShape)
|
||||||
|
.clickable(onClick = { ringtonePickerLauncher.launch(intent) })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item { Spacer(Modifier.height(12.dp)) }
|
item { Spacer(Modifier.height(12.dp)) }
|
||||||
|
|||||||
Reference in New Issue
Block a user