Skip to content

Commit 811e86e

Browse files
committed
Added ability to reply to posts
1 parent 547f1c6 commit 811e86e

5 files changed

Lines changed: 74 additions & 16 deletions

File tree

shared/src/commonMain/kotlin/site/remlit/snowdrop/App.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ data class StatusInteractionDetailRoute(
130130
data class ComposeRoute(
131131
val inReplyToId: String? = null,
132132
val cw: String = "",
133-
val content: String = ""
133+
val content: String = "",
134+
val visibility: String? = null
134135
)
135136

136137
@Serializable
@@ -426,7 +427,8 @@ fun App() = safe {
426427
ComposeView(
427428
args.inReplyToId,
428429
args.cw,
429-
args.content
430+
args.content,
431+
args.visibility
430432
)
431433
}
432434

shared/src/commonMain/kotlin/site/remlit/snowdrop/component/MiniStatus.kt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ import snowdrop.shared.generated.resources.Res
2828
import snowdrop.shared.generated.resources.icon_warning_20px
2929

3030
@Composable
31-
fun MiniStatus(status: Status) {
31+
fun MiniStatus(
32+
status: Status,
33+
showContentEvenIfCw: Boolean = false
34+
) {
3235
val navHandler = LocalNavController.current
3336

3437
Column(
@@ -65,6 +68,15 @@ fun MiniStatus(status: Status) {
6568
}
6669
}
6770

71+
@Composable
72+
fun Content() {
73+
Row(
74+
modifier = Modifier.padding(top = 5.dp)
75+
) {
76+
HtmlContent(status.content ?: "", status.mentions, maxLines = 3)
77+
}
78+
}
79+
6880
if (!status.spoilerText.isNullOrBlank()) {
6981
Row(
7082
modifier = Modifier.padding(top = 5.dp),
@@ -77,15 +89,9 @@ fun MiniStatus(status: Status) {
7789
fontWeight = FontWeight.Medium
7890
)
7991
}
80-
} else {
81-
if (status.content != null) {
82-
Row(
83-
modifier = Modifier.padding(top = 5.dp)
84-
) {
85-
HtmlContent(status.content, status.mentions, maxLines = 3)
86-
}
87-
}
88-
}
92+
93+
if (showContentEvenIfCw && status.content != null) Content()
94+
} else if (status.content != null) Content()
8995
}
9096
}
9197
}

shared/src/commonMain/kotlin/site/remlit/snowdrop/component/Status.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
4545
import androidx.navigation.toRoute
4646
import com.russhwolf.settings.ExperimentalSettingsApi
4747
import org.jetbrains.compose.resources.painterResource
48+
import site.remlit.snowdrop.ComposeRoute
4849
import site.remlit.snowdrop.ProfileRoute
4950
import site.remlit.snowdrop.StatusInteractionDetailRoute
5051
import site.remlit.snowdrop.ThreadRoute
@@ -358,14 +359,26 @@ fun Status(status: Status) {
358359
}
359360

