サイドメニューにバージョン表記。アップデートの有無を確認して表示。
This commit is contained in:
parent
1aa15618c9
commit
52a5ad4eaa
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,6 +4,8 @@
|
|||||||
/.idea/workspace.xml
|
/.idea/workspace.xml
|
||||||
/.idea/libraries
|
/.idea/libraries
|
||||||
/.idea/assetWizardSettings.xml
|
/.idea/assetWizardSettings.xml
|
||||||
|
/.idea/jarRepositories.xml
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
|
@ -1340,7 +1340,7 @@ class ActMain : AsyncActivity()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
SideMenuAdapter(this, findViewById(R.id.nav_view), drawer)
|
SideMenuAdapter(this, handler, findViewById(R.id.nav_view), drawer)
|
||||||
|
|
||||||
btnMenu = findViewById(R.id.btnMenu)
|
btnMenu = findViewById(R.id.btnMenu)
|
||||||
btnToot = findViewById(R.id.btnToot)
|
btnToot = findViewById(R.id.btnToot)
|
||||||
|
@ -947,6 +947,8 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
|
|||||||
action(R.string.drawable_list) {
|
action(R.string.drawable_list) {
|
||||||
action = { startActivity(Intent(this, ActDrawableList::class.java)) }
|
action = { startActivity(Intent(this, ActDrawableList::class.java)) }
|
||||||
}
|
}
|
||||||
|
sw(Pref.bpCheckBetaVersion, R.string.check_beta_release)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
action(R.string.app_data_export) {
|
action(R.string.app_data_export) {
|
||||||
|
@ -431,6 +431,12 @@ object Pref {
|
|||||||
"EmojiPickerCloseOnSelected",
|
"EmojiPickerCloseOnSelected",
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val bpCheckBetaVersion = BooleanPref(
|
||||||
|
"CheckBetaVersion",
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
// int
|
// int
|
||||||
|
|
||||||
val ipBackButtonAction = IntPref("back_button_action", 0)
|
val ipBackButtonAction = IntPref("back_button_action", 0)
|
||||||
@ -558,9 +564,7 @@ object Pref {
|
|||||||
val spBoostAlpha = StringPref("BoostAlpha", "60")
|
val spBoostAlpha = StringPref("BoostAlpha", "60")
|
||||||
|
|
||||||
val spScreenBottomPadding = StringPref("ScreenBottomPadding", "0")
|
val spScreenBottomPadding = StringPref("ScreenBottomPadding", "0")
|
||||||
|
|
||||||
val spVersionNameWhenReleaseNoteTap = StringPref("VersionNameWhenReleaseNoteTap", "")
|
|
||||||
|
|
||||||
val spPullNotificationCheckInterval = StringPref("PullNotificationCheckInterval", "15")
|
val spPullNotificationCheckInterval = StringPref("PullNotificationCheckInterval", "15")
|
||||||
val spUserAgent = StringPref("UserAgent", "")
|
val spUserAgent = StringPref("UserAgent", "")
|
||||||
|
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
package jp.juggler.subwaytooter
|
package jp.juggler.subwaytooter
|
||||||
|
|
||||||
|
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.Handler
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.text.TextPaint
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.text.style.ClickableSpan
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -17,17 +22,152 @@ import androidx.drawerlayout.widget.DrawerLayout
|
|||||||
import jp.juggler.subwaytooter.action.Action_Account
|
import jp.juggler.subwaytooter.action.Action_Account
|
||||||
import jp.juggler.subwaytooter.action.Action_App
|
import jp.juggler.subwaytooter.action.Action_App
|
||||||
import jp.juggler.subwaytooter.action.Action_Instance
|
import jp.juggler.subwaytooter.action.Action_Instance
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount
|
import jp.juggler.subwaytooter.table.SavedAccount
|
||||||
import jp.juggler.util.createColoredDrawable
|
import jp.juggler.subwaytooter.util.VersionString
|
||||||
import jp.juggler.util.getAttributeColor
|
import jp.juggler.util.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.jetbrains.anko.backgroundColor
|
import org.jetbrains.anko.backgroundColor
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
class SideMenuAdapter(
|
class SideMenuAdapter(
|
||||||
val activity : ActMain,
|
private val actMain : ActMain,
|
||||||
|
val handler : Handler,
|
||||||
navigationView : ViewGroup,
|
navigationView : ViewGroup,
|
||||||
private val drawer : DrawerLayout
|
private val drawer : DrawerLayout
|
||||||
) : BaseAdapter() {
|
) : BaseAdapter() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val itemTypeCount = ItemType.values().size
|
||||||
|
|
||||||
|
private var lastVersionView : WeakReference<TextView>? = null
|
||||||
|
|
||||||
|
private var versionRow = SpannableStringBuilder("")
|
||||||
|
private fun getVersionRow() = versionRow
|
||||||
|
|
||||||
|
private var releaseInfo : JsonObject? = null
|
||||||
|
|
||||||
|
private fun checkVersion(appContext : Context, handler : Handler) {
|
||||||
|
val currentVersion = try {
|
||||||
|
val pInfo = appContext.packageManager.getPackageInfo(appContext.packageName, 0)
|
||||||
|
pInfo.versionName
|
||||||
|
} catch(ex : PackageManager.NameNotFoundException) {
|
||||||
|
"??"
|
||||||
|
}
|
||||||
|
|
||||||
|
versionRow = SpannableStringBuilder().apply {
|
||||||
|
append(
|
||||||
|
appContext.getString(
|
||||||
|
R.string.app_name_with_version,
|
||||||
|
appContext.getString(R.string.app_name),
|
||||||
|
currentVersion
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun afterGet() {
|
||||||
|
|
||||||
|
versionRow = SpannableStringBuilder().apply {
|
||||||
|
|
||||||
|
append(
|
||||||
|
appContext.getString(
|
||||||
|
R.string.app_name_with_version,
|
||||||
|
appContext.getString(R.string.app_name),
|
||||||
|
currentVersion
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val newRelease = when(Pref.bpCheckBetaVersion(Pref.pref(appContext))){
|
||||||
|
false -> releaseInfo ?.jsonObject("stable")
|
||||||
|
else -> releaseInfo ?.jsonObject("beta")
|
||||||
|
}
|
||||||
|
|
||||||
|
val newVersion = newRelease
|
||||||
|
?.string("name")
|
||||||
|
?.replace("""version\s*""".toRegex(RegexOption.IGNORE_CASE), "")
|
||||||
|
?.trim()
|
||||||
|
|
||||||
|
if( newVersion?.isNotEmpty() != true || 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(
|
||||||
|
object:ClickableSpan() {
|
||||||
|
override fun onClick(widget : View) {
|
||||||
|
App1.openBrowser(widget.activity as ActMain, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateDrawState(ds : TextPaint) {
|
||||||
|
super.updateDrawState(ds)
|
||||||
|
ds.isUnderlineText = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
start, length,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
append("\n")
|
||||||
|
var start = length
|
||||||
|
append(
|
||||||
|
appContext.getString(
|
||||||
|
R.string.new_version_available,
|
||||||
|
newVersion
|
||||||
|
)
|
||||||
|
)
|
||||||
|
setSpan(
|
||||||
|
ForegroundColorSpan(
|
||||||
|
getAttributeColor(
|
||||||
|
appContext,
|
||||||
|
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(
|
||||||
|
object:ClickableSpan() {
|
||||||
|
override fun onClick(widget : View) {
|
||||||
|
App1.openBrowser(widget.activity as ActMain, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateDrawState(ds : TextPaint) {
|
||||||
|
super.updateDrawState(ds)
|
||||||
|
ds.isUnderlineText = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
start, length,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handler.post { lastVersionView?.get()?.let { it.text = versionRow } }
|
||||||
|
}
|
||||||
|
|
||||||
|
val lastUpdated = releaseInfo?.string("updated_at")?.let { TootStatus.parseTime(it) }
|
||||||
|
if(lastUpdated != null && System.currentTimeMillis() - lastUpdated < 86400000L) {
|
||||||
|
afterGet()
|
||||||
|
} else {
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
val json =
|
||||||
|
App1.getHttpCached("https://mastodon-msg.juggler.jp/appVersion/appVersion.json")
|
||||||
|
?.decodeUTF8()?.decodeJsonObject()
|
||||||
|
if(json != null) {
|
||||||
|
releaseInfo = json
|
||||||
|
afterGet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private enum class ItemType(val id : Int) {
|
private enum class ItemType(val id : Int) {
|
||||||
IT_NORMAL(0),
|
IT_NORMAL(0),
|
||||||
IT_GROUP_HEADER(1),
|
IT_GROUP_HEADER(1),
|
||||||
@ -35,10 +175,6 @@ class SideMenuAdapter(
|
|||||||
IT_VERSION(3)
|
IT_VERSION(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val itemTypeCount = ItemType.values().size
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Item(
|
private class Item(
|
||||||
val title : Int = 0,
|
val title : Int = 0,
|
||||||
val icon : Int = 0,
|
val icon : Int = 0,
|
||||||
@ -62,6 +198,9 @@ class SideMenuAdapter(
|
|||||||
|
|
||||||
private val list = arrayOf(
|
private val list = arrayOf(
|
||||||
|
|
||||||
|
Item(icon = R.drawable.ic_info, title = 1) ,
|
||||||
|
|
||||||
|
Item(),
|
||||||
Item(title = R.string.account),
|
Item(title = R.string.account),
|
||||||
|
|
||||||
Item(title = R.string.account_add, icon = R.drawable.ic_account_add) {
|
Item(title = R.string.account_add, icon = R.drawable.ic_account_add) {
|
||||||
@ -220,10 +359,6 @@ class SideMenuAdapter(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
Item(icon = R.drawable.ic_info, title = 1) {
|
|
||||||
App1.openCustomTab(this, "https://github.com/tateisu/SubwayTooter/releases")
|
|
||||||
},
|
|
||||||
|
|
||||||
Item(icon = R.drawable.ic_info, title = R.string.oss_license) {
|
Item(icon = R.drawable.ic_info, title = R.string.oss_license) {
|
||||||
startActivity(Intent(this, ActOSSLicense::class.java))
|
startActivity(Intent(this, ActOSSLicense::class.java))
|
||||||
},
|
},
|
||||||
@ -233,14 +368,7 @@ class SideMenuAdapter(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private val iconColor = getAttributeColor(activity, R.attr.colorTimeSmall)
|
private val iconColor = getAttributeColor(actMain, R.attr.colorTimeSmall)
|
||||||
|
|
||||||
private val currentVersion = try {
|
|
||||||
val pInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
|
|
||||||
pInfo.versionName
|
|
||||||
} catch(ex : PackageManager.NameNotFoundException) {
|
|
||||||
"??"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCount() : Int = list.size
|
override fun getCount() : Int = list.size
|
||||||
override fun getItem(position : Int) : Any = list[position]
|
override fun getItem(position : Int) : Any = list[position]
|
||||||
@ -254,7 +382,7 @@ class SideMenuAdapter(
|
|||||||
parent : ViewGroup?,
|
parent : ViewGroup?,
|
||||||
resId : Int
|
resId : Int
|
||||||
) : T =
|
) : T =
|
||||||
(view ?: activity.layoutInflater.inflate(resId, parent, false))
|
(view ?: actMain.layoutInflater.inflate(resId, parent, false))
|
||||||
as? T ?: error("invalid view type! ${T::class.java.simpleName}")
|
as? T ?: error("invalid view type! ${T::class.java.simpleName}")
|
||||||
|
|
||||||
override fun getView(position : Int, view : View?, parent : ViewGroup?) : View =
|
override fun getView(position : Int, view : View?, parent : ViewGroup?) : View =
|
||||||
@ -263,97 +391,67 @@ class SideMenuAdapter(
|
|||||||
ItemType.IT_DIVIDER ->
|
ItemType.IT_DIVIDER ->
|
||||||
viewOrInflate(view, parent, R.layout.lv_sidemenu_separator)
|
viewOrInflate(view, parent, R.layout.lv_sidemenu_separator)
|
||||||
ItemType.IT_GROUP_HEADER ->
|
ItemType.IT_GROUP_HEADER ->
|
||||||
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_group)
|
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_group).apply {
|
||||||
.apply {
|
text = actMain.getString(title)
|
||||||
text = activity.getString(title)
|
}
|
||||||
}
|
|
||||||
ItemType.IT_NORMAL ->
|
ItemType.IT_NORMAL ->
|
||||||
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item)
|
|
||||||
.apply {
|
|
||||||
isAllCaps = false
|
|
||||||
text = activity.getString(title)
|
|
||||||
val drawable = createColoredDrawable(activity, icon, iconColor, 1f)
|
|
||||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
|
||||||
drawable,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
|
|
||||||
setOnClickListener {
|
|
||||||
action(activity)
|
|
||||||
drawer.closeDrawer(GravityCompat.START)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ItemType.IT_VERSION ->
|
|
||||||
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item).apply {
|
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item).apply {
|
||||||
text = SpannableStringBuilder().apply {
|
|
||||||
val lastVersion = Pref.spVersionNameWhenReleaseNoteTap(activity.pref)
|
|
||||||
if(lastVersion.isNotEmpty() && lastVersion != currentVersion) {
|
|
||||||
append(
|
|
||||||
activity.getString(
|
|
||||||
R.string.release_notes_updated,
|
|
||||||
lastVersion,
|
|
||||||
currentVersion
|
|
||||||
)
|
|
||||||
)
|
|
||||||
setSpan(
|
|
||||||
ForegroundColorSpan(
|
|
||||||
getAttributeColor(
|
|
||||||
activity,
|
|
||||||
R.attr.colorRegexFilterError
|
|
||||||
)
|
|
||||||
),
|
|
||||||
0, length,
|
|
||||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
append(
|
|
||||||
activity.getString(
|
|
||||||
R.string.release_notes_latest,
|
|
||||||
currentVersion
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isAllCaps = false
|
isAllCaps = false
|
||||||
val drawable = createColoredDrawable(activity, icon, iconColor, 1f)
|
text = actMain.getString(title)
|
||||||
|
val drawable = createColoredDrawable(actMain, icon, iconColor, 1f)
|
||||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||||
drawable,
|
drawable,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
activity.pref.edit()
|
action(actMain)
|
||||||
.put(Pref.spVersionNameWhenReleaseNoteTap, currentVersion)
|
|
||||||
.apply()
|
|
||||||
notifyDataSetChanged()
|
|
||||||
action(activity)
|
|
||||||
drawer.closeDrawer(GravityCompat.START)
|
drawer.closeDrawer(GravityCompat.START)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ItemType.IT_VERSION ->
|
||||||
|
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item).apply {
|
||||||
|
lastVersionView = WeakReference(this)
|
||||||
|
movementMethod = LinkMovementMethod.getInstance();
|
||||||
|
textSize = 18f
|
||||||
|
isAllCaps = false
|
||||||
|
background= null
|
||||||
|
// val drawable = createColoredDrawable(actMain, icon, iconColor, 1f)
|
||||||
|
// setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||||
|
// drawable,
|
||||||
|
// null,
|
||||||
|
// null,
|
||||||
|
// null
|
||||||
|
// )
|
||||||
|
|
||||||
|
text = getVersionRow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
ListView(activity).apply {
|
checkVersion(actMain.applicationContext, handler)
|
||||||
|
|
||||||
|
ListView(actMain).apply {
|
||||||
adapter = this@SideMenuAdapter
|
adapter = this@SideMenuAdapter
|
||||||
layoutParams = FrameLayout.LayoutParams(
|
layoutParams = FrameLayout.LayoutParams(
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT
|
FrameLayout.LayoutParams.MATCH_PARENT
|
||||||
)
|
)
|
||||||
backgroundColor = getAttributeColor(activity, R.attr.colorWindowBackground)
|
backgroundColor = getAttributeColor(actMain, R.attr.colorWindowBackground)
|
||||||
selector = StateListDrawable()
|
selector = StateListDrawable()
|
||||||
divider = null
|
divider = null
|
||||||
dividerHeight = 0
|
dividerHeight = 0
|
||||||
|
|
||||||
val pad_tb = (activity.density * 12f + 0.5f).toInt()
|
val pad_tb = (actMain.density * 12f + 0.5f).toInt()
|
||||||
setPadding(0, pad_tb, 0, pad_tb)
|
setPadding(0, pad_tb, 0, pad_tb)
|
||||||
clipToPadding = false
|
clipToPadding = false
|
||||||
scrollBarStyle = ListView.SCROLLBARS_OUTSIDE_OVERLAY
|
scrollBarStyle = ListView.SCROLLBARS_OUTSIDE_OVERLAY
|
||||||
|
|
||||||
navigationView.addView(this)
|
navigationView.addView(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1032,4 +1032,9 @@
|
|||||||
<string name="personal_notes_of">%1$sに関する覚え書き</string>
|
<string name="personal_notes_of">%1$sに関する覚え書き</string>
|
||||||
<string name="custom_thumbnail">カスタムサムネイル</string>
|
<string name="custom_thumbnail">カスタムサムネイル</string>
|
||||||
<string name="close_emoji_picker_when_selected">絵文字を選択したら絵文字ピッカーを閉じる</string>
|
<string name="close_emoji_picker_when_selected">絵文字を選択したら絵文字ピッカーを閉じる</string>
|
||||||
|
<string name="new_version_available">新バージョンがあります %1$s</string>
|
||||||
|
<string name="app_name_with_version">%1$s %2$s</string>
|
||||||
|
<string name="release_note_with_assets">更新履歴 (AssetsセクションにAPKファイルがあります)</string>
|
||||||
|
<string name="release_note">更新履歴</string>
|
||||||
|
<string name="check_beta_release">ベータ版を確認する</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1039,4 +1039,9 @@
|
|||||||
<string name="personal_notes_of">Personal notes of %1$s</string>
|
<string name="personal_notes_of">Personal notes of %1$s</string>
|
||||||
<string name="custom_thumbnail">Custom thumbnail</string>
|
<string name="custom_thumbnail">Custom thumbnail</string>
|
||||||
<string name="close_emoji_picker_when_selected">Close emoji picker after selecting emoji</string>
|
<string name="close_emoji_picker_when_selected">Close emoji picker after selecting emoji</string>
|
||||||
|
<string name="new_version_available">New version available! %1$s</string>
|
||||||
|
<string name="app_name_with_version">%1$s %2$s</string>
|
||||||
|
<string name="release_note_with_assets">Release note (Please find the APK file in assets section.)</string>
|
||||||
|
<string name="release_note">Release note</string>
|
||||||
|
<string name="check_beta_release">Check beta release</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user