Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.219.*] Pre-release merge #693

Merged
merged 7 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,23 @@ class MainActivity : ComponentActivity() {

FileKit.init(this)

enableEdgeToEdge(
statusBarStyle = SystemBarStyle.dark(Color.TRANSPARENT),
navigationBarStyle = SystemBarStyle.dark(Color.TRANSPARENT)
)
enableEdgeToEdge()

val activityComponent = ActivityComponent::class.create(activity = this)

setContent { activityComponent.app() }
setContent {
activityComponent.app { useDarkTheme ->
enableEdgeToEdge(
statusBarStyle =
if (useDarkTheme) {
SystemBarStyle.dark(Color.TRANSPARENT)
} else {
SystemBarStyle.light(Color.TRANSPARENT, Color.TRANSPARENT)
},
navigationBarStyle = SystemBarStyle.dark(Color.TRANSPARENT)
)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class SettingsRepository(private val dataStore: DataStore<Preferences>) {
private val showReaderViewKey = booleanPreferencesKey("pref_show_reader_view")
private val feedsViewModeKey = stringPreferencesKey("pref_feeds_view_mode")
private val feedsSortOrderKey = stringPreferencesKey("pref_feeds_sort_order")
private val appThemeModeKey = stringPreferencesKey("pref_app_theme_mode")

val browserType: Flow<BrowserType> =
dataStore.data.map { preferences ->
Expand Down Expand Up @@ -73,6 +74,11 @@ class SettingsRepository(private val dataStore: DataStore<Preferences>) {
mapToFeedsOrderBy(preferences[feedsSortOrderKey]) ?: FeedsOrderBy.Latest
}

val appThemeMode: Flow<AppThemeMode> =
dataStore.data.map { preferences ->
mapToAppThemeMode(preferences[appThemeModeKey]) ?: AppThemeMode.Auto
}

suspend fun updateFeedsSortOrder(value: FeedsOrderBy) {
dataStore.edit { preferences -> preferences[feedsSortOrderKey] = value.name }
}
Expand Down Expand Up @@ -109,6 +115,15 @@ class SettingsRepository(private val dataStore: DataStore<Preferences>) {
dataStore.edit { preferences -> preferences[feedsViewModeKey] = value.name }
}

suspend fun updateAppTheme(value: AppThemeMode) {
dataStore.edit { preferences -> preferences[appThemeModeKey] = value.name }
}

private fun mapToAppThemeMode(pref: String?): AppThemeMode? {
if (pref.isNullOrBlank()) return null
return AppThemeMode.valueOf(pref)
}

private fun mapToFeedsOrderBy(pref: String?): FeedsOrderBy? {
if (pref.isNullOrBlank()) return null
return FeedsOrderBy.valueOf(pref)
Expand All @@ -135,6 +150,12 @@ class SettingsRepository(private val dataStore: DataStore<Preferences>) {
}
}

enum class AppThemeMode {
Light,
Dark,
Auto
}

enum class BrowserType {
Default,
InApp
Expand Down
2 changes: 1 addition & 1 deletion iosApp/iosApp/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,6 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Dark</string>
<string>Automatic</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ function updateStyles(colors) {
padding-top: 16px;
color: ${colors.textColor};
font-family: 'Golos Text', sans-serif;
overflow-wrap: break-word;
}
a {
color: ${colors.linkColor};
Expand Down
67 changes: 56 additions & 11 deletions shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/app/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@
*/
package dev.sasikanth.rss.reader.app

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.SheetValue
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import coil3.ImageLoader
import coil3.annotation.ExperimentalCoilApi
Expand All @@ -33,9 +38,7 @@ import com.arkivanov.essenty.backhandler.BackHandler
import dev.sasikanth.rss.reader.about.ui.AboutScreen
import dev.sasikanth.rss.reader.addfeed.ui.AddFeedScreen
import dev.sasikanth.rss.reader.bookmarks.ui.BookmarksScreen
import dev.sasikanth.rss.reader.components.DynamicContentTheme
import dev.sasikanth.rss.reader.components.LocalDynamicColorState
import dev.sasikanth.rss.reader.components.rememberDynamicColorState
import dev.sasikanth.rss.reader.data.repository.AppThemeMode
import dev.sasikanth.rss.reader.feed.ui.FeedInfoBottomSheet
import dev.sasikanth.rss.reader.group.ui.GroupScreen
import dev.sasikanth.rss.reader.groupselection.ui.GroupSelectionSheet
Expand All @@ -49,11 +52,17 @@ import dev.sasikanth.rss.reader.search.ui.SearchScreen
import dev.sasikanth.rss.reader.settings.ui.SettingsScreen
import dev.sasikanth.rss.reader.share.LocalShareHandler
import dev.sasikanth.rss.reader.share.ShareHandler
import dev.sasikanth.rss.reader.ui.DynamicContentTheme
import dev.sasikanth.rss.reader.ui.LocalDynamicColorState
import dev.sasikanth.rss.reader.ui.darkAppColorScheme
import dev.sasikanth.rss.reader.ui.lightAppColorScheme
import dev.sasikanth.rss.reader.ui.rememberDynamicColorState
import dev.sasikanth.rss.reader.util.DispatchersProvider
import dev.sasikanth.rss.reader.utils.LocalWindowSizeClass
import me.tatarka.inject.annotations.Assisted
import me.tatarka.inject.annotations.Inject

typealias App = @Composable () -> Unit
typealias App = @Composable (onThemeChange: (useDarkTheme: Boolean) -> Unit) -> Unit

@Inject
@Composable
Expand All @@ -64,18 +73,36 @@ fun App(
linkHandler: LinkHandler,
imageLoader: ImageLoader,
dispatchersProvider: DispatchersProvider,
@Assisted onThemeChange: (useDarkTheme: Boolean) -> Unit
) {
setSingletonImageLoaderFactory { imageLoader }

val dynamicColorState = rememberDynamicColorState(imageLoader = imageLoader)
val appState by appPresenter.state.collectAsState()
val dynamicColorState =
rememberDynamicColorState(
defaultLightAppColorScheme = lightAppColorScheme(),
defaultDarkAppColorScheme = darkAppColorScheme(),
)

CompositionLocalProvider(
LocalWindowSizeClass provides calculateWindowSizeClass(),
LocalDynamicColorState provides dynamicColorState,
LocalShareHandler provides shareHandler,
LocalLinkHandler provides linkHandler
LocalLinkHandler provides linkHandler,
LocalDynamicColorState provides dynamicColorState,
) {
DynamicContentTheme(dynamicColorState) {
val isSystemInDarkTheme = isSystemInDarkTheme()
val useDarkTheme =
remember(isSystemInDarkTheme) {
when (appState.appThemeMode) {
AppThemeMode.Light -> false
AppThemeMode.Dark -> true
AppThemeMode.Auto -> isSystemInDarkTheme
}
}

LaunchedEffect(useDarkTheme) { onThemeChange(useDarkTheme) }

DynamicContentTheme(useDarkTheme = useDarkTheme) {
ProvideStrings {
Box {
Children(
Expand All @@ -93,7 +120,21 @@ fun App(
PlaceholderScreen(modifier = fillMaxSizeModifier)
}
is Screen.Home -> {
HomeScreen(homePresenter = screen.presenter, modifier = fillMaxSizeModifier)
HomeScreen(
homePresenter = screen.presenter,
useDarkTheme = useDarkTheme,
modifier = fillMaxSizeModifier,
onBottomSheetStateChanged = { sheetValue ->
val tempUseDarkTheme =
if (sheetValue == SheetValue.Expanded) {
true
} else {
useDarkTheme
}

onThemeChange(tempUseDarkTheme)
}
)
}
is Screen.Search -> {
SearchScreen(searchPresenter = screen.presenter, modifier = fillMaxSizeModifier)
Expand All @@ -118,10 +159,14 @@ fun App(
)
}
is Screen.AddFeed -> {
AddFeedScreen(presenter = screen.presenter, modifier = fillMaxSizeModifier)
DynamicContentTheme(useDarkTheme = true) {
AddFeedScreen(presenter = screen.presenter, modifier = fillMaxSizeModifier)
}
}
is Screen.GroupDetails -> {
GroupScreen(presenter = screen.presenter, modifier = fillMaxSizeModifier)
DynamicContentTheme(useDarkTheme = true) {
GroupScreen(presenter = screen.presenter, modifier = fillMaxSizeModifier)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,15 @@ import dev.sasikanth.rss.reader.util.DispatchersProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -89,7 +96,8 @@ class AppPresenter(
PresenterInstance(
dispatchersProvider = dispatchersProvider,
lastUpdatedAt = lastUpdatedAt,
rssRepository = rssRepository
rssRepository = rssRepository,
settingsRepository = settingsRepository,
)
}

Expand All @@ -113,6 +121,8 @@ class AppPresenter(
childFactory = ::createModal,
)

internal val state = presenterInstance.state

private val scope = coroutineScope(dispatchersProvider.main + SupervisorJob())

init {
Expand Down Expand Up @@ -262,10 +272,24 @@ class AppPresenter(
private class PresenterInstance(
dispatchersProvider: DispatchersProvider,
private val lastUpdatedAt: LastUpdatedAt,
private val rssRepository: RssRepository
private val rssRepository: RssRepository,
private val settingsRepository: SettingsRepository,
) : InstanceKeeper.Instance {

private val coroutineScope = CoroutineScope(SupervisorJob() + dispatchersProvider.main)
private val _state = MutableStateFlow(AppState.DEFAULT)
val state: StateFlow<AppState> =
_state.stateIn(
scope = coroutineScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = AppState.DEFAULT
)

init {
settingsRepository.appThemeMode
.onEach { appThemeMode -> _state.update { it.copy(appThemeMode = appThemeMode) } }
.launchIn(coroutineScope)
}

fun refreshFeedsIfExpired() {
coroutineScope.launch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sasikanth.rss.reader.home

sealed interface HomeEffect {
package dev.sasikanth.rss.reader.app

data object MinimizeSheet : HomeEffect
import dev.sasikanth.rss.reader.data.repository.AppThemeMode

data class AppState(val appThemeMode: AppThemeMode) {

companion object {
val DEFAULT = AppState(appThemeMode = AppThemeMode.Auto)
}
}
Loading