360361
/*
362+
*
363+
*
361364
* Footer
365+
*
366+
*
362367
*/
363368
Row(
364369
modifier = Modifier.padding(start = 5.dp, end = 5.dp),
365370
horizontalArrangement = Arrangement.spacedBy(5.dp),
366371
verticalAlignment = Alignment.CenterVertically
367372
) {
368-
FooterButton(onClick = { }) {
373+
FooterButton(onClick = {
374+
navHandler.navigate(ComposeRoute(
375+
inReplyToId = realStatus.id,
376+
cw = if (!realStatus.spoilerText.isNullOrBlank()) "RE: ${realStatus.spoilerText}" else "",
377+
// what a block
378+
content = (if (!isMine) "@${realStatus.account!!.acct} " else "") +
379+
realStatus.mentions.joinToString(separator = "") { "@${it.acct} " }
380+
))
381+
}) {
369382
if (realStatus.inReplyToId != null) Icon(
370383
painterResource(Res.drawable.icon_reply_all_24px),
371384
null

shared/src/commonMain/kotlin/site/remlit/snowdrop/util/cache/Fetchers.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ fun fetchAccount(id: String): Flow<Account> = flow {
2626
}
2727
}
2828

29+
/**
30+
* Gets the cached representation of an account (if available) before
31+
* the request to get a fresh version finishes. Returns null if ID is
32+
* null.
33+
* */
34+
fun fetchAccountOrNull(id: String?): Flow<Account?> =
35+
if (id != null) fetchAccount(id) else flow { emit(null) }
36+
2937
/**
3038
* Gets the cached representation of a status (if available) before
3139
* the request to get a fresh version finishes.
@@ -42,3 +50,11 @@ fun fetchStatus(id: String): Flow<Status> = flow {
4250
putCacheEntry("status_$id", req.response)
4351
}
4452
}
53+
54+
/**
55+
* Gets the cached representation of a status (if available) before
56+
* the request to get a fresh version finishes. Returns null if ID is
57+
* null.
58+
* */
59+
fun fetchStatusOrNull(id: String?): Flow<Status?> =
60+
if (id != null) fetchStatus(id) else flow { emit(null) }

shared/src/commonMain/kotlin/site/remlit/snowdrop/view/ComposeView.kt

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,16 @@ import kotlinx.coroutines.runBlocking
5151
import org.jetbrains.compose.resources.painterResource
5252
import site.remlit.snowdrop.api.statuses.createStatus
5353
import site.remlit.snowdrop.component.Avatar
54+
import site.remlit.snowdrop.component.MiniStatus
5455
import site.remlit.snowdrop.component.ViewSurface
5556
import site.remlit.snowdrop.component.Visibility
5657
import site.remlit.snowdrop.model.request.CreateStatusRequest
5758
import site.remlit.snowdrop.util.LocalNavController
5859
import site.remlit.snowdrop.util.WarningColor25
5960
import site.remlit.snowdrop.util.bgIO
6061
import site.remlit.snowdrop.util.blockingSettings
62+
import site.remlit.snowdrop.util.cache.fetchStatus
63+
import site.remlit.snowdrop.util.cache.fetchStatusOrNull
6164
import site.remlit.snowdrop.util.getCurrentAccountObjectFlow
6265
import site.remlit.snowdrop.util.settings
6366
import snowdrop.shared.generated.resources.Res
@@ -74,7 +77,8 @@ import snowdrop.shared.generated.resources.icon_warning_24px
7477
fun ComposeView(
7578
inReplyToId: String? = null,
7679
initialCw: String = "",
77-
initialContent: String = ""
80+
initialContent: String = "",
81+
visibility: String? = null
7882
) = ViewSurface {
7983
val navHandler = LocalNavController.current
8084

@@ -90,13 +94,20 @@ fun ComposeView(
9094

9195
var cw by remember { mutableStateOf(initialCw) }
9296
var content by remember { mutableStateOf(initialContent) }
93-
var visibility by remember { mutableStateOf(blockingSettings.getString("default_visibility", "public")) }
97+
var visibility by remember {
98+
mutableStateOf(visibility
99+
?: blockingSettings.getString("default_visibility", "public"))
100+
}
101+
102+
val replyTarget by fetchStatusOrNull(inReplyToId)
103+
.collectAsStateWithLifecycle(null)
94104

95105
// can submit stuff
96106
canSubmit = !content.isBlank()
97107

98108
suspend fun sendPost() {
99109
val res = createStatus(CreateStatusRequest(
110+
inReplyToId = inReplyToId,
100111
status = content,
101112
spoilerText = cw,
102113
visibility = visibility
@@ -112,7 +123,8 @@ fun ComposeView(
112123
}
113124
},
114125
title = {
115-
Text("Compose")
126+
if (inReplyToId != null) Text("Reply")
127+
else Text("Compose")
116128
}
117129
)
118130

@@ -159,6 +171,7 @@ fun ComposeView(
159171
expanded = visibilityDropdownOpen,
160172
onDismissRequest = { visibilityDropdownOpen = !visibilityDropdownOpen }
161173
) {
174+
// todo: do minimum visibility based on the view's visibility parameter
162175
DropdownMenuItem(
163176
leadingIcon = {
164177
Icon(painterResource(Res.drawable.icon_globe_20px) ,null)
@@ -248,6 +261,14 @@ fun ComposeView(
248261
}
249262
}
250263

264+
if (replyTarget != null)
265+
Column(
266+
modifier = Modifier.padding(horizontal = 10.dp)
267+
) {
268+
MiniStatus(replyTarget!!, showContentEvenIfCw = true)
269+
}
270+
271+
251272
Column(
252273
modifier = Modifier.fillMaxHeight().weight(1f),
253274
verticalArrangement = Arrangement.spacedBy(5.dp)

0 commit comments

Comments
 (0)