fix #129. add confirmation when quit language filter editor without save. fix export/import error when language filter is set.

This commit is contained in:
tateisu 2020-02-01 02:37:39 +09:00
parent 947fab0340
commit 74933a1491
9 changed files with 136 additions and 88 deletions

View File

@ -22,7 +22,7 @@ android {
minSdkVersion min_sdk_version
versionCode 402
versionName "4.0.2"
versionName "4.0.2x"
applicationId "jp.juggler.subwaytooter"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@ -5,6 +5,7 @@ import android.content.Intent
import android.net.Uri
import android.os.AsyncTask
import android.os.Bundle
import android.os.PersistableBundle
import android.os.Process
import android.text.Editable
import android.text.TextWatcher
@ -38,6 +39,7 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
internal val log = LogCategory("ActLanguageFilter")
internal const val EXTRA_COLUMN_INDEX = "column_index"
private const val STATE_LANGUAGE_LIST = "language_list"
fun open(activity : ActMain, idx : Int, request_code : Int) {
val intent = Intent(activity, ActLanguageFilter::class.java)
@ -59,6 +61,19 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
}
}
private fun equalsLanguageList(a : JsonObject?, b : JsonObject?) : Boolean {
fun JsonObject.encodeToString() : String {
val clone = this.toString().decodeJsonObject()
if(! clone.contains(TootStatus.LANGUAGE_CODE_DEFAULT)) {
clone[TootStatus.LANGUAGE_CODE_DEFAULT] = true
}
return clone.keys.sorted().joinToString(",") { "$it=${this[it]}" }
}
val a_sign = (a ?: JsonObject()).encodeToString()
val b_sign = (b ?: JsonObject()).encodeToString()
return a_sign == b_sign
}
}
private val languageNameMap by lazy {
@ -94,6 +109,7 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
put(TootStatus.LANGUAGE_CODE_DEFAULT, getString(R.string.language_code_default))
put(TootStatus.LANGUAGE_CODE_UNKNOWN, getString(R.string.language_code_unknown))
}
}
private fun getDesc(item : MyItem) : String {
@ -121,9 +137,39 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
column_index = intent.getIntExtra(EXTRA_COLUMN_INDEX, 0)
column = app_state.column_list[column_index]
if(savedInstanceState != null) {
try {
val sv = savedInstanceState.getString(STATE_LANGUAGE_LIST, null)
if(sv != null) {
val list = sv.decodeJsonObject()
load(list)
return
}
} catch(ex : Throwable) {
log.trace(ex)
}
}
load(column.language_filter)
}
override fun onSaveInstanceState(outState : Bundle, outPersistentState : PersistableBundle) {
super.onSaveInstanceState(outState, outPersistentState)
outState.putString(STATE_LANGUAGE_LIST, encodeLanguageList().toString())
}
override fun onBackPressed() {
if(! equalsLanguageList(column.language_filter, encodeLanguageList())) {
AlertDialog.Builder(this)
.setMessage(R.string.language_filter_quit_waring)
.setPositiveButton(R.string.ok) { _, _ -> finish() }
.setNegativeButton(R.string.cancel, null)
.show()
return
}
super.onBackPressed()
}
private fun initUI() {
setContentView(R.layout.act_language_filter)
App1.initEdgeToEdge(this)
@ -143,21 +189,30 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
listView.onItemClickListener = adapter
}
// UIのデータをJsonObjectにエンコード
private fun encodeLanguageList() = jsonObject {
for(item in languageList) {
put(item.code, item.allow)
}
}
private fun load(src : JsonObject?) {
loading_busy = true
try {
languageList.clear()
if(src != null) {
for(key in src.keys) {
languageList.add(MyItem(key, src.boolean(key) ?: true))
}
}
if(null == languageList.find { it.code == TootStatus.LANGUAGE_CODE_DEFAULT }) {
languageList.add(MyItem(TootStatus.LANGUAGE_CODE_DEFAULT, true))
}
languageList.sortWith(languageComparator)
adapter.notifyDataSetChanged()
} finally {
loading_busy = false
@ -165,11 +220,7 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
}
private fun save() {
column.language_filter = jsonObject {
for(item in languageList) {
put(item.code, item.allow)
}
}
column.language_filter = encodeLanguageList()
}
private inner class MyAdapter : BaseAdapter(), AdapterView.OnItemClickListener {

View File

@ -41,82 +41,76 @@ object AppDataExporter {
private const val KEY_HIGHLIGHT_WORD = "highlight_word"
@Throws(IOException::class, JsonException::class)
private fun writeJSONObject(writer : JsonWriter, src : JsonObject) {
private fun writeJsonValue(writer : JsonWriter, value:Any?) {
when(value) {
null -> writer.nullValue()
is String -> writer.value(value)
is Boolean -> writer.value(value)
is Number -> writer.value(value)
is EntityId -> writer.value(value.toString())
is JsonObject -> writeJsonObject(writer,value)
is JsonArray ->writeJsonArray(writer,value)
else -> throw RuntimeException("writeJsonValue: bad data type: $value")
}
}
@Throws(IOException::class, JsonException::class)
private fun writeJsonArray(writer : JsonWriter, src : JsonArray) {
writer.beginArray()
for( value in src) {
writeJsonValue(writer,value)
}
writer.endArray()
}
@Throws(IOException::class, JsonException::class)
private fun writeJsonObject(writer : JsonWriter, src : JsonObject) {
writer.beginObject()
val it = src.keys.iterator()
while(it.hasNext()) {
val k = it.next()
if(src.isNull(k)) {
writer.name(k)
writer.nullValue()
} else {
when(val o = src[k]) {
is String -> {
writer.name(k)
writer.value(o)
}
is Boolean -> {
writer.name(k)
writer.value(o)
}
is Number -> {
writer.name(k)
writer.value(o)
}
is EntityId -> {
writer.name(k)
writer.value(o.toString())
}
else -> throw RuntimeException(
String.format(
Locale.JAPAN,
"bad data type: JsonObject key =%s",
k
)
)
}
}
for( entry in src.entries){
writer.name(entry.key)
writeJsonValue(writer, entry.value)
}
writer.endObject()
}
@Throws(IOException::class, JsonException::class)
private fun readJsonObject(reader : JsonReader) : JsonObject {
val dst = JsonObject()
private fun readJsonValue(reader:JsonReader):Any?{
return when(val token = reader.peek()) {
JsonToken.NULL -> {
reader.nextNull()
null
}
JsonToken.STRING -> reader.nextString()
JsonToken.BOOLEAN -> reader.nextBoolean()
JsonToken.NUMBER -> reader.nextDouble()
JsonToken.BEGIN_ARRAY -> readJsonArray(reader)
JsonToken.BEGIN_OBJECT -> readJsonObject(reader)
else -> null
}
}
@Throws(IOException::class, JsonException::class)
private fun readJsonArray(reader:JsonReader):JsonArray{
val dst = JsonArray()
reader.beginArray()
while(reader.hasNext()) {
dst.add(readJsonValue(reader))
}
reader.endArray()
return dst
}
@Throws(IOException::class, JsonException::class)
private fun readJsonObject(reader:JsonReader):JsonObject{
val dst = JsonObject()
reader.beginObject()
while(reader.hasNext()) {
val name = reader.nextName()
when(val token = reader.peek()) {
JsonToken.NULL -> reader.nextNull()
JsonToken.STRING -> dst[name] = reader.nextString()
JsonToken.BOOLEAN -> dst[name] = reader.nextBoolean()
JsonToken.NUMBER -> dst[name] = reader.nextDouble()
else -> throw RuntimeException(
String.format(
Locale.JAPAN,
"bad data type: %s key =%s",
token,
name
)
)
}
val value = readJsonValue(reader)
dst[name]=value
}
reader.endObject()
return dst
}
@ -329,7 +323,7 @@ object AppDataExporter {
for(column in app_state.column_list) {
val dst = JsonObject()
column.encodeJSON(dst, 0)
writeJSONObject(writer, dst)
writeJsonObject(writer, dst)
}
writer.endArray()
}

View File

@ -1,10 +1,8 @@
package jp.juggler.subwaytooter.action
import android.content.*
import android.content.pm.PackageManager
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.net.Uri
import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.Pref

View File

@ -1054,14 +1054,15 @@ class TootStatus(parser : TootParser, src : JsonObject) : TimelineItem() {
}
}
return formatDate(t,date_format,omitZeroSecond = false)
return formatDate(t,date_format,omitZeroSecond = false,omitYear = false)
}
// 告知の開始/終了日付
private fun formatDate(
t : Long,
format:SimpleDateFormat ,
omitZeroSecond:Boolean
omitZeroSecond:Boolean,
omitYear:Boolean
) : String {
var dateTarget = format.format(Date(t))
@ -1071,10 +1072,15 @@ class TootStatus(parser : TootParser, src : JsonObject) : TimelineItem() {
}
// 年の部分が現在と同じなら省略する
val dateNow = format.format(Date())
val delm = dateNow.indexOf('-')
if(delm!=-1 && dateNow.substring(0,delm+1) == dateTarget.substring(0,delm+1)){
dateTarget = dateTarget.substring(delm+1)
if(omitYear) {
val dateNow = format.format(Date())
val delm = dateNow.indexOf('-')
if(delm != - 1 && dateNow.substring(0, delm + 1) == dateTarget.substring(
0,
delm + 1
)) {
dateTarget = dateTarget.substring(delm + 1)
}
}
return dateTarget
@ -1083,13 +1089,13 @@ class TootStatus(parser : TootParser, src : JsonObject) : TimelineItem() {
fun formatTimeRange(start : Long, end : Long, allDay : Boolean):Pair<String,String>{
val strStart = when {
start <= 0L -> ""
allDay-> formatDate(start,date_format2,omitZeroSecond = false)
else -> formatDate(start, date_format,omitZeroSecond = true)
allDay-> formatDate(start,date_format2,omitZeroSecond = false,omitYear = true)
else -> formatDate(start, date_format,omitZeroSecond = true,omitYear = true)
}
val strEnd = when {
end <= 0L -> ""
allDay-> formatDate(end,date_format2,omitZeroSecond = false)
else -> formatDate(end, date_format,omitZeroSecond = true)
allDay-> formatDate(end,date_format2,omitZeroSecond = false,omitYear = true)
else -> formatDate(end, date_format,omitZeroSecond = true,omitYear = true)
}
// 終了日は先頭と同じ部分を省略する
var skip = 0

View File

@ -4,8 +4,6 @@ import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
@ -13,7 +11,6 @@ import android.view.ViewGroup
import android.view.WindowManager
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.action.CustomShare
import jp.juggler.subwaytooter.action.cn

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp"
android:gravity="center_vertical"

View File

@ -1011,5 +1011,6 @@
<string name="emojione_shortcode_support_desc">サーバが古い間に作られた投稿は(サーバがアップデートした後でも)EmojiOneのショートコードを含むかもしれません。</string>
<string name="copy_to_clipboard">クリップボードにコピー</string>
<string name="copied_to_clipboard">クリップボードにコピーしました</string>
<string name="language_filter_quit_waring">Language filter is not saved. exit anyway?</string>
</resources>

View File

@ -1006,4 +1006,5 @@
<string name="emojione_shortcode_support_desc">The toots made by old Mastodon may contain emojione\'s shortcode even if the server have been updated.</string>
<string name="copy_to_clipboard">Copy to clipboard</string>
<string name="copied_to_clipboard">Copied to clipboard.</string>
<string name="language_filter_quit_waring">Language filter is not saved. exit anyway?</string>
</resources>