1
0
mirror of https://github.com/tateisu/SubwayTooter synced 2025-01-28 01:29:23 +01:00

「Fav/BT非通知ユーザ」を設定できるようにした

This commit is contained in:
tateisu 2018-03-16 01:23:43 +09:00
parent 3995a39d6a
commit 0bcdbc3946
14 changed files with 439 additions and 39 deletions

View File

@ -12,8 +12,8 @@ android {
minSdkVersion 21
targetSdkVersion 27
versionCode 225
versionName "2.2.5"
versionCode 226
versionName "2.2.6"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

View File

@ -182,6 +182,11 @@
android:label="@string/muted_word"
/>
<activity
android:name=".ActFavMute"
android:label="@string/fav_muted_user"
/>
<activity
android:name=".ActHighlightWordList"
android:label="@string/highlight_word"

View File

@ -0,0 +1,196 @@
package jp.juggler.subwaytooter
import android.content.Context
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.woxthebox.draglistview.DragItem
import com.woxthebox.draglistview.DragItemAdapter
import com.woxthebox.draglistview.DragListView
import com.woxthebox.draglistview.swipe.ListSwipeHelper
import com.woxthebox.draglistview.swipe.ListSwipeItem
import java.util.ArrayList
import jp.juggler.subwaytooter.table.FavMute
import jp.juggler.subwaytooter.util.LogCategory
class ActFavMute : AppCompatActivity() {
companion object {
private val log = LogCategory("ActFavMute")
}
private lateinit var listView : DragListView
private lateinit var listAdapter : MyListAdapter
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
App1.setActivityTheme(this, false)
initUI()
loadData()
}
override fun onBackPressed() {
setResult(RESULT_OK)
super.onBackPressed()
}
private fun initUI() {
setContentView(R.layout.act_word_list)
Styler.fixHorizontalPadding2(findViewById(R.id.llContent))
// リストのアダプター
listAdapter = MyListAdapter()
// ハンドル部分をドラッグで並べ替えできるRecyclerView
listView = findViewById(R.id.drag_list_view)
listView.setLayoutManager(LinearLayoutManager(this))
listView.setAdapter(listAdapter, false)
listView.setCanDragHorizontally(true)
listView.isDragEnabled = false
listView.setCustomDragItem(MyDragItem(this, R.layout.lv_mute_app))
listView.recyclerView.isVerticalScrollBarEnabled = true
// listView.setDragListListener( new DragListView.DragListListenerAdapter() {
// @Override
// public void onItemDragStarted( int position ){
// // 操作中はリフレッシュ禁止
// // mRefreshLayout.setEnabled( false );
// }
//
// @Override
// public void onItemDragEnded( int fromPosition, int toPosition ){
// // 操作完了でリフレッシュ許可
// // mRefreshLayout.setEnabled( USE_SWIPE_REFRESH );
//
//// if( fromPosition != toPosition ){
//// // 並べ替えが発生した
//// }
// }
// } );
// リストを左右スワイプした
listView.setSwipeListener(object : ListSwipeHelper.OnSwipeListenerAdapter() {
override fun onItemSwipeStarted(item : ListSwipeItem?) {
// 操作中はリフレッシュ禁止
// mRefreshLayout.setEnabled( false );
}
override fun onItemSwipeEnded(item : ListSwipeItem?, swipedDirection : ListSwipeItem.SwipeDirection?) {
// 操作完了でリフレッシュ許可
// mRefreshLayout.setEnabled( USE_SWIPE_REFRESH );
// 左にスワイプした(右端に青が見えた) なら要素を削除する
if(swipedDirection == ListSwipeItem.SwipeDirection.LEFT) {
val o = item ?.tag
if(o is MyItem) {
FavMute.delete(o.name)
listAdapter.removeItem(listAdapter.getPositionForItem(o))
}
}
}
})
}
private fun loadData() {
val tmp_list = ArrayList<MyItem>()
try {
FavMute.createCursor().use { cursor ->
val idx_id = cursor.getColumnIndex(FavMute.COL_ID)
val idx_name = cursor.getColumnIndex(FavMute.COL_ACCT)
while(cursor.moveToNext()) {
val id = cursor.getLong(idx_id)
val name = cursor.getString(idx_name)
val item = MyItem(id, name)
tmp_list.add(item)
}
}
} catch(ex : Throwable) {
log.trace(ex)
}
listAdapter.itemList = tmp_list
}
// リスト要素のデータ
internal class MyItem(val id : Long, val name : String)
// リスト要素のViewHolder
internal class MyViewHolder(viewRoot : View) : DragItemAdapter.ViewHolder(viewRoot, R.id.ivDragHandle, false) {
val tvName : TextView
init {
tvName = viewRoot.findViewById(R.id.tvName)
// リスト要素のビューが ListSwipeItem だった場合、Swipe操作を制御できる
if(viewRoot is ListSwipeItem) {
viewRoot.setSwipeInStyle(ListSwipeItem.SwipeInStyle.SLIDE)
viewRoot.supportedSwipeDirection = ListSwipeItem.SwipeDirection.LEFT
}
} // View ID。 ここを押すとドラッグ操作をすぐに開始する
// 長押しでドラッグ開始するなら真
fun bind(item : MyItem) {
itemView.tag = item // itemView は親クラスのメンバ変数
tvName.text = item.name
}
// @Override
// public boolean onItemLongClicked( View view ){
// return false;
// }
// @Override
// public void onItemClicked( View view ){
// }
}
// ドラッグ操作中のデータ
private inner class MyDragItem internal constructor(context : Context, layoutId : Int) : DragItem(context, layoutId) {
override fun onBindDragView(clickedView : View, dragView : View) {
dragView.findViewById<TextView>(R.id.tvName).text = clickedView.findViewById<TextView>(R.id.tvName).text
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor(
Styler.getAttributeColor(this@ActFavMute, R.attr.list_item_bg_pressed_dragged)
)
}
}
private inner class MyListAdapter internal constructor() : DragItemAdapter<MyItem, MyViewHolder>() {
init {
setHasStableIds(true)
itemList = ArrayList()
}
override fun onCreateViewHolder(parent : ViewGroup, viewType : Int) : MyViewHolder {
val view = layoutInflater.inflate(R.layout.lv_mute_app, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder : MyViewHolder, position : Int) {
super.onBindViewHolder(holder, position)
holder.bind(itemList[position])
}
override fun getUniqueItemId(position : Int) : Long {
val item = mItemList[position] // mItemList は親クラスのメンバ変数
return item.id
}
}
}

View File

@ -1039,6 +1039,7 @@ class ActMain : AppCompatActivity()
R.id.nav_app_setting -> ActAppSetting.open(this, REQUEST_CODE_APP_SETTING)
R.id.nav_muted_app -> startActivity(Intent(this, ActMutedApp::class.java))
R.id.nav_muted_word -> startActivity(Intent(this, ActMutedWord::class.java))
R.id.nav_fav_mute -> startActivity(Intent(this, ActFavMute::class.java))
R.id.nav_highlight_word -> startActivity(Intent(this, ActHighlightWordList::class.java))
R.id.nav_app_about -> startActivityForResult(
Intent(this, ActAbout::class.java),

View File

@ -33,20 +33,7 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import jp.juggler.subwaytooter.api.entity.TootAttachment
import jp.juggler.subwaytooter.table.AcctColor
import jp.juggler.subwaytooter.table.AcctSet
import jp.juggler.subwaytooter.table.HighlightWord
import jp.juggler.subwaytooter.table.MutedApp
import jp.juggler.subwaytooter.table.ClientInfo
import jp.juggler.subwaytooter.table.ContentWarning
import jp.juggler.subwaytooter.table.LogData
import jp.juggler.subwaytooter.table.MediaShown
import jp.juggler.subwaytooter.table.MutedWord
import jp.juggler.subwaytooter.table.NotificationTracking
import jp.juggler.subwaytooter.table.PostDraft
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.TagSet
import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.table.*
import jp.juggler.subwaytooter.util.*
import okhttp3.Cache
import okhttp3.CacheControl
@ -87,6 +74,7 @@ class App1 : Application() {
PostDraft.onDBCreate(db)
TagSet.onDBCreate(db)
HighlightWord.onDBCreate(db)
FavMute.onDBCreate(db)
}
override fun onUpgrade(db : SQLiteDatabase, oldVersion : Int, newVersion : Int) {
@ -105,6 +93,7 @@ class App1 : Application() {
PostDraft.onDBUpgrade(db, oldVersion, newVersion)
TagSet.onDBUpgrade(db, oldVersion, newVersion)
HighlightWord.onDBUpgrade(db, oldVersion, newVersion)
FavMute.onDBUpgrade(db, oldVersion, newVersion)
}
}
@ -115,7 +104,7 @@ class App1 : Application() {
const val FILE_PROVIDER_AUTHORITY = "jp.juggler.subwaytooter.FileProvider"
internal const val DB_NAME = "app_db"
internal const val DB_VERSION = 21
internal const val DB_VERSION = 22
// 2017/4/25 v10 1=>2 SavedAccount に通知設定を追加
// 2017/4/25 v10 1=>2 NotificationTracking テーブルを追加
@ -136,6 +125,7 @@ class App1 : Application() {
// 2017/9/23 v161 18=>19 ClientInfoテーブルを置き換える
// 2017/12/01 v175 19=>20 UserRelation に項目追加
// 2018/1/03 v197 20=>21 HighlightWord テーブルを追加
// 2018/3/16 v226 21=>22 FavMuteテーブルを追加
private lateinit var db_open_helper : DBOpenHelper

View File

@ -17,15 +17,8 @@ import java.util.Locale
import java.util.concurrent.atomic.AtomicBoolean
import java.util.regex.Pattern
import jp.juggler.subwaytooter.table.AcctColor
import jp.juggler.subwaytooter.table.AcctSet
import jp.juggler.subwaytooter.table.HighlightWord
import jp.juggler.subwaytooter.table.MutedApp
import jp.juggler.subwaytooter.table.MutedWord
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.TagSet
import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.table.*
import jp.juggler.subwaytooter.util.*
class Column(
@ -359,6 +352,7 @@ class Column(
private var column_regex_filter = COLUMN_REGEX_FILTER_DEFAULT
private var muted_app : HashSet<String>? = null
private var muted_word : WordTrieTree? = null
private var favMuteSet : HashSet<String>? = null
private var highlight_trie : WordTrieTree? = null
private var max_id : String = ""
@ -876,6 +870,28 @@ class Column(
}
}
fun onHideFavouriteNotification(acct : String) {
if( column_type != TYPE_NOTIFICATIONS) return
val tmp_list = ArrayList<TimelineItem>(list_data.size)
for(o in list_data) {
if(o is TootNotification && o.type != TootNotification.TYPE_MENTION ) {
val a = o.account
if( a!=null){
val a_acct = access_info.getFullAcct(a)
if( a_acct == acct) continue
}
}
tmp_list.add(o)
}
if(tmp_list.size != list_data.size) {
list_data.clear()
list_data.addAll(tmp_list)
fireShowContent(reason = "onHideFavouriteNotification")
}
}
fun onDomainBlockChanged(target_account : SavedAccount, domain : String, bBlocked : Boolean) {
if(target_account.host != access_info.host) return
if(access_info.isPseudo) return
@ -1054,6 +1070,7 @@ class Column(
muted_app = MutedApp.nameSet
muted_word = MutedWord.nameSet
favMuteSet = FavMute.acctSet
highlight_trie = HighlightWord.nameSet
}
@ -1167,6 +1184,18 @@ class Column(
return true
}
}
// ふぁぼ魔ミュート
when(item.type){
TootNotification.TYPE_REBLOG,TootNotification.TYPE_FAVOURITE,TootNotification.TYPE_FOLLOW ->{
val who = item.account
if( who != null && favMuteSet?.contains( access_info.getFullAcct(who) ) == true){
PollingWorker.log.d("%s is in favMuteSet.",access_info.getFullAcct(who))
return true
}
}
}
return false
}
@ -3612,4 +3641,5 @@ class Column(
path
}
}
}

View File

@ -25,6 +25,7 @@ import jp.juggler.subwaytooter.api.entity.TootNotification
import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.dialog.DlgListMember
import jp.juggler.subwaytooter.dialog.DlgQRCode
import jp.juggler.subwaytooter.table.FavMute
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.LogCategory
@ -99,6 +100,8 @@ internal class DlgContextMenu(
val btnHideBoost = viewRoot.findViewById<View>(R.id.btnHideBoost)
val btnShowBoost = viewRoot.findViewById<View>(R.id.btnShowBoost)
val btnHideFavourite = viewRoot.findViewById<View>(R.id.btnHideFavourite)
val btnShowFavourite = viewRoot.findViewById<View>(R.id.btnShowFavourite)
val btnListMemberAddRemove = viewRoot.findViewById<View>(R.id.btnListMemberAddRemove)
@ -129,6 +132,8 @@ internal class DlgContextMenu(
btnConversationMute.setOnClickListener(this)
btnHideBoost.setOnClickListener(this)
btnShowBoost.setOnClickListener(this)
btnHideFavourite.setOnClickListener(this)
btnShowFavourite.setOnClickListener(this)
btnListMemberAddRemove.setOnClickListener(this)
btnInstanceInformation.setOnClickListener(this)
btnDomainBlock.setOnClickListener(this)
@ -299,6 +304,17 @@ internal class DlgContextMenu(
btnShowBoost.visibility = View.VISIBLE
}
if( who == null ){
btnHideFavourite.visibility = View.GONE
btnShowFavourite.visibility = View.GONE
}else if( FavMute.contains( access_info.getFullAcct(who) )){
btnHideFavourite.visibility = View.GONE
btnShowFavourite.visibility = View.VISIBLE
}else{
btnHideFavourite.visibility = View.VISIBLE
btnShowFavourite.visibility = View.GONE
}
val who_host = who?.host
if( who_host==null || who_host.isEmpty() || who_host == "?") {
btnOpenTimeline.visibility = View.GONE
@ -568,6 +584,20 @@ internal class DlgContextMenu(
Action_User.showBoosts(activity, access_info, who, true)
}
R.id.btnHideFavourite -> who?.let { who ->
val acct = access_info.getFullAcct(who)
FavMute.save( acct)
showToast(activity,false,R.string.changed)
for( column in activity.app_state.column_list ){
column.onHideFavouriteNotification(acct)
}
}
R.id.btnShowFavourite -> who?.let { who ->
FavMute.delete( access_info.getFullAcct(who))
showToast(activity,false,R.string.changed)
}
R.id.btnListMemberAddRemove -> who?.let { who ->
DlgListMember(activity, who, access_info).show()
}

View File

@ -46,11 +46,7 @@ import java.util.concurrent.atomic.AtomicReference
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.entity.TootNotification
import jp.juggler.subwaytooter.api.TootParser
import jp.juggler.subwaytooter.table.AcctColor
import jp.juggler.subwaytooter.table.MutedApp
import jp.juggler.subwaytooter.table.MutedWord
import jp.juggler.subwaytooter.table.NotificationTracking
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.*
import jp.juggler.subwaytooter.util.*
import okhttp3.Call
import okhttp3.Request
@ -554,6 +550,7 @@ class PollingWorker private constructor(c : Context) {
val bPollingRequired = AtomicBoolean(false)
lateinit var muted_app : HashSet<String>
lateinit var muted_word : WordTrieTree
lateinit var favMuteSet : HashSet<String>
var bPollingComplete = false
var install_id : String? = null
@ -620,6 +617,7 @@ class PollingWorker private constructor(c : Context) {
muted_app = MutedApp.nameSet
muted_word = MutedWord.nameSet
favMuteSet = FavMute.acctSet
// タスクがあれば処理する
while(true) {
@ -1037,6 +1035,7 @@ class PollingWorker private constructor(c : Context) {
private val dstListData = ArrayList<Data>()
private val muted_app : HashSet<String> get() = job.muted_app
private val muted_word : WordTrieTree get() = job.muted_word
private val favMuteSet : HashSet<String> get() = job.favMuteSet
private lateinit var nr : NotificationTracking
private lateinit var parser : TootParser
@ -1370,15 +1369,13 @@ class PollingWorker private constructor(c : Context) {
nid_last_show = id
}
val type = src.parseString("type")
if(id <= nr.nid_read) {
// warning.d("update_sub: ignore data that id=%s, <= read id %s ",id,nr.nid_read);
return
} else {
log.d("update_sub: found data that id=%s, > read id %s ", id, nr.nid_read)
}
log.d("update_sub: found data that id=%s, > read id %s ", id, nr.nid_read)
if(id > nr.nid_show) {
log.d(
"update_sub: found new data that id=%s, greater than shown id %s ",
@ -1388,7 +1385,8 @@ class PollingWorker private constructor(c : Context) {
// 種別チェックより先に「表示済み」idの更新を行う
nr.nid_show = id
}
val type = src.parseString("type")
if(! account.notification_mention && TootNotification.TYPE_MENTION == type
|| ! account.notification_boost && TootNotification.TYPE_REBLOG == type
|| ! account.notification_favourite && TootNotification.TYPE_FAVOURITE == type
@ -1398,10 +1396,18 @@ class PollingWorker private constructor(c : Context) {
val notification = parser.notification(src) ?: return
run {
val status = notification.status
if(status != null) {
if(status.checkMuted(muted_app, muted_word)) {
// アプリミュートと単語ミュート
val status = notification.status
if(status != null && status.checkMuted(muted_app, muted_word)) {
return
}
// ふぁぼ魔ミュート
when(type){
TootNotification.TYPE_REBLOG,TootNotification.TYPE_FAVOURITE,TootNotification.TYPE_FOLLOW ->{
val who = notification.account
if( who != null && favMuteSet.contains( account.getFullAcct(who) ) ){
log.d("%s is in favMuteSet.",account.getFullAcct(who))
return
}
}

View File

@ -0,0 +1,97 @@
package jp.juggler.subwaytooter.table
import android.content.ContentValues
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.util.LogCategory
object FavMute {
private val log = LogCategory("FavMute")
const val table = "fav_mute"
const val COL_ID = "_id"
const val COL_ACCT = "acct"
fun onDBCreate(db : SQLiteDatabase) {
log.d("onDBCreate!")
db.execSQL(
"create table if not exists " + table
+ "($COL_ID INTEGER PRIMARY KEY"
+ ",$COL_ACCT text not null "
+ ")"
)
db.execSQL(
"create unique index if not exists ${table}_acct on $table($COL_ACCT)"
)
}
fun onDBUpgrade(db : SQLiteDatabase, oldVersion : Int, newVersion : Int) {
if(oldVersion < 22 && newVersion >= 22) {
onDBCreate(db)
}
}
fun save(acct : String?) {
acct ?: return
try {
val cv = ContentValues()
cv.put(COL_ACCT, acct)
App1.database.replace(table, null, cv)
} catch(ex : Throwable) {
log.e(ex, "save failed.")
}
}
fun delete(acct : String) {
try {
App1.database.delete(table, "$COL_ACCT=?", arrayOf(acct))
} catch(ex : Throwable) {
log.e(ex, "delete failed.")
}
}
fun createCursor() : Cursor {
return App1.database.query(table, null, null, null, null, null, COL_ACCT + " asc")
}
val acctSet: HashSet<String>
get() {
val dst = HashSet<String>()
try {
App1.database.query(table, null, null, null, null, null, null)
.use{ cursor->
val idx_name = cursor.getColumnIndex(COL_ACCT)
while(cursor.moveToNext()) {
val s = cursor.getString(idx_name)
dst.add(s)
}
}
} catch(ex : Throwable) {
log.trace(ex)
}
return dst
}
fun contains( acct : String) : Boolean {
var found = false
try {
App1.database.query(table, null, "$COL_ACCT=?", arrayOf(acct), null, null, null)
.use{ cursor->
while(cursor.moveToNext()) {
found= true
}
}
} catch(ex : Throwable) {
log.trace(ex)
}
return found
}
}

View File

@ -651,6 +651,35 @@
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnHideFavourite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/btn_bg_transparent"
android:gravity="start|center_vertical"
android:minHeight="32dp"
android:paddingBottom="4dp"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:text="@string/hide_favourite_notification_from_user"
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnShowFavourite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/btn_bg_transparent"
android:gravity="start|center_vertical"
android:minHeight="32dp"
android:paddingBottom="4dp"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:text="@string/show_favourite_notification_from_user"
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnOpenTimeline"

View File

@ -134,6 +134,10 @@
android:id="@+id/nav_muted_word"
android:icon="?attr/ic_mute"
android:title="@string/muted_word"/>
<item
android:id="@+id/nav_fav_mute"
android:icon="?attr/ic_mute"
android:title="@string/fav_muted_user"/>
<item
android:id="@+id/nav_app_about"

View File

@ -621,6 +621,10 @@
<string name="contact">contact account</string>
<string name="languages">languages</string>
<string name="append_attachment_url_to_content">Append attachment URL to context text</string>
<string name="hide_favourite_notification_from_user">Hide favourite notification from this user</string>
<string name="show_favourite_notification_from_user">Show favourite notification from this user</string>
<string name="fav_muted_user">FavMuted user</string>
<string name="changed">changed.</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>-->

View File

@ -904,5 +904,9 @@
<string name="contact">連絡先アカウント</string>
<string name="languages">言語</string>
<string name="append_attachment_url_to_content">添付メディアのURLを本文に記載する</string>
<string name="hide_favourite_notification_from_user">このユーザをFav,BT非通知に追加</string>
<string name="show_favourite_notification_from_user">このユーザをFav,BT非通知から削除</string>
<string name="fav_muted_user">Fav/BT非通知ユーザ</string>
<string name="changed">変更しました</string>
</resources>

View File

@ -610,4 +610,8 @@
<string name="contact">contact account</string>
<string name="languages">languages</string>
<string name="append_attachment_url_to_content">Append attachment URL to context text</string>
<string name="hide_favourite_notification_from_user">Hide favourite notification from this user</string>
<string name="show_favourite_notification_from_user">Show favourite notification from this user</string>
<string name="fav_muted_user">FavMuted user</string>
<string name="changed">changed.</string>
</resources>