- (Misskey)返信のかわりに引用Renoteを作成できる(タンス側のバグがなければ)。
- (Misskey)返信と引用Renoteの際に元投稿をプレビューカードとして表示する。 - プレビューカードの表示にボーダー枠を追加。
This commit is contained in:
parent
0a7d2c68bd
commit
25cd2e201b
@ -200,7 +200,7 @@ class ActMain : AppCompatActivity()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private val link_click_listener : MyClickableSpanClickCallback = { viewClicked, span ->
|
||||
internal val link_click_listener : MyClickableSpanClickCallback = { viewClicked, span ->
|
||||
|
||||
var view = viewClicked
|
||||
var column : Column? = null
|
||||
@ -353,8 +353,8 @@ class ActMain : AppCompatActivity()
|
||||
// (カラム一覧画面のデフォルト選択位置に使われる)
|
||||
val currentColumn : Int
|
||||
get() = phoneTab(
|
||||
{ pe -> pe.pager.currentItem },
|
||||
{ _ -> - 1 }
|
||||
{ it.pager.currentItem },
|
||||
{ - 1 }
|
||||
)
|
||||
|
||||
// 新しいカラムをどこに挿入するか
|
||||
@ -369,8 +369,8 @@ class ActMain : AppCompatActivity()
|
||||
// 新しいカラムをどこに挿入するか
|
||||
private val defaultInsertPosition : Int
|
||||
get() = phoneTab(
|
||||
{ pe -> pe.pager.currentItem + 1 },
|
||||
{ _ -> Integer.MAX_VALUE }
|
||||
{ it.pager.currentItem + 1 },
|
||||
{ Integer.MAX_VALUE }
|
||||
)
|
||||
|
||||
private fun validateFloat(fv : Float) : Float {
|
||||
@ -664,15 +664,15 @@ class ActMain : AppCompatActivity()
|
||||
private fun performQuickPost(account : SavedAccount?) {
|
||||
if(account == null) {
|
||||
phoneTab({ env ->
|
||||
|
||||
|
||||
// スマホモードなら表示中のカラムがあればそれで
|
||||
val c = try{
|
||||
val c = try {
|
||||
app_state.column_list[env.pager.currentItem]
|
||||
}catch(ex:Throwable){
|
||||
} catch(ex : Throwable) {
|
||||
null
|
||||
}
|
||||
|
||||
if( c?.access_info?.isPseudo == false ) {
|
||||
|
||||
if(c?.access_info?.isPseudo == false) {
|
||||
// 疑似アカウントではない
|
||||
performQuickPost(c.access_info)
|
||||
} else {
|
||||
@ -684,7 +684,7 @@ class ActMain : AppCompatActivity()
|
||||
message = getString(R.string.account_picker_toot)
|
||||
) { ai -> performQuickPost(ai) }
|
||||
}
|
||||
}, { _ ->
|
||||
}, {
|
||||
// アカウント選択してやり直し
|
||||
AccountPicker.pick(
|
||||
this,
|
||||
@ -702,7 +702,8 @@ class ActMain : AppCompatActivity()
|
||||
post_helper.bNSFW = false
|
||||
post_helper.in_reply_to_id = null
|
||||
post_helper.attachment_list = null
|
||||
post_helper.emojiMapCustom = App1.custom_emoji_lister.getMap(account.host,account.isMisskey)
|
||||
post_helper.emojiMapCustom =
|
||||
App1.custom_emoji_lister.getMap(account.host, account.isMisskey)
|
||||
|
||||
|
||||
etQuickToot.hideKeyboard()
|
||||
@ -1324,7 +1325,6 @@ class ActMain : AppCompatActivity()
|
||||
env.tablet_pager.layoutManager = env.tablet_layout_manager
|
||||
env.tablet_pager.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
|
||||
|
||||
override fun onScrollStateChanged(recyclerView : RecyclerView, newState : Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
|
||||
@ -1423,7 +1423,7 @@ class ActMain : AppCompatActivity()
|
||||
if(c == 0) {
|
||||
Styler.setIconAttr(this, ivIcon, column.getIconAttrId(column.column_type))
|
||||
} else {
|
||||
Styler.setIconAttr(this, ivIcon, column.getIconAttrId(column.column_type),c)
|
||||
Styler.setIconAttr(this, ivIcon, column.getIconAttrId(column.column_type), c)
|
||||
}
|
||||
|
||||
//
|
||||
@ -1460,7 +1460,7 @@ class ActMain : AppCompatActivity()
|
||||
var slide_ratio = 0f
|
||||
if(vr.first <= vr.last) {
|
||||
val child = env.tablet_layout_manager.findViewByPosition(vr.first)
|
||||
slide_ratio = Math.abs( (child?.left ?: 0) / nColumnWidth.toFloat())
|
||||
slide_ratio = Math.abs((child?.left ?: 0) / nColumnWidth.toFloat())
|
||||
}
|
||||
|
||||
llColumnStrip.setVisibleRange(vr.first, vr.last, slide_ratio)
|
||||
@ -1505,9 +1505,9 @@ class ActMain : AppCompatActivity()
|
||||
|
||||
// ActOAuthCallbackで受け取ったUriを処理する
|
||||
private fun handleIntentUri(uri : Uri) {
|
||||
|
||||
|
||||
log.d("handleIntentUri ${uri}")
|
||||
|
||||
|
||||
when(uri.scheme) {
|
||||
"subwaytooter", "misskeyclientproto" -> return try {
|
||||
handleOAuth2CallbackUri(uri)
|
||||
@ -2031,7 +2031,7 @@ class ActMain : AppCompatActivity()
|
||||
}
|
||||
}
|
||||
|
||||
}, { _ ->
|
||||
}, {
|
||||
removeColumn(column)
|
||||
|
||||
if(! app_state.column_list.isEmpty() && page_delete > 0) {
|
||||
@ -2061,8 +2061,8 @@ class ActMain : AppCompatActivity()
|
||||
|
||||
var lastColumnIndex = when(_lastColumnIndex) {
|
||||
- 1 -> phoneTab(
|
||||
{ pe -> pe.pager.currentItem },
|
||||
{ _ -> 0 }
|
||||
{ it.pager.currentItem },
|
||||
{ 0 }
|
||||
)
|
||||
else -> _lastColumnIndex
|
||||
}
|
||||
@ -2272,9 +2272,9 @@ class ActMain : AppCompatActivity()
|
||||
Styler.setIconAttr(this, btnMenu, R.attr.ic_hamburger)
|
||||
Styler.setIconAttr(this, btnQuickToot, R.attr.btn_post)
|
||||
} else {
|
||||
Styler.setIconAttr(this, btnToot, R.attr.ic_edit,c)
|
||||
Styler.setIconAttr(this, btnMenu, R.attr.ic_hamburger,c)
|
||||
Styler.setIconAttr(this, btnQuickToot, R.attr.btn_post,c)
|
||||
Styler.setIconAttr(this, btnToot, R.attr.ic_edit, c)
|
||||
Styler.setIconAttr(this, btnMenu, R.attr.ic_hamburger, c)
|
||||
Styler.setIconAttr(this, btnQuickToot, R.attr.btn_post, c)
|
||||
}
|
||||
|
||||
c = footer_tab_bg_color
|
||||
@ -2337,9 +2337,9 @@ class ActMain : AppCompatActivity()
|
||||
for(i in 0 until env.tablet_layout_manager.childCount) {
|
||||
val v = env.tablet_layout_manager.getChildAt(i)
|
||||
|
||||
val columnViewHolder =when(v){
|
||||
null-> null
|
||||
else->(env.tablet_pager.getChildViewHolder(v) as? TabletColumnViewHolder)?.columnViewHolder
|
||||
val columnViewHolder = when(v) {
|
||||
null -> null
|
||||
else -> (env.tablet_pager.getChildViewHolder(v) as? TabletColumnViewHolder)?.columnViewHolder
|
||||
}
|
||||
|
||||
if(columnViewHolder?.isColumnSettingShown == true) {
|
||||
@ -2569,7 +2569,7 @@ class ActMain : AppCompatActivity()
|
||||
ZipInputStream(FileInputStream(file)).use { zipStream ->
|
||||
while(true) {
|
||||
val entry = zipStream.nextEntry ?: break
|
||||
++zipEntryCount
|
||||
++ zipEntryCount
|
||||
try {
|
||||
//
|
||||
val entryName = entry.name
|
||||
@ -2581,13 +2581,13 @@ class ActMain : AppCompatActivity()
|
||||
continue
|
||||
}
|
||||
|
||||
if( AppDataExporter.restoreBackgroundImage(
|
||||
if(AppDataExporter.restoreBackgroundImage(
|
||||
this@ActMain,
|
||||
newColumnList,
|
||||
zipStream,
|
||||
entryName
|
||||
)
|
||||
){
|
||||
) {
|
||||
continue
|
||||
}
|
||||
} finally {
|
||||
@ -2597,12 +2597,12 @@ class ActMain : AppCompatActivity()
|
||||
}
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
if(zipEntryCount!=0) {
|
||||
if(zipEntryCount != 0) {
|
||||
showToast(this@ActMain, ex, "importAppData failed.")
|
||||
}
|
||||
}
|
||||
// zipではなかった場合、zipEntryがない状態になる。例外はPH-1では出なかったが、出ても問題ないようにする。
|
||||
if(zipEntryCount==0) {
|
||||
if(zipEntryCount == 0) {
|
||||
InputStreamReader(FileInputStream(file), "UTF-8").use { inStream ->
|
||||
newColumnList = AppDataExporter.decodeAppData(
|
||||
this@ActMain,
|
||||
@ -2767,13 +2767,12 @@ class ActMain : AppCompatActivity()
|
||||
}
|
||||
}
|
||||
|
||||
private var dlgPrivacyPolicy : WeakReference<Dialog>?=null
|
||||
private var dlgPrivacyPolicy : WeakReference<Dialog>? = null
|
||||
|
||||
private fun checkPrivacyPolicy() {
|
||||
|
||||
// 既に表示中かもしれない
|
||||
if( dlgPrivacyPolicy?.get()?.isShowing == true) return
|
||||
|
||||
if(dlgPrivacyPolicy?.get()?.isShowing == true) return
|
||||
|
||||
val res_id = when(getString(R.string.language_code)) {
|
||||
"ja" -> R.raw.privacy_policy_ja
|
||||
@ -2783,29 +2782,27 @@ class ActMain : AppCompatActivity()
|
||||
|
||||
// プライバシーポリシーデータの読み込み
|
||||
val bytes = loadRawResource(res_id)
|
||||
if( bytes.isEmpty() ) return
|
||||
if(bytes.isEmpty()) return
|
||||
|
||||
// 同意ずみなら表示しない
|
||||
val digest = bytes.digestSHA256().encodeBase64Url()
|
||||
if( digest == Pref.spAgreedPrivacyPolicyDigest(pref) ) return
|
||||
if(digest == Pref.spAgreedPrivacyPolicyDigest(pref)) return
|
||||
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
.setTitle(R.string.privacy_policy)
|
||||
.setMessage( bytes.decodeUTF8())
|
||||
.setNegativeButton(R.string.cancel){_,_ ->
|
||||
.setMessage(bytes.decodeUTF8())
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
finish()
|
||||
}
|
||||
.setOnCancelListener{_->
|
||||
.setOnCancelListener {
|
||||
finish()
|
||||
}
|
||||
.setPositiveButton(R.string.agree){_,_ ->
|
||||
pref.edit().put(Pref.spAgreedPrivacyPolicyDigest,digest).apply()
|
||||
.setPositiveButton(R.string.agree) { _, _ ->
|
||||
pref.edit().put(Pref.spAgreedPrivacyPolicyDigest, digest).apply()
|
||||
}
|
||||
.create()
|
||||
dlgPrivacyPolicy = WeakReference(dialog)
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
internal const val DRAFT_REPLY_URL = "reply_url"
|
||||
internal const val DRAFT_IS_ENQUETE = "is_enquete"
|
||||
internal const val DRAFT_ENQUETE_ITEMS = "enquete_items"
|
||||
internal const val DRAFT_QUOTED_RENOTE = "quotedRenote"
|
||||
|
||||
private const val STATE_MUSHROOM_INPUT = "mushroom_input"
|
||||
private const val STATE_MUSHROOM_START = "mushroom_start"
|
||||
@ -223,6 +224,8 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
internal lateinit var etContentWarning : MyEditText
|
||||
internal lateinit var etContent : MyEditText
|
||||
|
||||
internal lateinit var cbQuoteRenote : CheckBox
|
||||
|
||||
internal lateinit var cbEnquete : CheckBox
|
||||
private lateinit var llEnquete : View
|
||||
internal lateinit var list_etChoice : List<MyEditText>
|
||||
@ -703,14 +706,17 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
selectAccount(null)
|
||||
}
|
||||
|
||||
|
||||
updateContentWarning()
|
||||
showMediaAttachment()
|
||||
showVisibility()
|
||||
updateTextCount()
|
||||
showReplyTo()
|
||||
showEnquete()
|
||||
showQuotedRenote()
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
post_helper.onDestroy()
|
||||
|
||||
@ -765,6 +771,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
updateTextCount()
|
||||
showReplyTo()
|
||||
showEnquete()
|
||||
showQuotedRenote()
|
||||
}
|
||||
|
||||
private fun appendContentText(
|
||||
@ -853,6 +860,8 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
etContentWarning = findViewById(R.id.etContentWarning)
|
||||
etContent = findViewById(R.id.etContent)
|
||||
|
||||
cbQuoteRenote= findViewById(R.id.cbQuoteRenote)
|
||||
|
||||
cbEnquete = findViewById(R.id.cbEnquete)
|
||||
llEnquete = findViewById(R.id.llEnquete)
|
||||
|
||||
@ -1128,6 +1137,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
log.trace(ex)
|
||||
}
|
||||
showVisibility()
|
||||
showQuotedRenote()
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@ -1974,6 +1984,8 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
|
||||
post_helper.redraft_status_id = redraft_status_id
|
||||
|
||||
post_helper.useQuotedRenote = cbQuoteRenote.isChecked
|
||||
|
||||
post_helper.post(account) { target_account, status ->
|
||||
val data = Intent()
|
||||
data.putExtra(EXTRA_POSTED_ACCT, target_account.acct)
|
||||
@ -1986,6 +1998,12 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
}
|
||||
}
|
||||
|
||||
private fun showQuotedRenote() {
|
||||
val isReply = in_reply_to_id != null
|
||||
val isMisskey = account?.isMisskey == true
|
||||
cbQuoteRenote.visibility = if( isReply && isMisskey ) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
internal fun showReplyTo() {
|
||||
if(in_reply_to_id == null) {
|
||||
llReply.visibility = View.GONE
|
||||
@ -2008,6 +2026,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
in_reply_to_image = null
|
||||
in_reply_to_url = null
|
||||
showReplyTo()
|
||||
showQuotedRenote()
|
||||
}
|
||||
|
||||
private fun saveDraft() {
|
||||
@ -2054,7 +2073,9 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
json.put(DRAFT_REPLY_IMAGE, in_reply_to_image)
|
||||
json.put(DRAFT_REPLY_URL, in_reply_to_url)
|
||||
|
||||
json.put(DRAFT_QUOTED_RENOTE,cbQuoteRenote.isChecked)
|
||||
json.put(DRAFT_IS_ENQUETE, isEnquete)
|
||||
|
||||
val array = JSONArray()
|
||||
for(s in str_choice) {
|
||||
array.put(s)
|
||||
@ -2206,6 +2227,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
val draft_visibility = TootVisibility
|
||||
.parseSavedVisibility(draft.parseString(DRAFT_VISIBILITY))
|
||||
|
||||
|
||||
val evEmoji = DecodeOptions(this@ActPost, decodeEmoji = true).decodeEmoji(content)
|
||||
etContent.setText(evEmoji)
|
||||
etContent.setSelection(evEmoji.length)
|
||||
@ -2215,6 +2237,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
cbNSFW.isChecked = nsfw_checked
|
||||
if(draft_visibility != null) this@ActPost.visibility = draft_visibility
|
||||
|
||||
cbQuoteRenote.isChecked = draft.optBoolean(DRAFT_QUOTED_RENOTE)
|
||||
cbEnquete.isChecked = draft.optBoolean(DRAFT_IS_ENQUETE, false)
|
||||
val array = draft.optJSONArray(DRAFT_ENQUETE_ITEMS)
|
||||
if(array != null) {
|
||||
@ -2254,6 +2277,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
in_reply_to_image = reply_image
|
||||
in_reply_to_url = reply_url
|
||||
}
|
||||
|
||||
|
||||
updateContentWarning()
|
||||
showMediaAttachment()
|
||||
@ -2261,6 +2285,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
|
||||
updateTextCount()
|
||||
showReplyTo()
|
||||
showEnquete()
|
||||
showQuotedRenote()
|
||||
|
||||
if(! list_warning.isEmpty()) {
|
||||
val sb = StringBuilder()
|
||||
|
@ -26,6 +26,7 @@ import jp.juggler.subwaytooter.api.TootTaskRunner
|
||||
import jp.juggler.subwaytooter.api.entity.*
|
||||
import jp.juggler.subwaytooter.dialog.ActionsDialog
|
||||
import jp.juggler.subwaytooter.dialog.DlgConfirm
|
||||
import jp.juggler.subwaytooter.drawable.PreviewCardBorder
|
||||
import jp.juggler.subwaytooter.span.EmojiImageSpan
|
||||
import jp.juggler.subwaytooter.span.MyClickableSpan
|
||||
import jp.juggler.subwaytooter.table.*
|
||||
@ -120,12 +121,13 @@ internal class ItemViewHolder(
|
||||
private lateinit var tvFilterDetail : TextView
|
||||
|
||||
private lateinit var tvMediaDescription : TextView
|
||||
|
||||
private lateinit var llCardOuter : View
|
||||
private lateinit var tvCardText : TextView
|
||||
private lateinit var ivCardImage : MyNetworkImageView
|
||||
|
||||
private lateinit var llExtra : LinearLayout
|
||||
|
||||
|
||||
private lateinit var llConversationIcons : View
|
||||
private lateinit var ivConversationIcon1 : MyNetworkImageView
|
||||
private lateinit var ivConversationIcon2 : MyNetworkImageView
|
||||
@ -134,8 +136,6 @@ internal class ItemViewHolder(
|
||||
private lateinit var tvConversationIconsMore : TextView
|
||||
private lateinit var tvConversationParticipants : TextView
|
||||
|
||||
|
||||
|
||||
private lateinit var tvApplication : TextView
|
||||
|
||||
private lateinit var tvMessageHolder : TextView
|
||||
@ -181,7 +181,8 @@ internal class ItemViewHolder(
|
||||
btnFollow.setOnClickListener(this)
|
||||
btnFollow.setOnLongClickListener(this)
|
||||
|
||||
ivCardImage.setOnClickListener(this)
|
||||
llCardOuter.setOnClickListener(this)
|
||||
llCardOuter.setOnLongClickListener(this)
|
||||
|
||||
ivThumbnail.setOnClickListener(this)
|
||||
|
||||
@ -263,6 +264,13 @@ internal class ItemViewHolder(
|
||||
this.reply_invalidator = NetworkEmojiInvalidator(activity.handler, tvReply)
|
||||
this.follow_invalidator = NetworkEmojiInvalidator(activity.handler, tvFollowerName)
|
||||
this.name_invalidator = NetworkEmojiInvalidator(activity.handler, tvName)
|
||||
|
||||
val cardBackground = llCardOuter.background
|
||||
if(cardBackground is PreviewCardBorder) {
|
||||
val density = activity.density
|
||||
cardBackground.round = (density * 8f)
|
||||
cardBackground.width = (density * 1f)
|
||||
}
|
||||
}
|
||||
|
||||
fun onViewRecycled() {
|
||||
@ -375,6 +383,7 @@ internal class ItemViewHolder(
|
||||
llTrendTag.visibility = View.GONE
|
||||
llFilter.visibility = View.GONE
|
||||
tvMediaDescription.visibility = View.GONE
|
||||
llCardOuter.visibility = View.GONE
|
||||
tvCardText.visibility = View.GONE
|
||||
ivCardImage.visibility = View.GONE
|
||||
llConversationIcons.visibility = View.GONE
|
||||
@ -402,6 +411,12 @@ internal class ItemViewHolder(
|
||||
tvConversationIconsMore.setTextColor(c)
|
||||
tvConversationParticipants.setTextColor(c)
|
||||
|
||||
val cardBackground = llCardOuter.background
|
||||
if(cardBackground is PreviewCardBorder) {
|
||||
cardBackground.color = c
|
||||
}
|
||||
|
||||
|
||||
c = if(column.acct_color != 0) column.acct_color else Styler.getAttributeColor(
|
||||
activity,
|
||||
R.attr.colorTimeSmall
|
||||
@ -484,12 +499,10 @@ internal class ItemViewHolder(
|
||||
}
|
||||
extra_invalidator_list.clear()
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun showConversationIcons(cs:TootConversationSummary) {
|
||||
private fun showConversationIcons(cs : TootConversationSummary) {
|
||||
|
||||
val accounts = cs.accounts
|
||||
val last_account_id = cs.last_status.account.id
|
||||
|
||||
val accountsOther = cs.accounts.filter { it.get().id != last_account_id }
|
||||
@ -498,17 +511,17 @@ internal class ItemViewHolder(
|
||||
|
||||
val size = accountsOther.size
|
||||
|
||||
tvConversationParticipants.text =if(size <= 1){
|
||||
tvConversationParticipants.text = if(size <= 1) {
|
||||
activity.getString(R.string.conversation_to)
|
||||
}else{
|
||||
} else {
|
||||
activity.getString(R.string.participants)
|
||||
}
|
||||
|
||||
fun showIcon(iv : MyNetworkImageView, idx : Int) {
|
||||
val bShown = idx < size
|
||||
iv.visibility = if(bShown) View.VISIBLE else View.GONE
|
||||
if(!bShown) return
|
||||
|
||||
if(! bShown) return
|
||||
|
||||
val who = accountsOther[idx].get()
|
||||
iv.setImageUrl(
|
||||
activity.pref,
|
||||
@ -527,14 +540,14 @@ internal class ItemViewHolder(
|
||||
else -> activity.getString(R.string.participants_and_more)
|
||||
}
|
||||
}
|
||||
|
||||
if( cs.last_status.in_reply_to_id != null ) {
|
||||
|
||||
if(cs.last_status.in_reply_to_id != null) {
|
||||
llSearchTag.visibility = View.VISIBLE
|
||||
btnSearchTag.text = activity.getString(R.string.show_conversation)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openConversationSummary(){
|
||||
private fun openConversationSummary() {
|
||||
val cs = item as? TootConversationSummary ?: return
|
||||
|
||||
if(cs.unread) {
|
||||
@ -545,7 +558,7 @@ internal class ItemViewHolder(
|
||||
reset = true
|
||||
)
|
||||
// 未読フラグのクリアをサーバに送る
|
||||
Action_Toot.clearConversationUnread(activity,access_info,cs)
|
||||
Action_Toot.clearConversationUnread(activity, access_info, cs)
|
||||
}
|
||||
|
||||
Action_Toot.conversation(
|
||||
@ -936,7 +949,7 @@ internal class ItemViewHolder(
|
||||
// }
|
||||
|
||||
var content = status.decoded_content
|
||||
|
||||
|
||||
// ニコフレのアンケートの表示
|
||||
val enquete = status.enquete
|
||||
if(enquete != null) {
|
||||
@ -958,10 +971,7 @@ internal class ItemViewHolder(
|
||||
}
|
||||
|
||||
// カードの表示(会話ビューのみ)
|
||||
val card = status.card
|
||||
if(card != null) {
|
||||
showPreviewCard(activity, card)
|
||||
}
|
||||
showPreviewCard(activity, status)
|
||||
|
||||
// if( status.decoded_tags == null ){
|
||||
// tvTags.setVisibility( View.GONE );
|
||||
@ -1048,7 +1058,7 @@ internal class ItemViewHolder(
|
||||
setMedia(media_attachments, sb, ivMedia2, 1)
|
||||
setMedia(media_attachments, sb, ivMedia3, 2)
|
||||
setMedia(media_attachments, sb, ivMedia4, 3)
|
||||
if( sb. isNotEmpty()){
|
||||
if(sb.isNotEmpty()) {
|
||||
tvMediaDescription.visibility = View.VISIBLE
|
||||
tvMediaDescription.text = sb
|
||||
}
|
||||
@ -1326,9 +1336,10 @@ internal class ItemViewHolder(
|
||||
if(column.content_color != 0) column.content_color else content_color_default
|
||||
tv.setTextColor(c)
|
||||
|
||||
if( ta.description ?. isNotEmpty() == true){
|
||||
if( sbDesc.isNotEmpty()) sbDesc.append("\n")
|
||||
val desc = activity.getString(R.string.media_description, idx + 1, ta.description)
|
||||
if(ta.description?.isNotEmpty() == true) {
|
||||
if(sbDesc.isNotEmpty()) sbDesc.append("\n")
|
||||
val desc =
|
||||
activity.getString(R.string.media_description, idx + 1, ta.description)
|
||||
sbDesc.append(desc)
|
||||
}
|
||||
}
|
||||
@ -1353,8 +1364,6 @@ internal class ItemViewHolder(
|
||||
}
|
||||
private var boostedAction : () -> Unit = defaultBoostedAction
|
||||
|
||||
|
||||
|
||||
override fun onClick(v : View) {
|
||||
|
||||
val pos = activity.nextPosition(column)
|
||||
@ -1516,8 +1525,26 @@ internal class ItemViewHolder(
|
||||
openFilterMenu(item)
|
||||
}
|
||||
|
||||
ivCardImage-> status_showing?.card?.url?.let { url ->
|
||||
if(url.isNotEmpty()) App1.openCustomTab(activity, url)
|
||||
llCardOuter -> status_showing?.card?.let { card ->
|
||||
val originalStatus = card.originalStatus
|
||||
if(originalStatus != null) {
|
||||
Action_Toot.conversation(
|
||||
activity,
|
||||
activity.nextPosition(column),
|
||||
access_info,
|
||||
originalStatus
|
||||
)
|
||||
} else {
|
||||
val url = card.url
|
||||
if(url?.isNotEmpty() == true) {
|
||||
ChromeTabOpener(
|
||||
activity,
|
||||
pos,
|
||||
url,
|
||||
accessInfo = access_info
|
||||
).open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llConversationIcons -> openConversationSummary()
|
||||
@ -1593,6 +1620,12 @@ internal class ItemViewHolder(
|
||||
return true
|
||||
}
|
||||
|
||||
llCardOuter -> Action_Toot.conversationOtherInstance(
|
||||
activity,
|
||||
activity.nextPosition(column),
|
||||
status_showing?.card?.originalStatus
|
||||
)
|
||||
|
||||
btnSearchTag, llTrendTag -> {
|
||||
val item = this.item
|
||||
when(item) {
|
||||
@ -1666,15 +1699,35 @@ internal class ItemViewHolder(
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPreviewCard(activity : ActMain, card : TootCard) {
|
||||
private fun showPreviewCard(activity : ActMain, status : TootStatus) {
|
||||
val card = status.card ?: return
|
||||
|
||||
// 会話カラムで返信ステータスなら捏造したカードを表示しない
|
||||
if(column.column_type == Column.TYPE_CONVERSATION
|
||||
&& card.originalStatus != null
|
||||
&& status.reply != null
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
llCardOuter.visibility = View.VISIBLE
|
||||
|
||||
val sb = StringBuilder()
|
||||
addLinkAndCaption(sb, activity.getString(R.string.card_header_card), card.url, card.title)
|
||||
|
||||
addLinkAndCaption(
|
||||
sb,
|
||||
activity.getString(R.string.card_header_card),
|
||||
card.url,
|
||||
card.title
|
||||
)
|
||||
|
||||
addLinkAndCaption(
|
||||
sb,
|
||||
activity.getString(R.string.card_header_author),
|
||||
card.author_url,
|
||||
card.author_name
|
||||
)
|
||||
|
||||
addLinkAndCaption(
|
||||
sb,
|
||||
activity.getString(R.string.card_header_provider),
|
||||
@ -1688,12 +1741,20 @@ internal class ItemViewHolder(
|
||||
|
||||
val limit = Pref.spCardDescriptionLength.toInt(activity.pref)
|
||||
|
||||
sb.append(HTMLDecoder.encodeEntity(ellipsize(description,if( limit <= 0 ) 64 else limit)))
|
||||
sb.append(
|
||||
HTMLDecoder.encodeEntity(
|
||||
ellipsize(
|
||||
description,
|
||||
if(limit <= 0) 64 else limit
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if( sb.isNotEmpty() ){
|
||||
val text = DecodeOptions(activity, access_info).decodeHTML(sb.toString())
|
||||
if( text.isNotEmpty()){
|
||||
if(sb.isNotEmpty()) {
|
||||
val text =
|
||||
DecodeOptions(activity, access_info, forceHtml = true).decodeHTML(sb.toString())
|
||||
if(text.isNotEmpty()) {
|
||||
tvCardText.visibility = View.VISIBLE
|
||||
tvCardText.text = text
|
||||
}
|
||||
@ -1711,11 +1772,11 @@ internal class ItemViewHolder(
|
||||
}
|
||||
}
|
||||
|
||||
private fun ellipsize(src:String,limit:Int):String{
|
||||
return if( src.codePointCount(0,src.length) <= limit ) {
|
||||
private fun ellipsize(src : String, limit : Int) : String {
|
||||
return if(src.codePointCount(0, src.length) <= limit) {
|
||||
src
|
||||
}else {
|
||||
"${src.substring(0, src.offsetByCodePoints(0,limit))}…"
|
||||
} else {
|
||||
"${src.substring(0, src.offsetByCodePoints(0, limit))}…"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1899,7 +1960,7 @@ internal class ItemViewHolder(
|
||||
}
|
||||
|
||||
if((result.response?.code() ?: - 1) in 200 until 300) {
|
||||
if(status.increaseReaction(code,true,"addReaction")){
|
||||
if(status.increaseReaction(code, true, "addReaction")) {
|
||||
// 1個だけ描画更新するのではなく、TLにある複数の要素をまとめて更新する
|
||||
list_adapter.notifyChange(reason = "addReaction complete", reset = true)
|
||||
}
|
||||
@ -2021,14 +2082,13 @@ internal class ItemViewHolder(
|
||||
val data = result.jsonObject
|
||||
if(data != null) {
|
||||
if(accessInfo.isMisskey) {
|
||||
if( enquete.increaseVote(activity,idx,true) ){
|
||||
if(enquete.increaseVote(activity, idx, true)) {
|
||||
showToast(context, false, R.string.enquete_voted)
|
||||
|
||||
|
||||
// 1個だけ開閉するのではなく、例えば通知TLにある複数の要素をまとめて開閉するなどある
|
||||
list_adapter.notifyChange(reason = "onClickEnqueteChoice", reset = true)
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
val message = data.parseString("message") ?: "?"
|
||||
val valid = data.optBoolean("valid")
|
||||
@ -2499,25 +2559,35 @@ internal class ItemViewHolder(
|
||||
}
|
||||
}
|
||||
|
||||
tvMediaDescription = textView{}.lparams(matchParent, wrapContent)
|
||||
tvMediaDescription = textView {}.lparams(matchParent, wrapContent)
|
||||
|
||||
tvCardText = textView{
|
||||
|
||||
}.lparams(matchParent, wrapContent){
|
||||
topMargin = dip(3)
|
||||
}
|
||||
|
||||
ivCardImage = myNetworkImageView {
|
||||
llCardOuter = verticalLayout {
|
||||
lparams(matchParent, wrapContent) {
|
||||
topMargin = dip(3)
|
||||
startMargin = dip(12)
|
||||
endMargin = dip(6)
|
||||
}
|
||||
padding = dip(3)
|
||||
bottomPadding = dip(6)
|
||||
|
||||
contentDescription = context.getString(R.string.thumbnail)
|
||||
background = PreviewCardBorder()
|
||||
|
||||
scaleType = if(Pref.bpDontCropMediaThumb(App1.pref))
|
||||
ImageView.ScaleType.FIT_CENTER
|
||||
else
|
||||
ImageView.ScaleType.CENTER_CROP
|
||||
tvCardText = textView {
|
||||
}.lparams(matchParent, wrapContent) {
|
||||
}
|
||||
|
||||
}.lparams(matchParent, activity.app_state.media_thumb_height) {
|
||||
topMargin = dip(3)
|
||||
ivCardImage = myNetworkImageView {
|
||||
|
||||
contentDescription = context.getString(R.string.thumbnail)
|
||||
|
||||
scaleType = if(Pref.bpDontCropMediaThumb(App1.pref))
|
||||
ImageView.ScaleType.FIT_CENTER
|
||||
else
|
||||
ImageView.ScaleType.CENTER_CROP
|
||||
|
||||
}.lparams(matchParent, activity.app_state.media_thumb_height) {
|
||||
topMargin = dip(3)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2526,7 +2596,6 @@ internal class ItemViewHolder(
|
||||
topMargin = dip(0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// button bar
|
||||
@ -2560,34 +2629,34 @@ internal class ItemViewHolder(
|
||||
|
||||
tvConversationParticipants = textView {
|
||||
text = context.getString(R.string.participants)
|
||||
}.lparams(wrapContent,wrapContent){
|
||||
}.lparams(wrapContent, wrapContent) {
|
||||
endMargin = dip(3)
|
||||
}
|
||||
|
||||
ivConversationIcon1 = myNetworkImageView {
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
}.lparams(dip(24),dip(24)) {
|
||||
}.lparams(dip(24), dip(24)) {
|
||||
endMargin = dip(3)
|
||||
}
|
||||
ivConversationIcon2 = myNetworkImageView {
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
}.lparams(dip(24),dip(24)) {
|
||||
}.lparams(dip(24), dip(24)) {
|
||||
endMargin = dip(3)
|
||||
}
|
||||
ivConversationIcon3 = myNetworkImageView {
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
}.lparams(dip(24),dip(24)) {
|
||||
}.lparams(dip(24), dip(24)) {
|
||||
endMargin = dip(3)
|
||||
}
|
||||
ivConversationIcon4 = myNetworkImageView {
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
}.lparams(dip(24),dip(24)) {
|
||||
}.lparams(dip(24), dip(24)) {
|
||||
endMargin = dip(3)
|
||||
}
|
||||
|
||||
tvConversationIconsMore = textView {
|
||||
|
||||
}.lparams(wrapContent,wrapContent)
|
||||
}.lparams(wrapContent, wrapContent)
|
||||
}
|
||||
|
||||
llSearchTag = linearLayout {
|
||||
|
@ -179,7 +179,7 @@ internal class ViewHolderHeaderProfile(
|
||||
btnFollow.setImageDrawable(null)
|
||||
tvRemoteProfileWarning.visibility = View.GONE
|
||||
} else {
|
||||
tvCreated.text = TootStatus.formatTime(tvCreated.context, who.time_created_at, true)
|
||||
tvCreated.text = TootStatus.formatTime(tvCreated.context, (whoDetail?:who).time_created_at, true)
|
||||
ivBackground.setImageUrl(
|
||||
activity.pref,
|
||||
0f,
|
||||
|
@ -181,7 +181,6 @@ object Action_Follow {
|
||||
override fun background(client : TootApiClient) : TootApiResult? {
|
||||
var result : TootApiResult?
|
||||
|
||||
val parser = TootParser(activity, access_info)
|
||||
|
||||
if(access_info.isMisskey) {
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
package jp.juggler.subwaytooter.api.entity
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
import jp.juggler.subwaytooter.api.TootParser
|
||||
import jp.juggler.subwaytooter.util.HTMLDecoder
|
||||
import jp.juggler.subwaytooter.util.filterNotEmpty
|
||||
import jp.juggler.subwaytooter.util.parseString
|
||||
import org.json.JSONObject
|
||||
|
||||
class TootCard(
|
||||
|
||||
@ -19,10 +21,12 @@ class TootCard(
|
||||
val image : String?,
|
||||
|
||||
val type : String?,
|
||||
val author_name : String?,
|
||||
val author_url : String?,
|
||||
val provider_name : String?,
|
||||
val provider_url : String?
|
||||
val author_name : String? =null,
|
||||
val author_url : String? =null,
|
||||
val provider_name : String? =null,
|
||||
val provider_url : String? =null,
|
||||
|
||||
val originalStatus :TootStatus? =null
|
||||
) {
|
||||
|
||||
constructor(src : JSONObject) : this(
|
||||
@ -38,4 +42,17 @@ class TootCard(
|
||||
provider_url = src.parseString("provider_url")
|
||||
|
||||
)
|
||||
|
||||
constructor(parser: TootParser, src:TootStatus) :this(
|
||||
originalStatus = src,
|
||||
url = src.url,
|
||||
title = "${src.account.display_name} @${parser.linkHelper .getFullAcct(src.account.acct)}",
|
||||
description = if( parser.serviceType==ServiceType.MISSKEY){
|
||||
src.spoiler_text.filterNotEmpty() ?: src.content
|
||||
}else{
|
||||
src.spoiler_text.filterNotEmpty() ?: HTMLDecoder.encodeEntity( src.content ?: "")
|
||||
},
|
||||
image = src.media_attachments ?. firstOrNull() ?. urlForThumbnail ?: src.account.avatar_static,
|
||||
type = "photo"
|
||||
)
|
||||
}
|
||||
|
@ -312,6 +312,18 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
|
||||
|
||||
this.deletedAt = src.parseString("deletedAt")
|
||||
this.time_deleted_at = parseTime(deletedAt)
|
||||
|
||||
if( card == null) {
|
||||
|
||||
if(reblog != null && hasAnyContent() ) {
|
||||
// 引用Renoteにプレビューカードをでっちあげる
|
||||
card = TootCard(parser, reblog)
|
||||
} else if(reply != null ) {
|
||||
// 返信にプレビューカードをでっちあげる
|
||||
card = TootCard(parser, reply!! )
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
misskeyVisibleIds = null
|
||||
reply = null
|
||||
|
@ -0,0 +1,39 @@
|
||||
package jp.juggler.subwaytooter.drawable
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
class PreviewCardBorder : Drawable() {
|
||||
|
||||
var color = 0
|
||||
var round = 0f
|
||||
var width = 1f
|
||||
|
||||
private val paint = Paint()
|
||||
|
||||
override fun draw(canvas : Canvas) {
|
||||
paint.isAntiAlias = true
|
||||
paint.color = color
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = width
|
||||
|
||||
val bounds = this.bounds
|
||||
val left = bounds.left + width/2
|
||||
val right = bounds.right -width/2
|
||||
val top = bounds.top + width/2
|
||||
val bottom = bounds.bottom -width/2
|
||||
|
||||
canvas.drawRoundRect( left,top,right,bottom,round,round,paint )
|
||||
}
|
||||
|
||||
override fun getOpacity() : Int = PixelFormat.TRANSLUCENT
|
||||
|
||||
override fun setAlpha(alpha : Int) =Unit
|
||||
|
||||
override fun setColorFilter(colorFilter : ColorFilter?) =Unit
|
||||
|
||||
|
||||
}
|
@ -21,7 +21,8 @@ class DecodeOptions(
|
||||
var emojiMapProfile : HashMap<String, NicoProfileEmoji>? = null,
|
||||
var highlightTrie : WordTrieTree? = null,
|
||||
var unwrapEmojiImageTag :Boolean = false,
|
||||
var enlargeCustomEmoji :Float = 1f
|
||||
var enlargeCustomEmoji :Float = 1f,
|
||||
var forceHtml : Boolean = false // force use HTML instead of Misskey Markdown
|
||||
) {
|
||||
|
||||
internal fun isMediaAttachment(url : String?) : Boolean {
|
||||
|
@ -468,7 +468,7 @@ object HTMLDecoder {
|
||||
|
||||
fun decodeHTML(options : DecodeOptions, src : String?) : SpannableStringBuilder {
|
||||
|
||||
if( options.linkHelper?.isMisskey == true){
|
||||
if( options.linkHelper?.isMisskey == true && !options.forceHtml ){
|
||||
return MisskeyMarkdownDecoder.decodeMarkdown(options,src)
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,7 @@ class PostHelper(
|
||||
var enquete_items : ArrayList<String>? = null
|
||||
var emojiMapCustom : HashMap<String, CustomEmoji>? = null
|
||||
var redraft_status_id : EntityId? = null
|
||||
var useQuotedRenote : Boolean = false
|
||||
|
||||
private var last_post_tapped : Long = 0L
|
||||
|
||||
@ -358,7 +359,11 @@ class PostHelper(
|
||||
}
|
||||
|
||||
if(in_reply_to_id != null) {
|
||||
json.put("replyId", in_reply_to_id.toString())
|
||||
if( useQuotedRenote){
|
||||
json.put("renoteId", in_reply_to_id.toString())
|
||||
}else{
|
||||
json.put("replyId", in_reply_to_id.toString())
|
||||
}
|
||||
}
|
||||
|
||||
json.put("viaMobile", true)
|
||||
@ -470,8 +475,9 @@ class PostHelper(
|
||||
}
|
||||
|
||||
result = if(isMisskey) {
|
||||
log.d("misskey json %s",body_string)
|
||||
|
||||
client.request("/api/notes/create", request_builder)
|
||||
// TODO {"error":{}} が返ってきた時にどう扱えばいい?
|
||||
} else {
|
||||
client.request("/api/v1/statuses", request_builder)
|
||||
}
|
||||
@ -549,7 +555,7 @@ class PostHelper(
|
||||
private var isMisskey = false
|
||||
|
||||
private val onEmojiListLoad : (list : ArrayList<CustomEmoji>) -> Unit =
|
||||
{ _ : ArrayList<CustomEmoji> ->
|
||||
{
|
||||
val popup = this@PostHelper.popup
|
||||
if(popup?.isShowing == true) proc_text_changed.run()
|
||||
}
|
||||
@ -740,9 +746,9 @@ class PostHelper(
|
||||
val remain = limit - code_list.size
|
||||
if(remain > 0) {
|
||||
val s = src.substring(last_colon + 1, end).toLowerCase().replace('-', '_')
|
||||
val src = EmojiDecoder.searchShortCode(activity, s, remain)
|
||||
log.d("checkEmoji: search for %s, result=%d", s, src.size)
|
||||
code_list.addAll(src)
|
||||
val matches = EmojiDecoder.searchShortCode(activity, s, remain)
|
||||
log.d("checkEmoji: search for %s, result=%d", s, matches.size)
|
||||
code_list.addAll(matches)
|
||||
|
||||
}
|
||||
|
||||
|
@ -488,6 +488,12 @@ fun String?.optInt() : Int? {
|
||||
}
|
||||
}
|
||||
|
||||
fun String?.filterNotEmpty() :String? = when{
|
||||
this==null -> null
|
||||
this.isEmpty() -> null
|
||||
else->this
|
||||
}
|
||||
|
||||
//fun String.ellipsize(max : Int) = if(this.length > max) this.substring(0, max - 1) + "…" else this
|
||||
//
|
||||
//fun String.toCamelCase() : String {
|
||||
|
@ -83,6 +83,14 @@
|
||||
android:src="?attr/btn_close"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbQuoteRenote"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/make_quote_renote"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@ -217,6 +225,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPostFormBackground"
|
||||
android:layout_marginBottom="32dp"
|
||||
>
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyEditText
|
||||
@ -231,11 +240,12 @@
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbEnquete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="@string/make_enquete"
|
||||
/>
|
||||
|
||||
|
@ -784,5 +784,6 @@
|
||||
<string name="participants">会話の参加者:</string>
|
||||
<string name="participants_and_more">…他</string>
|
||||
<string name="conversation_to">送り先:</string>
|
||||
<string name="make_quote_renote">引用Renoteにする</string>
|
||||
|
||||
</resources>
|
||||
|
@ -803,5 +803,6 @@
|
||||
<string name="participants">Conversation participants:</string>
|
||||
<string name="participants_and_more">… and more</string>
|
||||
<string name="conversation_to">To:</string>
|
||||
<string name="make_quote_renote">Use \"Quoted Renote\"</string>
|
||||
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user