(Misskey)フォローボタンの表示でリクエスト申請中状態を表示する。フォローリクエストの申請者からの取り消し操作。検索カラムでタンスの検索APIを利用できる。

This commit is contained in:
tateisu 2018-08-29 01:24:36 +09:00
parent f82f139bd5
commit 658f228bd1
12 changed files with 239 additions and 51 deletions

View File

@ -275,7 +275,9 @@ class ActMain : AppCompatActivity()
val unfollow_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.unfollow_succeeded)
}
val cancel_follow_request_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.follow_request_cancelled)
}
val favourite_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.favourite_succeeded)
}

View File

@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong
import java.util.regex.Pattern
import kotlin.collections.ArrayList
enum class StreamingIndicatorState {
NONE,
@ -1441,8 +1442,8 @@ class Column(
return if(bForceReload || this.who_account == null) {
if(isMisskey) {
val params = JSONObject()
params.put("userId", profile_id)
val params = access_info.putMisskeyApiToken(JSONObject())
.put("userId", profile_id)
val result = client.request(PATH_MISSKEY_PROFILE, params.toPostRequestBuilder())
val parser = TootParser(
context,
@ -2362,7 +2363,49 @@ class Column(
}
TYPE_SEARCH -> {
TYPE_SEARCH -> if(isMisskey){
var result : TootApiResult? = null
val parser = TootParser(context,access_info)
var params:JSONObject
list_tmp = ArrayList()
val queryTag = search_query.trim().replace("^#".toRegex(),"")
if(queryTag.isNotEmpty() ){
params = access_info.putMisskeyApiToken(JSONObject())
.put("query",queryTag)
result = client.request("/api/hashtags/search",params.toPostRequestBuilder())
val jsonArray = result?.jsonArray
if( jsonArray != null){
val src = TootTag.parseTootTagList(parser,jsonArray)
list_tmp = addAll(list_tmp, src)
}
}
val queryAccount = search_query.trim().replace("^@".toRegex(),"")
if(queryAccount.isNotEmpty() ){
params = access_info.putMisskeyApiToken(JSONObject())
.put("query",queryAccount)
result = client.request("/api/users/search",params.toPostRequestBuilder())
val jsonArray = result?.jsonArray
if( jsonArray != null){
val src = TootParser(context,access_info).accountList(jsonArray)
list_tmp = addAll(list_tmp, src)
}
}
if(search_query.isNotEmpty() ){
params = access_info.putMisskeyApiToken(JSONObject())
.put("query",search_query)
result = client.request("/api/notes/search",params.toPostRequestBuilder())
val jsonArray = result?.jsonArray
if( jsonArray != null){
val src = parser.statusList(jsonArray)
list_tmp = addWithFilterStatus(list_tmp, src)
}
}
return result
}else{
if(access_info.isPseudo) {
// 1.5.0rc からマストドンの検索APIは認証を要求するようになった
return TootApiResult(context.getString(R.string.search_is_not_available_on_pseudo_account))

View File

@ -400,15 +400,26 @@ internal class DlgContextMenu(
}
R.id.btnFollow ->
if(access_info.isPseudo) {
Action_Follow.followFromAnotherAccount(activity, pos, access_info, who)
} else {
val bSet = ! (relation.getFollowing(who) || relation.getRequested(who))
Action_Follow.follow(
when {
access_info.isPseudo -> Action_Follow.followFromAnotherAccount(activity, pos, access_info, who)
access_info.isMisskey && relation.getRequested(who) && !relation.getFollowing(who) -> Action_Follow.deleteFollowRequest(
activity, pos, access_info, whoRef,
bFollow = bSet,
callback = if(bSet) activity.follow_complete_callback else activity.unfollow_complete_callback
callback = activity.cancel_follow_request_complete_callback
)
else -> {
val bSet = !(relation.getRequested(who) || relation.getFollowing(who) )
Action_Follow.follow(
activity, pos, access_info, whoRef,
bFollow = bSet,
callback = when(bSet) {
true -> activity.follow_complete_callback
else -> activity.unfollow_complete_callback
}
)
}
}
R.id.btnAccountText ->

View File

@ -276,6 +276,15 @@ internal class StatusButtons(
// 何もしない
}
access_info.isMisskey && relation.getRequested(account) && !relation.getFollowing(account) ->
Action_Follow.deleteFollowRequest(
activity,
activity.nextPosition(column),
access_info,
accountRef,
callback = activity.cancel_follow_request_complete_callback
)
relation.getFollowing(account) || relation.getRequested(account) -> {
// フォロー解除
Action_Follow.follow(

View File

@ -176,6 +176,7 @@ object Action_Follow {
TootTaskRunner(activity, TootTaskRunner.PROGRESS_NONE).run(access_info, object : TootTask {
var relation : UserRelation? = null
override fun background(client : TootApiClient) : TootApiResult? {
var result : TootApiResult?
@ -187,12 +188,13 @@ object Action_Follow {
// リモートユーザの同期
if(who.acct.contains("@")) {
val params = access_info.putMisskeyApiToken(JSONObject())
.put("username", who.username)
.put("host", who.host)
result = client.request("/api/users/show", params.toPostRequestBuilder())
val user = parser.account(result?.jsonObject) ?: return result
userId = user.id
result = client.syncAccountByAcct(access_info, who.acct)
val user = result?.data as? TootAccount
if(user != null) {
userId = user.id
} else {
return result
}
}
val params = access_info.putMisskeyApiToken(JSONObject())
@ -203,22 +205,23 @@ object Action_Follow {
else -> "/api/following/delete"
}, params.toPostRequestBuilder()
)
if(result?.error?.contains("already following") == true){
if(result?.error?.contains("already following") == true) {
// DBから読み直す
this.relation = UserRelation.load(access_info.db_id,userId).apply{
this.relation = UserRelation.load(access_info.db_id, userId).apply {
following = true
}
}else if(result?.error?.contains("already not following") == true){
} else if(result?.error?.contains("already not following") == true) {
// DBから読み直す
this.relation = UserRelation.load(access_info.db_id,userId).apply{
this.relation = UserRelation.load(access_info.db_id, userId).apply {
following = false
}
} else {
// parserに残ってるRelationをDBに保存する
val user = parser.account(result?.jsonObject) ?: return result
this.relation = saveUserRelationMisskey(access_info,user.id,parser)
this.relation = saveUserRelationMisskey(access_info, user.id, parser)
}
} else {
if(bFollow and who.acct.contains("@")) {
@ -247,12 +250,12 @@ object Action_Follow {
)
)
result = client.request(
"/api/v1/accounts/${who.id}/${ if(bFollow) "follow" else "unfollow" }"
"/api/v1/accounts/${who.id}/${if(bFollow) "follow" else "unfollow"}"
, request_builder
)
val newRelation = parseItem(::TootRelationShip, result?.jsonObject )
val newRelation = parseItem(::TootRelationShip, result?.jsonObject)
if(newRelation != null) {
relation = saveUserRelation(access_info,newRelation)
relation = saveUserRelation(access_info, newRelation)
}
}
}
@ -267,8 +270,6 @@ object Action_Follow {
val relation = this.relation
if(relation != null) {
if(bFollow && relation.getRequested(who)) {
// 鍵付きアカウントにフォローリクエストを申請した状態
showToast(activity, false, R.string.follow_requested)
@ -277,8 +278,6 @@ object Action_Follow {
} else {
// ローカル操作成功、もしくはリモートフォロー成功
if(callback != null) callback()
}
@ -294,6 +293,110 @@ object Action_Follow {
})
}
fun deleteFollowRequest(
activity : ActMain,
pos : Int,
access_info : SavedAccount,
whoRef : TootAccountRef,
bConfirmed : Boolean = false,
callback : EmptyCallback? = null
) {
if(!access_info.isMisskey){
follow(
activity,
pos,
access_info,
whoRef,
bFollow = false,
bConfirmed = bConfirmed,
callback = callback
)
return
}
val who = whoRef.get()
if(access_info.isMe(who)) {
showToast(activity, false, R.string.it_is_you)
return
}
if(! bConfirmed) {
DlgConfirm.openSimple(
activity,
activity.getString(
R.string.confirm_cancel_follow_request_who_from,
whoRef.decoded_display_name,
AcctColor.getNickname(access_info.acct)
)
){
deleteFollowRequest(
activity,
pos,
access_info,
whoRef,
bConfirmed = true, // CHANGED
callback = callback
)
}
return
}
TootTaskRunner(activity, TootTaskRunner.PROGRESS_NONE).run(access_info, object : TootTask {
var relation : UserRelation? = null
override fun background(client : TootApiClient) : TootApiResult? {
var result : TootApiResult? =null
val parser = TootParser(activity, access_info)
if(access_info.isMisskey) {
var userId : EntityId = who.id
// リモートユーザの同期
if(who.acct.contains("@")) {
result = client.syncAccountByAcct(access_info, who.acct)
val user = result?.data as? TootAccount
if(user != null) {
userId = user.id
} else {
return result
}
}
val params = access_info.putMisskeyApiToken(JSONObject())
.put("userId", userId)
result = client.request("/api/following/requests/cancel"
, params.toPostRequestBuilder()
)
// parserに残ってるRelationをDBに保存する
val user = parser.account(result?.jsonObject) ?: return result
this.relation = saveUserRelationMisskey(access_info, user.id, parser)
}
return result
}
override fun handleResult(result : TootApiResult?) {
if(result == null) return // cancelled.
val relation = this.relation
if(relation != null) {
// ローカル操作成功、もしくはリモートフォロー成功
if(callback != null) callback()
activity.showColumnMatchAccount(access_info)
} else {
showToast(activity, false, result.error)
}
}
})
}
// acct で指定したユーザをリモートフォローする
fun followRemote(
activity : ActMain,
@ -376,15 +479,15 @@ object Action_Follow {
var remote_who : TootAccount? = null
var relation : UserRelation? = null
override fun background(client : TootApiClient) : TootApiResult? {
val parser = TootParser(activity,access_info)
var result:TootApiResult?
val parser = TootParser(activity, access_info)
var result : TootApiResult?
if(access_info.isMisskey) {
val delimiter = acct.indexOf('@')
val username = acct.substring(0,delimiter)
val host = acct.substring(delimiter+1)
val username = acct.substring(0, delimiter)
val host = acct.substring(delimiter + 1)
// リモートユーザの同期
var params = access_info.putMisskeyApiToken(JSONObject())
@ -396,7 +499,7 @@ object Action_Follow {
params = access_info.putMisskeyApiToken(JSONObject())
.put("userId", userId)
result = client.request(
"/api/following/create",
params.toPostRequestBuilder()
@ -406,13 +509,13 @@ object Action_Follow {
|| result?.error?.contains("already not following") == true
) {
// DBから読み直して値を変更する
this.relation = UserRelation.load(access_info.db_id,userId).apply{
this.relation = UserRelation.load(access_info.db_id, userId).apply {
following = true
}
} else {
// parserに残ってるRelationをDBに保存する
user = parser.account(result?.jsonObject) ?: return result
this.relation = saveUserRelationMisskey(access_info,user.id,parser)
this.relation = saveUserRelationMisskey(access_info, user.id, parser)
}
} else {
@ -430,7 +533,7 @@ object Action_Follow {
result = rr.result
relation = rr.relation
}
}
return result
@ -523,15 +626,15 @@ object Action_Follow {
TootTaskRunner(activity).run(access_info, object : TootTask {
override fun background(client : TootApiClient) : TootApiResult? {
if( access_info.isMisskey){
if(access_info.isMisskey) {
val params = access_info.putMisskeyApiToken(JSONObject())
.put("userId",who.id )
.put("userId", who.id)
return client.request(
"/api/following/requests/${if(bAllow) "accept" else "reject"}",
params.toPostRequestBuilder()
)
}else{
} else {
val request_builder = Request.Builder().post(
RequestBody.create(
TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED, "" // 空データ

View File

@ -76,7 +76,7 @@ object Action_Toot {
}
// 必要なら確認を出す
if(! bConfirmed) {
if(! bConfirmed && !access_info.isMisskey) {
DlgConfirm.open(
activity,
activity.getString(

View File

@ -20,7 +20,7 @@ class TootResults(parser : TootParser, src : JSONObject) {
init {
accounts = parser.accountList(src.optJSONArray("accounts"))
statuses = parser.statusList(src.optJSONArray("statuses"))
hashtags = TootTag.parseTootTagList(src.optJSONArray("hashtags"))
hashtags = TootTag.parseTootTagList(parser,src.optJSONArray("hashtags"))
}
}

View File

@ -1,5 +1,6 @@
package jp.juggler.subwaytooter.api.entity
import jp.juggler.subwaytooter.api.TootParser
import jp.juggler.subwaytooter.util.notEmptyOrThrow
import jp.juggler.subwaytooter.util.parseString
@ -19,14 +20,27 @@ open class TootTag(
)
companion object {
// 検索結果のhashtagリストから生成する
fun parseTootTagList(array : JSONArray?) : ArrayList<TootTag> {
fun parseTootTagList(parser:TootParser,array : JSONArray?) : ArrayList<TootTag> {
val result = ArrayList<TootTag>()
if(array != null) {
for(i in 0 until array.length()) {
val sv = array.parseString(i)
if(sv?.isNotEmpty() == true) {
result.add(TootTag(name = sv))
if( parser.serviceType == ServiceType.MISSKEY){
if(array != null) {
for(i in 0 until array.length()) {
val sv = array.parseString(i)
if(sv?.isNotEmpty() == true) {
result.add(TootTag(name = sv))
}
}
}
}else {
if(array != null) {
for(i in 0 until array.length()) {
val sv = array.parseString(i)
if(sv?.isNotEmpty() == true) {
result.add(TootTag(name = sv))
}
}
}
}

View File

@ -247,6 +247,7 @@ class UserRelation {
muting = src.optBoolean("isMuted")
blocking = false
endorsed = false
requested = src.optBoolean("hasPendingFollowRequestFromYou")
}
}

View File

@ -783,6 +783,8 @@
<string name="endorse_unset">Remove endorsement in your profile</string>
<string name="endorse_succeeded">Endorsement added.</string>
<string name="remove_endorse_succeeded">Endorsement removed.</string>
<string name="follow_request_cancelled">Follow request was cancelled.</string>
<string name="confirm_cancel_follow_request_who_from">Follow request from %2$s to %1$s will be cancelled. Are you sure?</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

@ -1059,5 +1059,7 @@
<string name="endorse_unset">「プロフィールに紹介」を取り消す</string>
<string name="endorse_succeeded">紹介を追加しました</string>
<string name="remove_endorse_succeeded">紹介を削除しました</string>
<string name="follow_request_cancelled">フォローリクエストを取り消しました</string>
<string name="confirm_cancel_follow_request_who_from">%2$s から %1$s へのフォローリクエストを取り消します。よろしいですか?</string>
</resources>

View File

@ -768,6 +768,7 @@
<string name="endorse_unset">Remove endorsement in your profile</string>
<string name="endorse_succeeded">Endorsement added.</string>
<string name="remove_endorse_succeeded">Endorsement removed.</string>
<string name="follow_request_cancelled">Follow request was cancelled.</string>
<string name="confirm_cancel_follow_request_who_from">Follow request from %2$s to %1$s will be cancelled. Are you sure?</string>
</resources>