mirror of
https://github.com/tateisu/SubwayTooter
synced 2025-02-07 06:04:23 +01:00
(Misskey)投稿のコンテキストメニューから引用リノート。別アカ選択あり。引用リノートで投稿画面を開いたらCWやメンションを引き継がない。(Misskey)投稿のURLをタップした時にアプリ内で開く。(Misskey)外部タンスの投稿を複製したURLを別のタンスに同期する際、投稿元タンスでのuriを取得してから目的のタンスに同期する
This commit is contained in:
parent
b3bf3a878e
commit
0275edfdbc
@ -85,11 +85,9 @@ class ActMain : AppCompatActivity()
|
|||||||
internal var sent_intent2 : Intent? = null
|
internal var sent_intent2 : Intent? = null
|
||||||
|
|
||||||
internal val reUrlHashTag =
|
internal val reUrlHashTag =
|
||||||
Pattern.compile("\\Ahttps://([^/]+)/tags/([^?#・\\s\\-+.,:;/]+)(?:\\z|[?#])")
|
Pattern.compile("""\Ahttps://([^/]+)/tags/([^?#・\s\-+.,:;/]+)(?:\z|[?#])""")
|
||||||
|
|
||||||
@Suppress("HasPlatformType")
|
|
||||||
val reStatusPage = Pattern.compile("\\Ahttps://([^/]+)/@([A-Za-z0-9_]+)/(\\d+)(?:\\z|[?#])")
|
|
||||||
|
|
||||||
|
|
||||||
var boostButtonSize = 0
|
var boostButtonSize = 0
|
||||||
var timeline_font : Typeface = Typeface.DEFAULT
|
var timeline_font : Typeface = Typeface.DEFAULT
|
||||||
var timeline_font_bold : Typeface = Typeface.DEFAULT_BOLD
|
var timeline_font_bold : Typeface = Typeface.DEFAULT_BOLD
|
||||||
@ -1557,10 +1555,10 @@ class ActMain : AppCompatActivity()
|
|||||||
|
|
||||||
val url = uri.toString()
|
val url = uri.toString()
|
||||||
|
|
||||||
var m = reStatusPage.matcher(url)
|
// https://mastodon.juggler.jp/@SubwayTooter/(status_id)
|
||||||
|
var m = TootStatus.reStatusPage.matcher(url)
|
||||||
if(m.find()) {
|
if(m.find()) {
|
||||||
try {
|
try {
|
||||||
// https://mastodon.juggler.jp/@SubwayTooter/(status_id)
|
|
||||||
val host = m.group(1)
|
val host = m.group(1)
|
||||||
val status_id = EntityIdLong(m.group(3).toLong(10))
|
val status_id = EntityIdLong(m.group(3).toLong(10))
|
||||||
// ステータスをアプリ内で開く
|
// ステータスをアプリ内で開く
|
||||||
@ -1579,6 +1577,28 @@ class ActMain : AppCompatActivity()
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://misskey.xyz/notes/(id)
|
||||||
|
m = TootStatus.reStatusPageMisskey.matcher(url)
|
||||||
|
if(m.find()) {
|
||||||
|
try {
|
||||||
|
val host = m.group(1)
|
||||||
|
val status_id = EntityIdString(m.group(2))
|
||||||
|
// ステータスをアプリ内で開く
|
||||||
|
Action_Toot.conversationOtherInstance(
|
||||||
|
this@ActMain,
|
||||||
|
defaultInsertPosition,
|
||||||
|
url,
|
||||||
|
status_id,
|
||||||
|
host,
|
||||||
|
status_id
|
||||||
|
)
|
||||||
|
} catch(ex : Throwable) {
|
||||||
|
showToast(this, ex, "can't parse status id.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// ユーザページをアプリ内で開く
|
// ユーザページをアプリ内で開く
|
||||||
m = TootAccount.reAccountUrl.matcher(url)
|
m = TootAccount.reAccountUrl.matcher(url)
|
||||||
if(m.find()) {
|
if(m.find()) {
|
||||||
@ -2204,7 +2224,7 @@ class ActMain : AppCompatActivity()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ステータスページをアプリから開く
|
// ステータスページをアプリから開く
|
||||||
m = reStatusPage.matcher(opener.url)
|
m = TootStatus.reStatusPage.matcher(opener.url)
|
||||||
if(m.find()) {
|
if(m.find()) {
|
||||||
try {
|
try {
|
||||||
// https://mastodon.juggler.jp/@SubwayTooter/(status_id)
|
// https://mastodon.juggler.jp/@SubwayTooter/(status_id)
|
||||||
@ -2234,6 +2254,37 @@ class ActMain : AppCompatActivity()
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ステータスページをアプリから開く
|
||||||
|
m = TootStatus.reStatusPageMisskey.matcher(opener.url)
|
||||||
|
if(m.find()) {
|
||||||
|
try {
|
||||||
|
// https://misskey.xyz/notes/(id)
|
||||||
|
val host = m.group(1)
|
||||||
|
val status_id = EntityIdString(m.group(2))
|
||||||
|
if(accessInto.isNA || ! host.equals(accessInto.host, ignoreCase = true)) {
|
||||||
|
Action_Toot.conversationOtherInstance(
|
||||||
|
this@ActMain,
|
||||||
|
opener.pos,
|
||||||
|
opener.url,
|
||||||
|
status_id,
|
||||||
|
host,
|
||||||
|
status_id
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Action_Toot.conversationLocal(
|
||||||
|
this@ActMain,
|
||||||
|
opener.pos,
|
||||||
|
accessInto,
|
||||||
|
status_id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch(ex : Throwable) {
|
||||||
|
showToast(this, ex, "can't parse status id.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// ユーザページをアプリ内で開く
|
// ユーザページをアプリ内で開く
|
||||||
m = TootAccount.reAccountUrl.matcher(opener.url)
|
m = TootAccount.reAccountUrl.matcher(opener.url)
|
||||||
if(m.find()) {
|
if(m.find()) {
|
||||||
|
@ -69,6 +69,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
internal const val KEY_REDRAFT_STATUS = "redraft_status"
|
internal const val KEY_REDRAFT_STATUS = "redraft_status"
|
||||||
internal const val KEY_INITIAL_TEXT = "initial_text"
|
internal const val KEY_INITIAL_TEXT = "initial_text"
|
||||||
internal const val KEY_SENT_INTENT = "sent_intent"
|
internal const val KEY_SENT_INTENT = "sent_intent"
|
||||||
|
internal const val KEY_QUOTED_RENOTE = "quoted_renote"
|
||||||
|
|
||||||
internal const val KEY_ATTACHMENT_LIST = "attachment_list"
|
internal const val KEY_ATTACHMENT_LIST = "attachment_list"
|
||||||
internal const val KEY_VISIBILITY = "visibility"
|
internal const val KEY_VISIBILITY = "visibility"
|
||||||
@ -104,24 +105,27 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val imageHeaderList = arrayOf(
|
private val imageHeaderList = arrayOf(
|
||||||
Pair("image/jpeg",intArrayOf(0xff,0xd8,0xff,0xe0).toByteArray()),
|
Pair("image/jpeg", intArrayOf(0xff, 0xd8, 0xff, 0xe0).toByteArray()),
|
||||||
Pair("image/png",intArrayOf(0x89 ,0x50 ,0x4E ,0x47 ,0x0D ,0x0A ,0x1A ,0x0A).toByteArray()),
|
Pair(
|
||||||
Pair("image/gif", charArrayOf('G' ,'I' ,'F').toByteArray())
|
"image/png",
|
||||||
|
intArrayOf(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A).toByteArray()
|
||||||
|
),
|
||||||
|
Pair("image/gif", charArrayOf('G', 'I', 'F').toByteArray())
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun checkImageHeaderList(contentResolver:ContentResolver, uri : Uri) : String? {
|
private fun checkImageHeaderList(contentResolver : ContentResolver, uri : Uri) : String? {
|
||||||
try{
|
try {
|
||||||
contentResolver.openInputStream(uri)?.use{ inStream ->
|
contentResolver.openInputStream(uri)?.use { inStream ->
|
||||||
val data = ByteArray(32)
|
val data = ByteArray(32)
|
||||||
val nRead = inStream.read(data,0,data.size)
|
val nRead = inStream.read(data, 0, data.size)
|
||||||
for( pair in imageHeaderList ){
|
for(pair in imageHeaderList) {
|
||||||
val type = pair.first
|
val type = pair.first
|
||||||
val header = pair.second
|
val header = pair.second
|
||||||
if( nRead >= header.size && data.startWith(header) ) return type
|
if(nRead >= header.size && data.startWith(header)) return type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch(ex:Throwable){
|
} catch(ex : Throwable) {
|
||||||
log.e(ex,"checkImageHeaderList failed.")
|
log.e(ex, "checkImageHeaderList failed.")
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -175,22 +179,31 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
initial_text : String? = null,
|
initial_text : String? = null,
|
||||||
|
|
||||||
// 外部アプリから共有されたインテント
|
// 外部アプリから共有されたインテント
|
||||||
sent_intent : Intent? = null
|
sent_intent : Intent? = null,
|
||||||
|
|
||||||
|
// (Misskey) 返信を引用リノートにする
|
||||||
|
quotedRenote : Boolean = false
|
||||||
) {
|
) {
|
||||||
val intent = Intent(activity, ActPost::class.java)
|
val intent = Intent(activity, ActPost::class.java)
|
||||||
intent.putExtra(KEY_ACCOUNT_DB_ID, account_db_id)
|
intent.putExtra(KEY_ACCOUNT_DB_ID, account_db_id)
|
||||||
|
|
||||||
if(redraft_status != null) {
|
if(redraft_status != null) {
|
||||||
intent.putExtra(KEY_REDRAFT_STATUS, redraft_status.json.toString())
|
intent.putExtra(KEY_REDRAFT_STATUS, redraft_status.json.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
if(reply_status != null) {
|
if(reply_status != null) {
|
||||||
intent.putExtra(KEY_REPLY_STATUS, reply_status.json.toString())
|
intent.putExtra(KEY_REPLY_STATUS, reply_status.json.toString())
|
||||||
|
intent.putExtra(KEY_QUOTED_RENOTE, quotedRenote)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(initial_text != null) {
|
if(initial_text != null) {
|
||||||
intent.putExtra(KEY_INITIAL_TEXT, initial_text)
|
intent.putExtra(KEY_INITIAL_TEXT, initial_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sent_intent != null) {
|
if(sent_intent != null) {
|
||||||
intent.putExtra(KEY_SENT_INTENT, sent_intent)
|
intent.putExtra(KEY_SENT_INTENT, sent_intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.startActivityForResult(intent, request_code)
|
activity.startActivityForResult(intent, request_code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,14 +333,12 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||||
if(requestCode == REQUEST_CODE_ATTACHMENT_OLD && resultCode == Activity.RESULT_OK) {
|
if(requestCode == REQUEST_CODE_ATTACHMENT_OLD && resultCode == Activity.RESULT_OK) {
|
||||||
data?.handleGetContentResult(contentResolver)?.forEach {
|
data?.handleGetContentResult(contentResolver)?.forEach {
|
||||||
addAttachment(it.first, it.second)
|
addAttachment(it.first, it.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(requestCode == REQUEST_CODE_ATTACHMENT && resultCode == Activity.RESULT_OK) {
|
} else if(requestCode == REQUEST_CODE_ATTACHMENT && resultCode == Activity.RESULT_OK) {
|
||||||
data?.handleGetContentResult(contentResolver)?.forEach {
|
data?.handleGetContentResult(contentResolver)?.forEach {
|
||||||
addAttachment(it.first, it.second)
|
addAttachment(it.first, it.second)
|
||||||
@ -394,7 +405,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
initUI()
|
initUI()
|
||||||
|
|
||||||
// Android 9 から、明示的にフォーカスを当てる必要がある
|
// Android 9 から、明示的にフォーカスを当てる必要がある
|
||||||
if( savedInstanceState==null){
|
if(savedInstanceState == null) {
|
||||||
etContent.requestFocus()
|
etContent.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,45 +547,56 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
if(sv != null && account != null) {
|
if(sv != null && account != null) {
|
||||||
try {
|
try {
|
||||||
val reply_status = TootParser(this@ActPost, account).status(sv.toJsonObject())
|
val reply_status = TootParser(this@ActPost, account).status(sv.toJsonObject())
|
||||||
|
|
||||||
|
val isQuoterRenote = intent.getBooleanExtra(KEY_QUOTED_RENOTE, false)
|
||||||
|
|
||||||
if(reply_status != null) {
|
if(reply_status != null) {
|
||||||
// CW をリプライ元に合わせる
|
|
||||||
if(reply_status.spoiler_text?.isNotEmpty() == true) {
|
|
||||||
cbContentWarning.isChecked = true
|
|
||||||
etContentWarning.setText(reply_status.spoiler_text)
|
|
||||||
}
|
|
||||||
|
|
||||||
val mention_list = ArrayList<String>()
|
if(isQuoterRenote) {
|
||||||
|
cbQuoteRenote.isChecked = true
|
||||||
val old_mentions = reply_status.mentions
|
|
||||||
if(old_mentions != null) {
|
// 引用リノートはCWやメンションを引き継がない
|
||||||
for(mention in old_mentions) {
|
|
||||||
val who_acct = mention.acct
|
}else{
|
||||||
if(who_acct.isNotEmpty()) {
|
|
||||||
if(account.isMe(who_acct)) continue
|
// CW をリプライ元に合わせる
|
||||||
sv = "@" + account.getFullAcct(who_acct)
|
if(reply_status.spoiler_text?.isNotEmpty() == true) {
|
||||||
if(! mention_list.contains(sv)) {
|
cbContentWarning.isChecked = true
|
||||||
mention_list.add(sv)
|
etContentWarning.setText(reply_status.spoiler_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mention_list = ArrayList<String>()
|
||||||
|
|
||||||
|
val old_mentions = reply_status.mentions
|
||||||
|
if(old_mentions != null) {
|
||||||
|
for(mention in old_mentions) {
|
||||||
|
val who_acct = mention.acct
|
||||||
|
if(who_acct.isNotEmpty()) {
|
||||||
|
if(account.isMe(who_acct)) continue
|
||||||
|
sv = "@" + account.getFullAcct(who_acct)
|
||||||
|
if(! mention_list.contains(sv)) {
|
||||||
|
mention_list.add(sv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// 元レスのacctを追加する
|
||||||
// 元レスのacctを追加する
|
val who_acct = account.getFullAcct(reply_status.account)
|
||||||
val who_acct = account.getFullAcct(reply_status.account)
|
if(! account.isMe(reply_status.account) // 自己レスにはメンションを追加しない
|
||||||
if(! account.isMe(reply_status.account) // 自己レスにはメンションを追加しない
|
&& ! mention_list.contains("@$who_acct") // 既に含まれているならメンションを追加しない
|
||||||
&& ! mention_list.contains("@$who_acct") // 既に含まれているならメンションを追加しない
|
) {
|
||||||
) {
|
mention_list.add("@$who_acct")
|
||||||
mention_list.add("@$who_acct")
|
}
|
||||||
}
|
|
||||||
|
val sb = StringBuilder()
|
||||||
val sb = StringBuilder()
|
for(acct in mention_list) {
|
||||||
for(acct in mention_list) {
|
if(sb.isNotEmpty()) sb.append(' ')
|
||||||
if(sb.isNotEmpty()) sb.append(' ')
|
sb.append(acct)
|
||||||
sb.append(acct)
|
}
|
||||||
}
|
if(sb.isNotEmpty()) {
|
||||||
if(sb.isNotEmpty()) {
|
appendContentText(sb.append(' ').toString())
|
||||||
appendContentText(sb.append(' ').toString())
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// リプライ表示をつける
|
// リプライ表示をつける
|
||||||
@ -607,13 +629,10 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
appendContentText(account?.default_text, selectBefore = true)
|
appendContentText(account?.default_text, selectBefore = true)
|
||||||
@ -650,14 +669,14 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
// 再編集の場合はdefault_textは反映されない
|
// 再編集の場合はdefault_textは反映されない
|
||||||
|
|
||||||
val decodeOptions = DecodeOptions(this)
|
val decodeOptions = DecodeOptions(this)
|
||||||
|
|
||||||
var text :Spannable
|
var text : Spannable
|
||||||
|
|
||||||
text = decodeOptions.decodeHTML(base_status.content)
|
text = decodeOptions.decodeHTML(base_status.content)
|
||||||
etContent.text = text
|
etContent.text = text
|
||||||
etContent.setSelection(text.length )
|
etContent.setSelection(text.length)
|
||||||
|
|
||||||
text =decodeOptions.decodeEmoji(base_status.spoiler_text)
|
text = decodeOptions.decodeEmoji(base_status.spoiler_text)
|
||||||
etContentWarning.setText(text)
|
etContentWarning.setText(text)
|
||||||
etContentWarning.setSelection(text.length)
|
etContentWarning.setSelection(text.length)
|
||||||
cbContentWarning.isChecked = text.isNotEmpty()
|
cbContentWarning.isChecked = text.isNotEmpty()
|
||||||
@ -716,7 +735,6 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
showQuotedRenote()
|
showQuotedRenote()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
post_helper.onDestroy()
|
post_helper.onDestroy()
|
||||||
|
|
||||||
@ -783,8 +801,8 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
if(svEmoji.isEmpty()) return
|
if(svEmoji.isEmpty()) return
|
||||||
|
|
||||||
val editable = etContent.text
|
val editable = etContent.text
|
||||||
if( editable == null ) {
|
if(editable == null) {
|
||||||
val sb = StringBuilder ()
|
val sb = StringBuilder()
|
||||||
if(selectBefore) {
|
if(selectBefore) {
|
||||||
val start = 0
|
val start = 0
|
||||||
sb.append(' ')
|
sb.append(' ')
|
||||||
@ -796,7 +814,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
etContent.setText(sb)
|
etContent.setText(sb)
|
||||||
etContent.setSelection(sb.length)
|
etContent.setSelection(sb.length)
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
if(editable.isNotEmpty()
|
if(editable.isNotEmpty()
|
||||||
&& ! CharacterGroup.isWhitespace(editable[editable.length - 1].toInt())
|
&& ! CharacterGroup.isWhitespace(editable[editable.length - 1].toInt())
|
||||||
) {
|
) {
|
||||||
@ -860,7 +878,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
etContentWarning = findViewById(R.id.etContentWarning)
|
etContentWarning = findViewById(R.id.etContentWarning)
|
||||||
etContent = findViewById(R.id.etContent)
|
etContent = findViewById(R.id.etContent)
|
||||||
|
|
||||||
cbQuoteRenote= findViewById(R.id.cbQuoteRenote)
|
cbQuoteRenote = findViewById(R.id.cbQuoteRenote)
|
||||||
|
|
||||||
cbEnquete = findViewById(R.id.cbEnquete)
|
cbEnquete = findViewById(R.id.cbEnquete)
|
||||||
llEnquete = findViewById(R.id.llEnquete)
|
llEnquete = findViewById(R.id.llEnquete)
|
||||||
@ -895,10 +913,10 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
btnPost.setOnClickListener(this)
|
btnPost.setOnClickListener(this)
|
||||||
btnRemoveReply.setOnClickListener(this)
|
btnRemoveReply.setOnClickListener(this)
|
||||||
|
|
||||||
val btnPlugin :ImageButton = findViewById(R.id.btnPlugin)
|
val btnPlugin : ImageButton = findViewById(R.id.btnPlugin)
|
||||||
val btnEmojiPicker :ImageButton = findViewById(R.id.btnEmojiPicker)
|
val btnEmojiPicker : ImageButton = findViewById(R.id.btnEmojiPicker)
|
||||||
val btnMore: ImageButton = findViewById(R.id.btnMore)
|
val btnMore : ImageButton = findViewById(R.id.btnMore)
|
||||||
|
|
||||||
btnPlugin.setOnClickListener(this)
|
btnPlugin.setOnClickListener(this)
|
||||||
btnEmojiPicker.setOnClickListener(this)
|
btnEmojiPicker.setOnClickListener(this)
|
||||||
btnMore.setOnClickListener(this)
|
btnMore.setOnClickListener(this)
|
||||||
@ -909,11 +927,11 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
iv.setErrorImageResId(Styler.getAttributeResourceId(this, R.attr.ic_unknown))
|
iv.setErrorImageResId(Styler.getAttributeResourceId(this, R.attr.ic_unknown))
|
||||||
}
|
}
|
||||||
|
|
||||||
setIcon(btnPost,R.drawable.btn_post)
|
setIcon(btnPost, R.drawable.btn_post)
|
||||||
setIcon(btnMore,R.drawable.btn_more)
|
setIcon(btnMore, R.drawable.btn_more)
|
||||||
setIcon(btnPlugin,R.drawable.ic_plugin)
|
setIcon(btnPlugin, R.drawable.ic_plugin)
|
||||||
setIcon(btnEmojiPicker,R.drawable.ic_face)
|
setIcon(btnEmojiPicker, R.drawable.ic_face)
|
||||||
setIcon(btnAttachment,R.drawable.btn_attachment)
|
setIcon(btnAttachment, R.drawable.btn_attachment)
|
||||||
|
|
||||||
cbContentWarning.setOnCheckedChangeListener { _, _ ->
|
cbContentWarning.setOnCheckedChangeListener { _, _ ->
|
||||||
updateContentWarning()
|
updateContentWarning()
|
||||||
@ -946,15 +964,15 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
etContent.contentMineTypeArray =
|
etContent.contentMineTypeArray =
|
||||||
acceptable_mime_types.toArray(arrayOfNulls<String>(ActPost.acceptable_mime_types.size))
|
acceptable_mime_types.toArray(arrayOfNulls<String>(ActPost.acceptable_mime_types.size))
|
||||||
etContent.commitContentListener = commitContentListener
|
etContent.commitContentListener = commitContentListener
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setIcon(iv:ImageView,drawableId:Int) {
|
private fun setIcon(iv : ImageView, drawableId : Int) {
|
||||||
Styler.setIconDrawableId(
|
Styler.setIconDrawableId(
|
||||||
this,
|
this,
|
||||||
iv,
|
iv,
|
||||||
drawableId,
|
drawableId,
|
||||||
Styler.getAttributeColor(this,R.attr.colorColumnHeaderName)
|
Styler.getAttributeColor(this, R.attr.colorColumnHeaderName)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1049,7 +1067,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
post_helper.setInstance(a.host, a.isMisskey)
|
post_helper.setInstance(a.host, a.isMisskey)
|
||||||
|
|
||||||
// 先読みしてキャッシュに保持しておく
|
// 先読みしてキャッシュに保持しておく
|
||||||
App1.custom_emoji_lister.getList(a.host,a.isMisskey) {
|
App1.custom_emoji_lister.getList(a.host, a.isMisskey) {
|
||||||
// 何もしない
|
// 何もしない
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1447,7 +1465,6 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun performAttachmentOld() {
|
private fun performAttachmentOld() {
|
||||||
// SAFのIntentで開く
|
// SAFのIntentで開く
|
||||||
try {
|
try {
|
||||||
@ -1562,13 +1579,13 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
|
|
||||||
// image/j()pg だの image/j(e)pg だの、mime type を誤記するアプリがあまりに多い
|
// image/j()pg だの image/j(e)pg だの、mime type を誤記するアプリがあまりに多い
|
||||||
// クレームで消耗するのを減らすためにファイルヘッダを確認する
|
// クレームで消耗するのを減らすためにファイルヘッダを確認する
|
||||||
if(mimeTypeArg == null || mimeTypeArg.startsWith("image/")){
|
if(mimeTypeArg == null || mimeTypeArg.startsWith("image/")) {
|
||||||
val sv = checkImageHeaderList(contentResolver,uri)
|
val sv = checkImageHeaderList(contentResolver, uri)
|
||||||
if( sv != null) return sv
|
if(sv != null) return sv
|
||||||
}
|
}
|
||||||
|
|
||||||
// 既に引数で与えられてる
|
// 既に引数で与えられてる
|
||||||
if(mimeTypeArg?.isNotEmpty() == true){
|
if(mimeTypeArg?.isNotEmpty() == true) {
|
||||||
return mimeTypeArg
|
return mimeTypeArg
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1583,8 +1600,6 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private fun addAttachment(
|
private fun addAttachment(
|
||||||
uri : Uri,
|
uri : Uri,
|
||||||
@ -1882,11 +1897,13 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showVisibility() {
|
private fun showVisibility() {
|
||||||
setIcon(btnVisibility,Styler.getVisibilityIcon(
|
setIcon(
|
||||||
this
|
btnVisibility, Styler.getVisibilityIcon(
|
||||||
, account?.isMisskey == true
|
this
|
||||||
, visibility ?: TootVisibility.Public
|
, account?.isMisskey == true
|
||||||
))
|
, visibility ?: TootVisibility.Public
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performVisibility() {
|
private fun performVisibility() {
|
||||||
@ -1999,7 +2016,8 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
|
|
||||||
post_helper.attachment_list = this.attachment_list
|
post_helper.attachment_list = this.attachment_list
|
||||||
|
|
||||||
post_helper.emojiMapCustom = App1.custom_emoji_lister.getMap(account.host,account.isMisskey)
|
post_helper.emojiMapCustom =
|
||||||
|
App1.custom_emoji_lister.getMap(account.host, account.isMisskey)
|
||||||
|
|
||||||
post_helper.redraft_status_id = redraft_status_id
|
post_helper.redraft_status_id = redraft_status_id
|
||||||
|
|
||||||
@ -2020,7 +2038,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
private fun showQuotedRenote() {
|
private fun showQuotedRenote() {
|
||||||
val isReply = in_reply_to_id != null
|
val isReply = in_reply_to_id != null
|
||||||
val isMisskey = account?.isMisskey == true
|
val isMisskey = account?.isMisskey == true
|
||||||
cbQuoteRenote.visibility = if( isReply && isMisskey ) View.VISIBLE else View.GONE
|
cbQuoteRenote.visibility = if(isReply && isMisskey) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun showReplyTo() {
|
internal fun showReplyTo() {
|
||||||
@ -2092,7 +2110,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
json.put(DRAFT_REPLY_IMAGE, in_reply_to_image)
|
json.put(DRAFT_REPLY_IMAGE, in_reply_to_image)
|
||||||
json.put(DRAFT_REPLY_URL, in_reply_to_url)
|
json.put(DRAFT_REPLY_URL, in_reply_to_url)
|
||||||
|
|
||||||
json.put(DRAFT_QUOTED_RENOTE,cbQuoteRenote.isChecked)
|
json.put(DRAFT_QUOTED_RENOTE, cbQuoteRenote.isChecked)
|
||||||
json.put(DRAFT_IS_ENQUETE, isEnquete)
|
json.put(DRAFT_IS_ENQUETE, isEnquete)
|
||||||
|
|
||||||
val array = JSONArray()
|
val array = JSONArray()
|
||||||
@ -2246,7 +2264,6 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
val draft_visibility = TootVisibility
|
val draft_visibility = TootVisibility
|
||||||
.parseSavedVisibility(draft.parseString(DRAFT_VISIBILITY))
|
.parseSavedVisibility(draft.parseString(DRAFT_VISIBILITY))
|
||||||
|
|
||||||
|
|
||||||
val evEmoji = DecodeOptions(this@ActPost, decodeEmoji = true).decodeEmoji(content)
|
val evEmoji = DecodeOptions(this@ActPost, decodeEmoji = true).decodeEmoji(content)
|
||||||
etContent.setText(evEmoji)
|
etContent.setText(evEmoji)
|
||||||
etContent.setSelection(evEmoji.length)
|
etContent.setSelection(evEmoji.length)
|
||||||
@ -2296,7 +2313,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
|||||||
in_reply_to_image = reply_image
|
in_reply_to_image = reply_image
|
||||||
in_reply_to_url = reply_url
|
in_reply_to_url = reply_url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
updateContentWarning()
|
updateContentWarning()
|
||||||
showMediaAttachment()
|
showMediaAttachment()
|
||||||
|
@ -2,7 +2,6 @@ package jp.juggler.subwaytooter
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.graphics.PorterDuff
|
|
||||||
import android.support.v4.app.ShareCompat
|
import android.support.v4.app.ShareCompat
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -68,6 +67,7 @@ internal class DlgContextMenu(
|
|||||||
val btnBoostAnotherAccount = viewRoot.findViewById<View>(R.id.btnBoostAnotherAccount)
|
val btnBoostAnotherAccount = viewRoot.findViewById<View>(R.id.btnBoostAnotherAccount)
|
||||||
val btnReactionAnotherAccount = viewRoot.findViewById<View>(R.id.btnReactionAnotherAccount)
|
val btnReactionAnotherAccount = viewRoot.findViewById<View>(R.id.btnReactionAnotherAccount)
|
||||||
val btnReplyAnotherAccount = viewRoot.findViewById<View>(R.id.btnReplyAnotherAccount)
|
val btnReplyAnotherAccount = viewRoot.findViewById<View>(R.id.btnReplyAnotherAccount)
|
||||||
|
val btnQuotedRenote = viewRoot.findViewById<View>(R.id.btnQuotedRenote)
|
||||||
val btnDelete = viewRoot.findViewById<View>(R.id.btnDelete)
|
val btnDelete = viewRoot.findViewById<View>(R.id.btnDelete)
|
||||||
val btnRedraft = viewRoot.findViewById<View>(R.id.btnRedraft)
|
val btnRedraft = viewRoot.findViewById<View>(R.id.btnRedraft)
|
||||||
|
|
||||||
@ -124,6 +124,7 @@ internal class DlgContextMenu(
|
|||||||
btnBoostAnotherAccount.setOnClickListener(this)
|
btnBoostAnotherAccount.setOnClickListener(this)
|
||||||
btnReactionAnotherAccount.setOnClickListener(this)
|
btnReactionAnotherAccount.setOnClickListener(this)
|
||||||
btnReplyAnotherAccount.setOnClickListener(this)
|
btnReplyAnotherAccount.setOnClickListener(this)
|
||||||
|
btnQuotedRenote.setOnClickListener(this)
|
||||||
btnReport.setOnClickListener(this)
|
btnReport.setOnClickListener(this)
|
||||||
btnMuteApp.setOnClickListener(this)
|
btnMuteApp.setOnClickListener(this)
|
||||||
btnDelete.setOnClickListener(this)
|
btnDelete.setOnClickListener(this)
|
||||||
@ -728,7 +729,12 @@ internal class DlgContextMenu(
|
|||||||
access_info,
|
access_info,
|
||||||
status
|
status
|
||||||
)
|
)
|
||||||
|
R.id.btnQuotedRenote-> Action_Toot.replyFromAnotherAccount(
|
||||||
|
activity,
|
||||||
|
access_info,
|
||||||
|
status,
|
||||||
|
quotedRenote = true
|
||||||
|
)
|
||||||
R.id.btnConversationAnotherAccount -> status?.let { status ->
|
R.id.btnConversationAnotherAccount -> status?.let { status ->
|
||||||
Action_Toot.conversationOtherInstance(activity, pos, status)
|
Action_Toot.conversationOtherInstance(activity, pos, status)
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,7 @@ import jp.juggler.subwaytooter.dialog.ActionsDialog
|
|||||||
import jp.juggler.subwaytooter.dialog.DlgConfirm
|
import jp.juggler.subwaytooter.dialog.DlgConfirm
|
||||||
import jp.juggler.subwaytooter.table.AcctColor
|
import jp.juggler.subwaytooter.table.AcctColor
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount
|
import jp.juggler.subwaytooter.table.SavedAccount
|
||||||
import jp.juggler.subwaytooter.util.EmptyCallback
|
import jp.juggler.subwaytooter.util.*
|
||||||
import jp.juggler.subwaytooter.util.LogCategory
|
|
||||||
import jp.juggler.subwaytooter.util.showToast
|
|
||||||
import jp.juggler.subwaytooter.util.toPostRequestBuilder
|
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
@ -893,40 +890,25 @@ object Action_Toot {
|
|||||||
// reply
|
// reply
|
||||||
|
|
||||||
fun reply(
|
fun reply(
|
||||||
activity : ActMain, access_info : SavedAccount, status : TootStatus
|
activity : ActMain,
|
||||||
|
access_info : SavedAccount,
|
||||||
|
status : TootStatus,
|
||||||
|
quotedRenote : Boolean = false
|
||||||
) {
|
) {
|
||||||
ActPost.open(
|
ActPost.open(
|
||||||
activity,
|
activity,
|
||||||
ActMain.REQUEST_CODE_POST,
|
ActMain.REQUEST_CODE_POST,
|
||||||
access_info.db_id,
|
access_info.db_id,
|
||||||
reply_status = status
|
reply_status = status,
|
||||||
|
quotedRenote = quotedRenote
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replyFromAnotherAccount(
|
|
||||||
activity : ActMain, timeline_account : SavedAccount, status : TootStatus?
|
|
||||||
) {
|
|
||||||
if(status == null) return
|
|
||||||
val who_host = timeline_account.host
|
|
||||||
AccountPicker.pick(
|
|
||||||
activity,
|
|
||||||
bAllowPseudo = false,
|
|
||||||
bAuto = false,
|
|
||||||
message = activity.getString(R.string.account_picker_reply),
|
|
||||||
accountListArg = makeAccountListNonPseudo(activity, who_host)
|
|
||||||
) { ai ->
|
|
||||||
if(ai.host.equals(status.host_access, ignoreCase = true)) {
|
|
||||||
// アクセス元ホストが同じならステータスIDを使って返信できる
|
|
||||||
reply(activity, ai, status)
|
|
||||||
} else {
|
|
||||||
// それ以外の場合、ステータスのURLを検索APIに投げることで返信できる
|
|
||||||
replyRemote(activity, ai, status.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun replyRemote(
|
private fun replyRemote(
|
||||||
activity : ActMain, access_info : SavedAccount, remote_status_url : String?
|
activity : ActMain,
|
||||||
|
access_info : SavedAccount,
|
||||||
|
remote_status_url : String?,
|
||||||
|
quotedRenote : Boolean = false
|
||||||
) {
|
) {
|
||||||
if(remote_status_url == null || remote_status_url.isEmpty()) return
|
if(remote_status_url == null || remote_status_url.isEmpty()) return
|
||||||
|
|
||||||
@ -951,7 +933,7 @@ object Action_Toot {
|
|||||||
|
|
||||||
val ls = local_status
|
val ls = local_status
|
||||||
if(ls != null) {
|
if(ls != null) {
|
||||||
reply(activity, access_info, ls)
|
reply(activity, access_info, ls, quotedRenote = quotedRenote)
|
||||||
} else {
|
} else {
|
||||||
showToast(activity, true, result.error)
|
showToast(activity, true, result.error)
|
||||||
}
|
}
|
||||||
@ -959,6 +941,47 @@ object Action_Toot {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun replyFromAnotherAccount(
|
||||||
|
activity : ActMain,
|
||||||
|
timeline_account : SavedAccount,
|
||||||
|
status : TootStatus?,
|
||||||
|
quotedRenote : Boolean = false
|
||||||
|
) {
|
||||||
|
status ?: return
|
||||||
|
val who_host = timeline_account.host
|
||||||
|
|
||||||
|
val accountCallback : SavedAccountCallback = { ai ->
|
||||||
|
if(ai.host.equals(status.host_access, ignoreCase = true)) {
|
||||||
|
// アクセス元ホストが同じならステータスIDを使って返信できる
|
||||||
|
reply(activity, ai, status, quotedRenote = quotedRenote)
|
||||||
|
} else {
|
||||||
|
// それ以外の場合、ステータスのURLを検索APIに投げることで返信できる
|
||||||
|
replyRemote(activity, ai, status.url, quotedRenote = quotedRenote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(quotedRenote) {
|
||||||
|
AccountPicker.pick(
|
||||||
|
activity,
|
||||||
|
bAllowPseudo = false,
|
||||||
|
bAllowMisskey = true,
|
||||||
|
bAllowMastodon = false,
|
||||||
|
bAuto = true,
|
||||||
|
message = activity.getString(R.string.account_picker_quoted_renote),
|
||||||
|
callback = accountCallback
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AccountPicker.pick(
|
||||||
|
activity,
|
||||||
|
bAllowPseudo = false,
|
||||||
|
bAuto = false,
|
||||||
|
message = activity.getString(R.string.account_picker_reply),
|
||||||
|
accountListArg = makeAccountListNonPseudo(activity, who_host),
|
||||||
|
callback = accountCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 投稿画面を開く。初期テキストを指定する
|
// 投稿画面を開く。初期テキストを指定する
|
||||||
fun redraft(
|
fun redraft(
|
||||||
activity : ActMain,
|
activity : ActMain,
|
||||||
@ -1175,7 +1198,7 @@ object Action_Toot {
|
|||||||
activity : ActMain,
|
activity : ActMain,
|
||||||
timeline_account : SavedAccount,
|
timeline_account : SavedAccount,
|
||||||
status : TootStatus?,
|
status : TootStatus?,
|
||||||
code :String? = null
|
code : String? = null
|
||||||
) {
|
) {
|
||||||
status ?: return
|
status ?: return
|
||||||
|
|
||||||
@ -1200,4 +1223,5 @@ object Action_Toot {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,12 @@ package jp.juggler.subwaytooter.api
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import jp.juggler.subwaytooter.*
|
import jp.juggler.subwaytooter.*
|
||||||
import jp.juggler.subwaytooter.api.entity.EntityId
|
import jp.juggler.subwaytooter.api.entity.*
|
||||||
import jp.juggler.subwaytooter.api.entity.TootAccount
|
|
||||||
import jp.juggler.subwaytooter.api.entity.TootInstance
|
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus
|
|
||||||
import jp.juggler.subwaytooter.table.ClientInfo
|
import jp.juggler.subwaytooter.table.ClientInfo
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount
|
import jp.juggler.subwaytooter.table.SavedAccount
|
||||||
import jp.juggler.subwaytooter.util.*
|
import jp.juggler.subwaytooter.util.*
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
|
import org.hjson.JsonObject
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
@ -117,7 +115,13 @@ class TootApiClient(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val DEFAULT_JSON_ERROR_PARSER = { json : JSONObject -> json.parseString("error") }
|
val DEFAULT_JSON_ERROR_PARSER = { json : JSONObject ->
|
||||||
|
val v = json.opt("error")
|
||||||
|
when(v) {
|
||||||
|
null,JSONObject.NULL -> null
|
||||||
|
else -> v.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun simplifyErrorHtml(
|
internal fun simplifyErrorHtml(
|
||||||
response : Response,
|
response : Response,
|
||||||
@ -516,7 +520,7 @@ class TootApiClient(
|
|||||||
val result = TootApiResult.makeWithCaption(instance)
|
val result = TootApiResult.makeWithCaption(instance)
|
||||||
if(result.error != null) return result
|
if(result.error != null) return result
|
||||||
|
|
||||||
val account = this.account ?: return result.setError("account is null")
|
val account = this.account // may null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(! sendRequest(result) {
|
if(! sendRequest(result) {
|
||||||
@ -525,7 +529,7 @@ class TootApiClient(
|
|||||||
|
|
||||||
request_builder.url("https://$instance$path")
|
request_builder.url("https://$instance$path")
|
||||||
|
|
||||||
val access_token = account.getAccessToken()
|
val access_token = account?.getAccessToken()
|
||||||
if(access_token?.isNotEmpty() == true) {
|
if(access_token?.isNotEmpty() == true) {
|
||||||
request_builder.header("Authorization", "Bearer $access_token")
|
request_builder.header("Authorization", "Bearer $access_token")
|
||||||
}
|
}
|
||||||
@ -801,13 +805,13 @@ class TootApiClient(
|
|||||||
|
|
||||||
val user : JSONObject = token_info.optJSONObject("user")
|
val user : JSONObject = token_info.optJSONObject("user")
|
||||||
?: return result.setError("missing user in the response.")
|
?: return result.setError("missing user in the response.")
|
||||||
|
|
||||||
token_info.remove("user")
|
token_info.remove("user")
|
||||||
|
|
||||||
val apiKey = "$access_token$appSecret".encodeUTF8().digestSHA256().encodeHexLower()
|
val apiKey = "$access_token$appSecret".encodeUTF8().digestSHA256().encodeHexLower()
|
||||||
|
|
||||||
// ユーザ情報を読めたならtokenInfoを保存する
|
// ユーザ情報を読めたならtokenInfoを保存する
|
||||||
EntityId.mayNull( user.parseString("id") )?.putTo(token_info,KEY_USER_ID)
|
EntityId.mayNull(user.parseString("id"))?.putTo(token_info, KEY_USER_ID)
|
||||||
token_info.put(KEY_IS_MISSKEY, true)
|
token_info.put(KEY_IS_MISSKEY, true)
|
||||||
token_info.put(KEY_AUTH_VERSION, AUTH_VERSION)
|
token_info.put(KEY_AUTH_VERSION, AUTH_VERSION)
|
||||||
token_info.put(KEY_API_KEY_MISSKEY, apiKey)
|
token_info.put(KEY_API_KEY_MISSKEY, apiKey)
|
||||||
@ -1042,7 +1046,7 @@ class TootApiClient(
|
|||||||
// misskeyのインスタンス情報を読めたら、それはmisskeyのインスタンス
|
// misskeyのインスタンス情報を読めたら、それはmisskeyのインスタンス
|
||||||
val r2 = getInstanceInformationMisskey() ?: return null
|
val r2 = getInstanceInformationMisskey() ?: return null
|
||||||
if(r2.jsonObject != null) return r2
|
if(r2.jsonObject != null) return r2
|
||||||
|
|
||||||
// マストドンのインスタンス情報を読めたら、それはマストドンのインスタンス
|
// マストドンのインスタンス情報を読めたら、それはマストドンのインスタンス
|
||||||
val r1 = getInstanceInformationMastodon() ?: return null
|
val r1 = getInstanceInformationMastodon() ?: return null
|
||||||
if(r1.jsonObject != null) return r1
|
if(r1.jsonObject != null) return r1
|
||||||
@ -1465,8 +1469,40 @@ fun TootApiClient.syncAccountByAcct(accessInfo : SavedAccount, acct : String) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TootApiClient.syncStatus(accessInfo : SavedAccount, url : String) =
|
fun TootApiClient.syncStatus(accessInfo : SavedAccount, urlArg : String) : TootApiResult? {
|
||||||
if(accessInfo.isMisskey) {
|
|
||||||
|
var url = urlArg
|
||||||
|
|
||||||
|
// misskey の投稿URLは外部タンスの投稿を複製したものの可能性がある
|
||||||
|
// これを投稿元タンスの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)){
|
||||||
|
result.data = obj
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
val uri = obj.uri
|
||||||
|
if(uri?.isNotEmpty() == true){
|
||||||
|
url = uri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return if(accessInfo.isMisskey) {
|
||||||
val params = accessInfo.putMisskeyApiToken().put("uri", url)
|
val params = accessInfo.putMisskeyApiToken().put("uri", url)
|
||||||
val result = request("/api/ap/show", params.toPostRequestBuilder())
|
val result = request("/api/ap/show", params.toPostRequestBuilder())
|
||||||
if(result != null) {
|
if(result != null) {
|
||||||
@ -1490,6 +1526,8 @@ fun TootApiClient.syncStatus(accessInfo : SavedAccount, url : String) =
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private inline fun <Z : Any?> String?.useNotEmpty(block : (String) -> Z?) : Z? =
|
private inline fun <Z : Any?> String?.useNotEmpty(block : (String) -> Z?) : Z? =
|
||||||
if(this?.isNotEmpty() == true) {
|
if(this?.isNotEmpty() == true) {
|
||||||
|
@ -658,6 +658,15 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
|
|||||||
@Suppress("HasPlatformType")
|
@Suppress("HasPlatformType")
|
||||||
private val reTootUriAP2 = Pattern.compile("https?://([^/]+)/@[A-Za-z0-9_]+/(\\d+)")
|
private val reTootUriAP2 = Pattern.compile("https?://([^/]+)/@[A-Za-z0-9_]+/(\\d+)")
|
||||||
|
|
||||||
|
// 公開ステータスページのURL マストドン
|
||||||
|
@Suppress("HasPlatformType")
|
||||||
|
val reStatusPage = Pattern.compile("""\Ahttps://([^/]+)/@([A-Za-z0-9_]+)/(\d+)(?:\z|[?#])""")
|
||||||
|
|
||||||
|
// 公開ステータスページのURL Misskey
|
||||||
|
@Suppress("HasPlatformType")
|
||||||
|
val reStatusPageMisskey = Pattern.compile("""\Ahttps://([^/]+)/notes/([0-9a-f]{24})\b""")
|
||||||
|
|
||||||
|
|
||||||
const val INVALID_ID = - 1L
|
const val INVALID_ID = - 1L
|
||||||
|
|
||||||
fun parseListTootsearch(
|
fun parseListTootsearch(
|
||||||
|
@ -101,6 +101,7 @@
|
|||||||
android:text="@string/share_url_more"
|
android:text="@string/share_url_more"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btnBoostedBy"
|
android:id="@+id/btnBoostedBy"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -206,6 +207,21 @@
|
|||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnQuotedRenote"
|
||||||
|
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/quote_renote"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btnProfilePin"
|
android:id="@+id/btnProfilePin"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<string name="account_picker_open_setting">どのアカウントの設定を開きますか?</string>
|
<string name="account_picker_open_setting">どのアカウントの設定を開きますか?</string>
|
||||||
<string name="account_picker_open_user_who">どのアカウントでユーザ %1$s のプロフィールを確認しますか?</string>
|
<string name="account_picker_open_user_who">どのアカウントでユーザ %1$s のプロフィールを確認しますか?</string>
|
||||||
<string name="account_picker_reply">どのアカウントで返信しますか?</string>
|
<string name="account_picker_reply">どのアカウントで返信しますか?</string>
|
||||||
|
<string name="account_picker_quoted_renote">どのアカウントで引用リノートしますか?</string>
|
||||||
<string name="account_picker_toot">どのアカウントでトゥートしますか?</string>
|
<string name="account_picker_toot">どのアカウントでトゥートしますか?</string>
|
||||||
<string name="account_remove">アカウントの削除</string>
|
<string name="account_remove">アカウントの削除</string>
|
||||||
<string name="account_select_please">アカウントを選択してください</string>
|
<string name="account_select_please">アカウントを選択してください</string>
|
||||||
@ -809,5 +810,6 @@
|
|||||||
<string name="quick_toot_bar_background_color">簡易投稿入力の背景色</string>
|
<string name="quick_toot_bar_background_color">簡易投稿入力の背景色</string>
|
||||||
<string name="dont_show_preview_card">プレビューカードを表示しない</string>
|
<string name="dont_show_preview_card">プレビューカードを表示しない</string>
|
||||||
<string name="instance_does_not_support_push_api_pleroma">このインスタンスはプッシュ購読APIに対応していません。多分Pleromaです。</string>
|
<string name="instance_does_not_support_push_api_pleroma">このインスタンスはプッシュ購読APIに対応していません。多分Pleromaです。</string>
|
||||||
|
<string name="quote_renote">引用リノート… (Misskey)</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -339,6 +339,7 @@
|
|||||||
<string name="minimum_column_width">Minimum column width (default=300(dp),app restart required)</string>
|
<string name="minimum_column_width">Minimum column width (default=300(dp),app restart required)</string>
|
||||||
<string name="media_thumbnail_height">Media Thumbnail height (default=64(dp), app restart required)</string>
|
<string name="media_thumbnail_height">Media Thumbnail height (default=64(dp), app restart required)</string>
|
||||||
<string name="account_picker_reply">Which account do you reply from?</string>
|
<string name="account_picker_reply">Which account do you reply from?</string>
|
||||||
|
<string name="account_picker_quoted_renote">Which account do you quoted renote from?</string>
|
||||||
<string name="reply_from_another_account">Reply from another account</string>
|
<string name="reply_from_another_account">Reply from another account</string>
|
||||||
<string name="launcher_icon_by">Thanks to フタバ for the application icon.</string>
|
<string name="launcher_icon_by">Thanks to フタバ for the application icon.</string>
|
||||||
<string name="ssl_bug_7_0">Android 7.0 can only use the elliptic curve \"prime256v1\".\nUnfortunately your instance seems to not support it.\nThis bug has been fixed in Android 7.1.1.\nYou can either upgrade your OS or ask the administrator of your instance to add support to the elliptic curve \"prime256v1\".\nSee also https://code.google.com/p/android/issues/detail?id=224438</string>
|
<string name="ssl_bug_7_0">Android 7.0 can only use the elliptic curve \"prime256v1\".\nUnfortunately your instance seems to not support it.\nThis bug has been fixed in Android 7.1.1.\nYou can either upgrade your OS or ask the administrator of your instance to add support to the elliptic curve \"prime256v1\".\nSee also https://code.google.com/p/android/issues/detail?id=224438</string>
|
||||||
@ -827,5 +828,6 @@
|
|||||||
<string name="quick_toot_bar_background_color">Quick toot bar background color</string>
|
<string name="quick_toot_bar_background_color">Quick toot bar background color</string>
|
||||||
<string name="dont_show_preview_card">Don\'t show preview card</string>
|
<string name="dont_show_preview_card">Don\'t show preview card</string>
|
||||||
<string name="instance_does_not_support_push_api_pleroma">This instance does not support push subscription API. maybe it is Pleroma</string>
|
<string name="instance_does_not_support_push_api_pleroma">This instance does not support push subscription API. maybe it is Pleroma</string>
|
||||||
|
<string name="quote_renote">Quoted renote… (Misskey)</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user