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.TextView
import androidx.appcompat.app.AppCompatActivity
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.LogCategory
class ActAbout : AppCompatActivity() {
class Translators(
val name:String,
val acct:String?,
val lang:String
val name : String,
val acct : String?,
val lang : String
)
companion object {
val log = LogCategory("ActAbout")
const val EXTRA_SEARCH = "search"
@ -33,22 +35,22 @@ class ActAbout : AppCompatActivity() {
// git log --pretty=format:"%an %s" |grep "Translated using Weblate"|sort|uniq
val translators = arrayOf(
Translators("Allan Nordhøy",null,"English & Norwegian Bokmål"),
Translators("ButterflyOfFire","@ButterflyOfFire@mstdn.fr", "Arabic & French"),
Translators("Ch",null,"Korean"),
Translators("Elizabeth Sherrock",null,"Chinese (Simplified)"),
Translators("Gennady Archangorodsky",null,"Hebrew"),
Translators("inqbs Siina",null,"Korean"),
Translators("Jeong Arm","@jarm@qdon.space","Korean"),
Translators("Joan Pujolar","@jpujolar@mastodont.cat","Catalan"),
Translators("Kai Zhang","@bearzk@mastodon.social","Chinese (Simplified)"),
Translators("lptprjh",null,"Korean"),
Translators("mynameismonkey",null,"Welsh"),
Translators("Nathan",null,"French"),
Translators("Owain Rhys Lewis",null,"Welsh"),
Translators("Swann Martinet",null,"French"),
Translators("takubunn",null,"Chinese (Simplified)"),
Translators("배태길",null,"Korea")
Translators("Allan Nordhøy", null, "English & Norwegian Bokmål"),
Translators("ButterflyOfFire", "@ButterflyOfFire@mstdn.fr", "Arabic & French"),
Translators("Ch", null, "Korean"),
Translators("Elizabeth Sherrock", null, "Chinese (Simplified)"),
Translators("Gennady Archangorodsky", null, "Hebrew"),
Translators("inqbs Siina", null, "Korean"),
Translators("Jeong Arm", "@jarm@qdon.space", "Korean"),
Translators("Joan Pujolar", "@jpujolar@mastodont.cat", "Catalan"),
Translators("Kai Zhang", "@bearzk@mastodon.social", "Chinese (Simplified)"),
Translators("lptprjh", null, "Korean"),
Translators("mynameismonkey", null, "Welsh"),
Translators("Nathan", null, "French"),
Translators("Owain Rhys Lewis", null, "Welsh"),
Translators("Swann Martinet", null, "French"),
Translators("takubunn", null, "Chinese (Simplified)"),
Translators("배태길", null, "Korea")
)
}
@ -69,7 +71,7 @@ class ActAbout : AppCompatActivity() {
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)
b.text = caption
b.setOnClickListener { onClick() }
@ -80,9 +82,6 @@ class ActAbout : AppCompatActivity() {
finish()
}
fun openUrl(url : String) {
App1.openBrowser(this@ActAbout, url)
}
setButton(
R.id.btnDeveloper,
@ -94,10 +93,14 @@ class ActAbout : AppCompatActivity() {
getString(R.string.search_for, 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) { openUrl(url_futaba) }
setButton(R.id.btnWeblate, getString(R.string.please_help_translation) ) { openUrl(url_weblate) }
// setButton(R.id.btnIconDesign, url_futaba)
// { openUrl(url_futaba) }
setButton(R.id.btnWeblate, getString(R.string.please_help_translation))
{ openBrowser(url_weblate) }
val ll = findViewById<LinearLayout>(R.id.llContributors)
val density = resources.displayMetrics.density
@ -117,7 +120,7 @@ class ActAbout : AppCompatActivity() {
setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
setPadding(padding, padding, padding, padding)
isAllCaps = false
//
val acct = who.acct ?: "@?@?"
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)
setSwitchColor(this, pref, root)
setSwitchColor(pref, root)
tvInstance = findViewById(R.id.tvInstance)
tvUser = findViewById(R.id.tvUser)
@ -529,7 +529,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
tvUserCustom.backgroundColor = ac.color_bg
tvUserCustom.text = ac.nickname
tvUserCustom.textColor = ac.color_fg.notZero()
?: getAttributeColor(this, R.attr.colorTimeSmall)
?: getAttributeColor(R.attr.colorTimeSmall)
}
private fun saveUIToData() {
@ -590,10 +590,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
R.id.btnAccountRemove -> performAccountRemove()
R.id.btnLoadPreference -> performLoadPreference()
R.id.btnVisibility -> performVisibility()
R.id.btnOpenBrowser -> App1.openBrowser(
this@ActAccountSetting,
"https://${account.apiHost.ascii}/"
)
R.id.btnOpenBrowser -> openBrowser("https://${account.apiHost.ascii}/")
R.id.btnPushSubscription -> startTest()
R.id.btnUserCustom -> ActNickname.open(
@ -694,7 +691,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
val json = result.jsonObject
if(json == null) {
showToast(this@ActAccountSetting, true, result.error)
showToast(true, result.error)
return
}
@ -745,7 +742,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
.setPositiveButton(R.string.ok) { _, _ ->
account.delete()
val pref = Pref.pref(this@ActAccountSetting)
val pref = pref()
if(account.db_id == Pref.lpTabletTootDefaultAccount(pref)) {
pref.edit().put(Pref.lpTabletTootDefaultAccount, - 1L).apply()
}
@ -810,7 +807,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
}
error != null -> {
showToast(this@ActAccountSetting, true, error)
showToast(true, error)
log.e("can't get oauth browser URL. $error")
}
}
@ -921,7 +918,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
if(data != null) {
showProfile(data)
} else {
showToast(this@ActAccountSetting, true, result.error)
showToast(true, result.error)
}
}
@ -1248,7 +1245,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
if(data != null) {
showProfile(data)
} else {
showToast(this@ActAccountSetting, true, result.error)
showToast(true, result.error)
for(arg in args) {
val key = arg.first
val value = arg.second
@ -1401,7 +1398,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
)
return
}
showToast(this, true, R.string.missing_permission_to_access_media)
showToast(true, R.string.missing_permission_to_access_media)
}
override fun onRequestPermissionsResult(
@ -1413,7 +1410,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openPicker(requestCode)
} 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)
} catch(ex : Throwable) {
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)
} catch(ex : Throwable) {
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 {
val cache_dir = externalCacheDir
if(cache_dir == null) {
showToast(this, false, "getExternalCacheDir returns null.")
showToast(false, "getExternalCacheDir returns null.")
break
}
@ -1522,7 +1519,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
} catch(ex : Throwable) {
log.trace(ex, "Resizing image failed.")
showToast(this, ex, "Resizing image failed.")
showToast(ex, "Resizing image failed.")
}
break
@ -1549,12 +1546,12 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
private fun addAttachment(request_code : Int, uri : Uri, mime_type : String?) {
if(mime_type == null) {
showToast(this, false, "mime type is not provided.")
showToast(false, "mime type is not provided.")
return
}
if(! mime_type.startsWith("image/")) {
showToast(this, false, "mime type is not image.")
showToast(false, "mime type is not image.")
return
}
@ -1583,7 +1580,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
)
override fun background(client : TootApiClient) : TootApiResult? {
return wps.updateSubscription(client,true)
return wps.updateSubscription(client, true)
}
override fun handleResult(result : TootApiResult?) {

View File

@ -81,7 +81,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
App1.setActivityTheme(this, noActionBar = true)
this.handler = App1.getAppState(this).handler
this.pref = Pref.pref(this)
this.pref = pref()
// val intent = this.intent
// val layoutId = intent.getIntExtra(EXTRA_LAYOUT_ID, 0)
@ -373,7 +373,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val margin_tb = dip(6)
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")
showCaption(name)
swSwitch.vg(false) // skip animation
setSwitchColor(activity, pref, swSwitch)
setSwitchColor(pref, swSwitch)
swSwitch.isEnabled = item.enabled
swSwitch.isChecked = bp(pref)
swSwitch.vg(true)
@ -840,7 +840,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val intent = intentOpenDocument("*/*")
startActivityForResult(intent, REQUEST_CODE_APP_DATA_IMPORT)
} 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() =
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? {
try {
if(uri == null) {
showToast(this, false, "missing uri.")
showToast(false, "missing uri.")
return null
}
@ -969,7 +969,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val source : InputStream? = contentResolver.openInputStream(uri)
if(source == null) {
showToast(this, false, "openInputStream returns null. uri=%s", uri)
showToast(false, "openInputStream returns null. uri=%s", uri)
return null
} else {
source.use { inStream ->
@ -981,20 +981,20 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
val face = Typeface.createFromFile(tmp_file)
if(face == null) {
showToast(this, false, "Typeface.createFromFile() failed.")
showToast(false, "Typeface.createFromFile() failed.")
return null
}
val file = File(dir, file_name)
if(! tmp_file.renameTo(file)) {
showToast(this, false, "File operation failed.")
showToast(false, "File operation failed.")
return null
}
return file
} catch(ex : Throwable) {
log.trace(ex)
showToast(this, ex, "saveTimelineFont failed.")
showToast(ex, "saveTimelineFont failed.")
return null
}
@ -1177,10 +1177,10 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi
}
) { setCustomShare(target, it) }
.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) {
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 {
companion object {
internal val log = LogCategory("ActColumnCustomize")
internal const val EXTRA_COLUMN_INDEX = "column_index"
@ -298,7 +299,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
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) {
EditorInfo.IME_ACTION_DONE -> {
etAlpha.hideKeyboard()
true
}
else -> false
}
}
}
private fun show() {
try {
loading_busy = true

View File

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

View File

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

View File

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

View File

@ -136,7 +136,7 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
val tvName : TextView
private val btnSound : View
private val ivSpeech: ImageButton
private val ivSpeech : ImageButton
init {
@ -160,15 +160,15 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
tvName.setBackgroundColor(item.color_bg)
tvName.setTextColor(
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)
tag = item
}
ivSpeech.vg(item.speech != 0 )?.apply{
ivSpeech.vg(item.speech != 0)?.apply {
setOnClickListener(this@MyViewHolder)
tag = item
}
@ -189,12 +189,14 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
override fun onClick(v : View) {
val o = v.tag
if(o is HighlightWord) {
when(v.id){
R.id.btnSound->{
when(v.id) {
R.id.btnSound -> {
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) {
override fun onBindDragView(clickedView : View, dragView : View) {
dragView.findViewById<TextView>(R.id.tvName).text =
clickedView.findViewById<TextView>(R.id.tvName).text
dragView.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
dragView.findViewById<View>(R.id.item_layout).setBackgroundColor(
getAttributeColor(
this@ActHighlightWordList,
R.attr.list_item_bg_pressed_dragged
)
)
dragView.findViewById<View>(R.id.item_layout)
.setBackgroundColor(getAttributeColor(R.attr.list_item_bg_pressed_dragged))
}
}
@ -250,23 +248,27 @@ class ActHighlightWordList : AppCompatActivity(), View.OnClickListener {
}
private fun create() {
DlgTextInput.show(this, getString(R.string.new_item), "", callback = object : DlgTextInput.Callback {
override fun onEmptyError() {
showToast(this@ActHighlightWordList, true, R.string.word_empty)
}
override fun onOK(dialog : Dialog, text : String) {
var item = HighlightWord.load(text)
if(item == null) {
item = HighlightWord(text)
item.save(this@ActHighlightWordList)
loadData()
DlgTextInput.show(
this,
getString(R.string.new_item),
"",
callback = object : DlgTextInput.Callback {
override fun onEmptyError() {
showToast(true, R.string.word_empty)
}
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) {

View File

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

View File

@ -33,6 +33,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
)
companion object {
internal val log = LogCategory("ActLanguageFilter")
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)
)
tv.textColor = getAttributeColor(
this@ActLanguageFilter, when(item.allow) {
when(item.allow) {
true -> R.attr.colorContentText
false -> R.attr.colorRegexFilterError
}
@ -310,6 +311,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
private object DlgLanguageFilter {
interface Callback {
fun onOK(code : String, allow : Boolean)
fun onDelete(code : String)
}
@ -371,7 +373,7 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
btnPresets.setEnabledColor(
activity,
R.drawable.ic_edit,
getAttributeColor(activity, R.attr.colorVectorDrawable),
activity.getAttributeColor(R.attr.colorVectorDrawable),
false
)
}
@ -439,9 +441,8 @@ class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
val intent = intentOpenDocument("*/*")
startActivityForResult(intent, REQUEST_CODE_IMPORT)
} catch(ex : Throwable) {
showToast(this, ex, "import failed.")
showToast(ex, "import failed.")
}
}
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)}")
val source = contentResolver.openInputStream(uri)
if(source == null) {
showToast( true, "openInputStream failed.")
showToast(true, "openInputStream failed.")
null
} else {
source.use { inStream ->

View File

@ -176,41 +176,41 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
//////////////////////////////////////////////////////////////////
// 変更しない変数
val follow_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.follow_succeeded)
val follow_complete_callback : ()->Unit = {
showToast(false, R.string.follow_succeeded)
}
val unfollow_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.unfollow_succeeded)
val unfollow_complete_callback : ()->Unit = {
showToast(false, R.string.unfollow_succeeded)
}
val cancel_follow_request_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.follow_request_cancelled)
val cancel_follow_request_complete_callback : ()->Unit = {
showToast(false, R.string.follow_request_cancelled)
}
val favourite_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.favourite_succeeded)
val favourite_complete_callback : ()->Unit = {
showToast(false, R.string.favourite_succeeded)
}
val unfavourite_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.unfavourite_succeeded)
val unfavourite_complete_callback : ()->Unit = {
showToast(false, R.string.unfavourite_succeeded)
}
val bookmark_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.bookmark_succeeded)
val bookmark_complete_callback : ()->Unit = {
showToast(false, R.string.bookmark_succeeded)
}
val unbookmark_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.unbookmark_succeeded)
val unbookmark_complete_callback : ()->Unit = {
showToast(false, R.string.unbookmark_succeeded)
}
val boost_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.boost_succeeded)
val boost_complete_callback : ()->Unit = {
showToast(false, R.string.boost_succeeded)
}
val unboost_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.unboost_succeeded)
val unboost_complete_callback : ()->Unit = {
showToast(false, R.string.unboost_succeeded)
}
val reaction_complete_callback : EmptyCallback = {
showToast(this@ActMain, false, R.string.reaction_succeeded)
val reaction_complete_callback : ()->Unit = {
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)
MyClickableSpan.showLinkUnderline = Pref.bpShowLinkUnderline(pref)
MyClickableSpan.defaultLinkColor = Pref.ipLinkColor(pref).notZero()
?: getAttributeColor(this, R.attr.colorLink)
?: getAttributeColor(R.attr.colorLink)
CustomShare.reloadCache(this, pref)
te = SystemClock.elapsedRealtime()
@ -1099,7 +1100,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
}
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) {
val db_id = data.getLongExtra(ActAccountSetting.EXTRA_DB_ID, - 1L)
checkAccessToken2(db_id)
@ -1195,7 +1196,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
) {
this@ActMain.finish()
} 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 -> {
showToast(
this@ActMain,
false,
R.string.cant_close_column_by_back_button_when_multiple_column_shown
)
@ -2048,28 +2048,25 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
// cancelled.
}
error != null -> showToast(
this@ActMain,
true,
"${result.error} ${result.requestInfo}".trim()
)
error != null ->
showToast(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 ->
if(sa.username != ta.username) {
showToast(this@ActMain, true, R.string.user_name_not_match)
showToast(true, R.string.user_name_not_match)
} else {
showToast(
this@ActMain,
false,
R.string.access_token_updated_for,
sa.acct.pretty
@ -2100,7 +2097,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val apDomain = ti?.uri
if(apDomain == null) {
showToast(this@ActMain, false, "Can't get ActivityPub domain name.")
showToast(false, "Can't get ActivityPub domain name.")
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)
@ -2221,7 +2218,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
}
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) {
if(column.dont_close) {
showToast(this, false, R.string.column_has_dont_close_option)
showToast(false, R.string.column_has_dont_close_option)
return
}
@ -2452,9 +2449,9 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
when(fullAcct.host.ascii) {
"github.com",
"twitter.com" ->
App1.openCustomTab(this, mention.url)
openCustomTab(mention.url)
"gmail.com" ->
App1.openBrowser(this, "mailto:${fullAcct.pretty}")
openBrowser("mailto:${fullAcct.pretty}")
else ->
Action_User.profile(
@ -2485,11 +2482,11 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val instanceHost = Host.parse(instance)
when(instanceHost.ascii) {
"github.com", "twitter.com" -> {
App1.openCustomTab(this, "https://$instance/$user")
openCustomTab("https://$instance/$user")
}
"gmail.com" -> {
App1.openBrowser(this, "mailto:$user@$instance")
openBrowser("mailto:$user@$instance")
}
else -> {
@ -2535,7 +2532,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
}
App1.openCustomTab(this, opener.url)
openCustomTab(opener.url)
} catch(ex : Throwable) {
// warning.trace( ex );
@ -2563,7 +2560,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val footer_tab_indicator_color = Pref.ipFooterTabIndicatorColor(pref)
val colorColumnStripBackground = footer_tab_bg_color.notZero()
?: getAttributeColor(this, R.attr.colorColumnStripBackground)
?: getAttributeColor(R.attr.colorColumnStripBackground)
svColumnStrip.setBackgroundColor(colorColumnStripBackground)
llQuickTootBar.setBackgroundColor(colorColumnStripBackground)
@ -2572,7 +2569,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
?: colorColumnStripBackground
val colorButtonFg = footer_button_fg_color.notZero()
?: getAttributeColor(this, R.attr.colorRippleEffect)
?: getAttributeColor(R.attr.colorRippleEffect)
btnMenu.backgroundDrawable =
getAdaptiveRippleDrawableRound(this, colorButtonBg, colorButtonFg)
@ -2585,7 +2582,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
val csl = ColorStateList.valueOf(
footer_button_fg_color.notZero()
?: getAttributeColor(this, R.attr.colorVectorDrawable)
?: getAttributeColor(R.attr.colorVectorDrawable)
)
btnToot.imageTintList = csl
btnMenu.imageTintList = csl
@ -2598,7 +2595,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
vFooterDivider2.setBackgroundColor(c)
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) {
log.trace(ex)
if(zipEntryCount != 0) {
showToast(this@ActMain, ex, "importAppData failed.")
showToast(ex, "importAppData failed.")
}
}
// zipではなかった場合、zipEntryがない状態になる。例外はPH-1では出なかったが、出ても問題ないようにする。
@ -2914,7 +2911,7 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
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()
},
preProc = {

View File

@ -107,9 +107,8 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
private lateinit var svDescription : View
private lateinit var tvDescription : TextView
private lateinit var tvStatus : TextView
private lateinit var cbMute: CheckBox
private var lastVolume = Float.NaN
private lateinit var cbMute : CheckBox
private var lastVolume = Float.NaN
internal var buffering_last_shown : Long = 0
@ -149,7 +148,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
val now = SystemClock.elapsedRealtime()
if(now - buffering_last_shown >= short_limit && exoPlayer.duration >= short_limit) {
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).
@ -163,7 +162,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
override fun onPlayerError(error : ExoPlaybackException) {
log.d("exoPlayer onPlayerError")
showToast(this@ActMediaViewer, error, "player error.")
showToast(error, "player error.")
}
override fun onPositionDiscontinuity(reason : Int) {
@ -187,7 +186,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
outState.putLong(STATE_PLAYER_POS, exoPlayer.currentPosition)
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?) {
@ -252,14 +251,14 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
findViewById<View>(R.id.btnDownload).setOnClickListener(this)
findViewById<View>(R.id.btnMore).setOnClickListener(this)
cbMute.setOnCheckedChangeListener{_,isChecked->
cbMute.setOnCheckedChangeListener { _, isChecked ->
if(isChecked) {
// mute
lastVolume = exoPlayer.volume
exoPlayer.volume = 0f
}else{
} else {
// unmute
exoPlayer.volume = when{
exoPlayer.volume = when {
lastVolume.isNaN() -> 1f
lastVolume <= 0f -> 1f
else -> lastVolume
@ -361,7 +360,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
private fun loadVideo(ta : TootAttachment, state : Bundle? = null) {
cbMute.vg(true)
if(cbMute.isChecked && lastVolume.isFinite() ) {
if(cbMute.isChecked && lastVolume.isFinite()) {
exoPlayer.volume = 0f
}
@ -399,7 +398,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
} else {
exoPlayer.playWhenReady = state.getBoolean(STATE_PLAYER_PLAY_WHEN_READY, true)
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")
private fun loadBitmap(ta : TootAttachment) {
cbMute.visibility=View.INVISIBLE
cbMute.visibility = View.INVISIBLE
val urlList = ta.getLargeUrlList(App1.pref)
if(urlList.isEmpty()) {
@ -546,7 +545,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
return Pair(null, "image size <= 0")
}
val dstSize = rotateSize(orientation,srcWidth,srcHeight)
val dstSize = rotateSize(orientation, srcWidth, srcHeight)
val dstSizeInt = Point(
max(1, (dstSize.x + 0.5f).toInt()),
max(1, (dstSize.y + 0.5f).toInt())
@ -599,13 +598,13 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
) : Pair<TootApiResult?, ByteArray?> {
val result = TootApiResult.makeWithCaption(url)
val request = try{
val request = try {
Request.Builder()
.url(url)
.cacheControl(App1.CACHE_CONTROL)
.addHeader("Accept", "image/webp,image/*,*/*;q=0.8")
.build()
}catch(ex:Throwable){
} catch(ex : Throwable) {
result.setError(ex.withCaption("incorrect URL."))
return Pair(result, null)
}
@ -667,7 +666,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
if(bitmap != null) {
pbvImage.setBitmap(bitmap)
} 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])
}
} catch(ex : Throwable) {
showToast(this, ex, "action failed.")
showToast(ex, "action failed.")
}
}
@ -702,7 +701,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
return
}
val downLoadManager :DownloadManager = systemService(this)
val downLoadManager : DownloadManager = systemService(this)
?: error("missing DownloadManager system service")
val url = if(ta is TootAttachment) {
@ -724,7 +723,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
it.remove()
} else if(url == dh.url) {
// 履歴に同じURLがあればエラーとする
showToast(this, false, R.string.dont_repeat_download_to_same_url)
showToast(false, R.string.dont_repeat_download_to_same_url)
return
}
}
@ -773,7 +772,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
downLoadManager.enqueue(request)
showToast(this, false, R.string.downloading)
showToast(false, R.string.downloading)
}
private fun share(action : String, url : String) {
@ -790,7 +789,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
startActivity(intent)
} 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)
showToast(this, false, R.string.url_is_copied)
showToast(false, R.string.url_is_copied)
} 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)
startActivity(intent)
} 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
)
} 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
}
if(bNotGranted) {
showToast(this, true, R.string.missing_permission_to_access_media)
showToast(true, R.string.missing_permission_to_access_media)
} else {
download(media_list[idx])
}

View File

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

View File

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

View File

@ -155,7 +155,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
tvAcct.text = acctPretty
val ac = AcctColor.load(acctAscii,acctPretty)
val ac = AcctColor.load(acctAscii, acctPretty)
color_bg = ac.color_bg
color_fg = ac.color_fg
etNickname.setText(ac.nickname)
@ -180,7 +180,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
private fun show() {
val s = etNickname.text.toString().trim { it <= ' ' }
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
}

View File

@ -493,7 +493,7 @@ class ActPost : AsyncActivity(),
private var mushroom_end : Int = 0
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) {
addAttachment(uri)
} else {
showToast(this@ActPost, false, "missing image uri")
showToast(false, "missing image uri")
}
}
@ -612,7 +612,7 @@ class ActPost : AsyncActivity(),
}
if(account_list.isEmpty()) {
showToast(this, true, R.string.please_add_account)
showToast(true, R.string.please_add_account)
finish()
return
}
@ -1413,7 +1413,6 @@ class ActPost : AsyncActivity(),
tvCharCount.text = remain.toString()
tvCharCount.setTextColor(
getAttributeColor(
this,
if(remain < 0)
R.attr.colorRegexFilterError
else
@ -1495,7 +1494,7 @@ class ActPost : AsyncActivity(),
if(a == null) {
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)
} else {
@ -1515,7 +1514,7 @@ class ActPost : AsyncActivity(),
}
btnAccount.textColor = ac.color_fg.notZero()
?: getAttributeColor(this, android.R.attr.textColorPrimary)
?: getAttributeColor(android.R.attr.textColorPrimary)
}
updateTextCount()
updateFeaturedTags()
@ -1525,19 +1524,19 @@ class ActPost : AsyncActivity(),
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
}
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
}
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
}
@ -1598,7 +1597,7 @@ class ActPost : AsyncActivity(),
selectAccount(a)
try {
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
}
@ -1644,7 +1643,6 @@ class ActPost : AsyncActivity(),
setAccountWithVisibilityConversion(access_info)
} else {
showToast(
this@ActPost,
true,
getString(R.string.in_reply_to_id_conversion_failed) + "\n" + result.error
)
@ -1701,7 +1699,7 @@ class ActPost : AsyncActivity(),
val pa = try {
attachment_list[idx]
} 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
}
@ -1771,7 +1769,7 @@ class ActPost : AsyncActivity(),
if(new_attachment != null) {
pa.attachment = attachment
} else {
showToast(this@ActPost, true, result.error)
showToast(true, result.error)
}
}
})
@ -1798,7 +1796,7 @@ class ActPost : AsyncActivity(),
startActivityForResult(intent, REQUEST_CODE_CUSTOM_THUMBNAIL)
} catch(ex : Throwable) {
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
if(account == null) {
showToast(this, false, R.string.account_select_please)
showToast(false, R.string.account_select_please)
return
}
val mime_type = getMimeType(src.uri, src.mimeType)
if(mime_type?.isEmpty() != false) {
showToast(this, false, R.string.mime_type_missing)
showToast(false, R.string.mime_type_missing)
return
}
val pa = lastPostAttachment
if(pa == null || ! attachment_list.contains(pa)) {
showToast(this, true, "lost attachment information")
showToast(true, "lost attachment information")
return
}
@ -1922,7 +1920,7 @@ class ActPost : AsyncActivity(),
override fun handleResult(result : TootApiResult?) {
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) {
val a = pa.attachment
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
}
@ -1960,7 +1958,7 @@ class ActPost : AsyncActivity(),
}
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()
} else {
showToast(this@ActPost, true, result.error)
showToast(true, result.error)
}
}
})
@ -2007,12 +2005,12 @@ class ActPost : AsyncActivity(),
private fun openAttachment() {
if(attachment_list.size >= 4) {
showToast(this, false, R.string.attachment_too_many)
showToast(false, R.string.attachment_too_many)
return
}
if(account == null) {
showToast(this, false, R.string.account_select_please)
showToast(false, R.string.account_select_please)
return
}
@ -2068,7 +2066,7 @@ class ActPost : AsyncActivity(),
startActivityForResult(intent, REQUEST_CODE_ATTACHMENT_OLD)
} catch(ex : Throwable) {
log.trace(ex)
showToast(this, ex, "ACTION_GET_CONTENT failed.")
showToast(ex, "ACTION_GET_CONTENT failed.")
}
}
@ -2109,7 +2107,7 @@ class ActPost : AsyncActivity(),
try {
val cache_dir = externalCacheDir
if(cache_dir == null) {
showToast(this, false, "getExternalCacheDir returns null.")
showToast(false, "getExternalCacheDir returns null.")
break
}
@ -2145,7 +2143,7 @@ class ActPost : AsyncActivity(),
} catch(ex : Throwable) {
log.trace(ex)
showToast(this, ex, "Resizing image failed.")
showToast(ex, "Resizing image failed.")
}
break
@ -2219,35 +2217,35 @@ class ActPost : AsyncActivity(),
) {
if(attachment_list.size >= 4) {
showToast(this, false, R.string.attachment_too_many)
showToast(false, R.string.attachment_too_many)
return
}
val account = this@ActPost.account
if(account == null) {
showToast(this, false, R.string.account_select_please)
showToast(false, R.string.account_select_please)
return
}
val mime_type = getMimeType(uri, mimeTypeArg)
if(mime_type?.isEmpty() != false) {
showToast(this, false, R.string.mime_type_missing)
showToast(false, R.string.mime_type_missing)
return
}
val instance = TootInstance.getCached(account.apiHost.ascii)
if(instance?.instanceType == TootInstance.InstanceType.Pixelfed) {
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
}
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
}
} else {
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
}
}
@ -2261,7 +2259,7 @@ class ActPost : AsyncActivity(),
// アップロード開始トースト(連発しない)
val now = System.currentTimeMillis()
if(now - lastAttachmentAdd >= 5000L) {
showToast(this, false, R.string.attachment_uploading)
showToast(false, R.string.attachment_uploading)
}
lastAttachmentAdd = now
@ -2547,7 +2545,6 @@ class ActPost : AsyncActivity(),
pa.status = PostAttachment.STATUS_UPLOAD_FAILED
if(result != null) {
showToast(
this@ActPost,
true,
"${result.error} ${result.response?.request?.method} ${result.response?.request?.url}"
)
@ -2581,7 +2578,7 @@ class ActPost : AsyncActivity(),
val now = System.currentTimeMillis()
if(now - lastAttachmentComplete >= 5000L) {
showToast(this@ActPost, false, R.string.attachment_uploaded)
showToast(false, R.string.attachment_uploaded)
}
lastAttachmentComplete = now
@ -2626,7 +2623,7 @@ class ActPost : AsyncActivity(),
startActivityForResult(intent, REQUEST_CODE_CAMERA)
} catch(ex : Throwable) {
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)
} catch(ex : Throwable) {
log.trace(ex)
showToast(this, ex, errorCaption)
showToast(ex, errorCaption)
}
}
@ -2648,7 +2645,7 @@ class ActPost : AsyncActivity(),
PERMISSION_REQUEST_CODE
)
} 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
}
if(bNotGranted) {
showToast(this, true, R.string.missing_permission_to_access_media)
showToast(true, R.string.missing_permission_to_access_media)
} else {
openAttachment()
}
@ -2763,7 +2760,7 @@ class ActPost : AsyncActivity(),
// アップロード中は投稿できない
for(pa in attachment_list) {
if(pa.status == PostAttachment.STATUS_UPLOADING) {
showToast(this, false, R.string.media_attachment_still_uploading)
showToast(false, R.string.media_attachment_still_uploading)
return
}
}
@ -2850,7 +2847,7 @@ class ActPost : AsyncActivity(),
}
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()
data.putExtra(EXTRA_POSTED_ACCT, target_account.acct.ascii)
setResult(RESULT_OK, data)

