add language filter in column setting

This commit is contained in:
tateisu 2019-12-13 23:48:38 +09:00
parent bf2882e1c7
commit f6294eba25
14 changed files with 749 additions and 662 deletions

View File

@ -64,6 +64,7 @@
<w>kenglxn</w> <w>kenglxn</w>
<w>kotlinx</w> <w>kotlinx</w>
<w>lateinit</w> <w>lateinit</w>
<w>latn</w>
<w>lparams</w> <w>lparams</w>
<w>magick</w> <w>magick</w>
<w>mailto</w> <w>mailto</w>

View File

@ -234,6 +234,12 @@
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
/> />
<activity
android:name=".ActLanguageFilter"
android:label="@string/language_filter"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
/>
<activity <activity
android:name=".ActNickname" android:name=".ActNickname"
android:label="@string/nickname_and_color_and_notification_sound" android:label="@string/nickname_and_color_and_notification_sound"

View File

@ -0,0 +1,490 @@
package jp.juggler.subwaytooter
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.os.AsyncTask
import android.os.Bundle
import android.os.Process
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.dialog.ActionsDialog
import jp.juggler.subwaytooter.dialog.ProgressDialogEx
import jp.juggler.util.*
import org.apache.commons.io.IOUtils
import org.jetbrains.anko.textColor
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.*
import kotlin.collections.ArrayList
class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
private class MyItem(
val code : String,
var allow : Boolean
)
companion object {
internal val log = LogCategory("ActLanguageFilter")
internal const val EXTRA_COLUMN_INDEX = "column_index"
fun open(activity : ActMain, idx : Int, request_code : Int) {
val intent = Intent(activity, ActLanguageFilter::class.java)
intent.putExtra(EXTRA_COLUMN_INDEX, idx)
activity.startActivityForResult(intent, request_code)
}
// 他の設定子画面と重複しない値にすること
private const val REQUEST_CODE_OTHER = 0
private const val REQUEST_CODE_IMPORT = 1
private val languageComparator = Comparator<MyItem> { a, b ->
when {
a.code == TootStatus.LANGUAGE_CODE_DEFAULT -> - 1
b.code == TootStatus.LANGUAGE_CODE_DEFAULT -> 1
a.code == TootStatus.LANGUAGE_CODE_UNKNOWN -> - 1
b.code == TootStatus.LANGUAGE_CODE_UNKNOWN -> 1
else -> a.code.compareTo(b.code)
}
}
}
private val languageNameMap by lazy {
HashMap<String, String>().apply {
// from https://github.com/google/cld3/blob/master/src/task_context_params.cc#L43
val languageNamesCld3 = arrayOf(
"eo", "co", "eu", "ta", "de", "mt", "ps", "te", "su", "uz", "zh-Latn", "ne",
"nl", "sw", "sq", "hmn", "ja", "no", "mn", "so", "ko", "kk", "sl", "ig",
"mr", "th", "zu", "ml", "hr", "bs", "lo", "sd", "cy", "hy", "uk", "pt",
"lv", "iw", "cs", "vi", "jv", "be", "km", "mk", "tr", "fy", "am", "zh",
"da", "sv", "fi", "ht", "af", "la", "id", "fil", "sm", "ca", "el", "ka",
"sr", "it", "sk", "ru", "ru-Latn", "bg", "ny", "fa", "haw", "gl", "et",
"ms", "gd", "bg-Latn", "ha", "is", "ur", "mi", "hi", "bn", "hi-Latn", "fr",
"yi", "hu", "xh", "my", "tg", "ro", "ar", "lb", "el-Latn", "st", "ceb",
"kn", "az", "si", "ky", "mg", "en", "gu", "es", "pl", "ja-Latn", "ga", "lt",
"sn", "yo", "pa", "ku"
)
for(src1 in languageNamesCld3) {
val src2 = src1.replace("-Latn", "")
val isLatn = src2 != src1
val locale = Locale(src2)
log.w("languageNameMap $src1 ${locale.language} ${locale.country} ${locale.displayName}")
put(
src1, if(isLatn) {
"${locale.displayName}(Latn)"
} else {
locale.displayName
}
)
}
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 {
val code = item.code
return languageNameMap[code] ?: getString(R.string.custom)
}
private var column_index : Int = 0
internal lateinit var column : Column
internal lateinit var app_state : AppState
internal var density : Float = 0f
private lateinit var listView : ListView
private lateinit var adapter : MyAdapter
private val languageList = ArrayList<MyItem>()
private var loading_busy : Boolean = false
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
App1.setActivityTheme(this)
initUI()
app_state = App1.getAppState(this)
density = app_state.density
column_index = intent.getIntExtra(EXTRA_COLUMN_INDEX, 0)
column = app_state.column_list[column_index]
load(column.language_filter ?: JSONObject())
}
private fun initUI() {
setContentView(R.layout.act_language_filter)
App1.initEdgeToEdge(this)
Styler.fixHorizontalPadding(findViewById(R.id.llContent))
for(id in intArrayOf(
R.id.btnAdd,
R.id.btnSave,
R.id.btnMore
)) {
findViewById<View>(id)?.setOnClickListener(this)
}
listView = findViewById(R.id.listView)
adapter = MyAdapter()
listView.adapter = adapter
listView.onItemClickListener = adapter
}
private fun load(src : JSONObject) {
loading_busy = true
try {
languageList.clear()
for(key in src.keys()) {
languageList.add(MyItem(key, src.parseBoolean(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
}
}
private fun save() {
val dst = JSONObject()
for(item in languageList) {
dst.put(item.code, item.allow)
}
column.language_filter = dst
}
private inner class MyAdapter : BaseAdapter(), AdapterView.OnItemClickListener {
override fun getCount() : Int = languageList.size
override fun getItemId(idx : Int) : Long = 0L
override fun getItem(idx : Int) : Any = languageList[idx]
override fun getView(idx : Int, viewArg : View?, parent : ViewGroup?) : View {
val tv = (viewArg ?: layoutInflater.inflate(
R.layout.lv_language_filter,
parent,
false
)) as TextView
val item = languageList[idx]
tv.text = String.format(
"%s %s : %s",
item.code,
getDesc(item),
getString(if(item.allow) R.string.language_show else R.string.language_hide)
)
tv.textColor = getAttributeColor(
this@ActLanguageFilter, when(item.allow) {
true -> R.attr.colorContentText
false -> R.attr.colorRegexFilterError
}
)
return tv
}
override fun onItemClick(parent : AdapterView<*>?, viewArg : View?, idx : Int, id : Long) {
if(idx in languageList.indices) edit(languageList[idx])
}
}
override fun onClick(v : View) {
when(v.id) {
R.id.btnSave -> {
save()
val data = Intent()
data.putExtra(EXTRA_COLUMN_INDEX, column_index)
setResult(RESULT_OK, data)
finish()
}
R.id.btnAdd -> edit(null)
R.id.btnMore -> {
ActionsDialog()
.addAction(getString(R.string.clear_all)) {
languageList.clear()
languageList.add(MyItem(TootStatus.LANGUAGE_CODE_DEFAULT, true))
adapter.notifyDataSetChanged()
}
.addAction(getString(R.string.export)) { export() }
.addAction(getString(R.string.import_)) { import() }
.show(this)
}
}
}
private fun edit(myItem : MyItem?) =
DlgLanguageFilter.open(this, myItem, object : DlgLanguageFilter.Callback {
override fun onOK(code : String, allow : Boolean) {
val it = languageList.iterator()
while(it.hasNext()) {
val item = it.next()
if(item.code == code) {
item.allow = allow
adapter.notifyDataSetChanged()
return
}
}
languageList.add(MyItem(code, allow))
languageList.sortWith(languageComparator)
adapter.notifyDataSetChanged()
return
}
override fun onDelete(code : String) {
val it = languageList.iterator()
while(it.hasNext()) {
val item = it.next()
if(item.code == code) it.remove()
}
adapter.notifyDataSetChanged()
}
})
private object DlgLanguageFilter {
interface Callback {
fun onOK(code : String, allow : Boolean)
fun onDelete(code : String)
}
@SuppressLint("InflateParams")
fun open(activity : ActLanguageFilter, item : MyItem?, callback : Callback) {
val view = activity.layoutInflater.inflate(R.layout.dlg_language_filter, null, false)
val etLanguage : EditText = view.findViewById(R.id.etLanguage)
val btnPresets : ImageButton = view.findViewById(R.id.btnPresets)
val tvLanguage : TextView = view.findViewById(R.id.tvLanguage)
val rbShow : RadioButton = view.findViewById(R.id.rbShow)
val rbHide : RadioButton = view.findViewById(R.id.rbHide)
when(item?.allow ?: true) {
true -> rbShow.isChecked = true
else -> rbHide.isChecked = true
}
fun updateDesc() {
val code = etLanguage.text.toString().trim()
val desc = activity.languageNameMap[code] ?: activity.getString(R.string.custom)
tvLanguage.text = desc
}
val languageList =
activity.languageNameMap.map { MyItem(it.key, true) }.sortedWith(languageComparator)
btnPresets.setOnClickListener {
val ad = ActionsDialog()
for(a in languageList) {
ad.addAction("${a.code} ${activity.getDesc(a)}") {
etLanguage.setText(a.code)
updateDesc()
}
}
ad.show(activity, activity.getString(R.string.presets))
}
etLanguage.setText(item?.code ?: "")
updateDesc()
etLanguage.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0 : Editable?) {
updateDesc()
}
override fun beforeTextChanged(p0 : CharSequence?, p1 : Int, p2 : Int, p3 : Int) {
}
override fun onTextChanged(p0 : CharSequence?, p1 : Int, p2 : Int, p3 : Int) {
}
})
if(item != null) {
etLanguage.isEnabled = false
btnPresets.isEnabled = false
btnPresets.setEnabledColor(activity,R.drawable.ic_edit, getAttributeColor(activity,R.attr.colorVectorDrawable),false)
}
val builder = AlertDialog.Builder(activity)
.setView(view)
.setCancelable(true)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok) { _, _ ->
callback.onOK(etLanguage.text.toString().trim(), rbShow.isChecked)
}
if(item != null && item.code != TootStatus.LANGUAGE_CODE_DEFAULT) {
builder.setNeutralButton(R.string.delete) { _, _ ->
callback.onDelete(etLanguage.text.toString().trim())
}
}
builder.show()
}
}
private fun export() {
val progress = ProgressDialogEx(this)
val data = JSONObject().apply {
for(item in languageList) {
put(item.code, item.allow)
}
}
.toString()
.encodeUTF8()
val task = @SuppressLint("StaticFieldLeak")
object : AsyncTask<Void, String, File?>() {
override fun doInBackground(vararg params : Void) : File? {
try {
val cache_dir = cacheDir
cache_dir.mkdir()
val file = File(
cache_dir,
"SubwayTooter-language-filter.${Process.myPid()}.${Process.myTid()}.json"
)
FileOutputStream(file).use { it.write(data) }
return file
} catch(ex : Throwable) {
log.trace(ex)
showToast(
this@ActLanguageFilter,
ex,
"can't save filter data to temporary file."
)
}
return null
}
override fun onCancelled(result : File?) {
onPostExecute(result)
}
override fun onPostExecute(result : File?) {
progress.dismissSafe()
if(isCancelled || result == null) {
// cancelled.
return
}
try {
val uri = FileProvider.getUriForFile(
this@ActLanguageFilter,
App1.FILE_PROVIDER_AUTHORITY,
result
)
val intent = Intent(Intent.ACTION_SEND)
intent.type = contentResolver.getType(uri)
intent.putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter language filter data")
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivityForResult(intent, REQUEST_CODE_OTHER)
} catch(ex : Throwable) {
log.trace(ex)
showToast(this@ActLanguageFilter, ex, "export failed.")
}
}
}
progress.isIndeterminateEx = true
progress.setCancelable(true)
progress.setOnCancelListener { task.cancel(true) }
progress.show()
task.executeOnExecutor(App1.task_executor)
}
private fun import() {
try {
val intent = intentOpenDocument("*/*")
startActivityForResult(intent, REQUEST_CODE_IMPORT)
} catch(ex : Throwable) {
showToast(this, ex, "import failed.")
}
}
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
if(resultCode == RESULT_OK && data != null && requestCode == REQUEST_CODE_IMPORT) {
data.handleGetContentResult(contentResolver).firstOrNull()?.uri?.let {
import2(it)
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun import2(uri : Uri) {
val type = contentResolver.getType(uri)
log.d("import2 type=%s", type)
val progress = ProgressDialogEx(this)
val task = @SuppressLint("StaticFieldLeak")
object : AsyncTask<Void, String, JSONObject?>() {
override fun doInBackground(vararg params : Void) : JSONObject? {
try {
val source = contentResolver.openInputStream(uri)
if(source == null) {
showToast(this@ActLanguageFilter, true, "openInputStream failed.")
return null
}
return source.use { inStream ->
val bao = ByteArrayOutputStream()
IOUtils.copy(inStream, bao)
JSONObject(bao.toByteArray().decodeUTF8())
}
} catch(ex : Throwable) {
log.trace(ex)
showToast(this@ActLanguageFilter, ex, "can't load filter data.")
return null
}
}
override fun onCancelled(result : JSONObject?) {
onPostExecute(result)
}
override fun onPostExecute(result : JSONObject?) {
progress.dismissSafe()
// cancelled.
if(isCancelled || result == null) return
load(result)
}
}
progress.isIndeterminateEx = true
progress.setCancelable(true)
progress.setOnCancelListener { task.cancel(true) }
progress.show()
task.executeOnExecutor(App1.task_executor)
}
}

View File

@ -91,6 +91,7 @@ class ActMain : AppCompatActivity()
const val REQUEST_CODE_COLUMN_COLOR = 6 const val REQUEST_CODE_COLUMN_COLOR = 6
const val REQUEST_CODE_APP_SETTING = 7 const val REQUEST_CODE_APP_SETTING = 7
const val REQUEST_CODE_TEXT = 8 const val REQUEST_CODE_TEXT = 8
const val REQUEST_CODE_LANGUAGE_FILTER = 9
const val COLUMN_WIDTH_MIN_DP = 300 const val COLUMN_WIDTH_MIN_DP = 300
@ -1018,7 +1019,7 @@ class ActMain : AppCompatActivity()
REQUEST_CODE_COLUMN_COLOR -> if(data != null) { REQUEST_CODE_COLUMN_COLOR -> if(data != null) {
app_state.saveColumnList() app_state.saveColumnList()
val idx = data.getIntExtra(ActColumnCustomize.EXTRA_COLUMN_INDEX, 0) val idx = data.getIntExtra(ActColumnCustomize.EXTRA_COLUMN_INDEX, 0)
if(idx >= 0 && idx < app_state.column_list.size) { if(idx in app_state.column_list.indices ) {
app_state.column_list[idx].fireColumnColor() app_state.column_list[idx].fireColumnColor()
app_state.column_list[idx].fireShowContent( app_state.column_list[idx].fireShowContent(
reason = "ActMain column color changed", reason = "ActMain column color changed",
@ -1027,6 +1028,14 @@ class ActMain : AppCompatActivity()
} }
updateColumnStrip() updateColumnStrip()
} }
REQUEST_CODE_LANGUAGE_FILTER -> if(data != null) {
app_state.saveColumnList()
val idx = data.getIntExtra(ActLanguageFilter.EXTRA_COLUMN_INDEX, 0)
if(idx in app_state.column_list.indices ) {
app_state.column_list[idx].onLanguageFilterChanged()
}
}
} }
} }

