Merge pull request #24 from Myzel394/add-theme-selsection

Add theme selection
This commit is contained in:
Myzel394 2023-10-22 15:21:36 +02:00 committed by GitHub
commit 3345ee6eb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 225 additions and 9 deletions

View File

@ -6,10 +6,15 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.datastore.dataStore import androidx.datastore.dataStore
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.db.AppSettingsSerializer import app.myzel394.alibi.db.AppSettingsSerializer
import app.myzel394.alibi.ui.Navigation import app.myzel394.alibi.ui.Navigation
import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY
import app.myzel394.alibi.ui.theme.AlibiTheme import app.myzel394.alibi.ui.theme.AlibiTheme
const val SETTINGS_FILE = "settings.json" const val SETTINGS_FILE = "settings.json"
@ -25,6 +30,24 @@ class MainActivity : AppCompatActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
setContent { setContent {
val dataStore = LocalContext.current.dataStore
val settings = dataStore
.data
.collectAsState(initial = AppSettings.getDefaultInstance())
.value
LaunchedEffect(settings.theme) {
if (!SUPPORTS_DARK_MODE_NATIVELY) {
val currentValue = AppCompatDelegate.getDefaultNightMode()
if (settings.theme == AppSettings.Theme.LIGHT && currentValue != AppCompatDelegate.MODE_NIGHT_NO) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
} else if (settings.theme == AppSettings.Theme.DARK && currentValue != AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
}
}
AlibiTheme { AlibiTheme {
Navigation() Navigation()
} }

View File

@ -16,6 +16,7 @@ data class AppSettings(
val audioRecorderSettings: AudioRecorderSettings = AudioRecorderSettings(), val audioRecorderSettings: AudioRecorderSettings = AudioRecorderSettings(),
val hasSeenOnboarding: Boolean = false, val hasSeenOnboarding: Boolean = false,
val showAdvancedSettings: Boolean = false, val showAdvancedSettings: Boolean = false,
val theme: Theme = Theme.SYSTEM,
) { ) {
fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings { fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings {
return copy(showAdvancedSettings = showAdvancedSettings) return copy(showAdvancedSettings = showAdvancedSettings)
@ -29,6 +30,16 @@ data class AppSettings(
return copy(hasSeenOnboarding = hasSeenOnboarding) return copy(hasSeenOnboarding = hasSeenOnboarding)
} }
fun setTheme(theme: Theme): AppSettings {
return copy(theme = theme)
}
enum class Theme {
SYSTEM,
LIGHT,
DARK,
}
companion object { companion object {
fun getDefaultInstance(): AppSettings = AppSettings() fun getDefaultInstance(): AppSettings = AppSettings()
} }
@ -167,6 +178,7 @@ data class AudioRecorderSettings(
MediaRecorder.OutputFormat.AAC_ADTS MediaRecorder.OutputFormat.AAC_ADTS
} }
} }
MediaRecorder.AudioEncoder.OPUS -> { MediaRecorder.AudioEncoder.OPUS -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaRecorder.OutputFormat.OGG MediaRecorder.OutputFormat.OGG
@ -174,6 +186,7 @@ data class AudioRecorderSettings(
MediaRecorder.OutputFormat.AAC_ADTS MediaRecorder.OutputFormat.AAC_ADTS
} }
} }
else -> MediaRecorder.OutputFormat.DEFAULT else -> MediaRecorder.OutputFormat.DEFAULT
} }
} }
@ -202,8 +215,7 @@ data class AudioRecorderSettings(
else -> 48000 else -> 48000
} }
fun getEncoder(): Int = encoder ?: fun getEncoder(): Int = encoder ?: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
MediaRecorder.AudioEncoder.AAC MediaRecorder.AudioEncoder.AAC
else else
MediaRecorder.AudioEncoder.AMR_NB MediaRecorder.AudioEncoder.AMR_NB

View File

@ -1,6 +1,8 @@
package app.myzel394.alibi.ui package app.myzel394.alibi.ui
import android.os.Build
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
val BIG_PRIMARY_BUTTON_SIZE = 64.dp val BIG_PRIMARY_BUTTON_SIZE = 64.dp
val MAX_AMPLITUDE = 20000 val MAX_AMPLITUDE = 20000
val SUPPORTS_DARK_MODE_NATIVELY = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q

