This commit is contained in:
tateisu 2020-09-30 02:44:56 +09:00
parent 0de55da66b
commit f4ac870c6a
70 changed files with 1461 additions and 1483 deletions

View File

@ -9,17 +9,19 @@ import android.widget.Button
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.LogCategory import jp.juggler.util.LogCategory
class ActAbout : AppCompatActivity() { class ActAbout : AppCompatActivity() {
class Translators( class Translators(
val name:String, val name : String,
val acct:String?, val acct : String?,
val lang:String val lang : String
) )
companion object { companion object {
val log = LogCategory("ActAbout") val log = LogCategory("ActAbout")
const val EXTRA_SEARCH = "search" const val EXTRA_SEARCH = "search"
@ -33,22 +35,22 @@ class ActAbout : AppCompatActivity() {
// git log --pretty=format:"%an %s" |grep "Translated using Weblate"|sort|uniq // git log --pretty=format:"%an %s" |grep "Translated using Weblate"|sort|uniq
val translators = arrayOf( val translators = arrayOf(
Translators("Allan Nordhøy",null,"English & Norwegian Bokmål"), Translators("Allan Nordhøy", null, "English & Norwegian Bokmål"),
Translators("ButterflyOfFire","@ButterflyOfFire@mstdn.fr", "Arabic & French"), Translators("ButterflyOfFire", "@ButterflyOfFire@mstdn.fr", "Arabic & French"),
Translators("Ch",null,"Korean"), Translators("Ch", null, "Korean"),
Translators("Elizabeth Sherrock",null,"Chinese (Simplified)"), Translators("Elizabeth Sherrock", null, "Chinese (Simplified)"),
Translators("Gennady Archangorodsky",null,"Hebrew"), Translators("Gennady Archangorodsky", null, "Hebrew"),
Translators("inqbs Siina",null,"Korean"), Translators("inqbs Siina", null, "Korean"),
Translators("Jeong Arm","@jarm@qdon.space","Korean"), Translators("Jeong Arm", "@jarm@qdon.space", "Korean"),
Translators("Joan Pujolar","@jpujolar@mastodont.cat","Catalan"), Translators("Joan Pujolar", "@jpujolar@mastodont.cat", "Catalan"),
Translators("Kai Zhang","@bearzk@mastodon.social","Chinese (Simplified)"), Translators("Kai Zhang", "@bearzk@mastodon.social", "Chinese (Simplified)"),
Translators("lptprjh",null,"Korean"), Translators("lptprjh", null, "Korean"),
Translators("mynameismonkey",null,"Welsh"), Translators("mynameismonkey", null, "Welsh"),
Translators("Nathan",null,"French"), Translators("Nathan", null, "French"),
Translators("Owain Rhys Lewis",null,"Welsh"), Translators("Owain Rhys Lewis", null, "Welsh"),
Translators("Swann Martinet",null,"French"), Translators("Swann Martinet", null, "French"),
Translators("takubunn",null,"Chinese (Simplified)"), Translators("takubunn", null, "Chinese (Simplified)"),
Translators("배태길",null,"Korea") Translators("배태길", null, "Korea")
) )
} }
@ -69,7 +71,7 @@ class ActAbout : AppCompatActivity() {
log.trace(ex, "getPackageInfo failed.") log.trace(ex, "getPackageInfo failed.")
} }
fun setButton(btnId : Int, caption : String, onClick : () -> Unit ) { fun setButton(btnId : Int, caption : String, onClick : () -> Unit) {
val b : Button = findViewById(btnId) val b : Button = findViewById(btnId)
b.text = caption b.text = caption
b.setOnClickListener { onClick() } b.setOnClickListener { onClick() }
@ -80,9 +82,6 @@ class ActAbout : AppCompatActivity() {
finish() finish()
} }
fun openUrl(url : String) {
App1.openBrowser(this@ActAbout, url)
}
setButton( setButton(
R.id.btnDeveloper, R.id.btnDeveloper,
@ -94,10 +93,14 @@ class ActAbout : AppCompatActivity() {
getString(R.string.search_for, official_acct) getString(R.string.search_for, official_acct)
) { searchAcct(official_acct) } ) { searchAcct(official_acct) }
setButton(R.id.btnReleaseNote, url_release)
{ openBrowser(url_release) }
setButton(R.id.btnReleaseNote, url_release) { openUrl(url_release) } // setButton(R.id.btnIconDesign, url_futaba)
// setButton(R.id.btnIconDesign, url_futaba) { openUrl(url_futaba) } // { openUrl(url_futaba) }
setButton(R.id.btnWeblate, getString(R.string.please_help_translation) ) { openUrl(url_weblate) }
setButton(R.id.btnWeblate, getString(R.string.please_help_translation))
{ openBrowser(url_weblate) }
val ll = findViewById<LinearLayout>(R.id.llContributors) val ll = findViewById<LinearLayout>(R.id.llContributors)
val density = resources.displayMetrics.density val density = resources.displayMetrics.density
@ -117,7 +120,7 @@ class ActAbout : AppCompatActivity() {
setBackgroundResource(R.drawable.btn_bg_transparent_round6dp) setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
setPadding(padding, padding, padding, padding) setPadding(padding, padding, padding, padding)
isAllCaps = false isAllCaps = false
// //
val acct = who.acct ?: "@?@?" val acct = who.acct ?: "@?@?"
text = "${who.name}\n$acct\n${getString(R.string.thanks_for, who.lang)}" text = "${who.name}\n$acct\n${getString(R.string.thanks_for, who.lang)}"

View File

@ -262,7 +262,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
Styler.fixHorizontalPadding(root) Styler.fixHorizontalPadding(root)
setSwitchColor(this, pref, root) setSwitchColor(pref, root)
tvInstance = findViewById(R.id.tvInstance) tvInstance = findViewById(R.id.tvInstance)
tvUser = findViewById(R.id.tvUser) tvUser = findViewById(R.id.tvUser)
@ -529,7 +529,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
tvUserCustom.backgroundColor = ac.color_bg tvUserCustom.backgroundColor = ac.color_bg
tvUserCustom.text = ac.nickname tvUserCustom.text = ac.nickname
tvUserCustom.textColor = ac.color_fg.notZero() tvUserCustom.textColor = ac.color_fg.notZero()
?: getAttributeColor(this, R.attr.colorTimeSmall) ?: getAttributeColor(R.attr.colorTimeSmall)
} }
private fun saveUIToData() { private fun saveUIToData() {
@ -590,10 +590,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
R.id.btnAccountRemove -> performAccountRemove() R.id.btnAccountRemove -> performAccountRemove()
R.id.btnLoadPreference -> performLoadPreference() R.id.btnLoadPreference -> performLoadPreference()
R.id.btnVisibility -> performVisibility() R.id.btnVisibility -> performVisibility()
R.id.btnOpenBrowser -> App1.openBrowser( R.id.btnOpenBrowser -> openBrowser("https://${account.apiHost.ascii}/")
this@ActAccountSetting,
"https://${account.apiHost.ascii}/"
)
R.id.btnPushSubscription -> startTest() R.id.btnPushSubscription -> startTest()
R.id.btnUserCustom -> ActNickname.open( R.id.btnUserCustom -> ActNickname.open(
@ -694,7 +691,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
val json = result.jsonObject val json = result.jsonObject
if(json == null) { if(json == null) {
showToast(this@ActAccountSetting, true, result.error) showToast(true, result.error)
return return
} }
@ -745,7 +742,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
.setPositiveButton(R.string.ok) { _, _ -> .setPositiveButton(R.string.ok) { _, _ ->
account.delete() account.delete()
val pref = Pref.pref(this@ActAccountSetting) val pref = pref()
if(account.db_id == Pref.lpTabletTootDefaultAccount(pref)) { if(account.db_id == Pref.lpTabletTootDefaultAccount(pref)) {
pref.edit().put(Pref.lpTabletTootDefaultAccount, - 1L).apply() pref.edit().put(Pref.lpTabletTootDefaultAccount, - 1L).apply()
} }
@ -810,7 +807,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
} }
error != null -> { error != null -> {
showToast(this@ActAccountSetting, true, error) showToast(true, error)
log.e("can't get oauth browser URL. $error") log.e("can't get oauth browser URL. $error")
} }
} }
@ -921,7 +918,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
if(data != null) { if(data != null) {
showProfile(data) showProfile(data)
} else { } else {
showToast(this@ActAccountSetting, true, result.error) showToast(true, result.error)
} }
} }
@ -1248,7 +1245,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
if(data != null) { if(data != null) {
showProfile(data) showProfile(data)
} else { } else {
showToast(this@ActAccountSetting, true, result.error) showToast(true, result.error)
for(arg in args) { for(arg in args) {
val key = arg.first val key = arg.first
val value = arg.second val value = arg.second
@ -1401,7 +1398,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
) )
return return
} }
showToast(this, true, R.string.missing_permission_to_access_media) showToast(true, R.string.missing_permission_to_access_media)
} }
override fun onRequestPermissionsResult( override fun onRequestPermissionsResult(
@ -1413,7 +1410,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openPicker(requestCode) openPicker(requestCode)
} else { } else {
showToast(this, true, R.string.missing_permission_to_access_media) showToast(true, R.string.missing_permission_to_access_media)
} }
} }
} }
@ -1424,7 +1421,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
startActivityForResult(intent, request_code) startActivityForResult(intent, request_code)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex, "performAttachment failed.") log.trace(ex, "performAttachment failed.")
showToast(this, ex, "performAttachment failed.") showToast(ex, "performAttachment failed.")
} }
} }
@ -1446,7 +1443,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
startActivityForResult(intent, request_code) startActivityForResult(intent, request_code)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex, "opening camera app failed.") log.trace(ex, "opening camera app failed.")
showToast(this, ex, "opening camera app failed.") showToast(ex, "opening camera app failed.")
} }
} }
@ -1483,7 +1480,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
try { try {
val cache_dir = externalCacheDir val cache_dir = externalCacheDir
if(cache_dir == null) { if(cache_dir == null) {
showToast(this, false, "getExternalCacheDir returns null.") showToast(false, "getExternalCacheDir returns null.")
break break
} }
@ -1522,7 +1519,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex, "Resizing image failed.") log.trace(ex, "Resizing image failed.")
showToast(this, ex, "Resizing image failed.") showToast(ex, "Resizing image failed.")
} }
break break
@ -1549,12 +1546,12 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
private fun addAttachment(request_code : Int, uri : Uri, mime_type : String?) { private fun addAttachment(request_code : Int, uri : Uri, mime_type : String?) {
if(mime_type == null) { if(mime_type == null) {
showToast(this, false, "mime type is not provided.") showToast(false, "mime type is not provided.")
return return
} }
if(! mime_type.startsWith("image/")) { if(! mime_type.startsWith("image/")) {
showToast(this, false, "mime type is not image.") showToast(false, "mime type is not image.")
return return
} }
@ -1583,7 +1580,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
) )
override fun background(client : TootApiClient) : TootApiResult? { override fun background(client : TootApiClient) : TootApiResult? {
return wps.updateSubscription(client,true) return wps.updateSubscription(client, true)
} }
override fun handleResult(result : TootApiResult?) { override fun handleResult(result : TootApiResult?) {

View File

@ -81,7 +81,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
App1.setActivityTheme(this, noActionBar = true) App1.setActivityTheme(this, noActionBar = true)
this.handler = App1.getAppState(this).handler this.handler = App1.getAppState(this).handler
this.pref = Pref.pref(this) this.pref = pref()
// val intent = this.intent // val intent = this.intent
// val layoutId = intent.getIntExtra(EXTRA_LAYOUT_ID, 0) // val layoutId = intent.getIntExtra(EXTRA_LAYOUT_ID, 0)
@ -373,7 +373,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val margin_tb = dip(6) val margin_tb = dip(6)
setMargins(margin_lr, margin_tb, margin_lr, margin_tb) setMargins(margin_lr, margin_tb, margin_lr, margin_tb)
} }
setBackgroundColor(getAttributeColor(context, R.attr.colorSettingDivider)) setBackgroundColor(context.getAttributeColor(R.attr.colorSettingDivider))
}) })
} }
@ -538,7 +538,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
item.pref.cast() ?: error("$name has no boolean pref") item.pref.cast() ?: error("$name has no boolean pref")
showCaption(name) showCaption(name)
swSwitch.vg(false) // skip animation swSwitch.vg(false) // skip animation
setSwitchColor(activity, pref, swSwitch) setSwitchColor(pref, swSwitch)
swSwitch.isEnabled = item.enabled swSwitch.isEnabled = item.enabled
swSwitch.isChecked = bp(pref) swSwitch.isChecked = bp(pref)
swSwitch.vg(true) swSwitch.vg(true)
@ -840,7 +840,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val intent = intentOpenDocument("*/*") val intent = intentOpenDocument("*/*")
startActivityForResult(intent, REQUEST_CODE_APP_DATA_IMPORT) startActivityForResult(intent, REQUEST_CODE_APP_DATA_IMPORT)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, ex, "importAppData(1) failed.") showToast(ex, "importAppData(1) failed.")
} }
} }
@ -884,7 +884,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
} }
fun setSwitchColor() = fun setSwitchColor() =
setSwitchColor(this@ActAppSetting, pref, lvList) setSwitchColor(pref, lvList)
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
@ -955,7 +955,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
private fun saveTimelineFont(uri : Uri?, file_name : String) : File? { private fun saveTimelineFont(uri : Uri?, file_name : String) : File? {
try { try {
if(uri == null) { if(uri == null) {
showToast(this, false, "missing uri.") showToast(false, "missing uri.")
return null return null
} }
@ -969,7 +969,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val source : InputStream? = contentResolver.openInputStream(uri) val source : InputStream? = contentResolver.openInputStream(uri)
if(source == null) { if(source == null) {
showToast(this, false, "openInputStream returns null. uri=%s", uri) showToast(false, "openInputStream returns null. uri=%s", uri)
return null return null
} else { } else {
source.use { inStream -> source.use { inStream ->
@ -981,20 +981,20 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val face = Typeface.createFromFile(tmp_file) val face = Typeface.createFromFile(tmp_file)
if(face == null) { if(face == null) {
showToast(this, false, "Typeface.createFromFile() failed.") showToast(false, "Typeface.createFromFile() failed.")
return null return null
} }
val file = File(dir, file_name) val file = File(dir, file_name)
if(! tmp_file.renameTo(file)) { if(! tmp_file.renameTo(file)) {
showToast(this, false, "File operation failed.") showToast(false, "File operation failed.")
return null return null
} }
return file return file
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "saveTimelineFont failed.") showToast(ex, "saveTimelineFont failed.")
return null return null
} }
@ -1177,10 +1177,10 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
} }
) { setCustomShare(target, it) } ) { setCustomShare(target, it) }
.show() .show()
if(! rv) showToast(this, true, "share target app is not installed.") if(! rv) showToast(true, "share target app is not installed.")
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "openCustomShareChooser failed.") showToast(ex, "openCustomShareChooser failed.")
} }
} }

View File

@ -33,6 +33,7 @@ import kotlin.math.max
class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPickerDialogListener { class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPickerDialogListener {
companion object { companion object {
internal val log = LogCategory("ActColumnCustomize") internal val log = LogCategory("ActColumnCustomize")
internal const val EXTRA_COLUMN_INDEX = "column_index" internal const val EXTRA_COLUMN_INDEX = "column_index"
@ -298,7 +299,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
show() show()
} }
else -> showToast(this@ActColumnCustomize, true, result.error ?: "?") else -> showToast(true, result.error ?: "?")
} }
} }
}) })
@ -395,18 +396,18 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
} }
}) })
etAlpha.setOnEditorActionListener{ _, actionId, _-> etAlpha.setOnEditorActionListener { _, actionId, _ ->
when(actionId) { when(actionId) {
EditorInfo.IME_ACTION_DONE -> { EditorInfo.IME_ACTION_DONE -> {
etAlpha.hideKeyboard() etAlpha.hideKeyboard()
true true
} }
else -> false else -> false
} }
} }
} }
private fun show() { private fun show() {
try { try {
loading_busy = true loading_busy = true

View File

@ -21,6 +21,7 @@ import java.util.*
class ActColumnList : AppCompatActivity() { class ActColumnList : AppCompatActivity() {
companion object { companion object {
private val log = LogCategory("ActColumnList") private val log = LogCategory("ActColumnList")
internal const val TMP_FILE_COLUMN_LIST = "tmp_column_list" internal const val TMP_FILE_COLUMN_LIST = "tmp_column_list"
@ -119,11 +120,7 @@ class ActColumnList : AppCompatActivity() {
if(swipedDirection == ListSwipeItem.SwipeDirection.LEFT) { if(swipedDirection == ListSwipeItem.SwipeDirection.LEFT) {
val adapterItem = item.tag as MyItem val adapterItem = item.tag as MyItem
if(adapterItem.json.optBoolean(Column.KEY_DONT_CLOSE, false)) { if(adapterItem.json.optBoolean(Column.KEY_DONT_CLOSE, false)) {
showToast( showToast(false, R.string.column_has_dont_close_option)
this@ActColumnList,
false,
R.string.column_has_dont_close_option
)
listView.resetSwipedViews(null) listView.resetSwipedViews(null)
return return
} }
@ -203,7 +200,7 @@ class ActColumnList : AppCompatActivity() {
val type = ColumnType.parse(json.optInt(Column.KEY_TYPE)) val type = ColumnType.parse(json.optInt(Column.KEY_TYPE))
val acct_color_bg = json.optInt(Column.KEY_COLUMN_ACCESS_COLOR_BG, 0) val acct_color_bg = json.optInt(Column.KEY_COLUMN_ACCESS_COLOR_BG, 0)
val acct_color_fg = json.optInt(Column.KEY_COLUMN_ACCESS_COLOR, 0) val acct_color_fg = json.optInt(Column.KEY_COLUMN_ACCESS_COLOR, 0)
.notZero() ?: getAttributeColor(context, R.attr.colorColumnListItemText) .notZero() ?: context.getAttributeColor(R.attr.colorColumnListItemText)
var bOldSelection : Boolean = false var bOldSelection : Boolean = false
fun setOldSelection(b : Boolean) { fun setOldSelection(b : Boolean) {
@ -276,16 +273,14 @@ class ActColumnList : AppCompatActivity() {
dragView.findViewById<View>(R.id.ivBookmark).visibility = dragView.findViewById<View>(R.id.ivBookmark).visibility =
clickedView.findViewById<View>(R.id.ivBookmark).visibility clickedView.findViewById<View>(R.id.ivBookmark).visibility
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor( dragView.findViewById<View>(R.id.item_layout)
getAttributeColor(this@ActColumnList, R.attr.list_item_bg_pressed_dragged) .setBackgroundColor(getAttributeColor(R.attr.list_item_bg_pressed_dragged))
)
} }
} }
private inner class MyListAdapter : private inner class MyListAdapter :
DragItemAdapter<MyItem, MyViewHolder>() { DragItemAdapter<MyItem, MyViewHolder>() {
init { init {
setHasStableIds(true) setHasStableIds(true)
itemList = ArrayList() itemList = ArrayList()

View File

@ -171,9 +171,8 @@ class ActFavMute : AppCompatActivity() {
dragView.findViewById<TextView>(R.id.tvName).text = dragView.findViewById<TextView>(R.id.tvName).text =
clickedView.findViewById<TextView>(R.id.tvName).text clickedView.findViewById<TextView>(R.id.tvName).text
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor( dragView.findViewById<View>(R.id.item_layout)
getAttributeColor(this@ActFavMute, R.attr.list_item_bg_pressed_dragged) .setBackgroundColor(getAttributeColor(R.attr.list_item_bg_pressed_dragged))
)
} }
} }

View File

@ -116,8 +116,8 @@ class ActHighlightWordEdit
swSpeech = findViewById(R.id.swSpeech) swSpeech = findViewById(R.id.swSpeech)
swSpeech.setOnCheckedChangeListener(this) swSpeech.setOnCheckedChangeListener(this)
setSwitchColor(this, App1.pref, swSound) setSwitchColor(App1.pref, swSound)
setSwitchColor(this, App1.pref, swSpeech) setSwitchColor(App1.pref, swSpeech)
intArrayOf( intArrayOf(
R.id.btnTextColorEdit, R.id.btnTextColorEdit,
@ -142,7 +142,7 @@ class ActHighlightWordEdit
tvName.text = item.name tvName.text = item.name
tvName.setBackgroundColor(item.color_bg) // may 0 tvName.setBackgroundColor(item.color_bg) // may 0
tvName.textColor = item.color_fg.notZero() tvName.textColor = item.color_fg.notZero()
?: getAttributeColor(this, android.R.attr.textColorPrimary) ?: getAttributeColor(android.R.attr.textColorPrimary)
} finally { } finally {
bBusy = false bBusy = false

View File

@ -136,7 +136,7 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
val tvName : TextView val tvName : TextView
private val btnSound : View private val btnSound : View
private val ivSpeech: ImageButton private val ivSpeech : ImageButton
init { init {
@ -160,15 +160,15 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
tvName.setBackgroundColor(item.color_bg) tvName.setBackgroundColor(item.color_bg)
tvName.setTextColor( tvName.setTextColor(
item.color_fg.notZero() item.color_fg.notZero()
?: getAttributeColor(this@ActHighlightWordList, android.R.attr.textColorPrimary) ?: getAttributeColor(android.R.attr.textColorPrimary)
) )
btnSound.vg(item.sound_type != HighlightWord.SOUND_TYPE_NONE)?.apply{ btnSound.vg(item.sound_type != HighlightWord.SOUND_TYPE_NONE)?.apply {
setOnClickListener(this@MyViewHolder) setOnClickListener(this@MyViewHolder)
tag = item tag = item
} }
ivSpeech.vg(item.speech != 0 )?.apply{ ivSpeech.vg(item.speech != 0)?.apply {
setOnClickListener(this@MyViewHolder) setOnClickListener(this@MyViewHolder)
tag = item tag = item
} }
@ -189,12 +189,14 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
override fun onClick(v : View) { override fun onClick(v : View) {
val o = v.tag val o = v.tag
if(o is HighlightWord) { if(o is HighlightWord) {
when(v.id){ when(v.id) {
R.id.btnSound->{ R.id.btnSound -> {
sound(o) sound(o)
} }
R.id.ivSpeech->{
App1.getAppState(this@ActHighlightWordList).addSpeech(o.name,dedupMode = DedupMode.None) R.id.ivSpeech -> {
App1.getAppState(this@ActHighlightWordList)
.addSpeech(o.name, dedupMode = DedupMode.None)
} }
} }
} }
@ -206,22 +208,18 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
DragItem(context, layoutId) { DragItem(context, layoutId) {
override fun onBindDragView(clickedView : View, dragView : View) { override fun onBindDragView(clickedView : View, dragView : View) {
dragView.findViewById<TextView>(R.id.tvName).text = dragView.findViewById<TextView>(R.id.tvName).text =
clickedView.findViewById<TextView>(R.id.tvName).text clickedView.findViewById<TextView>(R.id.tvName).text
dragView.findViewById<View>(R.id.btnSound).visibility = dragView.findViewById<View>(R.id.btnSound).visibility =
clickedView.findViewById<View>(R.id.btnSound).visibility clickedView.findViewById<View>(R.id.btnSound).visibility
dragView.findViewById<View>(R.id.ivSpeech).visibility= dragView.findViewById<View>(R.id.ivSpeech).visibility =
clickedView.findViewById<View>(R.id.ivSpeech).visibility clickedView.findViewById<View>(R.id.ivSpeech).visibility
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor( dragView.findViewById<View>(R.id.item_layout)
getAttributeColor( .setBackgroundColor(getAttributeColor(R.attr.list_item_bg_pressed_dragged))
this@ActHighlightWordList,
R.attr.list_item_bg_pressed_dragged
)
)
} }
} }
@ -250,23 +248,27 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
} }
private fun create() { private fun create() {
DlgTextInput.show(this, getString(R.string.new_item), "", callback = object : DlgTextInput.Callback { DlgTextInput.show(
override fun onEmptyError() { this,
showToast(this@ActHighlightWordList, true, R.string.word_empty) getString(R.string.new_item),
} "",
callback = object : DlgTextInput.Callback {
override fun onOK(dialog : Dialog, text : String) { override fun onEmptyError() {
var item = HighlightWord.load(text) showToast(true, R.string.word_empty)
if(item == null) {
item = HighlightWord(text)
item.save(this@ActHighlightWordList)
loadData()
} }
edit(item)
dialog.dismissSafe() override fun onOK(dialog : Dialog, text : String) {
} var item = HighlightWord.load(text)
}) if(item == null) {
item = HighlightWord(text)
item.save(this@ActHighlightWordList)
loadData()
}
edit(item)
dialog.dismissSafe()
}
})
} }
private fun edit(item : HighlightWord) { private fun edit(item : HighlightWord) {

View File

@ -178,7 +178,7 @@ class ActKeywordFilter
onLoadComplete(filter) onLoadComplete(filter)
} else { } else {
if(result != null) { if(result != null) {
showToast(this@ActKeywordFilter, true, result.error ?: "?") showToast(true, result.error ?: "?")
} }
finish() finish()
} }
@ -287,9 +287,9 @@ class ActKeywordFilter
result ?: return result ?: return
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(this@ActKeywordFilter, true, result.error) showToast(true, result.error)
} else { } else {
val app_state = App1.prepare(applicationContext,"ActKeywordFilter.save()") val app_state = App1.prepare(applicationContext, "ActKeywordFilter.save()")
for(column in app_state.column_list) { for(column in app_state.column_list) {
if(column.type == ColumnType.KEYWORD_FILTER && column.access_info == account) { if(column.type == ColumnType.KEYWORD_FILTER && column.access_info == account) {
column.filter_reload_required = true column.filter_reload_required = true

View File

@ -33,6 +33,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
) )
companion object { companion object {
internal val log = LogCategory("ActLanguageFilter") internal val log = LogCategory("ActLanguageFilter")
internal const val EXTRA_COLUMN_INDEX = "column_index" internal const val EXTRA_COLUMN_INDEX = "column_index"
@ -240,7 +241,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
getString(if(item.allow) R.string.language_show else R.string.language_hide) getString(if(item.allow) R.string.language_show else R.string.language_hide)
) )
tv.textColor = getAttributeColor( tv.textColor = getAttributeColor(
this@ActLanguageFilter, when(item.allow) { when(item.allow) {
true -> R.attr.colorContentText true -> R.attr.colorContentText
false -> R.attr.colorRegexFilterError false -> R.attr.colorRegexFilterError
} }
@ -310,6 +311,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
private object DlgLanguageFilter { private object DlgLanguageFilter {
interface Callback { interface Callback {
fun onOK(code : String, allow : Boolean) fun onOK(code : String, allow : Boolean)
fun onDelete(code : String) fun onDelete(code : String)
} }
@ -371,7 +373,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
btnPresets.setEnabledColor( btnPresets.setEnabledColor(
activity, activity,
R.drawable.ic_edit, R.drawable.ic_edit,
getAttributeColor(activity, R.attr.colorVectorDrawable), activity.getAttributeColor(R.attr.colorVectorDrawable),
false false
) )
} }
@ -439,9 +441,8 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
val intent = intentOpenDocument("*/*") val intent = intentOpenDocument("*/*")
startActivityForResult(intent, REQUEST_CODE_IMPORT) startActivityForResult(intent, REQUEST_CODE_IMPORT)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, ex, "import failed.") showToast(ex, "import failed.")
} }
} }
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) { override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
@ -460,7 +461,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
log.d("import2 type=${contentResolver.getType(uri)}") log.d("import2 type=${contentResolver.getType(uri)}")
val source = contentResolver.openInputStream(uri) val source = contentResolver.openInputStream(uri)
if(source == null) { if(source == null) {
showToast( true, "openInputStream failed.") showToast(true, "openInputStream failed.")
null null
} else { } else {
source.use { inStream -> source.use { inStream ->

View File

@ -176,41 +176,41 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// 変更しない変数 // 変更しない変数
val follow_complete_callback : EmptyCallback = { val follow_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.follow_succeeded) showToast(false, R.string.follow_succeeded)
} }
val unfollow_complete_callback : EmptyCallback = { val unfollow_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.unfollow_succeeded) showToast(false, R.string.unfollow_succeeded)
} }
val cancel_follow_request_complete_callback : EmptyCallback = { val cancel_follow_request_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.follow_request_cancelled) showToast(false, R.string.follow_request_cancelled)
} }
val favourite_complete_callback : EmptyCallback = { val favourite_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.favourite_succeeded) showToast(false, R.string.favourite_succeeded)
} }
val unfavourite_complete_callback : EmptyCallback = { val unfavourite_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.unfavourite_succeeded) showToast(false, R.string.unfavourite_succeeded)
} }
val bookmark_complete_callback : EmptyCallback = { val bookmark_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.bookmark_succeeded) showToast(false, R.string.bookmark_succeeded)
} }
val unbookmark_complete_callback : EmptyCallback = { val unbookmark_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.unbookmark_succeeded) showToast(false, R.string.unbookmark_succeeded)
} }
val boost_complete_callback : EmptyCallback = { val boost_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.boost_succeeded) showToast(false, R.string.boost_succeeded)
} }
val unboost_complete_callback : EmptyCallback = { val unboost_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.unboost_succeeded) showToast(false, R.string.unboost_succeeded)
} }
val reaction_complete_callback : EmptyCallback = { val reaction_complete_callback : ()->Unit = {
showToast(this@ActMain, false, R.string.reaction_succeeded) showToast(false, R.string.reaction_succeeded)
} }
// 相対時刻の表記を定期的に更新する // 相対時刻の表記を定期的に更新する
@ -566,7 +566,8 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
ItemViewHolder.toot_color_direct_me = Pref.ipTootColorDirectMe(pref) ItemViewHolder.toot_color_direct_me = Pref.ipTootColorDirectMe(pref)
MyClickableSpan.showLinkUnderline = Pref.bpShowLinkUnderline(pref) MyClickableSpan.showLinkUnderline = Pref.bpShowLinkUnderline(pref)
MyClickableSpan.defaultLinkColor = Pref.ipLinkColor(pref).notZero() MyClickableSpan.defaultLinkColor = Pref.ipLinkColor(pref).notZero()
?: getAttributeColor(this, R.attr.colorLink) ?: getAttributeColor(R.attr.colorLink)
CustomShare.reloadCache(this, pref) CustomShare.reloadCache(this, pref)
te = SystemClock.elapsedRealtime() te = SystemClock.elapsedRealtime()
@ -1099,7 +1100,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
} }
if(resultCode == Activity.RESULT_OK && data != null) { if(resultCode == Activity.RESULT_OK && data != null) {
App1.openBrowser(this, data.data) openBrowser(data.data)
} else if(resultCode == ActAccountSetting.RESULT_INPUT_ACCESS_TOKEN && data != null) { } else if(resultCode == ActAccountSetting.RESULT_INPUT_ACCESS_TOKEN && data != null) {
val db_id = data.getLongExtra(ActAccountSetting.EXTRA_DB_ID, - 1L) val db_id = data.getLongExtra(ActAccountSetting.EXTRA_DB_ID, - 1L)
checkAccessToken2(db_id) checkAccessToken2(db_id)
@ -1195,7 +1196,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
) { ) {
this@ActMain.finish() this@ActMain.finish()
} else { } else {
showToast(this@ActMain, false, R.string.missing_closeable_column) showToast(false, R.string.missing_closeable_column)
} }
} }
@ -1205,7 +1206,6 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
else -> { else -> {
showToast( showToast(
this@ActMain,
false, false,
R.string.cant_close_column_by_back_button_when_multiple_column_shown R.string.cant_close_column_by_back_button_when_multiple_column_shown
) )
@ -2048,28 +2048,25 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
// cancelled. // cancelled.
} }
error != null -> showToast( error != null ->
this@ActMain, showToast(true, "${result.error} ${result.requestInfo}".trim())
true,
"${result.error} ${result.requestInfo}".trim()
)
token_info == null -> showToast(this@ActMain, true, "can't get access token.") token_info == null -> showToast(true, "can't get access token.")
jsonObject == null -> showToast(this@ActMain, true, "can't parse json response.") jsonObject == null -> showToast(true, "can't parse json response.")
// 自分のユーザネームを取れなかった // 自分のユーザネームを取れなかった
// …普通はエラーメッセージが設定されてるはずだが // …普通はエラーメッセージが設定されてるはずだが
ta == null -> showToast(this@ActMain, true, "can't verify user credential.") ta == null -> showToast(true, "can't verify user credential.")
// アクセストークン更新時 // アクセストークン更新時
// インスタンスは同じだと思うが、ユーザ名が異なる可能性がある // インスタンスは同じだと思うが、ユーザ名が異なる可能性がある
sa != null -> sa != null ->
if(sa.username != ta.username) { if(sa.username != ta.username) {
showToast(this@ActMain, true, R.string.user_name_not_match) showToast(true, R.string.user_name_not_match)
} else { } else {
showToast( showToast(
this@ActMain,
false, false,
R.string.access_token_updated_for, R.string.access_token_updated_for,
sa.acct.pretty sa.acct.pretty
@ -2100,7 +2097,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val apDomain = ti?.uri val apDomain = ti?.uri
if(apDomain == null) { if(apDomain == null) {
showToast(this@ActMain, false, "Can't get ActivityPub domain name.") showToast(false, "Can't get ActivityPub domain name.")
return false return false
} }
@ -2138,7 +2135,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
} }
} }
showToast(this@ActMain, false, R.string.account_confirmed) showToast(false, R.string.account_confirmed)
// 通知の更新が必要かもしれない // 通知の更新が必要かもしれない
PollingWorker.queueUpdateNotification(this@ActMain) PollingWorker.queueUpdateNotification(this@ActMain)
@ -2221,7 +2218,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
} }
override fun onEmptyError() { override fun onEmptyError() {
showToast(this@ActMain, true, R.string.token_not_specified) showToast(true, R.string.token_not_specified)
} }
}) })
} }
@ -2252,7 +2249,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
fun closeColumn(column : Column, bConfirmed : Boolean = false) { fun closeColumn(column : Column, bConfirmed : Boolean = false) {
if(column.dont_close) { if(column.dont_close) {
showToast(this, false, R.string.column_has_dont_close_option) showToast(false, R.string.column_has_dont_close_option)
return return
} }
@ -2452,9 +2449,9 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
when(fullAcct.host.ascii) { when(fullAcct.host.ascii) {
"github.com", "github.com",
"twitter.com" -> "twitter.com" ->
App1.openCustomTab(this, mention.url) openCustomTab(mention.url)
"gmail.com" -> "gmail.com" ->
App1.openBrowser(this, "mailto:${fullAcct.pretty}") openBrowser("mailto:${fullAcct.pretty}")
else -> else ->
Action_User.profile( Action_User.profile(
@ -2485,11 +2482,11 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val instanceHost = Host.parse(instance) val instanceHost = Host.parse(instance)
when(instanceHost.ascii) { when(instanceHost.ascii) {
"github.com", "twitter.com" -> { "github.com", "twitter.com" -> {
App1.openCustomTab(this, "https://$instance/$user") openCustomTab("https://$instance/$user")
} }
"gmail.com" -> { "gmail.com" -> {
App1.openBrowser(this, "mailto:$user@$instance") openBrowser("mailto:$user@$instance")
} }
else -> { else -> {
@ -2535,7 +2532,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
} }
App1.openCustomTab(this, opener.url) openCustomTab(opener.url)
} catch(ex : Throwable) { } catch(ex : Throwable) {
// warning.trace( ex ); // warning.trace( ex );
@ -2563,7 +2560,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val footer_tab_indicator_color = Pref.ipFooterTabIndicatorColor(pref) val footer_tab_indicator_color = Pref.ipFooterTabIndicatorColor(pref)
val colorColumnStripBackground = footer_tab_bg_color.notZero() val colorColumnStripBackground = footer_tab_bg_color.notZero()
?: getAttributeColor(this, R.attr.colorColumnStripBackground) ?: getAttributeColor(R.attr.colorColumnStripBackground)
svColumnStrip.setBackgroundColor(colorColumnStripBackground) svColumnStrip.setBackgroundColor(colorColumnStripBackground)
llQuickTootBar.setBackgroundColor(colorColumnStripBackground) llQuickTootBar.setBackgroundColor(colorColumnStripBackground)
@ -2572,7 +2569,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
?: colorColumnStripBackground ?: colorColumnStripBackground
val colorButtonFg = footer_button_fg_color.notZero() val colorButtonFg = footer_button_fg_color.notZero()
?: getAttributeColor(this, R.attr.colorRippleEffect) ?: getAttributeColor(R.attr.colorRippleEffect)
btnMenu.backgroundDrawable = btnMenu.backgroundDrawable =
getAdaptiveRippleDrawableRound(this, colorButtonBg, colorButtonFg) getAdaptiveRippleDrawableRound(this, colorButtonBg, colorButtonFg)
@ -2585,7 +2582,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val csl = ColorStateList.valueOf( val csl = ColorStateList.valueOf(
footer_button_fg_color.notZero() footer_button_fg_color.notZero()
?: getAttributeColor(this, R.attr.colorVectorDrawable) ?: getAttributeColor(R.attr.colorVectorDrawable)
) )
btnToot.imageTintList = csl btnToot.imageTintList = csl
btnMenu.imageTintList = csl btnMenu.imageTintList = csl
@ -2598,7 +2595,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
vFooterDivider2.setBackgroundColor(c) vFooterDivider2.setBackgroundColor(c)
llColumnStrip.indicatorColor = footer_tab_indicator_color.notZero() llColumnStrip.indicatorColor = footer_tab_indicator_color.notZero()
?: getAttributeColor(this, R.attr.colorAccent) ?: getAttributeColor(R.attr.colorAccent)
} }
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
@ -2878,7 +2875,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
if(zipEntryCount != 0) { if(zipEntryCount != 0) {
showToast(this@ActMain, ex, "importAppData failed.") showToast(ex, "importAppData failed.")
} }
} }
// zipではなかった場合、zipEntryがない状態になる。例外はPH-1では出なかったが、出ても問題ないようにする。 // zipではなかった場合、zipEntryがない状態になる。例外はPH-1では出なかったが、出ても問題ないようにする。
@ -2914,7 +2911,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
PollingWorker.queueAppDataImportAfter(this@ActMain) PollingWorker.queueAppDataImportAfter(this@ActMain)
} }
showToast(this@ActMain, true, R.string.import_completed_please_restart_app) showToast(true, R.string.import_completed_please_restart_app)
finish() finish()
}, },
preProc = { preProc = {

View File

@ -107,9 +107,8 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
private lateinit var svDescription : View private lateinit var svDescription : View
private lateinit var tvDescription : TextView private lateinit var tvDescription : TextView
private lateinit var tvStatus : TextView private lateinit var tvStatus : TextView
private lateinit var cbMute: CheckBox private lateinit var cbMute : CheckBox
private var lastVolume = Float.NaN private var lastVolume = Float.NaN
internal var buffering_last_shown : Long = 0 internal var buffering_last_shown : Long = 0
@ -149,7 +148,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
val now = SystemClock.elapsedRealtime() val now = SystemClock.elapsedRealtime()
if(now - buffering_last_shown >= short_limit && exoPlayer.duration >= short_limit) { if(now - buffering_last_shown >= short_limit && exoPlayer.duration >= short_limit) {
buffering_last_shown = now buffering_last_shown = now
showToast(this@ActMediaViewer, false, R.string.video_buffering) showToast(false, R.string.video_buffering)
} }
/* /*
exoPlayer.getDuration() may returns negative value (TIME_UNSET ,same as Long.MIN_VALUE + 1). exoPlayer.getDuration() may returns negative value (TIME_UNSET ,same as Long.MIN_VALUE + 1).
@ -163,7 +162,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
override fun onPlayerError(error : ExoPlaybackException) { override fun onPlayerError(error : ExoPlaybackException) {
log.d("exoPlayer onPlayerError") log.d("exoPlayer onPlayerError")
showToast(this@ActMediaViewer, error, "player error.") showToast(error, "player error.")
} }
override fun onPositionDiscontinuity(reason : Int) { override fun onPositionDiscontinuity(reason : Int) {
@ -187,7 +186,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
outState.putLong(STATE_PLAYER_POS, exoPlayer.currentPosition) outState.putLong(STATE_PLAYER_POS, exoPlayer.currentPosition)
outState.putBoolean(STATE_PLAYER_PLAY_WHEN_READY, exoPlayer.playWhenReady) outState.putBoolean(STATE_PLAYER_PLAY_WHEN_READY, exoPlayer.playWhenReady)
outState.putFloat(STATE_LAST_VOLUME,lastVolume) outState.putFloat(STATE_LAST_VOLUME, lastVolume)
} }
override fun onCreate(savedInstanceState : Bundle?) { override fun onCreate(savedInstanceState : Bundle?) {
@ -252,14 +251,14 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
findViewById<View>(R.id.btnDownload).setOnClickListener(this) findViewById<View>(R.id.btnDownload).setOnClickListener(this)
findViewById<View>(R.id.btnMore).setOnClickListener(this) findViewById<View>(R.id.btnMore).setOnClickListener(this)
cbMute.setOnCheckedChangeListener{_,isChecked-> cbMute.setOnCheckedChangeListener { _, isChecked ->
if(isChecked) { if(isChecked) {
// mute // mute
lastVolume = exoPlayer.volume lastVolume = exoPlayer.volume
exoPlayer.volume = 0f exoPlayer.volume = 0f
}else{ } else {
// unmute // unmute
exoPlayer.volume = when{ exoPlayer.volume = when {
lastVolume.isNaN() -> 1f lastVolume.isNaN() -> 1f
lastVolume <= 0f -> 1f lastVolume <= 0f -> 1f
else -> lastVolume else -> lastVolume
@ -361,7 +360,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
private fun loadVideo(ta : TootAttachment, state : Bundle? = null) { private fun loadVideo(ta : TootAttachment, state : Bundle? = null) {
cbMute.vg(true) cbMute.vg(true)
if(cbMute.isChecked && lastVolume.isFinite() ) { if(cbMute.isChecked && lastVolume.isFinite()) {
exoPlayer.volume = 0f exoPlayer.volume = 0f
} }
@ -399,7 +398,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
} else { } else {
exoPlayer.playWhenReady = state.getBoolean(STATE_PLAYER_PLAY_WHEN_READY, true) exoPlayer.playWhenReady = state.getBoolean(STATE_PLAYER_PLAY_WHEN_READY, true)
exoPlayer.seekTo(max(0L, state.getLong(STATE_PLAYER_POS, 0L))) exoPlayer.seekTo(max(0L, state.getLong(STATE_PLAYER_POS, 0L)))
lastVolume = state.getFloat(STATE_LAST_VOLUME,1f) lastVolume = state.getFloat(STATE_LAST_VOLUME, 1f)
} }
} }
@ -486,7 +485,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
private fun loadBitmap(ta : TootAttachment) { private fun loadBitmap(ta : TootAttachment) {
cbMute.visibility=View.INVISIBLE cbMute.visibility = View.INVISIBLE
val urlList = ta.getLargeUrlList(App1.pref) val urlList = ta.getLargeUrlList(App1.pref)
if(urlList.isEmpty()) { if(urlList.isEmpty()) {
@ -546,7 +545,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
return Pair(null, "image size <= 0") return Pair(null, "image size <= 0")
} }
val dstSize = rotateSize(orientation,srcWidth,srcHeight) val dstSize = rotateSize(orientation, srcWidth, srcHeight)
val dstSizeInt = Point( val dstSizeInt = Point(
max(1, (dstSize.x + 0.5f).toInt()), max(1, (dstSize.x + 0.5f).toInt()),
max(1, (dstSize.y + 0.5f).toInt()) max(1, (dstSize.y + 0.5f).toInt())
@ -599,13 +598,13 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
) : Pair<TootApiResult?, ByteArray?> { ) : Pair<TootApiResult?, ByteArray?> {
val result = TootApiResult.makeWithCaption(url) val result = TootApiResult.makeWithCaption(url)
val request = try{ val request = try {
Request.Builder() Request.Builder()
.url(url) .url(url)
.cacheControl(App1.CACHE_CONTROL) .cacheControl(App1.CACHE_CONTROL)
.addHeader("Accept", "image/webp,image/*,*/*;q=0.8") .addHeader("Accept", "image/webp,image/*,*/*;q=0.8")
.build() .build()
}catch(ex:Throwable){ } catch(ex : Throwable) {
result.setError(ex.withCaption("incorrect URL.")) result.setError(ex.withCaption("incorrect URL."))
return Pair(result, null) return Pair(result, null)
} }
@ -667,7 +666,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
if(bitmap != null) { if(bitmap != null) {
pbvImage.setBitmap(bitmap) pbvImage.setBitmap(bitmap)
} else if(result != null) { } else if(result != null) {
showToast(this@ActMediaViewer, true, result.error) showToast(true, result.error)
} }
} }
}) })
@ -684,7 +683,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
R.id.btnMore -> more(media_list[idx]) R.id.btnMore -> more(media_list[idx])
} }
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, ex, "action failed.") showToast(ex, "action failed.")
} }
} }
@ -702,7 +701,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
return return
} }
val downLoadManager :DownloadManager = systemService(this) val downLoadManager : DownloadManager = systemService(this)
?: error("missing DownloadManager system service") ?: error("missing DownloadManager system service")
val url = if(ta is TootAttachment) { val url = if(ta is TootAttachment) {
@ -724,7 +723,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
it.remove() it.remove()
} else if(url == dh.url) { } else if(url == dh.url) {
// 履歴に同じURLがあればエラーとする // 履歴に同じURLがあればエラーとする
showToast(this, false, R.string.dont_repeat_download_to_same_url) showToast(false, R.string.dont_repeat_download_to_same_url)
return return
} }
} }
@ -773,7 +772,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
downLoadManager.enqueue(request) downLoadManager.enqueue(request)
showToast(this, false, R.string.downloading) showToast(false, R.string.downloading)
} }
private fun share(action : String, url : String) { private fun share(action : String, url : String) {
@ -790,7 +789,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
startActivity(intent) startActivity(intent)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, ex, "can't open app.") showToast(ex, "can't open app.")
} }
} }
@ -812,10 +811,10 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
//クリップボードにデータを格納 //クリップボードにデータを格納
cm.setPrimaryClip(cd) cm.setPrimaryClip(cd)
showToast(this, false, R.string.url_is_copied) showToast(false, R.string.url_is_copied)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, ex, "clipboard access failed.") showToast(ex, "clipboard access failed.")
} }
} }
@ -862,7 +861,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent) startActivity(intent)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this@ActMediaViewer, ex, "can't open app.") showToast(ex, "can't open app.")
} }
} }
} }
@ -873,7 +872,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), PERMISSION_REQUEST_CODE this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), PERMISSION_REQUEST_CODE
) )
} else { } else {
showToast(this, true, R.string.missing_permission_to_access_media) showToast(true, R.string.missing_permission_to_access_media)
} }
} }
@ -892,7 +891,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
++ i ++ i
} }
if(bNotGranted) { if(bNotGranted) {
showToast(this, true, R.string.missing_permission_to_access_media) showToast(true, R.string.missing_permission_to_access_media)
} else { } else {
download(media_list[idx]) download(media_list[idx])
} }

