diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/ActionUtils.kt b/app/src/main/java/jp/juggler/subwaytooter/action/ActionUtils.kt index f89e0840..93ebf9ee 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/action/ActionUtils.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/action/ActionUtils.kt @@ -62,16 +62,36 @@ internal fun findAccountByName( internal fun addPseudoAccount( context : Context, host : String, - isMisskey : Boolean = false -) : SavedAccount? { - + isMisskey : Boolean? = null, + callback : (SavedAccount) -> Unit +) { try { val username = "?" val full_acct = "$username@$host" var account = SavedAccount.loadAccountByAcct(context, full_acct) if(account != null) { - return account + callback(account) + return + } + + if(isMisskey == null) { + TootTaskRunner(context).run(object : TootTask { + + var isMisskey2 : Boolean = false + + override fun background(client : TootApiClient) : TootApiResult? { + client.instance = host + val r = client.getInstanceInformation() + isMisskey2 = r?.jsonObject?.optBoolean(TootApiClient.KEY_IS_MISSKEY) ?: false + return r + } + + override fun handleResult(result : TootApiResult?) { + if(result != null) addPseudoAccount(context, host, isMisskey2, callback) + } + }) + return } val account_info = JSONObject() @@ -91,15 +111,15 @@ internal fun addPseudoAccount( account.notification_reaction = false account.notification_vote = false account.saveSetting() - return account + callback(account) + return } catch(ex : Throwable) { val log = LogCategory("addPseudoAccount") log.trace(ex) log.e(ex, "failed.") showToast(context, ex, "addPseudoAccount failed.") } - - return null + return } // 疑似アカ以外のアカウントのリスト @@ -150,7 +170,7 @@ internal fun loadRelation1Mastodon( val r2 = rr.result val jsonArray = r2?.jsonArray if(jsonArray != null) { - val list = parseList(::TootRelationShip,TootParser(client.context,access_info), jsonArray) + val list = parseList(::TootRelationShip, TootParser(client.context, access_info), jsonArray) if(list.isNotEmpty()) { rr.relation = saveUserRelation(access_info, list[0]) } 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 6de17fd8..e4a568a2 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 @@ -102,8 +102,11 @@ object Action_Account { } else { // 疑似アカウントを追加 - val a = addPseudoAccount(activity, instance, data.optBoolean("isMisskey",false)) - if(a != null) { + addPseudoAccount( + activity, + instance, + data.optBoolean("isMisskey", false) + ) { a -> showToast(activity, false, R.string.server_confirmed) val pos = App1.getAppState(activity).column_list.size activity.addColumn(pos, a, Column.TYPE_LOCAL) @@ -113,7 +116,6 @@ object Action_Account { } catch(ignored : Throwable) { // IllegalArgumentException がたまに出る } - } } } else { @@ -155,8 +157,8 @@ object Action_Account { pos : Int, type : Int, bAllowPseudo : Boolean, - bAllowMisskey: Boolean =true, - bAllowMastodon: Boolean =true, + bAllowMisskey : Boolean = true, + bAllowMastodon : Boolean = true, args : Array = emptyArray() ) { @@ -198,7 +200,14 @@ object Action_Account { bAllowPseudo = false, bAuto = true, message = activity.getString(R.string.account_picker_toot) - ) { ai -> ActPost.open(activity, ActMain.REQUEST_CODE_POST, ai.db_id, initial_text = initial_text) } + ) { ai -> + ActPost.open( + activity, + ActMain.REQUEST_CODE_POST, + ai.db_id, + initial_text = initial_text + ) + } } } @@ -208,8 +217,8 @@ object Action_Account { who : TootAccount, bSet : Boolean ) { - if( access_info.isMisskey ){ - showToast(activity,false,"This feature is not provided on Misskey account.") + if(access_info.isMisskey) { + showToast(activity, false, "This feature is not provided on Misskey account.") return } @@ -220,20 +229,24 @@ object Action_Account { override fun background(client : TootApiClient) : TootApiResult? { val builder = Request.Builder().post( - RequestBody.create(TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED,"") + RequestBody.create(TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED, "") ) var result = client.request( - "/api/v1/accounts/${who.id}/"+when(bSet){ - true ->"pin" - false ->"unpin" + "/api/v1/accounts/${who.id}/" + when(bSet) { + true -> "pin" + false -> "unpin" } - ,builder + , builder ) val jsonObject = result?.jsonObject - if( jsonObject != null ){ - val tr = parseItem(::TootRelationShip,TootParser(client.context,access_info),jsonObject) - if( tr != null ) { - this.relation = saveUserRelation(access_info,tr) + if(jsonObject != null) { + val tr = parseItem( + ::TootRelationShip, + TootParser(client.context, access_info), + jsonObject + ) + if(tr != null) { + this.relation = saveUserRelation(access_info, tr) } } return result @@ -242,13 +255,15 @@ object Action_Account { override fun handleResult(result : TootApiResult?) { result ?: return - if( result.error != null ){ - showToast(activity,true,result.error) - }else{ - showToast(activity,false,when(bSet){ - true->R.string.endorse_succeeded - else->R.string.remove_endorse_succeeded - }) + if(result.error != null) { + showToast(activity, true, result.error) + } else { + showToast( + activity, false, when(bSet) { + true -> R.string.endorse_succeeded + else -> R.string.remove_endorse_succeeded + } + ) } } }) diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/Action_HashTag.kt b/app/src/main/java/jp/juggler/subwaytooter/action/Action_HashTag.kt index d786a6a6..33837a34 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/action/Action_HashTag.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/action/Action_HashTag.kt @@ -6,6 +6,7 @@ import jp.juggler.subwaytooter.ActMain import jp.juggler.subwaytooter.App1 import jp.juggler.subwaytooter.Column import jp.juggler.subwaytooter.R +import jp.juggler.subwaytooter.api.entity.TootStatus import jp.juggler.subwaytooter.dialog.ActionsDialog import jp.juggler.subwaytooter.table.AcctColor import jp.juggler.subwaytooter.table.SavedAccount @@ -14,14 +15,37 @@ object Action_HashTag { // ハッシュタグへの操作を選択する fun dialog( - activity : ActMain, pos : Int, url : String, host : String, tag_without_sharp : String, tag_list : ArrayList? + activity : ActMain, + pos : Int, + url : String, + host : String, + tag_without_sharp : String, + tag_list : ArrayList? ) { val tag_with_sharp = "#" + tag_without_sharp val d = ActionsDialog() - .addAction(activity.getString(R.string.open_hashtag_column)) { timelineOtherInstance(activity, pos, url, host, tag_without_sharp) } - .addAction(activity.getString(R.string.open_in_browser)) { App1.openCustomTab(activity, url) } - .addAction(activity.getString(R.string.quote_hashtag_of, tag_with_sharp)) { Action_Account.openPost(activity, tag_with_sharp + " ") } + .addAction(activity.getString(R.string.open_hashtag_column)) { + timelineOtherInstance( + activity, + pos, + url, + host, + tag_without_sharp + ) + } + .addAction(activity.getString(R.string.open_in_browser)) { + App1.openCustomTab( + activity, + url + ) + } + .addAction( + activity.getString( + R.string.quote_hashtag_of, + tag_with_sharp + ) + ) { Action_Account.openPost(activity, tag_with_sharp + " ") } if(tag_list != null && tag_list.size > 1) { val sb = StringBuilder() @@ -30,7 +54,12 @@ object Action_HashTag { sb.append(s) } val tag_all = sb.toString() - d.addAction(activity.getString(R.string.quote_all_hashtag_of, tag_all)) { Action_Account.openPost(activity, tag_all + " ") } + d.addAction( + activity.getString( + R.string.quote_all_hashtag_of, + tag_all + ) + ) { Action_Account.openPost(activity, tag_all + " ") } } d.show(activity, tag_with_sharp) @@ -43,7 +72,6 @@ object Action_HashTag { activity.addColumn(pos, access_info, Column.TYPE_HASHTAG, tag_without_sharp) } - // アカウントを選んでハッシュタグカラムを開く fun timelineOtherInstance( activity : ActMain, @@ -76,13 +104,17 @@ object Action_HashTag { } // ブラウザで表示する - dialog.addAction(activity.getString(R.string.open_web_on_host, host)) { App1.openCustomTab(activity, url) } - + dialog.addAction(activity.getString(R.string.open_web_on_host, host)) { + App1.openCustomTab( + activity, + url + ) + } + // 同タンスのアカウントがない場合は疑似アカウントを作成して開く if(list_original.isEmpty() && list_original_pseudo.isEmpty()) { dialog.addAction(activity.getString(R.string.open_in_pseudo_account, "?@" + host)) { - val sa = addPseudoAccount(activity, host) - if(sa != null) { + addPseudoAccount(activity, host) { sa -> timeline(activity, pos, sa, tag_without_sharp) } } @@ -90,15 +122,33 @@ object Action_HashTag { // 分類した順に選択肢を追加する for(a in list_original) { - dialog.addAction(AcctColor.getStringWithNickname(activity, R.string.open_in_account, a.acct)) + dialog.addAction( + AcctColor.getStringWithNickname( + activity, + R.string.open_in_account, + a.acct + ) + ) { timeline(activity, pos, a, tag_without_sharp) } } for(a in list_original_pseudo) { - dialog.addAction(AcctColor.getStringWithNickname(activity, R.string.open_in_account, a.acct)) + dialog.addAction( + AcctColor.getStringWithNickname( + activity, + R.string.open_in_account, + a.acct + ) + ) { timeline(activity, pos, a, tag_without_sharp) } } for(a in list_other) { - dialog.addAction(AcctColor.getStringWithNickname(activity, R.string.open_in_account, a.acct)) + dialog.addAction( + AcctColor.getStringWithNickname( + activity, + R.string.open_in_account, + a.acct + ) + ) { timeline(activity, pos, a, tag_without_sharp) } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Instance.kt b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Instance.kt index e3914215..b2ce5a7a 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Instance.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Instance.kt @@ -22,12 +22,12 @@ object Action_Instance { fun information( activity : ActMain, pos : Int, host : String ) { - activity.addColumn(false,pos, SavedAccount.na, Column.TYPE_INSTANCE_INFORMATION, host) + activity.addColumn(false, pos, SavedAccount.na, Column.TYPE_INSTANCE_INFORMATION, host) } // 指定タンスのローカルタイムラインを開く fun timelineLocal( - activity : ActMain, pos:Int,host : String + activity : ActMain, pos : Int, host : String ) { // 指定タンスのアカウントを持ってるか? val account_list = ArrayList() @@ -36,8 +36,7 @@ object Action_Instance { } if(account_list.isEmpty()) { // 持ってないなら疑似アカウントを追加する - val ai = addPseudoAccount(activity, host) - if(ai != null) { + addPseudoAccount(activity, host) { ai -> activity.addColumn(pos, ai, Column.TYPE_LOCAL) } } else { @@ -46,14 +45,13 @@ object Action_Instance { AccountPicker.pick( activity, bAllowPseudo = true, - bAuto = false, + bAuto = false, message = activity.getString(R.string.account_picker_add_timeline_of, host), accountListArg = account_list ) { ai -> activity.addColumn(pos, ai, Column.TYPE_LOCAL) } } } - // ドメインブロック fun blockDomain( activity : ActMain, access_info : SavedAccount, domain : String, bBlock : Boolean @@ -72,7 +70,8 @@ object Action_Instance { ) var request_builder = Request.Builder() - request_builder = if(bBlock) request_builder.post(body) else request_builder.delete(body) + request_builder = + if(bBlock) request_builder.post(body) else request_builder.delete(body) return client.request("/api/v1/domain_blocks", request_builder) } @@ -86,7 +85,11 @@ object Action_Instance { column.onDomainBlockChanged(access_info, domain, bBlock) } - showToast(activity, false, if(bBlock) R.string.block_succeeded else R.string.unblock_succeeded) + showToast( + activity, + false, + if(bBlock) R.string.block_succeeded else R.string.unblock_succeeded + ) } else { showToast(activity, false, result.error) @@ -99,70 +102,70 @@ object Action_Instance { fun timelinePublicAround2( activity : ActMain, access_info : SavedAccount, - pos:Int, - id:EntityId, - columnType:Int + pos : Int, + id : EntityId, + columnType : Int ) { - activity.addColumn(pos, access_info, columnType,id) + activity.addColumn(pos, access_info, columnType, id) } - + private fun timelinePublicAround3( activity : ActMain, access_info : SavedAccount, - pos:Int, - status:TootStatus, - columnType:Int + pos : Int, + status : TootStatus, + columnType : Int ) { - TootTaskRunner(activity).run(access_info,object:TootTask{ + TootTaskRunner(activity).run(access_info, object : TootTask { override fun background(client : TootApiClient) : TootApiResult? { - return client.syncStatus(access_info,status) + return client.syncStatus(access_info, status) } override fun handleResult(result : TootApiResult?) { - result?: return - val localStatus = result. data as? TootStatus - if( localStatus != null ){ - timelinePublicAround2(activity,access_info,pos,localStatus.id,columnType) - }else{ - showToast(activity,true,result.error) + result ?: return + val localStatus = result.data as? TootStatus + if(localStatus != null) { + timelinePublicAround2(activity, access_info, pos, localStatus.id, columnType) + } else { + showToast(activity, true, result.error) } } }) } - + // 指定タンスのローカルタイムラインを開く fun timelinePublicAround( activity : ActMain, access_info : SavedAccount, - pos:Int, + pos : Int, host : String?, - status:TootStatus?, - columnType:Int, - allowPseudo :Boolean = true + status : TootStatus?, + columnType : Int, + allowPseudo : Boolean = true ) { - if( host?.isEmpty() != false || host == "?") return - status?: return + if(host?.isEmpty() != false || host == "?") return + status ?: return // 利用可能なアカウントを列挙する val account_list1 = ArrayList() // 閲覧アカウントとホストが同じ val account_list2 = ArrayList() // その他実アカウント label@ for(a in SavedAccount.loadAccountList(activity)) { - - when{ + + when { // - a.isNA-> continue@label - + a.isNA -> continue@label + // Misskeyアカウントはステータスの同期が出来ないので選択させない a.isMisskey -> continue@label - + // 閲覧アカウントとホスト名が同じならステータスIDの変換が必要ない - a.host.equals( access_info.host,ignoreCase = true) ->{ - if( ! allowPseudo && a.isPseudo) continue@label + a.host.equals(access_info.host, ignoreCase = true) -> { + if(! allowPseudo && a.isPseudo) continue@label account_list1.add(a) } // 実アカウントならステータスを同期して同時間帯のTLを見れる - !a.isPseudo ->{ + ! a.isPseudo -> { account_list2.add(a) } } @@ -171,17 +174,17 @@ object Action_Instance { SavedAccount.sort(account_list2) account_list1.addAll(account_list2) - if( account_list1.isNotEmpty()) { + if(account_list1.isNotEmpty()) { AccountPicker.pick( activity, - bAuto = true, + bAuto = true, message = "select account to read timeline", accountListArg = account_list1 ) { ai -> - if( !ai.isNA && ai.host.equals( access_info.host,ignoreCase = true) ){ - timelinePublicAround2(activity,account_list1[0], pos, status.id,columnType) - }else { - timelinePublicAround3(activity, ai, pos, status,columnType) + if(! ai.isNA && ai.host.equals(access_info.host, ignoreCase = true)) { + timelinePublicAround2(activity, account_list1[0], pos, status.id, columnType) + } else { + timelinePublicAround3(activity, ai, pos, status, columnType) } } return @@ -190,6 +193,4 @@ object Action_Instance { showToast(activity, false, R.string.missing_available_account) } - - } diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt index ed550524..9a68df1d 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt @@ -698,12 +698,14 @@ object Action_Toot { // 同タンスのアカウントがないなら、疑似アカウントで開く選択肢 if(local_account_list.isEmpty()) { + + val isMisskey = TootStatus.reStatusPageMisskey.matcher(url).find() + if(status_id_original != null) { dialog.addAction( activity.getString(R.string.open_in_pseudo_account, "?@$host_original") ) { - val sa = addPseudoAccount(activity, host_original) - if(sa != null) { + addPseudoAccount(activity, host_original, isMisskey = isMisskey) { sa -> conversationLocal(activity, pos, sa, status_id_original) } } @@ -711,8 +713,7 @@ object Action_Toot { dialog.addAction( activity.getString(R.string.open_in_pseudo_account, "?@$host_original") ) { - val sa = addPseudoAccount(activity, host_original) - if(sa != null) { + addPseudoAccount(activity, host_original, isMisskey = isMisskey) { sa -> conversationRemote(activity, pos, sa, url) } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/TootApiClient.kt b/app/src/main/java/jp/juggler/subwaytooter/api/TootApiClient.kt index 8f7b33af..a9c284cd 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/api/TootApiClient.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/api/TootApiClient.kt @@ -118,7 +118,7 @@ class TootApiClient( val DEFAULT_JSON_ERROR_PARSER = { json : JSONObject -> val v = json.opt("error") when(v) { - null,JSONObject.NULL -> null + null, JSONObject.NULL -> null else -> v.toString() } } @@ -1477,29 +1477,34 @@ fun TootApiClient.syncStatus(accessInfo : SavedAccount, urlArg : String) : TootA // これを投稿元タンスのURLに変換しないと、投稿の同期には使えない val m = TootStatus.reStatusPageMisskey.matcher(urlArg) if(m.find()) { - val host = m.group(1) - val client2 = TootApiClient(context, callback = callback) - client2.instance =host - val params = JSONObject().put("uri", urlArg) - val result = client2.request("/api/ap/show", params.toPostRequestBuilder()) - if(result == null || result.error != null) return result - - val obj = parseMisskeyApShow( - TootParser(context, accessInfo,serviceType = ServiceType.MISSKEY), - result.jsonObject - ) as? TootStatus - - if( obj != null ){ - if( host .equals(accessInfo.host,ignoreCase = true)){ + val host = m.group(1) + val noteId = m.group(2) + + val result = TootApiClient(context, callback = callback) + .apply { instance = host } + .request( + "/api/notes/show", + JSONObject() + .put("noteId", noteId) + .toPostRequestBuilder() + ) ?: return null + + val obj = TootParser( + context, + accessInfo, + serviceType = ServiceType.MISSKEY + ).status(result.jsonObject) + + if(obj != null) { + if(host.equals(accessInfo.host, ignoreCase = true)) { result.data = obj return result } val uri = obj.uri - if(uri?.isNotEmpty() == true){ + if(uri?.isNotEmpty() == true) { url = uri } } - } return if(accessInfo.isMisskey) {