トレンドリンク、トレンド投稿カラムの追加。

This commit is contained in:
tateisu 2022-03-16 14:08:54 +09:00
parent 0bbb3728bb
commit 45a99a3d3a
11 changed files with 165 additions and 36 deletions

View File

@ -264,10 +264,15 @@ class SideMenuAdapter(
timeline(defaultInsertPosition, ColumnType.SEARCH, args = arrayOf("", false))
},
Item(icon = R.drawable.ic_hashtag, title = R.string.trend_tag) {
Item(icon = R.drawable.ic_trend, title = R.string.trend_tag) {
timeline(defaultInsertPosition, ColumnType.TREND_TAG)
},
Item(icon = R.drawable.ic_trend, title = R.string.trend_link) {
timeline(defaultInsertPosition, ColumnType.TREND_LINK)
},
Item(icon = R.drawable.ic_trend, title = R.string.trend_post) {
timeline(defaultInsertPosition, ColumnType.TREND_POST)
},
Item(icon = R.drawable.ic_star, title = R.string.favourites) {
timeline(defaultInsertPosition, ColumnType.FAVOURITES)
},

View File

@ -3,11 +3,10 @@ package jp.juggler.subwaytooter.api
import android.content.Context
import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.util.WordTrieTree
import jp.juggler.subwaytooter.util.LinkHelper
import jp.juggler.util.JsonArray
import jp.juggler.util.JsonObject
import jp.juggler.util.WordTrieTree
class TootParser(
val context: Context,
@ -45,7 +44,9 @@ class TootParser(
fun notification(src: JsonObject?) = parseItem(::TootNotification, this, src)
fun notificationList(src: JsonArray?) = parseList(::TootNotification, this, src)
fun tagList(array: JsonArray?) = TootTag.parseList(this, array)
fun tagList(array: JsonArray?) =
TootTag.parseList(this, array)
fun results(src: JsonObject?) = parseItem(::TootResults, this, src)
fun instance(src: JsonObject?) = parseItem(::TootInstance, this, src)

View File

@ -11,13 +11,23 @@ open class TootTag constructor(
// The hashtag, not including the preceding #
val name: String,
val type: TagType = TagType.Tag,
// The URL of the hashtag. may null if generated from TootContext
val url: String? = null,
val title: String? = null,
val description: String? = null,
// Mastodon /api/v2/search provides history.
val history: ArrayList<History>? = null,
) : TimelineItem() {
enum class TagType {
Tag,
TrendLink
}
val countDaily: Int
val countWeekly: Int
@ -55,26 +65,38 @@ open class TootTag constructor(
private val reNotestockTagUrl = """/explore/""".toRegex()
fun parse(parser: TootParser, src: JsonObject) =
if (parser.linkHelper.isMisskey) {
val name = src.stringOrThrow("tag").replaceFirst(reHeadSharp, "")
TootTag(
name = name,
url = "https://${parser.apiHost}/tags/${Uri.encode(name)}"
)
} else {
// /api/v1/accounts/$id/featured_tags の場合、
// name部分は先頭に#がついているかもしれない。必要なら除去するべき。
// url部分はユーザのタグTLになる。 https://nightly.fedibird.com/@noellabo/tagged/fedibird
// STはメニューから選べるので、URLは普通のタグURLの方が望ましい https://nightly.fedibird.com/tags/fedibird
TootTag(
name = src.stringOrThrow("name").replaceFirst(reHeadSharp, ""),
// mastodonではurl,notestockではhref
// notestockではタグのURLは https://mastodon.juggler.jp/explore/subwaytooter のようになる
url = (src.string("url") ?: src.string("href"))
?.replaceFirst(reUserTagUrl, "/tags/")
?.replaceFirst(reNotestockTagUrl, "/tags/"),
history = parseHistories(src.jsonArray("history"))
)
when {
parser.linkHelper.isMisskey -> {
val name = src.stringOrThrow("tag").replaceFirst(reHeadSharp, "")
TootTag(
name = name,
url = "https://${parser.apiHost}/tags/${Uri.encode(name)}"
)
}
src.string("type") == "link" -> {
TootTag(
type = TagType.TrendLink,
name = src.string("title") ?: "",
url = src.string("url") ?: "",
description = src.string("description") ?: "",
history = parseHistories(src.jsonArray("history"))
)
}
else -> {
// /api/v1/accounts/$id/featured_tags の場合、
// name部分は先頭に#がついているかもしれない。必要なら除去するべき。
// url部分はユーザのタグTLになる。 https://nightly.fedibird.com/@noellabo/tagged/fedibird
// STはメニューから選べるので、URLは普通のタグURLの方が望ましい https://nightly.fedibird.com/tags/fedibird
TootTag(
name = src.stringOrThrow("name").replaceFirst(reHeadSharp, ""),
// mastodonではurl,notestockではhref
// notestockではタグのURLは https://mastodon.juggler.jp/explore/subwaytooter のようになる
url = (src.string("url") ?: src.string("href"))
?.replaceFirst(reUserTagUrl, "/tags/")
?.replaceFirst(reNotestockTagUrl, "/tags/"),
history = parseHistories(src.jsonArray("history"))
)
}
}
private fun parseHistories(src: JsonArray?): ArrayList<History>? {
@ -110,6 +132,28 @@ open class TootTag constructor(
fun parseList(parser: TootParser, array: JsonArray?) =
parseListOrNull(parser, array) ?: emptyList()
// @Suppress("unused")
// inline fun parseListOrNull(
// factory: (parser: TootParser, src: JsonObject) -> T,
// parser: TootParser,
// src: JsonArray?,
// log: LogCategory = EntityUtil.log,
// ): ArrayList<T>? {
// if (src != null) {
// val src_length = src.size
// if (src_length > 0) {
// val dst = ArrayList<T>()
// dst.ensureCapacity(src_length)
// for (i in src.indices) {
// val item = parseItem(factory, parser, src.jsonObject(i), log)
// if (item != null) dst.add(item)
// }
// if (dst.isNotEmpty()) return dst
// }
// }
// return null
// }
private const val w = TootAccount.reRubyWord
private const val a = TootAccount.reRubyAlpha
private const val s = "_\\u00B7\\u200c" // separators

View File

@ -275,9 +275,9 @@ fun Column.isFiltered(item: TootNotification): Boolean {
TootNotification.TYPE_POLL_VOTE_MISSKEY,
-> dontShowVote
TootNotification.TYPE_STATUS -> dontShowNormalToot
TootNotification.TYPE_UPDATE -> dontShowNormalToot && dontShowBoost
TootNotification.TYPE_STATUS,
TootNotification.TYPE_UPDATE,
-> dontShowNormalToot
else -> false
}
@ -310,9 +310,10 @@ fun Column.isFiltered(item: TootNotification): Boolean {
TootNotification.TYPE_POLL_VOTE_MISSKEY,
-> quickFilter != Column.QUICK_FILTER_VOTE
TootNotification.TYPE_STATUS -> quickFilter != Column.QUICK_FILTER_POST
TootNotification.TYPE_STATUS,
TootNotification.TYPE_UPDATE,
-> quickFilter != Column.QUICK_FILTER_POST
TootNotification.TYPE_UPDATE -> quickFilter != Column.QUICK_FILTER_POST
else -> true
}
}

View File

@ -1636,7 +1636,7 @@ enum class ColumnType(
TREND_TAG(
24,
iconId = { R.drawable.ic_hashtag },
iconId = { R.drawable.ic_trend },
name1 = { it.getString(R.string.trend_tag) },
bAllowPseudo = true,
bAllowMastodon = true,
@ -1659,6 +1659,58 @@ enum class ColumnType(
canStreamingMastodon = streamingTypeNo,
canStreamingMisskey = streamingTypeNo,
),
TREND_LINK(
44,
iconId = { R.drawable.ic_trend },
name1 = { it.getString(R.string.trend_link) },
bAllowPseudo = false,
bAllowMastodon = true,
bAllowMisskey = false,
loading = { client ->
val result = client.request("/api/v1/trends/links")
val src = parser.tagList(result?.jsonArray)
this.listTmp = addAll(this.listTmp, src)
this.listTmp = addOne(
this.listTmp, TootMessageHolder(
context.getString(R.string.trend_tag_desc),
gravity = Gravity.END
)
)
result
},
canStreamingMastodon = streamingTypeNo,
canStreamingMisskey = streamingTypeNo,
),
TREND_POST(
45,
iconId = { R.drawable.ic_trend },
name1 = { it.getString(R.string.trend_post) },
bAllowPseudo = false,
bAllowMastodon = true,
bAllowMisskey = false,
loading = { client ->
val result = client.request("/api/v1/trends/statuses")
val src = parser.statusList(result?.jsonArray)
this.listTmp = addAll(this.listTmp, src)
// this.listTmp = addOne(
// this.listTmp, TootMessageHolder(
// context.getString(R.string.trend_tag_desc),
// gravity = Gravity.END
// )
// )
result
},
canStreamingMastodon = streamingTypeNo,
canStreamingMisskey = streamingTypeNo,
),
FOLLOW_SUGGESTION(

View File

@ -263,7 +263,11 @@ private fun ItemViewHolder.clickAvatar(pos: Int, longClick: Boolean = false) {
private fun ItemViewHolder.clickTag(pos: Int, item: TimelineItem?) {
with(activity) {
when (item) {
is TootTag -> tagTimeline(pos, accessInfo, item.name)
is TootTag -> if (item.type == TootTag.TagType.TrendLink) {
openCustomTab(item.url)
} else {
tagTimeline(pos, accessInfo, item.name)
}
is TootSearchGap -> column.startGap(item, isHead = true)
is TootConversationSummary -> clickConversation(
pos,

View File

@ -414,11 +414,17 @@ fun ItemViewHolder.showFilter(filter: TootFilter) {
fun ItemViewHolder.showSearchTag(tag: TootTag) {
if (tag.history?.isNotEmpty() == true) {
llTrendTag.visibility = View.VISIBLE
tvTrendTagName.text = "#${tag.name}"
tvTrendTagDesc.text =
activity.getString(R.string.people_talking, tag.accountDaily, tag.accountWeekly)
tvTrendTagCount.text = "${tag.countDaily}(${tag.countWeekly})"
cvTagHistory.setHistory(tag.history)
if (tag.type == TootTag.TagType.TrendLink) {
tvTrendTagName.text = tag.url?.ellipsizeDot3(256)
tvTrendTagDesc.text = tag.name + "\n" + tag.description
} else {
tvTrendTagName.text = "#${tag.name}"
tvTrendTagDesc.text =
activity.getString(R.string.people_talking, tag.accountDaily, tag.accountWeekly)
}
} else {
llSearchTag.visibility = View.VISIBLE
btnSearchTag.text = "#" + tag.name

View File

@ -162,7 +162,7 @@ private fun ItemViewHolder.showNotificationUpdate(
nStatus: TootStatus?
) {
val colorBg = PrefI.ipEventBgColorUpdate(activity.pref)
val iconId = R.drawable.ic_refresh
val iconId = R.drawable.ic_history
nAccountRef?.let { showBoost(it, n.time_created_at, iconId, R.string.display_name_updates_post) }
nStatus?.let { showNotificationStatus(it, colorBg) }
}

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
android:pathData="M16,6l2.29,2.29 -4.88,4.88 -4,-4L2,16.59 3.41,18l6,-6 4,4 6.3,-6.29L22,12V6z"/>
</vector>

View File

@ -726,6 +726,9 @@
<string name="toot_search_ts_of">トゥート検索(ts) \"%1$s\"</string>
<string name="tootsearch">tootsearch</string>
<string name="trend_tag">トレンドタグ</string>
<string name="trend_link">トレンドリンク</string>
<string name="trend_post">トレンド投稿</string>
<string name="trend_tag_desc">数字は「日毎(週毎)」を示します。</string>
<string name="ui_theme">UIテーマ(アプリ再起動が必要)</string>
<string name="unblock">ブロック解除</string>

View File

@ -696,6 +696,8 @@
<string name="yourself_can_see_your_network">Even if you choose to hide social graphs, yourself can see it.</string>
<string name="follow_follower_list_may_restrict">If the remote user choose to hide the social graph, only the followings/followers on this server will be displayed.</string>
<string name="trend_tag">Trending tags</string>
<string name="trend_link">Trending links</string>
<string name="trend_post">Trending posts</string>
<string name="people_talking">%1$d(%2$d) people talking</string>
<string name="trend_tag_desc">The numbers indicate \'daily(weekly)\'.</string>
<string name="redraft_and_delete">Redraft and delete</string>