View File

@ -162,6 +162,7 @@ class Column(
private const val KEY_QUICK_FILTER = "quickFilter" private const val KEY_QUICK_FILTER = "quickFilter"
private const val KEY_REGEX_TEXT = "regex_text" private const val KEY_REGEX_TEXT = "regex_text"
private const val KEY_LANGUAGE_FILTER = "language_filter"
private const val KEY_HEADER_BACKGROUND_COLOR = "header_background_color" private const val KEY_HEADER_BACKGROUND_COLOR = "header_background_color"
private const val KEY_HEADER_TEXT_COLOR = "header_text_color" private const val KEY_HEADER_TEXT_COLOR = "header_text_color"
@ -487,6 +488,8 @@ class Column(
internal var hashtag_none : String = "" internal var hashtag_none : String = ""
internal var hashtag_acct : String = "" internal var hashtag_acct : String = ""
internal var language_filter : JSONObject? = null
// プロフカラムでのアカウント情報 // プロフカラムでのアカウント情報
@Volatile @Volatile
internal var who_account : TootAccountRef? = null internal var who_account : TootAccountRef? = null
@ -552,6 +555,7 @@ class Column(
|| dont_show_reply || dont_show_reply
|| dont_show_reaction || dont_show_reaction
|| dont_show_vote || dont_show_vote
|| (language_filter?.length()?:0) >0
) )
@Volatile @Volatile
@ -705,6 +709,7 @@ class Column(
last_viewing_item_id = EntityId.from(src, KEY_LAST_VIEWING_ITEM) last_viewing_item_id = EntityId.from(src, KEY_LAST_VIEWING_ITEM)
regex_text = src.parseString(KEY_REGEX_TEXT) ?: "" regex_text = src.parseString(KEY_REGEX_TEXT) ?: ""
language_filter = src.optJSONObject(KEY_LANGUAGE_FILTER)
header_bg_color = src.optInt(KEY_HEADER_BACKGROUND_COLOR) header_bg_color = src.optInt(KEY_HEADER_BACKGROUND_COLOR)
header_fg_color = src.optInt(KEY_HEADER_TEXT_COLOR) header_fg_color = src.optInt(KEY_HEADER_TEXT_COLOR)
@ -807,6 +812,9 @@ class Column(
dst.put(KEY_REGEX_TEXT, regex_text) dst.put(KEY_REGEX_TEXT, regex_text)
val ov = language_filter
if( ov != null) dst.put(KEY_LANGUAGE_FILTER,ov)
dst.put(KEY_HEADER_BACKGROUND_COLOR, header_bg_color) dst.put(KEY_HEADER_BACKGROUND_COLOR, header_bg_color)
dst.put(KEY_HEADER_TEXT_COLOR, header_fg_color) dst.put(KEY_HEADER_TEXT_COLOR, header_fg_color)
dst.put(KEY_COLUMN_BACKGROUND_COLOR, column_bg_color) dst.put(KEY_COLUMN_BACKGROUND_COLOR, column_bg_color)
@ -1314,6 +1322,10 @@ class Column(
} }
fun onLanguageFilterChanged() {
// TODO
}
internal fun addColumnViewHolder(cvh : ColumnViewHolder) { internal fun addColumnViewHolder(cvh : ColumnViewHolder) {
// 現在のリストにあるなら削除する // 現在のリストにあるなら削除する
@ -1451,28 +1463,37 @@ class Column(
if(isFilteredByAttachment(status)) return true if(isFilteredByAttachment(status)) return true
val reblog = status.reblog
if(dont_show_boost) { if(dont_show_boost) {
if(status.reblog != null) return true if(reblog != null) return true
} }
if(dont_show_reply) { if(dont_show_reply) {
if(status.in_reply_to_id != null) return true if(status.in_reply_to_id != null) return true
if(status.reblog?.in_reply_to_id != null) return true if(reblog?.in_reply_to_id != null) return true
} }
if(dont_show_normal_toot) { if(dont_show_normal_toot) {
if(status.in_reply_to_id == null && status.reblog == null) return true if(status.in_reply_to_id == null && reblog == null) return true
} }
if(column_regex_filter(status.decoded_content)) return true if(column_regex_filter(status.decoded_content)) return true
if(column_regex_filter(status.reblog?.decoded_content)) return true if(column_regex_filter(reblog?.decoded_content)) return true
if(column_regex_filter(status.decoded_spoiler_text)) return true if(column_regex_filter(status.decoded_spoiler_text)) return true
if(column_regex_filter(status.reblog?.decoded_spoiler_text)) return true if(column_regex_filter(reblog?.decoded_spoiler_text)) return true
val languageFilter = language_filter
if(languageFilter != null ){
val bShow = languageFilter.parseBoolean(status.language ?: reblog?.language ?:TootStatus.LANGUAGE_CODE_UNKNOWN)
?: languageFilter.parseBoolean(TootStatus.LANGUAGE_CODE_DEFAULT)
?: true
if(!bShow) return true
}
if(access_info.isPseudo) { if(access_info.isPseudo) {
var r = UserRelation.loadPseudo(access_info.getFullAcct(status.account)) var r = UserRelation.loadPseudo(access_info.getFullAcct(status.account))
if(r.muting || r.blocking) return true if(r.muting || r.blocking) return true
val reblog = status.reblog
if(reblog != null) { if(reblog != null) {
r = UserRelation.loadPseudo(access_info.getFullAcct(reblog.account)) r = UserRelation.loadPseudo(access_info.getFullAcct(reblog.account))
if(r.muting || r.blocking) return true if(r.muting || r.blocking) return true
@ -1535,7 +1556,16 @@ class Column(
// just update _filtered flag for reversible filter // just update _filtered flag for reversible filter
status.updateKeywordFilteredFlag(access_info, filterTrees) status.updateKeywordFilteredFlag(access_info, filterTrees)
} }
if( status != null){
val languageFilter = language_filter
if(languageFilter != null ){
val bShow = languageFilter.parseBoolean(status.language ?: status.reblog?.language ?:TootStatus.LANGUAGE_CODE_UNKNOWN)
?: languageFilter.parseBoolean(TootStatus.LANGUAGE_CODE_DEFAULT)
?: true
if(!bShow) return true
}
}
if(status?.checkMuted() == true) { if(status?.checkMuted() == true) {
log.d("isFiltered: status muted by in-app muted words.") log.d("isFiltered: status muted by in-app muted words.")
return true return true
@ -3002,6 +3032,7 @@ class Column(
getHeaderNameColor() getHeaderNameColor()
) )
} }
// fun findListIndexByTimelineId(orderId : EntityId) : Int? { // fun findListIndexByTimelineId(orderId : EntityId) : Int? {
// list_data.forEachIndexed { i, v -> // list_data.forEachIndexed { i, v ->

View File

@ -113,6 +113,7 @@ class ColumnViewHolder(
private lateinit var llRegexFilter : View private lateinit var llRegexFilter : View
private lateinit var btnDeleteNotification : Button private lateinit var btnDeleteNotification : Button
private lateinit var btnColor : Button private lateinit var btnColor : Button
private lateinit var btnLanguageFilter : Button
private lateinit var svQuickFilter : HorizontalScrollView private lateinit var svQuickFilter : HorizontalScrollView
private lateinit var btnQuickFilterAll : Button private lateinit var btnQuickFilterAll : Button
@ -309,6 +310,7 @@ class ColumnViewHolder(
btnDeleteNotification.setOnClickListener(this) btnDeleteNotification.setOnClickListener(this)
btnColor.setOnClickListener(this) btnColor.setOnClickListener(this)
btnLanguageFilter.setOnClickListener(this)
refreshLayout.setOnRefreshListener(this) refreshLayout.setOnRefreshListener(this)
refreshLayout.setDistanceToTriggerSync((0.5f + 20f * activity.density).toInt()) refreshLayout.setDistanceToTriggerSync((0.5f + 20f * activity.density).toInt())
@ -586,6 +588,7 @@ class ColumnViewHolder(
vg(cbWithHighlight, bAllowFilter) vg(cbWithHighlight, bAllowFilter)
vg(etRegexFilter, bAllowFilter) vg(etRegexFilter, bAllowFilter)
vg(llRegexFilter, bAllowFilter) vg(llRegexFilter, bAllowFilter)
vg(btnLanguageFilter,bAllowFilter)
vg(cbDontShowBoost, column.canFilterBoost()) vg(cbDontShowBoost, column.canFilterBoost())
vg(cbDontShowReply, column.canFilterReply()) vg(cbDontShowReply, column.canFilterReply())
@ -1030,6 +1033,11 @@ class ColumnViewHolder(
ActColumnCustomize.open(activity, idx, ActMain.REQUEST_CODE_COLUMN_COLOR) ActColumnCustomize.open(activity, idx, ActMain.REQUEST_CODE_COLUMN_COLOR)
} }
btnLanguageFilter ->{
val idx = activity.app_state.column_list.indexOf(column)
ActLanguageFilter.open(activity, idx, ActMain.REQUEST_CODE_LANGUAGE_FILTER)
}
btnListAdd -> { btnListAdd -> {
val tv = etListName.text.toString().trim { it <= ' ' } val tv = etListName.text.toString().trim { it <= ' ' }
if(tv.isEmpty()) { if(tv.isEmpty()) {
@ -1871,6 +1879,12 @@ class ColumnViewHolder(
isAllCaps = false isAllCaps = false
text = context.getString(R.string.color_and_background) text = context.getString(R.string.color_and_background)
}.lparams(matchParent, wrapContent) }.lparams(matchParent, wrapContent)
btnLanguageFilter = button {
isAllCaps = false
text = context.getString(R.string.language_filter)
}.lparams(matchParent, wrapContent)
} }
} // end of column setting scroll view } // end of column setting scroll view

View File

@ -93,7 +93,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
val sensitive : Boolean val sensitive : Boolean
// The detected language for the status, if detected // The detected language for the status, if detected
private val language : String? val language : String?
//If not empty, warning text that should be displayed before the actual content //If not empty, warning text that should be displayed before the actual content
// アプリ内部では空文字列はCWなしとして扱う // アプリ内部では空文字列はCWなしとして扱う
@ -485,7 +485,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
parseItem(::TootApplication, parser, src.optJSONObject("application"), log) parseItem(::TootApplication, parser, src.optJSONObject("application"), log)
this.pinned = parser.pinned || src.optBoolean("pinned") this.pinned = parser.pinned || src.optBoolean("pinned")
this.muted = src.optBoolean("muted") this.muted = src.optBoolean("muted")
this.language = src.parseString("language") this.language = src.parseString("language")?.notEmpty()
this.decoded_mentions = HTMLDecoder.decodeMentions( this.decoded_mentions = HTMLDecoder.decodeMentions(
parser.linkHelper, parser.linkHelper,
this.mentions, this.mentions,
@ -815,6 +815,9 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
@Volatile @Volatile
internal var muted_word : WordTrieTree? = null internal var muted_word : WordTrieTree? = null
const val LANGUAGE_CODE_UNKNOWN="unknown"
const val LANGUAGE_CODE_DEFAULT="default"
val EMPTY_SPANNABLE = SpannableString("") val EMPTY_SPANNABLE = SpannableString("")
// OStatus // OStatus

View File

@ -2,13 +2,11 @@ package jp.juggler.subwaytooter.dialog
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import androidx.appcompat.app.AlertDialog
import android.view.View import android.view.View
import android.widget.CheckBox import android.widget.CheckBox
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.util.EmptyCallback
object DlgConfirm { object DlgConfirm {

View File

@ -0,0 +1,69 @@
<?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:id="@+id/llContent"
android:orientation="vertical">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fadeScrollbars="false"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:background="?attr/colorStatusButtonsPopupBg"
>
<ImageButton
android:id="@+id/btnAdd"
android:src="@drawable/ic_add"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="48dp"
android:contentDescription="@string/add"
android:textAllCaps="false"
android:elevation="3dp"
/>
<Button
android:id="@+id/btnSave"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="48dp"
android:text="@string/save"
android:textAllCaps="false"
android:elevation="3dp"
/>
<ImageButton
android:id="@+id/btnMore"
android:src="@drawable/ic_more"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/more"
android:elevation="3dp"
/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="@string/language_filter_description"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:paddingBottom="6dp"
/>
</LinearLayout>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:text="@string/language"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
>
<EditText
android:id="@+id/etLanguage"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="@string/language_code_hint"
/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="3dp"
android:src="@drawable/ic_edit"
android:id="@+id/btnPresets"
android:contentDescription="@string/presets"
/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:id="@+id/tvLanguage"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:text="@string/show_hide"
/>
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:orientation="horizontal"
>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/rbShow"
android:text="@string/language_show"
/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:id="@+id/rbHide"
android:text="@string/language_hide"
/>
</RadioGroup>
</LinearLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:id="@android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:background="@drawable/btn_bg_transparent"
/>

View File

@ -1,649 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="Autofill">
<!--
<LinearLayout
android:id="@+id/llColumnHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_column_header"
android:orientation="vertical"
android:paddingStart="12dp"
android:paddingTop="3dp"
android:paddingEnd="12dp"
android:paddingBottom="3dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tvColumnContext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:textColor="?attr/colorColumnHeaderAcct"
android:textSize="12sp"
tools:text="tvColumnContext"
/>
<TextView
android:id="@+id/tvColumnStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:gravity="end"
android:textColor="?attr/colorColumnHeaderPageNumber"
android:textSize="12sp"
tools:text="RS"
/>
<TextView
android:id="@+id/tvColumnIndex"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:gravity="end"
android:textColor="?attr/colorColumnHeaderPageNumber"
android:textSize="12sp"
tools:text="col 6/12"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:baselineAligned="false"
>
<ImageView
android:id="@+id/ivColumnIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="4dp"
android:importantForAccessibility="no"
android:scaleType="fitCenter"
/>
<TextView
android:id="@+id/tvColumnName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="tvColumnName"
/>
<ImageButton
android:id="@+id/btnColumnSetting"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="2dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/setting"
android:src="@drawable/ic_tune"
android:padding="8dp"
android:scaleType="fitCenter"
/>
<ImageButton
android:id="@+id/btnColumnReload"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="2dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/reload"
android:src="@drawable/ic_refresh"
android:padding="8dp"
android:scaleType="fitCenter"
/>
<ImageButton
android:id="@+id/btnColumnClose"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="2dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/close_column"
android:src="@drawable/ic_close"
android:padding="8dp"
android:scaleType="fitCenter"
/>
</LinearLayout>
</LinearLayout>
<jp.juggler.subwaytooter.view.MaxHeightScrollView
android:id="@+id/llColumnSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadeScrollbars="false"
app:maxHeight="240dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorColumnSettingBackground"
android:orientation="vertical"
android:paddingStart="12dp"
android:paddingTop="3dp"
android:paddingEnd="12dp"
android:paddingBottom="3dp"
android:id="@+id/llColumnSettingInside"
>
<LinearLayout
android:id="@+id/llHashtagExtra"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@+id/etHashtagExtraAny"
android:text="@string/hashtag_extra_any"
android:textColor="?attr/colorColumnHeaderPageNumber"
/>
<EditText
android:id="@+id/etHashtagExtraAny"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"
android:scrollHorizontally="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@+id/etHashtagExtraAll"
android:text="@string/hashtag_extra_all"
android:textColor="?attr/colorColumnHeaderPageNumber"
/>
<EditText
android:id="@+id/etHashtagExtraAll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"
android:scrollHorizontally="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@+id/etHashtagExtraNone"
android:text="@string/hashtag_extra_none"
android:textColor="?attr/colorColumnHeaderPageNumber"
/>
<EditText
android:id="@+id/etHashtagExtraNone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"
android:scrollHorizontally="true"
/>
</LinearLayout>
<CheckBox
android:id="@+id/cbDontCloseColumn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_close_column"
/>
<CheckBox
android:id="@+id/cbWithAttachment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/with_attachment"
/>
<CheckBox
android:id="@+id/cbWithHighlight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/with_highlight"
/>
<CheckBox
android:id="@+id/cbDontShowBoost"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_show_boost"
/>
<CheckBox
android:id="@+id/cbDontShowFavourite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_show_favourite"
/>
<CheckBox
android:id="@+id/cbDontShowFollow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_show_follow"
/>
<CheckBox
android:id="@+id/cbDontShowReply"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_show_reply"
/>
<CheckBox
android:id="@+id/cbDontShowReaction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_show_reaction"
/>
<CheckBox
android:id="@+id/cbDontShowVote"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_show_vote"
/>
<CheckBox
android:id="@+id/cbDontShowNormalToot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_show_normal_toot"
/>
<CheckBox
android:id="@+id/cbInstanceLocal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/instance_local"
/>
<CheckBox
android:id="@+id/cbDontStreaming"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_use_streaming_api"
/>
<CheckBox
android:id="@+id/cbDontAutoRefresh"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dont_refresh_on_activity_resume"
/>
<CheckBox
android:id="@+id/cbHideMediaDefault"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hide_media_default"
/>
<CheckBox
android:id="@+id/cbSystemNotificationNotRelated"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/system_notification_not_related"
/>
<CheckBox
android:id="@+id/cbEnableSpeech"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/enable_speech"
/>
<CheckBox
android:id="@+id/cbOldApi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/use_old_api"
/>
<LinearLayout
android:id="@+id/llRegexFilter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@+id/etRegexFilter"
android:text="@string/regex_filter"
android:textColor="?attr/colorColumnHeaderPageNumber"
/>
<TextView
android:id="@+id/tvRegexFilterError"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:textColor="?attr/colorRegexFilterError"
/>
</LinearLayout>
<EditText
android:id="@+id/etRegexFilter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"
android:scrollHorizontally="true"
/>
<Button
android:id="@+id/btnDeleteNotification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/notification_delete"
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnColor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/color_and_background"
android:textAllCaps="false"
/>
</LinearLayout>
</jp.juggler.subwaytooter.view.MaxHeightScrollView>
<LinearLayout
android:id="@+id/llSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSearchFormBackground"
android:orientation="vertical"
android:paddingStart="12dp"
android:paddingTop="3dp"
android:paddingEnd="12dp"
android:paddingBottom="3dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center"
android:orientation="horizontal"
>
<EditText
android:id="@+id/etSearch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:imeOptions="actionSearch"
android:inputType="text"
tools:ignore="LabelFor"
/>
<ImageButton
android:id="@+id/btnSearchClear"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="4dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/clear"
android:src="@drawable/ic_close"
android:tint="?attr/colorVectorDrawable"
/>
<ImageButton
android:id="@+id/btnSearch"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="4dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/search"
android:src="@drawable/ic_search"
android:tint="?attr/colorVectorDrawable"
/>
</LinearLayout>
<CheckBox
android:id="@+id/cbResolve"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/resolve_non_local_account"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/llListList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSearchFormBackground"
android:baselineAligned="false"
android:gravity="center"
android:orientation="horizontal"
android:paddingStart="12dp"
android:paddingTop="3dp"
android:paddingEnd="12dp"
android:paddingBottom="3dp"
>
<EditText
android:id="@+id/etListName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/list_create_hint"
android:imeOptions="actionSend"
android:inputType="text"
tools:ignore="LabelFor"
/>
<ImageButton
android:id="@+id/btnListAdd"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="4dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/add"
android:src="@drawable/ic_add"
android:tint="?attr/colorVectorDrawable"
/>
</LinearLayout>
<HorizontalScrollView
android:id="@+id/svQuickFilter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="40dp"
android:orientation="horizontal"
>
<Button
android:id="@+id/btnQuickFilterAll"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:background="@drawable/btn_bg_transparent"
android:minWidth="40dp"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:text="@string/all"
android:textAllCaps="false"
android:stateListAnimator="@null"
/>
<ImageButton
android:id="@+id/btnQuickFilterMention"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/mention2"
/>
<ImageButton
android:id="@+id/btnQuickFilterFavourite"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/favourite"
/>
<ImageButton
android:id="@+id/btnQuickFilterBoost"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/boost"
/>
<ImageButton
android:id="@+id/btnQuickFilterFollow"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/follow"
/>
<ImageButton
android:id="@+id/btnQuickFilterReaction"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/reaction"
/>
<ImageButton
android:id="@+id/btnQuickFilterVote"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:background="@drawable/btn_bg_transparent"
android:contentDescription="@string/vote_polls"
/>
</LinearLayout>
</HorizontalScrollView>
<FrameLayout
android:id="@+id/flColumnBackground"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<ImageView
android:id="@+id/ivColumnBackgroundImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:visibility="gone"
/>
<TextView
android:id="@+id/tvLoading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
/>
<com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout
android:id="@+id/swipyRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srl_direction="both"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fadeScrollbars="false"
android:padding="0dp"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical"
/>
</com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout>
<FrameLayout
android:id="@+id/llRefreshError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="6dp"
android:background="@drawable/bg_refresh_error"
>
<ImageView
android:id="@+id/ivRefreshError"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="4dp"
android:scaleType="fitCenter"
android:importantForAccessibility="no"
android:src="@drawable/ic_error"
android:tint="#ff0000"
/>
<TextView
android:id="@+id/tvRefreshError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginStart="32dp"
android:scaleType="center"
android:textColor="#fff"
/>
</FrameLayout>
</FrameLayout>
-->
</LinearLayout>

View File

@ -980,5 +980,19 @@
<string name="fedibird_domain_timeline">(fedibird)ドメインタイムライン</string> <string name="fedibird_domain_timeline">(fedibird)ドメインタイムライン</string>
<string name="domain_timeline">ドメインTL</string> <string name="domain_timeline">ドメインTL</string>
<string name="domain_timeline_of">%1$sのドメインTL</string> <string name="domain_timeline_of">%1$sのドメインTL</string>
<string name="language_filter">言語フィルタ</string>
<string name="export">エクスポート</string>
<string name="import_">インポート</string>
<string name="language_code_default">(デフォルト)</string>
<string name="language_code_unknown">(不明)</string>
<string name="language_show">表示する</string>
<string name="language_hide">隠す</string>
<string name="language">言語</string>
<string name="show_hide">表示する/隠す</string>
<string name="language_filter_description">フィルタを適用するにはカラムをリロードしてください</string>
<string name="clear_all">全て消去</string>
<string name="presets">プリセット</string>
<string name="custom">カスタム</string>
<string name="language_code_hint">プリセットを選択または言語コードを入力</string>
</resources> </resources>

View File

@ -974,4 +974,18 @@
<string name="fedibird_domain_timeline">(fedibird)Domain timeline</string> <string name="fedibird_domain_timeline">(fedibird)Domain timeline</string>
<string name="domain_timeline">Domain timeline</string> <string name="domain_timeline">Domain timeline</string>
<string name="domain_timeline_of">%1$s domain timeline</string> <string name="domain_timeline_of">%1$s domain timeline</string>
<string name="language_filter">Language filter</string>
<string name="export">Export</string>
<string name="import_">Import</string>
<string name="language_code_default">(default)</string>
<string name="language_code_unknown">(unknown)</string>
<string name="language_show">Show</string>
<string name="language_hide">Hide</string>
<string name="language">Language</string>
<string name="show_hide">Show/Hide</string>
<string name="language_filter_description">column reload required to apply filter.</string>
<string name="clear_all">Clear all</string>
<string name="presets">Presets</string>
<string name="custom">Custom</string>
<string name="language_code_hint">choose preset or input language code</string>
</resources> </resources>