diff --git a/app/src/main/java/dev/dimension/flare/ui/component/status/CommonStatusComponent.kt b/app/src/main/java/dev/dimension/flare/ui/component/status/CommonStatusComponent.kt
index 5bd299112..b3a79322d 100644
--- a/app/src/main/java/dev/dimension/flare/ui/component/status/CommonStatusComponent.kt
+++ b/app/src/main/java/dev/dimension/flare/ui/component/status/CommonStatusComponent.kt
@@ -528,7 +528,7 @@ private fun StatusActions(
text = action.displayItem.iconText,
color = statusActionItemColor(item = action.displayItem),
withTextMinWidth = index != items.lastIndex,
- ) {
+ ) { closeMenu ->
action.actions.forEach { subActions ->
if (subActions is StatusAction.Item) {
val color = statusActionItemColor(subActions)
@@ -550,6 +550,7 @@ private fun StatusActions(
)
},
onClick = {
+ closeMenu.invoke()
if (subActions is StatusAction.Item.Clickable) {
subActions.onClicked.invoke(
ClickContext(
diff --git a/app/src/main/java/dev/dimension/flare/ui/component/status/StatusRetweetHeaderComponent.kt b/app/src/main/java/dev/dimension/flare/ui/component/status/StatusRetweetHeaderComponent.kt
index 94487ef96..4ef20bf76 100644
--- a/app/src/main/java/dev/dimension/flare/ui/component/status/StatusRetweetHeaderComponent.kt
+++ b/app/src/main/java/dev/dimension/flare/ui/component/status/StatusRetweetHeaderComponent.kt
@@ -36,7 +36,7 @@ internal fun StatusRetweetHeaderComponent(
contentDescription = null,
modifier =
Modifier
- .size(16.dp),
+ .size(12.dp),
)
if (user != null) {
Spacer(modifier = Modifier.width(8.dp))
diff --git a/app/src/main/java/dev/dimension/flare/ui/component/status/UiTimelineComponent.kt b/app/src/main/java/dev/dimension/flare/ui/component/status/UiTimelineComponent.kt
index 435f1c131..e199dc9c1 100644
--- a/app/src/main/java/dev/dimension/flare/ui/component/status/UiTimelineComponent.kt
+++ b/app/src/main/java/dev/dimension/flare/ui/component/status/UiTimelineComponent.kt
@@ -20,6 +20,7 @@ import compose.icons.fontawesomeicons.solid.At
import compose.icons.fontawesomeicons.solid.CircleInfo
import compose.icons.fontawesomeicons.solid.Heart
import compose.icons.fontawesomeicons.solid.Pen
+import compose.icons.fontawesomeicons.solid.QuoteLeft
import compose.icons.fontawesomeicons.solid.Reply
import compose.icons.fontawesomeicons.solid.Retweet
import compose.icons.fontawesomeicons.solid.SquarePollHorizontal
@@ -28,6 +29,7 @@ import dev.dimension.flare.R
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.ui.model.ClickContext
import dev.dimension.flare.ui.model.UiTimeline
+import dev.dimension.flare.ui.model.mapper.MisskeyAchievement
@Composable
internal fun UiTimelineComponent(
@@ -144,6 +146,7 @@ private fun TopMessageComponent(
UiTimeline.TopMessage.Icon.Edit -> FontAwesomeIcons.Solid.Pen
UiTimeline.TopMessage.Icon.Info -> FontAwesomeIcons.Solid.CircleInfo
UiTimeline.TopMessage.Icon.Reply -> FontAwesomeIcons.Solid.Reply
+ UiTimeline.TopMessage.Icon.Quote -> FontAwesomeIcons.Solid.QuoteLeft
}
val text: String =
when (val type = data.type) {
@@ -230,53 +233,55 @@ private fun TopMessageComponent(
is UiTimeline.TopMessage.MessageType.Misskey ->
when (type) {
- UiTimeline.TopMessage.MessageType.Misskey.AchievementEarned ->
+ is UiTimeline.TopMessage.MessageType.Misskey.AchievementEarned ->
stringResource(
id = R.string.misskey_notification_item_achievement_earned,
+ type.achievement?.titleResId?.let { stringResource(it) } ?: "",
+ type.achievement?.descriptionResId?.let { stringResource(it) } ?: "",
)
- UiTimeline.TopMessage.MessageType.Misskey.App ->
+ is UiTimeline.TopMessage.MessageType.Misskey.App ->
stringResource(id = R.string.misskey_notification_item_app)
- UiTimeline.TopMessage.MessageType.Misskey.Follow ->
+ is UiTimeline.TopMessage.MessageType.Misskey.Follow ->
stringResource(id = R.string.misskey_notification_item_followed_you)
- UiTimeline.TopMessage.MessageType.Misskey.FollowRequestAccepted ->
+ is UiTimeline.TopMessage.MessageType.Misskey.FollowRequestAccepted ->
stringResource(
id = R.string.misskey_notification_item_follow_request_accepted,
)
- UiTimeline.TopMessage.MessageType.Misskey.Mention ->
+ is UiTimeline.TopMessage.MessageType.Misskey.Mention ->
stringResource(
id = R.string.misskey_notification_item_mentioned_you,
)
- UiTimeline.TopMessage.MessageType.Misskey.PollEnded ->
+ is UiTimeline.TopMessage.MessageType.Misskey.PollEnded ->
stringResource(
id = R.string.misskey_notification_item_poll_ended,
)
- UiTimeline.TopMessage.MessageType.Misskey.Quote ->
+ is UiTimeline.TopMessage.MessageType.Misskey.Quote ->
stringResource(
id = R.string.misskey_notification_item_quoted_your_status,
)
- UiTimeline.TopMessage.MessageType.Misskey.Reaction ->
+ is UiTimeline.TopMessage.MessageType.Misskey.Reaction ->
stringResource(
id = R.string.misskey_notification_item_reacted_to_your_status,
)
- UiTimeline.TopMessage.MessageType.Misskey.ReceiveFollowRequest ->
+ is UiTimeline.TopMessage.MessageType.Misskey.ReceiveFollowRequest ->
stringResource(
id = R.string.misskey_notification_item_requested_follow,
)
- UiTimeline.TopMessage.MessageType.Misskey.Renote ->
+ is UiTimeline.TopMessage.MessageType.Misskey.Renote ->
stringResource(
id = R.string.misskey_notification_item_reposted_your_status,
)
- UiTimeline.TopMessage.MessageType.Misskey.Reply ->
+ is UiTimeline.TopMessage.MessageType.Misskey.Reply ->
stringResource(
id = R.string.misskey_notification_item_replied_to_you,
)
@@ -317,3 +322,170 @@ private fun TopMessageComponent(
},
)
}
+
+val MisskeyAchievement.titleResId: Int
+ get() =
+ when (this) {
+ MisskeyAchievement.NOTES1 -> R.string.misskey_achievement_notes1_title
+ MisskeyAchievement.NOTES10 -> R.string.misskey_achievement_notes10_title
+ MisskeyAchievement.NOTES100 -> R.string.misskey_achievement_notes100_title
+ MisskeyAchievement.NOTES500 -> R.string.misskey_achievement_notes500_title
+ MisskeyAchievement.NOTES1000 -> R.string.misskey_achievement_notes1000_title
+ MisskeyAchievement.NOTES5000 -> R.string.misskey_achievement_notes5000_title
+ MisskeyAchievement.NOTES10000 -> R.string.misskey_achievement_notes10000_title
+ MisskeyAchievement.NOTES20000 -> R.string.misskey_achievement_notes20000_title
+ MisskeyAchievement.NOTES30000 -> R.string.misskey_achievement_notes30000_title
+ MisskeyAchievement.NOTES40000 -> R.string.misskey_achievement_notes40000_title
+ MisskeyAchievement.NOTES50000 -> R.string.misskey_achievement_notes50000_title
+ MisskeyAchievement.NOTES60000 -> R.string.misskey_achievement_notes60000_title
+ MisskeyAchievement.NOTES70000 -> R.string.misskey_achievement_notes70000_title
+ MisskeyAchievement.NOTES80000 -> R.string.misskey_achievement_notes80000_title
+ MisskeyAchievement.NOTES90000 -> R.string.misskey_achievement_notes90000_title
+ MisskeyAchievement.NOTES100000 -> R.string.misskey_achievement_notes100000_title
+ MisskeyAchievement.LOGIN3 -> R.string.misskey_achievement_login3_title
+ MisskeyAchievement.LOGIN7 -> R.string.misskey_achievement_login7_title
+ MisskeyAchievement.LOGIN15 -> R.string.misskey_achievement_login15_title
+ MisskeyAchievement.LOGIN30 -> R.string.misskey_achievement_login30_title
+ MisskeyAchievement.LOGIN60 -> R.string.misskey_achievement_login60_title
+ MisskeyAchievement.LOGIN100 -> R.string.misskey_achievement_login100_title
+ MisskeyAchievement.LOGIN200 -> R.string.misskey_achievement_login200_title
+ MisskeyAchievement.LOGIN300 -> R.string.misskey_achievement_login300_title
+ MisskeyAchievement.LOGIN400 -> R.string.misskey_achievement_login400_title
+ MisskeyAchievement.LOGIN500 -> R.string.misskey_achievement_login500_title
+ MisskeyAchievement.LOGIN600 -> R.string.misskey_achievement_login600_title
+ MisskeyAchievement.LOGIN700 -> R.string.misskey_achievement_login700_title
+ MisskeyAchievement.LOGIN800 -> R.string.misskey_achievement_login800_title
+ MisskeyAchievement.LOGIN900 -> R.string.misskey_achievement_login900_title
+ MisskeyAchievement.LOGIN1000 -> R.string.misskey_achievement_login1000_title
+ MisskeyAchievement.NOTE_CLIPPED1 -> R.string.misskey_achievement_note_clipped1_title
+ MisskeyAchievement.NOTE_FAVORITED1 -> R.string.misskey_achievement_note_favorited1_title
+ MisskeyAchievement.MY_NOTE_FAVORITED1 -> R.string.misskey_achievement_my_note_favorited1_title
+ MisskeyAchievement.PROFILE_FILLED -> R.string.misskey_achievement_profile_filled_title
+ MisskeyAchievement.MARKED_AS_CAT -> R.string.misskey_achievement_marked_as_cat_title
+ MisskeyAchievement.FOLLOWING1 -> R.string.misskey_achievement_following1_title
+ MisskeyAchievement.FOLLOWING10 -> R.string.misskey_achievement_following10_title
+ MisskeyAchievement.FOLLOWING50 -> R.string.misskey_achievement_following50_title
+ MisskeyAchievement.FOLLOWING100 -> R.string.misskey_achievement_following100_title
+ MisskeyAchievement.FOLLOWING300 -> R.string.misskey_achievement_following300_title
+ MisskeyAchievement.FOLLOWERS1 -> R.string.misskey_achievement_followers1_title
+ MisskeyAchievement.FOLLOWERS10 -> R.string.misskey_achievement_followers10_title
+ MisskeyAchievement.FOLLOWERS50 -> R.string.misskey_achievement_followers50_title
+ MisskeyAchievement.FOLLOWERS100 -> R.string.misskey_achievement_followers100_title
+ MisskeyAchievement.FOLLOWERS300 -> R.string.misskey_achievement_followers300_title
+ MisskeyAchievement.FOLLOWERS500 -> R.string.misskey_achievement_followers500_title
+ MisskeyAchievement.FOLLOWERS1000 -> R.string.misskey_achievement_followers1000_title
+ MisskeyAchievement.COLLECT_ACHIEVEMENTS30 -> R.string.misskey_achievement_collect_achievements30_title
+ MisskeyAchievement.VIEW_ACHIEVEMENTS3MIN -> R.string.misskey_achievement_view_achievements3min_title
+ MisskeyAchievement.I_LOVE_MISSKEY -> R.string.misskey_achievement_i_love_misskey_title
+ MisskeyAchievement.FOUND_TREASURE -> R.string.misskey_achievement_found_treasure_title
+ MisskeyAchievement.CLIENT30MIN -> R.string.misskey_achievement_client30min_title
+ MisskeyAchievement.CLIENT60MIN -> R.string.misskey_achievement_client60min_title
+ MisskeyAchievement.NOTE_DELETED_WITHIN1MIN -> R.string.misskey_achievement_note_deleted_within1min_title
+ MisskeyAchievement.POSTED_AT_LATE_NIGHT -> R.string.misskey_achievement_posted_at_late_night_title
+ MisskeyAchievement.POSTED_AT_0MIN0SEC -> R.string.misskey_achievement_posted_at_0min0sec_title
+ MisskeyAchievement.SELF_QUOTE -> R.string.misskey_achievement_self_quote_title
+ MisskeyAchievement.HTL20NPM -> R.string.misskey_achievement_htl20npm_title
+ MisskeyAchievement.VIEW_INSTANCE_CHART -> R.string.misskey_achievement_view_instance_chart_title
+ MisskeyAchievement.OUTPUT_HELLO_WORLD_ON_SCRATCHPAD -> R.string.misskey_achievement_output_hello_world_on_scratchpad_title
+ MisskeyAchievement.OPEN3WINDOWS -> R.string.misskey_achievement_open3windows_title
+ MisskeyAchievement.DRIVE_FOLDER_CIRCULAR_REFERENCE -> R.string.misskey_achievement_drive_folder_circular_reference_title
+ MisskeyAchievement.REACT_WITHOUT_READ -> R.string.misskey_achievement_react_without_read_title
+ MisskeyAchievement.CLICKED_CLICK_HERE -> R.string.misskey_achievement_clicked_click_here_title
+ MisskeyAchievement.JUST_PLAIN_LUCKY -> R.string.misskey_achievement_just_plain_lucky_title
+ MisskeyAchievement.SET_NAME_TO_SYUILO -> R.string.misskey_achievement_set_name_to_syuilo_title
+ MisskeyAchievement.PASSED_SINCE_ACCOUNT_CREATED1 -> R.string.misskey_achievement_passed_since_account_created1_title
+ MisskeyAchievement.PASSED_SINCE_ACCOUNT_CREATED2 -> R.string.misskey_achievement_passed_since_account_created2_title
+ MisskeyAchievement.PASSED_SINCE_ACCOUNT_CREATED3 -> R.string.misskey_achievement_passed_since_account_created3_title
+ MisskeyAchievement.LOGGED_IN_ON_BIRTHDAY -> R.string.misskey_achievement_logged_in_on_birthday_title
+ MisskeyAchievement.LOGGED_IN_ON_NEW_YEARS_DAY -> R.string.misskey_achievement_logged_in_on_new_years_day_title
+ MisskeyAchievement.COOKIE_CLICKED -> R.string.misskey_achievement_cookie_clicked_title
+ MisskeyAchievement.BRAIN_DIVER -> R.string.misskey_achievement_brain_diver_title
+ MisskeyAchievement.SMASH_TEST_NOTIFICATION_BUTTON -> R.string.misskey_achievement_smash_test_notification_button_title
+ MisskeyAchievement.TUTORIAL_COMPLETED -> R.string.misskey_achievement_tutorial_completed_title
+ MisskeyAchievement.BUBBLE_GAME_EXPLODING_HEAD -> R.string.misskey_achievement_bubble_game_exploding_head_title
+ MisskeyAchievement.BUBBLE_GAME_DOUBLE_EXPLODING_HEAD -> R.string.misskey_achievement_bubble_game_double_exploding_head_title
+ }
+
+val MisskeyAchievement.descriptionResId: Int
+ get() =
+ when (this) {
+ MisskeyAchievement.NOTES1 -> R.string.misskey_achievement_notes1_description
+ MisskeyAchievement.NOTES10 -> R.string.misskey_achievement_notes10_description
+ MisskeyAchievement.NOTES100 -> R.string.misskey_achievement_notes100_description
+ MisskeyAchievement.NOTES500 -> R.string.misskey_achievement_notes500_description
+ MisskeyAchievement.NOTES1000 -> R.string.misskey_achievement_notes1000_description
+ MisskeyAchievement.NOTES5000 -> R.string.misskey_achievement_notes5000_description
+ MisskeyAchievement.NOTES10000 -> R.string.misskey_achievement_notes10000_description
+ MisskeyAchievement.NOTES20000 -> R.string.misskey_achievement_notes20000_description
+ MisskeyAchievement.NOTES30000 -> R.string.misskey_achievement_notes30000_description
+ MisskeyAchievement.NOTES40000 -> R.string.misskey_achievement_notes40000_description
+ MisskeyAchievement.NOTES50000 -> R.string.misskey_achievement_notes50000_description
+ MisskeyAchievement.NOTES60000 -> R.string.misskey_achievement_notes60000_description
+ MisskeyAchievement.NOTES70000 -> R.string.misskey_achievement_notes70000_description
+ MisskeyAchievement.NOTES80000 -> R.string.misskey_achievement_notes80000_description
+ MisskeyAchievement.NOTES90000 -> R.string.misskey_achievement_notes90000_description
+ MisskeyAchievement.NOTES100000 -> R.string.misskey_achievement_notes100000_description
+ MisskeyAchievement.LOGIN3 -> R.string.misskey_achievement_login3_description
+ MisskeyAchievement.LOGIN7 -> R.string.misskey_achievement_login7_description
+ MisskeyAchievement.LOGIN15 -> R.string.misskey_achievement_login15_description
+ MisskeyAchievement.LOGIN30 -> R.string.misskey_achievement_login30_description
+ MisskeyAchievement.LOGIN60 -> R.string.misskey_achievement_login60_description
+ MisskeyAchievement.LOGIN100 -> R.string.misskey_achievement_login100_description
+ MisskeyAchievement.LOGIN200 -> R.string.misskey_achievement_login200_description
+ MisskeyAchievement.LOGIN300 -> R.string.misskey_achievement_login300_description
+ MisskeyAchievement.LOGIN400 -> R.string.misskey_achievement_login400_description
+ MisskeyAchievement.LOGIN500 -> R.string.misskey_achievement_login500_description
+ MisskeyAchievement.LOGIN600 -> R.string.misskey_achievement_login600_description
+ MisskeyAchievement.LOGIN700 -> R.string.misskey_achievement_login700_description
+ MisskeyAchievement.LOGIN800 -> R.string.misskey_achievement_login800_description
+ MisskeyAchievement.LOGIN900 -> R.string.misskey_achievement_login900_description
+ MisskeyAchievement.LOGIN1000 -> R.string.misskey_achievement_login1000_description
+ MisskeyAchievement.NOTE_CLIPPED1 -> R.string.misskey_achievement_note_clipped1_description
+ MisskeyAchievement.NOTE_FAVORITED1 -> R.string.misskey_achievement_note_favorited1_description
+ MisskeyAchievement.MY_NOTE_FAVORITED1 -> R.string.misskey_achievement_my_note_favorited1_description
+ MisskeyAchievement.PROFILE_FILLED -> R.string.misskey_achievement_profile_filled_description
+ MisskeyAchievement.MARKED_AS_CAT -> R.string.misskey_achievement_marked_as_cat_description
+ MisskeyAchievement.FOLLOWING1 -> R.string.misskey_achievement_following1_description
+ MisskeyAchievement.FOLLOWING10 -> R.string.misskey_achievement_following10_description
+ MisskeyAchievement.FOLLOWING50 -> R.string.misskey_achievement_following50_description
+ MisskeyAchievement.FOLLOWING100 -> R.string.misskey_achievement_following100_description
+ MisskeyAchievement.FOLLOWING300 -> R.string.misskey_achievement_following300_description
+ MisskeyAchievement.FOLLOWERS1 -> R.string.misskey_achievement_followers1_description
+ MisskeyAchievement.FOLLOWERS10 -> R.string.misskey_achievement_followers10_description
+ MisskeyAchievement.FOLLOWERS50 -> R.string.misskey_achievement_followers50_description
+ MisskeyAchievement.FOLLOWERS100 -> R.string.misskey_achievement_followers100_description
+ MisskeyAchievement.FOLLOWERS300 -> R.string.misskey_achievement_followers300_description
+ MisskeyAchievement.FOLLOWERS500 -> R.string.misskey_achievement_followers500_description
+ MisskeyAchievement.FOLLOWERS1000 -> R.string.misskey_achievement_followers1000_description
+ MisskeyAchievement.COLLECT_ACHIEVEMENTS30 -> R.string.misskey_achievement_collect_achievements30_description
+ MisskeyAchievement.VIEW_ACHIEVEMENTS3MIN -> R.string.misskey_achievement_view_achievements3min_description
+ MisskeyAchievement.I_LOVE_MISSKEY -> R.string.misskey_achievement_i_love_misskey_description
+ MisskeyAchievement.FOUND_TREASURE -> R.string.misskey_achievement_found_treasure_description
+ MisskeyAchievement.CLIENT30MIN -> R.string.misskey_achievement_client30min_description
+ MisskeyAchievement.CLIENT60MIN -> R.string.misskey_achievement_client60min_description
+ MisskeyAchievement.NOTE_DELETED_WITHIN1MIN -> R.string.misskey_achievement_note_deleted_within1min_description
+ MisskeyAchievement.POSTED_AT_LATE_NIGHT -> R.string.misskey_achievement_posted_at_late_night_description
+ MisskeyAchievement.POSTED_AT_0MIN0SEC -> R.string.misskey_achievement_posted_at_0min0sec_description
+ MisskeyAchievement.SELF_QUOTE -> R.string.misskey_achievement_self_quote_description
+ MisskeyAchievement.HTL20NPM -> R.string.misskey_achievement_htl20npm_description
+ MisskeyAchievement.VIEW_INSTANCE_CHART -> R.string.misskey_achievement_view_instance_chart_description
+ MisskeyAchievement.OUTPUT_HELLO_WORLD_ON_SCRATCHPAD -> R.string.misskey_achievement_output_hello_world_on_scratchpad_description
+ MisskeyAchievement.OPEN3WINDOWS -> R.string.misskey_achievement_open3windows_description
+ MisskeyAchievement.DRIVE_FOLDER_CIRCULAR_REFERENCE -> R.string.misskey_achievement_drive_folder_circular_reference_description
+ MisskeyAchievement.REACT_WITHOUT_READ -> R.string.misskey_achievement_react_without_read_description
+ MisskeyAchievement.CLICKED_CLICK_HERE -> R.string.misskey_achievement_clicked_click_here_description
+ MisskeyAchievement.JUST_PLAIN_LUCKY -> R.string.misskey_achievement_just_plain_lucky_description
+ MisskeyAchievement.SET_NAME_TO_SYUILO -> R.string.misskey_achievement_set_name_to_syuilo_description
+ MisskeyAchievement.PASSED_SINCE_ACCOUNT_CREATED1 -> R.string.misskey_achievement_passed_since_account_created1_description
+ MisskeyAchievement.PASSED_SINCE_ACCOUNT_CREATED2 -> R.string.misskey_achievement_passed_since_account_created2_description
+ MisskeyAchievement.PASSED_SINCE_ACCOUNT_CREATED3 -> R.string.misskey_achievement_passed_since_account_created3_description
+ MisskeyAchievement.LOGGED_IN_ON_BIRTHDAY -> R.string.misskey_achievement_logged_in_on_birthday_description
+ MisskeyAchievement.LOGGED_IN_ON_NEW_YEARS_DAY -> R.string.misskey_achievement_logged_in_on_new_years_day_description
+ MisskeyAchievement.COOKIE_CLICKED -> R.string.misskey_achievement_cookie_clicked_description
+ MisskeyAchievement.BRAIN_DIVER -> R.string.misskey_achievement_brain_diver_description
+ MisskeyAchievement.SMASH_TEST_NOTIFICATION_BUTTON -> R.string.misskey_achievement_smash_test_notification_button_description
+ MisskeyAchievement.TUTORIAL_COMPLETED -> R.string.misskey_achievement_tutorial_completed_description
+ MisskeyAchievement.BUBBLE_GAME_EXPLODING_HEAD -> R.string.misskey_achievement_bubble_game_exploding_head_description
+ MisskeyAchievement.BUBBLE_GAME_DOUBLE_EXPLODING_HEAD ->
+ R.string.misskey_achievement_bubble_game_double_exploding_head_description
+ }
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b8b7d0331..488b1722c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -55,8 +55,8 @@
Settings
followed you
- favourited your toot
- reblogged your toot
+ favourited
+ reblogged
A poll you were participating in has ended
mentioned you
request to follow you
@@ -67,30 +67,30 @@
Show less
followed you
- favourited your status
- reblogged your status
+ favourited
+ reblogged
A poll you were participating in has ended
mentioned you
boosted a status
replied to you
- quoted your status
+ quoted
Starterpack Joined
UnKnown
mentioned you
replied to you
- reposted your status
- quoted your status
+ reposted
+ quoted
reacted to your status
A poll you were participating in has ended
accepted your follow request
- You\'ve earned an achievement
+ You\'ve earned an achievement: %1$s\n%2$s
App
followed you
requested to follow you
reposted a status
- retweeted your tweet
+ retweeted
mentions you
Public
@@ -413,4 +413,256 @@
Media
Tab settings
+
+
+ just setting up my msky
+ Post your first note
+ Have a good time with Misskey!
+
+ Some notes
+ Post 10 notes
+
+ A lot of notes
+ Post 100 notes
+
+ Covered in notes
+ Post 500 notes
+
+ A mountain of notes
+ Post 1,000 notes
+
+ Overflowing notes
+ Post 5,000 notes
+
+ Supernote
+ Post 10,000 notes
+
+ Need... more... notes...
+ Post 20,000 notes
+
+ Notes notes notes!
+ Post 30,000 notes
+
+ Note factory
+ Post 40,000 notes
+
+ Planet of notes
+ Post 50,000 notes
+
+ Note quasar
+ Post 60,000 notes
+
+ Note black hole
+ Post 70,000 notes
+
+ Note galaxy
+ Post 80,000 notes
+
+ Note universe
+ Post 90,000 notes
+
+ ALL YOUR NOTE ARE BELONG TO US
+ Post 100,000 notes
+ You sure have a lot to say.
+
+ Beginner I
+ Log in for a total of 3 days
+ Starting today, just call me Misskist
+
+ Beginner II
+ Log in for a total of 7 days
+ Feel like you\'ve gotten the hang of things yet?
+
+ Beginner III
+ Log in for a total of 15 days
+
+ Misskist I
+ Log in for a total of 30 days
+
+ Misskist II
+ Log in for a total of 60 days
+
+ Misskist III
+ Log in for a total of 100 days
+ Violent Misskist
+
+ Regular I
+ Log in for a total of 200 days
+
+ Regular II
+ Log in for a total of 300 days
+
+ Regular III
+ Log in for a total of 400 days
+
+ Expert I
+ Log in for a total of 500 days
+ My friends, it has often been said that I like notes
+
+ Expert II
+ Log in for a total of 600 days
+
+ Expert III
+ Log in for a total of 700 days
+
+ Master of Notes I
+ Log in for a total of 800 days
+
+ Master of Notes II
+ Log in for a total of 900 days
+
+ Master of Notes III
+ Log in for a total of 1,000 days
+ Thank you for using Misskey!
+
+ Must... clip...
+ Clip your first note
+
+ Stargazer
+ Favorite your first note
+
+ Seeking Stars
+ Have somebody else favorite one of your notes
+
+ Well-prepared
+ Set up your profile
+
+ I Am a Cat
+ Mark your account as a cat
+ I\'ll give you a name later.
+
+ Following your first user
+ Follow a user
+
+ Keep up... keep up...
+ Follow 10 users
+
+ Lots of friends
+ Follow 50 accounts
+
+ 100 Friends
+ Follow 100 accounts
+
+ Friend overload
+ Follow 300 accounts
+
+ First follower
+ Gain 1 follower
+
+ Follow me!
+ Gain 10 followers
+
+ Coming in crowds
+ Gain 50 followers
+
+ Popular
+ Gain 100 followers
+
+ Please form a single line
+ Gain 300 followers
+
+ Radio Tower
+ Gain 500 followers
+
+ Influencer
+ Gain 1,000 followers
+
+ Achievement Collector
+ Earn 30 achievements
+
+ Likes Achievements
+ Look at your list of achievements for at least 3 minutes
+
+ I Love Misskey
+ Post \"I ❤ #Misskey\"
+ Misskey\'s development team greatly appreciates your support!
+
+ Treasure Hunt
+ You\'ve found the hidden treasure
+
+ Short break
+ Keep Misskey opened for at least 30 minutes
+
+ No \"Miss\" in Misskey
+ Keep Misskey opened for at least 60 minutes
+
+ Nevermind
+ Delete a note within a minute of posting it
+
+ Nocturnal
+ Post a note late at night
+ It\'s about time to go to bed.
+
+ Speaking Clock
+ Post a note at 00:00
+ Click Click Click Claaang
+
+ Self-Reference
+ Quote your own note
+
+ Flowing Timeline
+ Have the speed of your home timeline exceed 20 npm (notes per minute)
+
+ Analyst
+ View your instance\'s charts
+
+ Hello, world!
+ Output \"hello world\" in the Scratchpad
+
+ Multi-Window
+ Have at least 3 windows open at the same time
+
+ Circular Reference
+ Attempt to create a recursively nested folder in Drive
+
+ Did you really read that?
+ React on a note that\'s over 100 characters long within 3 seconds of it being posted
+
+ Click here
+ You\'ve clicked here
+
+ Just Plain Lucky
+ Has a chance to be obtained with a probability of 0.005\% every 10 seconds
+
+ God Complex
+ Set your name to \"syuilo\"
+
+ One Year Anniversary
+ One year has passed since your account was created
+
+ Two Year Anniversary
+ Two years have passed since your account was created
+
+ Three Year Anniversary
+ Three years have passed since your account was created
+
+ Happy Birthday
+ Log in on your birthday
+
+ Happy New Year!
+ Logged in on the first day of the year
+ To another great year on this instance
+
+ A game in which you click cookies
+ Clicked the cookie
+ Wait, are you on the correct website?
+
+ Brain Diver
+ Post the link to Brain Diver
+ Misskey-Misskey La-Tu-Ma
+
+ Test overflow
+ Trigger the notification test repeatedly within an extremely short time
+
+ Misskey Elementary Course Diploma
+ Tutorial completed
+
+ 🤯
+ The biggest object in the bubble game
+
+ Double🤯
+ Two of the biggest objects in the bubble game at the same time
+ You can fill a lunch box like this 🤯 🤯 a bit.
+
+
\ No newline at end of file
diff --git a/iosApp/iosApp/UI/Component/Status/StatusTimelineBuilder.swift b/iosApp/iosApp/UI/Component/Status/StatusTimelineBuilder.swift
index 69fd70f56..aa6ba4cd3 100644
--- a/iosApp/iosApp/UI/Component/Status/StatusTimelineBuilder.swift
+++ b/iosApp/iosApp/UI/Component/Status/StatusTimelineBuilder.swift
@@ -57,6 +57,7 @@ struct StatusItemView: View {
case .edit: "pencil"
case .info: "app"
case .reply: "arrowshape.turn.up.left"
+ case .quote: "quote.bubble.fill"
}
let text = switch onEnum(of: topMessage.type) {
case .bluesky(let data):
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/data/database/cache/mapper/Bluesky.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/data/database/cache/mapper/Bluesky.kt
index 478b9dd1a..e9682a98d 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/data/database/cache/mapper/Bluesky.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/data/database/cache/mapper/Bluesky.kt
@@ -213,25 +213,18 @@ internal fun List.toDbPagingTimeline(
}
}
val references =
- when (val data = it.reason) {
- is FeedViewPostReasonUnion.ReasonRepost ->
- listOfNotNull(
- if (reply != null) {
- ReferenceType.Reply to reply
- } else {
- null
- },
- ReferenceType.Retweet to status,
- ).toMap()
- else ->
- listOfNotNull(
- if (reply != null) {
- ReferenceType.Reply to reply
- } else {
- null
- },
- ).toMap()
- }
+ listOfNotNull(
+ if (reply != null) {
+ ReferenceType.Reply to reply
+ } else {
+ null
+ },
+ if (it.reason is FeedViewPostReasonUnion.ReasonRepost) {
+ ReferenceType.Retweet to it.post.toDbStatusWithUser(accountKey)
+ } else {
+ null
+ },
+ ).toMap()
createDbPagingTimelineWithStatus(
accountKey = accountKey,
pagingKey = pagingKey,
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/mastodon/MastodonDataSource.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/mastodon/MastodonDataSource.kt
index 63b1cc304..13940cea3 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/mastodon/MastodonDataSource.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/mastodon/MastodonDataSource.kt
@@ -549,7 +549,7 @@ class MastodonDataSource(
accountKey = account.accountKey,
cacheDatabase = database,
update = {
- it.copy(data = result)
+ result.reblog?.let { StatusContent.Mastodon(it) } ?: it
},
)
}
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/misskey/MisskeyDataSource.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/misskey/MisskeyDataSource.kt
index 77d93995d..210772e37 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/misskey/MisskeyDataSource.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/misskey/MisskeyDataSource.kt
@@ -27,7 +27,6 @@ import dev.dimension.flare.data.datasource.microblog.timelinePager
import dev.dimension.flare.data.network.misskey.api.model.AdminAccountsDeleteRequest
import dev.dimension.flare.data.network.misskey.api.model.IPinRequest
import dev.dimension.flare.data.network.misskey.api.model.MuteCreateRequest
-import dev.dimension.flare.data.network.misskey.api.model.NotesChildrenRequest
import dev.dimension.flare.data.network.misskey.api.model.NotesCreateRequest
import dev.dimension.flare.data.network.misskey.api.model.NotesCreateRequestPoll
import dev.dimension.flare.data.network.misskey.api.model.NotesReactionsCreateRequest
@@ -380,11 +379,40 @@ class MisskeyDataSource(
override fun renote(statusKey: MicroBlogKey) {
coroutineScope.launch {
- service.notesRenotes(
- NotesChildrenRequest(
- noteId = statusKey.id,
- ),
+ updateStatusUseCase(
+ statusKey = statusKey,
+ accountKey = account.accountKey,
+ cacheDatabase = database,
+ update = {
+ it.copy(
+ data =
+ it.data.copy(
+ renoteCount = it.data.renoteCount + 1,
+ ),
+ )
+ },
)
+ runCatching {
+ service.notesCreate(
+ NotesCreateRequest(
+ renoteId = statusKey.id,
+ ),
+ )
+ }.onFailure {
+ updateStatusUseCase(
+ statusKey = statusKey,
+ accountKey = account.accountKey,
+ cacheDatabase = database,
+ update = {
+ it.copy(
+ data =
+ it.data.copy(
+ renoteCount = it.data.renoteCount - 1,
+ ),
+ )
+ },
+ )
+ }
}
}
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiTimeline.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiTimeline.kt
index 54c72c06b..f6c552775 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiTimeline.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiTimeline.kt
@@ -5,11 +5,11 @@ import dev.dimension.flare.data.datasource.microblog.StatusAction
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.model.PlatformType
import dev.dimension.flare.ui.humanizer.humanize
+import dev.dimension.flare.ui.model.mapper.MisskeyAchievement
import dev.dimension.flare.ui.render.UiDateTime
import dev.dimension.flare.ui.render.UiRichText
import kotlinx.collections.immutable.ImmutableList
-// TODO: Handling item click event internally
@Immutable
data class UiTimeline internal constructor(
val topMessage: TopMessage?,
@@ -169,6 +169,7 @@ data class UiTimeline internal constructor(
Edit,
Info,
Reply,
+ Quote,
}
sealed interface MessageType {
@@ -191,27 +192,50 @@ data class UiTimeline internal constructor(
}
sealed interface Misskey : MessageType {
- data object Follow : Misskey
+ data class Follow(
+ val id: String,
+ ) : Misskey
- data object Mention : Misskey
+ data class Mention(
+ val id: String,
+ ) : Misskey
- data object Reply : Misskey
+ data class Reply(
+ val id: String,
+ ) : Misskey
- data object Renote : Misskey
+ data class Renote(
+ val id: String,
+ ) : Misskey
- data object Quote : Misskey
+ data class Quote(
+ val id: String,
+ ) : Misskey
- data object Reaction : Misskey
+ data class Reaction(
+ val id: String,
+ ) : Misskey
- data object PollEnded : Misskey
+ data class PollEnded(
+ val id: String,
+ ) : Misskey
- data object ReceiveFollowRequest : Misskey
+ data class ReceiveFollowRequest(
+ val id: String,
+ ) : Misskey
- data object FollowRequestAccepted : Misskey
+ data class FollowRequestAccepted(
+ val id: String,
+ ) : Misskey
- data object AchievementEarned : Misskey
+ data class AchievementEarned(
+ val id: String,
+ val achievement: MisskeyAchievement?,
+ ) : Misskey
- data object App : Misskey
+ data class App(
+ val id: String,
+ ) : Misskey
}
sealed interface Bluesky : MessageType {
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Bluesky.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Bluesky.kt
index 5fdb4b676..8543526c0 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Bluesky.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Bluesky.kt
@@ -17,11 +17,13 @@ import app.bsky.richtext.FacetFeatureUnion
import com.fleeksoft.ksoup.nodes.Element
import com.fleeksoft.ksoup.nodes.TextNode
import dev.dimension.flare.common.AppDeepLink
+import dev.dimension.flare.data.database.cache.model.StatusContent
import dev.dimension.flare.data.datasource.bluesky.bskyJson
import dev.dimension.flare.data.datasource.microblog.StatusAction
import dev.dimension.flare.data.datasource.microblog.StatusEvent
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.model.PlatformType
+import dev.dimension.flare.model.ReferenceType
import dev.dimension.flare.ui.model.UiCard
import dev.dimension.flare.ui.model.UiList
import dev.dimension.flare.ui.model.UiMedia
@@ -138,10 +140,11 @@ private fun parseBluesky(
internal fun FeedViewPostReasonUnion.render(
accountKey: MicroBlogKey,
- data: PostView,
event: StatusEvent.Bluesky,
-): UiTimeline =
- UiTimeline(
+ references: Map,
+): UiTimeline {
+ val data = (references[ReferenceType.Retweet] as? StatusContent.Bluesky)?.data
+ return UiTimeline(
topMessage =
(this as? FeedViewPostReasonUnion.ReasonRepost)?.value?.by?.let {
val user = it.render(accountKey)
@@ -159,9 +162,10 @@ internal fun FeedViewPostReasonUnion.render(
},
)
},
- content = data.renderStatus(accountKey, event),
+ content = data?.renderStatus(accountKey, event),
platformType = PlatformType.Bluesky,
)
+}
internal fun ListNotificationsNotification.render(accountKey: MicroBlogKey): UiTimeline {
val user = author.render(accountKey)
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Mastodon.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Mastodon.kt
index 040e2b601..ea48e4a80 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Mastodon.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Mastodon.kt
@@ -5,6 +5,7 @@ import com.fleeksoft.ksoup.nodes.Node
import dev.dimension.flare.common.AppDeepLink
import dev.dimension.flare.data.database.cache.model.DbEmoji
import dev.dimension.flare.data.database.cache.model.EmojiContent
+import dev.dimension.flare.data.database.cache.model.StatusContent
import dev.dimension.flare.data.datasource.guest.GuestDataSource
import dev.dimension.flare.data.datasource.microblog.StatusAction
import dev.dimension.flare.data.datasource.microblog.StatusEvent
@@ -19,6 +20,7 @@ import dev.dimension.flare.data.network.mastodon.api.model.Status
import dev.dimension.flare.data.network.mastodon.api.model.Visibility
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.model.PlatformType
+import dev.dimension.flare.model.ReferenceType
import dev.dimension.flare.ui.model.UiCard
import dev.dimension.flare.ui.model.UiEmoji
import dev.dimension.flare.ui.model.UiMedia
@@ -38,10 +40,14 @@ import kotlinx.datetime.Instant
internal fun Notification.render(
accountKey: MicroBlogKey,
event: StatusEvent.Mastodon,
+ references: Map,
): UiTimeline {
requireNotNull(account) { "account is null" }
val user = account.render(accountKey)
- val status = status?.renderStatus(accountKey, event)
+ val status =
+ (references[ReferenceType.Notification] as? StatusContent.Mastodon)
+ ?.data
+ ?.renderStatus(accountKey, event)
val topMessageType =
when (type) {
NotificationTypes.Follow -> UiTimeline.TopMessage.MessageType.Mastodon.Follow
@@ -97,6 +103,7 @@ internal fun Notification.render(
internal fun Status.render(
accountKey: MicroBlogKey,
event: StatusEvent.Mastodon,
+ references: Map = mapOf(),
): UiTimeline {
requireNotNull(account) { "account is null" }
val user = account.render(accountKey)
@@ -119,7 +126,7 @@ internal fun Status.render(
)
}
val currentStatus = this.renderStatus(accountKey, event)
- val actualStatus = reblog ?: this
+ val actualStatus = (references[ReferenceType.Retweet] as? StatusContent.Mastodon)?.data ?: this
return UiTimeline(
topMessage = topMessage,
content =
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Misskey.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Misskey.kt
index d286e8d35..1037c964f 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Misskey.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Misskey.kt
@@ -3,6 +3,7 @@ package dev.dimension.flare.ui.model.mapper
import com.fleeksoft.ksoup.nodes.Element
import com.fleeksoft.ksoup.nodes.TextNode
import dev.dimension.flare.common.AppDeepLink
+import dev.dimension.flare.data.database.cache.model.StatusContent
import dev.dimension.flare.data.datasource.microblog.StatusAction
import dev.dimension.flare.data.datasource.microblog.StatusEvent
import dev.dimension.flare.data.network.misskey.api.model.DriveFile
@@ -15,6 +16,7 @@ import dev.dimension.flare.data.network.misskey.api.model.UserLite
import dev.dimension.flare.data.network.misskey.api.model.Visibility
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.model.PlatformType
+import dev.dimension.flare.model.ReferenceType
import dev.dimension.flare.ui.model.UiEmoji
import dev.dimension.flare.ui.model.UiMedia
import dev.dimension.flare.ui.model.UiPoll
@@ -50,27 +52,72 @@ import moe.tlaster.mfm.parser.tree.UrlNode
internal fun Notification.render(
accountKey: MicroBlogKey,
event: StatusEvent.Misskey,
+ references: Map,
): UiTimeline {
val user = user?.render(accountKey)
- val status = note?.renderStatus(accountKey, event)
+ val status =
+ (references[ReferenceType.Notification] as? StatusContent.Misskey)
+ ?.data
+ ?.renderStatus(accountKey, event)
val topMessageType =
when (this.type) {
- NotificationType.Follow -> UiTimeline.TopMessage.MessageType.Misskey.Follow
- NotificationType.Mention -> UiTimeline.TopMessage.MessageType.Misskey.Mention
- NotificationType.Reply -> UiTimeline.TopMessage.MessageType.Misskey.Reply
- NotificationType.Renote -> UiTimeline.TopMessage.MessageType.Misskey.Renote
- NotificationType.Quote -> UiTimeline.TopMessage.MessageType.Misskey.Quote
- NotificationType.Reaction -> UiTimeline.TopMessage.MessageType.Misskey.Reaction
- NotificationType.PollEnded -> UiTimeline.TopMessage.MessageType.Misskey.PollEnded
- NotificationType.ReceiveFollowRequest -> UiTimeline.TopMessage.MessageType.Misskey.ReceiveFollowRequest
- NotificationType.FollowRequestAccepted -> UiTimeline.TopMessage.MessageType.Misskey.FollowRequestAccepted
- NotificationType.AchievementEarned -> UiTimeline.TopMessage.MessageType.Misskey.AchievementEarned
- NotificationType.App -> UiTimeline.TopMessage.MessageType.Misskey.App
+ NotificationType.Follow ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .Follow(id = id)
+ NotificationType.Mention ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .Mention(id = id)
+ NotificationType.Reply ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .Reply(id = id)
+ NotificationType.Renote ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .Renote(id = id)
+ NotificationType.Quote ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .Quote(id = id)
+ NotificationType.Reaction ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .Reaction(id = id)
+ NotificationType.PollEnded ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .PollEnded(id = id)
+ NotificationType.ReceiveFollowRequest ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .ReceiveFollowRequest(id = id)
+ NotificationType.FollowRequestAccepted ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .FollowRequestAccepted(id = id)
+ NotificationType.AchievementEarned ->
+ UiTimeline.TopMessage.MessageType.Misskey.AchievementEarned(
+ id = id,
+ achievement =
+ achievement?.let {
+ MisskeyAchievement.fromString(it)
+ },
+ )
+ NotificationType.App ->
+ UiTimeline.TopMessage.MessageType.Misskey
+ .App(id = id)
+ }
+ val icon =
+ when (this.type) {
+ NotificationType.Follow -> UiTimeline.TopMessage.Icon.Follow
+ NotificationType.Mention -> UiTimeline.TopMessage.Icon.Mention
+ NotificationType.Reply -> UiTimeline.TopMessage.Icon.Reply
+ NotificationType.Renote -> UiTimeline.TopMessage.Icon.Retweet
+ NotificationType.Quote -> UiTimeline.TopMessage.Icon.Quote
+ NotificationType.Reaction -> UiTimeline.TopMessage.Icon.Favourite
+ NotificationType.PollEnded -> UiTimeline.TopMessage.Icon.Poll
+ NotificationType.ReceiveFollowRequest -> UiTimeline.TopMessage.Icon.Follow
+ NotificationType.FollowRequestAccepted -> UiTimeline.TopMessage.Icon.Follow
+ NotificationType.AchievementEarned -> UiTimeline.TopMessage.Icon.Info
+ NotificationType.App -> UiTimeline.TopMessage.Icon.Info
}
val topMessage =
UiTimeline.TopMessage(
user = user,
- icon = UiTimeline.TopMessage.Icon.Retweet,
+ icon = icon,
type = topMessageType,
onClicked = {
if (user != null) {
@@ -99,11 +146,101 @@ internal fun Notification.render(
)
}
+enum class MisskeyAchievement(
+ val id: String,
+) {
+ NOTES1("notes1"),
+ NOTES10("notes10"),
+ NOTES100("notes100"),
+ NOTES500("notes500"),
+ NOTES1000("notes1000"),
+ NOTES5000("notes5000"),
+ NOTES10000("notes10000"),
+ NOTES20000("notes20000"),
+ NOTES30000("notes30000"),
+ NOTES40000("notes40000"),
+ NOTES50000("notes50000"),
+ NOTES60000("notes60000"),
+ NOTES70000("notes70000"),
+ NOTES80000("notes80000"),
+ NOTES90000("notes90000"),
+ NOTES100000("notes100000"),
+ LOGIN3("login3"),
+ LOGIN7("login7"),
+ LOGIN15("login15"),
+ LOGIN30("login30"),
+ LOGIN60("login60"),
+ LOGIN100("login100"),
+ LOGIN200("login200"),
+ LOGIN300("login300"),
+ LOGIN400("login400"),
+ LOGIN500("login500"),
+ LOGIN600("login600"),
+ LOGIN700("login700"),
+ LOGIN800("login800"),
+ LOGIN900("login900"),
+ LOGIN1000("login1000"),
+ NOTE_CLIPPED1("noteClipped1"),
+ NOTE_FAVORITED1("noteFavorited1"),
+ MY_NOTE_FAVORITED1("myNoteFavorited1"),
+ PROFILE_FILLED("profileFilled"),
+ MARKED_AS_CAT("markedAsCat"),
+ FOLLOWING1("following1"),
+ FOLLOWING10("following10"),
+ FOLLOWING50("following50"),
+ FOLLOWING100("following100"),
+ FOLLOWING300("following300"),
+ FOLLOWERS1("followers1"),
+ FOLLOWERS10("followers10"),
+ FOLLOWERS50("followers50"),
+ FOLLOWERS100("followers100"),
+ FOLLOWERS300("followers300"),
+ FOLLOWERS500("followers500"),
+ FOLLOWERS1000("followers1000"),
+ COLLECT_ACHIEVEMENTS30("collectAchievements30"),
+ VIEW_ACHIEVEMENTS3MIN("viewAchievements3min"),
+ I_LOVE_MISSKEY("iLoveMisskey"),
+ FOUND_TREASURE("foundTreasure"),
+ CLIENT30MIN("client30min"),
+ CLIENT60MIN("client60min"),
+ NOTE_DELETED_WITHIN1MIN("noteDeletedWithin1min"),
+ POSTED_AT_LATE_NIGHT("postedAtLateNight"),
+ POSTED_AT_0MIN0SEC("postedAt0min0sec"),
+ SELF_QUOTE("selfQuote"),
+ HTL20NPM("htl20npm"),
+ VIEW_INSTANCE_CHART("viewInstanceChart"),
+ OUTPUT_HELLO_WORLD_ON_SCRATCHPAD("outputHelloWorldOnScratchpad"),
+ OPEN3WINDOWS("open3windows"),
+ DRIVE_FOLDER_CIRCULAR_REFERENCE("driveFolderCircularReference"),
+ REACT_WITHOUT_READ("reactWithoutRead"),
+ CLICKED_CLICK_HERE("clickedClickHere"),
+ JUST_PLAIN_LUCKY("justPlainLucky"),
+ SET_NAME_TO_SYUILO("setNameToSyuilo"),
+ PASSED_SINCE_ACCOUNT_CREATED1("passedSinceAccountCreated1"),
+ PASSED_SINCE_ACCOUNT_CREATED2("passedSinceAccountCreated2"),
+ PASSED_SINCE_ACCOUNT_CREATED3("passedSinceAccountCreated3"),
+ LOGGED_IN_ON_BIRTHDAY("loggedInOnBirthday"),
+ LOGGED_IN_ON_NEW_YEARS_DAY("loggedInOnNewYearsDay"),
+ COOKIE_CLICKED("cookieClicked"),
+ BRAIN_DIVER("brainDiver"),
+ SMASH_TEST_NOTIFICATION_BUTTON("smashTestNotificationButton"),
+ TUTORIAL_COMPLETED("tutorialCompleted"),
+ BUBBLE_GAME_EXPLODING_HEAD("bubbleGameExplodingHead"),
+ BUBBLE_GAME_DOUBLE_EXPLODING_HEAD("bubbleGameDoubleExplodingHead"),
+ ;
+
+ companion object {
+ fun fromString(id: String): MisskeyAchievement? = entries.find { it.id == id }
+ }
+}
+
internal fun Note.render(
accountKey: MicroBlogKey,
event: StatusEvent.Misskey,
+ references: Map,
): UiTimeline {
val user = user.render(accountKey)
+ val renote = (references[ReferenceType.Retweet] as? StatusContent.Misskey)?.data
val topMessage =
if (renote == null || !text.isNullOrEmpty()) {
null
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Render.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Render.kt
index c37a113c8..39af265a3 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Render.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Render.kt
@@ -6,47 +6,60 @@ import dev.dimension.flare.data.database.cache.model.StatusContent
import dev.dimension.flare.data.database.cache.model.UserContent
import dev.dimension.flare.data.datasource.microblog.StatusEvent
import dev.dimension.flare.model.MicroBlogKey
+import dev.dimension.flare.model.ReferenceType
import dev.dimension.flare.ui.model.UiTimeline
internal fun DbPagingTimelineView.render(event: StatusEvent): UiTimeline =
status_content.render(
timeline.accountKey,
event,
+ references =
+ listOfNotNull(
+ retweet_status_content?.let { ReferenceType.Retweet to it },
+ quote_status_content?.let { ReferenceType.Quote to it },
+ reply_status_content?.let { ReferenceType.Reply to it },
+ notification_status_content?.let { ReferenceType.Notification to it },
+ ).toMap(),
)
internal fun StatusContent.render(
accountKey: MicroBlogKey,
event: StatusEvent,
+ references: Map = emptyMap(),
) = when (this) {
is StatusContent.Mastodon ->
data.render(
accountKey = accountKey,
event = event as StatusEvent.Mastodon,
+ references = references,
)
is StatusContent.MastodonNotification ->
data.render(
accountKey = accountKey,
event = event as StatusEvent.Mastodon,
+ references = references,
)
is StatusContent.Misskey ->
data.render(
accountKey = accountKey,
event = event as StatusEvent.Misskey,
+ references = references,
)
is StatusContent.MisskeyNotification ->
data.render(
accountKey = accountKey,
event = event as StatusEvent.Misskey,
+ references = references,
)
is StatusContent.BlueskyReason ->
reason.render(
accountKey = accountKey,
- data = data,
event = event as StatusEvent.Bluesky,
+ references = references,
)
is StatusContent.Bluesky ->
@@ -64,6 +77,7 @@ internal fun StatusContent.render(
data.render(
accountKey = accountKey,
event = event as StatusEvent.XQT,
+ references = references,
)
is StatusContent.VVO ->
diff --git a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/XQT.kt b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/XQT.kt
index aa7e1d087..e392a19a2 100644
--- a/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/XQT.kt
+++ b/shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/XQT.kt
@@ -4,6 +4,7 @@ import com.fleeksoft.ksoup.nodes.Element
import com.fleeksoft.ksoup.nodes.TextNode
import de.cketti.codepoints.deluxe.codePointSequence
import dev.dimension.flare.common.AppDeepLink
+import dev.dimension.flare.data.database.cache.model.StatusContent
import dev.dimension.flare.data.datasource.microblog.StatusAction
import dev.dimension.flare.data.datasource.microblog.StatusEvent
import dev.dimension.flare.data.network.xqt.model.GetProfileSpotlightsQuery200Response
@@ -11,8 +12,6 @@ import dev.dimension.flare.data.network.xqt.model.Media
import dev.dimension.flare.data.network.xqt.model.Tweet
import dev.dimension.flare.data.network.xqt.model.TweetCardLegacy
import dev.dimension.flare.data.network.xqt.model.TweetCardLegacyBindingValueData
-import dev.dimension.flare.data.network.xqt.model.TweetTombstone
-import dev.dimension.flare.data.network.xqt.model.TweetWithVisibilityResults
import dev.dimension.flare.data.network.xqt.model.User
import dev.dimension.flare.data.network.xqt.model.UserResultCore
import dev.dimension.flare.data.network.xqt.model.UserResults
@@ -20,6 +19,7 @@ import dev.dimension.flare.data.network.xqt.model.UserUnavailable
import dev.dimension.flare.data.network.xqt.model.legacy.TopLevel
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.model.PlatformType
+import dev.dimension.flare.model.ReferenceType
import dev.dimension.flare.model.xqtHost
import dev.dimension.flare.ui.model.UiCard
import dev.dimension.flare.ui.model.UiMedia
@@ -110,7 +110,7 @@ internal fun TopLevel.renderNotifications(
),
),
legacy = it,
- ).renderStatus(accountKey, event)
+ ).renderStatus(accountKey, event, emptyMap())
}
val itemContent =
when {
@@ -178,7 +178,7 @@ internal fun TopLevel.renderNotifications(
),
),
legacy = tweet,
- ).renderStatus(accountKey, event)
+ ).renderStatus(accountKey, event, emptyMap())
UiTimeline(
topMessage =
UiTimeline.TopMessage(
@@ -202,20 +202,15 @@ internal fun TopLevel.renderNotifications(
internal fun Tweet.render(
accountKey: MicroBlogKey,
event: StatusEvent.XQT,
+ references: Map = emptyMap(),
): UiTimeline {
val retweet =
- legacy
- ?.retweetedStatusResult
- ?.result
- ?.let {
- when (it) {
- is Tweet -> it
- is TweetTombstone -> null
- is TweetWithVisibilityResults -> it.tweet
- }
- }
- val actualTweet = retweet ?: this
- val user = renderStatus(accountKey, event).user
+ (references[ReferenceType.Retweet] as? StatusContent.XQT)
+ ?.data
+ ?.renderStatus(accountKey = accountKey, event = event, references = emptyMap())
+ val currentTweet = renderStatus(accountKey, event, references)
+ val actualTweet = retweet ?: currentTweet
+ val user = currentTweet.user
val topMessage =
if (retweet != null && user != null) {
UiTimeline.TopMessage(
@@ -229,10 +224,9 @@ internal fun Tweet.render(
} else {
null
}
- val currentTweet = this.renderStatus(accountKey, event)
return UiTimeline(
content =
- actualTweet.renderStatus(accountKey = accountKey, event = event).copy(
+ actualTweet.copy(
onClicked = {
launcher.launch(
AppDeepLink.StatusDetail(
@@ -251,17 +245,12 @@ internal fun Tweet.render(
internal fun Tweet.renderStatus(
accountKey: MicroBlogKey,
event: StatusEvent.XQT,
+ references: Map,
): UiTimeline.ItemContent.Status {
val quote =
- quotedStatusResult
- ?.result
- ?.let {
- when (it) {
- is Tweet -> it
- is TweetTombstone -> null
- is TweetWithVisibilityResults -> it.tweet
- }
- }?.renderStatus(accountKey = accountKey, event = event)
+ (references[ReferenceType.Quote] as? StatusContent.XQT)
+ ?.data
+ ?.renderStatus(accountKey = accountKey, event = event, references = emptyMap())
val user =
core
?.userResults