diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActHighlightWordList.kt b/app/src/main/java/jp/juggler/subwaytooter/ActHighlightWordList.kt
index afcad9ab..1e5e2dc3 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/ActHighlightWordList.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/ActHighlightWordList.kt
@@ -250,7 +250,7 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
}
private fun create() {
- DlgTextInput.show(this, getString(R.string.new_item), "", object : DlgTextInput.Callback {
+ DlgTextInput.show(this, getString(R.string.new_item), "", callback = object : DlgTextInput.Callback {
override fun onEmptyError() {
showToast(this@ActHighlightWordList, true, R.string.word_empty)
}
diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt b/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt
index 2030f313..09bc49cc 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt
@@ -2178,7 +2178,7 @@ class ActMain : AsyncActivity()
this,
getString(R.string.access_token_or_api_token),
null,
- object : DlgTextInput.Callback {
+ callback = object : DlgTextInput.Callback {
override fun onOK(dialog : Dialog, text : String) {
checkAccessToken(null, dialog, sa.host, text, sa)
}
diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt b/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt
index e2ed47ba..64909fab 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt
@@ -1757,7 +1757,7 @@ class ActPost : AsyncActivity(),
this,
getString(R.string.attachment_description),
a.description,
- object : DlgTextInput.Callback {
+ callback = object : DlgTextInput.Callback {
override fun onOK(dialog : Dialog, text : String) {
setAttachmentDescription(pa, dialog, text)
}
diff --git a/app/src/main/java/jp/juggler/subwaytooter/App1.kt b/app/src/main/java/jp/juggler/subwaytooter/App1.kt
index 8c385e88..e58809f6 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/App1.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/App1.kt
@@ -134,8 +134,9 @@ class App1 : Application() {
// 2019/12/18 44=> 45 SavedAccount テーブルに項目追加。
// 2019/12/18 44=> 46 SavedAccount テーブルに項目追加。
// 2020/6/8 46 => 54 別ブランチで色々してた。このブランチには影響ないが onDowngrade()を実装してないので上げてしまう
+ // 2020/7/19 54=>55 UserRelation テーブルに項目追加。
- internal const val DB_VERSION = 54
+ internal const val DB_VERSION = 55
private val tableList = arrayOf(
LogData,
diff --git a/app/src/main/java/jp/juggler/subwaytooter/Column.kt b/app/src/main/java/jp/juggler/subwaytooter/Column.kt
index 2c823a5a..c8ada552 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/Column.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/Column.kt
@@ -1706,35 +1706,31 @@ class Column(
// リロード不要なら何もしない
null
} else if(isMisskey) {
- val result = client.request(
+ client.request(
PATH_MISSKEY_PROFILE,
access_info.putMisskeyApiToken().apply {
put("userId", profile_id)
}.toPostRequestBuilder()
- )
-
- // ユーザリレーションの取り扱いのため、別のparserを作ってはいけない
- parser.misskeyDecodeProfilePin = true
- try {
- val a = TootAccountRef.mayNull(parser, parser.account(result?.jsonObject))
- if(a != null) {
+ )?.also{ result1 ->
+ // ユーザリレーションの取り扱いのため、別のparserを作ってはいけない
+ parser.misskeyDecodeProfilePin = true
+ try {
+ TootAccountRef.mayNull(parser, parser.account(result1.jsonObject))?.also{ a->
+ this.who_account = a
+ client.publishApiProgress("") // カラムヘッダの再表示
+ }
+ } finally {
+ parser.misskeyDecodeProfilePin = false
+ }
+ }
+ } else {
+ client.request(String.format(Locale.JAPAN, PATH_ACCOUNT, profile_id))?.also{result1 ->
+ TootAccountRef.mayNull(parser, parser.account(result1.jsonObject))?.also{ a->
this.who_account = a
client.publishApiProgress("") // カラムヘッダの再表示
+
}
- } finally {
- parser.misskeyDecodeProfilePin = false
}
-
- result
-
- } else {
- val result = client.request(String.format(Locale.JAPAN, PATH_ACCOUNT, profile_id))
- val a = TootAccountRef.mayNull(parser, parser.account(result?.jsonObject))
- if(a != null) {
- this.who_account = a
- client.publishApiProgress("") // カラムヘッダの再表示
- }
- result
}
}
@@ -1781,7 +1777,8 @@ class Column(
// parser内部にアカウントIDとRelationのマップが生成されるので、それをデータベースに記録する
run {
val now = System.currentTimeMillis()
- val who_list = parser.misskeyUserRelationMap.entries.toMutableList()
+ val who_list =
+ parser.misskeyUserRelationMap.entries.toMutableList()
var start = 0
val end = who_list.size
while(start < end) {
diff --git a/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt b/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt
index 37792055..b30457a1 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt
@@ -1,5 +1,6 @@
package jp.juggler.subwaytooter
+import android.app.Dialog
import android.graphics.Color
import android.text.SpannableStringBuilder
import android.text.Spanned
@@ -9,10 +10,11 @@ import android.widget.*
import jp.juggler.emoji.EmojiMap
import jp.juggler.subwaytooter.action.Action_Follow
import jp.juggler.subwaytooter.action.Action_User
-import jp.juggler.subwaytooter.api.MisskeyAccountDetailMap
+import jp.juggler.subwaytooter.api.*
import jp.juggler.subwaytooter.api.entity.TootAccount
import jp.juggler.subwaytooter.api.entity.TootAccountRef
import jp.juggler.subwaytooter.api.entity.TootStatus
+import jp.juggler.subwaytooter.dialog.DlgTextInput
import jp.juggler.subwaytooter.span.EmojiImageSpan
import jp.juggler.subwaytooter.span.createSpan
import jp.juggler.subwaytooter.table.AcctColor
@@ -68,6 +70,9 @@ internal class ViewHolderHeaderProfile(
private val density : Float
private val btnMore : ImageButton
+ private val tvPersonalNotes : TextView
+ private val btnPersonalNotesEdit : ImageButton
+
init {
ivBackground = viewRoot.findViewById(R.id.ivBackground)
llProfile = viewRoot.findViewById(R.id.llProfile)
@@ -95,18 +100,28 @@ internal class ViewHolderHeaderProfile(
ivMovedBy = viewRoot.findViewById(R.id.ivMovedBy)
llFields = viewRoot.findViewById(R.id.llFields)
+ tvPersonalNotes = viewRoot.findViewById(R.id.tvPersonalNotes)
+ btnPersonalNotesEdit = viewRoot.findViewById(R.id.btnPersonalNotesEdit)
+
+
density = tvDisplayName.resources.displayMetrics.density
- ivBackground.setOnClickListener(this)
- btnFollowing.setOnClickListener(this)
- btnFollowers.setOnClickListener(this)
- btnStatusCount.setOnClickListener(this)
- btnMore.setOnClickListener(this)
- btnFollow.setOnClickListener(this)
- tvRemoteProfileWarning.setOnClickListener(this)
-
- btnMoved.setOnClickListener(this)
- llMoved.setOnClickListener(this)
+ for(v in arrayOf(
+ ivBackground,
+ btnFollowing,
+ btnFollowers,
+ btnStatusCount,
+ btnMore,
+ btnFollow,
+ tvRemoteProfileWarning,
+ btnPersonalNotesEdit,
+
+ btnMoved,
+ llMoved,
+ btnPersonalNotesEdit
+ )) {
+ v.setOnClickListener(this)
+ }
btnMoved.setOnLongClickListener(this)
btnFollow.setOnLongClickListener(this)
@@ -132,6 +147,8 @@ internal class ViewHolderHeaderProfile(
private var contentColor = 0
+ private var relation : UserRelation? = null
+
override fun bindData(column : Column) {
super.bindData(column)
@@ -141,6 +158,7 @@ internal class ViewHolderHeaderProfile(
if(! f.isNaN()) {
tvMovedName.textSize = f
tvMoved.textSize = f
+ tvPersonalNotes.textSize = f
}
f = activity.acct_font_size_sp
@@ -159,6 +177,7 @@ internal class ViewHolderHeaderProfile(
val contentColor = column.getContentColor()
this.contentColor = contentColor
+ tvPersonalNotes.textColor = contentColor
tvMoved.textColor = contentColor
tvMovedName.textColor = contentColor
tvDisplayName.textColor = contentColor
@@ -175,7 +194,15 @@ internal class ViewHolderHeaderProfile(
color = contentColor,
alphaMultiplier = Styler.boost_alpha
)
-
+
+ setIconDrawableId(
+ activity,
+ btnPersonalNotesEdit,
+ R.drawable.ic_edit,
+ color = contentColor,
+ alphaMultiplier = Styler.boost_alpha
+ )
+
val acctColor = column.getAcctColor()
tvCreated.textColor = acctColor
tvMovedAcct.textColor = acctColor
@@ -200,6 +227,7 @@ internal class ViewHolderHeaderProfile(
llFields.removeAllViews()
if(who == null) {
+ relation = null
tvCreated.text = ""
tvLastStatusAt.vg(false)
ivBackground.setImageDrawable(null)
@@ -345,6 +373,8 @@ internal class ViewHolderHeaderProfile(
}
val relation = UserRelation.load(access_info.db_id, who.id)
+ this.relation = relation
+
Styler.setFollowIcon(
activity,
btnFollow,
@@ -355,6 +385,8 @@ internal class ViewHolderHeaderProfile(
alphaMultiplier = Styler.boost_alpha
)
+ tvPersonalNotes.text = relation.note ?: ""
+
showMoved(who, who.movedRef)
val fields = whoDetail?.fields ?: who.fields
@@ -550,6 +582,53 @@ internal class ViewHolderHeaderProfile(
)
}
}
+
+ R.id.btnPersonalNotesEdit -> whoRef?.let{ whoRef->
+ val who = whoRef.get()
+ val relation = this.relation
+ val lastColumn = column
+ DlgTextInput.show(
+ activity,
+ AcctColor.getStringWithNickname(activity,R.string.personal_notes_of,who.acct),
+ relation?.note ?: "",
+ allowEmpty = true,
+ callback = object: DlgTextInput.Callback{
+ override fun onEmptyError() {
+ }
+
+ override fun onOK(dialog : Dialog, text : String) {
+ TootTaskRunner(activity).run(column.access_info,object:TootTask{
+ override fun background(client : TootApiClient) : TootApiResult? {
+
+ if(access_info.isPseudo)
+ return TootApiResult("Personal notes is not supported on pseudo account.")
+
+ if(access_info.isMisskey)
+ return TootApiResult("Personal notes is not supported on Misskey account.")
+
+ return client.request("/api/v1/accounts/${who.id}/note",
+ jsonObject {
+ put("comment",text)
+ }.toPostRequestBuilder()
+ )
+ }
+
+ override fun handleResult(result : TootApiResult?) {
+ if(result==null) return
+ if(result.error!=null)
+ showToast(activity,true,result.error)
+ else{
+ relation?.note = text
+ dialog.dismissSafe()
+ if(lastColumn==column) bindData(column)
+ }
+ }
+ })
+ }
+ }
+ )
+
+ }
}
}
diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Account.kt b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Account.kt
index 14d4105a..09e58de4 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Account.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Account.kt
@@ -93,7 +93,7 @@ object Action_Account {
activity,
activity.getString(R.string.access_token_or_api_token),
null,
- object : DlgTextInput.Callback {
+ callback = object : DlgTextInput.Callback {
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
override fun onOK(
diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/Action_List.kt b/app/src/main/java/jp/juggler/subwaytooter/action/Action_List.kt
index 8c2ee0c1..7821e67e 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/action/Action_List.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/action/Action_List.kt
@@ -140,7 +140,7 @@ object Action_List {
activity,
activity.getString(R.string.rename),
item.title,
- object : DlgTextInput.Callback {
+ callback = object : DlgTextInput.Callback {
override fun onEmptyError() {
showToast(activity, false, R.string.list_name_empty)
}
diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootRelationShip.kt b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootRelationShip.kt
index e95af7dd..fc2c32dd 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootRelationShip.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootRelationShip.kt
@@ -39,6 +39,9 @@ class TootRelationShip(parser:TootParser,src : JsonObject) {
// misskey用
val requested_by : Boolean
+
+ // (Mastodon 3.2)
+ var note : String? = null
init {
@@ -91,6 +94,7 @@ class TootRelationShip(parser:TootParser,src : JsonObject) {
this.muting = src.optBoolean("muting")
this.requested = src.optBoolean("requested")
this.endorsed = src.optBoolean("endorsed")
+ this.note = src.optString( "note")
// https://github.com/tootsuite/mastodon/commit/9745de883b198375ba23f7fde879f6d75ce2df0f
// Mastodon 2.8.0から
diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgListMember.kt b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgListMember.kt
index 8cadd101..1f8ed44a 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgListMember.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgListMember.kt
@@ -265,7 +265,7 @@ class DlgListMember(
activity,
activity.getString(R.string.list_create),
null,
- object : DlgTextInput.Callback {
+ callback = object : DlgTextInput.Callback {
override fun onEmptyError() {
showToast(activity, false, R.string.list_name_empty)
diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgTextInput.kt b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgTextInput.kt
index b0d65dcb..d61bd1b8 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgTextInput.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgTextInput.kt
@@ -24,6 +24,7 @@ object DlgTextInput {
activity : Activity,
caption : CharSequence,
initial_text : CharSequence?,
+ allowEmpty : Boolean = false,
callback : Callback
) {
val view = activity.layoutInflater.inflate(R.layout.dlg_text_input, null, false)
@@ -51,7 +52,7 @@ object DlgTextInput {
btnOk.setOnClickListener {
val token = etInput.text.toString().trim { it <= ' ' }
- if( token.isEmpty() ) {
+ if( token.isEmpty() && !allowEmpty ) {
callback.onEmptyError()
} else {
callback.onOK(dialog, token)
diff --git a/app/src/main/java/jp/juggler/subwaytooter/table/TableUtils.kt b/app/src/main/java/jp/juggler/subwaytooter/table/TableUtils.kt
index 17d0626f..67376aee 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/table/TableUtils.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/table/TableUtils.kt
@@ -1,5 +1,6 @@
package jp.juggler.subwaytooter.table
+import android.content.ContentValues
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
@@ -21,3 +22,6 @@ interface TableCompanion {
fun onDBCreate(db : SQLiteDatabase)
fun onDBUpgrade(db : SQLiteDatabase, oldVersion : Int, newVersion : Int)
}
+
+fun ContentValues.putOrNull(key : String, value : String?) =
+ if(value == null) putNull(key) else put(key, value)
diff --git a/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.kt b/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.kt
index a6bbba47..255a963a 100644
--- a/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.kt
+++ b/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.kt
@@ -13,6 +13,7 @@ import jp.juggler.subwaytooter.api.entity.TootRelationShip
import jp.juggler.util.JsonObject
import jp.juggler.util.LogCategory
import jp.juggler.util.getInt
+import jp.juggler.util.getStringOrNull
class UserRelation {
@@ -26,6 +27,8 @@ class UserRelation {
var following_reblogs : Int = 0 // このユーザからのブーストをTLに表示する
var endorsed : Boolean = false // ユーザをプロフィールで紹介する
+ var note : String? = null
+
// 認証ユーザからのフォロー状態
fun getFollowing(who : TootAccount?) : Boolean {
return if(requested && ! following && who != null && ! who.locked) true else following
@@ -62,6 +65,7 @@ class UserRelation {
private const val COL_ENDORSED = "endorsed"
private const val COL_BLOCKED_BY = "blocked_by"
private const val COL_REQUESTED_BY = "requested_by"
+ private const val COL_NOTE = "note"
private const val DB_ID_PSEUDO = - 2L
@@ -83,6 +87,7 @@ class UserRelation {
,$COL_ENDORSED integer default 0
,$COL_BLOCKED_BY integer default 0
,$COL_REQUESTED_BY integer default 0
+ ,$COL_NOTE text default null
)"""
)
db.execSQL(
@@ -119,6 +124,13 @@ class UserRelation {
log.trace(ex)
}
}
+ if(oldVersion < 55 && newVersion >= 55) {
+ try {
+ db.execSQL("alter table $table add column $COL_NOTE text default null")
+ } catch(ex : Throwable) {
+ log.trace(ex)
+ }
+ }
}
fun deleteOld(now : Long) {
@@ -155,6 +167,7 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
+ cv.putOrNull(COL_NOTE, src.note)
App1.database.replaceOrThrow(table, null, cv)
val key = String.format("%s:%s", db_id, whoId)
@@ -184,6 +197,7 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
+ cv.putOrNull(COL_NOTE, src.note)
App1.database.replaceOrThrow(table, null, cv)
val key = String.format("%s:%s", db_id, id)
mMemoryCache.remove(key)
@@ -216,6 +230,7 @@ class UserRelation {
cv.put(COL_REQUESTED, src.requested.b2i())
cv.put(COL_FOLLOWING_REBLOGS, src.showing_reblogs)
cv.put(COL_ENDORSED, src.endorsed.b2i())
+ cv.putOrNull(COL_NOTE, src.note)
db.replaceOrThrow(table, null, cv)
}
@@ -267,6 +282,7 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
+ cv.putOrNull(COL_NOTE, src.note)
db.replaceOrThrow(table, null, cv)
}
bOK = true
@@ -307,6 +323,7 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
+ cv.putOrNull(COL_NOTE, src.note)
db.replace(table, null, cv)
}
bOK = true
@@ -365,6 +382,7 @@ class UserRelation {
dst.endorsed = cursor.getBoolean(COL_ENDORSED)
dst.blocked_by = cursor.getBoolean(COL_BLOCKED_BY)
dst.requested_by = cursor.getBoolean(COL_REQUESTED_BY)
+ dst.note = cursor.getStringOrNull(COL_NOTE)
return dst
}
}
diff --git a/app/src/main/res/layout/lv_header_profile.xml b/app/src/main/res/layout/lv_header_profile.xml
index 26ac16d2..9f05cf12 100644
--- a/app/src/main/res/layout/lv_header_profile.xml
+++ b/app/src/main/res/layout/lv_header_profile.xml
@@ -220,6 +220,39 @@
tools:text="xxxx-xx-xx xx:xx:xx"
/>
+
+
+
+
+
+
+
認証済みリンクの背景色 (アプリ再起動が必要)
認証済みリンクの文字色 (アプリ再起動が必要)
画面下部の余白(単位:dp。デフォルト:0。アプリ再起動が必要)
+ 覚え書き
+ %1$sに関する覚え書き
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a054c6d6..f052ebe8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1035,4 +1035,6 @@
Verified link background color (app restart required)
Verified link foreground color (app restart required)
Screen bottom padding (Unit: dp. Default:0. App restart required)
+ Personal notes
+ Personal notes of %1$s