- Adds Immutable Lists to avoid recompositions
- Moves NavController to a lambda to avoid recompositions - Moves AccountViewModel builder to a ViewModel Factory to avoid recompositions - Reduces notifications invalidation requests when starting the screen.
This commit is contained in:
+3
-1
@@ -82,7 +82,6 @@ android {
|
||||
lint {
|
||||
disable 'MissingTranslation'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -183,6 +182,9 @@ dependencies {
|
||||
implementation "com.patrykandpatrick.vico:views:${vico_version}"
|
||||
implementation "com.patrykandpatrick.vico:compose-m2:${vico_version}"
|
||||
|
||||
// immutable collections to avoid recomposition
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.5")
|
||||
|
||||
// Automatic memory leak detection
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.11'
|
||||
|
||||
|
||||
+2
-3
@@ -3,7 +3,6 @@ package com.vitorpamplona.amethyst.ui.components
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
@@ -14,7 +13,7 @@ fun TranslatableRichTextViewer(
|
||||
tags: List<List<String>>?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) = ExpandableRichTextViewer(
|
||||
content,
|
||||
canPreview,
|
||||
@@ -22,5 +21,5 @@ fun TranslatableRichTextViewer(
|
||||
tags,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object NotificationCache {
|
||||
// TODO: This must be account-based
|
||||
val lastReadByRoute = mutableMapOf<String, Long>()
|
||||
|
||||
fun markAsRead(route: String, timestampInSecs: Long) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.vitorpamplona.amethyst.model
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.vitorpamplona.amethyst.service.FileHeader
|
||||
@@ -43,6 +45,7 @@ val GLOBAL_FOLLOWS = " Global "
|
||||
val KIND3_FOLLOWS = " All Follows "
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
@Stable
|
||||
class Account(
|
||||
val loggedIn: Persona,
|
||||
var followingChannels: Set<String> = DefaultChannels,
|
||||
@@ -1166,4 +1169,5 @@ class AccountLiveData(private val account: Account) : LiveData<AccountState>(Acc
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class AccountState(val account: Account)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.vitorpamplona.amethyst.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.vitorpamplona.amethyst.service.NostrSingleEventDataSource
|
||||
@@ -442,4 +443,5 @@ class NoteLiveData(val note: Note) : LiveData<NoteState>(NoteState(note)) {
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class NoteState(val note: Note)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.vitorpamplona.amethyst.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
|
||||
@@ -420,4 +421,5 @@ class UserLiveData(val user: User) : LiveData<UserState>(UserState(user)) {
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class UserState(val user: User)
|
||||
|
||||
@@ -30,6 +30,7 @@ class Relay(
|
||||
) {
|
||||
val seconds = if (proxy != null) 20L else 10L
|
||||
val duration = Duration.ofSeconds(seconds)
|
||||
|
||||
private val httpClient = OkHttpClient.Builder()
|
||||
.proxy(proxy)
|
||||
.readTimeout(duration)
|
||||
|
||||
@@ -51,7 +51,6 @@ import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
@@ -73,7 +72,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun JoinUserOrChannelView(onClose: () -> Unit, account: Account, navController: NavController) {
|
||||
fun JoinUserOrChannelView(onClose: () -> Unit, account: Account, nav: (String) -> Unit) {
|
||||
val searchBarViewModel: SearchBarViewModel = viewModel()
|
||||
searchBarViewModel.account = account
|
||||
|
||||
@@ -116,7 +115,7 @@ fun JoinUserOrChannelView(onClose: () -> Unit, account: Account, navController:
|
||||
|
||||
Spacer(modifier = Modifier.height(15.dp))
|
||||
|
||||
RenderSeach(searchBarViewModel, account, navController)
|
||||
RenderSeach(searchBarViewModel, account, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +126,7 @@ fun JoinUserOrChannelView(onClose: () -> Unit, account: Account, navController:
|
||||
private fun RenderSeach(
|
||||
searchBarViewModel: SearchBarViewModel,
|
||||
account: Account,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val listState = rememberLazyListState()
|
||||
@@ -275,7 +274,7 @@ private fun RenderSeach(
|
||||
UserComposeForChat(
|
||||
item,
|
||||
account = account,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
@@ -295,7 +294,7 @@ private fun RenderSeach(
|
||||
channelLastTime = null,
|
||||
channelLastContent = item.info.about,
|
||||
false,
|
||||
onClick = { navController.navigate("Channel/${item.idHex}") }
|
||||
onClick = { nav("Channel/${item.idHex}") }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -307,12 +306,12 @@ private fun RenderSeach(
|
||||
fun UserComposeForChat(
|
||||
baseUser: User,
|
||||
account: Account,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.clickable(
|
||||
onClick = { navController.navigate("Room/${baseUser.pubkeyHex}") }
|
||||
onClick = { nav("Room/${baseUser.pubkeyHex}") }
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
@@ -324,7 +323,7 @@ fun UserComposeForChat(
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
UserPicture(baseUser, navController, account.userProfile(), 55.dp)
|
||||
UserPicture(baseUser, nav, account.userProfile(), 55.dp)
|
||||
|
||||
Column(modifier = Modifier.padding(start = 10.dp).weight(1f)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
|
||||
@@ -28,7 +28,6 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
@@ -39,7 +38,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun NewMediaView(uri: Uri, onClose: () -> Unit, postViewModel: NewMediaModel, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun NewMediaView(uri: Uri, onClose: () -> Unit, postViewModel: NewMediaModel, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val account = accountViewModel.accountLiveData.value?.account ?: return
|
||||
val resolver = LocalContext.current.contentResolver
|
||||
val context = LocalContext.current
|
||||
|
||||
@@ -57,7 +57,6 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
@@ -75,7 +74,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = null, account: Account, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = null, account: Account, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val postViewModel: NewPostViewModel = viewModel()
|
||||
|
||||
val context = LocalContext.current
|
||||
@@ -292,7 +291,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
|
||||
true,
|
||||
MaterialTheme.colors.background,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
} else if (noProtocolUrlValidator.matcher(myUrlPreview).matches()) {
|
||||
UrlPreview("https://$myUrlPreview", myUrlPreview)
|
||||
|
||||
@@ -15,14 +15,13 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.ui.actions.JoinUserOrChannelView
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewChannelView
|
||||
|
||||
@Composable
|
||||
fun ChannelFabColumn(account: Account, navController: NavController) {
|
||||
fun ChannelFabColumn(account: Account, nav: (String) -> Unit) {
|
||||
var isOpen by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
@@ -40,7 +39,7 @@ fun ChannelFabColumn(account: Account, navController: NavController) {
|
||||
}
|
||||
|
||||
if (wantsToJoinChannelOrUser) {
|
||||
JoinUserOrChannelView({ wantsToJoinChannelOrUser = false }, account = account, navController = navController)
|
||||
JoinUserOrChannelView({ wantsToJoinChannelOrUser = false }, account = account, nav = nav)
|
||||
}
|
||||
|
||||
Column() {
|
||||
|
||||
@@ -16,20 +16,19 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewPostView
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
fun NewNoteButton(account: Account, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun NewNoteButton(account: Account, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
var wantsToPost by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
if (wantsToPost) {
|
||||
NewPostView({ wantsToPost = false }, account = account, accountViewModel = accountViewModel, navController = navController)
|
||||
NewPostView({ wantsToPost = false }, account = account, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
|
||||
OutlinedButton(
|
||||
|
||||
@@ -22,9 +22,11 @@ class BundledUpdate(
|
||||
private var onlyOneInBlock = AtomicBoolean()
|
||||
private var invalidatesAgain = false
|
||||
|
||||
fun invalidate() {
|
||||
fun invalidate(ignoreIfDoing: Boolean = false) {
|
||||
if (onlyOneInBlock.getAndSet(true)) {
|
||||
invalidatesAgain = true
|
||||
if (!ignoreIfDoing) {
|
||||
invalidatesAgain = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -5,18 +5,17 @@ import androidx.compose.material.LocalTextStyle
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
||||
|
||||
@Composable
|
||||
fun ClickableNoteTag(
|
||||
baseNote: Note,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
ClickableText(
|
||||
text = AnnotatedString("@${baseNote.idNote().toShortenHex()}"),
|
||||
onClick = { navController.navigate("Note/${baseNote.idHex}") },
|
||||
onClick = { nav("Note/${baseNote.idHex}") },
|
||||
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
@@ -52,16 +51,16 @@ import kotlinx.coroutines.withContext
|
||||
@Composable
|
||||
fun ClickableRoute(
|
||||
nip19: Nip19.Return,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
if (nip19.type == Nip19.Type.USER) {
|
||||
DisplayUser(nip19, navController)
|
||||
DisplayUser(nip19, nav)
|
||||
} else if (nip19.type == Nip19.Type.ADDRESS) {
|
||||
DisplayAddress(nip19, navController)
|
||||
DisplayAddress(nip19, nav)
|
||||
} else if (nip19.type == Nip19.Type.NOTE) {
|
||||
DisplayNote(nip19, navController)
|
||||
DisplayNote(nip19, nav)
|
||||
} else if (nip19.type == Nip19.Type.EVENT) {
|
||||
DisplayEvent(nip19, navController)
|
||||
DisplayEvent(nip19, nav)
|
||||
} else {
|
||||
Text(
|
||||
"@${nip19.hex}${nip19.additionalChars} "
|
||||
@@ -72,7 +71,7 @@ fun ClickableRoute(
|
||||
@Composable
|
||||
private fun DisplayEvent(
|
||||
nip19: Nip19.Return,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var noteBase by remember { mutableStateOf<Note?>(null) }
|
||||
|
||||
@@ -92,28 +91,28 @@ private fun DisplayEvent(
|
||||
clickablePart = "@${note.idDisplayNote()}",
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Channel/${nip19.hex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else if (note.event is PrivateDmEvent) {
|
||||
CreateClickableText(
|
||||
clickablePart = "@${note.idDisplayNote()}",
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Room/${note.author?.pubkeyHex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else if (channel != null) {
|
||||
CreateClickableText(
|
||||
clickablePart = channel.toBestDisplayName(),
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Channel/${channel.idHex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else {
|
||||
CreateClickableText(
|
||||
clickablePart = "@${note.idDisplayNote()}",
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Event/${nip19.hex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -128,7 +127,7 @@ private fun DisplayEvent(
|
||||
@Composable
|
||||
private fun DisplayNote(
|
||||
nip19: Nip19.Return,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var noteBase by remember { mutableStateOf<Note?>(null) }
|
||||
|
||||
@@ -148,28 +147,28 @@ private fun DisplayNote(
|
||||
clickablePart = "@${note.idDisplayNote()}",
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Channel/${nip19.hex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else if (note.event is PrivateDmEvent) {
|
||||
CreateClickableText(
|
||||
clickablePart = "@${note.idDisplayNote()}",
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Room/${note.author?.pubkeyHex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else if (channel != null) {
|
||||
CreateClickableText(
|
||||
clickablePart = channel.toBestDisplayName(),
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Channel/${note.channel()?.idHex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else {
|
||||
CreateClickableText(
|
||||
clickablePart = "@${note.idDisplayNote()}",
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Note/${nip19.hex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -184,7 +183,7 @@ private fun DisplayNote(
|
||||
@Composable
|
||||
private fun DisplayAddress(
|
||||
nip19: Nip19.Return,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var noteBase by remember { mutableStateOf<Note?>(null) }
|
||||
|
||||
@@ -202,7 +201,7 @@ private fun DisplayAddress(
|
||||
clickablePart = "@${note.idDisplayNote()}",
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
route = "Note/${nip19.hex}",
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
@@ -216,7 +215,7 @@ private fun DisplayAddress(
|
||||
@Composable
|
||||
private fun DisplayUser(
|
||||
nip19: Nip19.Return,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var userBase by remember { mutableStateOf<User?>(null) }
|
||||
|
||||
@@ -238,7 +237,7 @@ private fun DisplayUser(
|
||||
suffix = "${nip19.additionalChars} ",
|
||||
tags = userTags,
|
||||
route = route,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -257,7 +256,7 @@ fun CreateClickableText(
|
||||
overrideColor: Color? = null,
|
||||
fontWeight: FontWeight = FontWeight.Normal,
|
||||
route: String,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
ClickableText(
|
||||
text = buildAnnotatedString {
|
||||
@@ -272,7 +271,7 @@ fun CreateClickableText(
|
||||
append(suffix)
|
||||
}
|
||||
},
|
||||
onClick = { navController.navigate(route) }
|
||||
onClick = { nav(route) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -378,21 +377,21 @@ fun CreateClickableTextWithEmoji(
|
||||
overrideColor: Color? = null,
|
||||
fontWeight: FontWeight = FontWeight.Normal,
|
||||
route: String,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val emojis = remember(tags) {
|
||||
tags?.filter { it.size > 2 && it[0] == "emoji" }?.associate { ":${it[1]}:" to it[2] } ?: emptyMap()
|
||||
}
|
||||
|
||||
if (emojis.isEmpty()) {
|
||||
CreateClickableText(clickablePart, suffix, overrideColor, fontWeight, route, navController)
|
||||
CreateClickableText(clickablePart, suffix, overrideColor, fontWeight, route, nav)
|
||||
} else {
|
||||
val myList = remember {
|
||||
assembleAnnotatedList(clickablePart, emojis)
|
||||
}
|
||||
|
||||
ClickableInLineIconRenderer(myList, LocalTextStyle.current.copy(color = overrideColor ?: MaterialTheme.colors.primary, fontWeight = fontWeight).toSpanStyle()) {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
}
|
||||
|
||||
val myList2 = remember {
|
||||
|
||||
@@ -7,18 +7,17 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
|
||||
@Composable
|
||||
fun ClickableUserTag(
|
||||
user: User,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val innerUserState by user.live().metadata.observeAsState()
|
||||
ClickableText(
|
||||
text = AnnotatedString("@${innerUserState?.user?.toBestDisplayName()}"),
|
||||
onClick = { navController.navigate("User/${innerUserState?.user?.pubkeyHex}") },
|
||||
onClick = { nav("User/${innerUserState?.user?.pubkeyHex}") },
|
||||
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-3
@@ -25,7 +25,6 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -39,7 +38,7 @@ fun ExpandableRichTextViewer(
|
||||
tags: List<List<String>>?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var showFullText by remember { mutableStateOf(false) }
|
||||
|
||||
@@ -69,7 +68,7 @@ fun ExpandableRichTextViewer(
|
||||
tags,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
|
||||
if (content.length > whereToCut && !showFullText) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.halilibo.richtext.markdown.Markdown
|
||||
import com.halilibo.richtext.markdown.MarkdownParseOptions
|
||||
@@ -94,19 +93,20 @@ fun RichTextViewer(
|
||||
tags: List<List<String>>?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val isMarkdown = remember { isMarkdown(content) }
|
||||
|
||||
Column(modifier = modifier) {
|
||||
if (isMarkdown) {
|
||||
RenderContentAsMarkdown(content, backgroundColor, tags, navController)
|
||||
RenderContentAsMarkdown(content, backgroundColor, tags, nav)
|
||||
} else {
|
||||
RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, navController)
|
||||
RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class RichTextViewerState(
|
||||
val content: String,
|
||||
val urlSet: Set<String>,
|
||||
@@ -122,10 +122,10 @@ private fun RenderRegular(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var processedState by remember {
|
||||
mutableStateOf<RichTextViewerState?>(RichTextViewerState(content, emptySet(), emptyMap(), emptyList(), emptyMap()))
|
||||
var state by remember {
|
||||
mutableStateOf(RichTextViewerState(content, emptySet(), emptyMap(), emptyList(), emptyMap()))
|
||||
}
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -149,80 +149,73 @@ private fun RenderRegular(
|
||||
val emojiMap = tags?.filter { it.size > 2 && it[0] == "emoji" }?.associate { ":${it[1]}:" to it[2] } ?: emptyMap()
|
||||
|
||||
if (urlSet.isNotEmpty() || emojiMap.isNotEmpty()) {
|
||||
processedState = RichTextViewerState(content, urlSet, imagesForPager, imageList, emojiMap)
|
||||
state = RichTextViewerState(content, urlSet, imagesForPager, imageList, emojiMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FlowRow doesn't work well with paragraphs. So we need to split them
|
||||
processedState?.let { state ->
|
||||
content.split('\n').forEach { paragraph ->
|
||||
FlowRow() {
|
||||
val s = if (isArabic(paragraph)) {
|
||||
paragraph.trim().split(' ')
|
||||
.reversed()
|
||||
} else {
|
||||
paragraph.trim().split(' ')
|
||||
}
|
||||
s.forEach { word: String ->
|
||||
if (canPreview) {
|
||||
// Explicit URL
|
||||
val img = state.imagesForPager[word]
|
||||
if (img != null) {
|
||||
ZoomableContentView(img, state.imageList)
|
||||
} else if (state.urlSet.contains(word)) {
|
||||
UrlPreview(word, "$word ")
|
||||
} else if (state.customEmoji.any { word.contains(it.key) }) {
|
||||
RenderCustomEmoji(word, state.customEmoji)
|
||||
} else if (word.startsWith("lnbc", true)) {
|
||||
MayBeInvoicePreview(word)
|
||||
} else if (word.startsWith("lnurl", true)) {
|
||||
MayBeWithdrawal(word)
|
||||
} else if (Patterns.EMAIL_ADDRESS.matcher(word).matches()) {
|
||||
ClickableEmail(word)
|
||||
} else if (word.length > 6 && Patterns.PHONE.matcher(word).matches()) {
|
||||
ClickablePhone(word)
|
||||
} else if (isBechLink(word)) {
|
||||
BechLink(
|
||||
content.split('\n').forEach { paragraph ->
|
||||
FlowRow() {
|
||||
val s = if (isArabic(paragraph)) {
|
||||
paragraph.trim().split(' ')
|
||||
.reversed()
|
||||
} else {
|
||||
paragraph.trim().split(' ')
|
||||
}
|
||||
s.forEach { word: String ->
|
||||
if (canPreview) {
|
||||
// Explicit URL
|
||||
val img = state.imagesForPager[word]
|
||||
if (img != null) {
|
||||
ZoomableContentView(img, state.imageList)
|
||||
} else if (state.urlSet.contains(word)) {
|
||||
UrlPreview(word, "$word ")
|
||||
} else if (state.customEmoji.any { word.contains(it.key) }) {
|
||||
RenderCustomEmoji(word, state.customEmoji)
|
||||
} else if (word.startsWith("lnbc", true)) {
|
||||
MayBeInvoicePreview(word)
|
||||
} else if (word.startsWith("lnurl", true)) {
|
||||
MayBeWithdrawal(word)
|
||||
} else if (Patterns.EMAIL_ADDRESS.matcher(word).matches()) {
|
||||
ClickableEmail(word)
|
||||
} else if (word.length > 6 && Patterns.PHONE.matcher(word).matches()) {
|
||||
ClickablePhone(word)
|
||||
} else if (isBechLink(word)) {
|
||||
BechLink(
|
||||
word,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
nav
|
||||
)
|
||||
} else if (word.startsWith("#")) {
|
||||
if (tagIndex.matcher(word).matches() && tags != null) {
|
||||
TagLink(
|
||||
word,
|
||||
tags,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
} else if (word.startsWith("#")) {
|
||||
if (tagIndex.matcher(word).matches() && tags != null) {
|
||||
TagLink(
|
||||
word,
|
||||
tags,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
)
|
||||
} else if (hashTagsPattern.matcher(word).matches()) {
|
||||
HashTag(word, navController)
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else if (noProtocolUrlValidator.matcher(word).matches()) {
|
||||
val matcher = noProtocolUrlValidator.matcher(word)
|
||||
matcher.find()
|
||||
val url = matcher.group(1) // url
|
||||
val additionalChars = matcher.group(4) ?: "" // additional chars
|
||||
} else if (hashTagsPattern.matcher(word).matches()) {
|
||||
HashTag(word, nav)
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else if (noProtocolUrlValidator.matcher(word).matches()) {
|
||||
val matcher = noProtocolUrlValidator.matcher(word)
|
||||
matcher.find()
|
||||
val url = matcher.group(1) // url
|
||||
val additionalChars = matcher.group(4) ?: "" // additional chars
|
||||
|
||||
if (url != null) {
|
||||
ClickableUrl(url, "https://$url")
|
||||
Text("$additionalChars ")
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
if (url != null) {
|
||||
ClickableUrl(url, "https://$url")
|
||||
Text("$additionalChars ")
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
@@ -230,71 +223,76 @@ private fun RenderRegular(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (state.urlSet.contains(word)) {
|
||||
ClickableUrl("$word ", word)
|
||||
} else if (word.startsWith("lnurl", true)) {
|
||||
val lnWithdrawal = LnWithdrawalUtil.findWithdrawal(word)
|
||||
if (lnWithdrawal != null) {
|
||||
ClickableWithdrawal(withdrawalString = lnWithdrawal)
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else if (state.customEmoji.any { word.contains(it.key) }) {
|
||||
RenderCustomEmoji(word, state.customEmoji)
|
||||
} else if (Patterns.EMAIL_ADDRESS.matcher(word).matches()) {
|
||||
ClickableEmail(word)
|
||||
} else if (Patterns.PHONE.matcher(word).matches() && word.length > 6) {
|
||||
ClickablePhone(word)
|
||||
} else if (isBechLink(word)) {
|
||||
BechLink(
|
||||
word,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
)
|
||||
} else if (word.startsWith("#")) {
|
||||
if (tagIndex.matcher(word).matches() && tags != null) {
|
||||
TagLink(
|
||||
word,
|
||||
tags,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
)
|
||||
} else if (hashTagsPattern.matcher(word).matches()) {
|
||||
HashTag(word, navController)
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else if (noProtocolUrlValidator.matcher(word).matches()) {
|
||||
val matcher = noProtocolUrlValidator.matcher(word)
|
||||
matcher.find()
|
||||
val url = matcher.group(1) // url
|
||||
val additionalChars = matcher.group(4) ?: "" // additional chars
|
||||
|
||||
if (url != null) {
|
||||
ClickableUrl(url, "https://$url")
|
||||
Text("$additionalChars ")
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (state.urlSet.contains(word)) {
|
||||
ClickableUrl("$word ", word)
|
||||
} else if (word.startsWith("lnurl", true)) {
|
||||
val lnWithdrawal = LnWithdrawalUtil.findWithdrawal(word)
|
||||
if (lnWithdrawal != null) {
|
||||
ClickableWithdrawal(withdrawalString = lnWithdrawal)
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else if (state.customEmoji.any { word.contains(it.key) }) {
|
||||
RenderCustomEmoji(word, state.customEmoji)
|
||||
} else if (Patterns.EMAIL_ADDRESS.matcher(word).matches()) {
|
||||
ClickableEmail(word)
|
||||
} else if (Patterns.PHONE.matcher(word).matches() && word.length > 6) {
|
||||
ClickablePhone(word)
|
||||
} else if (isBechLink(word)) {
|
||||
BechLink(
|
||||
word,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
nav
|
||||
)
|
||||
} else if (word.startsWith("#")) {
|
||||
if (tagIndex.matcher(word).matches() && tags != null) {
|
||||
TagLink(
|
||||
word,
|
||||
tags,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
nav
|
||||
)
|
||||
} else if (hashTagsPattern.matcher(word).matches()) {
|
||||
HashTag(word, nav)
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else if (noProtocolUrlValidator.matcher(word).matches()) {
|
||||
val matcher = noProtocolUrlValidator.matcher(word)
|
||||
matcher.find()
|
||||
val url = matcher.group(1) // url
|
||||
val additionalChars = matcher.group(4) ?: "" // additional chars
|
||||
|
||||
if (url != null) {
|
||||
ClickableUrl(url, "https://$url")
|
||||
Text("$additionalChars ")
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
text = "$word ",
|
||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,7 +309,7 @@ fun RenderCustomEmoji(word: String, customEmoji: Map<String, String>) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderContentAsMarkdown(content: String, backgroundColor: Color, tags: List<List<String>>?, navController: NavController) {
|
||||
private fun RenderContentAsMarkdown(content: String, backgroundColor: Color, tags: List<List<String>>?, nav: (String) -> Unit) {
|
||||
val myMarkDownStyle = richTextDefaults.copy(
|
||||
codeBlockStyle = richTextDefaults.codeBlockStyle?.copy(
|
||||
textStyle = TextStyle(
|
||||
@@ -416,7 +414,7 @@ private fun RenderContentAsMarkdown(content: String, backgroundColor: Color, tag
|
||||
) { link ->
|
||||
val route = uriToRoute(link)
|
||||
if (route != null) {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
} else {
|
||||
runCatching { uri.openUri(link) }
|
||||
}
|
||||
@@ -572,12 +570,14 @@ fun isBechLink(word: String): Boolean {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BechLink(word: String, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun BechLink(word: String, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
var nip19Route by remember { mutableStateOf<Nip19.Return?>(null) }
|
||||
var baseNotePair by remember { mutableStateOf<Pair<Note, String?>?>(null) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(key1 = word) {
|
||||
withContext(Dispatchers.IO) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
Nip19.uriToRoute(word)?.let {
|
||||
if (it.type == Nip19.Type.NOTE || it.type == Nip19.Type.EVENT || it.type == Nip19.Type.ADDRESS) {
|
||||
LocalCache.checkGetOrCreateNote(it.hex)?.let { note ->
|
||||
@@ -606,7 +606,7 @@ fun BechLink(word: String, canPreview: Boolean, backgroundColor: Color, accountV
|
||||
),
|
||||
parentBackgroundColor = backgroundColor,
|
||||
isQuotedNote = true,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
if (!it.second.isNullOrEmpty()) {
|
||||
Text(
|
||||
@@ -614,21 +614,23 @@ fun BechLink(word: String, canPreview: Boolean, backgroundColor: Color, accountV
|
||||
)
|
||||
}
|
||||
} ?: nip19Route?.let {
|
||||
ClickableRoute(it, navController)
|
||||
ClickableRoute(it, nav)
|
||||
} ?: Text(text = "$word ")
|
||||
} else {
|
||||
nip19Route?.let {
|
||||
ClickableRoute(it, navController)
|
||||
ClickableRoute(it, nav)
|
||||
} ?: Text(text = "$word ")
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HashTag(word: String, navController: NavController) {
|
||||
fun HashTag(word: String, nav: (String) -> Unit) {
|
||||
var tagSuffixPair by remember { mutableStateOf<Pair<String, String?>?>(null) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(key1 = word) {
|
||||
withContext(Dispatchers.IO) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val hashtagMatcher = hashTagsPattern.matcher(word)
|
||||
|
||||
val (myTag, mySuffix) = try {
|
||||
@@ -646,7 +648,7 @@ fun HashTag(word: String, navController: NavController) {
|
||||
}
|
||||
|
||||
tagSuffixPair?.let { tagPair ->
|
||||
val hashtagIcon = checkForHashtagWithIcon(tagPair.first)
|
||||
val hashtagIcon = remember(tagPair.first) { checkForHashtagWithIcon(tagPair.first) }
|
||||
ClickableText(
|
||||
text = buildAnnotatedString {
|
||||
withStyle(
|
||||
@@ -655,7 +657,7 @@ fun HashTag(word: String, navController: NavController) {
|
||||
append("#${tagPair.first}")
|
||||
}
|
||||
},
|
||||
onClick = { navController.navigate("Hashtag/${tagPair.first}") }
|
||||
onClick = { nav("Hashtag/${tagPair.first}") }
|
||||
)
|
||||
|
||||
if (hashtagIcon != null) {
|
||||
@@ -701,7 +703,7 @@ fun HashTag(word: String, navController: NavController) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
var baseUserPair by remember { mutableStateOf<Pair<User, String?>?>(null) }
|
||||
var baseNotePair by remember { mutableStateOf<Pair<Note, String?>?>(null) }
|
||||
|
||||
@@ -753,7 +755,7 @@ fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgro
|
||||
suffix = "${it.second} ",
|
||||
tags = userTags,
|
||||
route = route,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
@@ -773,13 +775,13 @@ fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgro
|
||||
),
|
||||
parentBackgroundColor = backgroundColor,
|
||||
isQuotedNote = true,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
it.second?.ifBlank { null }?.let {
|
||||
Text(text = "$it ")
|
||||
}
|
||||
} else {
|
||||
ClickableNoteTag(it.first, navController)
|
||||
ClickableNoteTag(it.first, nav)
|
||||
Text(text = "${it.second} ")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +132,7 @@ fun RobohashAsyncImageProxy(
|
||||
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality
|
||||
) {
|
||||
val proxy = remember(model) { model.proxyUrl() }
|
||||
|
||||
if (proxy == null) {
|
||||
RobohashAsyncImage(
|
||||
robot = robot,
|
||||
|
||||
@@ -37,7 +37,6 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
@@ -116,24 +115,26 @@ private fun RowScope.HasNewItemsIcon(
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = remember(accountState) { accountState?.account } ?: return
|
||||
|
||||
val notifState = NotificationCache.live.observeAsState()
|
||||
val notif = remember(notifState) { notifState.value } ?: return
|
||||
val notifState by NotificationCache.live.observeAsState()
|
||||
val notif = remember(notifState) { notifState?.cache } ?: return
|
||||
|
||||
var hasNewItems by remember { mutableStateOf<Boolean>(false) }
|
||||
|
||||
LaunchedEffect(key1 = notif) {
|
||||
LaunchedEffect(key1 = notifState, key2 = accountState) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val newHasNewItems = route.hasNewItems(account, notif.cache, emptySet())
|
||||
val newHasNewItems = route.hasNewItems(account, notif, emptySet())
|
||||
println("Notification Change ${route.route} $hasNewItems -> $newHasNewItems")
|
||||
if (newHasNewItems != hasNewItems) {
|
||||
hasNewItems = newHasNewItems
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
LaunchedEffect(accountState) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
LocalCache.live.newEventBundles.collect {
|
||||
val newHasNewItems = route.hasNewItems(account, notif.cache, it)
|
||||
val newHasNewItems = route.hasNewItems(account, notif, it)
|
||||
println("Notification From Base ${route.route} $hasNewItems -> $newHasNewItems")
|
||||
if (newHasNewItems != hasNewItems) {
|
||||
hasNewItems = newHasNewItems
|
||||
}
|
||||
@@ -182,7 +183,7 @@ private fun RowScope.BottomIcon(
|
||||
iconSize: Dp,
|
||||
base: String,
|
||||
hasNewItems: Boolean,
|
||||
navController: NavController,
|
||||
navController: NavHostController,
|
||||
onClick: (Boolean) -> Unit
|
||||
) {
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
|
||||
@@ -82,6 +82,14 @@ fun AppNavigation(
|
||||
}
|
||||
}
|
||||
|
||||
val nav = remember {
|
||||
{ route: String ->
|
||||
if (getRouteWithArguments(navController) != route) {
|
||||
navController.navigate(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NavHost(navController, startDestination = Route.Home.route) {
|
||||
Route.Video.let { route ->
|
||||
composable(route.route, route.arguments, content = {
|
||||
@@ -90,7 +98,7 @@ fun AppNavigation(
|
||||
VideoScreen(
|
||||
videoFeedView = videoFeedViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
scrollToTop = scrollToTop
|
||||
)
|
||||
|
||||
@@ -108,7 +116,7 @@ fun AppNavigation(
|
||||
SearchScreen(
|
||||
searchFeedViewModel = searchFeedViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
scrollToTop = scrollToTop
|
||||
)
|
||||
|
||||
@@ -128,7 +136,7 @@ fun AppNavigation(
|
||||
homeFeedViewModel = homeFeedViewModel,
|
||||
repliesFeedViewModel = repliesFeedViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
pagerState = homePagerState,
|
||||
scrollToTop = scrollToTop,
|
||||
nip47 = nip47
|
||||
@@ -152,7 +160,7 @@ fun AppNavigation(
|
||||
notifFeedViewModel = notifFeedViewModel,
|
||||
userReactionsStatsModel = userReactionsStatsModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
scrollToTop = scrollToTop
|
||||
)
|
||||
|
||||
@@ -163,16 +171,16 @@ fun AppNavigation(
|
||||
})
|
||||
}
|
||||
|
||||
composable(Route.Message.route, content = { ChatroomListScreen(accountViewModel, navController) })
|
||||
composable(Route.BlockedUsers.route, content = { HiddenUsersScreen(accountViewModel, navController) })
|
||||
composable(Route.Bookmarks.route, content = { BookmarkListScreen(accountViewModel, navController) })
|
||||
composable(Route.Message.route, content = { ChatroomListScreen(accountViewModel, nav) })
|
||||
composable(Route.BlockedUsers.route, content = { HiddenUsersScreen(accountViewModel, nav) })
|
||||
composable(Route.Bookmarks.route, content = { BookmarkListScreen(accountViewModel, nav) })
|
||||
|
||||
Route.Profile.let { route ->
|
||||
composable(route.route, route.arguments, content = {
|
||||
ProfileScreen(
|
||||
userId = it.arguments?.getString("id"),
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -182,7 +190,7 @@ fun AppNavigation(
|
||||
ThreadScreen(
|
||||
noteId = it.arguments?.getString("id"),
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -192,7 +200,7 @@ fun AppNavigation(
|
||||
HashtagScreen(
|
||||
tag = it.arguments?.getString("id"),
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -202,7 +210,7 @@ fun AppNavigation(
|
||||
ChatroomScreen(
|
||||
userId = it.arguments?.getString("id"),
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -212,7 +220,7 @@ fun AppNavigation(
|
||||
ChannelScreen(
|
||||
channelId = it.arguments?.getString("id"),
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -230,7 +238,7 @@ fun AppNavigation(
|
||||
|
||||
actionableNextPage?.let {
|
||||
LaunchedEffect(it) {
|
||||
navController.navigate(it)
|
||||
nav(it)
|
||||
}
|
||||
actionableNextPage = null
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ import kotlinx.coroutines.withContext
|
||||
@Composable
|
||||
fun AppTopBar(followLists: FollowListViewModel, navController: NavHostController, scaffoldState: ScaffoldState, accountViewModel: AccountViewModel) {
|
||||
when (currentRoute(navController)?.substringBefore("?")) {
|
||||
// Route.Profile.route -> TopBarWithBackButton(navController)
|
||||
// Route.Profile.route -> TopBarWithBackButton(nav)
|
||||
Route.Home.base -> HomeTopBar(followLists, scaffoldState, accountViewModel)
|
||||
Route.Video.base -> StoriesTopBar(followLists, scaffoldState, accountViewModel)
|
||||
Route.Notification.base -> NotificationTopBar(followLists, scaffoldState, accountViewModel)
|
||||
|
||||
@@ -48,8 +48,6 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import coil.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.BuildConfig
|
||||
import com.vitorpamplona.amethyst.LocalPreferences
|
||||
@@ -69,7 +67,7 @@ import kotlinx.coroutines.launch
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun DrawerContent(
|
||||
navController: NavHostController,
|
||||
nav: (String) -> Unit,
|
||||
scaffoldState: ScaffoldState,
|
||||
sheetState: ModalBottomSheetState,
|
||||
accountViewModel: AccountViewModel
|
||||
@@ -89,7 +87,7 @@ fun DrawerContent(
|
||||
.padding(horizontal = 25.dp)
|
||||
.padding(top = 100.dp),
|
||||
scaffoldState,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
Divider(
|
||||
thickness = 0.25.dp,
|
||||
@@ -97,7 +95,7 @@ fun DrawerContent(
|
||||
)
|
||||
ListContent(
|
||||
account.userProfile().pubkeyHex,
|
||||
navController,
|
||||
nav,
|
||||
scaffoldState,
|
||||
sheetState,
|
||||
modifier = Modifier
|
||||
@@ -106,7 +104,7 @@ fun DrawerContent(
|
||||
account
|
||||
)
|
||||
|
||||
BottomContent(account.userProfile(), scaffoldState, navController)
|
||||
BottomContent(account.userProfile(), scaffoldState, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +114,7 @@ fun ProfileContent(
|
||||
baseAccountUser: User,
|
||||
modifier: Modifier = Modifier,
|
||||
scaffoldState: ScaffoldState,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
@@ -170,7 +168,7 @@ fun ProfileContent(
|
||||
.border(3.dp, MaterialTheme.colors.background, CircleShape)
|
||||
.background(MaterialTheme.colors.background)
|
||||
.clickable(onClick = {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
@@ -185,7 +183,7 @@ fun ProfileContent(
|
||||
modifier = Modifier
|
||||
.padding(top = 7.dp)
|
||||
.clickable(onClick = {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
@@ -203,7 +201,7 @@ fun ProfileContent(
|
||||
.padding(top = 15.dp)
|
||||
.clickable(
|
||||
onClick = {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
@@ -215,7 +213,7 @@ fun ProfileContent(
|
||||
modifier = Modifier
|
||||
.padding(top = 15.dp)
|
||||
.clickable(onClick = {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
@@ -244,7 +242,7 @@ fun ProfileContent(
|
||||
@Composable
|
||||
fun ListContent(
|
||||
accountUserPubKey: String?,
|
||||
navController: NavHostController,
|
||||
nav: (String) -> Unit,
|
||||
scaffoldState: ScaffoldState,
|
||||
sheetState: ModalBottomSheetState,
|
||||
modifier: Modifier,
|
||||
@@ -263,7 +261,7 @@ fun ListContent(
|
||||
title = stringResource(R.string.profile),
|
||||
icon = Route.Profile.icon,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
scaffoldState = scaffoldState,
|
||||
route = "User/$accountUserPubKey"
|
||||
)
|
||||
@@ -272,7 +270,7 @@ fun ListContent(
|
||||
title = stringResource(R.string.bookmarks),
|
||||
icon = Route.Bookmarks.icon,
|
||||
tint = MaterialTheme.colors.onBackground,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
scaffoldState = scaffoldState,
|
||||
route = Route.Bookmarks.route
|
||||
)
|
||||
@@ -282,7 +280,7 @@ fun ListContent(
|
||||
title = stringResource(R.string.security_filters),
|
||||
icon = Route.BlockedUsers.icon,
|
||||
tint = MaterialTheme.colors.onBackground,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
scaffoldState = scaffoldState,
|
||||
route = Route.BlockedUsers.route
|
||||
)
|
||||
@@ -402,13 +400,13 @@ fun NavigationRow(
|
||||
title: String,
|
||||
icon: Int,
|
||||
tint: Color,
|
||||
navController: NavHostController,
|
||||
nav: (String) -> Unit,
|
||||
scaffoldState: ScaffoldState,
|
||||
route: String
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
IconRow(title, icon, tint, onClick = {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
@@ -448,7 +446,7 @@ fun IconRow(title: String, icon: Int, tint: Color, onClick: () -> Unit, onLongCl
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BottomContent(user: User, scaffoldState: ScaffoldState, navController: NavController) {
|
||||
fun BottomContent(user: User, scaffoldState: ScaffoldState, nav: (String) -> Unit) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
// store the dialog open or close state
|
||||
@@ -515,7 +513,7 @@ fun BottomContent(user: User, scaffoldState: ScaffoldState, navController: NavCo
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
navController.navigate(it)
|
||||
nav(it)
|
||||
},
|
||||
onClose = { dialogOpen = false }
|
||||
)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.vitorpamplona.amethyst.ui.navigation
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.navigation.NamedNavArgument
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
@@ -185,3 +187,48 @@ object MessagesLatestItem {
|
||||
return (note.createdAt() ?: 0) > lastTime
|
||||
}
|
||||
}
|
||||
|
||||
fun getRouteWithArguments(navController: NavHostController): String? {
|
||||
val currentEntry = navController.currentBackStackEntry ?: return null
|
||||
return getRouteWithArguments(currentEntry.destination, currentEntry.arguments)
|
||||
}
|
||||
|
||||
private fun getRouteWithArguments(
|
||||
destination: NavDestination,
|
||||
arguments: Bundle?
|
||||
): String? {
|
||||
var route = destination.route ?: return null
|
||||
arguments?.let { bundle ->
|
||||
destination.arguments.keys.forEach { key ->
|
||||
val value = destination.arguments[key]?.type?.get(bundle, key)?.toString()
|
||||
if (value == null) {
|
||||
val keyStart = route.indexOf("{$key}")
|
||||
// if it is a parameter, removes the complete segment `var={key}` and adjust connectors `#`, `&` or `&`
|
||||
if (keyStart > 0 && route[keyStart - 1] == '=') {
|
||||
val end = keyStart + "{$key}".length
|
||||
var start = keyStart
|
||||
for (i in keyStart downTo 0) {
|
||||
if (route[i] == '#' || route[i] == '?' || route[i] == '&') {
|
||||
start = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if (end < route.length && route[end] == '&') {
|
||||
route = route.removeRange(start, end + 1)
|
||||
} else if (end < route.length && route[end] == '#') {
|
||||
route = route.removeRange(start - 1, end)
|
||||
} else if (end == route.length) {
|
||||
route = route.removeRange(start - 1, end)
|
||||
} else {
|
||||
route = route.removeRange(start, end)
|
||||
}
|
||||
} else {
|
||||
route = route.replaceFirst("{$key}", "")
|
||||
}
|
||||
} else {
|
||||
route = route.replaceFirst("{$key}", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return route
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.screen.BadgeCard
|
||||
@@ -42,7 +41,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BadgeCompose(likeSetCard: BadgeCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun BadgeCompose(likeSetCard: BadgeCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteState by likeSetCard.note.live().metadata.observeAsState()
|
||||
val note = noteState?.note
|
||||
|
||||
@@ -79,7 +78,7 @@ fun BadgeCompose(likeSetCard: BadgeCard, isInnerNote: Boolean = false, routeForL
|
||||
routeFor(
|
||||
note,
|
||||
accountViewModel.userProfile()
|
||||
)?.let { navController.navigate(it) }
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
@@ -149,7 +148,7 @@ fun BadgeCompose(likeSetCard: BadgeCard, isInnerNote: Boolean = false, routeForL
|
||||
isBoostedNote = true,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
@@ -55,7 +54,7 @@ fun BlankNote(modifier: Modifier = Modifier, isQuote: Boolean = false, idHex: St
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HiddenNote(reports: Set<Note>, loggedIn: User, modifier: Modifier = Modifier, isQuote: Boolean = false, navController: NavController, onClick: () -> Unit) {
|
||||
fun HiddenNote(reports: Set<Note>, loggedIn: User, modifier: Modifier = Modifier, isQuote: Boolean = false, nav: (String) -> Unit, onClick: () -> Unit) {
|
||||
Column(modifier = modifier) {
|
||||
Row(modifier = Modifier.padding(horizontal = if (!isQuote) 12.dp else 6.dp)) {
|
||||
Column(modifier = Modifier.padding(start = if (!isQuote) 10.dp else 5.dp)) {
|
||||
@@ -75,7 +74,7 @@ fun HiddenNote(reports: Set<Note>, loggedIn: User, modifier: Modifier = Modifier
|
||||
reports.forEach {
|
||||
NoteAuthorPicture(
|
||||
baseNote = it,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
userAccount = loggedIn,
|
||||
size = 35.dp
|
||||
)
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -37,7 +36,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BoostSetCompose(boostSetCard: BoostSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun BoostSetCompose(boostSetCard: BoostSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteState by boostSetCard.note.live().metadata.observeAsState()
|
||||
val note = noteState?.note
|
||||
|
||||
@@ -77,7 +76,7 @@ fun BoostSetCompose(boostSetCard: BoostSetCard, isInnerNote: Boolean = false, ro
|
||||
routeFor(
|
||||
note,
|
||||
account.userProfile()
|
||||
)?.let { navController.navigate(it) }
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
@@ -114,7 +113,7 @@ fun BoostSetCompose(boostSetCard: BoostSetCard, isInnerNote: Boolean = false, ro
|
||||
boostSetCard.boostEvents.forEach {
|
||||
NoteAuthorPicture(
|
||||
baseNote = it,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
userAccount = account.userProfile(),
|
||||
size = 35.dp
|
||||
)
|
||||
@@ -128,7 +127,7 @@ fun BoostSetCompose(boostSetCard: BoostSetCard, isInnerNote: Boolean = false, ro
|
||||
isBoostedNote = true,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||
|
||||
@@ -39,7 +39,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
@@ -57,7 +56,7 @@ import kotlinx.coroutines.launch
|
||||
fun ChatroomCompose(
|
||||
baseNote: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteState by baseNote.live().metadata.observeAsState()
|
||||
val note = noteState?.note
|
||||
@@ -128,7 +127,7 @@ fun ChatroomCompose(
|
||||
channelLastTime = note.createdAt(),
|
||||
channelLastContent = "${author?.toBestDisplayName()}: " + description,
|
||||
hasNewMessages = hasNewMessages,
|
||||
onClick = { navController.navigate("Channel/${chan.idHex}") }
|
||||
onClick = { nav("Channel/${chan.idHex}") }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -172,7 +171,7 @@ fun ChatroomCompose(
|
||||
channelLastTime = note.createdAt(),
|
||||
channelLastContent = accountViewModel.decrypt(note),
|
||||
hasNewMessages = hasNewMessages,
|
||||
onClick = { navController.navigate("Room/${user.pubkeyHex}") }
|
||||
onClick = { nav("Room/${user.pubkeyHex}") }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -81,7 +80,7 @@ fun ChatroomMessageCompose(
|
||||
innerQuote: Boolean = false,
|
||||
parentBackgroundColor: Color? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
onWantsToReply: (Note) -> Unit
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
@@ -137,7 +136,7 @@ fun ChatroomMessageCompose(
|
||||
account.userProfile(),
|
||||
Modifier,
|
||||
innerQuote,
|
||||
navController,
|
||||
nav,
|
||||
onClick = { showHiddenNote = true }
|
||||
)
|
||||
} else {
|
||||
@@ -210,7 +209,7 @@ fun ChatroomMessageCompose(
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
if (noteEvent is ChannelCreateEvent) {
|
||||
navController.navigate("Channel/${note.idHex}")
|
||||
nav("Channel/${note.idHex}")
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
@@ -229,7 +228,7 @@ fun ChatroomMessageCompose(
|
||||
DrawAuthorInfo(
|
||||
baseNote,
|
||||
alignment,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
} else {
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
@@ -245,7 +244,7 @@ fun ChatroomMessageCompose(
|
||||
innerQuote = true,
|
||||
parentBackgroundColor = backgroundBubbleColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
onWantsToReply = onWantsToReply
|
||||
)
|
||||
}
|
||||
@@ -269,7 +268,7 @@ fun ChatroomMessageCompose(
|
||||
isAcceptableAndCanPreview.second,
|
||||
backgroundBubbleColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -363,7 +362,7 @@ private fun RenderRegularTextNote(
|
||||
canPreview: Boolean,
|
||||
backgroundBubbleColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val tags = remember { note.event?.tags() }
|
||||
val eventContent = remember { accountViewModel.decrypt(note) }
|
||||
@@ -371,23 +370,23 @@ private fun RenderRegularTextNote(
|
||||
|
||||
if (eventContent != null) {
|
||||
TranslatableRichTextViewer(
|
||||
eventContent,
|
||||
canPreview,
|
||||
modifier,
|
||||
tags,
|
||||
backgroundBubbleColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
content = eventContent,
|
||||
canPreview = canPreview,
|
||||
modifier = modifier,
|
||||
tags = tags,
|
||||
backgroundColor = backgroundBubbleColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav
|
||||
)
|
||||
} else {
|
||||
TranslatableRichTextViewer(
|
||||
stringResource(R.string.could_not_decrypt_the_message),
|
||||
true,
|
||||
modifier,
|
||||
tags,
|
||||
backgroundBubbleColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
content = stringResource(id = R.string.could_not_decrypt_the_message),
|
||||
canPreview = true,
|
||||
modifier = modifier,
|
||||
tags = tags,
|
||||
backgroundColor = backgroundBubbleColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -444,7 +443,7 @@ private fun RenderCreateChannelNote(note: Note) {
|
||||
private fun DrawAuthorInfo(
|
||||
baseNote: Note,
|
||||
alignment: Arrangement.Horizontal,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val userState by baseNote.author!!.live().metadata.observeAsState()
|
||||
|
||||
@@ -468,7 +467,7 @@ private fun DrawAuthorInfo(
|
||||
.height(25.dp)
|
||||
.clip(shape = CircleShape)
|
||||
.clickable(onClick = {
|
||||
navController.navigate(route)
|
||||
nav(route)
|
||||
})
|
||||
)
|
||||
|
||||
@@ -479,7 +478,7 @@ private fun DrawAuthorInfo(
|
||||
fontWeight = FontWeight.Bold,
|
||||
overrideColor = MaterialTheme.colors.onBackground,
|
||||
route = route,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -37,7 +36,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun LikeSetCompose(likeSetCard: LikeSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun LikeSetCompose(likeSetCard: LikeSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteState by likeSetCard.note.live().metadata.observeAsState()
|
||||
val note = noteState?.note
|
||||
|
||||
@@ -76,7 +75,7 @@ fun LikeSetCompose(likeSetCard: LikeSetCard, isInnerNote: Boolean = false, route
|
||||
routeFor(
|
||||
note,
|
||||
account.userProfile()
|
||||
)?.let { navController.navigate(it) }
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
@@ -113,7 +112,7 @@ fun LikeSetCompose(likeSetCard: LikeSetCard, isInnerNote: Boolean = false, route
|
||||
likeSetCard.likeEvents.forEach {
|
||||
NoteAuthorPicture(
|
||||
baseNote = it,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
userAccount = account.userProfile(),
|
||||
size = 35.dp
|
||||
)
|
||||
@@ -127,7 +126,7 @@ fun LikeSetCompose(likeSetCard: LikeSetCard, isInnerNote: Boolean = false, route
|
||||
isBoostedNote = true,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.screen.MessageSetCard
|
||||
@@ -35,7 +34,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun MessageSetCompose(messageSetCard: MessageSetCard, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun MessageSetCompose(messageSetCard: MessageSetCard, routeForLastRead: String, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteState by messageSetCard.note.live().metadata.observeAsState()
|
||||
val note = remember(noteState) { noteState?.note }
|
||||
|
||||
@@ -81,7 +80,7 @@ fun MessageSetCompose(messageSetCard: MessageSetCard, routeForLastRead: String,
|
||||
routeFor(
|
||||
note,
|
||||
accountViewModel.userProfile()
|
||||
)?.let { navController.navigate(it) }
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
@@ -108,7 +107,7 @@ fun MessageSetCompose(messageSetCard: MessageSetCard, routeForLastRead: String,
|
||||
addMarginTop = false,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.material.icons.filled.Bolt
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -35,7 +36,6 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -51,13 +51,15 @@ import com.vitorpamplona.amethyst.ui.screen.MultiSetCard
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
|
||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val baseNote = remember { multiSetCard.note }
|
||||
|
||||
val noteState by baseNote.live().metadata.observeAsState()
|
||||
@@ -90,34 +92,38 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
|
||||
val primaryColor = MaterialTheme.colors.primary.copy(0.12f)
|
||||
val defaultBackgroundColor = MaterialTheme.colors.background
|
||||
|
||||
val backgroundColor = remember(isNew) {
|
||||
if (isNew) {
|
||||
primaryColor.compositeOver(defaultBackgroundColor)
|
||||
} else {
|
||||
defaultBackgroundColor
|
||||
val backgroundColor by remember(isNew) {
|
||||
derivedStateOf {
|
||||
if (isNew) {
|
||||
primaryColor.compositeOver(defaultBackgroundColor)
|
||||
} else {
|
||||
defaultBackgroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val columnModifier = remember(isNew) {
|
||||
Modifier
|
||||
.background(backgroundColor)
|
||||
.padding(
|
||||
start = 12.dp,
|
||||
end = 12.dp,
|
||||
top = 10.dp
|
||||
)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
routeFor(
|
||||
baseNote,
|
||||
account.userProfile()
|
||||
)?.let { navController.navigate(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
)
|
||||
.fillMaxWidth()
|
||||
val columnModifier by remember(isNew, backgroundColor) {
|
||||
derivedStateOf {
|
||||
Modifier
|
||||
.background(backgroundColor)
|
||||
.padding(
|
||||
start = 12.dp,
|
||||
end = 12.dp,
|
||||
top = 10.dp
|
||||
)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
routeFor(
|
||||
baseNote,
|
||||
account.userProfile()
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
)
|
||||
.fillMaxWidth()
|
||||
}
|
||||
}
|
||||
|
||||
val zapEvents = remember { multiSetCard.zapEvents }
|
||||
@@ -126,15 +132,15 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
|
||||
|
||||
Column(modifier = columnModifier) {
|
||||
if (zapEvents.isNotEmpty()) {
|
||||
RenderZapGallery(zapEvents, navController, account, accountViewModel)
|
||||
RenderZapGallery(zapEvents, backgroundColor, nav, account, accountViewModel)
|
||||
}
|
||||
|
||||
if (boostEvents.isNotEmpty()) {
|
||||
RenderBoostGallery(boostEvents, navController, account, accountViewModel)
|
||||
RenderBoostGallery(boostEvents, backgroundColor, nav, account, accountViewModel)
|
||||
}
|
||||
|
||||
if (likeEvents.isNotEmpty()) {
|
||||
RenderLikeGallery(likeEvents, navController, account, accountViewModel)
|
||||
RenderLikeGallery(likeEvents, backgroundColor, nav, account, accountViewModel)
|
||||
}
|
||||
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
@@ -147,7 +153,7 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
|
||||
isBoostedNote = true,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||
@@ -158,8 +164,9 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
|
||||
|
||||
@Composable
|
||||
private fun RenderLikeGallery(
|
||||
likeEvents: List<Note>,
|
||||
navController: NavController,
|
||||
likeEvents: ImmutableList<Note>,
|
||||
backgroundColor: Color,
|
||||
nav: (String) -> Unit,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
@@ -183,14 +190,15 @@ private fun RenderLikeGallery(
|
||||
)
|
||||
}
|
||||
|
||||
AuthorGallery(likeEvents, navController, account, accountViewModel)
|
||||
AuthorGallery(likeEvents, backgroundColor, nav, account, accountViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderZapGallery(
|
||||
zapEvents: Map<Note, Note>,
|
||||
navController: NavController,
|
||||
zapEvents: ImmutableMap<Note, Note>,
|
||||
backgroundColor: Color,
|
||||
nav: (String) -> Unit,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
@@ -214,18 +222,23 @@ private fun RenderZapGallery(
|
||||
)
|
||||
}
|
||||
|
||||
AuthorGalleryZaps(zapEvents, navController, account, accountViewModel)
|
||||
AuthorGalleryZaps(zapEvents, backgroundColor, nav, account, accountViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderBoostGallery(
|
||||
boostEvents: List<Note>,
|
||||
navController: NavController,
|
||||
boostEvents: ImmutableList<Note>,
|
||||
backgroundColor: Color,
|
||||
nav: (String) -> Unit,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Row(
|
||||
modifier = remember {
|
||||
Modifier.fillMaxWidth()
|
||||
}
|
||||
) {
|
||||
Box(
|
||||
modifier = remember {
|
||||
Modifier
|
||||
@@ -245,14 +258,15 @@ private fun RenderBoostGallery(
|
||||
)
|
||||
}
|
||||
|
||||
AuthorGallery(boostEvents, navController, account, accountViewModel)
|
||||
AuthorGallery(boostEvents, backgroundColor, nav, account, accountViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AuthorGalleryZaps(
|
||||
authorNotes: Map<Note, Note>,
|
||||
navController: NavController,
|
||||
authorNotes: ImmutableMap<Note, Note>,
|
||||
backgroundColor: Color,
|
||||
nav: (String) -> Unit,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
@@ -261,7 +275,7 @@ fun AuthorGalleryZaps(
|
||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||
FlowRow() {
|
||||
authorNotes.forEach {
|
||||
AuthorPictureAndComment(it.key, it.value, navController, accountState, accountViewModel)
|
||||
AuthorPictureAndComment(it.key, it.value, backgroundColor, nav, accountState, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,7 +285,8 @@ fun AuthorGalleryZaps(
|
||||
private fun AuthorPictureAndComment(
|
||||
zapRequest: Note,
|
||||
zapEvent: Note?,
|
||||
navController: NavController,
|
||||
backgroundColor: Color,
|
||||
nav: (String) -> Unit,
|
||||
accountUser: State<UserState?>,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
@@ -287,23 +302,39 @@ private fun AuthorPictureAndComment(
|
||||
val amount = (zapEvent?.event as? LnZapEvent)?.amount
|
||||
if (decryptedContent != null) {
|
||||
val newAuthor = LocalCache.getOrCreateUser(decryptedContent.pubKey)
|
||||
content = Triple(newAuthor, decryptedContent.content, amount)
|
||||
content = Triple(newAuthor, decryptedContent.content.ifBlank { null }, amount)
|
||||
} else {
|
||||
if (!zapRequest.event?.content().isNullOrBlank() || amount != null) {
|
||||
content = Triple(author, zapRequest.event?.content(), amount)
|
||||
content = Triple(author, zapRequest.event?.content()?.ifBlank { null }, amount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val modifier = remember(content.second) {
|
||||
if (!content.second.isNullOrBlank()) {
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
nav("User/${author.pubkeyHex}")
|
||||
}
|
||||
} else {
|
||||
Modifier.clickable {
|
||||
nav("User/${author.pubkeyHex}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AuthorPictureAndComment(
|
||||
author = content.first,
|
||||
comment = content.second,
|
||||
amount = showAmountAxis(content.third),
|
||||
navController = navController,
|
||||
backgroundColor = backgroundColor,
|
||||
nav = nav,
|
||||
accountUser = accountUser,
|
||||
accountViewModel = accountViewModel
|
||||
accountViewModel = accountViewModel,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@@ -312,24 +343,12 @@ private fun AuthorPictureAndComment(
|
||||
author: User,
|
||||
comment: String?,
|
||||
amount: String?,
|
||||
navController: NavController,
|
||||
backgroundColor: Color,
|
||||
nav: (String) -> Unit,
|
||||
accountUser: State<UserState?>,
|
||||
accountViewModel: AccountViewModel
|
||||
accountViewModel: AccountViewModel,
|
||||
modifier: Modifier
|
||||
) {
|
||||
val modifier = remember(comment) {
|
||||
if (!comment.isNullOrBlank()) {
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
navController.navigate("User/${author.pubkeyHex}")
|
||||
}
|
||||
} else {
|
||||
Modifier.clickable {
|
||||
navController.navigate("User/${author.pubkeyHex}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
@@ -358,16 +377,16 @@ private fun AuthorPictureAndComment(
|
||||
}
|
||||
}
|
||||
|
||||
if (!comment.isNullOrBlank()) {
|
||||
comment?.let {
|
||||
Spacer(modifier = Modifier.width(5.dp))
|
||||
TranslatableRichTextViewer(
|
||||
content = comment,
|
||||
content = it,
|
||||
canPreview = true,
|
||||
tags = null,
|
||||
modifier = Modifier.weight(1f),
|
||||
backgroundColor = MaterialTheme.colors.background,
|
||||
backgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -375,27 +394,26 @@ private fun AuthorPictureAndComment(
|
||||
|
||||
@Composable
|
||||
fun AuthorGallery(
|
||||
authorNotes: Collection<Note>,
|
||||
navController: NavController,
|
||||
authorNotes: ImmutableList<Note>,
|
||||
backgroundColor: Color,
|
||||
nav: (String) -> Unit,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val accountState = account.userProfile().live().follows.observeAsState()
|
||||
val listToRender = remember {
|
||||
Pair(
|
||||
authorNotes.take(50).mapNotNull { it.author },
|
||||
authorNotes.size
|
||||
)
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||
FlowRow() {
|
||||
listToRender.first.forEach { author ->
|
||||
AuthorPictureAndComment(author, null, null, navController, accountState, accountViewModel)
|
||||
}
|
||||
authorNotes.forEach { note ->
|
||||
note.author?.let { user ->
|
||||
val modifier = remember {
|
||||
Modifier.clickable {
|
||||
nav("User/${user.pubkeyHex}")
|
||||
}
|
||||
}
|
||||
|
||||
if (listToRender.second > 50) {
|
||||
Text(" and ${listToRender.second - 50} others")
|
||||
AuthorPictureAndComment(user, null, null, backgroundColor, nav, accountState, accountViewModel, modifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.graphics.get
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import coil.compose.AsyncImagePainter
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
@@ -153,7 +152,7 @@ fun NoteCompose(
|
||||
addMarginTop: Boolean = true,
|
||||
parentBackgroundColor: Color? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = remember(accountState) { accountState?.account } ?: return
|
||||
@@ -212,11 +211,11 @@ fun NoteCompose(
|
||||
account.userProfile(),
|
||||
modifier,
|
||||
isBoostedNote,
|
||||
navController,
|
||||
nav,
|
||||
onClick = { showHiddenNote = true }
|
||||
)
|
||||
} else if ((noteEvent is ChannelCreateEvent || noteEvent is ChannelMetadataEvent) && baseChannel != null) {
|
||||
ChannelHeader(baseChannel = baseChannel, account = account, navController = navController)
|
||||
ChannelHeader(baseChannel = baseChannel, account = account, nav = nav)
|
||||
} else if (noteEvent is BadgeDefinitionEvent) {
|
||||
BadgeDisplay(baseNote = note)
|
||||
} else if (noteEvent is FileHeaderEvent) {
|
||||
@@ -267,11 +266,7 @@ fun NoteCompose(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
routeFor(note, loggedIn)?.let {
|
||||
if (note.idHex != navController.currentBackStackEntry?.arguments?.getString("id")) {
|
||||
navController.navigate(it)
|
||||
} else {
|
||||
Log.d("Amethyst-Navigation", "Note already exists in the backstack!")
|
||||
}
|
||||
nav(it)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -292,7 +287,7 @@ fun NoteCompose(
|
||||
}
|
||||
) {
|
||||
if (!isBoostedNote && !isQuotedNote) {
|
||||
DrawAuthorImages(baseNote, loggedIn, navController)
|
||||
DrawAuthorImages(baseNote, loggedIn, nav)
|
||||
}
|
||||
|
||||
Column(
|
||||
@@ -306,14 +301,14 @@ fun NoteCompose(
|
||||
showAuthorPicture = isQuotedNote,
|
||||
account = account,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
if (noteEvent !is RepostEvent && !makeItShort && !isQuotedNote) {
|
||||
SecondUserInfoRow(
|
||||
note,
|
||||
account,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
|
||||
@@ -326,17 +321,17 @@ fun NoteCompose(
|
||||
backgroundColor,
|
||||
account,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
|
||||
when (noteEvent) {
|
||||
is ReactionEvent -> {
|
||||
RenderReaction(note, backgroundColor, accountViewModel, navController)
|
||||
RenderReaction(note, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is RepostEvent -> {
|
||||
RenderRepost(note, backgroundColor, accountViewModel, navController)
|
||||
RenderRepost(note, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is ReportEvent -> {
|
||||
@@ -344,31 +339,31 @@ fun NoteCompose(
|
||||
}
|
||||
|
||||
is LongTextNoteEvent -> {
|
||||
RenderLongFormContent(note, loggedIn, accountViewModel, navController)
|
||||
RenderLongFormContent(note, loggedIn, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is BadgeAwardEvent -> {
|
||||
RenderBadgeAward(note, backgroundColor, accountViewModel, navController)
|
||||
RenderBadgeAward(note, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is PeopleListEvent -> {
|
||||
RenderPeopleList(noteState, backgroundColor, accountViewModel, navController)
|
||||
RenderPeopleList(noteState, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is AudioTrackEvent -> {
|
||||
RenderAudioTrack(note, loggedIn, accountViewModel, navController)
|
||||
RenderAudioTrack(note, loggedIn, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is PinListEvent -> {
|
||||
RenderPinListEvent(noteState, backgroundColor, accountViewModel, navController)
|
||||
RenderPinListEvent(noteState, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is PrivateDmEvent -> {
|
||||
RenderPrivateMessage(note, makeItShort, isAcceptableAndCanPreview.second, backgroundColor, accountViewModel, navController)
|
||||
RenderPrivateMessage(note, makeItShort, isAcceptableAndCanPreview.second, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is HighlightEvent -> {
|
||||
RenderHighlight(note, makeItShort, isAcceptableAndCanPreview.second, backgroundColor, accountViewModel, navController)
|
||||
RenderHighlight(note, makeItShort, isAcceptableAndCanPreview.second, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is PollNoteEvent -> {
|
||||
@@ -378,7 +373,7 @@ fun NoteCompose(
|
||||
isAcceptableAndCanPreview.second,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
|
||||
@@ -389,7 +384,7 @@ fun NoteCompose(
|
||||
isAcceptableAndCanPreview.second,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -438,7 +433,7 @@ private fun RenderTextEvent(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val tags = remember(note.event?.id()) { note.event?.tags() }
|
||||
val hashtags = remember(note.event?.id()) { note.event?.hashtags() ?: emptyList() }
|
||||
@@ -462,15 +457,15 @@ private fun RenderTextEvent(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
DisplayUncitedHashtags(hashtags, eventContent, navController)
|
||||
DisplayUncitedHashtags(hashtags, eventContent, nav)
|
||||
}
|
||||
}
|
||||
|
||||
if (!makeItShort) {
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Divider(
|
||||
@@ -486,7 +481,7 @@ private fun RenderPoll(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = note.event as? PollNoteEvent ?: return
|
||||
val eventContent = noteEvent.content()
|
||||
@@ -506,22 +501,22 @@ private fun RenderPoll(
|
||||
noteEvent.tags(),
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
|
||||
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController)
|
||||
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, nav)
|
||||
|
||||
PollNote(
|
||||
note,
|
||||
canPreview = canPreview && !makeItShort,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
|
||||
if (!makeItShort) {
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Divider(
|
||||
@@ -537,7 +532,7 @@ private fun RenderHighlight(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = note.event as? HighlightEvent ?: return
|
||||
|
||||
@@ -549,11 +544,11 @@ private fun RenderHighlight(
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
|
||||
if (!makeItShort) {
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Divider(
|
||||
@@ -569,7 +564,7 @@ private fun RenderPrivateMessage(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = note.event as? PrivateDmEvent ?: return
|
||||
val withMe = remember { noteEvent.with(accountViewModel.userProfile().pubkeyHex) }
|
||||
@@ -593,10 +588,10 @@ private fun RenderPrivateMessage(
|
||||
tags = noteEvent.tags(),
|
||||
backgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController)
|
||||
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, nav)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -613,12 +608,12 @@ private fun RenderPrivateMessage(
|
||||
noteEvent.tags(),
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
|
||||
if (!makeItShort) {
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Divider(
|
||||
@@ -632,12 +627,12 @@ fun RenderPeopleList(
|
||||
noteState: NoteState?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
DisplayPeopleList(noteState, backgroundColor, accountViewModel, navController)
|
||||
DisplayPeopleList(noteState, backgroundColor, accountViewModel, nav)
|
||||
|
||||
noteState?.note?.let {
|
||||
ReactionsRow(it, accountViewModel, navController)
|
||||
ReactionsRow(it, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Divider(
|
||||
@@ -651,7 +646,7 @@ fun DisplayPeopleList(
|
||||
noteState: NoteState?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val note = remember(noteState) { noteState?.note } ?: return
|
||||
val noteEvent = note.event as? PeopleListEvent ?: return
|
||||
@@ -696,7 +691,7 @@ fun DisplayPeopleList(
|
||||
user,
|
||||
overallModifier = Modifier,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -740,7 +735,7 @@ private fun RenderBadgeAward(
|
||||
note: Note,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
if (note.replyTo.isNullOrEmpty()) return
|
||||
|
||||
@@ -765,7 +760,7 @@ private fun RenderBadgeAward(
|
||||
modifier = Modifier
|
||||
.size(size = 35.dp)
|
||||
.clickable {
|
||||
navController.navigate("User/${user.pubkeyHex}")
|
||||
nav("User/${user.pubkeyHex}")
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
@@ -791,11 +786,11 @@ private fun RenderBadgeAward(
|
||||
unPackReply = false,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.padding(top = 10.dp),
|
||||
@@ -808,7 +803,7 @@ private fun RenderReaction(
|
||||
note: Note,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
note.replyTo?.lastOrNull()?.let {
|
||||
NoteCompose(
|
||||
@@ -818,7 +813,7 @@ private fun RenderReaction(
|
||||
unPackReply = false,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
@@ -836,7 +831,7 @@ private fun RenderRepost(
|
||||
note: Note,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val boostedNote = remember {
|
||||
note.replyTo?.lastOrNull()
|
||||
@@ -850,7 +845,7 @@ private fun RenderRepost(
|
||||
unPackReply = false,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -860,13 +855,13 @@ private fun RenderPinListEvent(
|
||||
noteState: NoteState?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = noteState?.note?.event as? PinListEvent ?: return
|
||||
|
||||
PinListHeader(noteState, backgroundColor, accountViewModel, navController)
|
||||
PinListHeader(noteState, backgroundColor, accountViewModel, nav)
|
||||
|
||||
ReactionsRow(noteState?.note, accountViewModel, navController)
|
||||
ReactionsRow(noteState?.note, accountViewModel, nav)
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.padding(top = 10.dp),
|
||||
@@ -879,7 +874,7 @@ fun PinListHeader(
|
||||
noteState: NoteState?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val note = remember(noteState) { noteState?.note } ?: return
|
||||
val noteEvent = note.event as? PinListEvent ?: return
|
||||
@@ -926,7 +921,7 @@ fun PinListHeader(
|
||||
tags = emptyList(),
|
||||
backgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -970,13 +965,13 @@ private fun RenderAudioTrack(
|
||||
note: Note,
|
||||
loggedIn: User,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = note.event as? AudioTrackEvent ?: return
|
||||
|
||||
AudioTrackHeader(noteEvent, note, loggedIn, navController)
|
||||
AudioTrackHeader(noteEvent, note, loggedIn, nav)
|
||||
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.padding(top = 10.dp),
|
||||
@@ -989,13 +984,13 @@ private fun RenderLongFormContent(
|
||||
note: Note,
|
||||
loggedIn: User,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = note.event as? LongTextNoteEvent ?: return
|
||||
|
||||
LongFormHeader(noteEvent, note, loggedIn)
|
||||
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.padding(top = 10.dp),
|
||||
@@ -1042,7 +1037,7 @@ private fun ReplyRow(
|
||||
backgroundColor: Color,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = note.event
|
||||
|
||||
@@ -1068,16 +1063,16 @@ private fun ReplyRow(
|
||||
parentBackgroundColor = MaterialTheme.colors.onSurface.copy(alpha = 0.05f)
|
||||
.compositeOver(backgroundColor),
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else {
|
||||
ReplyInformation(note.replyTo, noteEvent.mentions(), account, navController)
|
||||
ReplyInformation(note.replyTo, noteEvent.mentions(), account, nav)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
} else if (noteEvent is ChannelMessageEvent && (note.replyTo != null || noteEvent.hasAnyTaggedUser())) {
|
||||
note.channel()?.let {
|
||||
ReplyInformationChannel(note.replyTo, noteEvent.mentions(), it, account, navController)
|
||||
ReplyInformationChannel(note.replyTo, noteEvent.mentions(), it, account, nav)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
@@ -1088,7 +1083,7 @@ private fun ReplyRow(
|
||||
private fun SecondUserInfoRow(
|
||||
note: Note,
|
||||
account: Account,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = remember { note.event } ?: return
|
||||
val noteAuthor = remember { note.author } ?: return
|
||||
@@ -1098,7 +1093,7 @@ private fun SecondUserInfoRow(
|
||||
|
||||
val baseReward = remember { noteEvent.getReward() }
|
||||
if (baseReward != null) {
|
||||
DisplayReward(baseReward, note, account, navController)
|
||||
DisplayReward(baseReward, note, account, nav)
|
||||
}
|
||||
|
||||
val pow = remember { noteEvent.getPoWRank() }
|
||||
@@ -1114,7 +1109,7 @@ private fun FirstUserInfoRow(
|
||||
showAuthorPicture: Boolean,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var moreActionsExpanded by remember { mutableStateOf(false) }
|
||||
val eventNote = remember { baseNote.event } ?: return
|
||||
@@ -1126,7 +1121,7 @@ private fun FirstUserInfoRow(
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (showAuthorPicture) {
|
||||
NoteAuthorPicture(baseNote, navController, loggedIn, 25.dp)
|
||||
NoteAuthorPicture(baseNote, nav, loggedIn, 25.dp)
|
||||
Spacer(padding)
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
|
||||
} else {
|
||||
@@ -1140,7 +1135,7 @@ private fun FirstUserInfoRow(
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
|
||||
)
|
||||
} else {
|
||||
DisplayFollowingHashtagsInPost(eventNote, account, navController)
|
||||
DisplayFollowingHashtagsInPost(eventNote, account, nav)
|
||||
}
|
||||
|
||||
TimeAgo(time)
|
||||
@@ -1188,17 +1183,17 @@ fun TimeAgo(time: Long) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DrawAuthorImages(baseNote: Note, loggedIn: User, navController: NavController) {
|
||||
private fun DrawAuthorImages(baseNote: Note, loggedIn: User, nav: (String) -> Unit) {
|
||||
val baseChannel = remember { baseNote.channel() }
|
||||
val modifier = remember { Modifier.width(55.dp) }
|
||||
|
||||
Column(modifier) {
|
||||
// Draws the boosted picture outside the boosted card.
|
||||
Box(modifier = modifier, contentAlignment = Alignment.BottomEnd) {
|
||||
NoteAuthorPicture(baseNote, navController, loggedIn, 55.dp)
|
||||
NoteAuthorPicture(baseNote, nav, loggedIn, 55.dp)
|
||||
|
||||
if (baseNote.event is RepostEvent) {
|
||||
RepostNoteAuthorPicture(baseNote, navController, loggedIn)
|
||||
RepostNoteAuthorPicture(baseNote, nav, loggedIn)
|
||||
}
|
||||
|
||||
if (baseNote.event is ChannelMessageEvent && baseChannel != null) {
|
||||
@@ -1262,7 +1257,7 @@ private fun ChannelNotePicture(baseChannel: Channel) {
|
||||
@Composable
|
||||
private fun RepostNoteAuthorPicture(
|
||||
baseNote: Note,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
loggedIn: User
|
||||
) {
|
||||
val baseRepost = remember { baseNote.replyTo?.lastOrNull() }
|
||||
@@ -1277,7 +1272,7 @@ private fun RepostNoteAuthorPicture(
|
||||
Box(modifier) {
|
||||
NoteAuthorPicture(
|
||||
it,
|
||||
navController,
|
||||
nav,
|
||||
loggedIn,
|
||||
35.dp,
|
||||
pictureModifier = Modifier.border(
|
||||
@@ -1299,7 +1294,7 @@ fun DisplayHighlight(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val quote =
|
||||
remember {
|
||||
@@ -1316,7 +1311,7 @@ fun DisplayHighlight(
|
||||
emptyList(),
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
|
||||
var userBase by remember { mutableStateOf<User?>(null) }
|
||||
@@ -1343,7 +1338,7 @@ fun DisplayHighlight(
|
||||
suffix = " ",
|
||||
tags = userTags,
|
||||
route = route,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1371,7 +1366,7 @@ fun DisplayHighlight(
|
||||
fun DisplayFollowingHashtagsInPost(
|
||||
noteEvent: EventInterface,
|
||||
account: Account,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var firstTag by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
@@ -1386,7 +1381,7 @@ fun DisplayFollowingHashtagsInPost(
|
||||
firstTag?.let {
|
||||
ClickableText(
|
||||
text = AnnotatedString(" #$firstTag"),
|
||||
onClick = { navController.navigate("Hashtag/$firstTag") },
|
||||
onClick = { nav("Hashtag/$firstTag") },
|
||||
style = LocalTextStyle.current.copy(
|
||||
color = MaterialTheme.colors.primary.copy(
|
||||
alpha = 0.52f
|
||||
@@ -1402,7 +1397,7 @@ fun DisplayFollowingHashtagsInPost(
|
||||
fun DisplayUncitedHashtags(
|
||||
hashtags: List<String>,
|
||||
eventContent: String,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
if (hashtags.isNotEmpty()) {
|
||||
FlowRow(
|
||||
@@ -1412,7 +1407,7 @@ fun DisplayUncitedHashtags(
|
||||
if (!eventContent.contains(hashtag, true)) {
|
||||
ClickableText(
|
||||
text = AnnotatedString("#$hashtag "),
|
||||
onClick = { navController.navigate("Hashtag/$hashtag") },
|
||||
onClick = { nav("Hashtag/$hashtag") },
|
||||
style = LocalTextStyle.current.copy(
|
||||
color = MaterialTheme.colors.primary.copy(
|
||||
alpha = 0.52f
|
||||
@@ -1444,7 +1439,7 @@ fun DisplayReward(
|
||||
baseReward: BigDecimal,
|
||||
baseNote: Note,
|
||||
account: Account,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var popupExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
@@ -1455,7 +1450,7 @@ fun DisplayReward(
|
||||
) {
|
||||
ClickableText(
|
||||
text = AnnotatedString("#bounty"),
|
||||
onClick = { navController.navigate("Hashtag/bounty") },
|
||||
onClick = { nav("Hashtag/bounty") },
|
||||
style = LocalTextStyle.current.copy(
|
||||
color = MaterialTheme.colors.primary.copy(
|
||||
alpha = 0.52f
|
||||
@@ -1676,7 +1671,7 @@ fun FileStorageHeaderDisplay(baseNote: Note) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AudioTrackHeader(noteEvent: AudioTrackEvent, note: Note, loggedIn: User, navController: NavController) {
|
||||
fun AudioTrackHeader(noteEvent: AudioTrackEvent, note: Note, loggedIn: User, nav: (String) -> Unit) {
|
||||
val media = remember { noteEvent.media() }
|
||||
val cover = remember { noteEvent.cover() }
|
||||
val subject = remember { noteEvent.subject() }
|
||||
@@ -1713,7 +1708,7 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, note: Note, loggedIn: User, nav
|
||||
modifier = Modifier
|
||||
.padding(top = 5.dp, start = 10.dp, end = 10.dp)
|
||||
.clickable {
|
||||
navController.navigate("User/${it.second.pubkeyHex}")
|
||||
nav("User/${it.second.pubkeyHex}")
|
||||
}
|
||||
) {
|
||||
UserPicture(it.second, loggedIn, 25.dp)
|
||||
@@ -1962,17 +1957,13 @@ private fun ShowMoreRelaysButton(onClick: () -> Unit) {
|
||||
@Composable
|
||||
fun NoteAuthorPicture(
|
||||
baseNote: Note,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
userAccount: User,
|
||||
size: Dp,
|
||||
pictureModifier: Modifier = Modifier
|
||||
) {
|
||||
NoteAuthorPicture(baseNote, userAccount, size, pictureModifier) {
|
||||
if (it.pubkeyHex != navController.currentBackStackEntry?.arguments?.getString("id")) {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
} else {
|
||||
Log.d("Amethyst-Navigation", "Profile destination already exists in the backstack!")
|
||||
}
|
||||
nav("User/${it.pubkeyHex}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2019,17 +2010,13 @@ fun NoteAuthorPicture(
|
||||
@Composable
|
||||
fun UserPicture(
|
||||
user: User,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
userAccount: User,
|
||||
size: Dp,
|
||||
pictureModifier: Modifier = Modifier
|
||||
) {
|
||||
UserPicture(user, userAccount, size, pictureModifier) {
|
||||
if (it.pubkeyHex != navController.currentBackStackEntry?.arguments?.getString("id")) {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
} else {
|
||||
Log.d("Amethyst-Navigation", "Profile destination already exists in the backstack!")
|
||||
}
|
||||
nav("User/${it.pubkeyHex}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.compose.ui.window.Popup
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
@@ -47,7 +46,7 @@ fun PollNote(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = remember(accountState) { accountState?.account } ?: return
|
||||
@@ -64,7 +63,7 @@ fun PollNote(
|
||||
canPreview = canPreview,
|
||||
backgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ fun PollNote(
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val zapsState by baseNote.live().zaps.observeAsState()
|
||||
|
||||
@@ -93,7 +92,7 @@ fun PollNote(
|
||||
accountViewModel,
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -106,7 +105,7 @@ private fun OptionNote(
|
||||
accountViewModel: AccountViewModel,
|
||||
canPreview: Boolean,
|
||||
backgroundColor: Color,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -168,7 +167,7 @@ private fun OptionNote(
|
||||
pollViewModel.pollEvent?.tags(),
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -202,7 +201,7 @@ private fun OptionNote(
|
||||
pollViewModel.pollEvent?.tags(),
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Popup
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
@@ -66,7 +65,7 @@ import java.math.RoundingMode
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun ReactionsRow(baseNote: Note, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ReactionsRow(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = remember(accountState) { accountState?.account } ?: return
|
||||
|
||||
@@ -81,11 +80,11 @@ fun ReactionsRow(baseNote: Note, accountViewModel: AccountViewModel, navControll
|
||||
}
|
||||
|
||||
if (wantsToReplyTo != null) {
|
||||
NewPostView({ wantsToReplyTo = null }, wantsToReplyTo, null, account, accountViewModel, navController)
|
||||
NewPostView({ wantsToReplyTo = null }, wantsToReplyTo, null, account, accountViewModel, nav)
|
||||
}
|
||||
|
||||
if (wantsToQuote != null) {
|
||||
NewPostView({ wantsToQuote = null }, null, wantsToQuote, account, accountViewModel, navController)
|
||||
NewPostView({ wantsToQuote = null }, null, wantsToQuote, account, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
@@ -14,7 +14,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.*
|
||||
@@ -23,7 +22,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun ReplyInformation(replyTo: List<Note>?, mentions: List<String>, account: Account, navController: NavController) {
|
||||
fun ReplyInformation(replyTo: List<Note>?, mentions: List<String>, account: Account, nav: (String) -> Unit) {
|
||||
var dupMentions by remember { mutableStateOf<List<User>?>(null) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -34,7 +33,7 @@ fun ReplyInformation(replyTo: List<Note>?, mentions: List<String>, account: Acco
|
||||
|
||||
if (dupMentions != null) {
|
||||
ReplyInformation(replyTo, dupMentions, account) {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
nav("User/${it.pubkeyHex}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +115,7 @@ fun ReplyInformation(replyTo: List<Note>?, dupMentions: List<User>?, account: Ac
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReplyInformationChannel(replyTo: List<Note>?, mentions: List<String>, channel: Channel, account: Account, navController: NavController) {
|
||||
fun ReplyInformationChannel(replyTo: List<Note>?, mentions: List<String>, channel: Channel, account: Account, nav: (String) -> Unit) {
|
||||
var sortedMentions by remember { mutableStateOf<List<User>?>(null) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -134,26 +133,26 @@ fun ReplyInformationChannel(replyTo: List<Note>?, mentions: List<String>, channe
|
||||
sortedMentions,
|
||||
channel,
|
||||
onUserTagClick = {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
nav("User/${it.pubkeyHex}")
|
||||
},
|
||||
onChannelTagClick = {
|
||||
navController.navigate("Channel/${it.idHex}")
|
||||
nav("Channel/${it.idHex}")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReplyInformationChannel(replyTo: List<Note>?, mentions: List<User>?, channel: Channel, navController: NavController) {
|
||||
fun ReplyInformationChannel(replyTo: List<Note>?, mentions: List<User>?, channel: Channel, nav: (String) -> Unit) {
|
||||
ReplyInformationChannel(
|
||||
replyTo,
|
||||
mentions,
|
||||
channel,
|
||||
onUserTagClick = {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
nav("User/${it.pubkeyHex}")
|
||||
},
|
||||
onChannelTagClick = {
|
||||
navController.navigate("Channel/${it.idHex}")
|
||||
nav("Channel/${it.idHex}")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.FollowButton
|
||||
@@ -34,7 +33,7 @@ fun UserCompose(
|
||||
top = 10.dp
|
||||
),
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
@@ -47,14 +46,14 @@ fun UserCompose(
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.clickable(
|
||||
onClick = { navController.navigate("User/${baseUser.pubkeyHex}") }
|
||||
onClick = { nav("User/${baseUser.pubkeyHex}") }
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
modifier = overallModifier,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
UserPicture(baseUser, navController, account.userProfile(), 55.dp)
|
||||
UserPicture(baseUser, nav, account.userProfile(), 55.dp)
|
||||
|
||||
Column(modifier = Modifier.padding(start = 10.dp).weight(1f)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavController
|
||||
import com.patrykandpatrick.vico.core.chart.composed.ComposedChartEntryModel
|
||||
import com.patrykandpatrick.vico.core.entry.ChartEntryModel
|
||||
import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer
|
||||
@@ -54,7 +53,7 @@ import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
@Composable
|
||||
fun UserReactionsRow(model: UserReactionsViewModel, accountViewModel: AccountViewModel, navController: NavController, onClick: () -> Unit) {
|
||||
fun UserReactionsRow(model: UserReactionsViewModel, accountViewModel: AccountViewModel, nav: (String) -> Unit, onClick: () -> Unit) {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
modifier = Modifier
|
||||
|
||||
@@ -23,7 +23,6 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||
@@ -37,7 +36,7 @@ import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
fun ZapNoteCompose(baseNote: Pair<Note, Note>, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ZapNoteCompose(baseNote: Pair<Note, Note>, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
@@ -60,7 +59,7 @@ fun ZapNoteCompose(baseNote: Pair<Note, Note>, accountViewModel: AccountViewMode
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.clickable(
|
||||
onClick = { navController.navigate("User/${baseAuthor.pubkeyHex}") }
|
||||
onClick = { nav("User/${baseAuthor.pubkeyHex}") }
|
||||
),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
@@ -73,7 +72,7 @@ fun ZapNoteCompose(baseNote: Pair<Note, Note>, accountViewModel: AccountViewMode
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
UserPicture(baseAuthor, navController, account.userProfile(), 55.dp)
|
||||
UserPicture(baseAuthor, nav, account.userProfile(), 55.dp)
|
||||
|
||||
Column(modifier = Modifier.padding(start = 10.dp).weight(1f)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -39,7 +38,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ZapSetCompose(zapSetCard: ZapSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ZapSetCompose(zapSetCard: ZapSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteState by zapSetCard.note.live().metadata.observeAsState()
|
||||
val note = noteState?.note
|
||||
|
||||
@@ -78,7 +77,7 @@ fun ZapSetCompose(zapSetCard: ZapSetCard, isInnerNote: Boolean = false, routeFor
|
||||
routeFor(
|
||||
note,
|
||||
account.userProfile()
|
||||
)?.let { navController.navigate(it) }
|
||||
)?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
@@ -115,7 +114,7 @@ fun ZapSetCompose(zapSetCard: ZapSetCard, isInnerNote: Boolean = false, routeFor
|
||||
zapSetCard.zapEvents.forEach {
|
||||
NoteAuthorPicture(
|
||||
baseNote = it.key,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
userAccount = account.userProfile(),
|
||||
size = 35.dp
|
||||
)
|
||||
@@ -129,7 +128,7 @@ fun ZapSetCompose(zapSetCard: ZapSetCard, isInnerNote: Boolean = false, routeFor
|
||||
isBoostedNote = true,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -37,7 +36,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ZapUserSetCompose(zapSetCard: ZapUserSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ZapUserSetCompose(zapSetCard: ZapUserSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
@@ -61,7 +60,7 @@ fun ZapUserSetCompose(zapSetCard: ZapUserSetCard, isInnerNote: Boolean = false,
|
||||
modifier = Modifier
|
||||
.background(backgroundColor)
|
||||
.clickable {
|
||||
navController.navigate("User/${zapSetCard.user.pubkeyHex}")
|
||||
nav("User/${zapSetCard.user.pubkeyHex}")
|
||||
}
|
||||
) {
|
||||
Row(
|
||||
@@ -95,14 +94,14 @@ fun ZapUserSetCompose(zapSetCard: ZapUserSetCard, isInnerNote: Boolean = false,
|
||||
zapSetCard.zapEvents.forEach {
|
||||
NoteAuthorPicture(
|
||||
baseNote = it.key,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
userAccount = account.userProfile(),
|
||||
size = 35.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
UserCompose(baseUser = zapSetCard.user, accountViewModel = accountViewModel, navController = navController)
|
||||
UserCompose(baseUser = zapSetCard.user, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.MainScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginPage
|
||||
@@ -21,10 +22,20 @@ fun AccountScreen(accountStateViewModel: AccountStateViewModel, startingPage: St
|
||||
LoginPage(accountStateViewModel, isFirstLogin = true)
|
||||
}
|
||||
is AccountState.LoggedIn -> {
|
||||
MainScreen(AccountViewModel(state.account), accountStateViewModel, startingPage)
|
||||
val accountViewModel: AccountViewModel = viewModel(
|
||||
key = state.account.userProfile().pubkeyHex,
|
||||
factory = AccountViewModel.Factory(state.account)
|
||||
)
|
||||
|
||||
MainScreen(accountViewModel, accountStateViewModel, startingPage)
|
||||
}
|
||||
is AccountState.LoggedInViewOnly -> {
|
||||
MainScreen(AccountViewModel(state.account), accountStateViewModel, startingPage)
|
||||
val accountViewModel: AccountViewModel = viewModel(
|
||||
key = state.account.userProfile().pubkeyHex,
|
||||
factory = AccountViewModel.Factory(state.account)
|
||||
)
|
||||
|
||||
MainScreen(accountViewModel, accountStateViewModel, startingPage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
|
||||
@Immutable
|
||||
abstract class Card() {
|
||||
abstract fun createdAt(): Long
|
||||
abstract fun id(): String
|
||||
@@ -47,7 +50,7 @@ class ZapSetCard(val note: Note, val zapEvents: Map<Note, Note>) : Card() {
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class ZapUserSetCard(val user: User, val zapEvents: Map<Note, Note>) : Card() {
|
||||
class ZapUserSetCard(val user: User, val zapEvents: ImmutableMap<Note, Note>) : Card() {
|
||||
val createdAt = zapEvents.maxOf { it.value.createdAt() ?: 0 }
|
||||
override fun createdAt(): Long {
|
||||
return createdAt
|
||||
@@ -56,7 +59,7 @@ class ZapUserSetCard(val user: User, val zapEvents: Map<Note, Note>) : Card() {
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class MultiSetCard(val note: Note, val boostEvents: List<Note>, val likeEvents: List<Note>, val zapEvents: Map<Note, Note>) : Card() {
|
||||
class MultiSetCard(val note: Note, val boostEvents: ImmutableList<Note>, val likeEvents: ImmutableList<Note>, val zapEvents: ImmutableMap<Note, Note>) : Card() {
|
||||
val createdAt = maxOf(
|
||||
zapEvents.maxOfOrNull { it.value.createdAt() ?: 0 } ?: 0,
|
||||
likeEvents.maxOfOrNull { it.createdAt() ?: 0 } ?: 0,
|
||||
@@ -91,7 +94,7 @@ class MessageSetCard(val note: Note) : Card() {
|
||||
|
||||
sealed class CardFeedState {
|
||||
object Loading : CardFeedState()
|
||||
class Loaded(val feed: MutableState<List<Card>>) : CardFeedState()
|
||||
class Loaded(val feed: MutableState<ImmutableList<Card>>) : CardFeedState()
|
||||
object Empty : CardFeedState()
|
||||
class FeedError(val errorMessage: String) : CardFeedState()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -23,7 +22,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.ui.note.BadgeCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.BoostSetCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.LikeSetCompose
|
||||
@@ -33,15 +31,13 @@ import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapSetCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapUserSetCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTimedValue
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun CardFeedView(
|
||||
viewModel: CardFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
routeForLastRead: String,
|
||||
scrollStateKey: String? = null,
|
||||
scrollToTop: Boolean = false
|
||||
@@ -74,7 +70,7 @@ fun CardFeedView(
|
||||
FeedLoaded(
|
||||
state = state,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead,
|
||||
scrollStateKey = scrollStateKey,
|
||||
scrollToTop = scrollToTop
|
||||
@@ -91,12 +87,11 @@ fun CardFeedView(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
@Composable
|
||||
private fun FeedLoaded(
|
||||
state: CardFeedState.Loaded,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
routeForLastRead: String,
|
||||
scrollStateKey: String?,
|
||||
scrollToTop: Boolean = false
|
||||
@@ -121,64 +116,61 @@ private fun FeedLoaded(
|
||||
state = listState
|
||||
) {
|
||||
itemsIndexed(state.feed.value, key = { _, item -> item.id() }) { _, item ->
|
||||
val (value, elapsed) = measureTimedValue {
|
||||
when (item) {
|
||||
is NoteCard -> NoteCompose(
|
||||
item.note,
|
||||
isBoostedNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is ZapSetCard -> ZapSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is ZapUserSetCard -> ZapUserSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is LikeSetCard -> LikeSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is BoostSetCard -> BoostSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is MultiSetCard -> MultiSetCompose(
|
||||
item,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is BadgeCard -> BadgeCompose(
|
||||
item,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is MessageSetCard -> MessageSetCompose(
|
||||
messageSetCard = item,
|
||||
routeForLastRead = routeForLastRead,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
when (item) {
|
||||
is NoteCard -> NoteCompose(
|
||||
item.note,
|
||||
isBoostedNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is ZapSetCard -> ZapSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is ZapUserSetCard -> ZapUserSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is LikeSetCard -> LikeSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is BoostSetCard -> BoostSetCompose(
|
||||
item,
|
||||
isInnerNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is MultiSetCard -> MultiSetCompose(
|
||||
item,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is BadgeCard -> BadgeCompose(
|
||||
item,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead
|
||||
)
|
||||
is MessageSetCard -> MessageSetCompose(
|
||||
messageSetCard = item,
|
||||
routeForLastRead = routeForLastRead,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
Log.d("Time", "${item.javaClass.simpleName} Feed in $elapsed ${item.id()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
||||
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.FeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -59,17 +62,28 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
if (newCards.isNotEmpty()) {
|
||||
lastNotes = notes.toSet()
|
||||
lastAccount = (localFilter as? NotificationFeedFilter)?.account
|
||||
val singleList = (oldNotesState.feed.value + newCards)
|
||||
|
||||
val updatedCards = (oldNotesState.feed.value + newCards)
|
||||
.distinctBy { it.id() }
|
||||
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
||||
.reversed()
|
||||
.take(1000)
|
||||
updateFeed(singleList)
|
||||
.toImmutableList()
|
||||
|
||||
if (!equalImmutableLists(oldNotesState.feed.value, updatedCards)) {
|
||||
updateFeed(updatedCards)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val cards = convertToCard(notes)
|
||||
lastNotes = notes.toSet()
|
||||
lastAccount = (localFilter as? NotificationFeedFilter)?.account
|
||||
|
||||
val cards = convertToCard(notes)
|
||||
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
||||
.reversed()
|
||||
.take(1000)
|
||||
.toImmutableList()
|
||||
|
||||
updateFeed(cards)
|
||||
}
|
||||
}
|
||||
@@ -138,9 +152,9 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
singleList.chunked(50).map { chunk ->
|
||||
MultiSetCard(
|
||||
baseNote,
|
||||
boostsInCard.filter { it in chunk },
|
||||
reactionsInCard.filter { it in chunk },
|
||||
zapsInCard.filter { it.value in chunk }
|
||||
boostsInCard.filter { it in chunk }.toImmutableList(),
|
||||
reactionsInCard.filter { it in chunk }.toImmutableList(),
|
||||
zapsInCard.filter { it.value in chunk }.toImmutableMap()
|
||||
)
|
||||
}
|
||||
}.flatten()
|
||||
@@ -148,7 +162,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
val userZaps = zapsPerUser.map {
|
||||
ZapUserSetCard(
|
||||
it.key,
|
||||
it.value
|
||||
it.value.toImmutableMap()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -165,7 +179,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
return (multiCards + textNoteCards + userZaps).sortedWith(compareBy({ it.createdAt() }, { it.id() })).reversed()
|
||||
}
|
||||
|
||||
private fun updateFeed(notes: List<Card>) {
|
||||
private fun updateFeed(notes: ImmutableList<Card>) {
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
val currentState = _feedContent.value
|
||||
@@ -173,7 +187,6 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { CardFeedState.Empty }
|
||||
} else if (currentState is CardFeedState.Loaded) {
|
||||
// updates the current list
|
||||
currentState.feed.value = notes
|
||||
} else {
|
||||
_feedContent.update { CardFeedState.Loaded(mutableStateOf(notes)) }
|
||||
@@ -207,8 +220,11 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
||||
.reversed()
|
||||
.take(1000)
|
||||
.toImmutableList()
|
||||
|
||||
updateFeed(updatedCards)
|
||||
if (!equalImmutableLists(oldNotesState.feed.value, updatedCards)) {
|
||||
updateFeed(updatedCards)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Refresh Everything
|
||||
@@ -227,8 +243,8 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
}
|
||||
private val bundlerInsert = BundledInsert<Set<Note>>(250, Dispatchers.IO)
|
||||
|
||||
fun invalidateData() {
|
||||
bundler.invalidate()
|
||||
fun invalidateData(ignoreIfDoing: Boolean = false) {
|
||||
bundler.invalidate(ignoreIfDoing)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
@@ -270,3 +286,13 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
super.onCleared()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> equalImmutableLists(list1: ImmutableList<T>, list2: ImmutableList<T>): Boolean {
|
||||
if (list1.size != list2.size) return false
|
||||
for (i in 0 until list1.size) {
|
||||
if (list1[i] !== list2[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -14,13 +14,12 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.note.ChatroomMessageCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
fun ChatroomFeedView(viewModel: FeedViewModel, accountViewModel: AccountViewModel, navController: NavController, routeForLastRead: String, onWantsToReply: (Note) -> Unit) {
|
||||
fun ChatroomFeedView(viewModel: FeedViewModel, accountViewModel: AccountViewModel, nav: (String) -> Unit, routeForLastRead: String, onWantsToReply: (Note) -> Unit) {
|
||||
val feedState by viewModel.feedContent.collectAsState()
|
||||
|
||||
var isRefreshing by remember { mutableStateOf(false) }
|
||||
@@ -63,7 +62,7 @@ fun ChatroomFeedView(viewModel: FeedViewModel, accountViewModel: AccountViewMode
|
||||
state = listState
|
||||
) {
|
||||
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item ->
|
||||
ChatroomMessageCompose(item, routeForLastRead, accountViewModel = accountViewModel, navController = navController, onWantsToReply = onWantsToReply)
|
||||
ChatroomMessageCompose(item, routeForLastRead, accountViewModel = accountViewModel, nav = nav, onWantsToReply = onWantsToReply)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.NotificationCache
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
||||
@@ -36,7 +35,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
fun ChatroomListFeedView(
|
||||
viewModel: FeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
markAsRead: MutableState<Boolean>
|
||||
) {
|
||||
val feedState by viewModel.feedContent.collectAsStateWithLifecycle()
|
||||
@@ -68,7 +67,7 @@ fun ChatroomListFeedView(
|
||||
if (refreshing) {
|
||||
refreshing = false
|
||||
}
|
||||
FeedLoaded(state, accountViewModel, navController, markAsRead)
|
||||
FeedLoaded(state, accountViewModel, nav, markAsRead)
|
||||
}
|
||||
|
||||
FeedState.Loading -> {
|
||||
@@ -86,7 +85,7 @@ fun ChatroomListFeedView(
|
||||
private fun FeedLoaded(
|
||||
state: FeedState.Loaded,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
markAsRead: MutableState<Boolean>
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
@@ -139,7 +138,7 @@ private fun FeedLoaded(
|
||||
ChatroomCompose(
|
||||
item,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@@ -39,7 +38,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
fun FeedView(
|
||||
viewModel: FeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
routeForLastRead: String?,
|
||||
scrollStateKey: String? = null,
|
||||
scrollToTop: Boolean = false,
|
||||
@@ -84,7 +83,7 @@ fun FeedView(
|
||||
state,
|
||||
routeForLastRead,
|
||||
accountViewModel,
|
||||
navController,
|
||||
nav,
|
||||
scrollStateKey,
|
||||
scrollToTop
|
||||
)
|
||||
@@ -108,7 +107,7 @@ private fun FeedLoaded(
|
||||
state: FeedState.Loaded,
|
||||
routeForLastRead: String?,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
scrollStateKey: String?,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
@@ -142,7 +141,7 @@ private fun FeedLoaded(
|
||||
modifier = baseModifier,
|
||||
isBoostedNote = false,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapNoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -30,7 +29,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
fun LnZapFeedView(
|
||||
viewModel: LnZapFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
enablePullRefresh: Boolean = true
|
||||
) {
|
||||
val feedState by viewModel.feedContent.collectAsState()
|
||||
@@ -64,7 +63,7 @@ fun LnZapFeedView(
|
||||
refreshing = false
|
||||
}
|
||||
|
||||
LnZapFeedLoaded(state, accountViewModel, navController)
|
||||
LnZapFeedLoaded(state, accountViewModel, nav)
|
||||
}
|
||||
is LnZapFeedState.Loading -> {
|
||||
LoadingFeed()
|
||||
@@ -83,7 +82,7 @@ fun LnZapFeedView(
|
||||
private fun LnZapFeedLoaded(
|
||||
state: LnZapFeedState.Loaded,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
@@ -95,7 +94,7 @@ private fun LnZapFeedLoaded(
|
||||
state = listState
|
||||
) {
|
||||
itemsIndexed(state.feed.value, key = { _, item -> item.second.idHex }) { _, item ->
|
||||
ZapNoteCompose(item, accountViewModel = accountViewModel, navController = navController)
|
||||
ZapNoteCompose(item, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
@@ -82,7 +81,7 @@ import kotlinx.coroutines.delay
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun ThreadFeedView(noteId: String, viewModel: FeedViewModel, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ThreadFeedView(noteId: String, viewModel: FeedViewModel, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedState by viewModel.feedContent.collectAsState()
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
@@ -139,7 +138,7 @@ fun ThreadFeedView(noteId: String, viewModel: FeedViewModel, accountViewModel: A
|
||||
if (item.idHex == noteId) MaterialTheme.colors.primary.copy(alpha = 0.52f) else MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
|
||||
),
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
} else {
|
||||
Column() {
|
||||
@@ -155,7 +154,7 @@ fun ThreadFeedView(noteId: String, viewModel: FeedViewModel, accountViewModel: A
|
||||
isBoostedNote = false,
|
||||
unPackReply = false,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -204,7 +203,7 @@ fun NoteMaster(
|
||||
baseNote: Note,
|
||||
modifier: Modifier = Modifier,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteState by baseNote.live().metadata.observeAsState()
|
||||
val note = noteState?.note
|
||||
@@ -233,7 +232,7 @@ fun NoteMaster(
|
||||
account.userProfile(),
|
||||
Modifier,
|
||||
false,
|
||||
navController,
|
||||
nav,
|
||||
onClick = { showHiddenNote = true }
|
||||
)
|
||||
} else {
|
||||
@@ -247,13 +246,13 @@ fun NoteMaster(
|
||||
.padding(start = 12.dp, end = 12.dp)
|
||||
.clickable(onClick = {
|
||||
note.author?.let {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
nav("User/${it.pubkeyHex}")
|
||||
}
|
||||
})
|
||||
) {
|
||||
NoteAuthorPicture(
|
||||
baseNote = baseNote,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
userAccount = account.userProfile(),
|
||||
size = 55.dp
|
||||
)
|
||||
@@ -262,7 +261,7 @@ fun NoteMaster(
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
|
||||
|
||||
DisplayFollowingHashtagsInPost(noteEvent, account, navController)
|
||||
DisplayFollowingHashtagsInPost(noteEvent, account, nav)
|
||||
|
||||
Text(
|
||||
timeAgo(note.createdAt(), context = context),
|
||||
@@ -290,7 +289,7 @@ fun NoteMaster(
|
||||
|
||||
val baseReward = noteEvent.getReward()
|
||||
if (baseReward != null) {
|
||||
DisplayReward(baseReward, baseNote, account, navController)
|
||||
DisplayReward(baseReward, baseNote, account, nav)
|
||||
}
|
||||
|
||||
val pow = noteEvent.getPoWRank()
|
||||
@@ -353,11 +352,11 @@ fun NoteMaster(
|
||||
) {
|
||||
Column() {
|
||||
if (noteEvent is PeopleListEvent) {
|
||||
DisplayPeopleList(noteState, MaterialTheme.colors.background, accountViewModel, navController)
|
||||
DisplayPeopleList(noteState, MaterialTheme.colors.background, accountViewModel, nav)
|
||||
} else if (noteEvent is AudioTrackEvent) {
|
||||
AudioTrackHeader(noteEvent, note, account.userProfile(), navController)
|
||||
AudioTrackHeader(noteEvent, note, account.userProfile(), nav)
|
||||
} else if (noteEvent is PinListEvent) {
|
||||
PinListHeader(noteState, MaterialTheme.colors.background, accountViewModel, navController)
|
||||
PinListHeader(noteState, MaterialTheme.colors.background, accountViewModel, nav)
|
||||
} else if (noteEvent is HighlightEvent) {
|
||||
DisplayHighlight(
|
||||
noteEvent.quote(),
|
||||
@@ -367,7 +366,7 @@ fun NoteMaster(
|
||||
true,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
} else {
|
||||
val eventContent = note.event?.content()
|
||||
@@ -384,10 +383,10 @@ fun NoteMaster(
|
||||
note.event?.tags(),
|
||||
MaterialTheme.colors.background,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
|
||||
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController)
|
||||
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, nav)
|
||||
|
||||
if (noteEvent is PollNoteEvent) {
|
||||
PollNote(
|
||||
@@ -395,13 +394,13 @@ fun NoteMaster(
|
||||
canPreview,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReactionsRow(note, accountViewModel, navController)
|
||||
ReactionsRow(note, accountViewModel, nav)
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.padding(top = 10.dp),
|
||||
|
||||
@@ -21,7 +21,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -30,7 +29,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
fun UserFeedView(
|
||||
viewModel: UserFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
enablePullRefresh: Boolean = true
|
||||
) {
|
||||
val feedState by viewModel.feedContent.collectAsState()
|
||||
@@ -61,7 +60,7 @@ fun UserFeedView(
|
||||
}
|
||||
is UserFeedState.Loaded -> {
|
||||
refreshing = false
|
||||
FeedLoaded(state, accountViewModel, navController)
|
||||
FeedLoaded(state, accountViewModel, nav)
|
||||
}
|
||||
is UserFeedState.Loading -> {
|
||||
LoadingFeed()
|
||||
@@ -80,7 +79,7 @@ fun UserFeedView(
|
||||
private fun FeedLoaded(
|
||||
state: UserFeedState.Loaded,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
@@ -92,7 +91,7 @@ private fun FeedLoaded(
|
||||
state = listState
|
||||
) {
|
||||
itemsIndexed(state.feed.value, key = { _, item -> item.pubkeyHex }) { _, item ->
|
||||
UserCompose(item, accountViewModel = accountViewModel, navController = navController)
|
||||
UserCompose(item, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.map
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -23,6 +25,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Locale
|
||||
|
||||
@Immutable
|
||||
class AccountViewModel(private val account: Account) : ViewModel() {
|
||||
val accountLiveData: LiveData<AccountState> = account.live.map { it }
|
||||
val accountLanguagesLiveData: LiveData<AccountState> = account.liveLanguages.map { it }
|
||||
@@ -228,4 +231,10 @@ class AccountViewModel(private val account: Account) : ViewModel() {
|
||||
fun dontShowBlockAlertDialog() {
|
||||
account.setHideBlockAlertDialog()
|
||||
}
|
||||
|
||||
class Factory(val account: Account) : ViewModelProvider.Factory {
|
||||
override fun <AccountViewModel : ViewModel> create(modelClass: Class<AccountViewModel>): AccountViewModel {
|
||||
return AccountViewModel(account) as AccountViewModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -19,7 +19,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.dal.BookmarkPrivateFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.BookmarkPublicFeedFilter
|
||||
@@ -30,7 +29,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BookmarkListScreen(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun BookmarkListScreen(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account
|
||||
|
||||
@@ -74,8 +73,8 @@ fun BookmarkListScreen(accountViewModel: AccountViewModel, navController: NavCon
|
||||
}
|
||||
HorizontalPager(pageCount = 2, state = pagerState) { page ->
|
||||
when (page) {
|
||||
0 -> FeedView(privateFeedViewModel, accountViewModel, navController, null)
|
||||
1 -> FeedView(publicFeedViewModel, accountViewModel, navController, null)
|
||||
0 -> FeedView(privateFeedViewModel, accountViewModel, nav, null)
|
||||
1 -> FeedView(publicFeedViewModel, accountViewModel, nav, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.Channel
|
||||
@@ -83,7 +82,7 @@ import com.vitorpamplona.amethyst.ui.screen.NostrChannelFeedViewModel
|
||||
fun ChannelScreen(
|
||||
channelId: String?,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account
|
||||
@@ -143,7 +142,7 @@ fun ChannelScreen(
|
||||
ChannelHeader(
|
||||
channel,
|
||||
account,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
|
||||
Column(
|
||||
@@ -152,7 +151,7 @@ fun ChannelScreen(
|
||||
.padding(vertical = 0.dp)
|
||||
.weight(1f, true)
|
||||
) {
|
||||
ChatroomFeedView(feedViewModel, accountViewModel, navController, "Channel/$channelId") {
|
||||
ChatroomFeedView(feedViewModel, accountViewModel, nav, "Channel/$channelId") {
|
||||
replyTo.value = it
|
||||
}
|
||||
}
|
||||
@@ -168,7 +167,7 @@ fun ChannelScreen(
|
||||
null,
|
||||
innerQuote = true,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
onWantsToReply = {
|
||||
replyTo.value = it
|
||||
}
|
||||
@@ -248,7 +247,7 @@ fun ChannelScreen(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChannelHeader(baseChannel: Channel, account: Account, navController: NavController) {
|
||||
fun ChannelHeader(baseChannel: Channel, account: Account, nav: (String) -> Unit) {
|
||||
val channelState by baseChannel.live.observeAsState()
|
||||
val channel = channelState?.channel ?: return
|
||||
|
||||
@@ -256,7 +255,7 @@ fun ChannelHeader(baseChannel: Channel, account: Account, navController: NavCont
|
||||
|
||||
Column(
|
||||
Modifier.clickable {
|
||||
navController.navigate("Channel/${baseChannel.idHex}")
|
||||
nav("Channel/${baseChannel.idHex}")
|
||||
}
|
||||
) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
@@ -306,9 +305,9 @@ fun ChannelHeader(baseChannel: Channel, account: Account, navController: NavCont
|
||||
}
|
||||
|
||||
if (account.followingChannels.contains(channel.idHex)) {
|
||||
LeaveButton(account, channel, navController)
|
||||
LeaveButton(account, channel, nav)
|
||||
} else {
|
||||
JoinButton(account, channel, navController)
|
||||
JoinButton(account, channel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,7 +385,7 @@ private fun EditButton(account: Account, channel: Channel) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun JoinButton(account: Account, channel: Channel, navController: NavController) {
|
||||
private fun JoinButton(account: Account, channel: Channel, nav: (String) -> Unit) {
|
||||
Button(
|
||||
modifier = Modifier.padding(horizontal = 3.dp),
|
||||
onClick = {
|
||||
@@ -404,12 +403,12 @@ private fun JoinButton(account: Account, channel: Channel, navController: NavCon
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeaveButton(account: Account, channel: Channel, navController: NavController) {
|
||||
private fun LeaveButton(account: Account, channel: Channel, nav: (String) -> Unit) {
|
||||
Button(
|
||||
modifier = Modifier.padding(horizontal = 3.dp),
|
||||
onClick = {
|
||||
account.leaveChannel(channel.idHex)
|
||||
navController.navigate(Route.Message.route)
|
||||
nav(Route.Message.route)
|
||||
},
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
colors = ButtonDefaults
|
||||
|
||||
+2
-3
@@ -39,7 +39,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
|
||||
import com.vitorpamplona.amethyst.ui.dal.ChatroomListKnownFeedFilter
|
||||
@@ -52,7 +51,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ChatroomListScreen(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ChatroomListScreen(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val pagerState = rememberPagerState()
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
@@ -151,7 +150,7 @@ fun ChatroomListScreen(accountViewModel: AccountViewModel, navController: NavCon
|
||||
ChatroomListFeedView(
|
||||
viewModel = tabs[page].viewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
markAsRead = tabs[page].markAsRead
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
@@ -61,7 +60,7 @@ import com.vitorpamplona.amethyst.ui.screen.ChatroomFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrChatRoomFeedViewModel
|
||||
|
||||
@Composable
|
||||
fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account
|
||||
val context = LocalContext.current
|
||||
@@ -106,7 +105,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
||||
|
||||
Column(Modifier.fillMaxHeight()) {
|
||||
NostrChatroomDataSource.withUser?.let {
|
||||
ChatroomHeader(it, account.userProfile(), navController = navController)
|
||||
ChatroomHeader(it, account.userProfile(), nav = nav)
|
||||
}
|
||||
|
||||
Column(
|
||||
@@ -115,7 +114,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
||||
.padding(vertical = 0.dp)
|
||||
.weight(1f, true)
|
||||
) {
|
||||
ChatroomFeedView(feedViewModel, accountViewModel, navController, "Room/$userId") {
|
||||
ChatroomFeedView(feedViewModel, accountViewModel, nav, "Room/$userId") {
|
||||
replyTo.value = it
|
||||
}
|
||||
}
|
||||
@@ -131,7 +130,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
||||
null,
|
||||
innerQuote = true,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
onWantsToReply = {
|
||||
replyTo.value = it
|
||||
}
|
||||
@@ -208,10 +207,10 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatroomHeader(baseUser: User, accountUser: User, navController: NavController) {
|
||||
fun ChatroomHeader(baseUser: User, accountUser: User, nav: (String) -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.clickable(
|
||||
onClick = { navController.navigate("User/${baseUser.pubkeyHex}") }
|
||||
onClick = { nav("User/${baseUser.pubkeyHex}") }
|
||||
)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
|
||||
@@ -22,7 +22,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.service.NostrHashtagDataSource
|
||||
import com.vitorpamplona.amethyst.ui.dal.HashtagFeedFilter
|
||||
@@ -32,7 +31,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun HashtagScreen(tag: String?, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun HashtagScreen(tag: String?, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
@@ -76,7 +75,7 @@ fun HashtagScreen(tag: String?, accountViewModel: AccountViewModel, navControlle
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
HashtagHeader(tag, account)
|
||||
FeedView(feedViewModel, accountViewModel, navController, null)
|
||||
FeedView(feedViewModel, accountViewModel, nav, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -18,7 +18,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.dal.HiddenAccountsFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrHiddenAccountsFeedViewModel
|
||||
@@ -27,7 +26,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun HiddenUsersScreen(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun HiddenUsersScreen(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account
|
||||
|
||||
@@ -55,7 +54,7 @@ fun HiddenUsersScreen(accountViewModel: AccountViewModel, navController: NavCont
|
||||
}
|
||||
HorizontalPager(pageCount = 1, state = pagerState) { page ->
|
||||
when (page) {
|
||||
0 -> UserFeedView(feedViewModel, accountViewModel, navController)
|
||||
0 -> UserFeedView(feedViewModel, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
|
||||
@@ -45,7 +44,7 @@ fun HomeScreen(
|
||||
homeFeedViewModel: NostrHomeFeedViewModel,
|
||||
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
pagerState: PagerState,
|
||||
scrollToTop: Boolean = false,
|
||||
nip47: String? = null
|
||||
@@ -120,7 +119,7 @@ fun HomeScreen(
|
||||
FeedView(
|
||||
viewModel = tabs[page].viewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
routeForLastRead = tabs[page].routeForLastRead,
|
||||
scrollStateKey = tabs[page].scrollStateKey,
|
||||
scrollToTop = scrollToTop
|
||||
|
||||
@@ -53,6 +53,14 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun
|
||||
skipHalfExpanded = true
|
||||
)
|
||||
|
||||
val nav = remember {
|
||||
{ route: String ->
|
||||
if (getRouteWithArguments(navController) != route) {
|
||||
navController.navigate(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = remember(accountState) { accountState?.account }
|
||||
|
||||
@@ -76,7 +84,7 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun
|
||||
AppTopBar(followLists, navController, scaffoldState, accountViewModel)
|
||||
},
|
||||
drawerContent = {
|
||||
DrawerContent(navController, scaffoldState, sheetState, accountViewModel)
|
||||
DrawerContent(nav, scaffoldState, sheetState, accountViewModel)
|
||||
BackHandler(enabled = scaffoldState.drawerState.isOpen) {
|
||||
scope.launch { scaffoldState.drawerState.close() }
|
||||
}
|
||||
@@ -97,6 +105,14 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun
|
||||
fun FloatingButtons(navController: NavHostController, accountViewModel: AccountViewModel, accountStateViewModel: AccountStateViewModel) {
|
||||
val accountState by accountStateViewModel.accountContent.collectAsState()
|
||||
|
||||
val nav = remember {
|
||||
{ route: String ->
|
||||
if (getRouteWithArguments(navController) != route) {
|
||||
navController.navigate(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Crossfade(targetState = accountState, animationSpec = tween(durationMillis = 100)) { state ->
|
||||
when (state) {
|
||||
is AccountState.LoggedInViewOnly -> {
|
||||
@@ -107,13 +123,13 @@ fun FloatingButtons(navController: NavHostController, accountViewModel: AccountV
|
||||
}
|
||||
is AccountState.LoggedIn -> {
|
||||
if (currentRoute(navController)?.substringBefore("?") == Route.Home.base) {
|
||||
NewNoteButton(state.account, accountViewModel, navController)
|
||||
NewNoteButton(state.account, accountViewModel, nav)
|
||||
}
|
||||
if (currentRoute(navController) == Route.Message.base) {
|
||||
ChannelFabColumn(state.account, navController)
|
||||
ChannelFabColumn(state.account, nav)
|
||||
}
|
||||
if (currentRoute(navController)?.substringBefore("?") == Route.Video.base) {
|
||||
NewImageButton(accountViewModel, navController)
|
||||
NewImageButton(accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-9
@@ -23,7 +23,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis
|
||||
import com.patrykandpatrick.vico.compose.axis.vertical.endAxis
|
||||
import com.patrykandpatrick.vico.compose.axis.vertical.startAxis
|
||||
@@ -61,7 +60,7 @@ fun NotificationScreen(
|
||||
notifFeedViewModel: NotificationViewModel,
|
||||
userReactionsStatsModel: UserReactionsViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
@@ -74,8 +73,6 @@ fun NotificationScreen(
|
||||
LaunchedEffect(account.userProfile().pubkeyHex, account.defaultNotificationFollowList) {
|
||||
NostrAccountDataSource.resetFilters()
|
||||
NotificationFeedFilter.account = account
|
||||
notifFeedViewModel.clear()
|
||||
notifFeedViewModel.invalidateData()
|
||||
}
|
||||
|
||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||
@@ -83,7 +80,7 @@ fun NotificationScreen(
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME) {
|
||||
NotificationFeedFilter.account = account
|
||||
notifFeedViewModel.invalidateData()
|
||||
notifFeedViewModel.invalidateData(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,11 +94,11 @@ fun NotificationScreen(
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
SummaryBar(userReactionsStatsModel, accountViewModel, navController)
|
||||
SummaryBar(userReactionsStatsModel, accountViewModel, nav)
|
||||
CardFeedView(
|
||||
viewModel = notifFeedViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
nav = nav,
|
||||
routeForLastRead = Route.Notification.base,
|
||||
scrollStateKey = ScrollStateKeys.NOTIFICATION_SCREEN,
|
||||
scrollToTop = scrollToTop
|
||||
@@ -111,12 +108,12 @@ fun NotificationScreen(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SummaryBar(model: UserReactionsViewModel, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun SummaryBar(model: UserReactionsViewModel, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
var showChart by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
UserReactionsRow(model, accountViewModel, navController) {
|
||||
UserReactionsRow(model, accountViewModel, nav) {
|
||||
showChart = !showChart
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
@@ -103,7 +102,7 @@ import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
if (userId == null) return
|
||||
|
||||
var userBase by remember { mutableStateOf<User?>(null) }
|
||||
@@ -118,14 +117,14 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
||||
ProfileScreen(
|
||||
user = it,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ProfileScreen(user: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ProfileScreen(user: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = remember(accountState) { accountState?.account } ?: return
|
||||
|
||||
@@ -210,7 +209,7 @@ fun ProfileScreen(user: User, accountViewModel: AccountViewModel, navController:
|
||||
.fillMaxHeight()
|
||||
) {
|
||||
Column(modifier = Modifier.padding()) {
|
||||
ProfileHeader(baseUser, navController, account, accountViewModel)
|
||||
ProfileHeader(baseUser, nav, account, accountViewModel)
|
||||
ScrollableTabRow(
|
||||
backgroundColor = MaterialTheme.colors.background,
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
@@ -246,13 +245,13 @@ fun ProfileScreen(user: User, accountViewModel: AccountViewModel, navController:
|
||||
}
|
||||
) { page ->
|
||||
when (page) {
|
||||
0 -> TabNotesNewThreads(accountViewModel, navController)
|
||||
1 -> TabNotesConversations(accountViewModel, navController)
|
||||
2 -> TabFollows(baseUser, accountViewModel, navController)
|
||||
3 -> TabFollowers(baseUser, accountViewModel, navController)
|
||||
4 -> TabReceivedZaps(baseUser, accountViewModel, navController)
|
||||
5 -> TabBookmarks(baseUser, accountViewModel, navController)
|
||||
6 -> TabReports(baseUser, accountViewModel, navController)
|
||||
0 -> TabNotesNewThreads(accountViewModel, nav)
|
||||
1 -> TabNotesConversations(accountViewModel, nav)
|
||||
2 -> TabFollows(baseUser, accountViewModel, nav)
|
||||
3 -> TabFollowers(baseUser, accountViewModel, nav)
|
||||
4 -> TabReceivedZaps(baseUser, accountViewModel, nav)
|
||||
5 -> TabBookmarks(baseUser, accountViewModel, nav)
|
||||
6 -> TabReports(baseUser, accountViewModel, nav)
|
||||
7 -> TabRelays(baseUser, accountViewModel)
|
||||
}
|
||||
}
|
||||
@@ -331,7 +330,7 @@ private fun FollowTabHeader(baseUser: User) {
|
||||
@Composable
|
||||
private fun ProfileHeader(
|
||||
baseUser: User,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
account: Account,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
@@ -412,7 +411,7 @@ private fun ProfileHeader(
|
||||
.height(35.dp)
|
||||
.padding(bottom = 3.dp)
|
||||
) {
|
||||
MessageButton(baseUser, navController)
|
||||
MessageButton(baseUser, nav)
|
||||
|
||||
// No need for this button anymore
|
||||
// NPubCopyButton(baseUser)
|
||||
@@ -421,7 +420,7 @@ private fun ProfileHeader(
|
||||
}
|
||||
}
|
||||
|
||||
DrawAdditionalInfo(baseUser, account, accountViewModel, navController)
|
||||
DrawAdditionalInfo(baseUser, account, accountViewModel, nav)
|
||||
|
||||
Divider(modifier = Modifier.padding(top = 6.dp))
|
||||
}
|
||||
@@ -468,7 +467,7 @@ private fun ProfileActions(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val userState by baseUser.live().metadata.observeAsState()
|
||||
val user = remember(userState) { userState?.user } ?: return
|
||||
val tags = remember(userState) { userState?.user?.info?.latestMetadata?.tags }
|
||||
@@ -534,7 +533,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewMode
|
||||
user,
|
||||
onScan = {
|
||||
dialogOpen = false
|
||||
navController.navigate(it)
|
||||
nav(it)
|
||||
},
|
||||
onClose = { dialogOpen = false }
|
||||
)
|
||||
@@ -553,7 +552,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewMode
|
||||
}
|
||||
}
|
||||
|
||||
DisplayBadges(baseUser, navController)
|
||||
DisplayBadges(baseUser, nav)
|
||||
|
||||
DisplayNip05ProfileStatus(user)
|
||||
|
||||
@@ -613,7 +612,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewMode
|
||||
tags = null,
|
||||
backgroundColor = MaterialTheme.colors.background,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -701,7 +700,7 @@ private fun DisplayLNAddress(
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
private fun DisplayBadges(
|
||||
baseUser: User,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val userBadgeState by baseUser.live().badges.observeAsState()
|
||||
val userBadge = remember(userBadgeState) { userBadgeState?.user } ?: return
|
||||
@@ -716,7 +715,7 @@ private fun DisplayBadges(
|
||||
val baseBadgeDefinition = badgeAwardState?.note?.replyTo?.firstOrNull()
|
||||
|
||||
if (baseBadgeDefinition != null) {
|
||||
BadgeThumb(baseBadgeDefinition, navController, 35.dp)
|
||||
BadgeThumb(baseBadgeDefinition, nav, 35.dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -728,12 +727,12 @@ private fun DisplayBadges(
|
||||
@Composable
|
||||
fun BadgeThumb(
|
||||
note: Note,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
size: Dp,
|
||||
pictureModifier: Modifier = Modifier
|
||||
) {
|
||||
BadgeThumb(note, size, pictureModifier) {
|
||||
navController.navigate("Note/${it.idHex}")
|
||||
nav("Note/${it.idHex}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,7 +830,7 @@ private fun DrawBanner(baseUser: User) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabNotesNewThreads(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TabNotesNewThreads(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedViewModel: NostrUserProfileNewThreadsFeedViewModel = viewModel()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -842,13 +841,13 @@ fun TabNotesNewThreads(accountViewModel: AccountViewModel, navController: NavCon
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
FeedView(feedViewModel, accountViewModel, navController, null, enablePullRefresh = false)
|
||||
FeedView(feedViewModel, accountViewModel, nav, null, enablePullRefresh = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabNotesConversations(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TabNotesConversations(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedViewModel: NostrUserProfileConversationsFeedViewModel = viewModel()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -859,13 +858,13 @@ fun TabNotesConversations(accountViewModel: AccountViewModel, navController: Nav
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
FeedView(feedViewModel, accountViewModel, navController, null, enablePullRefresh = false)
|
||||
FeedView(feedViewModel, accountViewModel, nav, null, enablePullRefresh = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabBookmarks(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TabBookmarks(baseUser: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedViewModel: NostrUserProfileBookmarksFeedViewModel = viewModel()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -876,13 +875,13 @@ fun TabBookmarks(baseUser: User, accountViewModel: AccountViewModel, navControll
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
FeedView(feedViewModel, accountViewModel, navController, null, enablePullRefresh = false)
|
||||
FeedView(feedViewModel, accountViewModel, nav, null, enablePullRefresh = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabFollows(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TabFollows(baseUser: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedViewModel: NostrUserProfileFollowsUserFeedViewModel = viewModel()
|
||||
|
||||
val userState by baseUser.live().follows.observeAsState()
|
||||
@@ -895,13 +894,13 @@ fun TabFollows(baseUser: User, accountViewModel: AccountViewModel, navController
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
UserFeedView(feedViewModel, accountViewModel, navController, enablePullRefresh = false)
|
||||
UserFeedView(feedViewModel, accountViewModel, nav, enablePullRefresh = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabFollowers(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TabFollowers(baseUser: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedViewModel: NostrUserProfileFollowersUserFeedViewModel = viewModel()
|
||||
|
||||
val userState by baseUser.live().follows.observeAsState()
|
||||
@@ -914,13 +913,13 @@ fun TabFollowers(baseUser: User, accountViewModel: AccountViewModel, navControll
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
UserFeedView(feedViewModel, accountViewModel, navController, enablePullRefresh = false)
|
||||
UserFeedView(feedViewModel, accountViewModel, nav, enablePullRefresh = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabReceivedZaps(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TabReceivedZaps(baseUser: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedViewModel: NostrUserProfileZapsFeedViewModel = viewModel()
|
||||
|
||||
val userState by baseUser.live().zaps.observeAsState()
|
||||
@@ -933,13 +932,13 @@ fun TabReceivedZaps(baseUser: User, accountViewModel: AccountViewModel, navContr
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
LnZapFeedView(feedViewModel, accountViewModel, navController, enablePullRefresh = false)
|
||||
LnZapFeedView(feedViewModel, accountViewModel, nav, enablePullRefresh = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabReports(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun TabReports(baseUser: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val feedViewModel: NostrUserProfileReportFeedViewModel = viewModel()
|
||||
|
||||
val userState by baseUser.live().reports.observeAsState()
|
||||
@@ -952,7 +951,7 @@ fun TabReports(baseUser: User, accountViewModel: AccountViewModel, navController
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
FeedView(feedViewModel, accountViewModel, navController, null, enablePullRefresh = false)
|
||||
FeedView(feedViewModel, accountViewModel, nav, null, enablePullRefresh = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -993,12 +992,12 @@ fun TabRelays(user: User, accountViewModel: AccountViewModel) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MessageButton(user: User, navController: NavController) {
|
||||
private fun MessageButton(user: User, nav: (String) -> Unit) {
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 3.dp)
|
||||
.width(50.dp),
|
||||
onClick = { navController.navigate("Room/${user.pubkeyHex}") },
|
||||
onClick = { nav("Room/${user.pubkeyHex}") },
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
colors = ButtonDefaults
|
||||
.buttonColors(
|
||||
|
||||
@@ -48,7 +48,6 @@ import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.Channel
|
||||
@@ -83,7 +82,7 @@ import kotlinx.coroutines.channels.Channel as CoroutineChannel
|
||||
fun SearchScreen(
|
||||
searchFeedViewModel: NostrGlobalFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||
@@ -124,8 +123,8 @@ fun SearchScreen(
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
SearchBar(accountViewModel, navController)
|
||||
FeedView(searchFeedViewModel, accountViewModel, navController, null, ScrollStateKeys.GLOBAL_SCREEN, scrollToTop)
|
||||
SearchBar(accountViewModel, nav)
|
||||
FeedView(searchFeedViewModel, accountViewModel, nav, null, ScrollStateKeys.GLOBAL_SCREEN, scrollToTop)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +184,7 @@ class SearchBarViewModel : ViewModel() {
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
@Composable
|
||||
private fun SearchBar(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
private fun SearchBar(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val searchBarViewModel: SearchBarViewModel = viewModel()
|
||||
searchBarViewModel.account = accountViewModel.accountLiveData.value?.account
|
||||
|
||||
@@ -306,12 +305,12 @@ private fun SearchBar(accountViewModel: AccountViewModel, navController: NavCont
|
||||
) {
|
||||
itemsIndexed(searchBarViewModel.hashtagResults.value, key = { _, item -> "#" + item }) { _, item ->
|
||||
HashtagLine(item) {
|
||||
navController.navigate("Hashtag/$item")
|
||||
nav("Hashtag/$item")
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(searchBarViewModel.searchResults.value, key = { _, item -> "u" + item.pubkeyHex }) { _, item ->
|
||||
UserCompose(item, accountViewModel = accountViewModel, navController = navController)
|
||||
UserCompose(item, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
|
||||
itemsIndexed(searchBarViewModel.searchResultsChannels.value, key = { _, item -> "c" + item.idHex }) { _, item ->
|
||||
@@ -327,12 +326,12 @@ private fun SearchBar(accountViewModel: AccountViewModel, navController: NavCont
|
||||
channelLastTime = null,
|
||||
channelLastContent = item.info.about,
|
||||
false,
|
||||
onClick = { navController.navigate("Channel/${item.idHex}") }
|
||||
onClick = { nav("Channel/${item.idHex}") }
|
||||
)
|
||||
}
|
||||
|
||||
itemsIndexed(searchBarViewModel.searchResultsNotes.value, key = { _, item -> "n" + item.idHex }) { _, item ->
|
||||
NoteCompose(item, accountViewModel = accountViewModel, navController = navController)
|
||||
NoteCompose(item, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,13 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.service.NostrThreadDataSource
|
||||
import com.vitorpamplona.amethyst.ui.dal.ThreadFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrThreadFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.ThreadFeedView
|
||||
|
||||
@Composable
|
||||
fun ThreadScreen(noteId: String?, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ThreadScreen(noteId: String?, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val account by accountViewModel.accountLiveData.observeAsState()
|
||||
|
||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||
@@ -63,7 +62,7 @@ fun ThreadScreen(noteId: String?, accountViewModel: AccountViewModel, navControl
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
ThreadFeedView(noteId, feedViewModel, accountViewModel, navController)
|
||||
ThreadFeedView(noteId, feedViewModel, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
@@ -99,7 +98,7 @@ import kotlinx.coroutines.launch
|
||||
fun VideoScreen(
|
||||
videoFeedView: NostrVideoFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||
@@ -142,7 +141,7 @@ fun VideoScreen(
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
FeedView(videoFeedView, accountViewModel, navController, ScrollStateKeys.VIDEO_SCREEN, scrollToTop)
|
||||
FeedView(videoFeedView, accountViewModel, nav, ScrollStateKeys.VIDEO_SCREEN, scrollToTop)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +150,7 @@ fun VideoScreen(
|
||||
fun FeedView(
|
||||
videoFeedView: NostrVideoFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
scrollStateKey: String? = null,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
@@ -176,7 +175,7 @@ fun FeedView(
|
||||
SlidingCarousel(
|
||||
state.feed,
|
||||
accountViewModel,
|
||||
navController,
|
||||
nav,
|
||||
scrollStateKey,
|
||||
scrollToTop
|
||||
)
|
||||
@@ -196,7 +195,7 @@ fun FeedView(
|
||||
fun SlidingCarousel(
|
||||
feed: MutableState<List<Note>>,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
nav: (String) -> Unit,
|
||||
scrollStateKey: String? = null,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
@@ -222,7 +221,7 @@ fun SlidingCarousel(
|
||||
}
|
||||
) { index ->
|
||||
feed.value.getOrNull(index)?.let { note ->
|
||||
RenderVideoOrPictureNote(note, accountViewModel, navController)
|
||||
RenderVideoOrPictureNote(note, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,7 +230,7 @@ fun SlidingCarousel(
|
||||
private fun RenderVideoOrPictureNote(
|
||||
note: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val noteEvent = note.event
|
||||
|
||||
@@ -255,7 +254,7 @@ private fun RenderVideoOrPictureNote(
|
||||
Column(Modifier.weight(1f)) {
|
||||
Row(Modifier.padding(10.dp), verticalAlignment = Alignment.Bottom) {
|
||||
Column(Modifier.size(55.dp), verticalArrangement = Arrangement.Center) {
|
||||
NoteAuthorPicture(note, navController, loggedIn, 55.dp)
|
||||
NoteAuthorPicture(note, nav, loggedIn, 55.dp)
|
||||
}
|
||||
|
||||
Column(
|
||||
@@ -299,7 +298,7 @@ private fun RenderVideoOrPictureNote(
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.Center) {
|
||||
ReactionsColumn(note, accountViewModel, navController)
|
||||
ReactionsColumn(note, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,7 +341,7 @@ private fun RelayBadges(baseNote: Note) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReactionsColumn(baseNote: Note, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun ReactionsColumn(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
@@ -355,11 +354,11 @@ fun ReactionsColumn(baseNote: Note, accountViewModel: AccountViewModel, navContr
|
||||
}
|
||||
|
||||
if (wantsToReplyTo != null) {
|
||||
NewPostView({ wantsToReplyTo = null }, wantsToReplyTo, null, account, accountViewModel, navController)
|
||||
NewPostView({ wantsToReplyTo = null }, wantsToReplyTo, null, account, accountViewModel, nav)
|
||||
}
|
||||
|
||||
if (wantsToQuote != null) {
|
||||
NewPostView({ wantsToQuote = null }, null, wantsToQuote, account, accountViewModel, navController)
|
||||
NewPostView({ wantsToQuote = null }, null, wantsToQuote, account, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
@@ -380,7 +379,7 @@ fun ReactionsColumn(baseNote: Note, accountViewModel: AccountViewModel, navContr
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun NewImageButton(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun NewImageButton(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
var wantsToPost by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
@@ -397,15 +396,7 @@ fun NewImageButton(accountViewModel: AccountViewModel, navController: NavControl
|
||||
// awaits an refresh on the list
|
||||
delay(250)
|
||||
val route = Route.Video.route.replace("{scrollToTop}", "true")
|
||||
navController.navigate(route) {
|
||||
navController.graph.startDestinationRoute?.let { start ->
|
||||
popUpTo(start) { inclusive = false }
|
||||
restoreState = true
|
||||
}
|
||||
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
nav(route)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +436,7 @@ fun NewImageButton(accountViewModel: AccountViewModel, navController: NavControl
|
||||
onClose = { pickedURI = null },
|
||||
postViewModel = postViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController
|
||||
nav = nav
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -30,7 +30,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import androidx.navigation.NavController
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService
|
||||
import com.vitorpamplona.amethyst.service.lang.ResultOrError
|
||||
@@ -47,7 +46,7 @@ fun TranslatableRichTextViewer(
|
||||
tags: List<List<String>>?,
|
||||
backgroundColor: Color,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
var translatedTextState by remember {
|
||||
mutableStateOf(ResultOrError(content, null, null, null))
|
||||
@@ -93,7 +92,7 @@ fun TranslatableRichTextViewer(
|
||||
tags,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
navController
|
||||
nav
|
||||
)
|
||||
|
||||
val target = translatedTextState.targetLang
|
||||
|
||||
Reference in New Issue
Block a user