キーワードフィルタを単語マッチに対応。アプリ設定に「カラムストリップのタップで上端にスクロール」を追加
This commit is contained in:
parent
eccee68092
commit
8f66511c46
|
@ -12,8 +12,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 27
|
||||
|
||||
versionCode 262
|
||||
versionName "2.6.2"
|
||||
versionCode 263
|
||||
versionName "2.6.3"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
// https://stackoverflow.com/questions/47791227/java-lang-illegalstateexception-dex-archives-setting-dex-extension-only-for
|
||||
|
|
|
@ -42,6 +42,7 @@ class ActKeywordFilter
|
|||
}
|
||||
|
||||
internal const val STATE_EXPIRE_SPINNER = "expire_spinner"
|
||||
internal const val STATE_EXPIRE_AT = "expire_at"
|
||||
|
||||
private val expire_duration_list = arrayOf(
|
||||
- 1, // dont change
|
||||
|
@ -64,12 +65,14 @@ class ActKeywordFilter
|
|||
private lateinit var cbContextPublic : CheckBox
|
||||
private lateinit var cbContextThread : CheckBox
|
||||
private lateinit var cbFilterIrreversible : CheckBox
|
||||
private lateinit var cbFilterWordMatch : CheckBox
|
||||
private lateinit var tvExpire : TextView
|
||||
private lateinit var spExpire : Spinner
|
||||
|
||||
private var loading = false
|
||||
private var density : Float = 1f
|
||||
private var filter_id : Long = - 1L
|
||||
private var filter_expire : Long = 0L
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
@ -107,6 +110,7 @@ class ActKeywordFilter
|
|||
if(iv != - 1) {
|
||||
spExpire.setSelection(iv)
|
||||
}
|
||||
filter_expire = savedInstanceState.getLong(STATE_EXPIRE_AT, filter_expire)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +118,7 @@ class ActKeywordFilter
|
|||
super.onSaveInstanceState(outState)
|
||||
if(! loading) {
|
||||
outState.putInt(STATE_EXPIRE_SPINNER, spExpire.selectedItemPosition)
|
||||
outState.putLong(STATE_EXPIRE_AT,filter_expire)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +137,7 @@ class ActKeywordFilter
|
|||
cbContextPublic = findViewById(R.id.cbContextPublic)
|
||||
cbContextThread = findViewById(R.id.cbContextThread)
|
||||
cbFilterIrreversible = findViewById(R.id.cbFilterIrreversible)
|
||||
cbFilterWordMatch = findViewById(R.id.cbFilterWordMatch)
|
||||
tvExpire = findViewById(R.id.tvExpire)
|
||||
spExpire = findViewById(R.id.spExpire)
|
||||
|
||||
|
@ -183,6 +189,8 @@ class ActKeywordFilter
|
|||
private fun onLoadComplete(filter : TootFilter) {
|
||||
loading = false
|
||||
|
||||
filter_expire = filter.time_expires_at
|
||||
|
||||
etPhrase.setText(filter.phrase)
|
||||
setContextChecked(filter, cbContextHome, TootFilter.CONTEXT_HOME)
|
||||
setContextChecked(filter, cbContextNotification, TootFilter.CONTEXT_NOTIFICATIONS)
|
||||
|
@ -190,6 +198,7 @@ class ActKeywordFilter
|
|||
setContextChecked(filter, cbContextThread, TootFilter.CONTEXT_THREAD)
|
||||
|
||||
cbFilterIrreversible.isChecked = filter.irreversible
|
||||
cbFilterWordMatch.isChecked = filter.whole_word
|
||||
|
||||
tvExpire.text = if(filter.time_expires_at == 0L) {
|
||||
getString(R.string.filter_expire_unlimited)
|
||||
|
@ -227,6 +236,7 @@ class ActKeywordFilter
|
|||
})
|
||||
|
||||
put("irreversible", cbFilterIrreversible.isChecked)
|
||||
put("whole_word", cbFilterWordMatch.isChecked)
|
||||
|
||||
var seconds = - 1
|
||||
|
||||
|
@ -238,15 +248,14 @@ class ActKeywordFilter
|
|||
when(seconds) {
|
||||
|
||||
// dont change
|
||||
- 1 -> put("expires_in", "")
|
||||
- 1 -> {}
|
||||
|
||||
// unlimited
|
||||
0 -> if(filter_id == - 1L) {
|
||||
// don't specify expires_in for creating
|
||||
put("expires_in", "")
|
||||
0 -> if( filter_expire <= 0L ) {
|
||||
// already unlimited. don't change.
|
||||
} else {
|
||||
// FIXME: currently there is no way to remove expires from existing filter.
|
||||
put("expires_in", (Int.MAX_VALUE shr 1))
|
||||
put("expires_in", Int.MAX_VALUE )
|
||||
}
|
||||
|
||||
// set seconds
|
||||
|
|
|
@ -1009,7 +1009,7 @@ class ActMain : AppCompatActivity()
|
|||
false,
|
||||
Column.TYPE_BLOCKS
|
||||
)
|
||||
R.id.nav_keyword_filter-> Action_Account.timeline(
|
||||
R.id.nav_keyword_filter -> Action_Account.timeline(
|
||||
this,
|
||||
defaultInsertPosition,
|
||||
false,
|
||||
|
@ -1314,6 +1314,18 @@ class ActMain : AppCompatActivity()
|
|||
})
|
||||
}
|
||||
|
||||
private fun isVisibleColumn(idx : Int) = phoneTab({ env ->
|
||||
val c = env.pager.currentItem
|
||||
c == idx
|
||||
}, { env ->
|
||||
val vs = env.tablet_layout_manager.findFirstVisibleItemPosition()
|
||||
var ve = env.tablet_layout_manager.findLastVisibleItemPosition()
|
||||
if(ve - vs > nScreenColumn - 1) {
|
||||
ve = vs + nScreenColumn - 1
|
||||
}
|
||||
vs != RecyclerView.NO_POSITION && vs <= idx && idx <= ve
|
||||
})
|
||||
|
||||
internal fun updateColumnStrip() {
|
||||
llEmpty.visibility = if(app_state.column_list.isEmpty()) View.VISIBLE else View.GONE
|
||||
|
||||
|
@ -1326,7 +1338,14 @@ class ActMain : AppCompatActivity()
|
|||
val ivIcon = viewRoot.findViewById<ImageView>(R.id.ivIcon)
|
||||
|
||||
viewRoot.tag = i
|
||||
viewRoot.setOnClickListener { v -> scrollToColumn(v.tag as Int) }
|
||||
viewRoot.setOnClickListener { v ->
|
||||
val idx = v.tag as Int
|
||||
if(Pref.bpScrollTopFromColumnStrip(pref) && isVisibleColumn(idx)) {
|
||||
app_state.column_list[i].viewHolder?.scrollToTop2()
|
||||
return@setOnClickListener
|
||||
}
|
||||
scrollToColumn(idx)
|
||||
}
|
||||
viewRoot.contentDescription = column.getColumnName(true)
|
||||
//
|
||||
|
||||
|
|
|
@ -3991,10 +3991,13 @@ class Column(
|
|||
private fun encodeFilterTree(filterList : ArrayList<TootFilter>?) : WordTrieTree? {
|
||||
val column_context = getFilterContext()
|
||||
if(column_context == 0 || filterList == null) return null
|
||||
val tree = WordTrieTree(WordTrieTree.WORD_VALIDATOR)
|
||||
val tree = WordTrieTree()
|
||||
for(filter in filterList) {
|
||||
if((filter.context and column_context) != 0) {
|
||||
tree.add(filter.phrase)
|
||||
tree.add(filter.phrase,validator = when(filter.whole_word){
|
||||
true -> WordTrieTree.WORD_VALIDATOR
|
||||
else -> WordTrieTree.EMPTY_VALIDATOR
|
||||
})
|
||||
}
|
||||
}
|
||||
return tree
|
||||
|
|
|
@ -851,6 +851,8 @@ class ColumnViewHolder(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onClick(v : View) {
|
||||
val column = this.column
|
||||
val status_adapter = this.status_adapter
|
||||
|
@ -883,11 +885,7 @@ class ColumnViewHolder(
|
|||
column.startLoading()
|
||||
}
|
||||
|
||||
R.id.llColumnHeader -> {
|
||||
if(status_adapter.itemCount > 0) {
|
||||
scrollToTop()
|
||||
}
|
||||
}
|
||||
R.id.llColumnHeader -> scrollToTop2()
|
||||
|
||||
R.id.btnColumnSetting -> llColumnSetting.visibility =
|
||||
if(llColumnSetting.visibility == View.VISIBLE) View.GONE else View.VISIBLE
|
||||
|
@ -1210,5 +1208,12 @@ class ColumnViewHolder(
|
|||
} catch(ignored : Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun scrollToTop2() {
|
||||
val status_adapter = this.status_adapter
|
||||
if(loading_busy || status_adapter == null) return
|
||||
if(status_adapter.itemCount > 0) {
|
||||
scrollToTop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -504,18 +504,20 @@ internal class ItemViewHolder(
|
|||
.append(": ")
|
||||
.append(filter.getContextNames(activity).joinToString("/"))
|
||||
//
|
||||
val flags = ArrayList<String>()
|
||||
if( filter.irreversible ) flags.add(activity.getString(R.string.filter_irreversible))
|
||||
if( filter.whole_word ) flags.add(activity.getString(R.string.filter_word_match))
|
||||
if( flags.isNotEmpty() ){
|
||||
sb.append('\n')
|
||||
.append( flags.joinToString(", "))
|
||||
}
|
||||
//
|
||||
if( filter.time_expires_at != 0L ){
|
||||
sb.append('\n')
|
||||
.append(activity.getString(R.string.filter_expires_at))
|
||||
.append(": ")
|
||||
.append( TootStatus.formatTime(activity,filter.time_expires_at,false))
|
||||
}
|
||||
//
|
||||
if( filter.irreversible){
|
||||
sb.append('\n')
|
||||
.append(activity.getString(R.string.filter_irreversible))
|
||||
|
||||
}
|
||||
|
||||
tvFilterDetail.text = sb.toString()
|
||||
}
|
||||
|
|
|
@ -312,7 +312,11 @@ object Pref {
|
|||
false,
|
||||
R.id.swDontRetrievePreviewCard
|
||||
)
|
||||
|
||||
val bpScrollTopFromColumnStrip = BooleanPref(
|
||||
"ScrollTopFromColumnStrip",
|
||||
false,
|
||||
R.id.swScrollTopFromColumnStrip
|
||||
)
|
||||
|
||||
// int
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ class TootFilter( src: JSONObject) :TimelineItem() {
|
|||
private val expires_at : String? // null is not specified, or "2018-07-06T00:59:13.161Z"
|
||||
val time_expires_at : Long // 0L if not specified
|
||||
val irreversible : Boolean
|
||||
val whole_word : Boolean
|
||||
|
||||
init{
|
||||
id = src.parseLong("id") ?: throw RuntimeException("missing id")
|
||||
|
@ -74,6 +75,7 @@ class TootFilter( src: JSONObject) :TimelineItem() {
|
|||
expires_at = src.parseString("expires_at") // may null
|
||||
time_expires_at = TootStatus.parseTime(expires_at)
|
||||
irreversible = src.optBoolean("irreversible")
|
||||
whole_word = src.optBoolean("whole_word")
|
||||
}
|
||||
|
||||
fun getContextNames(context: Context) : ArrayList<String> {
|
||||
|
|
|
@ -6,7 +6,6 @@ class CharacterGroup {
|
|||
|
||||
companion object {
|
||||
|
||||
|
||||
// Tokenizerが終端に達したことを示す
|
||||
const val END = - 1
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ import android.support.v4.util.SparseArrayCompat
|
|||
|
||||
import java.util.ArrayList
|
||||
|
||||
class WordTrieTree(private var validator : (src : CharSequence, start : Int, end : Int) -> Boolean = EMPTY_VALIDATOR) {
|
||||
class WordTrieTree {
|
||||
|
||||
companion object {
|
||||
|
||||
private val grouper = CharacterGroup()
|
||||
|
||||
private val EMPTY_VALIDATOR = { _ : CharSequence, _ : Int, _ : Int -> true }
|
||||
val EMPTY_VALIDATOR = { _ : CharSequence, _ : Int, _ : Int -> true }
|
||||
|
||||
// マストドン2.4.3rc2でキーワードフィルタは単語の前後に 正規表現 \b を仮定するようになった
|
||||
// Trie木でマッチ候補が出たらマッチ範囲と前後の文字で単語区切りを検証する
|
||||
|
@ -55,6 +55,10 @@ class WordTrieTree(private var validator : (src : CharSequence, start : Int, end
|
|||
|
||||
// Trieツリー的には終端単語と続くノードの両方が存在する場合がありうる。
|
||||
// たとえば ABC と ABCDEF を登録してから ABCDEFG を探索したら、単語 ABC と単語 ABCDEF にマッチする。
|
||||
|
||||
// このノードが終端なら、単語マッチの有無を覚えておく
|
||||
internal var validator : (src : CharSequence, start : Int, end : Int) -> Boolean =
|
||||
EMPTY_VALIDATOR
|
||||
}
|
||||
|
||||
private val node_root = Node()
|
||||
|
@ -63,7 +67,10 @@ class WordTrieTree(private var validator : (src : CharSequence, start : Int, end
|
|||
get() = node_root.child_nodes.size() == 0
|
||||
|
||||
// 単語の追加
|
||||
fun add(s : String) {
|
||||
fun add(
|
||||
s : String,
|
||||
validator : (src : CharSequence, start : Int, end : Int) -> Boolean = EMPTY_VALIDATOR
|
||||
) {
|
||||
val t = grouper.tokenizer().reset(s, 0, s.length)
|
||||
|
||||
var token_count = 0
|
||||
|
@ -80,6 +87,7 @@ class WordTrieTree(private var validator : (src : CharSequence, start : Int, end
|
|||
val old_word = node.match_word
|
||||
if(old_word == null || old_word.length < t.text.length) {
|
||||
node.match_word = t.text.toString()
|
||||
node.validator = validator
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -113,7 +121,9 @@ class WordTrieTree(private var validator : (src : CharSequence, start : Int, end
|
|||
// match_wordが定義されたノードは単語の終端を示す
|
||||
val match_word = node.match_word
|
||||
// マッチ候補はvalidatorで単語区切りなどの検査を行う
|
||||
if(match_word != null && validator(t.text, start, t.offset)) {
|
||||
if(match_word != null
|
||||
&& node.validator(t.text, start, t.offset)
|
||||
) {
|
||||
|
||||
// マッチしたことを覚えておく
|
||||
dst = Match(start, t.offset, match_word)
|
||||
|
|
|
@ -218,6 +218,22 @@
|
|||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/scroll_top_from_column_strip"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Switch
|
||||
android:id="@+id/swScrollTopFromColumnStrip"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/dont_screen_off"
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/filter_irreversible"
|
||||
android:text="@string/filter_options"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
@ -108,11 +108,19 @@
|
|||
<CheckBox
|
||||
android:id="@+id/cbFilterIrreversible"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:text="@string/filter_irreversible"
|
||||
android:text="@string/filter_irreversible_long"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbFilterWordMatch"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:text="@string/filter_word_match_long"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -692,18 +692,31 @@
|
|||
<string name="follow_suggestion">Follow suggestion</string>
|
||||
<string name="close_all_columns">Close all columns</string>
|
||||
<string name="confirm_close_column_all">All columns (exclude protected) will be closed. Are tou sure?</string>
|
||||
<string name="filtered">filtered</string>
|
||||
<string name="keyword_filters">Keyword filters</string>
|
||||
<string name="filter_context">context</string>
|
||||
<string name="filter_expires_at">expires_at</string>
|
||||
<string name="filter_home">home</string>
|
||||
|
||||
<string name="keyword_filters">Keyword filters</string>
|
||||
<string name="keyword_filter">Keyword filter</string>
|
||||
<string name="keyword_filter_new">New filter</string>
|
||||
<string name="keyword_filter_edit">Edit filter</string>
|
||||
<string name="filter_delete_confirm">The filter \'%1$s\' will be deleted. Are you sure?</string>
|
||||
<string name="filter_of">Filter \'%1$s\'</string>
|
||||
<string name="filtered">filtered</string>
|
||||
|
||||
<string name="filter_phrase">Phrase</string>
|
||||
<string name="filter_context">Filter contexts</string>
|
||||
|
||||
<string name="filter_options">Options</string>
|
||||
<string name="filter_irreversible">Irreversible</string>
|
||||
<string name="filter_irreversible_long">Irreversible. Drop instead of hide. Filtered toots will disappear irreversibly, even if filter is later removed.</string>
|
||||
<string name="filter_word_match">Whole word</string>
|
||||
<string name="filter_word_match_long">Whole word. Recommended to enable only phrases consisting of alphanumeric characters.</string>
|
||||
|
||||
<string name="filter_expires_at">Expire</string>
|
||||
|
||||
<string name="filter_home">home</string>
|
||||
<string name="filter_notification">notification</string>
|
||||
<string name="filter_public">public</string>
|
||||
<string name="filter_thread">conversation</string>
|
||||
<string name="filter_irreversible">irreversible</string>
|
||||
<string name="filter_delete_confirm">The filter \'%1$s\' will be deleted. Are you sure?</string>
|
||||
<string name="filter_of">Filter \'%1$s\'</string>
|
||||
<string name="filter_phrase">Phrase</string>
|
||||
|
||||
<string name="dont_change">Don\'t change</string>
|
||||
<string name="filter_expire_unlimited">Unlimited</string>
|
||||
<string name="filter_expire_30min">30 minutes after save</string>
|
||||
|
@ -712,11 +725,9 @@
|
|||
<string name="filter_expire_12hour">12 hours after save</string>
|
||||
<string name="filter_expire_1day">1 day after save</string>
|
||||
<string name="filter_expire_1week">1 week after save</string>
|
||||
<string name="keyword_filter_new">New filter</string>
|
||||
<string name="keyword_filter_edit">Edit filter</string>
|
||||
<string name="keyword_filter">Keyword filter</string>
|
||||
<string name="scroll_top_from_column_strip">Scroll to top when tapping visible column in column strip</string>
|
||||
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
<!--<string name="abc_action_bar_home_description_format">%1$s, %2$s</string>-->
|
||||
<!--<string name="abc_action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>-->
|
||||
<!--<string name="abc_action_bar_up_description">Revenir en haut de la page</string>-->
|
||||
|
|
|
@ -970,19 +970,31 @@
|
|||
<string name="follow_suggestion">フォロー推奨ユーザ</string>
|
||||
<string name="close_all_columns">全てのカラムを閉じる</string>
|
||||
<string name="confirm_close_column_all">(保護されていない)全てのカラムが閉じられます。よろしいですか?</string>
|
||||
<string name="filtered">フィルタされました</string>
|
||||
<string name="keyword_filter">単語フィルタ</string>
|
||||
|
||||
<string name="keyword_filters">単語フィルタ</string>
|
||||
<string name="keyword_filter">単語フィルタ</string>
|
||||
<string name="keyword_filter_new">フィルタの作成</string>
|
||||
<string name="keyword_filter_edit">フィルタの編集</string>
|
||||
<string name="filter_delete_confirm">フィルタ \'%1$s\' は削除されます。よろしいですか?</string>
|
||||
<string name="filter_of">フィルタ \'%1$s\'</string>
|
||||
<string name="filtered">フィルタされました</string>
|
||||
|
||||
<string name="filter_phrase">フレーズ</string>
|
||||
<string name="filter_context">適用箇所</string>
|
||||
|
||||
<string name="filter_options">オプション</string>
|
||||
<string name="filter_irreversible">不可逆</string>
|
||||
<string name="filter_irreversible_long">不可逆。隠すのではなく除外する。フィルターが後で削除されても、除外されたトゥートは元に戻せなくなります。</string>
|
||||
<string name="filter_word_match">単語マッチ</string>
|
||||
<string name="filter_word_match_long">単語マッチ。英数字だけで構成されるフレーズ以外では無効にすることを推奨します。</string>
|
||||
|
||||
<string name="filter_expires_at">期限</string>
|
||||
|
||||
<string name="filter_home">ホーム</string>
|
||||
<string name="filter_notification">通知</string>
|
||||
<string name="filter_public">公開TL</string>
|
||||
<string name="filter_thread">会話</string>
|
||||
<string name="filter_irreversible">不可逆</string>
|
||||
<string name="filter_delete_confirm">フィルタ \'%1$s\' は削除されます。よろしいですか?</string>
|
||||
<string name="filter_of">フィルタ \'%1$s\'</string>
|
||||
<string name="filter_phrase">フレーズ</string>
|
||||
|
||||
<string name="dont_change">変更しない</string>
|
||||
<string name="filter_expire_unlimited">無期限</string>
|
||||
<string name="filter_expire_30min">30分後</string>
|
||||
|
@ -991,7 +1003,6 @@
|
|||
<string name="filter_expire_12hour">12時間後</string>
|
||||
<string name="filter_expire_1day">1日後</string>
|
||||
<string name="filter_expire_1week">1週間後</string>
|
||||
<string name="keyword_filter_new">フィルタの作成</string>
|
||||
<string name="keyword_filter_edit">フィルタの編集</string>
|
||||
<string name="scroll_top_from_column_strip">Scroll to top when tapping visible column in column strip</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -677,18 +677,32 @@
|
|||
<string name="follow_suggestion">Follow suggestion</string>
|
||||
<string name="close_all_columns">Close all columns</string>
|
||||
<string name="confirm_close_column_all">All columns (exclude protected) will be closed. Are tou sure?</string>
|
||||
<string name="filtered">filtered</string>
|
||||
|
||||
|
||||
<string name="keyword_filters">Keyword filters</string>
|
||||
<string name="filter_context">context</string>
|
||||
<string name="filter_expires_at">expires_at</string>
|
||||
<string name="keyword_filter">Keyword filter</string>
|
||||
<string name="keyword_filter_new">New filter</string>
|
||||
<string name="keyword_filter_edit">Edit filter</string>
|
||||
<string name="filter_delete_confirm">The filter \'%1$s\' will be deleted. Are you sure?</string>
|
||||
<string name="filter_of">Filter \'%1$s\'</string>
|
||||
<string name="filtered">filtered</string>
|
||||
|
||||
<string name="filter_phrase">Phrase</string>
|
||||
<string name="filter_context">Filter contexts</string>
|
||||
|
||||
<string name="filter_options">Options</string>
|
||||
<string name="filter_irreversible">Irreversible</string>
|
||||
<string name="filter_irreversible_long">Irreversible. Drop instead of hide. Filtered toots will disappear irreversibly, even if filter is later removed.</string>
|
||||
<string name="filter_word_match">Whole word</string>
|
||||
<string name="filter_word_match_long">Whole word. Recommended to enable only phrases consisting of alphanumeric characters.</string>
|
||||
|
||||
<string name="filter_expires_at">Expire</string>
|
||||
|
||||
<string name="filter_home">home</string>
|
||||
<string name="filter_notification">notification</string>
|
||||
<string name="filter_public">public</string>
|
||||
<string name="filter_thread">conversation</string>
|
||||
<string name="filter_irreversible">irreversible</string>
|
||||
<string name="filter_delete_confirm">The filter \'%1$s\' will be deleted. Are you sure?</string>
|
||||
<string name="filter_of">Filter \'%1$s\'</string>
|
||||
<string name="filter_phrase">Phrase</string>
|
||||
|
||||
<string name="dont_change">Don\'t change</string>
|
||||
<string name="filter_expire_unlimited">Unlimited</string>
|
||||
<string name="filter_expire_30min">30 minutes after save</string>
|
||||
|
@ -697,7 +711,5 @@
|
|||
<string name="filter_expire_12hour">12 hours after save</string>
|
||||
<string name="filter_expire_1day">1 day after save</string>
|
||||
<string name="filter_expire_1week">1 week after save</string>
|
||||
<string name="keyword_filter_new">New filter</string>
|
||||
<string name="keyword_filter_edit">Edit filter</string>
|
||||
<string name="keyword_filter">Keyword filter</string>
|
||||
<string name="scroll_top_from_column_strip">Scroll to top when tapping visible column in column strip</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue