Skip to content

Commit aade86c

Browse files
committed
add rss sources presenter
1 parent 57ab9a7 commit aade86c

File tree

10 files changed

+87
-25
lines changed

10 files changed

+87
-25
lines changed

shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiStatus.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,6 @@ public fun createSampleStatus(user: UiUserV2): UiTimeline =
124124
aboveTextContent = null,
125125
onClicked = {},
126126
onMediaClicked = { _, _ -> },
127+
platformType = user.platformType,
127128
),
128-
platformType = user.platformType,
129129
)

shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiTimeline.kt

+12-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ import kotlinx.collections.immutable.ImmutableList
1414
public data class UiTimeline internal constructor(
1515
val topMessage: TopMessage?,
1616
val content: ItemContent?,
17-
val platformType: PlatformType,
1817
) {
1918
val itemKey: String
2019
get() =
2120
buildString {
22-
append(platformType.name)
2321
if (topMessage != null) {
2422
append("withTopMessage")
2523
append(topMessage.itemKey)
@@ -55,7 +53,18 @@ public data class UiTimeline internal constructor(
5553
public sealed interface ItemContent {
5654
public val itemKey: String
5755

56+
public data class Feed internal constructor(
57+
val title: String,
58+
val description: String,
59+
val url: String,
60+
val image: String?,
61+
) : ItemContent {
62+
override val itemKey: String
63+
get() = "Feed_$url"
64+
}
65+
5866
public data class Status internal constructor(
67+
val platformType: PlatformType,
5968
val images: ImmutableList<UiMedia>,
6069
val sensitive: Boolean,
6170
val contentWarning: UiRichText?,
@@ -76,6 +85,7 @@ public data class UiTimeline internal constructor(
7685
override val itemKey: String
7786
get() =
7887
buildString {
88+
append(platformType.name)
7989
append("Status")
8090
append(statusKey)
8191
}

shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Bluesky.kt

+2-4
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,6 @@ internal fun FeedViewPostReasonUnion.render(
214214
)
215215
},
216216
content = data?.renderStatus(accountKey, event),
217-
platformType = PlatformType.Bluesky,
218217
)
219218
}
220219

@@ -243,7 +242,6 @@ internal fun StatusContent.BlueskyNotification.renderBlueskyNotification(
243242
UiTimeline(
244243
topMessage = topMessage,
245244
content = content,
246-
platformType = PlatformType.Bluesky,
247245
)
248246
}
249247
is StatusContent.BlueskyNotification.Post ->
@@ -281,7 +279,6 @@ internal fun StatusContent.BlueskyNotification.renderBlueskyNotification(
281279
return UiTimeline(
282280
topMessage = topMessage,
283281
content = content,
284-
platformType = PlatformType.Bluesky,
285282
)
286283
}
287284
}
@@ -319,7 +316,6 @@ internal fun PostView.render(
319316
) = UiTimeline(
320317
topMessage = null,
321318
content = renderStatus(accountKey, event),
322-
platformType = PlatformType.Bluesky,
323319
)
324320

325321
internal fun PostView.renderStatus(
@@ -335,6 +331,7 @@ internal fun PostView.renderStatus(
335331
)
336332

337333
return UiTimeline.ItemContent.Status(
334+
platformType = PlatformType.Bluesky,
338335
user = user,
339336
images = findMedias(this),
340337
card = findCard(this),
@@ -843,6 +840,7 @@ private fun render(
843840
),
844841
)
845842
},
843+
platformType = PlatformType.Bluesky,
846844
onMediaClicked = { media, index ->
847845
launcher.launch(
848846
AppDeepLink.StatusMedia(

shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Mastodon.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ internal fun Notification.render(
119119

120120
else -> status ?: UiTimeline.ItemContent.User(user)
121121
},
122-
platformType = PlatformType.Mastodon,
123122
)
124123
}
125124

@@ -171,7 +170,6 @@ internal fun Status.render(
171170
return UiTimeline(
172171
topMessage = topMessage,
173172
content = actualStatus.renderStatus(host, accountKey, event),
174-
platformType = PlatformType.Mastodon,
175173
)
176174
}
177175

@@ -354,6 +352,7 @@ private fun Status.renderStatus(
354352
),
355353
)
356354
},
355+
platformType = PlatformType.Mastodon,
357356
onMediaClicked = { media, index ->
358357
launcher.launch(
359358
AppDeepLink.StatusMedia(

shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Misskey.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ internal fun Notification.render(
151151
else ->
152152
status ?: user?.let { UiTimeline.ItemContent.User(it) }
153153
},
154-
platformType = PlatformType.Misskey,
155154
)
156155
}
157156

@@ -276,7 +275,6 @@ internal fun Note.render(
276275
return UiTimeline(
277276
topMessage = topMessage,
278277
content = actualStatus.renderStatus(accountKey, event),
279-
platformType = PlatformType.Misskey,
280278
)
281279
}
282280

@@ -484,6 +482,7 @@ internal fun Note.renderStatus(
484482
),
485483
)
486484
},
485+
platformType = PlatformType.Misskey,
487486
onMediaClicked = { media, index ->
488487
launcher.launch(
489488
AppDeepLink.StatusMedia(

shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/VVO.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ internal fun Status.render(
4646
)
4747
},
4848
content = renderStatus(accountKey, event),
49-
platformType = PlatformType.VVo,
5049
)
5150
}
5251

@@ -235,6 +234,7 @@ internal fun Status.renderStatus(
235234
),
236235
)
237236
},
237+
platformType = PlatformType.VVo,
238238
onMediaClicked = { media, index ->
239239
launcher.launch(
240240
AppDeepLink.StatusMedia(
@@ -322,7 +322,6 @@ internal fun Comment.render(
322322
UiTimeline(
323323
topMessage = null,
324324
content = renderStatus(accountKey, event),
325-
platformType = PlatformType.VVo,
326325
)
327326

328327
internal fun Comment.renderStatus(
@@ -444,6 +443,7 @@ internal fun Comment.renderStatus(
444443
),
445444
)
446445
},
446+
platformType = PlatformType.VVo,
447447
onMediaClicked = { media, index ->
448448
launcher.launch(
449449
AppDeepLink.StatusMedia(
@@ -488,7 +488,6 @@ internal fun Attitude.render(
488488
statusKey = MicroBlogKey(id.toString(), vvoHost),
489489
),
490490
content = content,
491-
platformType = PlatformType.VVo,
492491
)
493492
}
494493

shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/XQT.kt

+1-3
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ internal fun TopLevel.renderNotifications(
146146
statusKey = MicroBlogKey(id = notification.id.orEmpty(), host = accountKey.host),
147147
),
148148
content = itemContent,
149-
platformType = PlatformType.xQt,
150149
)
151150
} else if (mentionTweet != null) {
152151
val tweet = globalObjects?.tweets?.get(mentionTweet.id) ?: return@mapNotNull null
@@ -192,7 +191,6 @@ internal fun TopLevel.renderNotifications(
192191
statusKey = MicroBlogKey(id = notification?.id.orEmpty(), host = accountKey.host),
193192
),
194193
content = data,
195-
platformType = PlatformType.xQt,
196194
)
197195
} else {
198196
null
@@ -230,7 +228,6 @@ internal fun Tweet.render(
230228
return UiTimeline(
231229
content = actualTweet,
232230
topMessage = topMessage,
233-
platformType = PlatformType.xQt,
234231
)
235232
}
236233

@@ -515,6 +512,7 @@ internal fun Tweet.renderStatus(
515512
onClicked = {
516513
launcher.launch(AppDeepLink.StatusDetail(accountKey = accountKey, statusKey = statusKey))
517514
},
515+
platformType = PlatformType.xQt,
518516
onMediaClicked = { media, index ->
519517
launcher.launch(
520518
AppDeepLink.StatusMedia(

shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/compose/ComposePresenter.kt

+9-6
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ public class ComposePresenter(
6868
}
6969
val replyState =
7070
statusState?.map {
71-
if (it.platformType == PlatformType.VVo) {
71+
if (it.content is UiTimeline.ItemContent.Status && it.content.platformType == PlatformType.VVo) {
7272
it.copy(
73-
content = (it.content as? UiTimeline.ItemContent.Status)?.quote?.firstOrNull() ?: it.content,
73+
content = it.content.quote.firstOrNull() ?: it.content,
7474
)
7575
} else {
7676
it
@@ -80,7 +80,7 @@ public class ComposePresenter(
8080
statusState?.mapNotNull {
8181
val content = it.content
8282
if (content is UiTimeline.ItemContent.Status) {
83-
when (it.platformType) {
83+
when (content.platformType) {
8484
PlatformType.VVo -> {
8585
if (content.quote.any() && status is ComposeStatus.Quote) {
8686
InitialText(
@@ -108,9 +108,12 @@ public class ComposePresenter(
108108
accounts.flatMap { data ->
109109
accountState
110110
.flatMap { current ->
111-
statusState?.map {
112-
current to listOf(it.platformType)
113-
} ?: UiState.Success(current to PlatformType.entries.toList())
111+
statusState
112+
?.mapNotNull {
113+
it.content as? UiTimeline.ItemContent.Status
114+
}?.map {
115+
current to listOf(it.platformType)
116+
} ?: UiState.Success(current to PlatformType.entries.toList())
114117
}.map { (current, platforms) ->
115118
data
116119
.sortedBy {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package dev.dimension.flare.ui.presenter.home.rss
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.getValue
5+
import androidx.compose.runtime.mutableStateOf
6+
import androidx.compose.runtime.remember
7+
import androidx.compose.runtime.setValue
8+
import androidx.compose.runtime.snapshotFlow
9+
import dev.dimension.flare.data.network.rss.Rss
10+
import dev.dimension.flare.ui.model.UiState
11+
import dev.dimension.flare.ui.model.collectAsUiState
12+
import dev.dimension.flare.ui.model.flatMap
13+
import dev.dimension.flare.ui.presenter.PresenterBase
14+
import kotlinx.coroutines.flow.map
15+
16+
public class CheckRssSourcePresenter : PresenterBase<CheckRssSourcePresenter.State>() {
17+
public interface State {
18+
public val isValid: UiState<Boolean>
19+
20+
public fun setUrl(value: String)
21+
}
22+
23+
@Composable
24+
override fun body(): State {
25+
var url by remember { mutableStateOf("") }
26+
val isValid =
27+
remember {
28+
snapshotFlow { url }
29+
.map {
30+
runCatching {
31+
Rss.fetch(it)
32+
}.fold(
33+
onSuccess = {
34+
UiState.Success(true) as UiState<Boolean>
35+
},
36+
onFailure = {
37+
UiState.Error(it)
38+
},
39+
)
40+
}
41+
}.collectAsUiState().value.flatMap { it }
42+
43+
return object : State {
44+
override val isValid = isValid
45+
46+
override fun setUrl(value: String) {
47+
url = value
48+
}
49+
}
50+
}
51+
}

shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/home/rss/RssSourcesPresenter.kt

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.compose.runtime.rememberCoroutineScope
77
import dev.dimension.flare.common.PagingState
88
import dev.dimension.flare.common.collectPagingState
99
import dev.dimension.flare.data.database.app.AppDatabase
10+
import dev.dimension.flare.data.database.app.model.DbRssSources
1011
import dev.dimension.flare.ui.model.UiRssSource
1112
import dev.dimension.flare.ui.model.mapper.render
1213
import dev.dimension.flare.ui.presenter.PresenterBase
@@ -20,7 +21,7 @@ public class RssSourcesPresenter :
2021
KoinComponent {
2122
private val appDatabase by inject<AppDatabase>()
2223

23-
public interface State {
24+
public interface State : CheckRssSourcePresenter.State {
2425
public val sources: PagingState<UiRssSource>
2526

2627
public fun add(
@@ -41,13 +42,17 @@ public class RssSourcesPresenter :
4142
}
4243
}
4344
}.collectPagingState()
44-
return object : State {
45+
val checkRssSourcePresenterState = remember { CheckRssSourcePresenter() }.body()
46+
return object : State, CheckRssSourcePresenter.State by checkRssSourcePresenterState {
4547
override val sources: PagingState<UiRssSource> = sources
4648

4749
override fun add(
4850
url: String,
4951
title: String,
5052
) {
53+
scope.launch {
54+
appDatabase.rssSourceDao().insert(DbRssSources(url = url, title = title, lastUpdate = 0))
55+
}
5156
}
5257

5358
override fun delete(url: String) {

0 commit comments

Comments
 (0)