View File

@ -161,7 +161,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
} catch(ex : Throwable) {
log.trace(ex)
showToast(this, ex, "send failed.")
showToast(ex, "send failed.")
}
}
@ -169,7 +169,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
private fun search() {
val sv = selection
if(sv.isEmpty()) {
showToast(this, false, "please select search keyword")
showToast(false, "please select search keyword")
return
}
try {
@ -180,7 +180,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
}
} catch(ex : Throwable) {
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) {
val sv = selection
if(sv.isEmpty()) {
showToast(this, false, "please select search keyword")
showToast(false, "please select search keyword")
return
}
try {
@ -206,10 +206,10 @@ class ActText : AppCompatActivity(), View.OnClickListener {
try {
MutedWord.save(selection)
App1.getAppState(this).onMuteUpdated()
showToast(this, false, R.string.word_was_muted)
showToast(false, R.string.word_was_muted)
} catch(ex : Throwable) {
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.app.Activity
import android.app.Application
import android.content.ComponentName
import android.content.Context
import android.content.Intent
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.SQLiteOpenHelper
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.view.View
import android.view.WindowInsetsController
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
import androidx.browser.customtabs.CustomTabsIntent
import com.bumptech.glide.Glide
import com.bumptech.glide.GlideBuilder
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.model.GlideUrl
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.util.CustomEmojiCache
import jp.juggler.subwaytooter.util.CustomEmojiLister
import jp.juggler.subwaytooter.util.ProgressResponseBody
import jp.juggler.subwaytooter.util.cn
import jp.juggler.util.*
import okhttp3.*
import org.conscrypt.Conscrypt
@ -51,7 +35,6 @@ import java.security.Security
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.max
import kotlin.math.pow
class App1 : Application() {
@ -315,7 +298,7 @@ class App1 : Application() {
initializeFont()
pref = Pref.pref(app_context)
pref = app_context.pref()
run {
@ -518,7 +501,7 @@ class App1 : Application() {
}
fun setActivityTheme(
activity : Activity,
activity : AppCompatActivity,
noActionBar : 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()
@ -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
fun initEdgeToEdge(@Suppress("UNUSED_PARAMETER") activity : Activity) {
// if(Build.VERSION.SDK_INT >= 29){

View File

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

View File

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

View File

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

View File

@ -415,7 +415,7 @@ class ColumnTask_Gap(
}
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")
break
}
@ -563,7 +563,7 @@ class ColumnTask_Gap(
defaultAccountListParser
) : TootApiResult? {
if( column.pagingType != ColumnPagingType.Default ) {
if(column.pagingType != ColumnPagingType.Default) {
return TootApiResult("can't support gap")
}

View File

@ -59,6 +59,7 @@ class ColumnViewHolder(
CompoundButton.OnCheckedChangeListener, View.OnLongClickListener {
companion object {
private val log = LogCategory("ColumnViewHolder")
val fieldRecycler : Field by lazy {
@ -540,8 +541,8 @@ class ColumnViewHolder(
// }
log.d(
"restoreScrollPosition [$page_idx] %s , column has no saved scroll position."
, column.getColumnName(true)
"restoreScrollPosition [$page_idx] %s , column has no saved scroll position.",
column.getColumnName(true)
)
return
}
@ -550,18 +551,18 @@ class ColumnViewHolder(
if(listView.visibility != View.VISIBLE) {
log.d(
"restoreScrollPosition [$page_idx] %s , listView is not visible. saved position %s,%s is dropped."
, column.getColumnName(true)
, sp.adapterIndex
, sp.offset
"restoreScrollPosition [$page_idx] %s , listView is not visible. saved position %s,%s is dropped.",
column.getColumnName(true),
sp.adapterIndex,
sp.offset
)
} else {
log.d(
"restoreScrollPosition [%d] %s , listView is visible. resume %s,%s"
, page_idx
, column.getColumnName(true)
, sp.adapterIndex
, sp.offset
"restoreScrollPosition [%d] %s , listView is visible. resume %s,%s",
page_idx,
column.getColumnName(true),
sp.adapterIndex,
sp.offset
)
sp.restore(this@ColumnViewHolder)
}
@ -717,21 +718,21 @@ class ColumnViewHolder(
fun dip(dp : Int) : Int = (activity.density * dp + 0.5f).toInt()
val context = activity
val announcementsBgColor = Pref.ipAnnouncementsBgColor(activity.pref).notZero()
?: getAttributeColor(context, R.attr.colorSearchFormBackground)
val announcementsBgColor = Pref.ipAnnouncementsBgColor(App1.pref).notZero()
?: context.getAttributeColor(R.attr.colorSearchFormBackground)
btnAnnouncementsCutout.apply {
color = announcementsBgColor
}
llAnnouncementsBox.apply {
background = createRoundDrawable( dip(6).toFloat(), announcementsBgColor )
background = createRoundDrawable(dip(6).toFloat(), announcementsBgColor)
val pad_tb = dip(2)
setPadding(0, pad_tb, 0, pad_tb)
}
val searchBgColor = Pref.ipSearchBgColor(activity.pref).notZero()
?: getAttributeColor(context, R.attr.colorSearchFormBackground)
val searchBgColor = Pref.ipSearchBgColor(App1.pref).notZero()
?: context.getAttributeColor(R.attr.colorSearchFormBackground)
llSearch.apply {
backgroundColor = searchBgColor
@ -740,7 +741,7 @@ class ColumnViewHolder(
topPadding = dip(3)
bottomPadding = dip(3)
}
llListList.apply {
backgroundColor = searchBgColor
startPadding = dip(12)
@ -1145,7 +1146,7 @@ class ColumnViewHolder(
btnListAdd -> {
val tv = etListName.text.toString().trim { it <= ' ' }
if(tv.isEmpty()) {
showToast(activity, true, R.string.list_name_empty)
activity.showToast(true, R.string.list_name_empty)
return
}
Action_List.create(activity, column.access_info, tv, null)
@ -1161,7 +1162,7 @@ class ColumnViewHolder(
btnQuickFilterFavourite -> clickQuickFilter(Column.QUICK_FILTER_FAVOURITE)
btnQuickFilterBoost -> clickQuickFilter(Column.QUICK_FILTER_BOOST)
btnQuickFilterFollow -> clickQuickFilter(Column.QUICK_FILTER_FOLLOW)
btnQuickFilterPost-> clickQuickFilter(Column.QUICK_FILTER_POST)
btnQuickFilterPost -> clickQuickFilter(Column.QUICK_FILTER_POST)
btnQuickFilterReaction -> clickQuickFilter(Column.QUICK_FILTER_REACTION)
btnQuickFilterVote -> clickQuickFilter(Column.QUICK_FILTER_VOTE)
@ -1232,7 +1233,7 @@ class ColumnViewHolder(
tvColumnContext.text = ac.nickname
tvColumnContext.setTextColor(
ac.color_fg.notZero()
?: getAttributeColor(activity, R.attr.colorTimeSmall)
?: activity.getAttributeColor(R.attr.colorTimeSmall)
)
tvColumnContext.setBackgroundColor(ac.color_bg)
@ -1393,11 +1394,11 @@ class ColumnViewHolder(
val scroll_save = ScrollPosition()
column.scroll_save = scroll_save
log.d(
"saveScrollPosition [%d] %s , listView is not visible, save %s,%s"
, page_idx
, column.getColumnName(true)
, scroll_save.adapterIndex
, scroll_save.offset
"saveScrollPosition [%d] %s , listView is not visible, save %s,%s",
page_idx,
column.getColumnName(true),
scroll_save.adapterIndex,
scroll_save.offset
)
return true
}
@ -1406,11 +1407,11 @@ class ColumnViewHolder(
val scroll_save = ScrollPosition(this)
column.scroll_save = scroll_save
log.d(
"saveScrollPosition [%d] %s , listView is visible, save %s,%s"
, page_idx
, column.getColumnName(true)
, scroll_save.adapterIndex
, scroll_save.offset
"saveScrollPosition [%d] %s , listView is visible, save %s,%s",
page_idx,
column.getColumnName(true),
scroll_save.adapterIndex,
scroll_save.offset
)
return true
}
@ -1586,10 +1587,10 @@ class ColumnViewHolder(
if(insideColumnSetting) {
svQuickFilter.setBackgroundColor(0)
val colorFg = getAttributeColor(activity, R.attr.colorContentText)
val colorFg = activity.getAttributeColor(R.attr.colorContentText)
val colorBgSelected = colorFg.applyAlphaMultiplier(0.25f)
val colorFgList = ColorStateList.valueOf(colorFg)
val colorBg = getAttributeColor(activity, R.attr.colorColumnSettingBackground)
val colorBg = activity.getAttributeColor(R.attr.colorColumnSettingBackground)
showQuickFilterButton = { btn, iconId, selected ->
btn.backgroundDrawable =
getAdaptiveRippleDrawableRound(
@ -1721,7 +1722,7 @@ class ColumnViewHolder(
gravity = Gravity.END
startPadding = dip(4)
endPadding = dip(4)
textColor = getAttributeColor(context, R.attr.colorColumnHeaderAcct)
textColor = context.getAttributeColor(R.attr.colorColumnHeaderAcct)
textSize = 12f
}.lparams(0, wrapContent) {
@ -1730,7 +1731,7 @@ class ColumnViewHolder(
tvColumnStatus = textView {
gravity = Gravity.END
textColor = getAttributeColor(context, R.attr.colorColumnHeaderPageNumber)
textColor = context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
textSize = 12f
}.lparams(wrapContent, wrapContent) {
@ -1739,7 +1740,7 @@ class ColumnViewHolder(
tvColumnIndex = textView {
gravity = Gravity.END
textColor = getAttributeColor(context, R.attr.colorColumnHeaderPageNumber)
textColor = context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
textSize = 12f
}.lparams(wrapContent, wrapContent) {
@ -1843,7 +1844,7 @@ class ColumnViewHolder(
val paint = Paint().apply {
isAntiAlias = true
color =
getAttributeColor(context, R.attr.colorColumnSettingBackground)
context.getAttributeColor(R.attr.colorColumnSettingBackground)
}
val path = Path()
addOutsideDrawer(this) { canvas, parent, view, left, top ->
@ -1909,7 +1910,7 @@ class ColumnViewHolder(
maxHeight = dip(240)
backgroundColor =
getAttributeColor(context, R.attr.colorColumnSettingBackground)
context.getAttributeColor(R.attr.colorColumnSettingBackground)
llColumnSettingInside = verticalLayout {
lparams(matchParent, wrapContent)
@ -1924,7 +1925,7 @@ class ColumnViewHolder(
label = textView {
textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber)
context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.hashtag_extra_any)
}.lparams(matchParent, wrapContent)
@ -1939,7 +1940,7 @@ class ColumnViewHolder(
label = textView {
textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber)
context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.hashtag_extra_all)
}.lparams(matchParent, wrapContent)
@ -1954,7 +1955,7 @@ class ColumnViewHolder(
label = textView {
textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber)
context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.hashtag_extra_none)
}.lparams(matchParent, wrapContent)
@ -2049,12 +2050,12 @@ class ColumnViewHolder(
label = textView {
textColor =
getAttributeColor(context, R.attr.colorColumnHeaderPageNumber)
context.getAttributeColor(R.attr.colorColumnHeaderPageNumber)
text = context.getString(R.string.regex_filter)
}.lparams(wrapContent, wrapContent)
tvRegexFilterError = textView {
textColor = getAttributeColor(context, R.attr.colorRegexFilterError)
textColor = context.getAttributeColor(R.attr.colorRegexFilterError)
}.lparams(0, wrapContent) {
weight = 1f
startMargin = dip(4)
@ -2220,10 +2221,7 @@ class ColumnViewHolder(
contentDescription = context.getString(R.string.clear)
imageResource = R.drawable.ic_close
imageTintList = ColorStateList.valueOf(
getAttributeColor(
context,
R.attr.colorVectorDrawable
)
context.getAttributeColor(R.attr.colorVectorDrawable)
)
}.lparams(dip(40), dip(40)) {
startMargin = dip(4)
@ -2234,10 +2232,7 @@ class ColumnViewHolder(
contentDescription = context.getString(R.string.search)
imageResource = R.drawable.ic_search
imageTintList = ColorStateList.valueOf(
getAttributeColor(
context,
R.attr.colorVectorDrawable
)
context.getAttributeColor(R.attr.colorVectorDrawable)
)
}.lparams(dip(40), dip(40)) {
startMargin = dip(4)
@ -2269,8 +2264,7 @@ class ColumnViewHolder(
contentDescription = context.getString(R.string.add)
imageResource = R.drawable.ic_add
imageTintList = ColorStateList.valueOf(
getAttributeColor(
context,
context.getAttributeColor(
R.attr.colorVectorDrawable
)
)
@ -2688,8 +2682,8 @@ class ColumnViewHolder(
btn.background = if(reaction.me == true) {
getAdaptiveRippleDrawableRound(
actMain,
getAttributeColor(actMain, R.attr.colorButtonBgCw),
getAttributeColor(actMain, R.attr.colorRippleEffect)
actMain.getAttributeColor(R.attr.colorButtonBgCw),
actMain.getAttributeColor(R.attr.colorRippleEffect)
)
} else {
ContextCompat.getDrawable(actMain, R.drawable.btn_bg_transparent_round6dp)
@ -2775,7 +2769,7 @@ class ColumnViewHolder(
override fun handleResult(result : TootApiResult?) {
result ?: return
if(result.jsonObject == null) {
showToast(activity, true, result.error)
activity.showToast(true, result.error)
} else {
sample.count = 0
val list = item.reactions
@ -2811,7 +2805,7 @@ class ColumnViewHolder(
override fun handleResult(result : TootApiResult?) {
result ?: return
if(result.jsonObject == null) {
showToast(activity, true, result.error)
activity.showToast(true, result.error)
} else {
val it = item.reactions?.iterator() ?: return
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.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.CustomShare
import jp.juggler.subwaytooter.util.CustomShareTarget
import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.subwaytooter.util.*
import jp.juggler.util.*
import org.jetbrains.anko.allCaps
import org.jetbrains.anko.backgroundDrawable
@ -349,14 +347,14 @@ internal class DlgContextMenu(
val colorButtonAccent =
Pref.ipButtonFollowingColor(activity.pref).notZero()
?: getAttributeColor(activity, R.attr.colorImageButtonAccent)
?: activity.getAttributeColor(R.attr.colorImageButtonAccent)
val colorButtonError =
Pref.ipButtonFollowRequestColor(activity.pref).notZero()
?: getAttributeColor(activity, R.attr.colorRegexFilterError)
?: activity.getAttributeColor(R.attr.colorRegexFilterError)
val colorButtonNormal =
getAttributeColor(activity, R.attr.colorImageButton)
activity.getAttributeColor(R.attr.colorImageButton)
fun showRelation(relation : UserRelation) {
@ -407,7 +405,7 @@ internal class DlgContextMenu(
ivFollowedBy.vg(false)
btnFollow.setImageResource(R.drawable.ic_follow_plus)
btnFollow.imageTintList =
ColorStateList.valueOf(getAttributeColor(activity, R.attr.colorImageButton))
ColorStateList.valueOf(activity.getAttributeColor(R.attr.colorImageButton))
btnNotificationFrom.visibility = View.GONE
} else {
@ -585,7 +583,7 @@ internal class DlgContextMenu(
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)
btn.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null)
}
@ -713,7 +711,7 @@ internal class DlgContextMenu(
Action_User.mention(activity, access_info, who)
R.id.btnAccountWebPage -> who.url?.let { url ->
App1.openCustomTabOrBrowser(activity, url)
activity.openCustomTabOrBrowser(url)
}
R.id.btnFollowRequestOK ->
@ -752,13 +750,13 @@ internal class DlgContextMenu(
R.id.btnDomainBlock ->
if(access_info.isPseudo) {
// 疑似アカウントではドメインブロックできない
showToast(activity, false, R.string.domain_block_from_pseudo)
activity.showToast(false, R.string.domain_block_from_pseudo)
return
} else {
val whoApDomain = who.apDomain
// 自分のドメインではブロックできない
if(access_info.matchHost(whoApDomain)) {
showToast(activity, false, R.string.domain_block_from_local)
activity.showToast(false, R.string.domain_block_from_local)
return
}
AlertDialog.Builder(activity)
@ -794,7 +792,7 @@ internal class DlgContextMenu(
R.id.btnAvatarImage -> {
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: 設定によっては内蔵メディアビューアで開けないか?
}
@ -821,7 +819,7 @@ internal class DlgContextMenu(
R.id.btnHideFavourite -> {
val acct = access_info.getFullAcct(who)
FavMute.save(acct)
showToast(activity, false, R.string.changed)
activity.showToast(false, R.string.changed)
for(column in activity.app_state.column_list) {
column.onHideFavouriteNotification(acct)
}
@ -829,7 +827,7 @@ internal class DlgContextMenu(
R.id.btnShowFavourite -> {
FavMute.delete(access_info.getFullAcct(who))
showToast(activity, false, R.string.changed)
activity.showToast(false, R.string.changed)
}
R.id.btnListMemberAddRemove ->
@ -884,14 +882,12 @@ internal class DlgContextMenu(
R.id.btnCopyAccountId -> who.id.toString().copyToClipboard(activity)
R.id.btnOpenAccountInAdminWebUi ->
App1.openBrowser(
activity,
activity.openBrowser(
"https://${access_info.apiHost.ascii}/admin/accounts/${who.id}"
)
R.id.btnOpenInstanceInAdminWebUi ->
App1.openBrowser(
activity,
activity.openBrowser(
"https://${access_info.apiHost.ascii}/admin/instances/${who.apDomain.ascii}"
)
@ -929,8 +925,8 @@ internal class DlgContextMenu(
status,
access_info.getFullAcct(status.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 -> {
if(access_info.isMisskey) {
showToast(activity, false, R.string.misskey_account_not_supported)
activity.showToast(false, R.string.misskey_account_not_supported)
} else {
access_info.getFullAcct(who).validFull()?.let {
activity.addColumn(
@ -963,9 +959,8 @@ internal class DlgContextMenu(
when(v.id) {
R.id.btnStatusWebPage -> status?.url?.let { url ->
App1.openCustomTabOrBrowser(activity, url)
}
R.id.btnStatusWebPage ->
activity.openCustomTabOrBrowser(status?.url)
R.id.btnText -> if(status != null) {
ActText.open(activity, ActMain.REQUEST_CODE_TEXT, access_info, status)

View File

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

View File

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

View File

@ -6,6 +6,9 @@ import android.graphics.Color
import androidx.preference.PreferenceManager
import jp.juggler.util.optInt
fun Context.pref() : SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(this)
@Suppress("EqualsOrHashCode")
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
}
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 invoke(pref : SharedPreferences) : T
override fun equals(other : Any?) =
this === other
operator fun invoke(context : Context) : T {
return invoke(Pref.pref(context))
}
operator fun invoke(context : Context) : T =
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) {
e.remove(key)
return true
true
}else {
false
}
return false
}
}
fun SharedPreferences.Editor.remove(item : BasePref<*>) : SharedPreferences.Editor {
@ -125,10 +125,6 @@ fun SharedPreferences.Editor.put(item : FloatPref, v : Float) =
object Pref {
fun pref(context : Context) : SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(context)
}
// キー名と設定項目のマップ。インポートやアプリ設定で使う
val map = HashMap<String, BasePref<*>>()
@ -445,6 +441,7 @@ object Pref {
// int
val ipBackButtonAction = IntPref("back_button_action", 0)
@Suppress("unused")
const val BACK_ASK_ALWAYS = 0
const val BACK_CLOSE_COLUMN = 1
@ -454,18 +451,18 @@ object Pref {
val ipUiTheme = IntPref("ui_theme", 0)
val ipResizeImage = IntPref("resize_image", 4)
const val RC_SIMPLE = 0
const val RC_ACTUAL = 1
@Suppress("unused")
const val RC_NONE = 2
val ipRepliesCount = IntPref("RepliesCount", RC_SIMPLE)
val ipBoostsCount = IntPref("BoostsCount", RC_ACTUAL)
val ipFavouritesCount = IntPref("FavouritesCount", RC_ACTUAL)
val ipRefreshAfterToot = IntPref("refresh_after_toot", 0)
const val RAT_REFRESH_SCROLL = 0
@Suppress("unused")
const val RAT_REFRESH_DONT_SCROLL = 1
const val RAT_DONT_REFRESH = 2
@ -477,6 +474,7 @@ object Pref {
val ipVisibilityStyle = IntPref("ipVisibilityStyle", VS_BY_ACCOUNT)
const val ABP_TOP = 0
@Suppress("unused")
const val ABP_BOTTOM = 1
const val ABP_START = 2
@ -547,8 +545,6 @@ object Pref {
val ipVerifiedLinkBgColor = IntPref("VerifiedLinkBgColor", 0)
val ipVerifiedLinkFgColor = IntPref("VerifiedLinkFgColor", 0)
// val ipTrendTagCountShowing = IntPref("TrendTagCountShowing", 0)
// const val TTCS_WEEKLY = 0
// const val TTCS_DAILY = 1
@ -577,7 +573,7 @@ object Pref {
val spBoostAlpha = StringPref("BoostAlpha", "60")
val spScreenBottomPadding = StringPref("ScreenBottomPadding", "8")
val spPullNotificationCheckInterval = StringPref("PullNotificationCheckInterval", "15")
val spUserAgent = StringPref("UserAgent", "")
@ -611,3 +607,4 @@ object Pref {
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.table.SavedAccount
import jp.juggler.subwaytooter.util.VersionString
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@ -52,7 +53,7 @@ class SideMenuAdapter(
private fun clickableSpan(url : String) =
object : ClickableSpan() {
override fun onClick(widget : View) {
App1.openBrowser(widget.activity as ActMain, url)
widget.activity?.openBrowser(url)
}
override fun updateDrawState(ds : TextPaint) {
@ -89,10 +90,9 @@ class SideMenuAdapter(
currentVersion
)
)
val newRelease = when(Pref.bpCheckBetaVersion(Pref.pref(appContext))) {
false -> releaseInfo?.jsonObject("stable")
else -> releaseInfo?.jsonObject("beta")
}
val newRelease = releaseInfo?.jsonObject(
if(Pref.bpCheckBetaVersion(App1.pref)) "beta" else "stable"
)
val newVersion =
(newRelease?.string("name")?.notEmpty() ?: newRelease?.string("tag_name"))
@ -122,10 +122,7 @@ class SideMenuAdapter(
)
setSpan(
ForegroundColorSpan(
getAttributeColor(
appContext,
R.attr.colorRegexFilterError
)
appContext.getAttributeColor(R.attr.colorRegexFilterError)
),
start, length,
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 getItem(position : Int) : Any = list[position]
@ -427,7 +424,7 @@ class SideMenuAdapter(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
backgroundColor = getAttributeColor(actMain, R.attr.colorWindowBackground)
backgroundColor = actMain.getAttributeColor(R.attr.colorWindowBackground)
selector = StateListDrawable()
divider = null
dividerHeight = 0

View File

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

View File

@ -30,7 +30,7 @@ object Styler {
fun defaultColorIcon(context : Context, iconId : Int) : Drawable? =
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)
}
@ -123,7 +123,7 @@ object Styler {
val icon_id = getVisibilityIconId(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()
// アイコン部分
@ -159,12 +159,12 @@ object Styler {
alphaMultiplier : Float
) {
fun colorAccent() =
Pref.ipButtonFollowingColor(Pref.pref(context)).notZero()
?: getAttributeColor(context, R.attr.colorImageButtonAccent)
Pref.ipButtonFollowingColor(context.pref()).notZero()
?: context.getAttributeColor(R.attr.colorImageButtonAccent)
fun colorError() =
Pref.ipButtonFollowRequestColor(Pref.pref(context)).notZero()
?: getAttributeColor(context, R.attr.colorRegexFilterError)
Pref.ipButtonFollowRequestColor(context.pref()).notZero()
?: context.getAttributeColor(R.attr.colorRegexFilterError)
// 被フォロー状態
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.TootInstance
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.MyNetworkImageView
import jp.juggler.util.LogCategory
@ -20,10 +22,10 @@ import org.conscrypt.OpenSSLX509Certificate
internal class ViewHolderHeaderInstance(
arg_activity : ActMain,
viewRoot : View
) : ViewHolderHeaderBase(arg_activity, viewRoot)
, View.OnClickListener {
) : ViewHolderHeaderBase(arg_activity, viewRoot), View.OnClickListener {
companion object {
private val log = LogCategory("ViewHolderHeaderInstance")
}
@ -122,12 +124,13 @@ internal class ViewHolderHeaderInstance(
btnEmail.isEnabled = email.isNotEmpty()
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.isEnabled = contact_acct.isNotEmpty()
tvLanguages.text = instance.languages?.joinToString(", ") ?: ""
tvInvitesEnabled.text = when(instance.invites_enabled){
tvInvitesEnabled.text = when(instance.invites_enabled) {
null -> "?"
true -> activity.getString(R.string.yes)
false -> activity.getString(R.string.no)
@ -183,15 +186,15 @@ internal class ViewHolderHeaderInstance(
Certificate : ${cert.type}
subject : ${cert.subjectDN}
subjectAlternativeNames : ${
cert.subjectAlternativeNames
?.joinToString(", ") {
try {
it?.last()
} catch(ignored : Throwable) {
it
cert.subjectAlternativeNames
?.joinToString(", ") {
try {
it?.last()
} catch(ignored : Throwable) {
it
}
?.toString() ?: "null"
}
?.toString() ?: "null"
}
}
issuer : ${cert.issuerX500Principal}
end : ${cert.notAfter}
@ -216,7 +219,7 @@ internal class ViewHolderHeaderInstance(
R.id.btnEmail -> instance?.email?.let { email ->
try {
if(email.contains("://")) {
App1.openCustomTab(activity, email)
activity.openCustomTab(email)
} else {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
@ -227,28 +230,31 @@ internal class ViewHolderHeaderInstance(
} catch(ex : Throwable) {
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 ->
Action_Account.timeline(
activity
, activity.nextPosition(column)
, ColumnType.SEARCH
, args = arrayOf("@${who.username}@${who.apDomain.ascii}", true)
activity,
activity.nextPosition(column),
ColumnType.SEARCH,
args = arrayOf("@${who.username}@${who.apDomain.ascii}", true)
)
}
R.id.btnInstance -> App1.openBrowser(activity, "https://${host.pretty}/about")
R.id.ivThumbnail -> App1.openBrowser(activity, instance?.thumbnail)
R.id.btnInstance ->
activity.openBrowser("https://${host.ascii}/about")
R.id.ivThumbnail ->
activity.openBrowser(instance?.thumbnail)
R.id.btnAbout ->
App1.openBrowser(activity, "https://${host.pretty}/about")
activity.openBrowser("https://${host.ascii}/about")
R.id.btnAboutMore ->
App1.openBrowser(activity, "https://${host.pretty}/about/more")
activity.openBrowser("https://${host.ascii}/about/more")
R.id.btnExplore -> Action_Instance.profileDirectoryFromInstanceInformation(
activity,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@ import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.dialog.AccountPicker
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.*
import java.util.*
@ -35,7 +36,7 @@ object Action_Instance {
override fun handleResult(result : TootApiResult?) {
result ?: return // cancelled.
when(val ti = targetInstance) {
null -> showToast(activity, true, result.error)
null -> activity.showToast(true, result.error)
else -> profileDirectory(activity, accessInfo, host, ti, pos)
}
}
@ -43,11 +44,11 @@ object Action_Instance {
// 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ページを開く
! instance.versionGE(TootInstance.VERSION_3_0_0_rc1) ->
App1.openBrowser(activity, "https://${host.ascii}/explore")
activity.openBrowser("https://${host.ascii}/explore")
// ホスト名部分が一致するならそのアカウントで開く
accessInfo.matchHost(host) ->
@ -123,10 +124,10 @@ object Action_Instance {
fun timelineDomain(
activity : ActMain,
pos : Int,
accessInfo: SavedAccount,
accessInfo : SavedAccount,
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)) {
showToast(activity, false, R.string.it_is_you)
activity.showToast(false, R.string.it_is_you)
return
}
@ -190,14 +191,13 @@ object Action_Instance {
column.onDomainBlockChanged(access_info, domain, bBlock)
}
showToast(
activity,
activity.showToast(
false,
if(bBlock) R.string.block_succeeded else R.string.unblock_succeeded
)
} else {
showToast(activity, false, result.error)
activity.showToast(false, result.error)
}
}
})
@ -235,7 +235,7 @@ object Action_Instance {
if(localStatus != null) {
timelinePublicAround2(activity, access_info, pos, localStatus.id, type)
} else {
showToast(activity, true, result.error)
activity.showToast(true, result.error)
}
}
})
@ -298,7 +298,7 @@ object Action_Instance {
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 {
fun interface CreateCallback {
fun onCreated(list : TootList)
}
@ -65,11 +66,11 @@ object Action_List {
column.onListListUpdated(access_info)
}
showToast(activity, false, R.string.list_created)
activity.showToast(false, R.string.list_created)
callback?.onCreated(list)
} else {
showToast(activity, false, result.error)
activity.showToast(false, result.error)
}
}
})
@ -85,8 +86,7 @@ object Action_List {
if(! bConfirmed) {
DlgConfirm.openSimple(
activity
, activity.getString(R.string.list_delete_confirm, list.title)
activity, activity.getString(R.string.list_delete_confirm, list.title)
) {
delete(activity, access_info, list, bConfirmed = true)
}
@ -121,10 +121,10 @@ object Action_List {
column.onListListUpdated(access_info)
}
showToast(activity, false, R.string.delete_succeeded)
activity.showToast(false, R.string.delete_succeeded)
} else {
showToast(activity, false, result.error)
activity.showToast(false, result.error)
}
}
})
@ -142,7 +142,7 @@ object Action_List {
item.title,
callback = object : DlgTextInput.Callback {
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) {
@ -191,7 +191,7 @@ object Action_List {
}
dialog.dismissSafe()
} 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)
fun interface Callback {
fun onListMemberUpdated(willRegistered : Boolean, bSuccess : Boolean)
}
@ -51,13 +52,13 @@ object Action_ListMember {
} else {
val isMe = access_info.isMe(local_who)
if( isMe ) {
if(isMe) {
val (ti, ri) = TootInstance.get(client)
if(ti == null) return ri
if(! ti.versionGE(TootInstance.VERSION_3_1_0_rc1)) {
return TootApiResult(activity.getString(R.string.it_is_you))
}
}else if(bFollow) {
} else if(bFollow) {
// リモートユーザの解決
if(! access_info.isLocalUser(local_who)) {
val (r2, ar) = client.syncAccountByAcct(access_info, local_who.acct)
@ -119,7 +120,7 @@ object Action_ListMember {
// フォロー状態の更新を表示に反映させる
if(bFollow) activity.showColumnMatchAccount(access_info)
showToast(activity, false, R.string.list_member_added)
activity.showToast(false, R.string.list_member_added)
bSuccess = true
@ -159,7 +160,7 @@ object Action_ListMember {
return
}
showToast(activity, true, error)
activity.showToast(true, error)
}
} finally {
@ -209,12 +210,12 @@ object Action_ListMember {
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
} else {
showToast(activity, false, result.error)
activity.showToast(false, result.error)
}
} finally {
callback?.onListMemberUpdated(false, bSuccess)

View File

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

View File

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

View File

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

View File

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

View File

@ -30,36 +30,36 @@ object AccountPicker {
activity : AppCompatActivity,
bAllowPseudo : Boolean = false,
bAllowMisskey : Boolean = true,
bAllowMastodon: Boolean = true,
bAllowMastodon : Boolean = true,
bAuto : Boolean = false,
message : String? = null,
accountListArg : ArrayList<SavedAccount>? = null,
dismiss_callback : DialogInterfaceCallback? = null,
extra_callback : (LinearLayout,Int,Int)->Unit = {_,_,_->},
extra_callback : (LinearLayout, Int, Int) -> Unit = { _, _, _ -> },
callback : SavedAccountCallback
) {
var removedMisskey =0
var removedPseudo =0
var removedMisskey = 0
var removedPseudo = 0
var removeMastodon = 0
val account_list : MutableList<SavedAccount> = accountListArg ?: {
val l = SavedAccount.loadAccountList(activity).filter { a->
val l = SavedAccount.loadAccountList(activity).filter { a ->
var bOk = true
if( !bAllowMastodon && !a.isMisskey ){
++removeMastodon
bOk=false
if(! bAllowMastodon && ! a.isMisskey) {
++ removeMastodon
bOk = false
}
if( !bAllowMisskey && a.isMisskey ){
++removedMisskey
bOk=false
if(! bAllowMisskey && a.isMisskey) {
++ removedMisskey
bOk = false
}
if( !bAllowPseudo && a.isPseudo ){
++removedPseudo
bOk=false
if(! bAllowPseudo && a.isPseudo) {
++ removedPseudo
bOk = false
}
bOk
}.toMutableList()
SavedAccount.sort(l)
@ -67,30 +67,30 @@ object AccountPicker {
}()
if(account_list.isEmpty()) {
val sb=StringBuilder()
if( removedPseudo > 0 ){
val sb = StringBuilder()
if(removedPseudo > 0) {
sb.append(activity.getString(R.string.not_available_for_pseudo_account))
}
if( removedMisskey > 0 ){
if(sb.isNotEmpty() ) sb.append('\n')
if(removedMisskey > 0) {
if(sb.isNotEmpty()) sb.append('\n')
sb.append(activity.getString(R.string.not_available_for_misskey_account))
}
if( removeMastodon > 0 ){
if(sb.isNotEmpty() ) sb.append('\n')
if(removeMastodon > 0) {
if(sb.isNotEmpty()) sb.append('\n')
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))
}
showToast(activity, false,sb.toString())
activity.showToast(false, sb.toString())
return
}
if(bAuto && account_list.size == 1) {
callback(account_list[0])
return
@ -121,19 +121,22 @@ object AccountPicker {
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_tb = (0.5f + 6f * density).toInt()
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 b = Button(activity)
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 {
b.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
}
@ -148,13 +151,13 @@ object AccountPicker {
b.minHeight = (0.5f + 32f * density).toInt()
val sb = SpannableStringBuilder(ac.nickname)
if( a.last_notification_error?.isNotEmpty() == true) {
if(a.last_notification_error?.isNotEmpty() == true) {
sb.append("\n")
val start = sb.length
sb.append(a.last_notification_error)
val end = sb.length
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")
val start = sb.length
sb.append(a.last_subscription_error)
@ -171,7 +174,7 @@ object AccountPicker {
llAccounts.addView(b)
}
extra_callback(llAccounts,pad_se, pad_tb)
extra_callback(llAccounts, pad_se, pad_tb)
dialog.show()
}

View File

@ -2,26 +2,23 @@ package jp.juggler.subwaytooter.dialog
import android.content.Context
import androidx.appcompat.app.AlertDialog
import java.util.ArrayList
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.util.EmptyCallback
import java.util.*
class ActionsDialog {
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
}
fun show(context : Context, title : CharSequence? = null ) : ActionsDialog {
fun show(context : Context, title : CharSequence? = null) : ActionsDialog {
val caption_list = arrayOfNulls<CharSequence>(action_list.size)
var i = 0
val ie = caption_list.size
@ -33,11 +30,11 @@ class ActionsDialog {
.setNegativeButton(R.string.cancel, null)
.setItems(caption_list) { _, which ->
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()

View File

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

View File

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

View File

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

View File

@ -24,6 +24,7 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
View.OnClickListener {
companion object {
val log = LogCategory("DlgFocusPoint")
}
@ -57,7 +58,7 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
fun show() {
val url = attachment.preview_url
if(url == null) {
showToast(activity, false, "missing image url")
activity.showToast(false, "missing image url")
return
}
@ -65,7 +66,10 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
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.inScaled = false
options.outWidth = 0
@ -92,7 +96,7 @@ class DlgFocusPoint(val activity : Activity, val attachment : TootAttachment) :
override fun background(client : TootApiClient) : TootApiResult? {
try {
val(result,data) = client.getHttpBytes(url)
val (result, data) = client.getHttpBytes(url)
data ?: return result
bitmap = decodeBitmap(data, 1024)
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?) {
val bitmap = this.bitmap
if(bitmap == null) {
showToast(activity, true, result?.error ?: "?")
activity.showToast(true, result?.error ?: "?")
dialog.dismissSafe()
return
}

View File

@ -134,7 +134,7 @@ class DlgListMember(
this.list_owner = a
if(a == null) {
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)
//
@ -148,7 +148,7 @@ class DlgListMember(
btnListOwner.setBackgroundResource(R.drawable.btn_bg_transparent_round6dp)
}
btnListOwner.textColor = ac.color_fg.notZero()
?: getAttributeColor(activity, android.R.attr.textColorPrimary)
?: activity.getAttributeColor( android.R.attr.textColorPrimary)
}
loadLists()
@ -175,7 +175,7 @@ class DlgListMember(
val (r1, ar) = client.syncAccountByAcct(list_owner, target_user_full_acct)
r1 ?: return null // cancelled.
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
@ -241,7 +241,7 @@ class DlgListMember(
val error = result.error
if(error?.isNotEmpty() == true) {
showToast(activity, true, result.error)
activity.showToast( true, result.error)
}
}
@ -268,14 +268,14 @@ class DlgListMember(
callback = object : DlgTextInput.Callback {
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) {
val list_owner = this@DlgListMember.list_owner
if(list_owner == null) {
showToast(activity, false, "list owner is not selected.")
activity.showToast( false, "list owner is not selected.")
return
}
@ -376,14 +376,14 @@ class DlgListMember(
val list_owner = this@DlgListMember.list_owner
if(list_owner == null) {
showToast(activity, false, "list owner is not selected")
activity.showToast( false, "list owner is not selected")
revokeCheckedChanged(isChecked)
return
}
val local_who = this@DlgListMember.local_who
if(local_who == null) {
showToast(activity, false, "target user is not synchronized")
activity.showToast( false, "target user is not synchronized")
revokeCheckedChanged(isChecked)
return
}

View File

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

View File

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

View File

@ -23,35 +23,35 @@ object ReportForm {
access_info : SavedAccount,
who : TootAccount,
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 tvUser :TextView = view.findViewById(R.id.tvUser)
val tvStatusCaption :TextView = view.findViewById(R.id.tvStatusCaption)
val tvStatus :TextView = view.findViewById(R.id.tvStatus)
val etComment :EditText = view.findViewById(R.id.etComment)
val tvUser : TextView = view.findViewById(R.id.tvUser)
val tvStatusCaption : TextView = view.findViewById(R.id.tvStatusCaption)
val tvStatus : TextView = view.findViewById(R.id.tvStatus)
val etComment : EditText = view.findViewById(R.id.etComment)
val cbForward : CheckBox = view.findViewById(R.id.cbForward)
val tvForwardDesc:TextView = view.findViewById(R.id.tvForwardDesc)
val canForward = !access_info.matchHost( who)
val tvForwardDesc : TextView = view.findViewById(R.id.tvForwardDesc)
val canForward = ! access_info.matchHost(who)
cbForward.isChecked = false
if(!canForward){
if(! canForward) {
cbForward.visibility = View.GONE
tvForwardDesc.visibility = View.GONE
}else{
} else {
cbForward.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
if( status == null){
if(status == null) {
tvStatusCaption.visibility = View.GONE
tvStatus.visibility = View.GONE
}else{
} else {
tvStatus.text = status.decoded_content
}
@ -60,11 +60,11 @@ object ReportForm {
view.findViewById<View>(R.id.btnOk).setOnClickListener(View.OnClickListener {
val comment = etComment.text.toString().trim()
if(comment.isEmpty()) {
showToast(activity, true, R.string.comment_empty)
activity.showToast(true, R.string.comment_empty)
return@OnClickListener
}
onClickOk(dialog, comment,cbForward.isChecked)
onClickOk(dialog, comment, cbForward.isChecked)
})
view.findViewById<View>(R.id.btnCancel).setOnClickListener { dialog.cancel() }

View File

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

View File

@ -71,7 +71,7 @@ object CustomShare {
label =
"${context.getString(R.string.copy_to_clipboard)}(${context.getString(R.string.app_name)})"
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)
}
} else {
@ -105,7 +105,7 @@ object CustomShare {
// convert "pkgName/className" string to ComponentName object.
val cn = getCustomShareComponentName(App1.pref, target)
if(cn == null) {
showToast(context, true, R.string.custom_share_app_not_found)
context.showToast(true, R.string.custom_share_app_not_found)
return
}
val cnStr = "${cn.packageName}/${cn.className}"
@ -113,9 +113,9 @@ object CustomShare {
try {
val cm : ClipboardManager = systemService(context) !!
cm.setPrimaryClip(ClipData.newPlainText("", text))
showToast(context, false, R.string.copied_to_clipboard)
context.showToast(false, R.string.copied_to_clipboard)
} catch(ex : Throwable) {
showToast(context, ex, "copy to clipboard failed.")
context.showToast(ex, "copy to clipboard failed.")
}
return
}
@ -128,10 +128,10 @@ object CustomShare {
context.startActivity(intent)
} catch(ex : ActivityNotFoundException) {
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) {
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.
val cn = getCustomShareComponentName(App1.pref, target)
if(cn == null) {
showToast(context, true, R.string.custom_share_app_not_found)
context.showToast(true, R.string.custom_share_app_not_found)
return
}
@ -155,7 +155,7 @@ object CustomShare {
invoke(context, sv, target)
} catch(ex : Throwable) {
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.R
import jp.juggler.subwaytooter.api.entity.CustomEmoji
import jp.juggler.subwaytooter.pref
import jp.juggler.subwaytooter.span.EmojiImageSpan
import jp.juggler.subwaytooter.span.HighlightSpan
import jp.juggler.subwaytooter.span.NetworkEmojiSpan
@ -356,7 +357,7 @@ object EmojiDecoder {
val useEmojioneShortcode = when(val context = options.context) {
null -> false
else -> Pref.bpEmojioneShortcode( Pref.pref(context))
else -> Pref.bpEmojioneShortcode( context.pref())
}
splitShortCode(s, callback = object : ShortCodeSplitterCallback {

View File

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

View File

@ -38,6 +38,7 @@ class PostHelper(
) {
companion object {
private val log = LogCategory("PostHelper")
private val reCharsNotEmoji = "[^0-9A-Za-z_-]".asciiPattern()
@ -47,6 +48,7 @@ class PostHelper(
}
interface PostCompleteCallback {
fun onPostComplete(target_account : SavedAccount, status : TootStatus)
fun onScheduledPostComplete(target_account : SavedAccount)
}
@ -110,14 +112,14 @@ class PostHelper(
val hasAttachment = attachment_list?.isNotEmpty() ?: false
if(! hasAttachment && content.isEmpty()) {
showToast(activity, true, R.string.post_error_contents_empty)
activity.showToast(true, R.string.post_error_contents_empty)
return
}
// nullはCWチェックなしを示す
// nullじゃなくてカラならエラー
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
}
@ -134,19 +136,19 @@ class PostHelper(
if(item.isEmpty()) {
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
}
} else {
val code_count = item.codePointCount(0, item.length)
if(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
} else if(n > 0) {
for(i in 0 until n) {
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
}
}
@ -278,7 +280,7 @@ class PostHelper(
// 確認を終えたらボタン連打判定
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
}
@ -286,371 +288,372 @@ class PostHelper(
val delta = now - last_post_tapped
last_post_tapped = now
if(delta < 1000L) {
showToast(activity, false, R.string.post_button_tapped_repeatly)
activity.showToast(false, R.string.post_button_tapped_repeatly)
return
}
// 全ての確認を終えたらバックグラウンドでの処理を開始する
last_post_task = WeakReference(TootTaskRunner(activity
, progressSetupCallback = { progressDialog ->
last_post_task =
WeakReference(TootTaskRunner(activity, progressSetupCallback = { progressDialog ->
progressDialog.setCanceledOnTouchOutside(false)
}
).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)
).run(account, object : TootTask {
var result : TootApiResult?
var status : TootStatus? = 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 credential_tmp : TootAccount? = null
var visibility_checked : TootVisibility? = visibility
var scheduledStatusSucceeded = false
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
fun getCredential(
client : TootApiClient,
parser : TootParser
) : TootApiResult? {
val result = client.request("/api/v1/accounts/verify_credentials")
credential_tmp = parser.account(result?.jsonObject)
return result
}
val status = parser.status(
if(account.isMisskey) {
result?.jsonObject?.jsonObject("createdNote") ?: result?.jsonObject
} else {
result?.jsonObject
}
)
this.status = status
if(status != null) {
override fun background(client : TootApiClient) : TootApiResult? {
val parser = TootParser(activity, account)
// タグを覚えておく
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))
var result : TootApiResult?
// 元の投稿を削除する
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()
)
}
val count = tag_list.size
if(count > 0) {
TagSet.saveList(System.currentTimeMillis(), tag_list, 0, count)
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
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
val status = this.status
when {
status != null -> {
// 連投してIdempotency が同じだった場合もエラーにはならず、ここを通る
callback.onPostComplete(account, status)
return
}
scheduledStatusSucceeded -> {
callback.onScheduledPostComplete(account)
return
override fun handleResult(result : TootApiResult?) {
result ?: return
val status = this.status
when {
status != null -> {
// 連投してIdempotency が同じだった場合もエラーにはならず、ここを通る
callback.onPostComplete(account, status)
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(": → ")
sb.setSpan(
ForegroundColorSpan(
getAttributeColor(
activity,
R.attr.colorTimeSmall
)
),
ForegroundColorSpan(activity.getAttributeColor(R.attr.colorTimeSmall)),
start,
sb.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
@ -922,6 +920,7 @@ class PostHelper(
}
interface Callback2 {
fun onTextUpdate()
fun canOpenPopup() : Boolean
@ -1053,7 +1052,10 @@ class PostHelper(
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()
}
@ -1091,7 +1093,7 @@ class PostHelper(
fun openFeaturedTagList(list : List<TootTag>?) {
val ad = ActionsDialog()
list?.forEach {tag->
list?.forEach { tag ->
ad.addAction("#${tag.name}") {
val et = this.et ?: return@addAction
@ -1112,7 +1114,7 @@ class PostHelper(
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 src = et.text ?: ""
@ -1124,7 +1126,7 @@ class PostHelper(
sb.append(src.subSequence(0, start))
if(! EmojiDecoder.canStartHashtag(sb, sb.length)) sb.append(' ')
sb.append('#')
val newSelection = sb.length
if(end < src_length) sb.append(src.subSequence(end, src_length))
et.text = sb

View File

@ -4,17 +4,12 @@ import android.content.DialogInterface
import jp.juggler.subwaytooter.api.TootApiResult
import jp.juggler.subwaytooter.table.SavedAccount
/////////////////////////////////////////////////////////////////
// callback (that returns Unit)
typealias EmptyCallback = ()->Unit
typealias TootApiResultCallback = (result : TootApiResult) -> 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_height = options.outHeight
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
}
@ -204,7 +204,7 @@ fun createResizedBitmap(
}
if(sourceBitmap == null) {
showToast(context, false, "could not decode image.")
context.showToast(false, "could not decode image.")
return null
}
try {
@ -234,7 +234,7 @@ fun createResizedBitmap(
Bitmap.createBitmap(dstSizeInt.x, dstSizeInt.y, Bitmap.Config.ARGB_8888)
try {
return if(dst == null) {
showToast(context, false, "bitmap creation failed.")
context.showToast(false, "bitmap creation failed.")
null
} else {
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)
ToastUtils.showToastImpl(context, bLong, msg)
ToastUtils.showToastImpl(this, bLong, msg)
}
fun showToast(context : Context, ex : Throwable, fmt : String?, vararg args : Any) {
ToastUtils.showToastImpl(context, true, ex.withCaption(fmt, *args))
fun Context.showToast(ex : Throwable, fmt : String?, vararg args : Any) {
ToastUtils.showToastImpl(this, true, ex.withCaption(fmt, *args))
}
fun showToast(context : Context, bLong : Boolean, string_id : Int, vararg args : Any) {
ToastUtils.showToastImpl(context, bLong, context.getString(string_id, *args))
fun Context.showToast(bLong : Boolean, string_id : Int, vararg args : Any) {
ToastUtils.showToastImpl(this, bLong, getString(string_id, *args))
}
fun showToast(context : Context, ex : Throwable, string_id : Int, vararg args : Any) {
ToastUtils.showToastImpl(context, true, ex.withCaption(context.resources, string_id, *args))
fun Context.showToast(ex : Throwable, string_id : Int, vararg args : Any) {
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 {
val theme = context.theme
fun Context.getAttributeColor(attrId : Int) : Int {
val a = theme.obtainStyledAttributes(intArrayOf(attrId))
val color = a.getColor(0, Color.BLACK)
a.recycle()
@ -298,10 +297,10 @@ fun CharSequence.copyToClipboard(context : Context) {
clipboard.setPrimaryClip(clip)
showToast(context, false, R.string.copy_complete)
context.showToast(false, R.string.copy_complete)
} catch(ex : Throwable) {
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()
}
private fun mixColor(col1 : Int, col2 : Int) : Int = Color.rgb(
(Color.red(col1) + Color.red(col2)) ushr 1,
(Color.green(col1) + Color.green(col2)) ushr 1,
(Color.blue(col1) + Color.blue(col2)) ushr 1
)
fun setSwitchColor(
activity : AppCompatActivity,
fun Context.setSwitchColor(
pref : SharedPreferences,
root : View?
) {
val colorBg = getAttributeColor(activity, R.attr.colorWindowBackground)
val colorBg = getAttributeColor(R.attr.colorWindowBackground)
val colorOn = Pref.ipSwitchOnColor(pref)
val colorOff = /* Pref.ipSwitchOffColor(pref).notZero() ?: */
getAttributeColor(activity, android.R.attr.colorPrimary)
getAttributeColor(android.R.attr.colorPrimary)
val colorDisabled = mixColor(colorBg, colorOff)
@ -157,7 +154,6 @@ fun setSwitchColor(
}
}
private fun rgbToLab(rgb : Int) : Triple<Float, Float, 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 {
forceDark -> Color.BLACK
else -> Pref.ipStatusBarColor(App1.pref).notZero()
?: getAttributeColor(activity, R.attr.colorPrimaryDark)
?: getAttributeColor(R.attr.colorPrimaryDark)
}
statusBarColor = c or Color.BLACK