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

Rss support #606

Merged
merged 8 commits into from
Jan 24, 2025
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
35 changes: 32 additions & 3 deletions app/src/main/java/dev/dimension/flare/data/model/TabSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import compose.icons.fontawesomeicons.solid.List
import compose.icons.fontawesomeicons.solid.MagnifyingGlass
import compose.icons.fontawesomeicons.solid.Message
import compose.icons.fontawesomeicons.solid.RectangleList
import compose.icons.fontawesomeicons.solid.Rss
import compose.icons.fontawesomeicons.solid.SquareRss
import compose.icons.fontawesomeicons.solid.Star
import compose.icons.fontawesomeicons.solid.Users
import dev.dimension.flare.R
Expand Down Expand Up @@ -96,7 +96,9 @@ sealed interface TitleType {
Favourite,
List,
Feeds,
DirectMessage, ;
DirectMessage,
Rss,
;

fun toId(): Int =
when (this) {
Expand All @@ -113,6 +115,7 @@ sealed interface TitleType {
List -> R.string.home_tab_list_title
Feeds -> R.string.home_tab_feeds_title
DirectMessage -> R.string.dm_list_title
Rss -> R.string.rss_title
}
}
}
Expand Down Expand Up @@ -148,6 +151,7 @@ sealed interface IconType {
List,
Feeds,
Messages,
Rss,
;

fun toIcon(): ImageVector =
Expand All @@ -167,8 +171,9 @@ sealed interface IconType {
Misskey -> FontAwesomeIcons.Brands.Misskey
Bluesky -> FontAwesomeIcons.Brands.Bluesky
List -> FontAwesomeIcons.Solid.List
Feeds -> FontAwesomeIcons.Solid.Rss
Feeds -> FontAwesomeIcons.Solid.SquareRss
Messages -> FontAwesomeIcons.Solid.Message
Rss -> FontAwesomeIcons.Solid.SquareRss
}
}
}
Expand Down Expand Up @@ -213,6 +218,13 @@ sealed interface TimelineTabItem : TabItem {
icon = IconType.Material(IconType.Material.MaterialIcon.Notification),
),
),
RssTabItem(
metaData =
TabMetaData(
title = TitleType.Localized(TitleType.Localized.LocalizedKey.Rss),
icon = IconType.Material(IconType.Material.MaterialIcon.Rss),
),
),
DiscoverTabItem(
account = AccountType.Active,
metaData =
Expand Down Expand Up @@ -241,6 +253,13 @@ sealed interface TimelineTabItem : TabItem {
icon = IconType.Material(IconType.Material.MaterialIcon.Home),
),
),
RssTabItem(
metaData =
TabMetaData(
title = TitleType.Localized(TitleType.Localized.LocalizedKey.Rss),
icon = IconType.Material(IconType.Material.MaterialIcon.Rss),
),
),
DiscoverTabItem(
account = AccountType.Guest,
metaData =
Expand Down Expand Up @@ -811,6 +830,16 @@ data class DirectMessageTabItem(
override fun update(metaData: TabMetaData): TabItem = copy(metaData = metaData)
}

@Serializable
data class RssTabItem(
override val metaData: TabMetaData,
) : TabItem {
override val account: AccountType = AccountType.Guest
override val key: String = "rss"

override fun update(metaData: TabMetaData): TabItem = copy(metaData = metaData)
}

@OptIn(ExperimentalSerializationApi::class)
private object TabSettingsSerializer : Serializer<TabSettings> {
override suspend fun readFrom(input: InputStream): TabSettings =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dev.dimension.flare.ui.component.status

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalUriHandler
import dev.dimension.flare.ui.component.NetworkImage
import dev.dimension.flare.ui.model.UiTimeline

@Composable
internal fun FeedComponent(
data: UiTimeline.ItemContent.Feed,
modifier: Modifier = Modifier,
) {
val uriHandler = LocalUriHandler.current
Column(
modifier =
modifier
.clickable {
uriHandler.openUri(data.url)
},
) {
data.image?.let {
NetworkImage(
model = it,
contentDescription = data.title,
modifier =
Modifier
.aspectRatio(16f / 9f)
.clip(
MaterialTheme.shapes.medium,
),
)
}
Text(
text = data.title,
style = MaterialTheme.typography.titleMedium,
)
data.description?.let {
Text(
text = it,
style = MaterialTheme.typography.bodyMedium,
maxLines = 2,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ private fun ItemContentComponent(
modifier
.padding(bottom = 8.dp),
)

is UiTimeline.ItemContent.Feed -> {
FeedComponent(
data = item,
modifier =
modifier
.padding(bottom = 8.dp),
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import com.ramcosta.composedestinations.generated.destinations.HomeTimelineRoute
import com.ramcosta.composedestinations.generated.destinations.ListScreenRouteDestination
import com.ramcosta.composedestinations.generated.destinations.MeRouteDestination
import com.ramcosta.composedestinations.generated.destinations.NotificationRouteDestination
import com.ramcosta.composedestinations.generated.destinations.RssRouteDestination
import com.ramcosta.composedestinations.generated.destinations.ServiceSelectRouteDestination
import com.ramcosta.composedestinations.generated.destinations.SettingsRouteDestination
import com.ramcosta.composedestinations.generated.destinations.TimelineRouteDestination
Expand All @@ -97,6 +98,7 @@ import dev.dimension.flare.data.model.DiscoverTabItem
import dev.dimension.flare.data.model.HomeTimelineTabItem
import dev.dimension.flare.data.model.NotificationTabItem
import dev.dimension.flare.data.model.ProfileTabItem
import dev.dimension.flare.data.model.RssTabItem
import dev.dimension.flare.data.model.SettingsTabItem
import dev.dimension.flare.data.model.TabItem
import dev.dimension.flare.data.model.TimelineTabItem
Expand Down Expand Up @@ -652,6 +654,7 @@ private fun getDirection(
is AllListTabItem -> ListScreenRouteDestination(accountType)
is Bluesky.FeedsTabItem -> BlueskyFeedsRouteDestination(accountType)
is DirectMessageTabItem -> DMScreenRouteDestination(accountType)
is RssTabItem -> RssRouteDestination
}

@Composable
Expand Down
79 changes: 79 additions & 0 deletions app/src/main/java/dev/dimension/flare/ui/screen/rss/RssScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package dev.dimension.flare.ui.screen.rss

import android.os.Parcelable
import androidx.activity.compose.BackHandler
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.layout.AnimatedPane
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
import androidx.compose.runtime.Composable
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.CreateRssSourceRouteDestination
import com.ramcosta.composedestinations.generated.destinations.EditRssSourceRouteDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import dev.dimension.flare.ui.component.ThemeWrapper
import kotlinx.parcelize.Parcelize

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Destination<RootGraph>(
wrappers = [ThemeWrapper::class],
)
@Composable
internal fun RssRoute(navigator: DestinationsNavigator) {
RssScreen(
navigator = navigator,
)
}

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
private fun RssScreen(navigator: DestinationsNavigator) {
val scaffoldNavigator =
rememberListDetailPaneScaffoldNavigator<RssPaneNavArgs>()
BackHandler(
scaffoldNavigator.canNavigateBack(),
) {
scaffoldNavigator.navigateBack()
}
ListDetailPaneScaffold(
directive = scaffoldNavigator.scaffoldDirective,
value = scaffoldNavigator.scaffoldValue,
listPane = {
AnimatedPane {
RssSourcesScreen(
onAdd = {
navigator.navigate(CreateRssSourceRouteDestination)
},
onEdit = {
navigator.navigate(EditRssSourceRouteDestination(it))
},
onClicked = {
scaffoldNavigator.navigateTo(
ListDetailPaneScaffoldRole.Detail,
RssPaneNavArgs(it),
)
},
)
}
},
detailPane = {
AnimatedPane {
scaffoldNavigator.currentDestination?.content?.let { args ->
RssTimelineScreen(
id = args.id,
onBack = {
scaffoldNavigator.navigateBack()
},
)
}
}
},
)
}

@Parcelize
private data class RssPaneNavArgs(
val id: Int,
) : Parcelable
Loading
Loading