feat: Themes, WiP
This commit is contained in:
parent
5518b96c46
commit
604a813b84
1
TODO.md
1
TODO.md
|
@ -29,6 +29,7 @@ x CI pipeline (gradle?)
|
|||
- Add NSFW filter
|
||||
- Translate all strings
|
||||
- Swipe player down and up
|
||||
- implement preferences using data stores
|
||||
|
||||
Issues:
|
||||
- Server change doesn't work until restart (retrofit)
|
||||
|
|
|
@ -3,8 +3,7 @@ package net.schueller.peertube.common
|
|||
object Constants {
|
||||
|
||||
const val PREF_LANG_APP_KEY = "pref_language_app"
|
||||
const val PREF_THEME_KEY = "pref_theme"
|
||||
const val PREF_DARK_MODE_KEY = "pref_dark_mode"
|
||||
|
||||
const val PREF_SHOW_NSFW_KEY = "pref_show_nsfw"
|
||||
const val PREF_VIDEO_LANG_KEY = "pref_show_nsfw"
|
||||
const val PREF_VIDEO_SPEED_KEY = "pref_video_speed"
|
||||
|
@ -43,7 +42,14 @@ object Constants {
|
|||
|
||||
const val APP_BACKGROUND_AUDIO_INTENT = "BACKGROUND_AUDIO"
|
||||
|
||||
const val PREF_THEME_KEY = "pref_theme"
|
||||
const val PREF_DARK_MODE_KEY = "pref_dark_mode_2"
|
||||
const val PREF_DARK_MODE_DARK = "dark"
|
||||
const val PREF_DARK_MODE_LIGHT = "light"
|
||||
const val PREF_DARK_MODE_AUTO = "auto"
|
||||
|
||||
// legacy color prefs
|
||||
const val COLOR_PREF_DEFAULT = "AppTheme.RED"
|
||||
const val COLOR_PREF_RED = "AppTheme.RED"
|
||||
const val COLOR_PREF_PINK = "AppTheme.PINK"
|
||||
const val COLOR_PREF_PURPLE = "AppTheme.PURPLE"
|
||||
|
|
|
@ -19,6 +19,8 @@ import net.schueller.peertube.feature_server_address.domain.repository.ServerAdd
|
|||
import net.schueller.peertube.feature_server_address.domain.repository.ServerRepository
|
||||
import net.schueller.peertube.feature_video.domain.repository.VideoRepository
|
||||
import net.schueller.peertube.feature_server_address.domain.use_case.*
|
||||
import net.schueller.peertube.feature_settings.settings.data.repository.SettingsRepositoryImpl
|
||||
import net.schueller.peertube.feature_settings.settings.domain.repository.SettingsRepository
|
||||
import net.schueller.peertube.feature_video.data.remote.auth.LoginService
|
||||
import net.schueller.peertube.feature_video.data.remote.auth.Session
|
||||
import net.schueller.peertube.feature_video.data.repository.RetrofitInstance
|
||||
|
@ -78,6 +80,12 @@ object AppModule {
|
|||
return VideoRepositoryImpl(api)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSettingsRepository(@ApplicationContext context: Context): SettingsRepository {
|
||||
return SettingsRepositoryImpl(context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideServerInstanceApi(): ServerInstanceApi {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package net.schueller.peertube.feature_settings.settings.data.repository
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import net.schueller.peertube.feature_settings.settings.domain.repository.SettingsRepository
|
||||
import net.schueller.peertube.presentation.dataStore
|
||||
|
||||
class SettingsRepositoryImpl(private val context: Context) : SettingsRepository {
|
||||
|
||||
override suspend fun getBooleanSettings(key: String, default: Boolean): Flow<Boolean> {
|
||||
val dataStoreKey = booleanPreferencesKey(key)
|
||||
return context.dataStore.data.map { preferences ->
|
||||
preferences[dataStoreKey] ?: default
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getStringSettings(key: String, default: String): Flow<String> {
|
||||
val dataStoreKey = stringPreferencesKey(key)
|
||||
return context.dataStore.data.map { preferences ->
|
||||
preferences[dataStoreKey] ?: default
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getIntegerSettings(key: String, default: Int): Flow<Int> {
|
||||
val dataStoreKey = intPreferencesKey(key)
|
||||
return context.dataStore.data.map { preferences ->
|
||||
preferences[dataStoreKey] ?: default
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package net.schueller.peertube.feature_settings.settings.domain.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface SettingsRepository {
|
||||
|
||||
suspend fun getBooleanSettings(key: String, default: Boolean): Flow<Boolean>
|
||||
suspend fun getStringSettings(key: String, default: String): Flow<String>
|
||||
suspend fun getIntegerSettings(key: String, default: Int): Flow<Int>
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.schueller.peertube.feature_settings.settings
|
||||
package net.schueller.peertube.feature_settings.settings.presentation
|
||||
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -7,7 +7,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.jamal.composeprefs.ui.GroupHeader
|
||||
import com.jamal.composeprefs.ui.PrefsScreen
|
||||
import com.jamal.composeprefs.ui.prefs.*
|
||||
import net.schueller.peertube.presentation.dataStore
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
|
@ -15,6 +16,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
|||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
@ -35,6 +37,7 @@ import net.schueller.peertube.feature_video.presentation.video.components.appBar
|
|||
import net.schueller.peertube.feature_video.presentation.video.components.videoPlay.VideoPlayScreen
|
||||
import net.schueller.peertube.feature_video.presentation.video.events.VideoPlayEvent
|
||||
import net.schueller.peertube.feature_video.presentation.video.player.ExoPlayerHolder
|
||||
import net.schueller.peertube.presentation.ui.theme.PeertubeTheme
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
|
|
|
@ -15,10 +15,8 @@ import android.os.Bundle
|
|||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
|
@ -27,7 +25,6 @@ import androidx.navigation.compose.NavHost
|
|||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import coil.annotation.ExperimentalCoilApi
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import com.google.android.exoplayer2.ui.PlayerNotificationManager
|
||||
|
@ -40,7 +37,7 @@ import net.schueller.peertube.common.Constants.PREF_BACKGROUND_STOP_KEY
|
|||
import net.schueller.peertube.common.Constants.PREF_BACK_PAUSE_KEY
|
||||
import net.schueller.peertube.common.VideoHelper
|
||||
import net.schueller.peertube.feature_server_address.presentation.address_add_edit.AddEditAddressScreen
|
||||
import net.schueller.peertube.feature_settings.settings.SettingsScreen
|
||||
import net.schueller.peertube.feature_settings.settings.presentation.SettingsScreen
|
||||
import net.schueller.peertube.presentation.ui.theme.PeertubeTheme
|
||||
import net.schueller.peertube.feature_video.presentation.video.VideoListScreen
|
||||
import net.schueller.peertube.feature_server_address.presentation.ServerAddressScreen
|
||||
|
@ -64,7 +61,8 @@ class MainActivity : ComponentActivity() {
|
|||
|
||||
@OptIn(ExperimentalPermissionsApi::class,
|
||||
androidx.compose.material.ExperimentalMaterialApi::class,
|
||||
androidx.compose.ui.ExperimentalComposeUiApi::class
|
||||
androidx.compose.ui.ExperimentalComposeUiApi::class,
|
||||
coil.annotation.ExperimentalCoilApi::class
|
||||
)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -95,7 +93,9 @@ class MainActivity : ComponentActivity() {
|
|||
// }
|
||||
// )
|
||||
|
||||
Surface(color = MaterialTheme.colors.background) {
|
||||
Surface(
|
||||
color = MaterialTheme.colors.background
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
NavHost(
|
||||
navController = navController,
|
||||
|
|
|
@ -1,97 +1,78 @@
|
|||
package net.schueller.peertube.presentation.ui.theme
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import net.schueller.peertube.common.Constants
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import net.schueller.peertube.common.Constants.COLOR_PREF_BLUE
|
||||
import net.schueller.peertube.common.Constants.COLOR_PREF_GREEN
|
||||
import net.schueller.peertube.common.Constants.COLOR_PREF_RED
|
||||
import net.schueller.peertube.presentation.dataStore
|
||||
|
||||
import net.schueller.peertube.common.Constants.PREF_DARK_MODE_AUTO
|
||||
import net.schueller.peertube.common.Constants.PREF_DARK_MODE_DARK
|
||||
|
||||
@Composable
|
||||
fun PeertubeTheme(
|
||||
useDarkTheme: Boolean = isSystemInDarkTheme(),
|
||||
viewModel: ThemeViewModel = hiltViewModel(),
|
||||
content: @Composable() () -> Unit
|
||||
) {
|
||||
|
||||
val context = LocalContext.current
|
||||
val sharedPreferences = context.getSharedPreferences(context.packageName + "_preferences", Context.MODE_PRIVATE)
|
||||
|
||||
|
||||
// TODO: get pref out of dataStore, migrate old prefs
|
||||
// LocalContext.current.dataStore.data.map {
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// val EXAMPLE_COUNTER = booleanPreferencesKey(Constants.PREF_DARK_MODE_KEY)
|
||||
// val useDarkMode: Flow<Boolean> = LocalContext.current.dataStore.data
|
||||
// .map { preferences ->
|
||||
// preferences[EXAMPLE_COUNTER] ?: useDarkTheme
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
val useDarkMode = sharedPreferences.getBoolean(
|
||||
Constants.PREF_DARK_MODE_KEY,
|
||||
val useDarkMode = if (viewModel.themeState.value.darkMode == PREF_DARK_MODE_AUTO) {
|
||||
useDarkTheme
|
||||
)
|
||||
|
||||
Log.v("TH", "userdark: "+useDarkMode)
|
||||
|
||||
val theme = sharedPreferences.getString(
|
||||
Constants.PREF_THEME_KEY,
|
||||
COLOR_PREF_BLUE
|
||||
)
|
||||
Log.v("TH", "theme: "+theme)
|
||||
} else viewModel.themeState.value.darkMode == PREF_DARK_MODE_DARK
|
||||
|
||||
Log.v("TH", "useDarkMode : "+useDarkMode)
|
||||
Log.v("TH", "viewModel : "+viewModel.themeState.value.currentTheme)
|
||||
|
||||
// Support existing saved preferences in older version
|
||||
// https://material-foundation.github.io/material-theme-builder/
|
||||
val colors = if (!useDarkMode) {
|
||||
when (theme) {
|
||||
when (viewModel.themeState.value.currentTheme) {
|
||||
COLOR_PREF_BLUE -> {
|
||||
Log.v("TH", "use COLOR_PREF_BLUE : "+COLOR_PREF_BLUE)
|
||||
|
||||
net.schueller.peertube.presentation.ui.theme.colors.blue.LightThemeColors
|
||||
}
|
||||
COLOR_PREF_RED -> {
|
||||
Log.v("TH", "use COLOR_PREF_RED : "+COLOR_PREF_RED)
|
||||
|
||||
net.schueller.peertube.presentation.ui.theme.colors.red.LightThemeColors
|
||||
}
|
||||
COLOR_PREF_GREEN -> {
|
||||
Log.v("TH", "use COLOR_PREF_GREEN : "+COLOR_PREF_GREEN)
|
||||
|
||||
net.schueller.peertube.presentation.ui.theme.colors.green.LightThemeColors
|
||||
}
|
||||
else -> {
|
||||
Log.v("TH", "else : ")
|
||||
|
||||
net.schueller.peertube.presentation.ui.theme.colors.def.LightThemeColors
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (theme) {
|
||||
when (viewModel.themeState.value.currentTheme) {
|
||||
COLOR_PREF_BLUE -> {
|
||||
Log.v("TH", "use COLOR_PREF_BLUE : "+COLOR_PREF_BLUE)
|
||||
net.schueller.peertube.presentation.ui.theme.colors.blue.DarkThemeColors
|
||||
}
|
||||
COLOR_PREF_RED -> {
|
||||
Log.v("TH", "use COLOR_PREF_RED : "+COLOR_PREF_RED)
|
||||
net.schueller.peertube.presentation.ui.theme.colors.red.DarkThemeColors
|
||||
}
|
||||
COLOR_PREF_GREEN -> {
|
||||
Log.v("TH", "use green : "+COLOR_PREF_GREEN)
|
||||
|
||||
Log.v("TH", "use COLOR_PREF_GREEN : "+COLOR_PREF_GREEN)
|
||||
net.schueller.peertube.presentation.ui.theme.colors.green.DarkThemeColors
|
||||
}
|
||||
else -> {
|
||||
Log.v("TH", "else : ")
|
||||
net.schueller.peertube.presentation.ui.theme.colors.def.DarkThemeColors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.v("TH", "colors : " + colors.primary)
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colors,
|
||||
typography = AppTypography,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package net.schueller.peertube.presentation.ui.theme
|
||||
|
||||
import net.schueller.peertube.common.Constants.COLOR_PREF_DEFAULT
|
||||
import net.schueller.peertube.common.Constants.PREF_DARK_MODE_AUTO
|
||||
|
||||
data class ThemeState(
|
||||
val darkMode: String = PREF_DARK_MODE_AUTO,
|
||||
val currentTheme: String = COLOR_PREF_DEFAULT
|
||||
)
|
|
@ -0,0 +1,39 @@
|
|||
package net.schueller.peertube.presentation.ui.theme
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import net.schueller.peertube.common.Constants.COLOR_PREF_DEFAULT
|
||||
import net.schueller.peertube.common.Constants.PREF_DARK_MODE_AUTO
|
||||
import net.schueller.peertube.common.Constants.PREF_DARK_MODE_KEY
|
||||
import net.schueller.peertube.common.Constants.PREF_THEME_KEY
|
||||
import net.schueller.peertube.feature_settings.settings.domain.repository.SettingsRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class ThemeViewModel @Inject constructor(private val settingsRepository: SettingsRepository): ViewModel() {
|
||||
|
||||
private val _themeState = mutableStateOf(ThemeState())
|
||||
val themeState: State<ThemeState> = _themeState
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
settingsRepository
|
||||
.getStringSettings(PREF_THEME_KEY, COLOR_PREF_DEFAULT).collect {
|
||||
_themeState.value = _themeState.value.copy(
|
||||
currentTheme = it
|
||||
)
|
||||
}
|
||||
settingsRepository
|
||||
.getStringSettings(PREF_DARK_MODE_KEY, PREF_DARK_MODE_AUTO).collect {
|
||||
_themeState.value = _themeState.value.copy(
|
||||
darkMode = it
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.Peertube" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_200</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/black</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_200</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
|
@ -1,10 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
|
@ -1,17 +1,6 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.Peertube" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<style name="Theme.Peertube" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:statusBarColor">@android:color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Peertube.NoActionBar">
|
||||
|
@ -19,7 +8,4 @@
|
|||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Peertube.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
|
||||
<style name="Theme.Peertube.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||
</resources>
|
Loading…
Reference in New Issue