Skip to content

Commit

Permalink
fix media extract
Browse files Browse the repository at this point in the history
  • Loading branch information
storytellerF committed Dec 27, 2024
1 parent e7451a7 commit 49ba047
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.media3.common.MediaItem
Expand Down Expand Up @@ -75,12 +76,14 @@ actual fun AudioView(url: String) {
player.pause()
}
}
val shape = RoundedCornerShape(20.dp)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(100.dp)
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceContainer, RoundedCornerShape(20.dp))
.background(MaterialTheme.colorScheme.surfaceContainer, shape)
.clip(shape)
) {
IconButton({
if (player.isPlaying) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.storyteller_f.a.app.compontents

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
Expand Down Expand Up @@ -37,13 +42,16 @@ actual fun VideoView(url: String) {
player.pause()
}
}
val shape = RoundedCornerShape(20.dp)
AndroidView(
factory = {
PlayerView(it)
},
modifier = Modifier
.fillMaxWidth()
.aspectRatio(16f / 9)
.background(MaterialTheme.colorScheme.surfaceContainer, shape)
.clip(shape)
) {
log {
"Video $url update"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ private fun ProjectDialogInternal(dismiss: () -> Unit) {
ButtonNav(Icons.Default.DesignServices, stringResource(Res.string.design_spec)) {
uriHandler.openUri("https://storytellerf.github.io/aspec/")
}
ButtonNav(Icons.Default.Add, "About") {
ButtonNav(Icons.Default.Code, "About") {
dismiss()
appNav.gotoAbout()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import androidx.compose.material.icons.outlined.AddReaction
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.storyteller_f.a.app.LocalAppNav
import com.storyteller_f.a.app.bus
import com.storyteller_f.a.app.client
import com.storyteller_f.a.app.*
import com.storyteller_f.a.app.common.*
import com.storyteller_f.a.app.globalDialogState
import com.storyteller_f.a.app.model.OnAddReaction
import com.storyteller_f.a.app.model.OnRemoveReaction
import com.storyteller_f.a.app.model.OnTopicChanged
import com.storyteller_f.a.app.model.createReactionsViewModel
import com.storyteller_f.a.app.world.Pill
Expand Down Expand Up @@ -120,20 +119,22 @@ private fun EmojiCell(
val scope = rememberCoroutineScope()
val emoji = info.emoji
val hasReacted = info.hasReacted
Pill(info.count.toString(), emoji = emoji, selected = hasReacted == true) {
Pill(info.count.toString(), emoji = emoji, selected = hasReacted) {
emoji.let { string ->
if (hasReacted) {
scope.launch {
globalDialogState.use {
client.deleteReaction(string, topicInfo.id)
bus.emit(OnTopicChanged(topicInfo.copy(reactionCount = reactionCount - 1)))
bus.emit(OnRemoveReaction(topicInfo.id, string))
}
}
} else {
scope.launch {
globalDialogState.use {
client.addReaction(topicInfo.id, string)
bus.emit(OnTopicChanged(topicInfo.copy(reactionCount = reactionCount + 1)))
bus.emit(OnAddReaction(topicInfo.id, string))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,15 @@ class TopicsViewModel(id: PrimaryKey, val type: ObjectType? = null) : PagingView
bus.collect { value ->
if (value is OnTopicChanged) {
val topicInfo = value.topicInfo
updateDocumentInParent(extractHeadlineIfPlain(topicInfo))
// 尝试更新到推荐
if (select(all()).from(getOrCreateCollection("topics$id"))
.where(Expression.property("id").equalTo(topicInfo.id)).execute().next() != null
) {
updateDocument("topics0", topicInfo)
if (id == topicInfo.parentId) {
updateDocumentInParent(extractHeadlineIfPlain(topicInfo))
} else if (id == DEFAULT_PRIMARY_KEY) {
// 尝试更新到推荐
if (select(all()).from(getOrCreateCollection("topics0"))
.where(Expression.property("id").equalTo(topicInfo.id)).execute().next() != null
) {
updateDocument("topics0", extractHeadlineIfPlain(topicInfo))
}
}
}
}
Expand All @@ -153,7 +156,7 @@ class TopicsViewModel(id: PrimaryKey, val type: ObjectType? = null) : PagingView
private fun extractHeadlineIfPlain(it: TopicInfo): TopicInfo {
val content = it.content
return if (content is TopicContent.Plain) {
it.copy(content = TopicContent.Extracted(extractMarkdownHeadline(content.plain), content.list))
it.copy(content = TopicContent.Extracted(extractMarkdownHeadline(content.plain), content.list, content.plain))
} else {
it
}
Expand Down Expand Up @@ -319,10 +322,37 @@ class MemberViewModel(private val objectId: PrimaryKey, private val word: String
})

data class OnTopicChanged(val topicInfo: TopicInfo)
data class OnAddReaction(val topicId: PrimaryKey, val emoji: String)
data class OnRemoveReaction(val topicId: PrimaryKey, val emoji: String)

class ReactionsViewModel(private val objectId: PrimaryKey) : SimpleViewModel<ServerResponse<ReactionInfo>>() {
init {
load()
viewModelScope.launch {
bus.collect {
if (it is OnAddReaction) {
if (it.topicId == objectId) {
handler.data.value?.data.orEmpty().map { info ->
when {
info.emoji != it.emoji -> info
info.hasReacted -> info
else -> info.copy(count = info.count, hasReacted = true)
}
}
}
} else if (it is OnRemoveReaction) {
if (it.topicId == objectId) {
handler.data.value?.data.orEmpty().map { info ->
when {
info.emoji != it.emoji -> info
!info.hasReacted -> info
else -> info.copy(count = info.count - 1, hasReacted = false)
}
}
}
}
}
}
}

override suspend fun loadInternal() = client.getReactions(objectId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package com.storyteller_f.a.app.topic
import androidx.compose.foundation.Image
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Error
import androidx.compose.material.icons.filled.Refresh
Expand All @@ -19,6 +21,7 @@ import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -177,6 +180,6 @@ class CustomCoil3ImageTransformerImpl(private val mediaMap: Map<String, MediaInf
override fun transform(link: String): ImageData {
return rememberAsyncImagePainter(
model = imageRequestInMarkdown(link, mediaMap)
).let { ImageData(it) }
).let { ImageData(it, modifier = Modifier.clip(RoundedCornerShape(10.dp)).fillMaxWidth()) }
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
package com.storyteller_f.a.app.user

import androidx.compose.foundation.layout.Column
import androidx.compose.material.Surface
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import app.cash.paging.compose.collectAsLazyPagingItems
import com.storyteller_f.a.app.LocalAppNav
import com.storyteller_f.a.app.compontents.UserIcon
import com.storyteller_f.a.app.model.createTopicSearchInUserViewModel
import com.storyteller_f.a.app.model.createUserViewModel
import com.storyteller_f.a.app.search.CustomSearchBar
import com.storyteller_f.a.app.search.SearchScope
import com.storyteller_f.a.app.world.TopicList
import com.storyteller_f.a.client_lib.LoginViewModel
import com.storyteller_f.shared.model.UserInfo
import com.storyteller_f.shared.type.ObjectType
import com.storyteller_f.shared.type.PrimaryKey

@Composable
fun UserPage(uid: PrimaryKey) {
val userViewModel = createUserViewModel(uid)
val user by userViewModel.handler.data.collectAsState()
Surface {
Column {
val my by LoginViewModel.user.collectAsState()
UserPageInternal(user, my, uid)
}

@Composable
private fun UserPageInternal(
user: UserInfo?,
my: UserInfo?,
uid: PrimaryKey
) {
val appNav = LocalAppNav.current
Scaffold(floatingActionButton = {
if (user != null && my?.id == user.id) {
FloatingActionButton({
appNav.gotoTopicCompose(ObjectType.USER, user.id, false, null)
}) {
Icon(Icons.Default.Add, "add topic")
}
}
}) {
Column(
modifier = Modifier.padding(bottom = it.calculateBottomPadding()),
) {
CustomSearchBar(SearchScope.UserTopic(uid)) {
UserIcon(user)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,27 @@ private fun UserRefCellInternal(viewModel: UserViewModel) {

@Composable
fun UserCell(userInfo: UserInfo?, customBackground: Boolean, avatarSize: Dp = 50.dp) {
userInfo ?: return
val appNav = LocalAppNav.current
Row(
modifier = if (customBackground) {
Modifier
.fillMaxWidth()
.fillMaxWidth().clickable {
appNav.gotoUser(userInfo.id)
}
} else {
Modifier.fillMaxWidth().background(MaterialTheme.colorScheme.surfaceDim, RoundedCornerShape(8.dp))
Modifier.fillMaxWidth().clickable {
appNav.gotoUser(userInfo.id)
}.background(MaterialTheme.colorScheme.surfaceDim, RoundedCornerShape(8.dp))
.padding(8.dp)
},
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
UserIcon(userInfo, size = avatarSize)
Column {
userInfo?.nickname?.let { Text(it) }
userInfo?.aid?.let {
Text(userInfo.nickname)
userInfo.aid?.let {
Text("aid: $it")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ suspend fun checkRootReadPermission(
}
}

ObjectType.USER -> TODO()
ObjectType.USER -> getRawUserById(parentId).mapNotNull {
RootReadPermission(true, false, false)
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions server/src/test/kotlin/TopicTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,13 @@ class TopicTest {
}
}
}

@Test
fun `test create in user`() {
test { client, _ ->
attachSession(client) {
client.createNewTopic(ObjectType.USER, it.data4, "hello").getOrThrow()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ sealed interface TopicContent {

@Serializable
@SerialName("extracted")
data class Extracted(val plain: String, val list: List<MediaInfo> = emptyList()) : TopicContent
data class Extracted(val plain: String, val list: List<MediaInfo> = emptyList(), val origin: String) : TopicContent

@Serializable
@SerialName("plain")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,8 @@ fun extractMarkdownMediaLink(markdownText: String): MutableList<String> {
override fun visitNode(node: ASTNode) {
when (node.type) {
MarkdownElementTypes.IMAGE -> {
// Extract the first level header content
val markdownImage = markdownText.substring(node.startOffset, node.endOffset)

// 正则表达式匹配 ![alt text](image path "title")
val regex = Regex("""!\[([^]]*)]\(([^ )]+)(?:\s+"([^"]*)")?\)""")

val matchResult = regex.find(markdownImage)
if (matchResult != null) {
val imagePath = matchResult.groupValues[2] // 提取图片路径
list.add(imagePath)
}
val imagePath = extractImageUrl(node, markdownText)
imagePath?.let { list.add(it) }
}

MarkdownElementTypes.CODE_FENCE -> {
Expand All @@ -149,7 +140,21 @@ fun extractMarkdownMediaLink(markdownText: String): MutableList<String> {
})
return list
}
fun extractImageUrl(node: ASTNode, markdownText: String): String? {
// Extract the first level header content
val markdownImage = markdownText.substring(node.startOffset, node.endOffset)

// 正则表达式匹配 ![alt text](image path "title")
val regex = Regex("""!\[([^]]*)]\(([^ )]+)(?:\s+"([^"]*)")?\)""")

val matchResult = regex.find(markdownImage)
val imagePath = if (matchResult != null) {
matchResult.groupValues[2] // 提取图片路径
} else {
null
}
return imagePath
}
private fun astNode(markdownText: String): ASTNode {
val flavour = CommonMarkFlavourDescriptor()
val parser = MarkdownParser(flavour)
Expand Down

0 comments on commit 49ba047

Please sign in to comment.