View File

@ -0,0 +1,174 @@
package app.myzel394.alibi.ui.components.SettingsScreen.atoms
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Mic
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
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.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.navOptions
import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings
import kotlinx.coroutines.launch
@Composable
fun Preview(
modifier: Modifier = Modifier,
backgroundColor: Color,
primaryColor: Color,
textColor: Color,
onSelect: () -> Unit,
isSelected: Boolean = false,
) {
Box(
modifier = modifier,
contentAlignment = Alignment.Center,
) {
Column(
modifier = Modifier
.width(100.dp)
.height(200.dp)
.clip(shape = RoundedCornerShape(10.dp))
.border(width = 1.dp, color = textColor, shape = RoundedCornerShape(10.dp))
.background(backgroundColor)
.clickable { onSelect() },
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween,
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
Box(
modifier = Modifier
.width(30.dp)
.height(10.dp)
.clip(shape = RoundedCornerShape(10.dp))
.background(primaryColor)
)
Box(
modifier = Modifier
.size(10.dp)
.clip(shape = RoundedCornerShape(10.dp))
.background(primaryColor)
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Icon(
Icons.Default.Mic,
contentDescription = null,
tint = primaryColor,
)
Box(
modifier = Modifier
.width(40.dp)
.height(6.dp)
.clip(shape = RoundedCornerShape(10.dp))
.background(primaryColor)
)
Box(
modifier = Modifier
.width(75.dp)
.height(10.dp)
.clip(shape = RoundedCornerShape(10.dp))
.background(textColor)
)
}
Box {}
}
if (isSelected) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxSize(),
) {
Icon(
Icons.Default.CheckCircle,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier
.size(30.dp),
)
}
}
}
}
@Composable
fun ThemeSelector() {
val scope = rememberCoroutineScope()
val dataStore = LocalContext.current.dataStore
val settings = dataStore
.data
.collectAsState(initial = AppSettings.getDefaultInstance())
.value
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Preview(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
backgroundColor = Color(0xFFF0F0F0),
primaryColor = Color(0xFFAAAAAA),
textColor = Color(0xFFCCCCCC),
onSelect = {
scope.launch {
dataStore.updateData {
it.setTheme(AppSettings.Theme.LIGHT)
}
}
},
isSelected = settings.theme == AppSettings.Theme.LIGHT,
)
Preview(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
backgroundColor = Color(0xFF444444),
primaryColor = Color(0xFF888888),
textColor = Color(0xFF606060),
onSelect = {
scope.launch {
dataStore.updateData {
it.setTheme(AppSettings.Theme.DARK)
}
}
},
isSelected = settings.theme == AppSettings.Theme.DARK,
)
}
}

View File

@ -35,6 +35,7 @@ import androidx.navigation.NavController
import app.myzel394.alibi.R import app.myzel394.alibi.R
import app.myzel394.alibi.dataStore import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.BitrateTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.BitrateTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.EncoderTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.EncoderTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.ForceExactMaxDurationTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.ForceExactMaxDurationTile
@ -43,6 +44,7 @@ import app.myzel394.alibi.ui.components.SettingsScreen.atoms.IntervalDurationTil
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.MaxDurationTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.MaxDurationTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.OutputFormatTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.OutputFormatTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.SamplingRateTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.SamplingRateTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.ThemeSelector
import app.myzel394.alibi.ui.components.atoms.GlobalSwitch import app.myzel394.alibi.ui.components.atoms.GlobalSwitch
import app.myzel394.alibi.ui.components.atoms.MessageBox import app.myzel394.alibi.ui.components.atoms.MessageBox
import app.myzel394.alibi.ui.components.atoms.MessageType import app.myzel394.alibi.ui.components.atoms.MessageType
@ -107,6 +109,9 @@ fun SettingsScreen(
message = stringResource(R.string.ui_settings_hint_recordingActive_message), message = stringResource(R.string.ui_settings_hint_recordingActive_message),
) )
} }
if (!SUPPORTS_DARK_MODE_NATIVELY) {
ThemeSelector()
}
GlobalSwitch( GlobalSwitch(
label = stringResource(R.string.ui_settings_advancedSettings_label), label = stringResource(R.string.ui_settings_advancedSettings_label),
checked = settings.showAdvancedSettings, checked = settings.showAdvancedSettings,