古い端末のサポート終了予定をサイドメニューに表示する

This commit is contained in:
tateisu 2022-07-17 06:44:58 +09:00
parent 3831ff27b9
commit 43884919f8
9 changed files with 137 additions and 102 deletions

View File

@ -74,7 +74,7 @@ class ActMain : AppCompatActivity(),
var stripIconSize = 1 var stripIconSize = 1
var screenBottomPadding = 0 var screenBottomPadding = 0
var timelineFont: Typeface = Typeface.DEFAULT var timelineFont: Typeface = Typeface.DEFAULT
var timeline_font_bold: Typeface = Typeface.DEFAULT_BOLD var timelineFontBold: Typeface = Typeface.DEFAULT_BOLD
var eventFadeAlpha = 1f var eventFadeAlpha = 1f
} }

View File

@ -39,13 +39,13 @@ fun ActMain.reloadFonts() {
sv = PrefS.spTimelineFontBold(pref) sv = PrefS.spTimelineFontBold(pref)
if (sv.isNotEmpty()) { if (sv.isNotEmpty()) {
try { try {
ActMain.timeline_font_bold = Typeface.createFromFile(sv) ActMain.timelineFontBold = Typeface.createFromFile(sv)
} catch (ex: Throwable) { } catch (ex: Throwable) {
log.trace(ex) log.trace(ex)
} }
} else { } else {
try { try {
ActMain.timeline_font_bold = Typeface.create(ActMain.timelineFont, Typeface.BOLD) ActMain.timelineFontBold = Typeface.create(ActMain.timelineFont, Typeface.BOLD)
} catch (ex: Throwable) { } catch (ex: Throwable) {
log.trace(ex) log.trace(ex)
} }

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.drawable.StateListDrawable import android.graphics.drawable.StateListDrawable
import android.os.Build
import android.os.Handler import android.os.Handler
import android.text.Spannable import android.text.Spannable
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
@ -11,6 +12,7 @@ import android.text.TextPaint
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.text.style.UnderlineSpan
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.BaseAdapter import android.widget.BaseAdapter
@ -30,7 +32,8 @@ import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.VersionString import jp.juggler.subwaytooter.util.VersionString
import jp.juggler.subwaytooter.util.openBrowser import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.* import jp.juggler.util.*
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.anko.backgroundColor import org.jetbrains.anko.backgroundColor
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
@ -47,120 +50,146 @@ class SideMenuAdapter(
companion object { companion object {
private val log = LogCategory("SideMenuAdapter") private val log = LogCategory("SideMenuAdapter")
private const val urlAppVersion =
"https://mastodon-msg.juggler.jp/appVersion/appVersion.json"
private const val urlGithubReleases =
"https://github.com/tateisu/SubwayTooter/releases"
private const val urlOlderDevices =
"https://github.com/tateisu/SubwayTooter/discussions/192"
private val itemTypeCount = ItemType.values().size private val itemTypeCount = ItemType.values().size
private var lastVersionView: WeakReference<TextView>? = null private var lastVersionView: WeakReference<TextView>? = null
private var versionRow = SpannableStringBuilder("") private var versionText = SpannableStringBuilder("")
private var releaseInfo: JsonObject? = null private var releaseInfo: JsonObject? = null
private fun clickableSpan(url: String) = private fun clickableSpan(
object : ClickableSpan() { url: String,
override fun onClick(widget: View) { showUnderline: Boolean = false,
widget.activity?.openBrowser(url) ) = object : ClickableSpan() {
} override fun onClick(widget: View) {
widget.activity?.openBrowser(url)
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.isUnderlineText = false
}
} }
// 文字列を組み立ててhandler経由でViewに設定する override fun updateDrawState(ds: TextPaint) {
// メインスレッドでもそれ以外でも動作する super.updateDrawState(ds)
fun afterGet(appContext: Context, handler: Handler, currentVersion: String) { ds.isUnderlineText = showUnderline
versionRow = SpannableStringBuilder().apply {
append(
appContext.getString(
R.string.app_name_with_version,
appContext.getString(R.string.app_name),
currentVersion
)
)
val newRelease = releaseInfo?.jsonObject(
if (PrefB.bpCheckBetaVersion()) "beta" else "stable"
)
val newVersion =
(newRelease?.string("name")?.notEmpty() ?: newRelease?.string("tag_name"))
?.replace("""(v|version)\s*""".toRegex(RegexOption.IGNORE_CASE), "")
?.trim()
if (newVersion == null || newVersion.isEmpty() || VersionString(currentVersion) >= VersionString(
newVersion
)
) {
val url = "https://github.com/tateisu/SubwayTooter/releases"
append("\n")
val start = length
append(appContext.getString(R.string.release_note))
setSpan(
clickableSpan(url),
start, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
} else {
append("\n")
var start = length
append(
appContext.getString(
R.string.new_version_available,
newVersion
)
)
setSpan(
ForegroundColorSpan(
appContext.attrColor(R.attr.colorRegexFilterError)
),
start, length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
newRelease?.string("html_url")?.let { url ->
append("\n")
start = length
append(appContext.getString(R.string.release_note_with_assets))
setSpan(
clickableSpan(url),
start, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
} }
handler.post { lastVersionView?.get()?.text = versionRow }
} }
// メインスレッドから呼ばれる private fun SpannableStringBuilder.appendSpanLine(
private fun checkVersion(appContext: Context, handler: Handler) { text: String,
vararg spans: Any,
) = this.apply {
if (isNotEmpty()) {
append("\n")
}
val start = length
append(text)
for (span in spans) {
setSpan(span, start, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
// バージョン情報と更新履歴と新リリース告知の文字列を組み立てる
// メインスレッドでもそれ以外でも動作すること
private fun Context.createVersionRow() = SpannableStringBuilder().apply {
val currentVersion = try { val currentVersion = try {
appContext.packageManager.getPackageInfo(appContext.packageName, 0).versionName packageManager.getPackageInfo(packageName, 0).versionName
} catch (ignored: PackageManager.NameNotFoundException) { } catch (ignored: PackageManager.NameNotFoundException) {
"??" "??"
} }
versionRow = SpannableStringBuilder().apply { append(
append( getString(
appContext.getString( R.string.app_name_with_version,
R.string.app_name_with_version, getString(R.string.app_name),
appContext.getString(R.string.app_name), currentVersion
currentVersion )
)
val newRelease = releaseInfo?.jsonObject(
if (PrefB.bpCheckBetaVersion()) "beta" else "stable"
)
// 使用中のアプリバージョンより新しいリリースがある?
val newVersion =
(newRelease?.string("name")?.notEmpty() ?: newRelease?.string("tag_name"))
?.replace("""(v|version)\s*""".toRegex(RegexOption.IGNORE_CASE), "")
?.trim()
?.notEmpty()
?.takeIf { VersionString(it) > VersionString(currentVersion) }
val releaseMinSdkVersion = newRelease?.int("minSdkVersion")
?: Build.VERSION.SDK_INT
val releaseMinSdkVersionScheduled = newRelease?.int("minSdkVersionScheduled")
?: Build.VERSION.SDK_INT
when {
// 新しいバージョンがある
// それはこの端末にインストール可能である
newVersion != null && Build.VERSION.SDK_INT >= releaseMinSdkVersion -> {
appendSpanLine(
getString(
R.string.new_version_available,
newVersion
),
ForegroundColorSpan(
attrColor(R.attr.colorRegexFilterError)
),
) )
newRelease?.string("html_url")?.let {
appendSpanLine(
getString(R.string.release_note_with_assets),
clickableSpan(it)
)
}
}
// 通常時は更新履歴へのリンク
else -> appendSpanLine(
getString(R.string.release_note),
UnderlineSpan(),
clickableSpan(urlGithubReleases),
) )
} }
val lastUpdated = releaseInfo?.string("updated_at")?.let { TootStatus.parseTime(it) } // 端末のOSバージョンがサポートから外れる予定なら、サイドメニューにリンクを追加する
if (lastUpdated != null && System.currentTimeMillis() - lastUpdated < 86400000L) { if (Build.VERSION.SDK_INT < releaseMinSdkVersionScheduled) {
afterGet(appContext, handler, currentVersion) appendSpanLine(
} else { getString(R.string.old_devices_warning),
launchIO { clickableSpan(urlOlderDevices, showUnderline = true),
val json = )
App1.getHttpCached("https://mastodon-msg.juggler.jp/appVersion/appVersion.json") }
?.decodeUTF8()?.decodeJsonObject() }
if (json != null) {
releaseInfo = json // メインスレッドから呼ばれる
afterGet(appContext, handler, currentVersion) private fun Context.checkVersion() {
// サイドメニューから参照されるバージョン文字列を初期化する
// この時点ではreleaseInfoはnullかもしれない
versionText = createVersionRow()
// releaseInfoが既にあり、更新時刻が十分に新しいなら情報を取得し直す必要はない
releaseInfo?.string("updated_at")
?.let { TootStatus.parseTime(it) }
?.takeIf { it >= System.currentTimeMillis() - 86400000L }
?.let { return }
// リリース情報を取得し直す
launchIO {
try {
val json = App1.getHttpCached(urlAppVersion)
?.decodeUTF8()
?.decodeJsonObject()
?: error("missing appVersion json")
releaseInfo = json
versionText = createVersionRow()
withContext(Dispatchers.Main) {
lastVersionView?.get()?.text = versionText
} }
} catch (ex: Throwable) {
log.e(ex, "checkVersion failed")
} }
} }
} }
@ -451,8 +480,12 @@ class SideMenuAdapter(
movementMethod = LinkMovementMethod.getInstance() movementMethod = LinkMovementMethod.getInstance()
textSize = 18f textSize = 18f
isAllCaps = false isAllCaps = false
setLineSpacing(
1f,
1.1f
)
background = null background = null
text = versionRow text = versionText
} }
ItemType.IT_TIMEZONE -> ItemType.IT_TIMEZONE ->
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item).apply { viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item).apply {
@ -502,7 +535,7 @@ class SideMenuAdapter(
} }
init { init {
checkVersion(actMain.applicationContext, handler) actMain.applicationContext.checkVersion()
ListView(actMain).apply { ListView(actMain).apply {
adapter = this@SideMenuAdapter adapter = this@SideMenuAdapter

View File

@ -174,7 +174,7 @@ private fun ColumnViewHolder.showAnnouncementFonts() {
tvAnnouncementPeriod.setLineSpacing(0f, spacing) tvAnnouncementPeriod.setLineSpacing(0f, spacing)
tvAnnouncementContent.setLineSpacing(0f, spacing) tvAnnouncementContent.setLineSpacing(0f, spacing)
} }
tvAnnouncementsCaption.typeface = ActMain.timeline_font_bold tvAnnouncementsCaption.typeface = ActMain.timelineFontBold
val fontNormal = ActMain.timelineFont val fontNormal = ActMain.timelineFont
tvAnnouncementsIndex.typeface = fontNormal tvAnnouncementsIndex.typeface = fontNormal
tvAnnouncementPeriod.typeface = fontNormal tvAnnouncementPeriod.typeface = fontNormal

View File

@ -667,7 +667,7 @@ internal class ViewHolderHeaderProfile(
authorDomain = who authorDomain = who
) )
val nameTypeface = ActMain.timeline_font_bold val nameTypeface = ActMain.timelineFontBold
val valueTypeface = ActMain.timelineFont val valueTypeface = ActMain.timelineFont
for (item in fields) { for (item in fields) {

View File

@ -49,7 +49,7 @@ fun ItemViewHolder.bind(
this.accessInfo = column.accessInfo this.accessInfo = column.accessInfo
val fontBold = ActMain.timeline_font_bold val fontBold = ActMain.timelineFontBold
val fontNormal = ActMain.timelineFont val fontNormal = ActMain.timelineFont
viewRoot.scan { v -> viewRoot.scan { v ->
try { try {

View File

@ -29,7 +29,7 @@ class SpanOutputEnv(
val decorationEnabled = PrefB.bpMfmDecorationEnabled(context) val decorationEnabled = PrefB.bpMfmDecorationEnabled(context)
val showUnsupportedMarkup = PrefB.bpMfmDecorationShowUnsupportedMarkup(context) val showUnsupportedMarkup = PrefB.bpMfmDecorationShowUnsupportedMarkup(context)
val fontBold = ActMain.timeline_font_bold val fontBold = ActMain.timelineFontBold
val linkHelper: LinkHelper? = options.linkHelper val linkHelper: LinkHelper? = options.linkHelper
var spanList = SpanList() var spanList = SpanList()

View File

@ -1150,4 +1150,5 @@
<string name="use_web_settings">Web設定を使う</string> <string name="use_web_settings">Web設定を使う</string>
<string name="content">本文</string> <string name="content">本文</string>
<string name="enable_misskey_notification_check">Misskeyサーバで通知チェックを行う(不安定)</string> <string name="enable_misskey_notification_check">Misskeyサーバで通知チェックを行う(不安定)</string>
<string name="old_devices_warning">古い端末のサポート終了</string>
</resources> </resources>

View File

@ -1159,4 +1159,5 @@
<string name="use_web_settings">(Use web setting)</string> <string name="use_web_settings">(Use web setting)</string>
<string name="content">Content</string> <string name="content">Content</string>
<string name="enable_misskey_notification_check">Enable notification check for Misskey server (unstable)</string> <string name="enable_misskey_notification_check">Enable notification check for Misskey server (unstable)</string>
<string name="old_devices_warning">End of support for older devices</string>
</resources> </resources>