feat: Themes, WiP

This commit is contained in:
Stefan Schüller 2022-02-12 16:41:30 +01:00
parent 5518b96c46
commit 604a813b84
14 changed files with 147 additions and 91 deletions

View File

@ -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)

View File

@ -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"

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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>
}

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

@ -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
)

View File

@ -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
)
}
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>