View File

@ -19,6 +19,7 @@ import com.woxthebox.draglistview.swipe.ListSwipeItem
class ActMutedApp : AppCompatActivity() { class ActMutedApp : AppCompatActivity() {
companion object { companion object {
private val log = LogCategory("ActMutedApp") private val log = LogCategory("ActMutedApp")
} }
@ -168,9 +169,8 @@ class ActMutedApp : AppCompatActivity() {
dragView.findViewById<TextView>(R.id.tvName).text = dragView.findViewById<TextView>(R.id.tvName).text =
clickedView.findViewById<TextView>(R.id.tvName).text clickedView.findViewById<TextView>(R.id.tvName).text
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor( dragView.findViewById<View>(R.id.item_layout)
getAttributeColor(this@ActMutedApp, R.attr.list_item_bg_pressed_dragged) .setBackgroundColor(getAttributeColor(R.attr.list_item_bg_pressed_dragged))
)
} }
} }

View File

@ -19,6 +19,7 @@ import java.util.*
class ActMutedPseudoAccount : AppCompatActivity() { class ActMutedPseudoAccount : AppCompatActivity() {
companion object { companion object {
private val log = LogCategory("ActMutedPseudoAccount") private val log = LogCategory("ActMutedPseudoAccount")
} }
@ -167,9 +168,8 @@ class ActMutedPseudoAccount : AppCompatActivity() {
dragView.findViewById<TextView>(R.id.tvName).text = dragView.findViewById<TextView>(R.id.tvName).text =
clickedView.findViewById<TextView>(R.id.tvName).text clickedView.findViewById<TextView>(R.id.tvName).text
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor( dragView.findViewById<View>(R.id.item_layout)
getAttributeColor(this@ActMutedPseudoAccount, R.attr.list_item_bg_pressed_dragged) .setBackgroundColor(getAttributeColor(R.attr.list_item_bg_pressed_dragged))
)
} }
} }

View File

@ -168,9 +168,8 @@ class ActMutedWord : AppCompatActivity() {
dragView.findViewById<TextView>(R.id.tvName).text = dragView.findViewById<TextView>(R.id.tvName).text =
clickedView.findViewById<TextView>(R.id.tvName).text clickedView.findViewById<TextView>(R.id.tvName).text
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor( dragView.findViewById<View>(R.id.item_layout)
getAttributeColor(this@ActMutedWord, R.attr.list_item_bg_pressed_dragged) .setBackgroundColor(getAttributeColor(R.attr.list_item_bg_pressed_dragged))
)
} }
} }

View File

@ -155,7 +155,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
tvAcct.text = acctPretty tvAcct.text = acctPretty
val ac = AcctColor.load(acctAscii,acctPretty) val ac = AcctColor.load(acctAscii, acctPretty)
color_bg = ac.color_bg color_bg = ac.color_bg
color_fg = ac.color_fg color_fg = ac.color_fg
etNickname.setText(ac.nickname) etNickname.setText(ac.nickname)
@ -180,7 +180,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
private fun show() { private fun show() {
val s = etNickname.text.toString().trim { it <= ' ' } val s = etNickname.text.toString().trim { it <= ' ' }
tvPreview.text = s.notEmpty() ?: acctPretty tvPreview.text = s.notEmpty() ?: acctPretty
tvPreview.textColor = color_fg.notZero() ?: getAttributeColor(this, R.attr.colorTimeSmall) tvPreview.textColor = color_fg.notZero() ?: getAttributeColor(R.attr.colorTimeSmall)
tvPreview.backgroundColor = color_bg tvPreview.backgroundColor = color_bg
} }

View File

