Skip to content

Commit

Permalink
[1.54.*] Pre-release merge (#277)
Browse files Browse the repository at this point in the history
  • Loading branch information
tramline-github[bot] authored Feb 3, 2024
2 parents 0da2d77 + 39ca894 commit cab8f5b
Show file tree
Hide file tree
Showing 18 changed files with 708 additions and 137 deletions.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,8 @@ val EnTwineStrings =
openSourceDesc =
"Twine is built on open source technologies and is completely free to use, you can find the source code of Twine and some of my other popular projects on GitHub. Click here to head over there.",
markAsRead = "Mark as Read",
markAsUnRead = "Mark as Unread"
markAsUnRead = "Mark as Unread",
removeFeed = "Remove feed",
delete = "Delete",
removeFeedDesc = { "Do you want to remove \"${it}\"?" }
)
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ data class TwineStrings(
val openSource: String,
val openSourceDesc: String,
val markAsRead: String,
val markAsUnRead: String
val markAsUnRead: String,
val removeFeed: String,
val delete: String,
val removeFeedDesc: (String) -> String
)

object Locales {
Expand Down
73 changes: 46 additions & 27 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,23 +15,27 @@
*/
package dev.sasikanth.rss.reader.app

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
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.getValue
import androidx.compose.ui.Modifier
import coil3.ImageLoader
import coil3.annotation.ExperimentalCoilApi
import coil3.compose.setSingletonImageLoaderFactory
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.StackAnimation
import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
import com.arkivanov.essenty.backhandler.BackHandler
import dev.sasikanth.rss.reader.about.ui.AboutScreen
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.feed.ui.FeedInfoBottomSheet
import dev.sasikanth.rss.reader.home.ui.HomeScreen
import dev.sasikanth.rss.reader.platform.LinkHandler
import dev.sasikanth.rss.reader.platform.LocalLinkHandler
Expand Down Expand Up @@ -67,34 +71,49 @@ fun App(
) {
DynamicContentTheme(dynamicColorState) {
ProvideStrings {
Children(
modifier = Modifier.fillMaxSize(),
stack = appPresenter.screenStack,
animation =
backAnimation(
backHandler = appPresenter.backHandler,
onBack = appPresenter::onBackClicked
)
) { child ->
val fillMaxSizeModifier = Modifier.fillMaxSize()
when (val screen = child.instance) {
is Screen.Home -> {
HomeScreen(homePresenter = screen.presenter, modifier = fillMaxSizeModifier)
Box {
Children(
modifier = Modifier.fillMaxSize(),
stack = appPresenter.screenStack,
animation =
backAnimation(
backHandler = appPresenter.backHandler,
onBack = appPresenter::onBackClicked
)
) { child ->
val fillMaxSizeModifier = Modifier.fillMaxSize()
when (val screen = child.instance) {
is Screen.Home -> {
HomeScreen(homePresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.Search -> {
SearchScreen(searchPresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.Bookmarks -> {
BookmarksScreen(
bookmarksPresenter = screen.presenter,
modifier = fillMaxSizeModifier
)
}
is Screen.Settings -> {
SettingsScreen(settingsPresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.About -> {
AboutScreen(aboutPresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.Reader -> {
ReaderScreen(presenter = screen.presenter, modifier = fillMaxSizeModifier)
}
}
is Screen.Search -> {
SearchScreen(searchPresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.Bookmarks -> {
BookmarksScreen(bookmarksPresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.Settings -> {
SettingsScreen(settingsPresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.About -> {
AboutScreen(aboutPresenter = screen.presenter, modifier = fillMaxSizeModifier)
}
is Screen.Reader -> {
ReaderScreen(presenter = screen.presenter, modifier = fillMaxSizeModifier)
}

val modals by appPresenter.modalStack.subscribeAsState()
modals.child?.instance?.also { modal ->
when (modal) {
is Modals.FeedInfo ->
FeedInfoBottomSheet(
feedPresenter = modal.presenter,
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
package dev.sasikanth.rss.reader.app

import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.slot.ChildSlot
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
Expand All @@ -30,6 +35,7 @@ import com.arkivanov.essenty.parcelable.Parcelize
import dev.sasikanth.rss.reader.about.AboutPresenter
import dev.sasikanth.rss.reader.bookmarks.BookmarksPresenter
import dev.sasikanth.rss.reader.di.scopes.ActivityScope
import dev.sasikanth.rss.reader.feed.FeedPresenter
import dev.sasikanth.rss.reader.home.HomePresenter
import dev.sasikanth.rss.reader.reader.ReaderPresenter
import dev.sasikanth.rss.reader.refresh.LastUpdatedAt
Expand All @@ -50,6 +56,7 @@ private typealias HomePresenterFactory =
openBookmarks: () -> Unit,
openSettings: () -> Unit,
openPost: (String) -> Unit,
openFeedInfo: (String) -> Unit,
) -> HomePresenter

private typealias SearchPresentFactory =
Expand Down Expand Up @@ -86,6 +93,13 @@ private typealias ReaderPresenterFactory =
goBack: () -> Unit,
) -> ReaderPresenter

private typealias FeedPresenterFactory =
(
feedLink: String,
ComponentContext,
dismiss: () -> Unit,
) -> FeedPresenter

@Inject
@ActivityScope
class AppPresenter(
Expand All @@ -97,6 +111,7 @@ class AppPresenter(
private val settingsPresenter: SettingsPresenterFactory,
private val aboutPresenter: AboutPresenterFactory,
private val readerPresenter: ReaderPresenterFactory,
private val feedPresenter: FeedPresenterFactory,
private val lastUpdatedAt: LastUpdatedAt,
private val rssRepository: RssRepository
) : ComponentContext by componentContext {
Expand All @@ -111,6 +126,7 @@ class AppPresenter(
}

private val navigation = StackNavigation<Config>()
private val modalNavigation = SlotNavigation<ModalConfig>()

internal val screenStack: Value<ChildStack<*, Screen>> =
childStack(
Expand All @@ -120,6 +136,13 @@ class AppPresenter(
childFactory = ::createScreen,
)

internal val modalStack: Value<ChildSlot<*, Modals>> =
childSlot(
source = modalNavigation,
handleBackButton = true,
childFactory = ::createModal,
)

init {
lifecycle.doOnStart { presenterInstance.refreshFeedsIfExpired() }
}
Expand All @@ -128,6 +151,16 @@ class AppPresenter(
navigation.pop()
}

private fun createModal(modalConfig: ModalConfig, componentContext: ComponentContext): Modals =
when (modalConfig) {
is ModalConfig.FeedInfo -> {
Modals.FeedInfo(
presenter =
feedPresenter(modalConfig.feedLink, componentContext) { modalNavigation.dismiss() }
)
}
}

private fun createScreen(config: Config, componentContext: ComponentContext): Screen =
when (config) {
Config.Home -> {
Expand All @@ -138,7 +171,8 @@ class AppPresenter(
{ navigation.push(Config.Search) },
{ navigation.push(Config.Bookmarks) },
{ navigation.push(Config.Settings) },
{ navigation.push(Config.Reader(it)) }
{ navigation.push(Config.Reader(it)) },
{ modalNavigation.activate(ModalConfig.FeedInfo(it)) }
)
)
}
Expand Down Expand Up @@ -217,4 +251,8 @@ class AppPresenter(

@Parcelize data class Reader(val postLink: String) : Config
}

sealed interface ModalConfig : Parcelable {
@Parcelize data class FeedInfo(val feedLink: String) : ModalConfig
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2024 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.app

import dev.sasikanth.rss.reader.feed.FeedPresenter

internal sealed interface Modals {
class FeedInfo(val presenter: FeedPresenter) : Modals
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2024 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.components

import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import dev.sasikanth.rss.reader.resources.strings.LocalStrings
import dev.sasikanth.rss.reader.ui.AppTheme

@Composable
internal fun ConfirmFeedDeleteDialog(
feedName: String,
onRemoveFeed: () -> Unit,
dismiss: () -> Unit,
modifier: Modifier = Modifier,
) {
AlertDialog(
modifier = modifier,
onDismissRequest = dismiss,
confirmButton = {
TextButton(
onClick = {
onRemoveFeed()
dismiss()
},
shape = MaterialTheme.shapes.large
) {
Text(
text = LocalStrings.current.delete,
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.error
)
}
},
dismissButton = {
TextButton(onClick = dismiss, shape = MaterialTheme.shapes.large) {
Text(
text = LocalStrings.current.buttonCancel,
style = MaterialTheme.typography.labelLarge,
color = AppTheme.colorScheme.textEmphasisMed
)
}
},
title = {
Text(text = LocalStrings.current.removeFeed, color = AppTheme.colorScheme.textEmphasisMed)
},
text = {
Text(
text = LocalStrings.current.removeFeedDesc(feedName),
color = AppTheme.colorScheme.textEmphasisMed
)
},
containerColor = AppTheme.colorScheme.tintedSurface,
titleContentColor = AppTheme.colorScheme.onSurface,
textContentColor = AppTheme.colorScheme.onSurface,
)
}
Loading

0 comments on commit cab8f5b

Please sign in to comment.