@ -493,7 +493,7 @@ class ActPost : AsyncActivity(),
private var mushroom_end : Int = 0 private var mushroom_end : Int = 0
private val link_click_listener : (View, MyClickableSpan) -> Unit = { _, span -> private val link_click_listener : (View, MyClickableSpan) -> Unit = { _, span ->
App1.openBrowser(this@ActPost, span.linkInfo.url) openBrowser(span.linkInfo.url)
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -557,7 +557,7 @@ class ActPost : AsyncActivity(),
if(uri != null) { if(uri != null) {
addAttachment(uri) addAttachment(uri)
} else { } else {
showToast(this@ActPost, false, "missing image uri") showToast(false, "missing image uri")
} }
} }
@ -612,7 +612,7 @@ class ActPost : AsyncActivity(),
} }
if(account_list.isEmpty()) { if(account_list.isEmpty()) {
showToast(this, true, R.string.please_add_account) showToast(true, R.string.please_add_account)
finish() finish()
return return
} }
@ -1413,7 +1413,6 @@ class ActPost : AsyncActivity(),
tvCharCount.text = remain.toString() tvCharCount.text = remain.toString()
tvCharCount.setTextColor( tvCharCount.setTextColor(
getAttributeColor( getAttributeColor(
this,
if(remain < 0) if(remain < 0)
R.attr.colorRegexFilterError R.attr.colorRegexFilterError
else else
@ -1495,7 +1494,7 @@ class ActPost : AsyncActivity(),
if(a == null) { if(a == null) {
btnAccount.text = getString(R.string.not_selected) btnAccount.text = getString(R.string.not_selected)
btnAccount.setTextColor(getAttributeColor(this, android.R.attr.textColorPrimary)) btnAccount.setTextColor(getAttributeColor(android.R.attr.textColorPrimary))
btnAccount.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp) btnAccount.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
} else { } else {
@ -1515,7 +1514,7 @@ class ActPost : AsyncActivity(),
} }
btnAccount.textColor = ac.color_fg.notZero() btnAccount.textColor = ac.color_fg.notZero()
?: getAttributeColor(this, android.R.attr.textColorPrimary) ?: getAttributeColor(android.R.attr.textColorPrimary)
} }
updateTextCount() updateTextCount()
updateFeaturedTags() updateFeaturedTags()
@ -1525,19 +1524,19 @@ class ActPost : AsyncActivity(),
if(scheduledStatus != null) { if(scheduledStatus != null) {
// 予約投稿の再編集ではアカウントを切り替えられない // 予約投稿の再編集ではアカウントを切り替えられない
showToast(this, false, R.string.cant_change_account_when_editing_scheduled_status) showToast(false, R.string.cant_change_account_when_editing_scheduled_status)
return return
} }
if(attachment_list.isNotEmpty()) { if(attachment_list.isNotEmpty()) {
// 添付ファイルがあったら確認の上添付ファイルを捨てないと切り替えられない // 添付ファイルがあったら確認の上添付ファイルを捨てないと切り替えられない
showToast(this, false, R.string.cant_change_account_when_attachment_specified) showToast(false, R.string.cant_change_account_when_attachment_specified)
return return
} }
if(redraft_status_id != null) { if(redraft_status_id != null) {
// 添付ファイルがあったら確認の上添付ファイルを捨てないと切り替えられない // 添付ファイルがあったら確認の上添付ファイルを捨てないと切り替えられない
showToast(this, false, R.string.cant_change_account_when_redraft) showToast(false, R.string.cant_change_account_when_redraft)
return return
} }
@ -1598,7 +1597,7 @@ class ActPost : AsyncActivity(),
selectAccount(a) selectAccount(a)
try { try {
if(TootVisibility.isVisibilitySpoilRequired(this.visibility, a.visibility)) { if(TootVisibility.isVisibilitySpoilRequired(this.visibility, a.visibility)) {
showToast(this@ActPost, true, R.string.spoil_visibility_for_account) showToast(true, R.string.spoil_visibility_for_account)
this.visibility = a.visibility this.visibility = a.visibility
} }
@ -1644,7 +1643,6 @@ class ActPost : AsyncActivity(),
setAccountWithVisibilityConversion(access_info) setAccountWithVisibilityConversion(access_info)
} else { } else {
showToast( showToast(
this@ActPost,
true, true,
getString(R.string.in_reply_to_id_conversion_failed) + "\n" + result.error getString(R.string.in_reply_to_id_conversion_failed) + "\n" + result.error
) )
@ -1701,7 +1699,7 @@ class ActPost : AsyncActivity(),
val pa = try { val pa = try {
attachment_list[idx] attachment_list[idx]
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, false, ex.withCaption("can't get attachment item[$idx].")) showToast(false, ex.withCaption("can't get attachment item[$idx]."))
return return
} }
@ -1771,7 +1769,7 @@ class ActPost : AsyncActivity(),
if(new_attachment != null) { if(new_attachment != null) {
pa.attachment = attachment pa.attachment = attachment
} else { } else {
showToast(this@ActPost, true, result.error) showToast(true, result.error)
} }
} }
}) })
@ -1798,7 +1796,7 @@ class ActPost : AsyncActivity(),
startActivityForResult(intent, REQUEST_CODE_CUSTOM_THUMBNAIL) startActivityForResult(intent, REQUEST_CODE_CUSTOM_THUMBNAIL)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "ACTION_GET_CONTENT failed.") showToast(ex, "ACTION_GET_CONTENT failed.")
} }
} }
@ -1809,19 +1807,19 @@ class ActPost : AsyncActivity(),
val account = this@ActPost.account val account = this@ActPost.account
if(account == null) { if(account == null) {
showToast(this, false, R.string.account_select_please) showToast(false, R.string.account_select_please)
return return
} }
val mime_type = getMimeType(src.uri, src.mimeType) val mime_type = getMimeType(src.uri, src.mimeType)
if(mime_type?.isEmpty() != false) { if(mime_type?.isEmpty() != false) {
showToast(this, false, R.string.mime_type_missing) showToast(false, R.string.mime_type_missing)
return return
} }
val pa = lastPostAttachment val pa = lastPostAttachment
if(pa == null || ! attachment_list.contains(pa)) { if(pa == null || ! attachment_list.contains(pa)) {
showToast(this, true, "lost attachment information") showToast(true, "lost attachment information")
return return
} }
@ -1922,7 +1920,7 @@ class ActPost : AsyncActivity(),
override fun handleResult(result : TootApiResult?) { override fun handleResult(result : TootApiResult?) {
showMediaAttachment() showMediaAttachment()
result?.error?.let { showToast(this@ActPost, true, it) } result?.error?.let { showToast(true, it) }
} }
}) })
} }
@ -1946,7 +1944,7 @@ class ActPost : AsyncActivity(),
private fun editAttachmentDescription(pa : PostAttachment) { private fun editAttachmentDescription(pa : PostAttachment) {
val a = pa.attachment val a = pa.attachment
if(a == null) { if(a == null) {
showToast(this, true, R.string.attachment_description_cant_edit_while_uploading) showToast(true, R.string.attachment_description_cant_edit_while_uploading)
return return
} }
@ -1960,7 +1958,7 @@ class ActPost : AsyncActivity(),
} }
override fun onEmptyError() { override fun onEmptyError() {
showToast(this@ActPost, true, R.string.description_empty) showToast(true, R.string.description_empty)
} }
}) })
} }
@ -1998,7 +1996,7 @@ class ActPost : AsyncActivity(),
dialog.dismissSafe() dialog.dismissSafe()
} else { } else {
showToast(this@ActPost, true, result.error) showToast(true, result.error)
} }
} }
}) })
@ -2007,12 +2005,12 @@ class ActPost : AsyncActivity(),
private fun openAttachment() { private fun openAttachment() {
if(attachment_list.size >= 4) { if(attachment_list.size >= 4) {
showToast(this, false, R.string.attachment_too_many) showToast(false, R.string.attachment_too_many)
return return
} }
if(account == null) { if(account == null) {
showToast(this, false, R.string.account_select_please) showToast(false, R.string.account_select_please)
return return
} }
@ -2068,7 +2066,7 @@ class ActPost : AsyncActivity(),
startActivityForResult(intent, REQUEST_CODE_ATTACHMENT_OLD) startActivityForResult(intent, REQUEST_CODE_ATTACHMENT_OLD)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "ACTION_GET_CONTENT failed.") showToast(ex, "ACTION_GET_CONTENT failed.")
} }
} }
@ -2109,7 +2107,7 @@ class ActPost : AsyncActivity(),
try { try {
val cache_dir = externalCacheDir val cache_dir = externalCacheDir
if(cache_dir == null) { if(cache_dir == null) {
showToast(this, false, "getExternalCacheDir returns null.") showToast(false, "getExternalCacheDir returns null.")
break break
} }
@ -2145,7 +2143,7 @@ class ActPost : AsyncActivity(),
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "Resizing image failed.") showToast(ex, "Resizing image failed.")
} }
break break
@ -2219,35 +2217,35 @@ class ActPost : AsyncActivity(),
) { ) {
if(attachment_list.size >= 4) { if(attachment_list.size >= 4) {
showToast(this, false, R.string.attachment_too_many) showToast(false, R.string.attachment_too_many)
return return
} }
val account = this@ActPost.account val account = this@ActPost.account
if(account == null) { if(account == null) {
showToast(this, false, R.string.account_select_please) showToast(false, R.string.account_select_please)
return return
} }
val mime_type = getMimeType(uri, mimeTypeArg) val mime_type = getMimeType(uri, mimeTypeArg)
if(mime_type?.isEmpty() != false) { if(mime_type?.isEmpty() != false) {
showToast(this, false, R.string.mime_type_missing) showToast(false, R.string.mime_type_missing)
return return
} }
val instance = TootInstance.getCached(account.apiHost.ascii) val instance = TootInstance.getCached(account.apiHost.ascii)
if(instance?.instanceType == TootInstance.InstanceType.Pixelfed) { if(instance?.instanceType == TootInstance.InstanceType.Pixelfed) {
if(in_reply_to_id != null) { if(in_reply_to_id != null) {
showToast(this, true, R.string.pixelfed_does_not_allow_reply_with_media) showToast(true, R.string.pixelfed_does_not_allow_reply_with_media)
return return
} }
if(! acceptable_mime_types_pixelfed.contains(mime_type)) { if(! acceptable_mime_types_pixelfed.contains(mime_type)) {
showToast(this, true, R.string.mime_type_not_acceptable, mime_type) showToast(true, R.string.mime_type_not_acceptable, mime_type)
return return
} }
} else { } else {
if(! acceptable_mime_types.contains(mime_type)) { if(! acceptable_mime_types.contains(mime_type)) {
showToast(this, true, R.string.mime_type_not_acceptable, mime_type) showToast(true, R.string.mime_type_not_acceptable, mime_type)
return return
} }
} }
@ -2261,7 +2259,7 @@ class ActPost : AsyncActivity(),
// アップロード開始トースト(連発しない) // アップロード開始トースト(連発しない)
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
if(now - lastAttachmentAdd >= 5000L) { if(now - lastAttachmentAdd >= 5000L) {
showToast(this, false, R.string.attachment_uploading) showToast(false, R.string.attachment_uploading)
} }
lastAttachmentAdd = now lastAttachmentAdd = now
@ -2547,7 +2545,6 @@ class ActPost : AsyncActivity(),
pa.status = PostAttachment.STATUS_UPLOAD_FAILED pa.status = PostAttachment.STATUS_UPLOAD_FAILED
if(result != null) { if(result != null) {
showToast( showToast(
this@ActPost,
true, true,
"${result.error} ${result.response?.request?.method} ${result.response?.request?.url}" "${result.error} ${result.response?.request?.method} ${result.response?.request?.url}"
) )
@ -2581,7 +2578,7 @@ class ActPost : AsyncActivity(),
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
if(now - lastAttachmentComplete >= 5000L) { if(now - lastAttachmentComplete >= 5000L) {
showToast(this@ActPost, false, R.string.attachment_uploaded) showToast(false, R.string.attachment_uploaded)
} }
lastAttachmentComplete = now lastAttachmentComplete = now
@ -2626,7 +2623,7 @@ class ActPost : AsyncActivity(),
startActivityForResult(intent, REQUEST_CODE_CAMERA) startActivityForResult(intent, REQUEST_CODE_CAMERA)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "opening camera app failed.") showToast(ex, "opening camera app failed.")
} }
} }
@ -2636,7 +2633,7 @@ class ActPost : AsyncActivity(),
startActivityForResult(Intent(action), requestCode) startActivityForResult(Intent(action), requestCode)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, errorCaption) showToast(ex, errorCaption)
} }
} }
@ -2648,7 +2645,7 @@ class ActPost : AsyncActivity(),
PERMISSION_REQUEST_CODE PERMISSION_REQUEST_CODE
) )
} else { } else {
showToast(this, true, R.string.missing_permission_to_access_media) showToast(true, R.string.missing_permission_to_access_media)
} }
} }
@ -2667,7 +2664,7 @@ class ActPost : AsyncActivity(),
++ i ++ i
} }
if(bNotGranted) { if(bNotGranted) {
showToast(this, true, R.string.missing_permission_to_access_media) showToast(true, R.string.missing_permission_to_access_media)
} else { } else {
openAttachment() openAttachment()
} }
@ -2763,7 +2760,7 @@ class ActPost : AsyncActivity(),
// アップロード中は投稿できない // アップロード中は投稿できない
for(pa in attachment_list) { for(pa in attachment_list) {
if(pa.status == PostAttachment.STATUS_UPLOADING) { if(pa.status == PostAttachment.STATUS_UPLOADING) {
showToast(this, false, R.string.media_attachment_still_uploading) showToast(false, R.string.media_attachment_still_uploading)
return return
} }
} }
@ -2850,7 +2847,7 @@ class ActPost : AsyncActivity(),
} }
override fun onScheduledPostComplete(target_account : SavedAccount) { override fun onScheduledPostComplete(target_account : SavedAccount) {
showToast(this@ActPost, false, getString(R.string.scheduled_status_sent)) showToast(false, getString(R.string.scheduled_status_sent))
val data = Intent() val data = Intent()
data.putExtra(EXTRA_POSTED_ACCT, target_account.acct.ascii) data.putExtra(EXTRA_POSTED_ACCT, target_account.acct.ascii)
setResult(RESULT_OK, data) setResult(RESULT_OK, data)

View File

@ -161,7 +161,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "send failed.") showToast(ex, "send failed.")
} }
} }
@ -169,7 +169,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
private fun search() { private fun search() {
val sv = selection val sv = selection
if(sv.isEmpty()) { if(sv.isEmpty()) {
showToast(this, false, "please select search keyword") showToast(false, "please select search keyword")
return return
} }
try { try {
@ -180,7 +180,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
} }
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "search failed.") showToast(ex, "search failed.")
} }
} }
@ -188,7 +188,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
private fun searchToot(@Suppress("SameParameterValue") resultCode : Int) { private fun searchToot(@Suppress("SameParameterValue") resultCode : Int) {
val sv = selection val sv = selection
if(sv.isEmpty()) { if(sv.isEmpty()) {
showToast(this, false, "please select search keyword") showToast(false, "please select search keyword")
return return
} }
try { try {
@ -206,10 +206,10 @@ class ActText : AppCompatActivity(), View.OnClickListener {
try { try {
MutedWord.save(selection) MutedWord.save(selection)
App1.getAppState(this).onMuteUpdated() App1.getAppState(this).onMuteUpdated()
showToast(this, false, R.string.word_was_muted) showToast(false, R.string.word_was_muted)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(this, ex, "muteWord failed.") showToast(ex, "muteWord failed.")
} }
} }

View File

@ -3,27 +3,14 @@ package jp.juggler.subwaytooter
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.Application import android.app.Application
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.content.res.ColorStateList
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper import android.database.sqlite.SQLiteOpenHelper
import android.graphics.Color
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.util.Log import android.util.Log
import android.view.View
import android.view.WindowInsetsController
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
import androidx.browser.customtabs.CustomTabsIntent
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.GlideBuilder import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.Registry import com.bumptech.glide.Registry
@ -32,13 +19,10 @@ import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
import com.bumptech.glide.load.engine.executor.GlideExecutor import com.bumptech.glide.load.engine.executor.GlideExecutor
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import jp.juggler.subwaytooter.api.TootApiClient import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.entity.TootAttachment
import jp.juggler.subwaytooter.dialog.DlgAppPicker
import jp.juggler.subwaytooter.table.* import jp.juggler.subwaytooter.table.*
import jp.juggler.subwaytooter.util.CustomEmojiCache import jp.juggler.subwaytooter.util.CustomEmojiCache
import jp.juggler.subwaytooter.util.CustomEmojiLister import jp.juggler.subwaytooter.util.CustomEmojiLister
import jp.juggler.subwaytooter.util.ProgressResponseBody import jp.juggler.subwaytooter.util.ProgressResponseBody
import jp.juggler.subwaytooter.util.cn
import jp.juggler.util.* import jp.juggler.util.*
import okhttp3.* import okhttp3.*
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
@ -51,7 +35,6 @@ import java.security.Security
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.max import kotlin.math.max
import kotlin.math.pow
class App1 : Application() { class App1 : Application() {
@ -315,7 +298,7 @@ class App1 : Application() {
initializeFont() initializeFont()
pref = Pref.pref(app_context) pref = app_context.pref()
run { run {
@ -518,7 +501,7 @@ class App1 : Application() {
} }
fun setActivityTheme( fun setActivityTheme(
activity : Activity, activity : AppCompatActivity,
noActionBar : Boolean = false, noActionBar : Boolean = false,
forceDark : Boolean = false forceDark : Boolean = false
) { ) {
@ -534,7 +517,7 @@ class App1 : Application() {
} }
) )
setStatusBarColor(activity, forceDark = forceDark) activity.setStatusBarColor(forceDark = forceDark)
} }
internal val CACHE_CONTROL = CacheControl.Builder() internal val CACHE_CONTROL = CacheControl.Builder()
@ -610,147 +593,6 @@ class App1 : Application() {
} }
// returns true if activity is opened.
// returns false if fallback required
private fun startActivityExcludeMyApp(
activity : AppCompatActivity,
intent : Intent,
startAnimationBundle : Bundle? = null
) : Boolean {
try {
val pm = activity.packageManager !!
val myName = activity.packageName
val filter : (ResolveInfo) -> Boolean = {
it.activityInfo.packageName != myName &&
it.activityInfo.exported &&
- 1 == it.activityInfo.packageName.indexOf("com.huawei.android.internal")
}
// resolveActivity がこのアプリ以外のActivityを返すなら、それがベストなんだろう
// ただしAndroid M以降はMATCH_DEFAULT_ONLYだと「常時」が設定されてないとnullを返す
val ri = pm.resolveActivity(
intent,
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PackageManager.MATCH_ALL
} else {
PackageManager.MATCH_DEFAULT_ONLY
}
)?.takeIf(filter)
if(ri != null) {
intent.setClassName(ri.activityInfo.packageName, ri.activityInfo.name)
activity.startActivity(intent, startAnimationBundle)
return true
}
return DlgAppPicker(
activity,
intent,
autoSelect = true,
filter = filter
) {
try {
intent.component = it.cn()
activity.startActivity(intent, startAnimationBundle)
} catch(ex : Throwable) {
log.trace(ex)
showToast(activity, ex, "can't open. ${intent.data}")
}
}.show()
} catch(ex : Throwable) {
log.trace(ex)
showToast(activity, ex, "can't open. ${intent.data}")
return true // fallback not required in this case
}
}
fun openBrowser(activity : AppCompatActivity, uri : Uri?) {
if(uri != null) {
val rv = startActivityExcludeMyApp(activity, Intent(Intent.ACTION_VIEW, uri))
if(! rv) showToast(activity, true, "there is no app that can open $uri")
}
}
fun openBrowser(activity : AppCompatActivity, url : String?) =
openBrowser(activity, url.mayUri())
// ubway Tooterの「アプリ設定/挙動/リンクを開く際にCustom Tabsを使わない」をONにして
// 投稿のコンテキストメニューの「トゥートへのアクション/Webページを開く」「ユーザへのアクション/Webページを開く」を使うと
// 投げたインテントをST自身が受け取って「次のアカウントから開く」ダイアログが出て
// 「Webページを開く」をまた押すと無限ループしてダイアログの影が徐々に濃くなりそのうち壊れる
// これを避けるには、投稿やトゥートを開く際に bpDontUseCustomTabs がオンならST以外のアプリを列挙したアプリ選択ダイアログを出すしかない
fun openCustomTabOrBrowser(activity : AppCompatActivity, url : String) {
if(! Pref.bpDontUseCustomTabs(pref)) {
openCustomTab(activity, url)
} else {
openBrowser(activity, url)
}
}
// Chrome Custom Tab を開く
fun openCustomTab(activity : AppCompatActivity, url : String) {
if(Pref.bpDontUseCustomTabs(pref)) {
openCustomTabOrBrowser(activity, url)
return
}
try {
if(url.startsWith("http") && Pref.bpPriorChrome(pref)) {
try {
// 初回はChrome指定で試す
val customTabsIntent = CustomTabsIntent.Builder()
.setToolbarColor(getAttributeColor(activity, R.attr.colorPrimary))
.setShowTitle(true)
.build()
val rv = startActivityExcludeMyApp(
activity,
customTabsIntent.intent.also {
it.component = ComponentName(
"com.android.chrome",
"com.google.android.apps.chrome.Main"
)
it.data = url.toUri()
},
customTabsIntent.startAnimationBundle
)
if(rv) return
} catch(ex2 : Throwable) {
log.e(ex2, "openChromeTab: missing chrome. retry to other application.")
}
}
// Chromeがないようなのでcomponent指定なしでリトライ
val customTabsIntent = CustomTabsIntent.Builder()
.setToolbarColor(getAttributeColor(activity, R.attr.colorPrimary))
.setShowTitle(true)
.build()
val rv = startActivityExcludeMyApp(
activity,
customTabsIntent.intent.also {
it.data = url.toUri()
},
customTabsIntent.startAnimationBundle
)
if(! rv) {
showToast(activity, true, "the browser app is not installed.")
}
} catch(ex : Throwable) {
log.trace(ex)
val scheme = url.mayUri()?.scheme ?: url
showToast(activity, true, "can't open browser app for %s", scheme)
}
}
fun openCustomTab(activity : AppCompatActivity, ta : TootAttachment) {
val url = ta.getLargeUrl(pref) ?: return
openCustomTab(activity, url)
}
// https://developer.android.com/preview/features/gesturalnav?hl=ja // https://developer.android.com/preview/features/gesturalnav?hl=ja
fun initEdgeToEdge(@Suppress("UNUSED_PARAMETER") activity : Activity) { fun initEdgeToEdge(@Suppress("UNUSED_PARAMETER") activity : Activity) {
// if(Build.VERSION.SDK_INT >= 29){ // if(Build.VERSION.SDK_INT >= 29){

View File

@ -10,6 +10,7 @@ import android.widget.TextView
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import jp.juggler.subwaytooter.util.CustomShareTarget import jp.juggler.subwaytooter.util.CustomShareTarget
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.* import jp.juggler.util.*
import org.jetbrains.anko.backgroundDrawable import org.jetbrains.anko.backgroundDrawable
@ -537,7 +538,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
val intent = intentOpenDocument("*/*") val intent = intentOpenDocument("*/*")
startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT) startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, ex, "could not open picker for font") showToast(ex, "could not open picker for font")
} }
} }
onClickReset = { onClickReset = {
@ -559,7 +560,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
val intent = intentOpenDocument("*/*") val intent = intentOpenDocument("*/*")
startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT_BOLD) startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT_BOLD)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this, ex, "could not open picker for font") showToast(ex, "could not open picker for font")
} }
} }
onClickReset = { onClickReset = {
@ -701,10 +702,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
sw(Pref.bpInstanceTicker, R.string.show_instance_ticker) { sw(Pref.bpInstanceTicker, R.string.show_instance_ticker) {
desc = R.string.instance_ticker_copyright desc = R.string.instance_ticker_copyright
descClick = { descClick = {
App1.openBrowser( openBrowser("https://github.com/MiyonMiyon/InstanceTicker_List")
this,
"https://github.com/MiyonMiyon/InstanceTicker_List"
)
} }
} }
@ -769,12 +767,12 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
colorAlpha(Pref.ipEventBgColorQuote, R.string.quote_renote) colorAlpha(Pref.ipEventBgColorQuote, R.string.quote_renote)
colorAlpha(Pref.ipEventBgColorVote, R.string.vote_polls) colorAlpha(Pref.ipEventBgColorVote, R.string.vote_polls)
colorAlpha(Pref.ipEventBgColorStatus, R.string.status) colorAlpha(Pref.ipEventBgColorStatus, R.string.status)
colorAlpha( colorAlpha(
Pref.ipConversationMainTootBgColor, Pref.ipConversationMainTootBgColor,
R.string.conversation_main_toot_background_color R.string.conversation_main_toot_background_color
) )
colorAlpha(Pref.ipEventBgColorGap, R.string.gap) colorAlpha(Pref.ipEventBgColorGap, R.string.gap)
} }
@ -800,12 +798,12 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
val header_bg = when { val header_bg = when {
color_column_header_bg != 0 -> color_column_header_bg color_column_header_bg != 0 -> color_column_header_bg
else -> getAttributeColor(activity, R.attr.color_column_header) else -> activity.getAttributeColor(R.attr.color_column_header)
} }
val header_fg = when { val header_fg = when {
color_column_header_fg != 0 -> color_column_header_fg color_column_header_fg != 0 -> color_column_header_fg
else -> getAttributeColor(activity, R.attr.colorColumnHeaderName) else -> activity.getAttributeColor(R.attr.colorColumnHeaderName)
} }
llColumnHeader.background = getAdaptiveRippleDrawable(header_bg, header_fg) llColumnHeader.background = getAdaptiveRippleDrawable(header_bg, header_fg)
@ -836,12 +834,12 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
tvSampleAcct.setTextColor( tvSampleAcct.setTextColor(
color_column_acct.notZero() color_column_acct.notZero()
?: getAttributeColor(activity, R.attr.colorTimeSmall) ?: activity.getAttributeColor(R.attr.colorTimeSmall)
) )
tvSampleContent.setTextColor( tvSampleContent.setTextColor(
color_column_text.notZero() color_column_text.notZero()
?: getAttributeColor(activity, R.attr.colorContentText) ?: activity.getAttributeColor(R.attr.colorContentText)
) )
} }
@ -876,7 +874,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
val footer_tab_indicator_color = Pref.ipFooterTabIndicatorColor(pref) val footer_tab_indicator_color = Pref.ipFooterTabIndicatorColor(pref)
val colorColumnStripBackground = footer_tab_bg_color.notZero() val colorColumnStripBackground = footer_tab_bg_color.notZero()
?: getAttributeColor(activity, R.attr.colorColumnStripBackground) ?: activity.getAttributeColor(R.attr.colorColumnStripBackground)
llFooterBG.setBackgroundColor(colorColumnStripBackground) llFooterBG.setBackgroundColor(colorColumnStripBackground)
@ -884,7 +882,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
?: colorColumnStripBackground ?: colorColumnStripBackground
val colorButtonFg = footer_button_fg_color.notZero() val colorButtonFg = footer_button_fg_color.notZero()
?: getAttributeColor(activity, R.attr.colorRippleEffect) ?: activity.getAttributeColor(R.attr.colorRippleEffect)
ivFooterMenu.backgroundDrawable = ivFooterMenu.backgroundDrawable =
getAdaptiveRippleDrawableRound(activity, colorButtonBg, colorButtonFg) getAdaptiveRippleDrawableRound(activity, colorButtonBg, colorButtonFg)
@ -893,7 +891,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
val csl = ColorStateList.valueOf( val csl = ColorStateList.valueOf(
footer_button_fg_color.notZero() footer_button_fg_color.notZero()
?: getAttributeColor(activity, R.attr.colorVectorDrawable) ?: activity.getAttributeColor(R.attr.colorVectorDrawable)
) )
ivFooterToot.imageTintList = csl ivFooterToot.imageTintList = csl
ivFooterMenu.imageTintList = csl ivFooterMenu.imageTintList = csl
@ -905,7 +903,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
vIndicator.setBackgroundColor( vIndicator.setBackgroundColor(
footer_tab_indicator_color.notZero() footer_tab_indicator_color.notZero()
?: getAttributeColor(activity, R.attr.colorAccent) ?: activity.getAttributeColor(R.attr.colorAccent)
) )
} }
@ -931,11 +929,11 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
} }
colorOpaque(Pref.ipStatusBarColor, R.string.status_bar_color) { colorOpaque(Pref.ipStatusBarColor, R.string.status_bar_color) {
changed = { setStatusBarColor(this) } changed = { setStatusBarColor() }
} }
colorOpaque(Pref.ipNavigationBarColor, R.string.navigation_bar_color) { colorOpaque(Pref.ipNavigationBarColor, R.string.navigation_bar_color) {
changed = { setStatusBarColor(this) } changed = { setStatusBarColor() }
} }
colorOpaque(Pref.ipSearchBgColor, R.string.search_bar_background_color) colorOpaque(Pref.ipSearchBgColor, R.string.search_bar_background_color)
@ -958,15 +956,15 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
section(R.string.developer_options) { section(R.string.developer_options) {
sw(Pref.bpCheckBetaVersion, R.string.check_beta_release) sw(Pref.bpCheckBetaVersion, R.string.check_beta_release)
action(R.string.drawable_list) { action(R.string.drawable_list) {
action = { startActivity(Intent(this, ActDrawableList::class.java)) } action = { startActivity(Intent(this, ActDrawableList::class.java)) }
} }
action(R.string.exit_reasons) { action(R.string.exit_reasons) {
action = { action = {
if(Build.VERSION.SDK_INT >= 30 ){ if(Build.VERSION.SDK_INT >= 30) {
startActivity(Intent(this, ActExitReasons::class.java)) startActivity(Intent(this, ActExitReasons::class.java))
}else{ } else {
showToast(false, "this feature requires Android 11") showToast(false, "this feature requires Android 11")
} }
} }

View File

@ -48,6 +48,7 @@ class AppState(
) { ) {
companion object { companion object {
internal val log = LogCategory("AppState") internal val log = LogCategory("AppState")
private const val FILE_COLUMN_LIST = "column_list" private const val FILE_COLUMN_LIST = "column_list"
@ -86,7 +87,7 @@ class AppState(
} }
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(context, ex, "saveColumnList failed.") context.showToast(ex, "saveColumnList failed.")
} }
} }
} }
@ -102,7 +103,7 @@ class AppState(
} catch(ignored : FileNotFoundException) { } catch(ignored : FileNotFoundException) {
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(context, ex, "loadColumnList failed.") context.showToast(ex, "loadColumnList failed.")
} }
return null return null
@ -355,11 +356,11 @@ class AppState(
if(willSpeechEnabled && tts == null && tts_status == TTS_STATUS_NONE) { if(willSpeechEnabled && tts == null && tts_status == TTS_STATUS_NONE) {
tts_status = TTS_STATUS_INITIALIZING tts_status = TTS_STATUS_INITIALIZING
showToast(context, false, R.string.text_to_speech_initializing) context.showToast(false, R.string.text_to_speech_initializing)
log.d("initializing TextToSpeech…") log.d("initializing TextToSpeech…")
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
var tmp_tts : TextToSpeech? = null var tmp_tts : TextToSpeech? = null
val tts_init_listener : TextToSpeech.OnInitListener = val tts_init_listener : TextToSpeech.OnInitListener =
@ -367,8 +368,7 @@ class AppState(
val tts = tmp_tts val tts = tmp_tts
if(tts == null || TextToSpeech.SUCCESS != status) { if(tts == null || TextToSpeech.SUCCESS != status) {
showToast( context.showToast(
context,
false, false,
R.string.text_to_speech_initialize_failed, R.string.text_to_speech_initialize_failed,
status status
@ -379,7 +379,7 @@ class AppState(
runOnMainLooper { runOnMainLooper {
if(! willSpeechEnabled) { if(! willSpeechEnabled) {
showToast(context, false, R.string.text_to_speech_shutdown) context.showToast(false, R.string.text_to_speech_shutdown)
log.d("shutdown TextToSpeech…") log.d("shutdown TextToSpeech…")
tts.shutdown() tts.shutdown()
} else { } else {
@ -450,7 +450,7 @@ class AppState(
} }
if(! willSpeechEnabled && tts != null) { if(! willSpeechEnabled && tts != null) {
showToast(context, false, R.string.text_to_speech_shutdown) context.showToast(false, R.string.text_to_speech_shutdown)
log.d("shutdown TextToSpeech…") log.d("shutdown TextToSpeech…")
tts?.shutdown() tts?.shutdown()
tts = null tts = null

View File

@ -352,22 +352,22 @@ class Column(
fun reloadDefaultColor(activity : AppCompatActivity, pref : SharedPreferences) { fun reloadDefaultColor(activity : AppCompatActivity, pref : SharedPreferences) {
defaultColorHeaderBg = Pref.ipCcdHeaderBg(pref).notZero() defaultColorHeaderBg = Pref.ipCcdHeaderBg(pref).notZero()
?: getAttributeColor(activity, R.attr.color_column_header) ?: activity.getAttributeColor(R.attr.color_column_header)
defaultColorHeaderName = Pref.ipCcdHeaderFg(pref).notZero() defaultColorHeaderName = Pref.ipCcdHeaderFg(pref).notZero()
?: getAttributeColor(activity, R.attr.colorColumnHeaderName) ?: activity.getAttributeColor(R.attr.colorColumnHeaderName)
defaultColorHeaderPageNumber = Pref.ipCcdHeaderFg(pref).notZero() defaultColorHeaderPageNumber = Pref.ipCcdHeaderFg(pref).notZero()
?: getAttributeColor(activity, R.attr.colorColumnHeaderPageNumber) ?: activity.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
defaultColorContentBg = Pref.ipCcdContentBg(pref) defaultColorContentBg = Pref.ipCcdContentBg(pref)
// may zero // may zero
defaultColorContentAcct = Pref.ipCcdContentAcct(pref).notZero() defaultColorContentAcct = Pref.ipCcdContentAcct(pref).notZero()
?: getAttributeColor(activity, R.attr.colorTimeSmall) ?: activity.getAttributeColor(R.attr.colorTimeSmall)
defaultColorContentText = Pref.ipCcdContentText(pref).notZero() defaultColorContentText = Pref.ipCcdContentText(pref).notZero()
?: getAttributeColor(activity, R.attr.colorContentText) ?: activity.getAttributeColor(R.attr.colorContentText)
} }
} }
@ -2131,14 +2131,14 @@ class Column(
if(lastTask != null) { if(lastTask != null) {
if(! bSilent) { if(! bSilent) {
showToast(context, true, R.string.column_is_busy) context.showToast(true, R.string.column_is_busy)
val holder = viewHolder val holder = viewHolder
if(holder != null) holder.refreshLayout.isRefreshing = false if(holder != null) holder.refreshLayout.isRefreshing = false
} }
return return
} else if(bBottom && ! canRefreshBottom()) { } else if(bBottom && ! canRefreshBottom()) {
if(! bSilent) { if(! bSilent) {
showToast(context, true, R.string.end_of_list) context.showToast(true, R.string.end_of_list)
val holder = viewHolder val holder = viewHolder
if(holder != null) holder.refreshLayout.isRefreshing = false if(holder != null) holder.refreshLayout.isRefreshing = false
} }
@ -2175,12 +2175,12 @@ class Column(
internal fun startGap(gap : TimelineItem?, isHead : Boolean) { internal fun startGap(gap : TimelineItem?, isHead : Boolean) {
if(gap == null) { if(gap == null) {
showToast(context, true, "gap is null") context.showToast(true, "gap is null")
return return
} }
if(lastTask != null) { if(lastTask != null) {
showToast(context, true, R.string.column_is_busy) context.showToast(true, R.string.column_is_busy)
return return
} }

View File

@ -415,7 +415,7 @@ class ColumnTask_Gap(
} }
if(max_id == null) { if(max_id == null) {
showToast(context, false, "gap-getConversationSummaryList: missing max_id") context.showToast(false, "$logCaption: missing max_id")
log.d("$logCaption: missing max_id") log.d("$logCaption: missing max_id")
break break
} }
@ -563,7 +563,7 @@ class ColumnTask_Gap(
defaultAccountListParser defaultAccountListParser
) : TootApiResult? { ) : TootApiResult? {
if( column.pagingType != ColumnPagingType.Default ) { if(column.pagingType != ColumnPagingType.Default) {
return TootApiResult("can't support gap") return TootApiResult("can't support gap")
} }

View File

@ -59,6 +59,7 @@ class ColumnViewHolder(
CompoundButton.OnCheckedChangeListener, View.OnLongClickListener { CompoundButton.OnCheckedChangeListener, View.OnLongClickListener {
companion object { companion object {
private val log = LogCategory("ColumnViewHolder") private val log = LogCategory("ColumnViewHolder")
val fieldRecycler : Field by lazy { val fieldRecycler : Field by lazy {
@ -540,8 +541,8 @@ class ColumnViewHolder(
// } // }
log.d( log.d(
"restoreScrollPosition [$page_idx] %s , column has no saved scroll position." "restoreScrollPosition [$page_idx] %s , column has no saved scroll position.",
, column.getColumnName(true) column.getColumnName(true)
) )
return return
} }
@ -550,18 +551,18 @@ class ColumnViewHolder(
if(listView.visibility != View.VISIBLE) { if(listView.visibility != View.VISIBLE) {
log.d( log.d(
"restoreScrollPosition [$page_idx] %s , listView is not visible. saved position %s,%s is dropped." "restoreScrollPosition [$page_idx] %s , listView is not visible. saved position %s,%s is dropped.",
, column.getColumnName(true) column.getColumnName(true),
, sp.adapterIndex sp.adapterIndex,
, sp.offset sp.offset
) )
} else { } else {
log.d( log.d(
"restoreScrollPosition [%d] %s , listView is visible. resume %s,%s" "restoreScrollPosition [%d] %s , listView is visible. resume %s,%s",
, page_idx page_idx,
, column.getColumnName(true) column.getColumnName(true),
, sp.adapterIndex sp.adapterIndex,
, sp.offset sp.offset
) )
sp.restore(this@ColumnViewHolder) sp.restore(this@ColumnViewHolder)
} }
@ -717,21 +718,21 @@ class ColumnViewHolder(
fun dip(dp : Int) : Int = (activity.density * dp + 0.5f).toInt() fun dip(dp : Int) : Int = (activity.density * dp + 0.5f).toInt()
val context = activity val context = activity
val announcementsBgColor = Pref.ipAnnouncementsBgColor(activity.pref).notZero() val announcementsBgColor = Pref.ipAnnouncementsBgColor(App1.pref).notZero()
?: getAttributeColor(context, R.attr.colorSearchFormBackground) ?: context.getAttributeColor(R.attr.colorSearchFormBackground)
btnAnnouncementsCutout.apply { btnAnnouncementsCutout.apply {
color = announcementsBgColor color = announcementsBgColor
} }
llAnnouncementsBox.apply { llAnnouncementsBox.apply {
background = createRoundDrawable( dip(6).toFloat(), announcementsBgColor ) background = createRoundDrawable(dip(6).toFloat(), announcementsBgColor)
val pad_tb = dip(2) val pad_tb = dip(2)
setPadding(0, pad_tb, 0, pad_tb) setPadding(0, pad_tb, 0, pad_tb)
} }
val searchBgColor = Pref.ipSearchBgColor(activity.pref).notZero() val searchBgColor = Pref.ipSearchBgColor(App1.pref).notZero()
?: getAttributeColor(context, R.attr.colorSearchFormBackground) ?: context.getAttributeColor(R.attr.colorSearchFormBackground)
llSearch.apply { llSearch.apply {
backgroundColor = searchBgColor backgroundColor = searchBgColor
@ -740,7 +741,7 @@ class ColumnViewHolder(
topPadding = dip(3) topPadding = dip(3)
bottomPadding = dip(3) bottomPadding = dip(3)
} }
llListList.apply { llListList.apply {
backgroundColor = searchBgColor backgroundColor = searchBgColor
startPadding = dip(12) startPadding = dip(12)
@ -1145,7 +1146,7 @@ class ColumnViewHolder(
btnListAdd -> { btnListAdd -> {
val tv = etListName.text.toString().trim { it <= ' ' } val tv = etListName.text.toString().trim { it <= ' ' }
if(tv.isEmpty()) { if(tv.isEmpty()) {
showToast(activity, true, R.string.list_name_empty) activity.showToast(true, R.string.list_name_empty)
return return
} }
Action_List.create(activity, column.access_info, tv, null) Action_List.create(activity, column.access_info, tv, null)
@ -1161,7 +1162,7 @@ class ColumnViewHolder(
btnQuickFilterFavourite -> clickQuickFilter(Column.QUICK_FILTER_FAVOURITE) btnQuickFilterFavourite -> clickQuickFilter(Column.QUICK_FILTER_FAVOURITE)
btnQuickFilterBoost -> clickQuickFilter(Column.QUICK_FILTER_BOOST) btnQuickFilterBoost -> clickQuickFilter(Column.QUICK_FILTER_BOOST)
btnQuickFilterFollow -> clickQuickFilter(Column.QUICK_FILTER_FOLLOW) btnQuickFilterFollow -> clickQuickFilter(Column.QUICK_FILTER_FOLLOW)
btnQuickFilterPost-> clickQuickFilter(Column.QUICK_FILTER_POST) btnQuickFilterPost -> clickQuickFilter(Column.QUICK_FILTER_POST)
btnQuickFilterReaction -> clickQuickFilter(Column.QUICK_FILTER_REACTION) btnQuickFilterReaction -> clickQuickFilter(Column.QUICK_FILTER_REACTION)
btnQuickFilterVote -> clickQuickFilter(Column.QUICK_FILTER_VOTE) btnQuickFilterVote -> clickQuickFilter(Column.QUICK_FILTER_VOTE)
@ -1232,7 +1233,7 @@ class ColumnViewHolder(
tvColumnContext.text = ac.nickname tvColumnContext.text = ac.nickname
tvColumnContext.setTextColor( tvColumnContext.setTextColor(
ac.color_fg.notZero() ac.color_fg.notZero()
?: getAttributeColor(activity, R.attr.colorTimeSmall) ?: activity.getAttributeColor(R.attr.colorTimeSmall)
) )
tvColumnContext.setBackgroundColor(ac.color_bg) tvColumnContext.setBackgroundColor(ac.color_bg)
@ -1393,11 +1394,11 @@ class ColumnViewHolder(
val scroll_save = ScrollPosition() val scroll_save = ScrollPosition()
column.scroll_save = scroll_save column.scroll_save = scroll_save
log.d( log.d(
"saveScrollPosition [%d] %s , listView is not visible, save %s,%s" "saveScrollPosition [%d] %s , listView is not visible, save %s,%s",
, page_idx page_idx,
, column.getColumnName(true) column.getColumnName(true),
, scroll_save.adapterIndex scroll_save.adapterIndex,
, scroll_save.offset scroll_save.offset
) )
return true return true
} }
@ -1406,11 +1407,11 @@ class ColumnViewHolder(
val scroll_save = ScrollPosition(this) val scroll_save = ScrollPosition(this)
column.scroll_save = scroll_save column.scroll_save = scroll_save
log.d( log.d(
"saveScrollPosition [%d] %s , listView is visible, save %s,%s" "saveScrollPosition [%d] %s , listView is visible, save %s,%s",
, page_idx page_idx,
, column.getColumnName(true) column.getColumnName(true),
, scroll_save.adapterIndex scroll_save.adapterIndex,
, scroll_save.offset scroll_save.offset
) )
return true return true
} }
@ -1586,10 +1587,10 @@ class ColumnViewHolder(
if(insideColumnSetting) { if(insideColumnSetting) {
svQuickFilter.setBackgroundColor(0) svQuickFilter.setBackgroundColor(0)
val colorFg = getAttributeColor(activity, R.attr.colorContentText) val colorFg = activity.getAttributeColor(R.attr.colorContentText)
val colorBgSelected = colorFg.applyAlphaMultiplier(0.25f) val colorBgSelected = colorFg.applyAlphaMultiplier(0.25f)
val colorFgList = ColorStateList.valueOf(colorFg) val colorFgList = ColorStateList.valueOf(colorFg)
val colorBg = getAttributeColor(activity, R.attr.colorColumnSettingBackground) val colorBg = activity.getAttributeColor(R.attr.colorColumnSettingBackground)
showQuickFilterButton = { btn, iconId, selected -> showQuickFilterButton = { btn, iconId, selected ->
btn.backgroundDrawable = btn.backgroundDrawable =
getAdaptiveRippleDrawableRound( getAdaptiveRippleDrawableRound(
@ -1721,7 +1722,7 @@ class ColumnViewHolder(
gravity = Gravity.END gravity = Gravity.END
startPadding = dip(4) startPadding = dip(4)
endPadding = dip(4) endPadding = dip(4)
textColor = getAttributeColor(context, R.attr.colorColumnHeaderAcct) textColor = context.getAttributeColor(R.attr.colorColumnHeaderAcct)
textSize = 12f textSize = 12f
}.lparams(0, wrapContent) { }.lparams(0, wrapContent) {
@ -1730,7 +1731,7 @@ class ColumnViewHolder(
tvColumnStatus = textView { tvColumnStatus = textView {
gravity = Gravity.END gravity = Gravity.END
textColor = getAttributeColor(context, R.attr.colorColumnHeaderPageNumber) textColor = context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
textSize = 12f textSize = 12f
}.lparams(wrapContent, wrapContent) { }.lparams(wrapContent, wrapContent) {
@ -1739,7 +1740,7 @@ class ColumnViewHolder(
tvColumnIndex = textView { tvColumnIndex = textView {
gravity = Gravity.END gravity = Gravity.END
textColor = getAttributeColor(context, R.attr.colorColumnHeaderPageNumber) textColor = context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
textSize = 12f textSize = 12f
}.lparams(wrapContent, wrapContent) { }.lparams(wrapContent, wrapContent) {
@ -1843,7 +1844,7 @@ class ColumnViewHolder(
val paint = Paint().apply { val paint = Paint().apply {
isAntiAlias = true isAntiAlias = true
color = color =
getAttributeColor(context, R.attr.colorColumnSettingBackground) context.getAttributeColor(R.attr.colorColumnSettingBackground)
} }
val path = Path() val path = Path()
addOutsideDrawer(this) { canvas, parent, view, left, top -> addOutsideDrawer(this) { canvas, parent, view, left, top ->
@ -1909,7 +1910,7 @@ class ColumnViewHolder(
maxHeight = dip(240) maxHeight = dip(240)
backgroundColor = backgroundColor =
getAttributeColor(context, R.attr.colorColumnSettingBackground) context.getAttributeColor(R.attr.colorColumnSettingBackground)
llColumnSettingInside = verticalLayout { llColumnSettingInside = verticalLayout {
lparams(matchParent, wrapContent) lparams(matchParent, wrapContent)
@ -1924,7 +1925,7 @@ class ColumnViewHolder(
label = textView { label = textView {
textColor = textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber) context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.hashtag_extra_any) text = context.getString(R.string.hashtag_extra_any)
}.lparams(matchParent, wrapContent) }.lparams(matchParent, wrapContent)
@ -1939,7 +1940,7 @@ class ColumnViewHolder(
label = textView { label = textView {
textColor = textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber) context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.hashtag_extra_all) text = context.getString(R.string.hashtag_extra_all)
}.lparams(matchParent, wrapContent) }.lparams(matchParent, wrapContent)
@ -1954,7 +1955,7 @@ class ColumnViewHolder(
label = textView { label = textView {
textColor = textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber) context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.hashtag_extra_none) text = context.getString(R.string.hashtag_extra_none)
}.lparams(matchParent, wrapContent) }.lparams(matchParent, wrapContent)
@ -2049,12 +2050,12 @@ class ColumnViewHolder(
label = textView { label = textView {
textColor = textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber) context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.regex_filter) text = context.getString(R.string.regex_filter)
}.lparams(wrapContent, wrapContent) }.lparams(wrapContent, wrapContent)
tvRegexFilterError = textView { tvRegexFilterError = textView {
textColor = getAttributeColor(context, R.attr.colorRegexFilterError) textColor = context.getAttributeColor(R.attr.colorRegexFilterError)
}.lparams(0, wrapContent) { }.lparams(0, wrapContent) {
weight = 1f weight = 1f
startMargin = dip(4) startMargin = dip(4)
@ -2220,10 +2221,7 @@ class ColumnViewHolder(
contentDescription = context.getString(R.string.clear) contentDescription = context.getString(R.string.clear)
imageResource = R.drawable.ic_close imageResource = R.drawable.ic_close
imageTintList = ColorStateList.valueOf( imageTintList = ColorStateList.valueOf(
getAttributeColor( context.getAttributeColor(R.attr.colorVectorDrawable)
context,
R.attr.colorVectorDrawable
)
) )
}.lparams(dip(40), dip(40)) { }.lparams(dip(40), dip(40)) {
startMargin = dip(4) startMargin = dip(4)
@ -2234,10 +2232,7 @@ class ColumnViewHolder(
contentDescription = context.getString(R.string.search) contentDescription = context.getString(R.string.search)
imageResource = R.drawable.ic_search imageResource = R.drawable.ic_search
imageTintList = ColorStateList.valueOf( imageTintList = ColorStateList.valueOf(
getAttributeColor( context.getAttributeColor(R.attr.colorVectorDrawable)
context,
R.attr.colorVectorDrawable
)
) )
}.lparams(dip(40), dip(40)) { }.lparams(dip(40), dip(40)) {
startMargin = dip(4) startMargin = dip(4)
@ -2269,8 +2264,7 @@ class ColumnViewHolder(
contentDescription = context.getString(R.string.add) contentDescription = context.getString(R.string.add)
imageResource = R.drawable.ic_add imageResource = R.drawable.ic_add
imageTintList = ColorStateList.valueOf( imageTintList = ColorStateList.valueOf(
getAttributeColor( context.getAttributeColor(
context,
R.attr.colorVectorDrawable R.attr.colorVectorDrawable
) )
) )
@ -2688,8 +2682,8 @@ class ColumnViewHolder(
btn.background = if(reaction.me == true) { btn.background = if(reaction.me == true) {
getAdaptiveRippleDrawableRound( getAdaptiveRippleDrawableRound(
actMain, actMain,
getAttributeColor(actMain, R.attr.colorButtonBgCw), actMain.getAttributeColor(R.attr.colorButtonBgCw),
getAttributeColor(actMain, R.attr.colorRippleEffect) actMain.getAttributeColor(R.attr.colorRippleEffect)
) )
} else { } else {
ContextCompat.getDrawable(actMain, R.drawable.btn_bg_transparent_round6dp) ContextCompat.getDrawable(actMain, R.drawable.btn_bg_transparent_round6dp)
@ -2775,7 +2769,7 @@ class ColumnViewHolder(
override fun handleResult(result : TootApiResult?) { override fun handleResult(result : TootApiResult?) {
result ?: return result ?: return
if(result.jsonObject == null) { if(result.jsonObject == null) {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} else { } else {
sample.count = 0 sample.count = 0
val list = item.reactions val list = item.reactions
@ -2811,7 +2805,7 @@ class ColumnViewHolder(
override fun handleResult(result : TootApiResult?) { override fun handleResult(result : TootApiResult?) {
result ?: return result ?: return
if(result.jsonObject == null) { if(result.jsonObject == null) {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} else { } else {
val it = item.reactions?.iterator() ?: return val it = item.reactions?.iterator() ?: return
while(it.hasNext()) { while(it.hasNext()) {

View File

@ -19,9 +19,7 @@ import jp.juggler.subwaytooter.span.MyClickableSpan
import jp.juggler.subwaytooter.table.FavMute import jp.juggler.subwaytooter.table.FavMute
import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.CustomShare import jp.juggler.subwaytooter.util.*
import jp.juggler.subwaytooter.util.CustomShareTarget
import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.util.* import jp.juggler.util.*
import org.jetbrains.anko.allCaps import org.jetbrains.anko.allCaps
import org.jetbrains.anko.backgroundDrawable import org.jetbrains.anko.backgroundDrawable
@ -349,14 +347,14 @@ internal class DlgContextMenu(
val colorButtonAccent = val colorButtonAccent =
Pref.ipButtonFollowingColor(activity.pref).notZero() Pref.ipButtonFollowingColor(activity.pref).notZero()
?: getAttributeColor(activity, R.attr.colorImageButtonAccent) ?: activity.getAttributeColor(R.attr.colorImageButtonAccent)
val colorButtonError = val colorButtonError =
Pref.ipButtonFollowRequestColor(activity.pref).notZero() Pref.ipButtonFollowRequestColor(activity.pref).notZero()
?: getAttributeColor(activity, R.attr.colorRegexFilterError) ?: activity.getAttributeColor(R.attr.colorRegexFilterError)
val colorButtonNormal = val colorButtonNormal =
getAttributeColor(activity, R.attr.colorImageButton) activity.getAttributeColor(R.attr.colorImageButton)
fun showRelation(relation : UserRelation) { fun showRelation(relation : UserRelation) {
@ -407,7 +405,7 @@ internal class DlgContextMenu(
ivFollowedBy.vg(false) ivFollowedBy.vg(false)
btnFollow.setImageResource(R.drawable.ic_follow_plus) btnFollow.setImageResource(R.drawable.ic_follow_plus)
btnFollow.imageTintList = btnFollow.imageTintList =
ColorStateList.valueOf(getAttributeColor(activity, R.attr.colorImageButton)) ColorStateList.valueOf(activity.getAttributeColor(R.attr.colorImageButton))
btnNotificationFrom.visibility = View.GONE btnNotificationFrom.visibility = View.GONE
} else { } else {
@ -585,7 +583,7 @@ internal class DlgContextMenu(
R.drawable.ic_arrow_drop_down R.drawable.ic_arrow_drop_down
} }
val iconColor = getAttributeColor(activity, R.attr.colorTimeSmall) val iconColor = activity.getAttributeColor(R.attr.colorTimeSmall)
val drawable = createColoredDrawable(activity, iconId, iconColor, 1f) val drawable = createColoredDrawable(activity, iconId, iconColor, 1f)
btn.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null) btn.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null)
} }
@ -713,7 +711,7 @@ internal class DlgContextMenu(
Action_User.mention(activity, access_info, who) Action_User.mention(activity, access_info, who)
R.id.btnAccountWebPage -> who.url?.let { url -> R.id.btnAccountWebPage -> who.url?.let { url ->
App1.openCustomTabOrBrowser(activity, url) activity.openCustomTabOrBrowser(url)
} }
R.id.btnFollowRequestOK -> R.id.btnFollowRequestOK ->
@ -752,13 +750,13 @@ internal class DlgContextMenu(
R.id.btnDomainBlock -> R.id.btnDomainBlock ->
if(access_info.isPseudo) { if(access_info.isPseudo) {
// 疑似アカウントではドメインブロックできない // 疑似アカウントではドメインブロックできない
showToast(activity, false, R.string.domain_block_from_pseudo) activity.showToast(false, R.string.domain_block_from_pseudo)
return return
} else { } else {
val whoApDomain = who.apDomain val whoApDomain = who.apDomain
// 自分のドメインではブロックできない // 自分のドメインではブロックできない
if(access_info.matchHost(whoApDomain)) { if(access_info.matchHost(whoApDomain)) {
showToast(activity, false, R.string.domain_block_from_local) activity.showToast(false, R.string.domain_block_from_local)
return return
} }
AlertDialog.Builder(activity) AlertDialog.Builder(activity)
@ -794,7 +792,7 @@ internal class DlgContextMenu(
R.id.btnAvatarImage -> { R.id.btnAvatarImage -> {
val url = if(! who.avatar.isNullOrEmpty()) who.avatar else who.avatar_static val url = if(! who.avatar.isNullOrEmpty()) who.avatar else who.avatar_static
if(url != null && url.isNotEmpty()) App1.openCustomTab(activity, url) activity.openCustomTab(url)
// XXX: 設定によっては内蔵メディアビューアで開けないか? // XXX: 設定によっては内蔵メディアビューアで開けないか?
} }
@ -821,7 +819,7 @@ internal class DlgContextMenu(
R.id.btnHideFavourite -> { R.id.btnHideFavourite -> {
val acct = access_info.getFullAcct(who) val acct = access_info.getFullAcct(who)
FavMute.save(acct) FavMute.save(acct)
showToast(activity, false, R.string.changed) activity.showToast(false, R.string.changed)
for(column in activity.app_state.column_list) { for(column in activity.app_state.column_list) {
column.onHideFavouriteNotification(acct) column.onHideFavouriteNotification(acct)
} }
@ -829,7 +827,7 @@ internal class DlgContextMenu(
R.id.btnShowFavourite -> { R.id.btnShowFavourite -> {
FavMute.delete(access_info.getFullAcct(who)) FavMute.delete(access_info.getFullAcct(who))
showToast(activity, false, R.string.changed) activity.showToast(false, R.string.changed)
} }
R.id.btnListMemberAddRemove -> R.id.btnListMemberAddRemove ->
@ -884,14 +882,12 @@ internal class DlgContextMenu(
R.id.btnCopyAccountId -> who.id.toString().copyToClipboard(activity) R.id.btnCopyAccountId -> who.id.toString().copyToClipboard(activity)
R.id.btnOpenAccountInAdminWebUi -> R.id.btnOpenAccountInAdminWebUi ->
App1.openBrowser( activity.openBrowser(
activity,
"https://${access_info.apiHost.ascii}/admin/accounts/${who.id}" "https://${access_info.apiHost.ascii}/admin/accounts/${who.id}"
) )
R.id.btnOpenInstanceInAdminWebUi -> R.id.btnOpenInstanceInAdminWebUi ->
App1.openBrowser( activity.openBrowser(
activity,
"https://${access_info.apiHost.ascii}/admin/instances/${who.apDomain.ascii}" "https://${access_info.apiHost.ascii}/admin/instances/${who.apDomain.ascii}"
) )
@ -929,8 +925,8 @@ internal class DlgContextMenu(
status, status,
access_info.getFullAcct(status.account), access_info.getFullAcct(status.account),
NOT_CROSS_ACCOUNT, NOT_CROSS_ACCOUNT,
activity.boost_complete_callback, visibility = list[which],
visibility = list[which] callback =activity.boost_complete_callback,
) )
} }
} }
@ -940,7 +936,7 @@ internal class DlgContextMenu(
R.id.btnNotificationFrom -> { R.id.btnNotificationFrom -> {
if(access_info.isMisskey) { if(access_info.isMisskey) {
showToast(activity, false, R.string.misskey_account_not_supported) activity.showToast(false, R.string.misskey_account_not_supported)
} else { } else {
access_info.getFullAcct(who).validFull()?.let { access_info.getFullAcct(who).validFull()?.let {
activity.addColumn( activity.addColumn(
@ -963,9 +959,8 @@ internal class DlgContextMenu(
when(v.id) { when(v.id) {
R.id.btnStatusWebPage -> status?.url?.let { url -> R.id.btnStatusWebPage ->
App1.openCustomTabOrBrowser(activity, url) activity.openCustomTabOrBrowser(status?.url)
}
R.id.btnText -> if(status != null) { R.id.btnText -> if(status != null) {
ActText.open(activity, ActMain.REQUEST_CODE_TEXT, access_info, status) ActText.open(activity, ActMain.REQUEST_CODE_TEXT, access_info, status)

View File

@ -12,6 +12,7 @@ import jp.juggler.util.showToast
class DownloadReceiver : BroadcastReceiver() { class DownloadReceiver : BroadcastReceiver() {
companion object { companion object {
private val log = LogCategory("DownloadReceiver") private val log = LogCategory("DownloadReceiver")
} }
@ -33,8 +34,7 @@ class DownloadReceiver : BroadcastReceiver() {
} }
val title = cursor.getStringOrNull(DownloadManager.COLUMN_TITLE) val title = cursor.getStringOrNull(DownloadManager.COLUMN_TITLE)
val status = cursor.getIntOrNull(DownloadManager.COLUMN_STATUS) val status = cursor.getIntOrNull(DownloadManager.COLUMN_STATUS)
showToast( context.showToast(
context,
false, false,
if(status == DownloadManager.STATUS_SUCCESSFUL) { if(status == DownloadManager.STATUS_SUCCESSFUL) {
context.getString(R.string.download_complete, title) context.getString(R.string.download_complete, title)

View File

@ -330,7 +330,7 @@ internal class ItemViewHolder(
val textShowMedia = SpannableString(activity.getString(R.string.tap_to_show)) val textShowMedia = SpannableString(activity.getString(R.string.tap_to_show))
.apply { .apply {
val colorBg = getAttributeColor(activity, R.attr.colorShowMediaBackground) val colorBg = activity.getAttributeColor(R.attr.colorShowMediaBackground)
.applyAlphaMultiplier(0.5f) .applyAlphaMultiplier(0.5f)
setSpan( setSpan(
BackgroundColorSpan(colorBg), BackgroundColorSpan(colorBg),
@ -1259,10 +1259,7 @@ internal class ItemViewHolder(
val conversationMainBgColor = val conversationMainBgColor =
Pref.ipConversationMainTootBgColor(activity.pref).notZero() Pref.ipConversationMainTootBgColor(activity.pref).notZero()
?: (getAttributeColor( ?: (activity.getAttributeColor(R.attr.colorImageButtonAccent) and 0xffffff) or 0x20000000
activity,
R.attr.colorImageButtonAccent
) and 0xffffff) or 0x20000000
this.viewRoot.setBackgroundColor(conversationMainBgColor) this.viewRoot.setBackgroundColor(conversationMainBgColor)
@ -1976,7 +1973,7 @@ internal class ItemViewHolder(
column.startGap(item, isHead = false) column.startGap(item, isHead = false)
else -> else ->
showToast(activity, true, "This column can't support gap reading.") activity.showToast(true, "This column can't support gap reading.")
} }
is TootSearchGap -> column.startGap(item, isHead = true) is TootSearchGap -> column.startGap(item, isHead = true)
@ -2018,7 +2015,7 @@ internal class ItemViewHolder(
.addAction(activity.getString(R.string.delete)) { .addAction(activity.getString(R.string.delete)) {
Action_Toot.deleteScheduledPost(activity, access_info, item) { Action_Toot.deleteScheduledPost(activity, access_info, item) {
column.onScheduleDeleted(item) column.onScheduleDeleted(item)
showToast(activity, false, R.string.scheduled_post_deleted) activity.showToast(false, R.string.scheduled_post_deleted)
} }
} }
.show(activity) .show(activity)
@ -2279,8 +2276,8 @@ internal class ItemViewHolder(
// メディアタイプがunknownの場合、そのほとんどはリモートから来たURLである // メディアタイプがunknownの場合、そのほとんどはリモートから来たURLである
// Pref.bpPriorLocalURL の状態に関わらずリモートURLがあればそれをブラウザで開く // Pref.bpPriorLocalURL の状態に関わらずリモートURLがあればそれをブラウザで開く
when(val remoteUrl = item.remote_url.notEmpty()) { when(val remoteUrl = item.remote_url.notEmpty()) {
null -> App1.openCustomTab(activity, item) null -> activity.openCustomTab(item)
else -> App1.openCustomTab(activity, remoteUrl) else -> activity.openCustomTab(remoteUrl)
} }
} }
@ -2297,7 +2294,7 @@ internal class ItemViewHolder(
) )
// ブラウザで開く // ブラウザで開く
else -> App1.openCustomTab(activity, item) else -> activity.openCustomTab(item)
} }
} }
} catch(ex : Throwable) { } catch(ex : Throwable) {
@ -2674,7 +2671,7 @@ internal class ItemViewHolder(
private fun addReaction(status : TootStatus, code : String?) { private fun addReaction(status : TootStatus, code : String?) {
if(status.myReaction?.isNotEmpty() == true) { if(status.myReaction?.isNotEmpty() == true) {
showToast(activity, false, R.string.already_reactioned) activity.showToast(false, R.string.already_reactioned)
return return
} }
@ -2718,7 +2715,7 @@ internal class ItemViewHolder(
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(activity, false, error) activity.showToast(false, error)
return return
} }
@ -2739,7 +2736,7 @@ internal class ItemViewHolder(
val reaction = status.myReaction val reaction = status.myReaction
if(reaction?.isNotEmpty() != true) { if(reaction?.isNotEmpty() != true) {
showToast(activity, false, R.string.not_reactioned) activity.showToast(false, R.string.not_reactioned)
return return
} }
@ -2773,7 +2770,7 @@ internal class ItemViewHolder(
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(activity, false, error) activity.showToast(false, error)
return return
} }
@ -3050,7 +3047,7 @@ internal class ItemViewHolder(
idx : Int idx : Int
) { ) {
if(enquete.ownVoted) { if(enquete.ownVoted) {
showToast(context, false, R.string.already_voted) context.showToast(false, R.string.already_voted)
return return
} }
@ -3064,14 +3061,14 @@ internal class ItemViewHolder(
TootPollsType.FriendsNico -> { TootPollsType.FriendsNico -> {
val remain = enquete.time_start + TootPolls.ENQUETE_EXPIRE - now val remain = enquete.time_start + TootPolls.ENQUETE_EXPIRE - now
if(remain <= 0L) { if(remain <= 0L) {
showToast(context, false, R.string.enquete_was_end) context.showToast(false, R.string.enquete_was_end)
return return
} }
} }
TootPollsType.Mastodon -> { TootPollsType.Mastodon -> {
if(enquete.expired || now >= enquete.expired_at) { if(enquete.expired || now >= enquete.expired_at) {
showToast(context, false, R.string.enquete_was_end) context.showToast(false, R.string.enquete_was_end)
return return
} }
} }
@ -3108,7 +3105,7 @@ internal class ItemViewHolder(
if(data != null) { if(data != null) {
when(enquete.pollType) { when(enquete.pollType) {
TootPollsType.Misskey -> if(enquete.increaseVote(activity, idx, true)) { TootPollsType.Misskey -> if(enquete.increaseVote(activity, idx, true)) {
showToast(context, false, R.string.enquete_voted) context.showToast(false, R.string.enquete_voted)
// 1個だけ開閉するのではなく、例えば通知TLにある複数の要素をまとめて開閉するなどある // 1個だけ開閉するのではなく、例えば通知TLにある複数の要素をまとめて開閉するなどある
list_adapter.notifyChange(reason = "onClickEnqueteChoice", reset = true) list_adapter.notifyChange(reason = "onClickEnqueteChoice", reset = true)
@ -3130,7 +3127,7 @@ internal class ItemViewHolder(
reset = true reset = true
) )
} else if(result.error != null) { } else if(result.error != null) {
showToast(context, true, "response parse error") context.showToast(true, "response parse error")
} }
} }
@ -3138,14 +3135,14 @@ internal class ItemViewHolder(
val message = data.string("message") ?: "?" val message = data.string("message") ?: "?"
val valid = data.optBoolean("valid") val valid = data.optBoolean("valid")
if(valid) { if(valid) {
showToast(context, false, R.string.enquete_voted) context.showToast(false, R.string.enquete_voted)
} else { } else {
showToast(context, true, R.string.enquete_vote_failed, message) context.showToast(true, R.string.enquete_vote_failed, message)
} }
} }
} }
} else { } else {
showToast(context, true, result.error) context.showToast(true, result.error)
} }
} }
@ -3160,12 +3157,12 @@ internal class ItemViewHolder(
) { ) {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
if(now >= enquete.expired_at) { if(now >= enquete.expired_at) {
showToast(context, false, R.string.enquete_was_end) context.showToast(false, R.string.enquete_was_end)
return return
} }
if(enquete.items?.find { it.checked } == null) { if(enquete.items?.find { it.checked } == null) {
showToast(context, false, R.string.polls_choice_not_selected) context.showToast(false, R.string.polls_choice_not_selected)
return return
} }
@ -3207,7 +3204,7 @@ internal class ItemViewHolder(
// 1個だけ開閉するのではなく、例えば通知TLにある複数の要素をまとめて開閉するなどある // 1個だけ開閉するのではなく、例えば通知TLにある複数の要素をまとめて開閉するなどある
list_adapter.notifyChange(reason = "onClickEnqueteChoice", reset = true) list_adapter.notifyChange(reason = "onClickEnqueteChoice", reset = true)
} else if(result.error != null) { } else if(result.error != null) {
showToast(context, true, result.error) context.showToast(true, result.error)
} }
} }
}) })
@ -3322,13 +3319,11 @@ internal class ItemViewHolder(
tvFollowerAcct = textView { tvFollowerAcct = textView {
setPaddingStartEnd(dip(4), dip(4)) setPaddingStartEnd(dip(4), dip(4))
textSize = 12f // SP textSize = 12f // SP
// tools:text="aaaaaaaaaaaaaaaa"
}.lparams(matchParent, wrapContent) }.lparams(matchParent, wrapContent)
tvLastStatusAt = myTextView { tvLastStatusAt = myTextView {
setPaddingStartEnd(dip(4), dip(4)) setPaddingStartEnd(dip(4), dip(4))
textSize = 12f // SP textSize = 12f // SP
// tools:text="aaaaaaaaaaaaaaaa"
}.lparams(matchParent, wrapContent) }.lparams(matchParent, wrapContent)
} }
@ -3580,14 +3575,14 @@ internal class ItemViewHolder(
btnShowMedia = blurhashView { btnShowMedia = blurhashView {
errorColor = getAttributeColor( errorColor = context.getAttributeColor(
context,
R.attr.colorShowMediaBackground R.attr.colorShowMediaBackground
) )
gravity = Gravity.CENTER gravity = Gravity.CENTER
textColor = getAttributeColor( textColor = context.getAttributeColor(
context,
R.attr.colorShowMediaText R.attr.colorShowMediaText
) )
@ -3678,14 +3673,12 @@ internal class ItemViewHolder(
btnShowMedia = blurhashView { btnShowMedia = blurhashView {
errorColor = getAttributeColor( errorColor = context.getAttributeColor(
context,
R.attr.colorShowMediaBackground R.attr.colorShowMediaBackground
) )
gravity = Gravity.CENTER gravity = Gravity.CENTER
textColor = getAttributeColor( textColor = context.getAttributeColor(
context,
R.attr.colorShowMediaText R.attr.colorShowMediaText
) )
@ -3745,14 +3738,12 @@ internal class ItemViewHolder(
btnCardImageShow = blurhashView { btnCardImageShow = blurhashView {
errorColor = getAttributeColor( errorColor = context.getAttributeColor(
context,
R.attr.colorShowMediaBackground R.attr.colorShowMediaBackground
) )
gravity = Gravity.CENTER gravity = Gravity.CENTER
textColor = getAttributeColor( textColor = context.getAttributeColor(
context,
R.attr.colorShowMediaText R.attr.colorShowMediaText
) )

View File

@ -230,7 +230,7 @@ class PollingWorker private constructor(contextArg : Context) {
val intervalMillis = max( val intervalMillis = max(
minute * 5L, minute * 5L,
minute * Pref.spPullNotificationCheckInterval.toInt(Pref.pref(context)) minute * Pref.spPullNotificationCheckInterval.toInt(context.pref())
) )
val flexMillis = max( val flexMillis = max(

View File

@ -6,6 +6,9 @@ import android.graphics.Color
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import jp.juggler.util.optInt import jp.juggler.util.optInt
fun Context.pref() : SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(this)
@Suppress("EqualsOrHashCode") @Suppress("EqualsOrHashCode")
abstract class BasePref<T>(val key : String, val defVal : T) { abstract class BasePref<T>(val key : String, val defVal : T) {
@ -17,28 +20,25 @@ abstract class BasePref<T>(val key : String, val defVal : T) {
Pref.map[key] = this Pref.map[key] = this
} }
override fun equals(other : Any?) : Boolean {
return this === other
}
fun remove(e : SharedPreferences.Editor) {
e.remove(key)
}
abstract fun put(editor : SharedPreferences.Editor, v : T) abstract fun put(editor : SharedPreferences.Editor, v : T)
abstract fun invoke(pref : SharedPreferences) : T abstract fun invoke(pref : SharedPreferences) : T
override fun equals(other : Any?) =
this === other
operator fun invoke(context : Context) : T { operator fun invoke(context : Context) : T =
return invoke(Pref.pref(context)) invoke(context.pref())
}
fun removeDefault(pref : SharedPreferences, e : SharedPreferences.Editor) : Boolean { fun remove(e : SharedPreferences.Editor) : SharedPreferences.Editor =
e.remove(key)
fun removeDefault(pref : SharedPreferences, e : SharedPreferences.Editor) =
if(pref.contains(key) && this.invoke(pref) == defVal) { if(pref.contains(key) && this.invoke(pref) == defVal) {
e.remove(key) e.remove(key)
return true true
}else {
false
} }
return false
}
} }
fun SharedPreferences.Editor.remove(item : BasePref<*>) : SharedPreferences.Editor { fun SharedPreferences.Editor.remove(item : BasePref<*>) : SharedPreferences.Editor {
@ -125,10 +125,6 @@ fun SharedPreferences.Editor.put(item : FloatPref, v : Float) =
object Pref { object Pref {
fun pref(context : Context) : SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(context)
}
// キー名と設定項目のマップ。インポートやアプリ設定で使う // キー名と設定項目のマップ。インポートやアプリ設定で使う
val map = HashMap<String, BasePref<*>>() val map = HashMap<String, BasePref<*>>()
@ -445,6 +441,7 @@ object Pref {
// int // int
val ipBackButtonAction = IntPref("back_button_action", 0) val ipBackButtonAction = IntPref("back_button_action", 0)
@Suppress("unused") @Suppress("unused")
const val BACK_ASK_ALWAYS = 0 const val BACK_ASK_ALWAYS = 0
const val BACK_CLOSE_COLUMN = 1 const val BACK_CLOSE_COLUMN = 1
@ -454,18 +451,18 @@ object Pref {
val ipUiTheme = IntPref("ui_theme", 0) val ipUiTheme = IntPref("ui_theme", 0)
val ipResizeImage = IntPref("resize_image", 4) val ipResizeImage = IntPref("resize_image", 4)
const val RC_SIMPLE = 0 const val RC_SIMPLE = 0
const val RC_ACTUAL = 1 const val RC_ACTUAL = 1
@Suppress("unused") @Suppress("unused")
const val RC_NONE = 2 const val RC_NONE = 2
val ipRepliesCount = IntPref("RepliesCount", RC_SIMPLE) val ipRepliesCount = IntPref("RepliesCount", RC_SIMPLE)
val ipBoostsCount = IntPref("BoostsCount", RC_ACTUAL) val ipBoostsCount = IntPref("BoostsCount", RC_ACTUAL)
val ipFavouritesCount = IntPref("FavouritesCount", RC_ACTUAL) val ipFavouritesCount = IntPref("FavouritesCount", RC_ACTUAL)
val ipRefreshAfterToot = IntPref("refresh_after_toot", 0) val ipRefreshAfterToot = IntPref("refresh_after_toot", 0)
const val RAT_REFRESH_SCROLL = 0 const val RAT_REFRESH_SCROLL = 0
@Suppress("unused") @Suppress("unused")
const val RAT_REFRESH_DONT_SCROLL = 1 const val RAT_REFRESH_DONT_SCROLL = 1
const val RAT_DONT_REFRESH = 2 const val RAT_DONT_REFRESH = 2
@ -477,6 +474,7 @@ object Pref {
val ipVisibilityStyle = IntPref("ipVisibilityStyle", VS_BY_ACCOUNT) val ipVisibilityStyle = IntPref("ipVisibilityStyle", VS_BY_ACCOUNT)
const val ABP_TOP = 0 const val ABP_TOP = 0
@Suppress("unused") @Suppress("unused")
const val ABP_BOTTOM = 1 const val ABP_BOTTOM = 1
const val ABP_START = 2 const val ABP_START = 2
@ -547,8 +545,6 @@ object Pref {
val ipVerifiedLinkBgColor = IntPref("VerifiedLinkBgColor", 0) val ipVerifiedLinkBgColor = IntPref("VerifiedLinkBgColor", 0)
val ipVerifiedLinkFgColor = IntPref("VerifiedLinkFgColor", 0) val ipVerifiedLinkFgColor = IntPref("VerifiedLinkFgColor", 0)
// val ipTrendTagCountShowing = IntPref("TrendTagCountShowing", 0) // val ipTrendTagCountShowing = IntPref("TrendTagCountShowing", 0)
// const val TTCS_WEEKLY = 0 // const val TTCS_WEEKLY = 0
// const val TTCS_DAILY = 1 // const val TTCS_DAILY = 1
@ -577,7 +573,7 @@ object Pref {
val spBoostAlpha = StringPref("BoostAlpha", "60") val spBoostAlpha = StringPref("BoostAlpha", "60")
val spScreenBottomPadding = StringPref("ScreenBottomPadding", "8") val spScreenBottomPadding = StringPref("ScreenBottomPadding", "8")
val spPullNotificationCheckInterval = StringPref("PullNotificationCheckInterval", "15") val spPullNotificationCheckInterval = StringPref("PullNotificationCheckInterval", "15")
val spUserAgent = StringPref("UserAgent", "") val spUserAgent = StringPref("UserAgent", "")
@ -611,3 +607,4 @@ object Pref {
internal const val default_header_font_size = 14f internal const val default_header_font_size = 14f
} }

View File

@ -25,6 +25,7 @@ import jp.juggler.subwaytooter.action.Action_Instance
import jp.juggler.subwaytooter.api.entity.TootStatus import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.VersionString import jp.juggler.subwaytooter.util.VersionString
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.* import jp.juggler.util.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -52,7 +53,7 @@ class SideMenuAdapter(
private fun clickableSpan(url : String) = private fun clickableSpan(url : String) =
object : ClickableSpan() { object : ClickableSpan() {
override fun onClick(widget : View) { override fun onClick(widget : View) {
App1.openBrowser(widget.activity as ActMain, url) widget.activity?.openBrowser(url)
} }
override fun updateDrawState(ds : TextPaint) { override fun updateDrawState(ds : TextPaint) {
@ -89,10 +90,9 @@ class SideMenuAdapter(
currentVersion currentVersion
) )
) )
val newRelease = when(Pref.bpCheckBetaVersion(Pref.pref(appContext))) { val newRelease = releaseInfo?.jsonObject(
false -> releaseInfo?.jsonObject("stable") if(Pref.bpCheckBetaVersion(App1.pref)) "beta" else "stable"
else -> releaseInfo?.jsonObject("beta") )
}
val newVersion = val newVersion =
(newRelease?.string("name")?.notEmpty() ?: newRelease?.string("tag_name")) (newRelease?.string("name")?.notEmpty() ?: newRelease?.string("tag_name"))
@ -122,10 +122,7 @@ class SideMenuAdapter(
) )
setSpan( setSpan(
ForegroundColorSpan( ForegroundColorSpan(
getAttributeColor( appContext.getAttributeColor(R.attr.colorRegexFilterError)
appContext,
R.attr.colorRegexFilterError
)
), ),
start, length, start, length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
@ -362,7 +359,7 @@ class SideMenuAdapter(
} }
) )
private val iconColor = getAttributeColor(actMain, R.attr.colorTimeSmall) private val iconColor = actMain.getAttributeColor(R.attr.colorTimeSmall)
override fun getCount() : Int = list.size override fun getCount() : Int = list.size
override fun getItem(position : Int) : Any = list[position] override fun getItem(position : Int) : Any = list[position]
@ -427,7 +424,7 @@ class SideMenuAdapter(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT FrameLayout.LayoutParams.MATCH_PARENT
) )
backgroundColor = getAttributeColor(actMain, R.attr.colorWindowBackground) backgroundColor = actMain.getAttributeColor(R.attr.colorWindowBackground)
selector = StateListDrawable() selector = StateListDrawable()
divider = null divider = null
dividerHeight = 0 dividerHeight = 0

View File

@ -19,6 +19,7 @@ import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.CustomShare import jp.juggler.subwaytooter.util.CustomShare
import jp.juggler.subwaytooter.util.CustomShareTarget import jp.juggler.subwaytooter.util.CustomShareTarget
import jp.juggler.subwaytooter.util.emptyCallback
import jp.juggler.subwaytooter.util.startMargin import jp.juggler.subwaytooter.util.startMargin
import jp.juggler.subwaytooter.view.CountImageButton import jp.juggler.subwaytooter.view.CountImageButton
import jp.juggler.util.* import jp.juggler.util.*
@ -36,6 +37,7 @@ internal class StatusButtons(
) : View.OnClickListener, View.OnLongClickListener { ) : View.OnClickListener, View.OnLongClickListener {
companion object { companion object {
val log = LogCategory("StatusButtons") val log = LogCategory("StatusButtons")
} }
@ -64,7 +66,7 @@ internal class StatusButtons(
private val color_normal = column.getContentColor() private val color_normal = column.getContentColor()
private val color_accent : Int private val color_accent : Int
get() = getAttributeColor(activity, R.attr.colorImageButtonAccent) get() = activity.getAttributeColor(R.attr.colorImageButtonAccent)
init { init {
this.access_info = column.access_info this.access_info = column.access_info
@ -494,13 +496,13 @@ internal class StatusButtons(
status, status,
access_info.getFullAcct(status.account), access_info.getFullAcct(status.account),
NOT_CROSS_ACCOUNT, NOT_CROSS_ACCOUNT,
when { bSet = bSet,
! bSimpleList -> null callback = when {
! bSimpleList -> emptyCallback
// 簡略表示なら結果をトースト表示 // 簡略表示なら結果をトースト表示
bSet -> activity.boost_complete_callback bSet -> activity.boost_complete_callback
else -> activity.unboost_complete_callback else -> activity.unboost_complete_callback
}, },
bSet = bSet
) )
} }
} }
@ -518,13 +520,13 @@ internal class StatusButtons(
access_info, access_info,
status, status,
NOT_CROSS_ACCOUNT, NOT_CROSS_ACCOUNT,
when { bSet = bSet,
! bSimpleList -> null callback = when {
! bSimpleList -> emptyCallback
// 簡略表示なら結果をトースト表示 // 簡略表示なら結果をトースト表示
bSet -> activity.favourite_complete_callback bSet -> activity.favourite_complete_callback
else -> activity.unfavourite_complete_callback else -> activity.unfavourite_complete_callback
}, },
bSet = bSet
) )
} }
} }
@ -542,13 +544,13 @@ internal class StatusButtons(
access_info, access_info,
status, status,
NOT_CROSS_ACCOUNT, NOT_CROSS_ACCOUNT,
when { bSet = bSet,
! bSimpleList -> null callback = when {
! bSimpleList -> emptyCallback
// 簡略表示なら結果をトースト表示 // 簡略表示なら結果をトースト表示
bSet -> activity.bookmark_complete_callback bSet -> activity.bookmark_complete_callback
else -> activity.unbookmark_complete_callback else -> activity.unbookmark_complete_callback
}, },
bSet = bSet
) )
} }
} }
@ -720,6 +722,7 @@ internal class StatusButtons(
} }
open class _FlexboxLayout(ctx : Context) : FlexboxLayout(ctx) { open class _FlexboxLayout(ctx : Context) : FlexboxLayout(ctx) {
inline fun <T : View> T.lparams( inline fun <T : View> T.lparams(
width : Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, width : Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
height : Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, height : Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
@ -733,10 +736,10 @@ open class _FlexboxLayout(ctx : Context) : FlexboxLayout(ctx) {
} }
class StatusButtonsViewHolder( class StatusButtonsViewHolder(
activity : ActMain activity : ActMain,
, lpWidth : Int lpWidth : Int,
, topMarginDp : Float topMarginDp : Float,
, @JustifyContent justifyContent : Int = JustifyContent.CENTER @JustifyContent justifyContent : Int = JustifyContent.CENTER
) { ) {
private val buttonHeight = ActMain.boostButtonSize private val buttonHeight = ActMain.boostButtonSize

View File

@ -30,7 +30,7 @@ object Styler {
fun defaultColorIcon(context : Context, iconId : Int) : Drawable? = fun defaultColorIcon(context : Context, iconId : Int) : Drawable? =
ContextCompat.getDrawable(context, iconId)?.also { ContextCompat.getDrawable(context, iconId)?.also {
it.setTint(getAttributeColor(context, R.attr.colorVectorDrawable)) it.setTint(context.getAttributeColor(R.attr.colorVectorDrawable))
it.setTintMode(PorterDuff.Mode.SRC_IN) it.setTintMode(PorterDuff.Mode.SRC_IN)
} }
@ -123,7 +123,7 @@ object Styler {
val icon_id = getVisibilityIconId(isMisskeyData, visibility) val icon_id = getVisibilityIconId(isMisskeyData, visibility)
val sv = getVisibilityString(context, isMisskeyData, visibility) val sv = getVisibilityString(context, isMisskeyData, visibility)
val color = getAttributeColor(context, R.attr.colorVectorDrawable) val color = context.getAttributeColor(R.attr.colorVectorDrawable)
val sb = SpannableStringBuilder() val sb = SpannableStringBuilder()
// アイコン部分 // アイコン部分
@ -159,12 +159,12 @@ object Styler {
alphaMultiplier : Float alphaMultiplier : Float
) { ) {
fun colorAccent() = fun colorAccent() =
Pref.ipButtonFollowingColor(Pref.pref(context)).notZero() Pref.ipButtonFollowingColor(context.pref()).notZero()
?: getAttributeColor(context, R.attr.colorImageButtonAccent) ?: context.getAttributeColor(R.attr.colorImageButtonAccent)
fun colorError() = fun colorError() =
Pref.ipButtonFollowRequestColor(Pref.pref(context)).notZero() Pref.ipButtonFollowRequestColor(context.pref()).notZero()
?: getAttributeColor(context, R.attr.colorRegexFilterError) ?: context.getAttributeColor(R.attr.colorRegexFilterError)
// 被フォロー状態 // 被フォロー状態
when { when {

View File

@ -10,6 +10,8 @@ import jp.juggler.subwaytooter.action.Action_Instance
import jp.juggler.subwaytooter.api.entity.Host import jp.juggler.subwaytooter.api.entity.Host
import jp.juggler.subwaytooter.api.entity.TootInstance import jp.juggler.subwaytooter.api.entity.TootInstance
import jp.juggler.subwaytooter.util.DecodeOptions import jp.juggler.subwaytooter.util.DecodeOptions
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.subwaytooter.util.openCustomTab
import jp.juggler.subwaytooter.view.MyLinkMovementMethod import jp.juggler.subwaytooter.view.MyLinkMovementMethod
import jp.juggler.subwaytooter.view.MyNetworkImageView import jp.juggler.subwaytooter.view.MyNetworkImageView
import jp.juggler.util.LogCategory import jp.juggler.util.LogCategory
@ -20,10 +22,10 @@ import org.conscrypt.OpenSSLX509Certificate
internal class ViewHolderHeaderInstance( internal class ViewHolderHeaderInstance(
arg_activity : ActMain, arg_activity : ActMain,
viewRoot : View viewRoot : View
) : ViewHolderHeaderBase(arg_activity, viewRoot) ) : ViewHolderHeaderBase(arg_activity, viewRoot), View.OnClickListener {
, View.OnClickListener {
companion object { companion object {
private val log = LogCategory("ViewHolderHeaderInstance") private val log = LogCategory("ViewHolderHeaderInstance")
} }
@ -122,12 +124,13 @@ internal class ViewHolderHeaderInstance(
btnEmail.isEnabled = email.isNotEmpty() btnEmail.isEnabled = email.isNotEmpty()
val contact_acct = val contact_acct =
instance.contact_account?.let { who -> "@${who.username}@${who.apDomain.pretty}" } ?: "" instance.contact_account?.let { who -> "@${who.username}@${who.apDomain.pretty}" }
?: ""
btnContact.text = contact_acct btnContact.text = contact_acct
btnContact.isEnabled = contact_acct.isNotEmpty() btnContact.isEnabled = contact_acct.isNotEmpty()
tvLanguages.text = instance.languages?.joinToString(", ") ?: "" tvLanguages.text = instance.languages?.joinToString(", ") ?: ""
tvInvitesEnabled.text = when(instance.invites_enabled){ tvInvitesEnabled.text = when(instance.invites_enabled) {
null -> "?" null -> "?"
true -> activity.getString(R.string.yes) true -> activity.getString(R.string.yes)
false -> activity.getString(R.string.no) false -> activity.getString(R.string.no)
@ -183,15 +186,15 @@ internal class ViewHolderHeaderInstance(
Certificate : ${cert.type} Certificate : ${cert.type}
subject : ${cert.subjectDN} subject : ${cert.subjectDN}
subjectAlternativeNames : ${ subjectAlternativeNames : ${
cert.subjectAlternativeNames cert.subjectAlternativeNames
?.joinToString(", ") { ?.joinToString(", ") {
try { try {
it?.last() it?.last()
} catch(ignored : Throwable) { } catch(ignored : Throwable) {
it it
}
?.toString() ?: "null"
} }
?.toString() ?: "null"
}
} }
issuer : ${cert.issuerX500Principal} issuer : ${cert.issuerX500Principal}
end : ${cert.notAfter} end : ${cert.notAfter}
@ -216,7 +219,7 @@ internal class ViewHolderHeaderInstance(
R.id.btnEmail -> instance?.email?.let { email -> R.id.btnEmail -> instance?.email?.let { email ->
try { try {
if(email.contains("://")) { if(email.contains("://")) {
App1.openCustomTab(activity, email) activity.openCustomTab(email)
} else { } else {
val intent = Intent(Intent.ACTION_SEND) val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain" intent.type = "text/plain"
@ -227,28 +230,31 @@ internal class ViewHolderHeaderInstance(
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.e(ex, "startActivity failed. mail=$email") log.e(ex, "startActivity failed. mail=$email")
showToast(activity, true, R.string.missing_mail_app) activity.showToast(true, R.string.missing_mail_app)
} }
} }
R.id.btnContact -> instance?.contact_account?.let { who -> R.id.btnContact -> instance?.contact_account?.let { who ->
Action_Account.timeline( Action_Account.timeline(
activity activity,
, activity.nextPosition(column) activity.nextPosition(column),
, ColumnType.SEARCH ColumnType.SEARCH,
, args = arrayOf("@${who.username}@${who.apDomain.ascii}", true) args = arrayOf("@${who.username}@${who.apDomain.ascii}", true)
) )
} }
R.id.btnInstance -> App1.openBrowser(activity, "https://${host.pretty}/about") R.id.btnInstance ->
R.id.ivThumbnail -> App1.openBrowser(activity, instance?.thumbnail) activity.openBrowser("https://${host.ascii}/about")
R.id.ivThumbnail ->
activity.openBrowser(instance?.thumbnail)
R.id.btnAbout -> R.id.btnAbout ->
App1.openBrowser(activity, "https://${host.pretty}/about") activity.openBrowser("https://${host.ascii}/about")
R.id.btnAboutMore -> R.id.btnAboutMore ->
App1.openBrowser(activity, "https://${host.pretty}/about/more") activity.openBrowser("https://${host.ascii}/about/more")
R.id.btnExplore -> Action_Instance.profileDirectoryFromInstanceInformation( R.id.btnExplore -> Action_Instance.profileDirectoryFromInstanceInformation(
activity, activity,

View File

@ -22,6 +22,7 @@ import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.DecodeOptions import jp.juggler.subwaytooter.util.DecodeOptions
import jp.juggler.subwaytooter.util.NetworkEmojiInvalidator import jp.juggler.subwaytooter.util.NetworkEmojiInvalidator
import jp.juggler.subwaytooter.util.openCustomTab
import jp.juggler.subwaytooter.util.startMargin import jp.juggler.subwaytooter.util.startMargin
import jp.juggler.subwaytooter.view.MyLinkMovementMethod import jp.juggler.subwaytooter.view.MyLinkMovementMethod
import jp.juggler.subwaytooter.view.MyNetworkImageView import jp.juggler.subwaytooter.view.MyNetworkImageView
@ -139,7 +140,7 @@ internal class ViewHolderHeaderProfile(
override fun showColor() { override fun showColor() {
llProfile.setBackgroundColor( llProfile.setBackgroundColor(
when(val c = column.column_bg_color) { when(val c = column.column_bg_color) {
0 -> getAttributeColor(activity, R.attr.colorProfileBackgroundMask) 0 -> activity.getAttributeColor(R.attr.colorProfileBackgroundMask)
else -> - 0x40000000 or (0x00ffffff and c) else -> - 0x40000000 or (0x00ffffff and c)
} }
) )
@ -194,7 +195,7 @@ internal class ViewHolderHeaderProfile(
color = contentColor, color = contentColor,
alphaMultiplier = Styler.boost_alpha alphaMultiplier = Styler.boost_alpha
) )
setIconDrawableId( setIconDrawableId(
activity, activity,
btnPersonalNotesEdit, btnPersonalNotesEdit,
@ -202,7 +203,7 @@ internal class ViewHolderHeaderProfile(
color = contentColor, color = contentColor,
alphaMultiplier = Styler.boost_alpha alphaMultiplier = Styler.boost_alpha
) )
val acctColor = column.getAcctColor() val acctColor = column.getAcctColor()
tvCreated.textColor = acctColor tvCreated.textColor = acctColor
tvMovedAcct.textColor = acctColor tvMovedAcct.textColor = acctColor
@ -354,8 +355,10 @@ internal class ViewHolderHeaderProfile(
tvMisskeyExtra.vg(tvMisskeyExtra.text.isNotEmpty()) tvMisskeyExtra.vg(tvMisskeyExtra.text.isNotEmpty())
btnStatusCount.text = btnStatusCount.text =
"${activity.getString(R.string.statuses)}\n${whoDetail?.statuses_count "${activity.getString(R.string.statuses)}\n${
?: who.statuses_count}" whoDetail?.statuses_count
?: who.statuses_count
}"
if(Pref.bpHideFollowCount(activity.pref)) { if(Pref.bpHideFollowCount(activity.pref)) {
btnFollowing.text = activity.getString(R.string.following) btnFollowing.text = activity.getString(R.string.following)
@ -363,18 +366,18 @@ internal class ViewHolderHeaderProfile(
} else { } else {
btnFollowing.text = btnFollowing.text =
"${activity.getString(R.string.following)}\n${ "${activity.getString(R.string.following)}\n${
whoDetail?.following_count ?: who.following_count whoDetail?.following_count ?: who.following_count
}" }"
btnFollowers.text = btnFollowers.text =
"${activity.getString(R.string.followers)}\n${ "${activity.getString(R.string.followers)}\n${
whoDetail?.followers_count ?: who.followers_count whoDetail?.followers_count ?: who.followers_count
}" }"
} }
val relation = UserRelation.load(access_info.db_id, who.id) val relation = UserRelation.load(access_info.db_id, who.id)
this.relation = relation this.relation = relation
Styler.setFollowIcon( Styler.setFollowIcon(
activity, activity,
btnFollow, btnFollow,
@ -386,7 +389,7 @@ internal class ViewHolderHeaderProfile(
) )
tvPersonalNotes.text = relation.note ?: "" tvPersonalNotes.text = relation.note ?: ""
showMoved(who, who.movedRef) showMoved(who, who.movedRef)
val fields = whoDetail?.fields ?: who.fields val fields = whoDetail?.fields ?: who.fields
@ -451,8 +454,10 @@ internal class ViewHolderHeaderProfile(
?: (Color.BLACK or 0x7fbc99) ?: (Color.BLACK or 0x7fbc99)
valueText.setSpan( valueText.setSpan(
ForegroundColorSpan(linkFgColor) ForegroundColorSpan(linkFgColor),
, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE start,
end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
) )
} }
@ -537,9 +542,8 @@ internal class ViewHolderHeaderProfile(
when(v.id) { when(v.id) {
R.id.ivBackground, R.id.tvRemoteProfileWarning -> whoRef?.get()?.url?.let { url -> R.id.ivBackground, R.id.tvRemoteProfileWarning ->
App1.openCustomTab(activity, url) activity.openCustomTab(whoRef?.get()?.url)
}
R.id.btnFollowing -> { R.id.btnFollowing -> {
column.profile_tab = ProfileTab.Following column.profile_tab = ProfileTab.Following
@ -584,44 +588,45 @@ internal class ViewHolderHeaderProfile(
} }
} }
R.id.btnPersonalNotesEdit -> whoRef?.let{ whoRef-> R.id.btnPersonalNotesEdit -> whoRef?.let { whoRef ->
val who = whoRef.get() val who = whoRef.get()
val relation = this.relation val relation = this.relation
val lastColumn = column val lastColumn = column
DlgTextInput.show( DlgTextInput.show(
activity, activity,
AcctColor.getStringWithNickname(activity,R.string.personal_notes_of,who.acct), AcctColor.getStringWithNickname(activity, R.string.personal_notes_of, who.acct),
relation?.note ?: "", relation?.note ?: "",
allowEmpty = true, allowEmpty = true,
callback = object: DlgTextInput.Callback{ callback = object : DlgTextInput.Callback {
override fun onEmptyError() { override fun onEmptyError() {
} }
override fun onOK(dialog : Dialog, text : String) { override fun onOK(dialog : Dialog, text : String) {
TootTaskRunner(activity).run(column.access_info,object:TootTask{ TootTaskRunner(activity).run(column.access_info, object : TootTask {
override fun background(client : TootApiClient) : TootApiResult? { override fun background(client : TootApiClient) : TootApiResult? {
if(access_info.isPseudo) if(access_info.isPseudo)
return TootApiResult("Personal notes is not supported on pseudo account.") return TootApiResult("Personal notes is not supported on pseudo account.")
if(access_info.isMisskey) if(access_info.isMisskey)
return TootApiResult("Personal notes is not supported on Misskey account.") return TootApiResult("Personal notes is not supported on Misskey account.")
return client.request("/api/v1/accounts/${who.id}/note", return client.request(
"/api/v1/accounts/${who.id}/note",
jsonObject { jsonObject {
put("comment",text) put("comment", text)
}.toPostRequestBuilder() }.toPostRequestBuilder()
) )
} }
override fun handleResult(result : TootApiResult?) { override fun handleResult(result : TootApiResult?) {
if(result==null) return if(result == null) return
if(result.error!=null) if(result.error != null)
showToast(activity,true,result.error) activity.showToast(true, result.error)
else{ else {
relation?.note = text relation?.note = text
dialog.dismissSafe() dialog.dismissSafe()
if(lastColumn==column) bindData(column) if(lastColumn == column) bindData(column)
} }
} }
}) })

View File

@ -22,7 +22,7 @@ internal fun addPseudoAccount(
callback : (SavedAccount) -> Unit callback : (SavedAccount) -> Unit
) { ) {
try { try {
val acct = Acct.parse("?",host) val acct = Acct.parse("?", host)
var account = SavedAccount.loadAccountByAcct(context, acct.ascii) var account = SavedAccount.loadAccountByAcct(context, acct.ascii)
if(account != null) { if(account != null) {
@ -45,7 +45,7 @@ internal fun addPseudoAccount(
result == null -> { result == null -> {
} }
targetInstance == null -> showToast(context, false, result.error) targetInstance == null -> context.showToast(false, result.error)
else -> addPseudoAccount(context, host, targetInstance, callback) else -> addPseudoAccount(context, host, targetInstance, callback)
} }
}) })
@ -58,7 +58,7 @@ internal fun addPseudoAccount(
} }
val row_id = SavedAccount.insert( val row_id = SavedAccount.insert(
acct =acct.ascii, acct = acct.ascii,
host = host.ascii, host = host.ascii,
domain = instanceInfo.uri, domain = instanceInfo.uri,
account = account_info, account = account_info,
@ -85,7 +85,7 @@ internal fun addPseudoAccount(
val log = LogCategory("addPseudoAccount") val log = LogCategory("addPseudoAccount")
log.trace(ex) log.trace(ex)
log.e(ex, "failed.") log.e(ex, "failed.")
showToast(context, ex, "addPseudoAccount failed.") context.showToast(ex, "addPseudoAccount failed.")
} }
return return
} }
@ -100,7 +100,7 @@ fun makeAccountListNonPseudo(
for(a in SavedAccount.loadAccountList(context)) { for(a in SavedAccount.loadAccountList(context)) {
if(a.isPseudo) continue if(a.isPseudo) continue
when(pickup_host) { when(pickup_host) {
null, a.apDomain,a.apiHost -> list_same_host null, a.apDomain, a.apiHost -> list_same_host
else -> list_other_host else -> list_other_host
}.add(a) }.add(a)
} }

View File

@ -1,7 +1,6 @@
package jp.juggler.subwaytooter.action package jp.juggler.subwaytooter.action
import android.app.Dialog import android.app.Dialog
import android.content.Intent
import android.os.Build import android.os.Build
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import jp.juggler.subwaytooter.* import jp.juggler.subwaytooter.*
@ -14,6 +13,7 @@ import jp.juggler.subwaytooter.dialog.LoginForm
import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.LinkHelper import jp.juggler.subwaytooter.util.LinkHelper
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.* import jp.juggler.util.*
object Action_Account { object Action_Account {
@ -57,7 +57,7 @@ object Action_Account {
when(action) { when(action) {
LoginForm.Action.Existing -> if(data is String) { LoginForm.Action.Existing -> if(data is String) {
// ブラウザ用URLが生成された // ブラウザ用URLが生成された
App1.openBrowser(activity, data.toUri()) activity.openBrowser(data.toUri())
dialog.dismissSafe() dialog.dismissSafe()
return return
} }
@ -79,7 +79,7 @@ object Action_Account {
instance, instance,
instanceInfo = data instanceInfo = data
) { a -> ) { a ->
showToast(activity, false, R.string.server_confirmed) activity.showToast(false, R.string.server_confirmed)
val pos = App1.getAppState(activity).column_list.size val pos = App1.getAppState(activity).column_list.size
activity.addColumn(pos, a, ColumnType.LOCAL) activity.addColumn(pos, a, ColumnType.LOCAL)
dialog.dismissSafe() dialog.dismissSafe()
@ -111,7 +111,7 @@ object Action_Account {
} }
override fun onEmptyError() { override fun onEmptyError() {
showToast(activity, true, R.string.token_not_specified) activity.showToast(true, R.string.token_not_specified)
} }
} }
) )
@ -131,7 +131,7 @@ object Action_Account {
.setNeutralButton(R.string.close, null) .setNeutralButton(R.string.close, null)
.show() .show()
} else { } else {
showToast(activity, true, "$errorText ${result.requestInfo}".trim()) activity.showToast(true, "$errorText ${result.requestInfo}".trim())
} }
} }
}) })
@ -284,7 +284,7 @@ object Action_Account {
bSet : Boolean bSet : Boolean
) { ) {
if(access_info.isMisskey) { if(access_info.isMisskey) {
showToast(activity, false, "This feature is not provided on Misskey account.") activity.showToast(false, "This feature is not provided on Misskey account.")
return return
} }
@ -319,10 +319,10 @@ object Action_Account {
result ?: return result ?: return
if(result.error != null) { if(result.error != null) {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} else { } else {
showToast( activity.showToast(
activity, false, when(bSet) { false, when(bSet) {
true -> R.string.endorse_succeeded true -> R.string.endorse_succeeded
else -> R.string.remove_endorse_succeeded else -> R.string.remove_endorse_succeeded
} }

View File

@ -35,7 +35,7 @@ object Action_App {
MutedApp.save(application.name) MutedApp.save(application.name)
App1.getAppState(activity).onMuteUpdated() App1.getAppState(activity).onMuteUpdated()
showToast(activity, false, R.string.app_was_muted) activity.showToast(false, R.string.app_was_muted)
} }
} }

View File

@ -10,32 +10,40 @@ import jp.juggler.subwaytooter.api.TootTaskRunner
import jp.juggler.subwaytooter.api.entity.TootFilter import jp.juggler.subwaytooter.api.entity.TootFilter
import jp.juggler.subwaytooter.dialog.DlgConfirm import jp.juggler.subwaytooter.dialog.DlgConfirm
import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.util.LogCategory
import jp.juggler.util.showToast import jp.juggler.util.showToast
import okhttp3.Request import okhttp3.Request
object Action_Filter { object Action_Filter {
private val log = LogCategory("Action_Filter") // private val log = LogCategory("Action_Filter")
fun delete( activity : ActMain, access_info : SavedAccount,filter: TootFilter ,bConfirmed :Boolean = false){ fun delete(
if(!bConfirmed){ activity : ActMain,
DlgConfirm.openSimple(activity,activity.getString(R.string.filter_delete_confirm, filter.phrase)){ access_info : SavedAccount,
delete(activity,access_info,filter,bConfirmed=true) filter : TootFilter,
bConfirmed : Boolean = false
) {
if(! bConfirmed) {
DlgConfirm.openSimple(
activity,
activity.getString(R.string.filter_delete_confirm, filter.phrase)
) {
delete(activity, access_info, filter, bConfirmed = true)
} }
return return
} }
TootTaskRunner(activity).run(access_info, object : TootTask { TootTaskRunner(activity).run(access_info, object : TootTask {
var filterList : ArrayList<TootFilter>? = null var filterList : ArrayList<TootFilter>? = null
override fun background(client : TootApiClient) : TootApiResult? { override fun background(client : TootApiClient) : TootApiResult? {
var result = client.request("/api/v1/filters/${filter.id}", Request.Builder().delete()) var result =
if( result != null && result.error == null){ client.request("/api/v1/filters/${filter.id}", Request.Builder().delete())
if(result != null && result.error == null) {
result = client.request("/api/v1/filters") result = client.request("/api/v1/filters")
val jsonArray = result?.jsonArray val jsonArray = result?.jsonArray
if( jsonArray != null ) filterList = TootFilter.parseList(jsonArray) if(jsonArray != null) filterList = TootFilter.parseList(jsonArray)
} }
return result return result
} }
@ -44,15 +52,15 @@ object Action_Filter {
if(result == null) return // cancelled. if(result == null) return // cancelled.
val filterList = this.filterList val filterList = this.filterList
if( filterList != null) { if(filterList != null) {
showToast(activity, false, R.string.delete_succeeded) activity.showToast(false, R.string.delete_succeeded)
for(column in App1.getAppState(activity).column_list) { for(column in App1.getAppState(activity).column_list) {
if( column.access_info == access_info ){ if(column.access_info == access_info) {
column.onFilterDeleted(filter,filterList) column.onFilterDeleted(filter, filterList)
} }
} }
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }

View File

@ -1,7 +1,10 @@
package jp.juggler.subwaytooter.action package jp.juggler.subwaytooter.action
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import jp.juggler.subwaytooter.* import jp.juggler.subwaytooter.ActMain
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.ColumnType
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.* import jp.juggler.subwaytooter.api.*
import jp.juggler.subwaytooter.api.entity.* import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.dialog.AccountPicker import jp.juggler.subwaytooter.dialog.AccountPicker
@ -9,8 +12,10 @@ 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.table.UserRelation import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.EmptyCallback import jp.juggler.util.showToast
import jp.juggler.util.* import jp.juggler.util.toFormRequestBody
import jp.juggler.util.toPost
import jp.juggler.util.toPostRequestBuilder
object Action_Follow { object Action_Follow {
@ -22,12 +27,12 @@ object Action_Follow {
bFollow : Boolean = true, bFollow : Boolean = true,
bConfirmMoved : Boolean = false, bConfirmMoved : Boolean = false,
bConfirmed : Boolean = false, bConfirmed : Boolean = false,
callback : EmptyCallback? = null callback : () -> Unit = {}
) { ) {
val who = whoRef.get() val who = whoRef.get()
if(access_info.isMe(who)) { if(access_info.isMe(who)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -73,8 +78,7 @@ object Action_Follow {
R.string.confirm_follow_request_who_from, R.string.confirm_follow_request_who_from,
whoRef.decoded_display_name, whoRef.decoded_display_name,
AcctColor.getNickname(access_info) AcctColor.getNickname(access_info)
) ), object : DlgConfirm.Callback {
, object : DlgConfirm.Callback {
override fun onOK() { override fun onOK() {
follow( follow(
@ -242,8 +246,8 @@ object Action_Follow {
} else { } else {
client.request( client.request(
"/api/v1/accounts/${userId}/${if(bFollow) "follow" else "unfollow"}" "/api/v1/accounts/${userId}/${if(bFollow) "follow" else "unfollow"}",
, "".toFormRequestBody().toPost() "".toFormRequestBody().toPost()
)?.also { result -> )?.also { result ->
val newRelation = parseItem(::TootRelationShip, parser, result.jsonObject) val newRelation = parseItem(::TootRelationShip, parser, result.jsonObject)
if(newRelation != null) { if(newRelation != null) {
@ -262,21 +266,21 @@ object Action_Follow {
if(bFollow && relation.getRequested(who)) { if(bFollow && relation.getRequested(who)) {
// 鍵付きアカウントにフォローリクエストを申請した状態 // 鍵付きアカウントにフォローリクエストを申請した状態
showToast(activity, false, R.string.follow_requested) activity.showToast(false, R.string.follow_requested)
} else if(! bFollow && relation.getRequested(who)) { } else if(! bFollow && relation.getRequested(who)) {
showToast(activity, false, R.string.follow_request_cant_remove_by_sender) activity.showToast(false, R.string.follow_request_cant_remove_by_sender)
} else { } else {
// ローカル操作成功、もしくはリモートフォロー成功 // ローカル操作成功、もしくはリモートフォロー成功
if(callback != null) callback() callback()
} }
activity.showColumnMatchAccount(access_info) activity.showColumnMatchAccount(access_info)
} else if(bFollow && who.locked && (result.response?.code ?: - 1) == 422) { } else if(bFollow && who.locked && (result.response?.code ?: - 1) == 422) {
showToast(activity, false, R.string.cant_follow_locked_user) activity.showToast(false, R.string.cant_follow_locked_user)
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
@ -289,7 +293,7 @@ object Action_Follow {
access_info : SavedAccount, access_info : SavedAccount,
whoRef : TootAccountRef, whoRef : TootAccountRef,
bConfirmed : Boolean = false, bConfirmed : Boolean = false,
callback : EmptyCallback? = null callback : () -> Unit = {}
) { ) {
if(! access_info.isMisskey) { if(! access_info.isMisskey) {
follow( follow(
@ -307,7 +311,7 @@ object Action_Follow {
val who = whoRef.get() val who = whoRef.get()
if(access_info.isMe(who)) { if(access_info.isMe(who)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -350,8 +354,7 @@ object Action_Follow {
} }
client.request( client.request(
"/api/following/requests/cancel" "/api/following/requests/cancel", access_info.putMisskeyApiToken().apply {
, access_info.putMisskeyApiToken().apply {
put("userId", userId) put("userId", userId)
} }
.toPostRequestBuilder() .toPostRequestBuilder()
@ -375,16 +378,15 @@ object Action_Follow {
val relation = this.relation val relation = this.relation
if(relation != null) { if(relation != null) {
// ローカル操作成功、もしくはリモートフォロー成功 // ローカル操作成功、もしくはリモートフォロー成功
if(callback != null) callback() callback()
activity.showColumnMatchAccount(access_info) activity.showColumnMatchAccount(access_info)
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })
} }
// acct で指定したユーザをリモートフォローする // acct で指定したユーザをリモートフォローする
fun followRemote( fun followRemote(
@ -393,11 +395,11 @@ object Action_Follow {
acct : Acct, acct : Acct,
locked : Boolean, locked : Boolean,
bConfirmed : Boolean = false, bConfirmed : Boolean = false,
callback : EmptyCallback? = null callback : () -> Unit = {}
) { ) {
if(access_info.isMe(acct)) { if(access_info.isMe(acct)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -499,8 +501,7 @@ object Action_Follow {
} }
} else { } else {
client.request( client.request(
"/api/v1/accounts/${userId}/follow" "/api/v1/accounts/${userId}/follow", "".toFormRequestBody().toPost()
, "".toFormRequestBody().toPost()
)?.also { result -> )?.also { result ->
val newRelation = parseItem(::TootRelationShip, parser, result.jsonObject) val newRelation = parseItem(::TootRelationShip, parser, result.jsonObject)
if(newRelation != null) { if(newRelation != null) {
@ -515,15 +516,12 @@ object Action_Follow {
if(result == null) return // cancelled. if(result == null) return // cancelled.
if(relation != null) { if(relation != null) {
callback()
activity.showColumnMatchAccount(access_info) activity.showColumnMatchAccount(access_info)
if(callback != null) callback()
} else if(locked && (result.response?.code ?: - 1) == 422) { } else if(locked && (result.response?.code ?: - 1) == 422) {
showToast(activity, false, R.string.cant_follow_locked_user) activity.showToast(false, R.string.cant_follow_locked_user)
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
@ -590,7 +588,7 @@ object Action_Follow {
) { ) {
val who = whoRef.get() val who = whoRef.get()
if(access_info.isMe(who)) { if(access_info.isMe(who)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -647,14 +645,13 @@ object Action_Follow {
} }
} }
showToast( activity.showToast(
activity,
false, false,
if(bAllow) R.string.follow_request_authorized else R.string.follow_request_rejected, if(bAllow) R.string.follow_request_authorized else R.string.follow_request_rejected,
whoRef.decoded_display_name whoRef.decoded_display_name
) )
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })

View File

@ -1,7 +1,6 @@
package jp.juggler.subwaytooter.action package jp.juggler.subwaytooter.action
import jp.juggler.subwaytooter.ActMain import jp.juggler.subwaytooter.ActMain
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.ColumnType import jp.juggler.subwaytooter.ColumnType
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.entity.Acct import jp.juggler.subwaytooter.api.entity.Acct
@ -10,6 +9,7 @@ import jp.juggler.subwaytooter.dialog.ActionsDialog
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.matchHost import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.subwaytooter.util.openCustomTab
import jp.juggler.util.encodePercent import jp.juggler.util.encodePercent
import java.util.* import java.util.*
@ -23,7 +23,7 @@ object Action_HashTag {
host : Host, host : Host,
tag_without_sharp : String, tag_without_sharp : String,
tag_list : ArrayList<String>?, tag_list : ArrayList<String>?,
whoAcct: Acct? whoAcct : Acct?
) { ) {
val tag_with_sharp = "#$tag_without_sharp" val tag_with_sharp = "#$tag_without_sharp"
@ -40,12 +40,18 @@ object Action_HashTag {
// https://mastodon.juggler.jp/@tateisu/101865456016473337 // https://mastodon.juggler.jp/@tateisu/101865456016473337
// 一時的に使えなくする // 一時的に使えなくする
if( whoAcct != null ){ if(whoAcct != null) {
d.addAction(AcctColor.getStringWithNickname(activity, R.string.open_hashtag_from_account ,whoAcct)) { d.addAction(
AcctColor.getStringWithNickname(
activity,
R.string.open_hashtag_from_account,
whoAcct
)
) {
timelineOtherInstance( timelineOtherInstance(
activity, activity,
pos, pos,
"https://${whoAcct.host?.ascii}/@${whoAcct.username}/tagged/${ tag_without_sharp.encodePercent()}", "https://${whoAcct.host?.ascii}/@${whoAcct.username}/tagged/${tag_without_sharp.encodePercent()}",
host, host,
tag_without_sharp, tag_without_sharp,
whoAcct whoAcct
@ -54,18 +60,10 @@ object Action_HashTag {
} }
d.addAction(activity.getString(R.string.open_in_browser)) { d.addAction(activity.getString(R.string.open_in_browser))
App1.openCustomTab( { activity.openCustomTab(url) }
activity, .addAction(activity.getString(R.string.quote_hashtag_of, tag_with_sharp))
url { Action_Account.openPost(activity, "$tag_with_sharp ") }
)
}
.addAction(
activity.getString(
R.string.quote_hashtag_of,
tag_with_sharp
)
) { Action_Account.openPost(activity, "$tag_with_sharp ") }
if(tag_list != null && tag_list.size > 1) { if(tag_list != null && tag_list.size > 1) {
@ -94,10 +92,16 @@ object Action_HashTag {
tag_without_sharp : String, tag_without_sharp : String,
acctAscii : String? = null acctAscii : String? = null
) { ) {
if( acctAscii == null) { if(acctAscii == null) {
activity.addColumn(pos, access_info, ColumnType.HASHTAG, tag_without_sharp) activity.addColumn(pos, access_info, ColumnType.HASHTAG, tag_without_sharp)
}else { } else {
activity.addColumn(pos, access_info, ColumnType.HASHTAG_FROM_ACCT, tag_without_sharp,acctAscii) activity.addColumn(
pos,
access_info,
ColumnType.HASHTAG_FROM_ACCT,
tag_without_sharp,
acctAscii
)
} }
} }
@ -108,7 +112,7 @@ object Action_HashTag {
url : String, url : String,
host : Host, host : Host,
tag_without_sharp : String, tag_without_sharp : String,
acct :Acct? = null acct : Acct? = null
) { ) {
val dialog = ActionsDialog() val dialog = ActionsDialog()
@ -124,37 +128,36 @@ object Action_HashTag {
val list_original_pseudo = ArrayList<SavedAccount>() val list_original_pseudo = ArrayList<SavedAccount>()
val list_other = ArrayList<SavedAccount>() val list_other = ArrayList<SavedAccount>()
for(a in account_list) { for(a in account_list) {
if( acct == null){ if(acct == null) {
when { when {
!a.matchHost(host) -> list_other.add(a) ! a.matchHost(host) -> list_other.add(a)
a.isPseudo -> list_original_pseudo.add(a) a.isPseudo -> list_original_pseudo.add(a)
else -> list_original.add(a) else -> list_original.add(a)
} }
}else{ } else {
when { when {
// acctからidを取得できない // acctからidを取得できない
a.isPseudo -> { a.isPseudo -> {
} }
// ミスキーのアカウント別タグTLは未対応 // ミスキーのアカウント別タグTLは未対応
a.isMisskey -> { a.isMisskey -> {
} }
!a.matchHost(host) -> list_other.add(a) ! a.matchHost(host) -> list_other.add(a)
else -> list_original.add(a) else -> list_original.add(a)
} }
} }
} }
// ブラウザで表示する // ブラウザで表示する
dialog.addAction(activity.getString(R.string.open_web_on_host, host)) { dialog.addAction(activity.getString(R.string.open_web_on_host, host))
App1.openCustomTab(activity,url) { activity.openCustomTab(url) }
}
// 同タンスのアカウントがない場合は疑似アカウントを作成して開く // 同タンスのアカウントがない場合は疑似アカウントを作成して開く
// ただし疑似アカウントではアカウントの同期ができないため、特定ユーザのタグTLは読めない) // ただし疑似アカウントではアカウントの同期ができないため、特定ユーザのタグTLは読めない)
if( acct == null && list_original.isEmpty() && list_original_pseudo.isEmpty()) { if(acct == null && list_original.isEmpty() && list_original_pseudo.isEmpty()) {
dialog.addAction(activity.getString(R.string.open_in_pseudo_account, "?@$host")) { dialog.addAction(activity.getString(R.string.open_in_pseudo_account, "?@$host")) {
addPseudoAccount(activity, host) { sa -> addPseudoAccount(activity, host) { sa ->
timeline(activity, pos, sa, tag_without_sharp) timeline(activity, pos, sa, tag_without_sharp)
@ -171,7 +174,7 @@ object Action_HashTag {
a.acct a.acct
) )
) )
{ timeline(activity, pos, a, tag_without_sharp,acct?.ascii) } { timeline(activity, pos, a, tag_without_sharp, acct?.ascii) }
} }
for(a in list_original_pseudo) { for(a in list_original_pseudo) {
dialog.addAction( dialog.addAction(
@ -181,7 +184,7 @@ object Action_HashTag {
a.acct a.acct
) )
) )
{ timeline(activity, pos, a, tag_without_sharp,acct?.ascii) } { timeline(activity, pos, a, tag_without_sharp, acct?.ascii) }
} }
for(a in list_other) { for(a in list_other) {
dialog.addAction( dialog.addAction(
@ -191,7 +194,7 @@ object Action_HashTag {
a.acct a.acct
) )
) )
{ timeline(activity, pos, a, tag_without_sharp,acct?.ascii) } { timeline(activity, pos, a, tag_without_sharp, acct?.ascii) }
} }
dialog.show(activity, "#$tag_without_sharp") dialog.show(activity, "#$tag_without_sharp")

View File

@ -9,6 +9,7 @@ import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.dialog.AccountPicker import jp.juggler.subwaytooter.dialog.AccountPicker
import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.matchHost import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.* import jp.juggler.util.*
import java.util.* import java.util.*
@ -35,7 +36,7 @@ object Action_Instance {
override fun handleResult(result : TootApiResult?) { override fun handleResult(result : TootApiResult?) {
result ?: return // cancelled. result ?: return // cancelled.
when(val ti = targetInstance) { when(val ti = targetInstance) {
null -> showToast(activity, true, result.error) null -> activity.showToast(true, result.error)
else -> profileDirectory(activity, accessInfo, host, ti, pos) else -> profileDirectory(activity, accessInfo, host, ti, pos)
} }
} }
@ -43,11 +44,11 @@ object Action_Instance {
// Misskey非対応 // Misskey非対応
instance.instanceType == TootInstance.InstanceType.Misskey -> instance.instanceType == TootInstance.InstanceType.Misskey ->
showToast(activity, false, R.string.profile_directory_not_supported_on_misskey) activity.showToast(false, R.string.profile_directory_not_supported_on_misskey)
// バージョンが足りないならWebページを開く // バージョンが足りないならWebページを開く
! instance.versionGE(TootInstance.VERSION_3_0_0_rc1) -> ! instance.versionGE(TootInstance.VERSION_3_0_0_rc1) ->
App1.openBrowser(activity, "https://${host.ascii}/explore") activity.openBrowser("https://${host.ascii}/explore")
// ホスト名部分が一致するならそのアカウントで開く // ホスト名部分が一致するならそのアカウントで開く
accessInfo.matchHost(host) -> accessInfo.matchHost(host) ->
@ -123,10 +124,10 @@ object Action_Instance {
fun timelineDomain( fun timelineDomain(
activity : ActMain, activity : ActMain,
pos : Int, pos : Int,
accessInfo: SavedAccount, accessInfo : SavedAccount,
host : Host host : Host
){ ) {
activity.addColumn(pos, accessInfo, ColumnType.DOMAIN_TIMELINE,host) activity.addColumn(pos, accessInfo, ColumnType.DOMAIN_TIMELINE, host)
} }
// 指定タンスのローカルタイムラインを開く // 指定タンスのローカルタイムラインを開く
@ -167,7 +168,7 @@ object Action_Instance {
) { ) {
if(access_info.matchHost(domain)) { if(access_info.matchHost(domain)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -190,14 +191,13 @@ object Action_Instance {
column.onDomainBlockChanged(access_info, domain, bBlock) column.onDomainBlockChanged(access_info, domain, bBlock)
} }
showToast( activity.showToast(
activity,
false, false,
if(bBlock) R.string.block_succeeded else R.string.unblock_succeeded if(bBlock) R.string.block_succeeded else R.string.unblock_succeeded
) )
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })
@ -235,7 +235,7 @@ object Action_Instance {
if(localStatus != null) { if(localStatus != null) {
timelinePublicAround2(activity, access_info, pos, localStatus.id, type) timelinePublicAround2(activity, access_info, pos, localStatus.id, type)
} else { } else {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} }
} }
}) })
@ -298,7 +298,7 @@ object Action_Instance {
return return
} }
showToast(activity, false, R.string.missing_available_account) activity.showToast(false, R.string.missing_available_account)
} }
} }

View File

@ -15,6 +15,7 @@ import okhttp3.Request
object Action_List { object Action_List {
fun interface CreateCallback { fun interface CreateCallback {
fun onCreated(list : TootList) fun onCreated(list : TootList)
} }
@ -65,11 +66,11 @@ object Action_List {
column.onListListUpdated(access_info) column.onListListUpdated(access_info)
} }
showToast(activity, false, R.string.list_created) activity.showToast(false, R.string.list_created)
callback?.onCreated(list) callback?.onCreated(list)
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })
@ -85,8 +86,7 @@ object Action_List {
if(! bConfirmed) { if(! bConfirmed) {
DlgConfirm.openSimple( DlgConfirm.openSimple(
activity activity, activity.getString(R.string.list_delete_confirm, list.title)
, activity.getString(R.string.list_delete_confirm, list.title)
) { ) {
delete(activity, access_info, list, bConfirmed = true) delete(activity, access_info, list, bConfirmed = true)
} }
@ -121,10 +121,10 @@ object Action_List {
column.onListListUpdated(access_info) column.onListListUpdated(access_info)
} }
showToast(activity, false, R.string.delete_succeeded) activity.showToast(false, R.string.delete_succeeded)
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })
@ -142,7 +142,7 @@ object Action_List {
item.title, item.title,
callback = object : DlgTextInput.Callback { callback = object : DlgTextInput.Callback {
override fun onEmptyError() { override fun onEmptyError() {
showToast(activity, false, R.string.list_name_empty) activity.showToast(false, R.string.list_name_empty)
} }
override fun onOK(dialog : Dialog, text : String) { override fun onOK(dialog : Dialog, text : String) {
@ -191,7 +191,7 @@ object Action_List {
} }
dialog.dismissSafe() dialog.dismissSafe()
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })

View File

@ -17,6 +17,7 @@ object Action_ListMember {
private val reFollowError = "follow".asciiPattern(Pattern.CASE_INSENSITIVE) private val reFollowError = "follow".asciiPattern(Pattern.CASE_INSENSITIVE)
fun interface Callback { fun interface Callback {
fun onListMemberUpdated(willRegistered : Boolean, bSuccess : Boolean) fun onListMemberUpdated(willRegistered : Boolean, bSuccess : Boolean)
} }
@ -51,13 +52,13 @@ object Action_ListMember {
} else { } else {
val isMe = access_info.isMe(local_who) val isMe = access_info.isMe(local_who)
if( isMe ) { if(isMe) {
val (ti, ri) = TootInstance.get(client) val (ti, ri) = TootInstance.get(client)
if(ti == null) return ri if(ti == null) return ri
if(! ti.versionGE(TootInstance.VERSION_3_1_0_rc1)) { if(! ti.versionGE(TootInstance.VERSION_3_1_0_rc1)) {
return TootApiResult(activity.getString(R.string.it_is_you)) return TootApiResult(activity.getString(R.string.it_is_you))
} }
}else if(bFollow) { } else if(bFollow) {
// リモートユーザの解決 // リモートユーザの解決
if(! access_info.isLocalUser(local_who)) { if(! access_info.isLocalUser(local_who)) {
val (r2, ar) = client.syncAccountByAcct(access_info, local_who.acct) val (r2, ar) = client.syncAccountByAcct(access_info, local_who.acct)
@ -119,7 +120,7 @@ object Action_ListMember {
// フォロー状態の更新を表示に反映させる // フォロー状態の更新を表示に反映させる
if(bFollow) activity.showColumnMatchAccount(access_info) if(bFollow) activity.showColumnMatchAccount(access_info)
showToast(activity, false, R.string.list_member_added) activity.showToast(false, R.string.list_member_added)
bSuccess = true bSuccess = true
@ -159,7 +160,7 @@ object Action_ListMember {
return return
} }
showToast(activity, true, error) activity.showToast(true, error)
} }
} finally { } finally {
@ -209,12 +210,12 @@ object Action_ListMember {
column.onListMemberUpdated(access_info, list_id, local_who, false) column.onListMemberUpdated(access_info, list_id, local_who, false)
} }
showToast(activity, false, R.string.delete_succeeded) activity.showToast(false, R.string.delete_succeeded)
bSuccess = true bSuccess = true
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} finally { } finally {
callback?.onListMemberUpdated(false, bSuccess) callback?.onListMemberUpdated(false, bSuccess)

View File

@ -44,13 +44,13 @@ object Action_Notification {
if(result.jsonObject != null) { if(result.jsonObject != null) {
// ok. api have return empty object. // ok. api have return empty object.
for(column in App1.getAppState(activity).column_list) { for(column in App1.getAppState(activity).column_list) {
if(column.isNotificationColumn && column.access_info == target_account ) { if(column.isNotificationColumn && column.access_info == target_account) {
column.removeNotifications() column.removeNotifications()
} }
} }
showToast(activity, false, R.string.delete_succeeded) activity.showToast(false, R.string.delete_succeeded)
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
@ -92,9 +92,9 @@ object Action_Notification {
for(column in App1.getAppState(activity).column_list) { for(column in App1.getAppState(activity).column_list) {
column.removeNotificationOne(access_info, notification) column.removeNotificationOne(access_info, notification)
} }
showToast(activity, true, R.string.delete_succeeded) activity.showToast(true, R.string.delete_succeeded)
} else { } else {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} }
} }

View File

@ -9,9 +9,9 @@ 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.SavedAccountCallback import jp.juggler.subwaytooter.util.SavedAccountCallback
import jp.juggler.subwaytooter.util.matchHost import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.subwaytooter.util.openCustomTab
import jp.juggler.util.* import jp.juggler.util.*
import okhttp3.Request import okhttp3.Request
import java.util.* import java.util.*
@ -56,12 +56,12 @@ object Action_Toot {
access_info : SavedAccount, access_info : SavedAccount,
arg_status : TootStatus, arg_status : TootStatus,
nCrossAccountMode : Int, nCrossAccountMode : Int,
callback : EmptyCallback?, callback : () -> Unit,
bSet : Boolean = true, bSet : Boolean = true,
bConfirmed : Boolean = false bConfirmed : Boolean = false
) { ) {
if(App1.getAppState(activity).isBusyFav(access_info, arg_status)) { if(App1.getAppState(activity).isBusyFav(access_info, arg_status)) {
showToast(activity, false, R.string.wait_previous_operation) activity.showToast(false, R.string.wait_previous_operation)
return return
} }
@ -209,11 +209,10 @@ object Action_Toot {
true true
} }
} }
if(callback != null) callback() callback()
} }
else -> showToast(activity, true, result.error) else -> activity.showToast(true, result.error)
} }
// 結果に関わらず、更新中状態から復帰させる // 結果に関わらず、更新中状態から復帰させる
activity.showColumnMatchAccount(access_info) activity.showColumnMatchAccount(access_info)
@ -256,16 +255,16 @@ object Action_Toot {
access_info : SavedAccount, access_info : SavedAccount,
arg_status : TootStatus, arg_status : TootStatus,
nCrossAccountMode : Int, nCrossAccountMode : Int,
callback : EmptyCallback?, callback : () -> Unit,
bSet : Boolean = true, bSet : Boolean = true,
bConfirmed : Boolean = false bConfirmed : Boolean = false
) { ) {
if(App1.getAppState(activity).isBusyFav(access_info, arg_status)) { if(App1.getAppState(activity).isBusyFav(access_info, arg_status)) {
showToast(activity, false, R.string.wait_previous_operation) activity.showToast(false, R.string.wait_previous_operation)
return return
} }
if(access_info.isMisskey) { if(access_info.isMisskey) {
showToast(activity, false, R.string.misskey_account_not_supported) activity.showToast(false, R.string.misskey_account_not_supported)
return return
} }
@ -344,10 +343,10 @@ object Action_Toot {
true true
} }
} }
if(callback != null) callback() callback()
} }
else -> showToast(activity, true, result.error) else -> activity.showToast(true, result.error)
} }
// 結果に関わらず、更新中状態から復帰させる // 結果に関わらず、更新中状態から復帰させる
@ -377,7 +376,7 @@ object Action_Toot {
if(a.acct == status_owner) list.add(a) if(a.acct == status_owner) list.add(a)
} }
if(list.isEmpty()) { if(list.isEmpty()) {
showToast(activity, false, R.string.boost_private_toot_not_allowed) activity.showToast(false, R.string.boost_private_toot_not_allowed)
return return
} }
AccountPicker.pick( AccountPicker.pick(
@ -393,7 +392,7 @@ object Action_Toot {
status, status,
status_owner, status_owner,
calcCrossAccountMode(timeline_account, action_account), calcCrossAccountMode(timeline_account, action_account),
activity.boost_complete_callback callback = activity.boost_complete_callback
) )
} }
} else { } else {
@ -410,7 +409,7 @@ object Action_Toot {
status, status,
status_owner, status_owner,
calcCrossAccountMode(timeline_account, action_account), calcCrossAccountMode(timeline_account, action_account),
activity.boost_complete_callback callback = activity.boost_complete_callback
) )
} }
} }
@ -422,15 +421,15 @@ object Action_Toot {
arg_status : TootStatus, arg_status : TootStatus,
status_owner : Acct, status_owner : Acct,
nCrossAccountMode : Int, nCrossAccountMode : Int,
callback : EmptyCallback?,
bSet : Boolean = true, bSet : Boolean = true,
bConfirmed : Boolean = false, bConfirmed : Boolean = false,
visibility : TootVisibility? = null visibility : TootVisibility? = null,
callback : () -> Unit
) { ) {
// アカウントからステータスにブースト操作を行っているなら、何もしない // アカウントからステータスにブースト操作を行っているなら、何もしない
if(App1.getAppState(activity).isBusyBoost(access_info, arg_status)) { if(App1.getAppState(activity).isBusyBoost(access_info, arg_status)) {
showToast(activity, false, R.string.wait_previous_operation) activity.showToast(false, R.string.wait_previous_operation)
return return
} }
@ -438,7 +437,7 @@ object Action_Toot {
val isPrivateToot = access_info.isMastodon && val isPrivateToot = access_info.isMastodon &&
arg_status.visibility == TootVisibility.PrivateFollowers arg_status.visibility == TootVisibility.PrivateFollowers
if(isPrivateToot && access_info.acct != status_owner) { if(isPrivateToot && access_info.acct != status_owner) {
showToast(activity, false, R.string.boost_private_toot_not_allowed) activity.showToast(false, R.string.boost_private_toot_not_allowed)
return return
} }
@ -463,10 +462,10 @@ object Action_Toot {
arg_status, arg_status,
status_owner, status_owner,
nCrossAccountMode, nCrossAccountMode,
callback,
bSet = bSet, bSet = bSet,
bConfirmed = true, bConfirmed = true,
visibility = visibility visibility = visibility,
callback = callback,
) )
} }
@ -606,7 +605,7 @@ object Action_Toot {
true true
} }
} }
if(callback != null) callback() callback()
} }
new_status != null -> { new_status != null -> {
@ -652,10 +651,10 @@ object Action_Toot {
true true
} }
} }
if(callback != null) callback() callback()
} }
else -> showToast(activity, true, result.error) else -> activity.showToast(true, result.error)
} }
// 結果に関わらず、更新中状態から復帰させる // 結果に関わらず、更新中状態から復帰させる
@ -694,12 +693,12 @@ object Action_Toot {
if(result == null) return // cancelled. if(result == null) return // cancelled.
if(result.jsonObject != null) { if(result.jsonObject != null) {
showToast(activity, false, R.string.delete_succeeded) activity.showToast(false, R.string.delete_succeeded)
for(column in App1.getAppState(activity).column_list) { for(column in App1.getAppState(activity).column_list) {
column.onStatusRemoved(access_info.apDomain, status_id) column.onStatusRemoved(access_info.apDomain, status_id)
} }
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
@ -820,12 +819,8 @@ object Action_Toot {
val host_original = Host.parse(url.toUri().authority ?: "") val host_original = Host.parse(url.toUri().authority ?: "")
// 選択肢:ブラウザで表示する // 選択肢:ブラウザで表示する
dialog.addAction( dialog.addAction(activity.getString(R.string.open_web_on_host, host_original.pretty))
activity.getString( { activity.openCustomTab(url) }
R.string.open_web_on_host,
host_original.pretty
)
) { App1.openCustomTab(activity, url) }
// トゥートの投稿元タンスにあるアカウント // トゥートの投稿元タンスにあるアカウント
val local_account_list = ArrayList<SavedAccount>() val local_account_list = ArrayList<SavedAccount>()
@ -962,7 +957,7 @@ object Action_Toot {
if(local_status_id != null) { if(local_status_id != null) {
conversationLocal(activity, pos, access_info, local_status_id) conversationLocal(activity, pos, access_info, local_status_id)
} else { } else {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} }
} }
}) })
@ -993,9 +988,9 @@ object Action_Toot {
val status = tmp val status = tmp
val replyId = status?.in_reply_to_id val replyId = status?.in_reply_to_id
when { when {
status == null -> showToast(activity, true, result.error ?: "?") status == null -> activity.showToast(true, result.error ?: "?")
replyId == null -> showToast( replyId == null -> activity.showToast(
activity, true, true,
"showReplyTootsearch: in_reply_to_id is null" "showReplyTootsearch: in_reply_to_id is null"
) )
else -> conversationLocal(activity, pos, a, replyId) else -> conversationLocal(activity, pos, a, replyId)
@ -1096,7 +1091,7 @@ object Action_Toot {
} }
} }
else -> showToast(activity, true, result.error) else -> activity.showToast(true, result.error)
} }
// 結果に関わらず、更新中状態から復帰させる // 結果に関わらず、更新中状態から復帰させる
@ -1153,7 +1148,7 @@ object Action_Toot {
if(ls != null) { if(ls != null) {
reply(activity, access_info, ls, quote = quote) reply(activity, access_info, ls, quote = quote)
} else { } else {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} }
} }
}) })
@ -1252,7 +1247,7 @@ object Action_Toot {
return return
} }
val error = result.error ?: "(no information)" val error = result.error ?: "(no information)"
showToast(activity, true, activity.getString(R.string.cant_sync_toot) + " : $error") activity.showToast(true, activity.getString(R.string.cant_sync_toot) + " : $error")
} }
}) })
} }
@ -1293,13 +1288,12 @@ object Action_Toot {
} }
} }
} }
showToast( activity.showToast(
activity,
true, true,
if(bMute) R.string.mute_succeeded else R.string.unmute_succeeded if(bMute) R.string.mute_succeeded else R.string.unmute_succeeded
) )
} else { } else {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} }
} }
}) })
@ -1311,7 +1305,7 @@ object Action_Toot {
arg_status : TootStatus, arg_status : TootStatus,
status_owner_acct : Acct, status_owner_acct : Acct,
nCrossAccountMode : Int, nCrossAccountMode : Int,
callback : EmptyCallback?, callback : () -> Unit,
bSet : Boolean = true, bSet : Boolean = true,
code : String? = null code : String? = null
) { ) {
@ -1319,7 +1313,7 @@ object Action_Toot {
// 自分の投稿にはリアクション出来ない // 自分の投稿にはリアクション出来ない
if(access_info.acct == status_owner_acct) { if(access_info.acct == status_owner_acct) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -1404,11 +1398,11 @@ object Action_Toot {
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(activity, false, error) activity.showToast(false, error)
return return
} }
if(callback != null) callback() callback()
} }
}) })
} }
@ -1481,7 +1475,7 @@ object Action_Toot {
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(activity, false, error) activity.showToast(false, error)
return return
} }
@ -1512,7 +1506,7 @@ object Action_Toot {
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(activity, false, error) activity.showToast(false, error)
return return
} }

View File

@ -18,6 +18,7 @@ import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.TootApiResultCallback import jp.juggler.subwaytooter.util.TootApiResultCallback
import jp.juggler.subwaytooter.util.matchHost import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.subwaytooter.util.openCustomTab
import jp.juggler.util.* import jp.juggler.util.*
import okhttp3.Request import okhttp3.Request
@ -35,7 +36,7 @@ object Action_User {
val whoAcct = whoArg.acct val whoAcct = whoArg.acct
if(access_info.isMe(whoAcct)) { if(access_info.isMe(whoAcct)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -56,7 +57,7 @@ object Action_User {
TootApiResult() TootApiResult()
} }
val whoId = if(access_info.matchHost(whoAccessInfo) ) { val whoId = if(access_info.matchHost(whoAccessInfo)) {
whoArg.id whoArg.id
} else { } else {
val (result, accountRef) = client.syncAccountByAcct(access_info, whoAcct) val (result, accountRef) = client.syncAccountByAcct(access_info, whoAcct)
@ -124,7 +125,7 @@ object Action_User {
if(relation != null && whoId != null) { if(relation != null && whoId != null) {
// 未確認だが、自分をミュートしようとするとリクエストは成功するがレスポンス中のmutingはfalseになるはず // 未確認だが、自分をミュートしようとするとリクエストは成功するがレスポンス中のmutingはfalseになるはず
if(bMute && ! relation.muting) { if(bMute && ! relation.muting) {
showToast(activity, false, R.string.not_muted) activity.showToast(false, R.string.not_muted)
return return
} }
@ -163,14 +164,13 @@ object Action_User {
} }
} }
showToast( activity.showToast(
activity,
false, false,
if(relation.muting) R.string.mute_succeeded else R.string.unmute_succeeded if(relation.muting) R.string.mute_succeeded else R.string.unmute_succeeded
) )
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })
@ -220,7 +220,11 @@ object Action_User {
.show() .show()
} }
fun muteFromAnotherAccount(activity : ActMain, who : TootAccount,whoAccessInfo : SavedAccount) { fun muteFromAnotherAccount(
activity : ActMain,
who : TootAccount,
whoAccessInfo : SavedAccount
) {
AccountPicker.pick( AccountPicker.pick(
activity, activity,
bAllowPseudo = false, bAllowPseudo = false,
@ -228,7 +232,7 @@ object Action_User {
message = activity.getString(R.string.account_picker_mute, who.acct.pretty), message = activity.getString(R.string.account_picker_mute, who.acct.pretty),
accountListArg = makeAccountListNonPseudo(activity, who.apDomain) accountListArg = makeAccountListNonPseudo(activity, who.apDomain)
) { ai -> ) { ai ->
muteConfirm(activity, ai, who,whoAccessInfo) muteConfirm(activity, ai, who, whoAccessInfo)
} }
} }
@ -243,7 +247,7 @@ object Action_User {
val whoAcct = whoArg.acct val whoAcct = whoArg.acct
if(access_info.isMe(whoAcct)) { if(access_info.isMe(whoAcct)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -264,7 +268,7 @@ object Action_User {
TootApiResult() TootApiResult()
} }
val whoId = if(access_info.matchHost(whoAccessInfo) ) { val whoId = if(access_info.matchHost(whoAccessInfo)) {
whoArg.id whoArg.id
} else { } else {
val (result, accountRef) = client.syncAccountByAcct(access_info, whoAcct) val (result, accountRef) = client.syncAccountByAcct(access_info, whoAcct)
@ -334,7 +338,7 @@ object Action_User {
// 自分をブロックしようとすると、blocking==falseで帰ってくる // 自分をブロックしようとすると、blocking==falseで帰ってくる
if(bBlock && ! relation.blocking) { if(bBlock && ! relation.blocking) {
showToast(activity, false, R.string.not_blocked) activity.showToast(false, R.string.not_blocked)
return return
} }
@ -377,8 +381,7 @@ object Action_User {
} }
} }
showToast( activity.showToast(
activity,
false, false,
if(relation.blocking) if(relation.blocking)
R.string.block_succeeded R.string.block_succeeded
@ -386,7 +389,7 @@ object Action_User {
R.string.unblock_succeeded R.string.unblock_succeeded
) )
} else { } else {
showToast(activity, false, result.error) activity.showToast(false, result.error)
} }
} }
}) })
@ -464,9 +467,9 @@ object Action_User {
when(val who = this.who) { when(val who = this.who) {
null -> { null -> {
showToast(activity, true, result.error) activity.showToast(true, result.error)
// 仕方ないのでchrome tab で開く // 仕方ないのでchrome tab で開く
App1.openCustomTab(activity, who_url) activity.openCustomTab(who_url)
} }
else -> activity.addColumn(pos, access_info, ColumnType.PROFILE, who.id) else -> activity.addColumn(pos, access_info, ColumnType.PROFILE, who.id)
@ -550,7 +553,7 @@ object Action_User {
when(val who = this.who) { when(val who = this.who) {
null -> { null -> {
// ダメならchromeで開く // ダメならchromeで開く
App1.openCustomTab(activity, url) activity.openCustomTab(url)
} }
else -> profileLocal(activity, pos, access_info, who) else -> profileLocal(activity, pos, access_info, who)
@ -570,7 +573,7 @@ object Action_User {
if(! SavedAccount.hasRealAccount()) { if(! SavedAccount.hasRealAccount()) {
// 疑似アカウントしか登録されていない // 疑似アカウントしか登録されていない
// chrome tab で開く // chrome tab で開く
App1.openCustomTab(activity, original_url) activity.openCustomTab(original_url)
} else { } else {
AccountPicker.pick( AccountPicker.pick(
activity, activity,
@ -599,7 +602,7 @@ object Action_User {
b.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp) b.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
b.setOnClickListener { b.setOnClickListener {
App1.openCustomTab(activity, original_url) activity.openCustomTab(original_url)
} }
ll.addView(b, 0) ll.addView(b, 0)
} }
@ -636,7 +639,7 @@ object Action_User {
onReportComplete : TootApiResultCallback onReportComplete : TootApiResultCallback
) { ) {
if(access_info.isMe(who)) { if(access_info.isMe(who)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -663,9 +666,9 @@ object Action_User {
if(result.jsonObject != null) { if(result.jsonObject != null) {
onReportComplete(result) onReportComplete(result)
showToast(activity, false, R.string.report_completed) activity.showToast(false, R.string.report_completed)
} else { } else {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} }
} }
}) })
@ -676,7 +679,7 @@ object Action_User {
activity : ActMain, access_info : SavedAccount, who : TootAccount, bShow : Boolean activity : ActMain, access_info : SavedAccount, who : TootAccount, bShow : Boolean
) { ) {
if(access_info.isMe(who)) { if(access_info.isMe(who)) {
showToast(activity, false, R.string.it_is_you) activity.showToast(false, R.string.it_is_you)
return return
} }
@ -716,9 +719,9 @@ object Action_User {
if(result == null) return // cancelled. if(result == null) return // cancelled.
if(relation != null) { if(relation != null) {
showToast(activity, true, R.string.operation_succeeded) activity.showToast(true, R.string.operation_succeeded)
} else { } else {
showToast(activity, true, result.error) activity.showToast(true, result.error)
} }
} }
}) })
@ -751,7 +754,6 @@ object Action_User {
) { ) {
if(who == null) return if(who == null) return
val initial_text = "@${access_info.getFullAcct(who).ascii} " val initial_text = "@${access_info.getFullAcct(who).ascii} "
AccountPicker.pick( AccountPicker.pick(
activity, activity,
@ -794,11 +796,11 @@ object Action_User {
// error // error
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(activity, true, result.error) activity.showToast(true, result.error)
return return
} }
showToast(activity, false, R.string.delete_succeeded) activity.showToast(false, R.string.delete_succeeded)
// update suggestion column // update suggestion column
for(column in activity.app_state.column_list) { for(column in activity.app_state.column_list) {
@ -819,12 +821,20 @@ object Action_User {
return client.request( return client.request(
"/api/v1/accounts/$whoId/follow", "/api/v1/accounts/$whoId/follow",
jsonObject { jsonObject {
put("notify",enabled) put("notify", enabled)
}.toPostRequestBuilder() }.toPostRequestBuilder()
)?.also{ result-> )?.also { result ->
val relation = parseItem( ::TootRelationShip, TootParser(activity,accessInfo),result.jsonObject) val relation = parseItem(
if(relation!=null){ ::TootRelationShip,
UserRelation.save1Mastodon(System.currentTimeMillis(),accessInfo.db_id,relation) TootParser(activity, accessInfo),
result.jsonObject
)
if(relation != null) {
UserRelation.save1Mastodon(
System.currentTimeMillis(),
accessInfo.db_id,
relation
)
} }
} }
} }
@ -836,11 +846,11 @@ object Action_User {
// error // error
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(activity, true, result.error) activity.showToast(true, result.error)
return return
} }
showToast(activity, false, R.string.operation_succeeded) activity.showToast(false, R.string.operation_succeeded)
} }
}) })
} }

View File

@ -40,7 +40,7 @@ class TootApiClient(
} }
init { init {
pref = Pref.pref(context) pref = context.pref()
} }
companion object { companion object {
@ -566,7 +566,7 @@ class TootApiClient(
val result = TootApiResult.makeWithCaption(apiHost?.pretty) val result = TootApiResult.makeWithCaption(apiHost?.pretty)
if(result.error != null) { if(result.error != null) {
showToast(context, false, result.error) context.showToast(false, result.error)
return null return null
} }
@ -583,7 +583,7 @@ class TootApiClient(
) { ) {
val error = result.error val error = result.error
if(error != null) { if(error != null) {
showToast(context, false, error) context.showToast(false, error)
return null return null
} }
return null return null
@ -593,7 +593,7 @@ class TootApiClient(
val jsonObject = result.jsonObject val jsonObject = result.jsonObject
if(jsonObject == null) { if(jsonObject == null) {
showToast(context, false, result.error) context.showToast(false, result.error)
return null return null
} }
// {"token":"0ba88e2d-4b7d-4599-8d90-dc341a005637","url":"https://misskey.xyz/auth/0ba88e2d-4b7d-4599-8d90-dc341a005637"} // {"token":"0ba88e2d-4b7d-4599-8d90-dc341a005637","url":"https://misskey.xyz/auth/0ba88e2d-4b7d-4599-8d90-dc341a005637"}
@ -601,7 +601,7 @@ class TootApiClient(
// ブラウザで開くURL // ブラウザで開くURL
val url = jsonObject.string("url") val url = jsonObject.string("url")
if(url?.isEmpty() != false) { if(url?.isEmpty() != false) {
showToast(context, false, "missing 'url' in auth session response.") context.showToast(false, "missing 'url' in auth session response.")
return null return null
} }
@ -690,7 +690,7 @@ class TootApiClient(
val appSecret = jsonObject.string(KEY_MISSKEY_APP_SECRET) val appSecret = jsonObject.string(KEY_MISSKEY_APP_SECRET)
if(appSecret?.isEmpty() != false) { if(appSecret?.isEmpty() != false) {
showToast(context, true, context.getString(R.string.cant_get_misskey_app_secret)) context.showToast(true, context.getString(R.string.cant_get_misskey_app_secret))
return null return null
} }
// { // {

View File

@ -1,7 +1,7 @@
package jp.juggler.subwaytooter.api.entity package jp.juggler.subwaytooter.api.entity
import jp.juggler.subwaytooter.Pref
import jp.juggler.subwaytooter.api.TootParser import jp.juggler.subwaytooter.api.TootParser
import jp.juggler.subwaytooter.pref
import jp.juggler.subwaytooter.util.DecodeOptions import jp.juggler.subwaytooter.util.DecodeOptions
import jp.juggler.util.JsonObject import jp.juggler.util.JsonObject
import jp.juggler.util.filterNotEmpty import jp.juggler.util.filterNotEmpty
@ -61,7 +61,7 @@ class TootCard(
}, },
image = src.media_attachments image = src.media_attachments
?.firstOrNull() ?.firstOrNull()
?.urlForThumbnail(Pref.pref(parser.context)) ?.urlForThumbnail(parser.context.pref())
?: src.account.avatar_static, ?: src.account.avatar_static,
type = "photo" type = "photo"
) )

View File

@ -30,36 +30,36 @@ object AccountPicker {
activity : AppCompatActivity, activity : AppCompatActivity,
bAllowPseudo : Boolean = false, bAllowPseudo : Boolean = false,
bAllowMisskey : Boolean = true, bAllowMisskey : Boolean = true,
bAllowMastodon: Boolean = true, bAllowMastodon : Boolean = true,
bAuto : Boolean = false, bAuto : Boolean = false,
message : String? = null, message : String? = null,
accountListArg : ArrayList<SavedAccount>? = null, accountListArg : ArrayList<SavedAccount>? = null,
dismiss_callback : DialogInterfaceCallback? = null, dismiss_callback : DialogInterfaceCallback? = null,
extra_callback : (LinearLayout,Int,Int)->Unit = {_,_,_->}, extra_callback : (LinearLayout, Int, Int) -> Unit = { _, _, _ -> },
callback : SavedAccountCallback callback : SavedAccountCallback
) { ) {
var removedMisskey =0 var removedMisskey = 0
var removedPseudo =0 var removedPseudo = 0
var removeMastodon = 0 var removeMastodon = 0
val account_list : MutableList<SavedAccount> = accountListArg ?: { val account_list : MutableList<SavedAccount> = accountListArg ?: {
val l = SavedAccount.loadAccountList(activity).filter { a-> val l = SavedAccount.loadAccountList(activity).filter { a ->
var bOk = true var bOk = true
if( !bAllowMastodon && !a.isMisskey ){ if(! bAllowMastodon && ! a.isMisskey) {
++removeMastodon ++ removeMastodon
bOk=false bOk = false
} }
if( !bAllowMisskey && a.isMisskey ){ if(! bAllowMisskey && a.isMisskey) {
++removedMisskey ++ removedMisskey
bOk=false bOk = false
} }
if( !bAllowPseudo && a.isPseudo ){ if(! bAllowPseudo && a.isPseudo) {
++removedPseudo ++ removedPseudo
bOk=false bOk = false
} }
bOk bOk
}.toMutableList() }.toMutableList()
SavedAccount.sort(l) SavedAccount.sort(l)
@ -67,30 +67,30 @@ object AccountPicker {
}() }()
if(account_list.isEmpty()) { if(account_list.isEmpty()) {
val sb=StringBuilder() val sb = StringBuilder()
if( removedPseudo > 0 ){ if(removedPseudo > 0) {
sb.append(activity.getString(R.string.not_available_for_pseudo_account)) sb.append(activity.getString(R.string.not_available_for_pseudo_account))
} }
if( removedMisskey > 0 ){ if(removedMisskey > 0) {
if(sb.isNotEmpty() ) sb.append('\n') if(sb.isNotEmpty()) sb.append('\n')
sb.append(activity.getString(R.string.not_available_for_misskey_account)) sb.append(activity.getString(R.string.not_available_for_misskey_account))
} }
if( removeMastodon > 0 ){ if(removeMastodon > 0) {
if(sb.isNotEmpty() ) sb.append('\n') if(sb.isNotEmpty()) sb.append('\n')
sb.append(activity.getString(R.string.not_available_for_mastodon_account)) sb.append(activity.getString(R.string.not_available_for_mastodon_account))
} }
if( sb.isEmpty() ){ if(sb.isEmpty()) {
sb.append(activity.getString(R.string.account_empty)) sb.append(activity.getString(R.string.account_empty))
} }
showToast(activity, false,sb.toString()) activity.showToast(false, sb.toString())
return return
} }
if(bAuto && account_list.size == 1) { if(bAuto && account_list.size == 1) {
callback(account_list[0]) callback(account_list[0])
return return
@ -121,19 +121,22 @@ object AccountPicker {
val density = activity.resources.displayMetrics.density val density = activity.resources.displayMetrics.density
val llAccounts :LinearLayout= viewRoot.findViewById(R.id.llAccounts) val llAccounts : LinearLayout = viewRoot.findViewById(R.id.llAccounts)
val pad_se = (0.5f + 12f * density).toInt() val pad_se = (0.5f + 12f * density).toInt()
val pad_tb = (0.5f + 6f * density).toInt() val pad_tb = (0.5f + 6f * density).toInt()
for(a in account_list) { for(a in account_list) {
val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) val lp = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
val ac = AcctColor.load(a) val ac = AcctColor.load(a)
val b = Button(activity) val b = Button(activity)
if(AcctColor.hasColorBackground(ac)) { if(AcctColor.hasColorBackground(ac)) {
b.background = getAdaptiveRippleDrawableRound(activity,ac.color_bg,ac.color_fg) b.background = getAdaptiveRippleDrawableRound(activity, ac.color_bg, ac.color_fg)
} else { } else {
b.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp) b.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
} }
@ -148,13 +151,13 @@ object AccountPicker {
b.minHeight = (0.5f + 32f * density).toInt() b.minHeight = (0.5f + 32f * density).toInt()
val sb = SpannableStringBuilder(ac.nickname) val sb = SpannableStringBuilder(ac.nickname)
if( a.last_notification_error?.isNotEmpty() == true) { if(a.last_notification_error?.isNotEmpty() == true) {
sb.append("\n") sb.append("\n")
val start = sb.length val start = sb.length
sb.append(a.last_notification_error) sb.append(a.last_notification_error)
val end = sb.length val end = sb.length
sb.setSpan(RelativeSizeSpan(0.7f), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) sb.setSpan(RelativeSizeSpan(0.7f), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}else if(a.last_subscription_error?.isNotEmpty() == true) { } else if(a.last_subscription_error?.isNotEmpty() == true) {
sb.append("\n") sb.append("\n")
val start = sb.length val start = sb.length
sb.append(a.last_subscription_error) sb.append(a.last_subscription_error)
@ -171,7 +174,7 @@ object AccountPicker {
llAccounts.addView(b) llAccounts.addView(b)
} }
extra_callback(llAccounts,pad_se, pad_tb) extra_callback(llAccounts, pad_se, pad_tb)
dialog.show() dialog.show()
} }

View File

@ -2,26 +2,23 @@ package jp.juggler.subwaytooter.dialog
import android.content.Context import android.content.Context
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import java.util.ArrayList
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.util.EmptyCallback import java.util.*
class ActionsDialog { class ActionsDialog {
private val action_list = ArrayList<Action>() private val action_list = ArrayList<Action>()
private class Action(val caption : CharSequence, val r : EmptyCallback) private class Action(val caption : CharSequence, val action : () -> Unit)
fun addAction(caption : CharSequence, r : EmptyCallback) : ActionsDialog { fun addAction(caption : CharSequence, action : () -> Unit) : ActionsDialog {
action_list.add(Action(caption, r)) action_list.add(Action(caption, action))
return this return this
} }
fun show(context : Context, title : CharSequence? = null ) : ActionsDialog { fun show(context : Context, title : CharSequence? = null) : ActionsDialog {
val caption_list = arrayOfNulls<CharSequence>(action_list.size) val caption_list = arrayOfNulls<CharSequence>(action_list.size)
var i = 0 var i = 0
val ie = caption_list.size val ie = caption_list.size
@ -33,11 +30,11 @@ class ActionsDialog {
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.setItems(caption_list) { _, which -> .setItems(caption_list) { _, which ->
if(which >= 0 && which < action_list.size) { if(which >= 0 && which < action_list.size) {
action_list[which].r() action_list[which].action()
} }
} }
if( title != null && title.isNotEmpty() ) b.setTitle(title) if(title != null && title.isNotEmpty()) b.setTitle(title)
b.show() b.show()

View File

@ -11,14 +11,14 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import android.widget.* import android.widget.*
import androidx.appcompat.app.AppCompatActivity import android.app.Activity
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.util.CustomShare import jp.juggler.subwaytooter.util.CustomShare
import jp.juggler.subwaytooter.util.cn import jp.juggler.subwaytooter.util.cn
import jp.juggler.util.* import jp.juggler.util.*
class DlgAppPicker( class DlgAppPicker(
val activity : AppCompatActivity, val activity : Activity,
val intent : Intent, val intent : Intent,
val autoSelect : Boolean = false, val autoSelect : Boolean = false,
val filter : (ResolveInfo) -> Boolean = { true }, val filter : (ResolveInfo) -> Boolean = { true },
@ -26,6 +26,7 @@ class DlgAppPicker(
) { ) {
companion object { companion object {
fun Char.isAlpha() = ('A' <= this && this <= 'Z') || ('a' <= this && this <= 'z') fun Char.isAlpha() = ('A' <= this && this <= 'Z') || ('a' <= this && this <= 'z')
} }
@ -63,7 +64,7 @@ class DlgAppPicker(
val (label, icon) = CustomShare.getInfo(activity, CustomShare.CN_CLIPBOARD.cn()) val (label, icon) = CustomShare.getInfo(activity, CustomShare.CN_CLIPBOARD.cn())
add(ListItem(icon, label.toString(), CustomShare.CN_CLIPBOARD)) add(ListItem(icon, label.toString(), CustomShare.CN_CLIPBOARD))
} }
sortWith{ a, b -> sortWith { a, b ->
val a1 = a.text.firstOrNull() ?: '\u0000' val a1 = a.text.firstOrNull() ?: '\u0000'
val b1 = b.text.firstOrNull() ?: '\u0000' val b1 = b.text.firstOrNull() ?: '\u0000'
when { when {
@ -99,10 +100,10 @@ class DlgAppPicker(
// returns false if list is empty // returns false if list is empty
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
fun show() = fun show() =
if( list.isEmpty()){ if(list.isEmpty()) {
dialog?.dismissSafe() dialog?.dismissSafe()
false false
}else { } else {
dialog?.run { dialog?.run {
window?.setLayout( window?.setLayout(
WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
@ -113,7 +114,6 @@ class DlgAppPicker(
true true
} }
private inner class MyAdapter : BaseAdapter(), AdapterView.OnItemClickListener { private inner class MyAdapter : BaseAdapter(), AdapterView.OnItemClickListener {
override fun getCount() : Int = list.size override fun getCount() : Int = list.size
@ -142,6 +142,7 @@ class DlgAppPicker(
} }
private inner class MyViewHolder(viewRoot : View) { private inner class MyViewHolder(viewRoot : View) {
val ivImage : ImageView = viewRoot.findViewById(R.id.ivImage) val ivImage : ImageView = viewRoot.findViewById(R.id.ivImage)
val tvText : TextView = viewRoot.findViewById(R.id.tvText) val tvText : TextView = viewRoot.findViewById(R.id.tvText)
var item : ListItem? = null var item : ListItem? = null
@ -155,7 +156,7 @@ class DlgAppPicker(
activity, activity,
ivImage, ivImage,
R.drawable.ic_question, R.drawable.ic_question,
color = getAttributeColor(activity, R.attr.colorVectorDrawable), color = activity.getAttributeColor(R.attr.colorVectorDrawable),
alphaMultiplier = 1f alphaMultiplier = 1f
) )
} }

View File

@ -9,12 +9,12 @@ import android.widget.CheckBox
import android.widget.EditText import android.widget.EditText
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.entity.Host import jp.juggler.subwaytooter.api.entity.Host
import jp.juggler.subwaytooter.api.entity.TootInstance import jp.juggler.subwaytooter.api.entity.TootInstance
import jp.juggler.subwaytooter.util.DecodeOptions import jp.juggler.subwaytooter.util.DecodeOptions
import jp.juggler.subwaytooter.util.LinkHelper import jp.juggler.subwaytooter.util.LinkHelper
import jp.juggler.subwaytooter.util.openCustomTab
import jp.juggler.util.neatSpaces import jp.juggler.util.neatSpaces
import jp.juggler.util.notBlank import jp.juggler.util.notBlank
import jp.juggler.util.showToast import jp.juggler.util.showToast
@ -97,10 +97,10 @@ class DlgCreateAccount(
override fun onClick(v : View?) { override fun onClick(v : View?) {
when(v?.id) { when(v?.id) {
R.id.btnRules -> R.id.btnRules ->
App1.openCustomTab(activity, "https://$instance/about/more") activity.openCustomTab("https://$instance/about/more")
R.id.btnTerms -> R.id.btnTerms ->
App1.openCustomTab(activity, "https://$instance/terms") activity.openCustomTab("https://$instance/terms")
R.id.btnCancel -> R.id.btnCancel ->
dialog.cancel() dialog.cancel()
@ -112,16 +112,16 @@ class DlgCreateAccount(
when { when {
username.isEmpty() -> username.isEmpty() ->
showToast(activity, true, R.string.username_empty) activity.showToast(true, R.string.username_empty)
email.isEmpty() -> email.isEmpty() ->
showToast(activity, true, R.string.email_empty) activity.showToast(true, R.string.email_empty)
password.isEmpty() -> password.isEmpty() ->
showToast(activity, true, R.string.password_empty) activity.showToast(true, R.string.password_empty)
username.contains("/") || username.contains("@") -> username.contains("/") || username.contains("@") ->
showToast(activity, true, R.string.username_not_need_atmark) activity.showToast(true, R.string.username_not_need_atmark)
else -> onClickOk( else -> onClickOk(
dialog, dialog,

View File

@ -23,7 +23,8 @@ import kotlinx.coroutines.*
class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener,
DialogInterface.OnDismissListener { DialogInterface.OnDismissListener {
companion object{ companion object {
private val log = LogCategory("DlgDraftPicker") private val log = LogCategory("DlgDraftPicker")
} }
@ -55,7 +56,7 @@ class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongCl
val draft = getPostDraft(position) val draft = getPostDraft(position)
if(draft != null) { if(draft != null) {
showToast(activity, false, R.string.draft_deleted) activity.showToast(false, R.string.draft_deleted)
draft.delete() draft.delete()
reload() reload()
return true return true
@ -104,16 +105,16 @@ class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongCl
// cancel old task // cancel old task
task?.cancel() task?.cancel()
task = GlobalScope.launch(Dispatchers.Main){ task = GlobalScope.launch(Dispatchers.Main) {
val cursor =try { val cursor = try {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
PostDraft.createCursor() PostDraft.createCursor()
} ?: error("cursor is null") } ?: error("cursor is null")
}catch(ex:CancellationException) { } catch(ex : CancellationException) {
return@launch return@launch
}catch(ex:Throwable){ } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(activity,ex, "failed to loading drafts.") activity.showToast(ex, "failed to loading drafts.")
return@launch return@launch
} }
@ -136,6 +137,7 @@ class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongCl
} }
private inner class MyViewHolder(view : View) { private inner class MyViewHolder(view : View) {
val tvTime : TextView val tvTime : TextView
val tvText : TextView val tvText : TextView

View File

@ -24,6 +24,7 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
View.OnClickListener { View.OnClickListener {
companion object { companion object {
val log = LogCategory("DlgFocusPoint") val log = LogCategory("DlgFocusPoint")
} }
@ -57,7 +58,7 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
fun show() { fun show() {
val url = attachment.preview_url val url = attachment.preview_url
if(url == null) { if(url == null) {
showToast(activity, false, "missing image url") activity.showToast(false, "missing image url")
return return
} }
@ -65,7 +66,10 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
private val options = BitmapFactory.Options() private val options = BitmapFactory.Options()
private fun decodeBitmap(data : ByteArray, pixel_max : Int) : Bitmap? { private fun decodeBitmap(
data : ByteArray,
@Suppress("SameParameterValue") pixel_max : Int
) : Bitmap? {
options.inJustDecodeBounds = true options.inJustDecodeBounds = true
options.inScaled = false options.inScaled = false
options.outWidth = 0 options.outWidth = 0
@ -92,7 +96,7 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
override fun background(client : TootApiClient) : TootApiResult? { override fun background(client : TootApiClient) : TootApiResult? {
try { try {
val(result,data) = client.getHttpBytes(url) val (result, data) = client.getHttpBytes(url)
data ?: return result data ?: return result
bitmap = decodeBitmap(data, 1024) bitmap = decodeBitmap(data, 1024)
if(bitmap == null) return TootApiResult("image decode failed.") if(bitmap == null) return TootApiResult("image decode failed.")
@ -105,7 +109,7 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
override fun handleResult(result : TootApiResult?) { override fun handleResult(result : TootApiResult?) {
val bitmap = this.bitmap val bitmap = this.bitmap
if(bitmap == null) { if(bitmap == null) {
showToast(activity, true, result?.error ?: "?") activity.showToast(true, result?.error ?: "?")
dialog.dismissSafe() dialog.dismissSafe()
return return
} }

View File

@ -134,7 +134,7 @@ class DlgListMember(
this.list_owner = a this.list_owner = a
if(a == null) { if(a == null) {
btnListOwner.setText(R.string.not_selected) btnListOwner.setText(R.string.not_selected)
btnListOwner.setTextColor(getAttributeColor(activity, android.R.attr.textColorPrimary)) btnListOwner.setTextColor(activity.getAttributeColor( android.R.attr.textColorPrimary))
btnListOwner.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp) btnListOwner.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
// //
@ -148,7 +148,7 @@ class DlgListMember(
btnListOwner.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp) btnListOwner.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
} }
btnListOwner.textColor = ac.color_fg.notZero() btnListOwner.textColor = ac.color_fg.notZero()
?: getAttributeColor(activity, android.R.attr.textColorPrimary) ?: activity.getAttributeColor( android.R.attr.textColorPrimary)
} }
loadLists() loadLists()
@ -175,7 +175,7 @@ class DlgListMember(
val (r1, ar) = client.syncAccountByAcct(list_owner, target_user_full_acct) val (r1, ar) = client.syncAccountByAcct(list_owner, target_user_full_acct)
r1 ?: return null // cancelled. r1 ?: return null // cancelled.
val local_who = ar?.get() // may null val local_who = ar?.get() // may null
if(local_who == null) showToast(activity, true, r1.error) if(local_who == null) activity.showToast( true, r1.error)
this@DlgListMember.local_who = local_who this@DlgListMember.local_who = local_who
@ -241,7 +241,7 @@ class DlgListMember(
val error = result.error val error = result.error
if(error?.isNotEmpty() == true) { if(error?.isNotEmpty() == true) {
showToast(activity, true, result.error) activity.showToast( true, result.error)
} }
} }
@ -268,14 +268,14 @@ class DlgListMember(
callback = object : DlgTextInput.Callback { callback = object : DlgTextInput.Callback {
override fun onEmptyError() { override fun onEmptyError() {
showToast(activity, false, R.string.list_name_empty) activity.showToast( false, R.string.list_name_empty)
} }
override fun onOK(dialog : Dialog, text : String) { override fun onOK(dialog : Dialog, text : String) {
val list_owner = this@DlgListMember.list_owner val list_owner = this@DlgListMember.list_owner
if(list_owner == null) { if(list_owner == null) {
showToast(activity, false, "list owner is not selected.") activity.showToast( false, "list owner is not selected.")
return return
} }
@ -376,14 +376,14 @@ class DlgListMember(
val list_owner = this@DlgListMember.list_owner val list_owner = this@DlgListMember.list_owner
if(list_owner == null) { if(list_owner == null) {
showToast(activity, false, "list owner is not selected") activity.showToast( false, "list owner is not selected")
revokeCheckedChanged(isChecked) revokeCheckedChanged(isChecked)
return return
} }
val local_who = this@DlgListMember.local_who val local_who = this@DlgListMember.local_who
if(local_who == null) { if(local_who == null) {
showToast(activity, false, "target user is not synchronized") activity.showToast( false, "target user is not synchronized")
revokeCheckedChanged(isChecked) revokeCheckedChanged(isChecked)
return return
} }

View File

@ -5,11 +5,9 @@ import android.app.Activity
import android.app.Dialog import android.app.Dialog
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.drawable.PictureDrawable import android.graphics.drawable.PictureDrawable
import android.os.Build
import android.util.SparseArray import android.util.SparseArray
import android.view.* import android.view.*
import android.widget.* import android.widget.*
import androidx.core.view.ViewCompat
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import com.astuetz.PagerSlidingTabStrip import com.astuetz.PagerSlidingTabStrip
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
@ -44,6 +42,7 @@ class EmojiPicker(
class SkinTone(val suffix_list : Array<out String>) { class SkinTone(val suffix_list : Array<out String>) {
companion object { companion object {
fun create(vararg suffix_list : String) : SkinTone { fun create(vararg suffix_list : String) : SkinTone {
return SkinTone(suffix_list) return SkinTone(suffix_list)
} }
@ -269,8 +268,7 @@ class EmojiPicker(
setTypeface(typeface, Typeface.BOLD) setTypeface(typeface, Typeface.BOLD)
textColor = textColor = this@EmojiPicker.activity.getAttributeColor(R.attr.colorContentText)
getAttributeColor(this@EmojiPicker.activity, R.attr.colorContentText)
textSize = 16f // SP単位 textSize = 16f // SP単位
text = when(val name = it.key) { text = when(val name = it.key) {
@ -542,7 +540,7 @@ class EmojiPicker(
val pref = App1.pref val pref = App1.pref
if( Pref.bpEmojiPickerCloseOnSelected(pref)) if(Pref.bpEmojiPickerCloseOnSelected(pref))
dialog.dismissSafe() dialog.dismissSafe()
// Recentをロード(他インスタンスの絵文字を含む) // Recentをロード(他インスタンスの絵文字を含む)

View File

@ -19,6 +19,7 @@ import java.net.IDN
import java.util.* import java.util.*
object LoginForm { object LoginForm {
private val log = LogCategory("LoginForm") private val log = LogCategory("LoginForm")
private class StringArray : ArrayList<String>() private class StringArray : ArrayList<String>()
@ -107,10 +108,10 @@ object LoginForm {
when { when {
instance.isEmpty() -> instance.isEmpty() ->
showToast(activity, true, R.string.instance_not_specified) activity.showToast(true, R.string.instance_not_specified)
instance.contains("/") || instance.contains("@") -> instance.contains("/") || instance.contains("@") ->
showToast(activity, true, R.string.instance_not_need_slash) activity.showToast(true, R.string.instance_not_need_slash)
else -> { else -> {
val actionPos = spAction.selectedItemPosition val actionPos = spAction.selectedItemPosition
@ -124,7 +125,7 @@ object LoginForm {
} }
view.findViewById<View>(R.id.btnCancel).setOnClickListener { dialog.cancel() } view.findViewById<View>(R.id.btnCancel).setOnClickListener { dialog.cancel() }
val instance_list = HashSet<String>().apply{ val instance_list = HashSet<String>().apply {
try { try {
activity.resources.openRawResource(R.raw.server_list).use { inStream -> activity.resources.openRawResource(R.raw.server_list).use { inStream ->
val br = BufferedReader(InputStreamReader(inStream, "UTF-8")) val br = BufferedReader(InputStreamReader(inStream, "UTF-8"))
@ -133,8 +134,8 @@ object LoginForm {
br.readLine()?.trim { it <= ' ' }?.toLowerCase(Locale.JAPAN) ?: break br.readLine()?.trim { it <= ' ' }?.toLowerCase(Locale.JAPAN) ?: break
if(s.isEmpty()) continue if(s.isEmpty()) continue
add(s) add(s)
add(IDN.toASCII(s,IDN.ALLOW_UNASSIGNED)) add(IDN.toASCII(s, IDN.ALLOW_UNASSIGNED))
add(IDN.toUnicode(s,IDN.ALLOW_UNASSIGNED)) add(IDN.toUnicode(s, IDN.ALLOW_UNASSIGNED))
} }
} }
} catch(ex : Throwable) { } catch(ex : Throwable) {

View File

@ -23,35 +23,35 @@ object ReportForm {
access_info : SavedAccount, access_info : SavedAccount,
who : TootAccount, who : TootAccount,
status : TootStatus?, status : TootStatus?,
onClickOk : (dialog : Dialog, comment : String,forward:Boolean) -> Unit onClickOk : (dialog : Dialog, comment : String, forward : Boolean) -> Unit
) { ) {
val view = activity.layoutInflater.inflate(R.layout.dlg_report_user, null, false) val view = activity.layoutInflater.inflate(R.layout.dlg_report_user, null, false)
val tvUser :TextView = view.findViewById(R.id.tvUser) val tvUser : TextView = view.findViewById(R.id.tvUser)
val tvStatusCaption :TextView = view.findViewById(R.id.tvStatusCaption) val tvStatusCaption : TextView = view.findViewById(R.id.tvStatusCaption)
val tvStatus :TextView = view.findViewById(R.id.tvStatus) val tvStatus : TextView = view.findViewById(R.id.tvStatus)
val etComment :EditText = view.findViewById(R.id.etComment) val etComment : EditText = view.findViewById(R.id.etComment)
val cbForward : CheckBox = view.findViewById(R.id.cbForward) val cbForward : CheckBox = view.findViewById(R.id.cbForward)
val tvForwardDesc:TextView = view.findViewById(R.id.tvForwardDesc) val tvForwardDesc : TextView = view.findViewById(R.id.tvForwardDesc)
val canForward = !access_info.matchHost( who) val canForward = ! access_info.matchHost(who)
cbForward.isChecked = false cbForward.isChecked = false
if(!canForward){ if(! canForward) {
cbForward.visibility = View.GONE cbForward.visibility = View.GONE
tvForwardDesc.visibility = View.GONE tvForwardDesc.visibility = View.GONE
}else{ } else {
cbForward.visibility = View.VISIBLE cbForward.visibility = View.VISIBLE
tvForwardDesc.visibility = View.VISIBLE tvForwardDesc.visibility = View.VISIBLE
cbForward.text = activity.getString(R.string.report_forward_to,who.apDomain.pretty) cbForward.text = activity.getString(R.string.report_forward_to, who.apDomain.pretty)
} }
tvUser.text = who.acct.pretty tvUser.text = who.acct.pretty
if( status == null){ if(status == null) {
tvStatusCaption.visibility = View.GONE tvStatusCaption.visibility = View.GONE
tvStatus.visibility = View.GONE tvStatus.visibility = View.GONE
}else{ } else {
tvStatus.text = status.decoded_content tvStatus.text = status.decoded_content
} }
@ -60,11 +60,11 @@ object ReportForm {
view.findViewById<View>(R.id.btnOk).setOnClickListener(View.OnClickListener { view.findViewById<View>(R.id.btnOk).setOnClickListener(View.OnClickListener {
val comment = etComment.text.toString().trim() val comment = etComment.text.toString().trim()
if(comment.isEmpty()) { if(comment.isEmpty()) {
showToast(activity, true, R.string.comment_empty) activity.showToast(true, R.string.comment_empty)
return@OnClickListener return@OnClickListener
} }
onClickOk(dialog, comment,cbForward.isChecked) onClickOk(dialog, comment, cbForward.isChecked)
}) })
view.findViewById<View>(R.id.btnCancel).setOnClickListener { dialog.cancel() } view.findViewById<View>(R.id.btnCancel).setOnClickListener { dialog.cancel() }

View File

@ -19,7 +19,7 @@ class SavedAccount(
val db_id : Long, val db_id : Long,
acctArg : String, acctArg : String,
apiHostArg : String? = null, apiHostArg : String? = null,
apDomainArg : String? = null, apDomainArg : String? = null,
var token_info : JsonObject? = null, var token_info : JsonObject? = null,
var loginAccount : TootAccount? = null, // 疑似アカウントではnull var loginAccount : TootAccount? = null, // 疑似アカウントではnull
override val misskeyVersion : Int = 0 override val misskeyVersion : Int = 0
@ -74,14 +74,13 @@ class SavedAccount(
var last_subscription_error : String? = null var last_subscription_error : String? = null
var last_push_endpoint : String? = null var last_push_endpoint : String? = null
init { init {
val tmpAcct = Acct.parse(acctArg) val tmpAcct = Acct.parse(acctArg)
this.username = tmpAcct.username this.username = tmpAcct.username
if(username.isEmpty()) throw RuntimeException("missing username in acct") if(username.isEmpty()) throw RuntimeException("missing username in acct")
val tmpApiHost = apiHostArg?.notEmpty()?.let{ Host.parse(it)} val tmpApiHost = apiHostArg?.notEmpty()?.let { Host.parse(it) }
val tmpApDomain = apDomainArg?.notEmpty()?.let{ Host.parse(it)} val tmpApDomain = apDomainArg?.notEmpty()?.let { Host.parse(it) }
this.apiHost = tmpApiHost ?: tmpApDomain ?: tmpAcct.host ?: error("missing apiHost") this.apiHost = tmpApiHost ?: tmpApDomain ?: tmpAcct.host ?: error("missing apiHost")
this.apDomain = tmpApDomain ?: tmpApiHost ?: tmpAcct.host ?: error("missing apDomain") this.apDomain = tmpApDomain ?: tmpApiHost ?: tmpAcct.host ?: error("missing apDomain")
@ -106,7 +105,7 @@ class SavedAccount(
context, context,
LinkHelper.create( LinkHelper.create(
apiHostArg = this@SavedAccount.apiHost, apiHostArg = this@SavedAccount.apiHost,
apDomainArg = this@SavedAccount.apDomain, apDomainArg = this@SavedAccount.apDomain,
misskeyVersion = misskeyVersion misskeyVersion = misskeyVersion
) )
).account(jsonAccount) ).account(jsonAccount)
@ -292,20 +291,19 @@ class SavedAccount(
return acct.host == null || acct.host == this.apDomain return acct.host == null || acct.host == this.apDomain
} }
// fun isRemoteUser(acct : String) : Boolean { // fun isRemoteUser(acct : String) : Boolean {
// return ! isLocalUser(acct) // return ! isLocalUser(acct)
// } // }
fun isMe(who : TootAccount?) : Boolean = isMe(who?.acct) fun isMe(who : TootAccount?) : Boolean = isMe(who?.acct)
// fun isMe(who_acct : String) : Boolean = isMe(Acct.parse(who_acct)) // fun isMe(who_acct : String) : Boolean = isMe(Acct.parse(who_acct))
fun isMe(who_acct : Acct?):Boolean{ fun isMe(who_acct : Acct?) : Boolean {
who_acct?:return false who_acct ?: return false
if( who_acct.username != this.acct.username) return false if(who_acct.username != this.acct.username) return false
return who_acct.host == null || who_acct.host == this.acct.host return who_acct.host == null || who_acct.host == this.acct.host
} }
fun supplyBaseUrl(url : String?) : String? { fun supplyBaseUrl(url : String?) : String? {
return when { return when {
url == null || url.isEmpty() -> return null url == null || url.isEmpty() -> return null
@ -317,6 +315,7 @@ class SavedAccount(
fun isNicoru(account : TootAccount?) : Boolean = account?.apiHost == Host.FRIENDS_NICO fun isNicoru(account : TootAccount?) : Boolean = account?.apiHost == Host.FRIENDS_NICO
companion object : TableCompanion { companion object : TableCompanion {
private val log = LogCategory("SavedAccount") private val log = LogCategory("SavedAccount")
const val table = "access_info" const val table = "access_info"
@ -470,7 +469,7 @@ class SavedAccount(
// スキーマ57から // スキーマ57から
+ ",$COL_NOTIFICATION_POST integer default 1" + ",$COL_NOTIFICATION_POST integer default 1"
+ ")" + ")"
) )
db.execSQL("create index if not exists ${table}_user on ${table}(u)") db.execSQL("create index if not exists ${table}_user on ${table}(u)")
@ -604,7 +603,7 @@ class SavedAccount(
log.trace(ex) log.trace(ex)
} }
} }
if(oldVersion < 33 && newVersion >= 33) { if(oldVersion < 33 && newVersion >= 33) {
try { try {
db.execSQL("alter table $table add column $COL_NOTIFICATION_REACTION integer default 1") db.execSQL("alter table $table add column $COL_NOTIFICATION_REACTION integer default 1")
@ -617,7 +616,7 @@ class SavedAccount(
log.trace(ex) log.trace(ex)
} }
} }
if(oldVersion < 38 && newVersion >= 38) { if(oldVersion < 38 && newVersion >= 38) {
try { try {
db.execSQL("alter table $table add column $COL_DEFAULT_SENSITIVE integer default 0") db.execSQL("alter table $table add column $COL_DEFAULT_SENSITIVE integer default 0")
@ -716,7 +715,7 @@ class SavedAccount(
fun insert( fun insert(
acct : String, acct : String,
host : String, host : String,
domain:String?, domain : String?,
account : JsonObject, account : JsonObject,
token : JsonObject, token : JsonObject,
misskeyVersion : Int = 0 misskeyVersion : Int = 0
@ -725,7 +724,7 @@ class SavedAccount(
val cv = ContentValues() val cv = ContentValues()
cv.put(COL_USER, acct) cv.put(COL_USER, acct)
cv.put(COL_HOST, host) cv.put(COL_HOST, host)
cv.putOrNull(COL_DOMAIN,domain) cv.putOrNull(COL_DOMAIN, domain)
cv.put(COL_ACCOUNT, account.toString()) cv.put(COL_ACCOUNT, account.toString())
cv.put(COL_TOKEN, token.toString()) cv.put(COL_TOKEN, token.toString())
cv.put(COL_MISSKEY_VERSION, misskeyVersion) cv.put(COL_MISSKEY_VERSION, misskeyVersion)
@ -792,7 +791,7 @@ class SavedAccount(
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
log.e(ex, "loadAccountList failed.") log.e(ex, "loadAccountList failed.")
showToast(context, true, ex.withCaption("(SubwayTooter) broken in-app database?")) context.showToast(true, ex.withCaption("(SubwayTooter) broken in-app database?"))
} }
return result return result
@ -893,47 +892,47 @@ class SavedAccount(
return 0L return 0L
} }
fun isNicoru(acct:Acct) : Boolean { fun isNicoru(acct : Acct) : Boolean {
return acct.host == Host.FRIENDS_NICO return acct.host == Host.FRIENDS_NICO
} }
// private fun charAtLower(src : CharSequence, pos : Int) : Char { // private fun charAtLower(src : CharSequence, pos : Int) : Char {
// val c = src[pos] // val c = src[pos]
// return if(c >= 'a' && c <= 'z') c - ('a' - 'A') else c // return if(c >= 'a' && c <= 'z') c - ('a' - 'A') else c
// } // }
// //
// @Suppress("SameParameterValue") // @Suppress("SameParameterValue")
// private fun host_match( // private fun host_match(
// a : CharSequence, // a : CharSequence,
// a_startArg : Int, // a_startArg : Int,
// b : CharSequence, // b : CharSequence,
// b_startArg : Int // b_startArg : Int
// ) : Boolean { // ) : Boolean {
// var a_start = a_startArg // var a_start = a_startArg
// var b_start = b_startArg // var b_start = b_startArg
// //
// val a_end = a.length // val a_end = a.length
// val b_end = b.length // val b_end = b.length
// //
// var a_remain = a_end - a_start // var a_remain = a_end - a_start
// val b_remain = b_end - b_start // val b_remain = b_end - b_start
// //
// // 文字数が違う // // 文字数が違う
// if(a_remain != b_remain) return false // if(a_remain != b_remain) return false
// //
// // 文字数がゼロ // // 文字数がゼロ
// if(a_remain <= 0) return true // if(a_remain <= 0) return true
// //
// // 末尾の文字が違う // // 末尾の文字が違う
// if(charAtLower(a, a_end - 1) != charAtLower(b, b_end - 1)) return false // if(charAtLower(a, a_end - 1) != charAtLower(b, b_end - 1)) return false
// //
// // 先頭からチェック // // 先頭からチェック
// while(a_remain -- > 0) { // while(a_remain -- > 0) {
// if(charAtLower(a, a_start ++) != charAtLower(b, b_start ++)) return false // if(charAtLower(a, a_start ++) != charAtLower(b, b_start ++)) return false
// } // }
// //
// return true // return true
// } // }
private val account_comparator = Comparator<SavedAccount> { a, b -> private val account_comparator = Comparator<SavedAccount> { a, b ->
var i : Int var i : Int
@ -1065,7 +1064,7 @@ class SavedAccount(
fun updateNotificationError(text : String?) { fun updateNotificationError(text : String?) {
this.last_notification_error = text this.last_notification_error = text
if(db_id != INVALID_DB_ID){ if(db_id != INVALID_DB_ID) {
val cv = ContentValues() val cv = ContentValues()
when(text) { when(text) {
null -> cv.putNull(COL_LAST_NOTIFICATION_ERROR) null -> cv.putNull(COL_LAST_NOTIFICATION_ERROR)
@ -1077,7 +1076,7 @@ class SavedAccount(
fun updateSubscriptionError(text : String?) { fun updateSubscriptionError(text : String?) {
this.last_subscription_error = text this.last_subscription_error = text
if(db_id != INVALID_DB_ID){ if(db_id != INVALID_DB_ID) {
val cv = ContentValues() val cv = ContentValues()
when(text) { when(text) {
null -> cv.putNull(COL_LAST_SUBSCRIPTION_ERROR) null -> cv.putNull(COL_LAST_SUBSCRIPTION_ERROR)
@ -1089,7 +1088,7 @@ class SavedAccount(
fun updateLastPushEndpoint(text : String?) { fun updateLastPushEndpoint(text : String?) {
this.last_push_endpoint = text this.last_push_endpoint = text
if(db_id != INVALID_DB_ID){ if(db_id != INVALID_DB_ID) {
val cv = ContentValues() val cv = ContentValues()
when(text) { when(text) {
null -> cv.putNull(COL_LAST_PUSH_ENDPOINT) null -> cv.putNull(COL_LAST_PUSH_ENDPOINT)
@ -1107,5 +1106,4 @@ class SavedAccount(
override fun hashCode() : Int = acct.hashCode() override fun hashCode() : Int = acct.hashCode()
} }

View File

@ -0,0 +1,163 @@
package jp.juggler.subwaytooter.util
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.app.Activity
import androidx.browser.customtabs.CustomTabsIntent
import jp.juggler.subwaytooter.Pref
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.entity.TootAttachment
import jp.juggler.subwaytooter.dialog.DlgAppPicker
import jp.juggler.subwaytooter.pref
import jp.juggler.util.*
private val log = LogCategory("AppOpener")
// returns true if activity is opened.
// returns false if fallback required
private fun Activity.startActivityExcludeMyApp(
intent : Intent,
startAnimationBundle : Bundle? = null
) : Boolean {
try {
val pm = packageManager !!
val myName = packageName
val filter : (ResolveInfo) -> Boolean = {
it.activityInfo.packageName != myName &&
it.activityInfo.exported &&
- 1 == it.activityInfo.packageName.indexOf("com.huawei.android.internal")
}
// resolveActivity がこのアプリ以外のActivityを返すなら、それがベストなんだろう
// ただしAndroid M以降はMATCH_DEFAULT_ONLYだと「常時」が設定されてないとnullを返す
val ri = pm.resolveActivity(
intent,
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PackageManager.MATCH_ALL
} else {
PackageManager.MATCH_DEFAULT_ONLY
}
)?.takeIf(filter)
if(ri != null) {
intent.setClassName(ri.activityInfo.packageName, ri.activityInfo.name)
startActivity(intent, startAnimationBundle)
return true
}
return DlgAppPicker(
this,
intent,
autoSelect = true,
filter = filter
) {
try {
intent.component = it.cn()
startActivity(intent, startAnimationBundle)
} catch(ex : Throwable) {
log.trace(ex)
showToast(ex, "can't open. ${intent.data}")
}
}.show()
} catch(ex : Throwable) {
log.trace(ex)
showToast(ex, "can't open. ${intent.data}")
return true // fallback not required in this case
}
}
fun Activity.openBrowser(uri : Uri?) {
if(uri != null) {
val rv = startActivityExcludeMyApp(Intent(Intent.ACTION_VIEW, uri))
if(! rv) showToast(true, "there is no app that can open $uri")
}
}
fun Activity.openBrowser(url : String?) = openBrowser(url.mayUri())
// ubway Tooterの「アプリ設定/挙動/リンクを開く際にCustom Tabsを使わない」をONにして
// 投稿のコンテキストメニューの「トゥートへのアクション/Webページを開く」「ユーザへのアクション/Webページを開く」を使うと
// 投げたインテントをST自身が受け取って「次のアカウントから開く」ダイアログが出て
// 「Webページを開く」をまた押すと無限ループしてダイアログの影が徐々に濃くなりそのうち壊れる
// これを避けるには、投稿やトゥートを開く際に bpDontUseCustomTabs がオンならST以外のアプリを列挙したアプリ選択ダイアログを出すしかない
fun Activity.openCustomTabOrBrowser(url : String?) {
url ?: return
if(! Pref.bpDontUseCustomTabs(pref())) {
openCustomTab(url)
} else {
openBrowser(url)
}
}
// Chrome Custom Tab を開く
fun Activity.openCustomTab(url : String?) {
url ?: return
if(url.isEmpty()) {
showToast(false, "URL is empty string.")
return
}
val pref = pref()
if(Pref.bpDontUseCustomTabs(pref)) {
openCustomTabOrBrowser(url)
return
}
try {
if(url.startsWith("http") && Pref.bpPriorChrome(pref)) {
try {
// 初回はChrome指定で試す
val customTabsIntent = CustomTabsIntent.Builder()
.setToolbarColor(getAttributeColor(R.attr.colorPrimary))
.setShowTitle(true)
.build()
val rv = startActivityExcludeMyApp(
customTabsIntent.intent.also {
it.component = ComponentName(
"com.android.chrome",
"com.google.android.apps.chrome.Main"
)
it.data = url.toUri()
},
customTabsIntent.startAnimationBundle
)
if(rv) return
} catch(ex2 : Throwable) {
log.e(ex2, "openChromeTab: missing chrome. retry to other application.")
}
}
// Chromeがないようなのでcomponent指定なしでリトライ
val customTabsIntent = CustomTabsIntent.Builder()
.setToolbarColor(getAttributeColor(R.attr.colorPrimary))
.setShowTitle(true)
.build()
val rv = startActivityExcludeMyApp(
customTabsIntent.intent.also {
it.data = url.toUri()
},
customTabsIntent.startAnimationBundle
)
if(! rv) {
showToast(true, "the browser app is not installed.")
}
} catch(ex : Throwable) {
log.trace(ex)
val scheme = url.mayUri()?.scheme ?: url
showToast(true, "can't open browser app for %s", scheme)
}
}
fun Activity.openCustomTab(ta : TootAttachment) =
openCustomTab(ta.getLargeUrl(pref()))

View File

@ -31,18 +31,6 @@ abstract class AsyncActivity : AppCompatActivity(), CoroutineScope {
(job + Dispatchers.Default).cancel() (job + Dispatchers.Default).cancel()
} }
fun showToast(bLong : Boolean, fmt : String?, vararg args : Any) =
showToast(this, bLong, fmt, *args)
fun showToast(ex : Throwable, fmt : String?, vararg args : Any) =
showToast(this, ex, fmt, *args)
fun showToast(bLong : Boolean, string_id : Int, vararg args : Any) =
showToast(this, bLong, string_id, *args)
fun showToast(ex : Throwable, string_id : Int, vararg args : Any) =
showToast(this, ex, string_id, *args)
fun <T : Any?> runWithProgress( fun <T : Any?> runWithProgress(
caption : String, caption : String,
doInBackground : suspend CoroutineScope.(ProgressDialogEx) -> T, doInBackground : suspend CoroutineScope.(ProgressDialogEx) -> T,
@ -79,7 +67,7 @@ abstract class AsyncActivity : AppCompatActivity(), CoroutineScope {
} }
if(result != null) afterProc(result) if(result != null) afterProc(result)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(this@AsyncActivity, ex, "$caption failed.") showToast(ex, "$caption failed.")
} finally { } finally {
progress.dismissSafe() progress.dismissSafe()
try { try {

View File

@ -71,7 +71,7 @@ object CustomShare {
label = label =
"${context.getString(R.string.copy_to_clipboard)}(${context.getString(R.string.app_name)})" "${context.getString(R.string.copy_to_clipboard)}(${context.getString(R.string.app_name)})"
icon = ContextCompat.getDrawable(context, R.drawable.ic_copy)?.mutate()?.apply { icon = ContextCompat.getDrawable(context, R.drawable.ic_copy)?.mutate()?.apply {
setTint(getAttributeColor(context, R.attr.colorVectorDrawable)) setTint(context.getAttributeColor(R.attr.colorVectorDrawable))
setTintMode(PorterDuff.Mode.SRC_IN) setTintMode(PorterDuff.Mode.SRC_IN)
} }
} else { } else {
@ -105,7 +105,7 @@ object CustomShare {
// convert "pkgName/className" string to ComponentName object. // convert "pkgName/className" string to ComponentName object.
val cn = getCustomShareComponentName(App1.pref, target) val cn = getCustomShareComponentName(App1.pref, target)
if(cn == null) { if(cn == null) {
showToast(context, true, R.string.custom_share_app_not_found) context.showToast(true, R.string.custom_share_app_not_found)
return return
} }
val cnStr = "${cn.packageName}/${cn.className}" val cnStr = "${cn.packageName}/${cn.className}"
@ -113,9 +113,9 @@ object CustomShare {
try { try {
val cm : ClipboardManager = systemService(context) !! val cm : ClipboardManager = systemService(context) !!
cm.setPrimaryClip(ClipData.newPlainText("", text)) cm.setPrimaryClip(ClipData.newPlainText("", text))
showToast(context, false, R.string.copied_to_clipboard) context.showToast(false, R.string.copied_to_clipboard)
} catch(ex : Throwable) { } catch(ex : Throwable) {
showToast(context, ex, "copy to clipboard failed.") context.showToast(ex, "copy to clipboard failed.")
} }
return return
} }
@ -128,10 +128,10 @@ object CustomShare {
context.startActivity(intent) context.startActivity(intent)
} catch(ex : ActivityNotFoundException) { } catch(ex : ActivityNotFoundException) {
log.trace(ex) log.trace(ex)
showToast(context, true, R.string.custom_share_app_not_found) context.showToast(true, R.string.custom_share_app_not_found)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(context, ex, "invoke() failed.") context.showToast(ex, "invoke() failed.")
} }
} }
@ -147,7 +147,7 @@ object CustomShare {
// convert "pkgName/className" string to ComponentName object. // convert "pkgName/className" string to ComponentName object.
val cn = getCustomShareComponentName(App1.pref, target) val cn = getCustomShareComponentName(App1.pref, target)
if(cn == null) { if(cn == null) {
showToast(context, true, R.string.custom_share_app_not_found) context.showToast(true, R.string.custom_share_app_not_found)
return return
} }
@ -155,7 +155,7 @@ object CustomShare {
invoke(context, sv, target) invoke(context, sv, target)
} catch(ex : Throwable) { } catch(ex : Throwable) {
log.trace(ex) log.trace(ex)
showToast(context, ex, "invoke() failed.") context.showToast(ex, "invoke() failed.")
} }
} }

View File

@ -11,6 +11,7 @@ import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.Pref import jp.juggler.subwaytooter.Pref
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.entity.CustomEmoji import jp.juggler.subwaytooter.api.entity.CustomEmoji
import jp.juggler.subwaytooter.pref
import jp.juggler.subwaytooter.span.EmojiImageSpan import jp.juggler.subwaytooter.span.EmojiImageSpan
import jp.juggler.subwaytooter.span.HighlightSpan import jp.juggler.subwaytooter.span.HighlightSpan
import jp.juggler.subwaytooter.span.NetworkEmojiSpan import jp.juggler.subwaytooter.span.NetworkEmojiSpan
@ -356,7 +357,7 @@ object EmojiDecoder {
val useEmojioneShortcode = when(val context = options.context) { val useEmojioneShortcode = when(val context = options.context) {
null -> false null -> false
else -> Pref.bpEmojioneShortcode( Pref.pref(context)) else -> Pref.bpEmojioneShortcode( context.pref())
} }
splitShortCode(s, callback = object : ShortCodeSplitterCallback { splitShortCode(s, callback = object : ShortCodeSplitterCallback {

View File

@ -14,7 +14,6 @@ import android.widget.LinearLayout
import android.widget.PopupWindow import android.widget.PopupWindow
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.App1 import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.Pref
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.entity.Acct import jp.juggler.subwaytooter.api.entity.Acct
import jp.juggler.subwaytooter.view.MyEditText import jp.juggler.subwaytooter.view.MyEditText
@ -47,7 +46,7 @@ internal class PopupAutoCompleteAcct(
private val popup_width : Int private val popup_width : Int
val handler : Handler val handler : Handler
private val pref : SharedPreferences = Pref.pref(activity) private val pref : SharedPreferences = App1.pref
private var popup_rows : Int = 0 private var popup_rows : Int = 0
@ -98,7 +97,7 @@ internal class PopupAutoCompleteAcct(
run { run {
val v = activity.layoutInflater val v = activity.layoutInflater
.inflate(R.layout.lv_spinner_dropdown, llItems, false) as CheckedTextView .inflate(R.layout.lv_spinner_dropdown, llItems, false) as CheckedTextView
v.setTextColor(getAttributeColor(activity, android.R.attr.textColorPrimary)) v.setTextColor(activity.getAttributeColor(android.R.attr.textColorPrimary))
v.setText(R.string.close) v.setText(R.string.close)
v.setOnClickListener { acct_popup.dismiss() } v.setOnClickListener { acct_popup.dismiss() }
llItems.addView(v) llItems.addView(v)
@ -108,7 +107,7 @@ internal class PopupAutoCompleteAcct(
if(picker_caption != null && picker_callback != null) { if(picker_caption != null && picker_callback != null) {
val v = activity.layoutInflater val v = activity.layoutInflater
.inflate(R.layout.lv_spinner_dropdown, llItems, false) as CheckedTextView .inflate(R.layout.lv_spinner_dropdown, llItems, false) as CheckedTextView
v.setTextColor(getAttributeColor(activity, android.R.attr.textColorPrimary)) v.setTextColor(activity.getAttributeColor(android.R.attr.textColorPrimary))
v.text = picker_caption v.text = picker_caption
v.setOnClickListener { v.setOnClickListener {
acct_popup.dismiss() acct_popup.dismiss()
@ -126,7 +125,7 @@ internal class PopupAutoCompleteAcct(
val acct = acct_list[i] val acct = acct_list[i]
val v = activity.layoutInflater val v = activity.layoutInflater
.inflate(R.layout.lv_spinner_dropdown, llItems, false) as CheckedTextView .inflate(R.layout.lv_spinner_dropdown, llItems, false) as CheckedTextView
v.setTextColor(getAttributeColor(activity, android.R.attr.textColorPrimary)) v.setTextColor(activity.getAttributeColor(android.R.attr.textColorPrimary))
v.text = acct v.text = acct
if(acct is Spannable) { if(acct is Spannable) {
NetworkEmojiInvalidator(handler, v).register(acct) NetworkEmojiInvalidator(handler, v).register(acct)

View File

@ -38,6 +38,7 @@ class PostHelper(
) { ) {
companion object { companion object {
private val log = LogCategory("PostHelper") private val log = LogCategory("PostHelper")
private val reCharsNotEmoji = "[^0-9A-Za-z_-]".asciiPattern() private val reCharsNotEmoji = "[^0-9A-Za-z_-]".asciiPattern()
@ -47,6 +48,7 @@ class PostHelper(
} }
interface PostCompleteCallback { interface PostCompleteCallback {
fun onPostComplete(target_account : SavedAccount, status : TootStatus) fun onPostComplete(target_account : SavedAccount, status : TootStatus)
fun onScheduledPostComplete(target_account : SavedAccount) fun onScheduledPostComplete(target_account : SavedAccount)
} }
@ -110,14 +112,14 @@ class PostHelper(
val hasAttachment = attachment_list?.isNotEmpty() ?: false val hasAttachment = attachment_list?.isNotEmpty() ?: false
if(! hasAttachment && content.isEmpty()) { if(! hasAttachment && content.isEmpty()) {
showToast(activity, true, R.string.post_error_contents_empty) activity.showToast(true, R.string.post_error_contents_empty)
return return
} }
// nullはCWチェックなしを示す // nullはCWチェックなしを示す
// nullじゃなくてカラならエラー // nullじゃなくてカラならエラー
if(spoiler_text != null && spoiler_text.isEmpty()) { if(spoiler_text != null && spoiler_text.isEmpty()) {
showToast(activity, true, R.string.post_error_contents_warning_empty) activity.showToast(true, R.string.post_error_contents_warning_empty)
return return
} }
@ -134,19 +136,19 @@ class PostHelper(
if(item.isEmpty()) { if(item.isEmpty()) {
if(n < 2) { if(n < 2) {
showToast(activity, true, R.string.enquete_item_is_empty, n + 1) activity.showToast(true, R.string.enquete_item_is_empty, n + 1)
return return
} }
} else { } else {
val code_count = item.codePointCount(0, item.length) val code_count = item.codePointCount(0, item.length)
if(code_count > choice_max_chars) { if(code_count > choice_max_chars) {
val over = code_count - choice_max_chars val over = code_count - choice_max_chars
showToast(activity, true, R.string.enquete_item_too_long, n + 1, over) activity.showToast(true, R.string.enquete_item_too_long, n + 1, over)
return return
} else if(n > 0) { } else if(n > 0) {
for(i in 0 until n) { for(i in 0 until n) {
if(item == enquete_items[i]) { if(item == enquete_items[i]) {
showToast(activity, true, R.string.enquete_item_duplicate, n + 1) activity.showToast(true, R.string.enquete_item_duplicate, n + 1)
return return
} }
} }
@ -278,7 +280,7 @@ class PostHelper(
// 確認を終えたらボタン連打判定 // 確認を終えたらボタン連打判定
if(last_post_task?.get()?.isActive == true) { if(last_post_task?.get()?.isActive == true) {
showToast(activity, false, R.string.post_button_tapped_repeatly) activity.showToast(false, R.string.post_button_tapped_repeatly)
return return
} }
@ -286,371 +288,372 @@ class PostHelper(
val delta = now - last_post_tapped val delta = now - last_post_tapped
last_post_tapped = now last_post_tapped = now
if(delta < 1000L) { if(delta < 1000L) {
showToast(activity, false, R.string.post_button_tapped_repeatly) activity.showToast(false, R.string.post_button_tapped_repeatly)
return return
} }
// 全ての確認を終えたらバックグラウンドでの処理を開始する // 全ての確認を終えたらバックグラウンドでの処理を開始する
last_post_task = WeakReference(TootTaskRunner(activity last_post_task =
, progressSetupCallback = { progressDialog -> WeakReference(TootTaskRunner(activity, progressSetupCallback = { progressDialog ->
progressDialog.setCanceledOnTouchOutside(false) progressDialog.setCanceledOnTouchOutside(false)
} }
).run(account, object : TootTask { ).run(account, object : TootTask {
var status : TootStatus? = null
var credential_tmp : TootAccount? = null
var scheduledStatusSucceeded = false
fun getCredential(client : TootApiClient,parser:TootParser) : TootApiResult? {
val result = client.request("/api/v1/accounts/verify_credentials")
credential_tmp = parser.account(result?.jsonObject)
return result
}
override fun background(client : TootApiClient) : TootApiResult? {
val parser = TootParser(activity, account)
var result : TootApiResult? var status : TootStatus? = null
// 元の投稿を削除する var credential_tmp : TootAccount? = null
if(redraft_status_id != null) {
result = if(account.isMisskey) {
val params = account.putMisskeyApiToken(JsonObject()).apply {
put("noteId", redraft_status_id)
}
client.request(
"/api/notes/delete",
params.toPostRequestBuilder()
)
} else {
client.request(
"/api/v1/statuses/$redraft_status_id",
Request.Builder().delete()
)
}
log.d("delete redraft. result=$result")
Thread.sleep(2000L)
} else if(scheduledId != null) {
val r1 = client.request(
"/api/v1/scheduled_statuses/$scheduledId",
Request.Builder().delete()
)
log.d("delete old scheduled status. result=$r1")
Thread.sleep(2000L)
}
var visibility_checked : TootVisibility? = visibility var scheduledStatusSucceeded = false
val (instance, ri) = TootInstance.get(client) fun getCredential(
instance ?: return ri client : TootApiClient,
parser : TootParser
if(instance.instanceType == TootInstance.InstanceType.Pixelfed) { ) : TootApiResult? {
if(in_reply_to_id != null && attachment_list?.isNotEmpty() == true) { val result = client.request("/api/v1/accounts/verify_credentials")
return TootApiResult(activity.getString(R.string.pixelfed_does_not_allow_reply_with_media)) credential_tmp = parser.account(result?.jsonObject)
}
if(in_reply_to_id == null && attachment_list?.isNotEmpty() != true) {
return TootApiResult(activity.getString(R.string.pixelfed_does_not_allow_post_without_media))
}
}
if(visibility == TootVisibility.WebSetting) {
visibility_checked =
if(account.isMisskey || instance.versionGE(TootInstance.VERSION_1_6)) {
null
} else {
val r2 = getCredential(client,parser)
val credential_tmp = this.credential_tmp ?: return r2
val privacy = credential_tmp.source?.privacy
?: return TootApiResult(activity.getString(R.string.cant_get_web_setting_visibility))
TootVisibility.parseMastodon(privacy)
}
}
val json = JsonObject()
try {
if(account.isMisskey) {
account.putMisskeyApiToken(json)
json["text"] = EmojiDecoder.decodeShortCode(
content,
emojiMapCustom = emojiMapCustom
)
if(visibility_checked != null) {
if(visibility_checked == TootVisibility.DirectSpecified || visibility_checked == TootVisibility.DirectPrivate) {
val userIds = JsonArray()
val m = TootAccount.reMisskeyMentionPost.matcher(content)
while(m.find()) {
val username = m.groupEx(1)
val host = m.groupEx(2) // may null
result = client.request(
"/api/users/show",
account.putMisskeyApiToken().apply {
if(username?.isNotEmpty() == true)
put("username", username)
if(host?.isNotEmpty() == true)
put("host", host)
}.toPostRequestBuilder()
)
val id = result?.jsonObject?.string("id")
if(id?.isNotEmpty() == true) {
userIds.add(id)
}
}
json["visibility"] = when {
userIds.isNotEmpty() -> {
json["visibleUserIds"] = userIds
"specified"
}
account.misskeyVersion >= 11 -> "specified"
else -> "private"
}
} else {
val localVis = visibility_checked.strMisskey.replace(
"^local-".toRegex(),
""
)
if(localVis != visibility_checked.strMisskey) {
json["localOnly"] = true
json["visibility"] = localVis
} else {
json["visibility"] = visibility_checked.strMisskey
}
}
}
if(spoiler_text?.isNotEmpty() == true) {
json["cw"] = EmojiDecoder.decodeShortCode(
spoiler_text,
emojiMapCustom = emojiMapCustom
)
}
if(in_reply_to_id != null) {
if(useQuoteToot) {
json["renoteId"] = in_reply_to_id.toString()
} else {
json["replyId"] = in_reply_to_id.toString()
}
}
json["viaMobile"] = true
if(attachment_list != null) {
val array = JsonArray()
for(pa in attachment_list) {
val a = pa.attachment ?: continue
// Misskeyは画像の再利用に問題がないので redraftとバージョンのチェックは行わない
array.add(a.id.toString())
// Misskeyの場合、NSFWするにはアップロード済みの画像を drive/files/update で更新する
if(bNSFW) {
val r = client.request(
"/api/drive/files/update",
account.putMisskeyApiToken().apply {
put("fileId", a.id.toString())
put("isSensitive", true)
}
.toPostRequestBuilder()
)
if(r == null || r.error != null) return r
}
}
if(array.isNotEmpty()) json["mediaIds"] = array
}
if(enquete_items?.isNotEmpty() == true) {
val choices = JsonArray().apply {
for(item in enquete_items) {
val text = EmojiDecoder.decodeShortCode(
item,
emojiMapCustom = emojiMapCustom
)
if(text.isEmpty()) continue
add(text)
}
}
if(choices.isNotEmpty()) {
json["poll"] = jsonObject {
put("choices", choices)
}
}
}
if(scheduledAt != 0L) {
return TootApiResult("misskey has no scheduled status API")
}
} else {
json["status"] = EmojiDecoder.decodeShortCode(
content,
emojiMapCustom = emojiMapCustom
)
if(visibility_checked != null) {
json["visibility"] = visibility_checked.strMastodon
}
json["sensitive"] = bNSFW
json["spoiler_text"] = EmojiDecoder.decodeShortCode(
spoiler_text ?: "",
emojiMapCustom = emojiMapCustom
)
if(in_reply_to_id != null) {
if(useQuoteToot) {
json["quote_id"] = in_reply_to_id.toString()
} else {
json["in_reply_to_id"] = in_reply_to_id.toString()
}
}
if(attachment_list != null) {
json["media_ids"] = jsonArray {
for(pa in attachment_list) {
val a = pa.attachment ?: continue
if(a.redraft && ! instance.versionGE(TootInstance.VERSION_2_4_1)) continue
add(a.id.toString())
}
}
}
if(enquete_items?.isNotEmpty() == true) {
if(poll_type == TootPollsType.Mastodon) {
json["poll"] = jsonObject {
put("multiple", poll_multiple_choice)
put("hide_totals", poll_hide_totals)
put("expires_in", poll_expire_seconds)
put("options",
enquete_items.map {
EmojiDecoder.decodeShortCode(
it,
emojiMapCustom = emojiMapCustom
)
}
.toJsonArray()
)
}
} else {
json["isEnquete"] = true
json["enquete_items"] = enquete_items.map {
EmojiDecoder.decodeShortCode(
it,
emojiMapCustom = emojiMapCustom
)
}.toJsonArray()
}
}
if(scheduledAt != 0L) {
if(! instance.versionGE(TootInstance.VERSION_2_7_0_rc1)) {
return TootApiResult(activity.getString(R.string.scheduled_status_requires_mastodon_2_7_0))
}
// UTCの日時を渡す
val c = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"))
c.timeInMillis = scheduledAt
val sv = String.format(
"%d-%02d-%02d %02d:%02d:%02d",
c.get(Calendar.YEAR),
c.get(Calendar.MONTH) + 1,
c.get(Calendar.DAY_OF_MONTH),
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND)
)
json["scheduled_at"] = sv
}
}
} catch(ex : JsonException) {
log.trace(ex)
log.e(ex, "status encoding failed.")
}
val body_string = json.toString()
val request_builder = body_string.toRequestBody(MEDIA_TYPE_JSON).toPost()
if(! Pref.bpDontDuplicationCheck(pref)) {
val digest = (body_string + account.acct.ascii).digestSHA256Hex()
request_builder.header("Idempotency-Key", digest)
}
result = if(account.isMisskey) {
// log.d("misskey json %s", body_string)
client.request("/api/notes/create", request_builder)
} else {
client.request("/api/v1/statuses", request_builder)
}
val jsonObject = result?.jsonObject
if(scheduledAt != 0L && jsonObject != null) {
// {"id":"3","scheduled_at":"2019-01-06T07:08:00.000Z","media_attachments":[]}
scheduledStatusSucceeded = true
return result return result
} }
val status = parser.status( override fun background(client : TootApiClient) : TootApiResult? {
if(account.isMisskey) { val parser = TootParser(activity, account)
result?.jsonObject?.jsonObject("createdNote") ?: result?.jsonObject
} else {
result?.jsonObject
}
)
this.status = status
if(status != null) {
// タグを覚えておく var result : TootApiResult?
val s = status.decoded_content
val span_list = s.getSpans(0, s.length, MyClickableSpan::class.java) // 元の投稿を削除する
if(span_list != null) { if(redraft_status_id != null) {
val tag_list = ArrayList<String?>(span_list.size) result = if(account.isMisskey) {
for(span in span_list) { val params = account.putMisskeyApiToken(JsonObject()).apply {
val start = s.getSpanStart(span) put("noteId", redraft_status_id)
val end = s.getSpanEnd(span)
val text = s.subSequence(start, end).toString()
if(text.startsWith("#")) {
tag_list.add(text.substring(1))
} }
client.request(
"/api/notes/delete",
params.toPostRequestBuilder()
)
} else {
client.request(
"/api/v1/statuses/$redraft_status_id",
Request.Builder().delete()
)
} }
val count = tag_list.size log.d("delete redraft. result=$result")
if(count > 0) { Thread.sleep(2000L)
TagSet.saveList(System.currentTimeMillis(), tag_list, 0, count) } else if(scheduledId != null) {
val r1 = client.request(
"/api/v1/scheduled_statuses/$scheduledId",
Request.Builder().delete()
)
log.d("delete old scheduled status. result=$r1")
Thread.sleep(2000L)
}
var visibility_checked : TootVisibility? = visibility
val (instance, ri) = TootInstance.get(client)
instance ?: return ri
if(instance.instanceType == TootInstance.InstanceType.Pixelfed) {
if(in_reply_to_id != null && attachment_list?.isNotEmpty() == true) {
return TootApiResult(activity.getString(R.string.pixelfed_does_not_allow_reply_with_media))
}
if(in_reply_to_id == null && attachment_list?.isNotEmpty() != true) {
return TootApiResult(activity.getString(R.string.pixelfed_does_not_allow_post_without_media))
}
}
if(visibility == TootVisibility.WebSetting) {
visibility_checked =
if(account.isMisskey || instance.versionGE(TootInstance.VERSION_1_6)) {
null
} else {
val r2 = getCredential(client, parser)
val credential_tmp = this.credential_tmp ?: return r2
val privacy = credential_tmp.source?.privacy
?: return TootApiResult(activity.getString(R.string.cant_get_web_setting_visibility))
TootVisibility.parseMastodon(privacy)
}
}
val json = JsonObject()
try {
if(account.isMisskey) {
account.putMisskeyApiToken(json)
json["text"] = EmojiDecoder.decodeShortCode(
content,
emojiMapCustom = emojiMapCustom
)
if(visibility_checked != null) {
if(visibility_checked == TootVisibility.DirectSpecified || visibility_checked == TootVisibility.DirectPrivate) {
val userIds = JsonArray()
val m = TootAccount.reMisskeyMentionPost.matcher(content)
while(m.find()) {
val username = m.groupEx(1)
val host = m.groupEx(2) // may null
result = client.request(
"/api/users/show",
account.putMisskeyApiToken().apply {
if(username?.isNotEmpty() == true)
put("username", username)
if(host?.isNotEmpty() == true)
put("host", host)
}.toPostRequestBuilder()
)
val id = result?.jsonObject?.string("id")
if(id?.isNotEmpty() == true) {
userIds.add(id)
}
}
json["visibility"] = when {
userIds.isNotEmpty() -> {
json["visibleUserIds"] = userIds
"specified"
}
account.misskeyVersion >= 11 -> "specified"
else -> "private"
}
} else {
val localVis = visibility_checked.strMisskey.replace(
"^local-".toRegex(),
""
)
if(localVis != visibility_checked.strMisskey) {
json["localOnly"] = true
json["visibility"] = localVis
} else {
json["visibility"] = visibility_checked.strMisskey
}
}
}
if(spoiler_text?.isNotEmpty() == true) {
json["cw"] = EmojiDecoder.decodeShortCode(
spoiler_text,
emojiMapCustom = emojiMapCustom
)
}
if(in_reply_to_id != null) {
if(useQuoteToot) {
json["renoteId"] = in_reply_to_id.toString()
} else {
json["replyId"] = in_reply_to_id.toString()
}
}
json["viaMobile"] = true
if(attachment_list != null) {
val array = JsonArray()
for(pa in attachment_list) {
val a = pa.attachment ?: continue
// Misskeyは画像の再利用に問題がないので redraftとバージョンのチェックは行わない
array.add(a.id.toString())
// Misskeyの場合、NSFWするにはアップロード済みの画像を drive/files/update で更新する
if(bNSFW) {
val r = client.request(
"/api/drive/files/update",
account.putMisskeyApiToken().apply {
put("fileId", a.id.toString())
put("isSensitive", true)
}
.toPostRequestBuilder()
)
if(r == null || r.error != null) return r
}
}
if(array.isNotEmpty()) json["mediaIds"] = array
}
if(enquete_items?.isNotEmpty() == true) {
val choices = JsonArray().apply {
for(item in enquete_items) {
val text = EmojiDecoder.decodeShortCode(
item,
emojiMapCustom = emojiMapCustom
)
if(text.isEmpty()) continue
add(text)
}
}
if(choices.isNotEmpty()) {
json["poll"] = jsonObject {
put("choices", choices)
}
}
}
if(scheduledAt != 0L) {
return TootApiResult("misskey has no scheduled status API")
}
} else {
json["status"] = EmojiDecoder.decodeShortCode(
content,
emojiMapCustom = emojiMapCustom
)
if(visibility_checked != null) {
json["visibility"] = visibility_checked.strMastodon
}
json["sensitive"] = bNSFW
json["spoiler_text"] = EmojiDecoder.decodeShortCode(
spoiler_text ?: "",
emojiMapCustom = emojiMapCustom
)
if(in_reply_to_id != null) {
if(useQuoteToot) {
json["quote_id"] = in_reply_to_id.toString()
} else {
json["in_reply_to_id"] = in_reply_to_id.toString()
}
}
if(attachment_list != null) {
json["media_ids"] = jsonArray {
for(pa in attachment_list) {
val a = pa.attachment ?: continue
if(a.redraft && ! instance.versionGE(TootInstance.VERSION_2_4_1)) continue
add(a.id.toString())
}
}
}
if(enquete_items?.isNotEmpty() == true) {
if(poll_type == TootPollsType.Mastodon) {
json["poll"] = jsonObject {
put("multiple", poll_multiple_choice)
put("hide_totals", poll_hide_totals)
put("expires_in", poll_expire_seconds)
put("options",
enquete_items.map {
EmojiDecoder.decodeShortCode(
it,
emojiMapCustom = emojiMapCustom
)
}
.toJsonArray()
)
}
} else {
json["isEnquete"] = true
json["enquete_items"] = enquete_items.map {
EmojiDecoder.decodeShortCode(
it,
emojiMapCustom = emojiMapCustom
)
}.toJsonArray()
}
}
if(scheduledAt != 0L) {
if(! instance.versionGE(TootInstance.VERSION_2_7_0_rc1)) {
return TootApiResult(activity.getString(R.string.scheduled_status_requires_mastodon_2_7_0))
}
// UTCの日時を渡す
val c = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"))
c.timeInMillis = scheduledAt
val sv = String.format(
"%d-%02d-%02d %02d:%02d:%02d",
c.get(Calendar.YEAR),
c.get(Calendar.MONTH) + 1,
c.get(Calendar.DAY_OF_MONTH),
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND)
)
json["scheduled_at"] = sv
}
}
} catch(ex : JsonException) {
log.trace(ex)
log.e(ex, "status encoding failed.")
}
val body_string = json.toString()
val request_builder = body_string.toRequestBody(MEDIA_TYPE_JSON).toPost()
if(! Pref.bpDontDuplicationCheck(pref)) {
val digest = (body_string + account.acct.ascii).digestSHA256Hex()
request_builder.header("Idempotency-Key", digest)
}
result = if(account.isMisskey) {
// log.d("misskey json %s", body_string)
client.request("/api/notes/create", request_builder)
} else {
client.request("/api/v1/statuses", request_builder)
}
val jsonObject = result?.jsonObject
if(scheduledAt != 0L && jsonObject != null) {
// {"id":"3","scheduled_at":"2019-01-06T07:08:00.000Z","media_attachments":[]}
scheduledStatusSucceeded = true
return result
}
val status = parser.status(
if(account.isMisskey) {
result?.jsonObject?.jsonObject("createdNote") ?: result?.jsonObject
} else {
result?.jsonObject
}
)
this.status = status
if(status != null) {
// タグを覚えておく
val s = status.decoded_content
val span_list = s.getSpans(0, s.length, MyClickableSpan::class.java)
if(span_list != null) {
val tag_list = ArrayList<String?>(span_list.size)
for(span in span_list) {
val start = s.getSpanStart(span)
val end = s.getSpanEnd(span)
val text = s.subSequence(start, end).toString()
if(text.startsWith("#")) {
tag_list.add(text.substring(1))
}
}
val count = tag_list.size
if(count > 0) {
TagSet.saveList(System.currentTimeMillis(), tag_list, 0, count)
}
} }
} }
return result
} }
return result
} override fun handleResult(result : TootApiResult?) {
result ?: return
override fun handleResult(result : TootApiResult?) { val status = this.status
result ?: return when {
val status = this.status status != null -> {
when { // 連投してIdempotency が同じだった場合もエラーにはならず、ここを通る
status != null -> { callback.onPostComplete(account, status)
// 連投してIdempotency が同じだった場合もエラーにはならず、ここを通る return
callback.onPostComplete(account, status) }
return
}
scheduledStatusSucceeded -> {
callback.onScheduledPostComplete(account)
return
scheduledStatusSucceeded -> {
callback.onScheduledPostComplete(account)
return
}
else -> activity.showToast(true, result.error)
} }
else -> showToast(activity, true, result.error)
} }
} })
}) )
)
} }
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
@ -890,12 +893,7 @@ class PostHelper(
sb.append(item.alias) sb.append(item.alias)
sb.append(": → ") sb.append(": → ")
sb.setSpan( sb.setSpan(
ForegroundColorSpan( ForegroundColorSpan(activity.getAttributeColor(R.attr.colorTimeSmall)),
getAttributeColor(
activity,
R.attr.colorTimeSmall
)
),
start, start,
sb.length, sb.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
@ -922,6 +920,7 @@ class PostHelper(
} }
interface Callback2 { interface Callback2 {
fun onTextUpdate() fun onTextUpdate()
fun canOpenPopup() : Boolean fun canOpenPopup() : Boolean
@ -1053,7 +1052,10 @@ class PostHelper(
proc_text_changed.run() proc_text_changed.run()
// キーボードを再度表示する // キーボードを再度表示する
App1.getAppState(activity,"PostHelper/EmojiPicker/cb").handler.post { et.showKeyboard() } App1.getAppState(
activity,
"PostHelper/EmojiPicker/cb"
).handler.post { et.showKeyboard() }
}.show() }.show()
} }
@ -1091,7 +1093,7 @@ class PostHelper(
fun openFeaturedTagList(list : List<TootTag>?) { fun openFeaturedTagList(list : List<TootTag>?) {
val ad = ActionsDialog() val ad = ActionsDialog()
list?.forEach {tag-> list?.forEach { tag ->
ad.addAction("#${tag.name}") { ad.addAction("#${tag.name}") {
val et = this.et ?: return@addAction val et = this.et ?: return@addAction
@ -1112,7 +1114,7 @@ class PostHelper(
proc_text_changed.run() proc_text_changed.run()
} }
} }
ad.addAction( activity.getString(R.string.input_sharp_itself)){ ad.addAction(activity.getString(R.string.input_sharp_itself)) {
val et = this.et ?: return@addAction val et = this.et ?: return@addAction
val src = et.text ?: "" val src = et.text ?: ""
@ -1124,7 +1126,7 @@ class PostHelper(
sb.append(src.subSequence(0, start)) sb.append(src.subSequence(0, start))
if(! EmojiDecoder.canStartHashtag(sb, sb.length)) sb.append(' ') if(! EmojiDecoder.canStartHashtag(sb, sb.length)) sb.append(' ')
sb.append('#') sb.append('#')
val newSelection = sb.length val newSelection = sb.length
if(end < src_length) sb.append(src.subSequence(end, src_length)) if(end < src_length) sb.append(src.subSequence(end, src_length))
et.text = sb et.text = sb

View File

@ -4,17 +4,12 @@ import android.content.DialogInterface
import jp.juggler.subwaytooter.api.TootApiResult import jp.juggler.subwaytooter.api.TootApiResult
import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.table.SavedAccount
/////////////////////////////////////////////////////////////////
// callback (that returns Unit)
typealias EmptyCallback = ()->Unit
typealias TootApiResultCallback = (result : TootApiResult) -> Unit typealias TootApiResultCallback = (result : TootApiResult) -> Unit
typealias SavedAccountCallback = (ai : SavedAccount) -> Unit typealias SavedAccountCallback = (ai : SavedAccount) -> Unit
typealias DialogInterfaceCallback = (dialog: DialogInterface) -> Unit typealias DialogInterfaceCallback = (dialog : DialogInterface) -> Unit
typealias ProgressResponseBodyCallback = (bytesRead : Long, bytesTotal : Long) -> Unit
typealias ProgressResponseBodyCallback = (bytesRead : Long, bytesTotal : Long)->Unit val emptyCallback : () -> Unit = {}

View File

@ -124,7 +124,7 @@ fun createResizedBitmap(
var src_width = options.outWidth var src_width = options.outWidth
var src_height = options.outHeight var src_height = options.outHeight
if(src_width <= 0 || src_height <= 0) { if(src_width <= 0 || src_height <= 0) {
showToast(context, false, "could not get image bounds.") context.showToast(false, "could not get image bounds.")
return null return null
} }
@ -204,7 +204,7 @@ fun createResizedBitmap(
} }
if(sourceBitmap == null) { if(sourceBitmap == null) {
showToast(context, false, "could not decode image.") context.showToast(false, "could not decode image.")
return null return null
} }
try { try {
@ -234,7 +234,7 @@ fun createResizedBitmap(
Bitmap.createBitmap(dstSizeInt.x, dstSizeInt.y, Bitmap.Config.ARGB_8888) Bitmap.createBitmap(dstSizeInt.x, dstSizeInt.y, Bitmap.Config.ARGB_8888)
try { try {
return if(dst == null) { return if(dst == null) {
showToast(context, false, "bitmap creation failed.") context.showToast(false, "bitmap creation failed.")
null null
} else { } else {
val canvas = Canvas(dst) val canvas = Canvas(dst)

View File

@ -45,19 +45,19 @@ object ToastUtils {
} }
fun showToast(context : Context, bLong : Boolean, fmt : String?, vararg args : Any) { fun Context.showToast(bLong : Boolean, fmt : String?, vararg args : Any) {
val msg = if(fmt == null) "(null)" else if(args.isEmpty()) fmt else String.format(fmt, *args) val msg = if(fmt == null) "(null)" else if(args.isEmpty()) fmt else String.format(fmt, *args)
ToastUtils.showToastImpl(context, bLong, msg) ToastUtils.showToastImpl(this, bLong, msg)
} }
fun showToast(context : Context, ex : Throwable, fmt : String?, vararg args : Any) { fun Context.showToast(ex : Throwable, fmt : String?, vararg args : Any) {
ToastUtils.showToastImpl(context, true, ex.withCaption(fmt, *args)) ToastUtils.showToastImpl(this, true, ex.withCaption(fmt, *args))
} }
fun showToast(context : Context, bLong : Boolean, string_id : Int, vararg args : Any) { fun Context.showToast(bLong : Boolean, string_id : Int, vararg args : Any) {
ToastUtils.showToastImpl(context, bLong, context.getString(string_id, *args)) ToastUtils.showToastImpl(this, bLong, getString(string_id, *args))
} }
fun showToast(context : Context, ex : Throwable, string_id : Int, vararg args : Any) { fun Context.showToast(ex : Throwable, string_id : Int, vararg args : Any) {
ToastUtils.showToastImpl(context, true, ex.withCaption(context.resources, string_id, *args)) ToastUtils.showToastImpl(this, true, ex.withCaption(resources, string_id, *args))
} }

View File

@ -37,8 +37,7 @@ fun Int.applyAlphaMultiplier(alphaMultiplier : Float? = null) : Int {
} }
} }
fun getAttributeColor(context : Context, attrId : Int) : Int { fun Context.getAttributeColor(attrId : Int) : Int {
val theme = context.theme
val a = theme.obtainStyledAttributes(intArrayOf(attrId)) val a = theme.obtainStyledAttributes(intArrayOf(attrId))
val color = a.getColor(0, Color.BLACK) val color = a.getColor(0, Color.BLACK)
a.recycle() a.recycle()
@ -298,10 +297,10 @@ fun CharSequence.copyToClipboard(context : Context) {
clipboard.setPrimaryClip(clip) clipboard.setPrimaryClip(clip)
showToast(context, false, R.string.copy_complete) context.showToast(false, R.string.copy_complete)
} catch(ex : Throwable) { } catch(ex : Throwable) {
UiUtils.log.trace(ex) UiUtils.log.trace(ex)
showToast(context, ex, "copy failed.") context.showToast(ex, "copy failed.")
} }
} }

View File

@ -98,23 +98,20 @@ var CompoundButton.isCheckedNoAnime : Boolean
jumpDrawablesToCurrentState() jumpDrawablesToCurrentState()
} }
private fun mixColor(col1 : Int, col2 : Int) : Int = Color.rgb( private fun mixColor(col1 : Int, col2 : Int) : Int = Color.rgb(
(Color.red(col1) + Color.red(col2)) ushr 1, (Color.red(col1) + Color.red(col2)) ushr 1,
(Color.green(col1) + Color.green(col2)) ushr 1, (Color.green(col1) + Color.green(col2)) ushr 1,
(Color.blue(col1) + Color.blue(col2)) ushr 1 (Color.blue(col1) + Color.blue(col2)) ushr 1
) )
fun setSwitchColor( fun Context.setSwitchColor(
activity : AppCompatActivity,
pref : SharedPreferences, pref : SharedPreferences,
root : View? root : View?
) { ) {
val colorBg = getAttributeColor(activity, R.attr.colorWindowBackground) val colorBg = getAttributeColor(R.attr.colorWindowBackground)
val colorOn = Pref.ipSwitchOnColor(pref) val colorOn = Pref.ipSwitchOnColor(pref)
val colorOff = /* Pref.ipSwitchOffColor(pref).notZero() ?: */ val colorOff = /* Pref.ipSwitchOffColor(pref).notZero() ?: */
getAttributeColor(activity, android.R.attr.colorPrimary) getAttributeColor(android.R.attr.colorPrimary)
val colorDisabled = mixColor(colorBg, colorOff) val colorDisabled = mixColor(colorBg, colorOff)
@ -157,7 +154,6 @@ fun setSwitchColor(
} }
} }
private fun rgbToLab(rgb : Int) : Triple<Float, Float, Float> { private fun rgbToLab(rgb : Int) : Triple<Float, Float, Float> {
fun Int.revGamma() : Float { fun Int.revGamma() : Float {
@ -193,9 +189,9 @@ private fun rgbToLab(rgb : Int) : Triple<Float, Float, Float> {
) )
} }
fun setStatusBarColor(activity : Activity, forceDark : Boolean = false) { fun AppCompatActivity.setStatusBarColor(forceDark : Boolean = false) {
activity.window?.apply { window?.apply {
// 古い端末ではナビゲーションバーのアイコン色を設定できないため // 古い端末ではナビゲーションバーのアイコン色を設定できないため
// メディアビューア画面ではステータスバーやナビゲーションバーの色を設定しない… // メディアビューア画面ではステータスバーやナビゲーションバーの色を設定しない…
@ -211,7 +207,7 @@ fun setStatusBarColor(activity : Activity, forceDark : Boolean = false) {
var c = when { var c = when {
forceDark -> Color.BLACK forceDark -> Color.BLACK
else -> Pref.ipStatusBarColor(App1.pref).notZero() else -> Pref.ipStatusBarColor(App1.pref).notZero()
?: getAttributeColor(activity, R.attr.colorPrimaryDark) ?: getAttributeColor(R.attr.colorPrimaryDark)
} }
statusBarColor = c or Color.BLACK statusBarColor = c or Color.BLACK