From 35deaf985f4c0fad0ef0c21258290057a5b5474a Mon Sep 17 00:00:00 2001 From: tateisu Date: Sat, 19 Dec 2020 15:46:42 +0900 Subject: [PATCH] =?UTF-8?q?=E3=80=8C=E3=82=A2=E3=83=97=E3=83=AA=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A/=E6=8C=99=E5=8B=95/Web=E3=83=96=E3=83=A9=E3=82=A6?= =?UTF-8?q?=E3=82=B6=E3=80=8D=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 12 + .../jp/juggler/subwaytooter/ActAppSetting.kt | 67 +- .../jp/juggler/subwaytooter/AppSettingItem.kt | 1576 +++++++++-------- .../main/java/jp/juggler/subwaytooter/Pref.kt | 3 +- .../subwaytooter/dialog/DlgAppPicker.kt | 5 +- .../jp/juggler/subwaytooter/util/AppOpener.kt | 32 +- .../juggler/subwaytooter/util/CustomShare.kt | 293 +-- app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 9 files changed, 1043 insertions(+), 947 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a55e498c..34484157 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,18 @@ + + + + + + + + + + + + diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.kt b/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.kt index 3ea95b36..1d198489 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.kt @@ -2,6 +2,7 @@ package jp.juggler.subwaytooter import android.content.Intent import android.content.SharedPreferences +import android.content.pm.ResolveInfo import android.graphics.Color import android.graphics.Typeface import android.net.Uri @@ -21,13 +22,14 @@ import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import com.jrummyapps.android.colorpicker.ColorPickerDialog import com.jrummyapps.android.colorpicker.ColorPickerDialogListener -import jp.juggler.subwaytooter.util.CustomShare -import jp.juggler.subwaytooter.util.CustomShareTarget import jp.juggler.subwaytooter.dialog.DlgAppPicker import jp.juggler.subwaytooter.notification.PollingWorker import jp.juggler.subwaytooter.table.AcctColor import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.util.AsyncActivity +import jp.juggler.subwaytooter.util.CustomShare +import jp.juggler.subwaytooter.util.CustomShareTarget +import jp.juggler.subwaytooter.util.cn import jp.juggler.util.* import org.apache.commons.io.IOUtils import java.io.File @@ -1127,7 +1129,7 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi return list.size } - override fun getItem(position : Int) : Any? { + override fun getItem(position : Int) : Any { return list[position] } @@ -1164,16 +1166,17 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi } } - fun openCustomShareChooser(target : CustomShareTarget) { + fun openCustomShareChooser(appSettingItem: AppSettingItem,target : CustomShareTarget) { try { val rv = DlgAppPicker( this, - Intent().apply { + intent = Intent().apply { action = Intent.ACTION_SEND type = "text/plain" putExtra(Intent.EXTRA_TEXT, getString(R.string.content_sample)) - } - ) { setCustomShare(target, it) } + }, + addCopyAction = true + ) { setCustomShare(appSettingItem,target, it) } .show() if(! rv) showToast(true, "share target app is not installed.") } catch(ex : Throwable) { @@ -1182,22 +1185,11 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi } } - fun setCustomShare(target : CustomShareTarget?, value : String) { - - target ?: return - - val item = when(target) { - CustomShareTarget.Translate -> AppSettingItem.CUSTOM_TRANSLATE - CustomShareTarget.CustomShare1 -> AppSettingItem.CUSTOM_SHARE_1 - CustomShareTarget.CustomShare2 -> AppSettingItem.CUSTOM_SHARE_2 - CustomShareTarget.CustomShare3 -> AppSettingItem.CUSTOM_SHARE_3 - } - ?: error("setCustomShare $target has no setting item.") - - val sp : StringPref = item.pref.cast() ?: error("$target: not StringPref") + fun setCustomShare(appSettingItem: AppSettingItem,target : CustomShareTarget, value : String) { + val sp : StringPref = appSettingItem.pref.cast() ?: error("$target: not StringPref") pref.edit().put(sp, value).apply() - showCustomShareIcon(findItemViewHolder(item)?.textView1, target) + showCustomShareIcon(findItemViewHolder(appSettingItem)?.textView1, target) } fun showCustomShareIcon(tv : TextView?, target : CustomShareTarget) { @@ -1208,5 +1200,36 @@ class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickLi tv.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null) tv.compoundDrawablePadding = (resources.displayMetrics.density * 4f + 0.5f).toInt() } - + + fun openWebBrowserChooser(appSettingItem: AppSettingItem, intent:Intent, filter: (ResolveInfo) -> Boolean ) { + try { + val rv = DlgAppPicker( + this, + intent=intent, + filter = filter, + addCopyAction = false + ) { setWebBrowser( appSettingItem,it) } + .show() + if(! rv) showToast(true, "share target app is not installed.") + } catch(ex : Throwable) { + log.trace(ex) + showToast(ex, "openCustomShareChooser failed.") + } + } + + fun setWebBrowser(appSettingItem: AppSettingItem, value : String) { + val sp : StringPref = appSettingItem.pref.cast() ?: error("${getString(appSettingItem.caption)}: not StringPref") + pref.edit().put(sp, value).apply() + + showWebBrowser(findItemViewHolder(appSettingItem)?.textView1, value ) + } + + fun showWebBrowser(tv : TextView?,prefValue:String) { + tv ?: return + val cn =prefValue.cn() + val (label, icon) = CustomShare.getInfo(this, cn) + tv.text = label ?: getString(R.string.not_selected) + tv.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null) + tv.compoundDrawablePadding = (resources.displayMetrics.density * 4f + 0.5f).toInt() + } } \ No newline at end of file diff --git a/app/src/main/java/jp/juggler/subwaytooter/AppSettingItem.kt b/app/src/main/java/jp/juggler/subwaytooter/AppSettingItem.kt index abc7539e..ad7a1841 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/AppSettingItem.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/AppSettingItem.kt @@ -14,238 +14,233 @@ import jp.juggler.subwaytooter.util.openBrowser import jp.juggler.util.* import org.jetbrains.anko.backgroundDrawable -enum class SettingType(val id : Int) { - Path(0), - Divider(1), - Switch(2), - EditText(3), - Spinner(4), - ColorOpaque(5), - ColorAlpha(6), - Action(7), - Sample(8), - Group(9), - TextWithSelector(10), - CheckBox(11), - Section(12) +enum class SettingType(val id: Int) { + Path(0), + Divider(1), + Switch(2), + EditText(3), + Spinner(4), + ColorOpaque(5), + ColorAlpha(6), + Action(7), + Sample(8), + Group(9), + TextWithSelector(10), + CheckBox(11), + Section(12) } class AppSettingItem( - val parent : AppSettingItem?, - val type : SettingType, - @StringRes val caption : Int, - val pref : BasePref<*>? = null + val parent: AppSettingItem?, + val type: SettingType, + @StringRes val caption: Int, + val pref: BasePref<*>? = null ) { - - @StringRes - var desc : Int = 0 - var descClickSet = false - var descClick : ActAppSetting.() -> Unit = {} - set(value) { - field = value - descClickSet = true - } - - var getError : ActAppSetting.(String) -> String? = { null } - - // may be open exportAppData() or importAppData() - var action : ActAppSetting.() -> Unit = {} - - var changed : ActAppSetting.() -> Unit = {} - - // used for EditText - var inputType = InputTypeEx.text - - var sampleLayoutId : Int = 0 - var sampleUpdate : (ActAppSetting, View) -> Unit = { _, _ -> } - - var spinnerArgs : IntArray? = null - var spinnerArgsProc : (ActAppSetting) -> List = { _ -> emptyList() } - var spinnerInitializer : ActAppSetting.(Spinner) -> Unit = {} - var spinnerOnSelected : ActAppSetting.(Spinner, Int) -> Unit = { _, _ -> } - - var enabled : Boolean = true - - var onClickEdit : ActAppSetting.() -> Unit = {} - var onClickReset : ActAppSetting.() -> Unit = {} - var showTextView : ActAppSetting.(TextView) -> Unit = {} - - // for EditText - var hint : String? = null - var filter : (String) -> String = { it.trim() } - var captionFontSize : ActAppSetting.() -> Float? = { null } - var captionSpacing : ActAppSetting.() -> Float? = { null } - - // cast before save - var toFloat : ActAppSetting.(String) -> Float = { 0f } - var fromFloat : ActAppSetting.(Float) -> String = { it.toString() } - - val items = ArrayList() - - fun section( - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} + + @StringRes + var desc: Int = 0 + var descClickSet = false + var descClick: ActAppSetting.() -> Unit = {} + set(value) { + field = value + descClickSet = true + } + + var getError: ActAppSetting.(String) -> String? = { null } + + // may be open exportAppData() or importAppData() + var action: ActAppSetting.() -> Unit = {} + + var changed: ActAppSetting.() -> Unit = {} + + // used for EditText + var inputType = InputTypeEx.text + + var sampleLayoutId: Int = 0 + var sampleUpdate: (ActAppSetting, View) -> Unit = { _, _ -> } + + var spinnerArgs: IntArray? = null + var spinnerArgsProc: (ActAppSetting) -> List = { _ -> emptyList() } + var spinnerInitializer: ActAppSetting.(Spinner) -> Unit = {} + var spinnerOnSelected: ActAppSetting.(Spinner, Int) -> Unit = { _, _ -> } + + var enabled: Boolean = true + + var onClickEdit: ActAppSetting.() -> Unit = {} + var onClickReset: ActAppSetting.() -> Unit = {} + var showTextView: ActAppSetting.(TextView) -> Unit = {} + + // for EditText + var hint: String? = null + var filter: (String) -> String = { it.trim() } + var captionFontSize: ActAppSetting.() -> Float? = { null } + var captionSpacing: ActAppSetting.() -> Float? = { null } + + // cast before save + var toFloat: ActAppSetting.(String) -> Float = { 0f } + var fromFloat: ActAppSetting.(Float) -> String = { it.toString() } + + val items = ArrayList() + + fun section( + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} ) { - items.add(AppSettingItem(this, SettingType.Section, caption).apply { initializer() }) - } - - fun group( - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} + items.add(AppSettingItem(this, SettingType.Section, caption).apply { initializer() }) + } + + fun group( + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} ) { - items.add(AppSettingItem(this, SettingType.Group, caption).apply { initializer() }) - } - - fun item( - type : SettingType, - pref : BasePref<*>?, - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} - ) : AppSettingItem { - val item = AppSettingItem(this, type, caption, pref).apply { initializer() } - items.add(item) - return item - } - - fun spinner( - pref : IntPref, - @StringRes caption : Int, - vararg args : Int + items.add(AppSettingItem(this, SettingType.Group, caption).apply { initializer() }) + } + + fun item( + type: SettingType, + pref: BasePref<*>?, + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} + ): AppSettingItem { + val item = AppSettingItem(this, type, caption, pref).apply { initializer() } + items.add(item) + return item + } + + fun spinner( + pref: IntPref, + @StringRes caption: Int, + vararg args: Int ) = item(SettingType.Spinner, pref, caption) { - spinnerArgs = args - } - - fun spinner( - pref : IntPref, - @StringRes caption : Int, - argsProc : (ActAppSetting) -> List + spinnerArgs = args + } + + fun spinner( + pref: IntPref, + @StringRes caption: Int, + argsProc: (ActAppSetting) -> List ) = item(SettingType.Spinner, pref, caption) { - spinnerArgsProc = argsProc - } - - fun sw( - pref : BooleanPref, - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} + spinnerArgsProc = argsProc + } + + fun sw( + pref: BooleanPref, + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} ) = item(SettingType.Switch, pref, caption, initializer) - - fun checkbox( - pref : BooleanPref, - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} + + fun checkbox( + pref: BooleanPref, + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} ) = item(SettingType.CheckBox, pref, caption, initializer) - - fun action( - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} + + fun action( + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} ) = item(SettingType.Action, null, caption, initializer) - - fun colorOpaque( - pref : IntPref, - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} + + fun colorOpaque( + pref: IntPref, + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} ) = item(SettingType.ColorOpaque, pref, caption, initializer) - - fun colorAlpha( - pref : IntPref, - @StringRes caption : Int, - initializer : AppSettingItem.() -> Unit = {} + + fun colorAlpha( + pref: IntPref, + @StringRes caption: Int, + initializer: AppSettingItem.() -> Unit = {} ) = item(SettingType.ColorAlpha, pref, caption, initializer) - - fun text( - pref : StringPref, - @StringRes caption : Int, - inputType : Int, - initializer : AppSettingItem.() -> Unit = {} + + fun text( + pref: StringPref, + @StringRes caption: Int, + inputType: Int, + initializer: AppSettingItem.() -> Unit = {} ) = item(SettingType.EditText, pref, caption) { - this.inputType = inputType - this.initializer() - } - - fun textX( - pref : BasePref<*>, - @StringRes caption : Int, - inputType : Int, - initializer : AppSettingItem.() -> Unit = {} + this.inputType = inputType + this.initializer() + } + + fun textX( + pref: BasePref<*>, + @StringRes caption: Int, + inputType: Int, + initializer: AppSettingItem.() -> Unit = {} ) = item(SettingType.EditText, pref, caption) { - this.inputType = inputType - this.initializer() - } - - fun sample( - sampleLayoutId : Int = 0, - sampleUpdate : (ActAppSetting, View) -> Unit = { _, _ -> } + this.inputType = inputType + this.initializer() + } + + fun sample( + sampleLayoutId: Int = 0, + sampleUpdate: (ActAppSetting, View) -> Unit = { _, _ -> } // ,initializer : AppSettingItem.() -> Unit = {} ) = item(SettingType.Sample, pref, caption) { - this.sampleLayoutId = sampleLayoutId - this.sampleUpdate = sampleUpdate - } - - fun scan(block : (AppSettingItem) -> Unit) { - block(this) - for(item in items) item.scan(block) - } - - companion object { - - var SAMPLE_CCD_HEADER : AppSettingItem? = null - var SAMPLE_CCD_BODY : AppSettingItem? = null - var SAMPLE_FOOTER : AppSettingItem? = null - - var CUSTOM_TRANSLATE : AppSettingItem? = null - var CUSTOM_SHARE_1 : AppSettingItem? = null - var CUSTOM_SHARE_2 : AppSettingItem? = null - var CUSTOM_SHARE_3 : AppSettingItem? = null - - var TIMELINE_FONT : AppSettingItem? = null - var TIMELINE_FONT_BOLD : AppSettingItem? = null - - var FONT_SIZE_TIMELINE : AppSettingItem? = null - var FONT_SIZE_NOTIFICATION_TL : AppSettingItem? = null - } + this.sampleLayoutId = sampleLayoutId + this.sampleUpdate = sampleUpdate + } + + fun scan(block: (AppSettingItem) -> Unit) { + block(this) + for (item in items) item.scan(block) + } + + companion object { + + var SAMPLE_CCD_HEADER: AppSettingItem? = null + var SAMPLE_CCD_BODY: AppSettingItem? = null + var SAMPLE_FOOTER: AppSettingItem? = null + + var TIMELINE_FONT: AppSettingItem? = null + var TIMELINE_FONT_BOLD: AppSettingItem? = null + + var FONT_SIZE_TIMELINE: AppSettingItem? = null + var FONT_SIZE_NOTIFICATION_TL: AppSettingItem? = null + } } val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_setting).apply { - - section(R.string.notifications) { - - group(R.string.notification_style_before_oreo) { - - checkbox(Pref.bpNotificationSound, R.string.sound) { - enabled = Build.VERSION.SDK_INT < 26 - } - - checkbox(Pref.bpNotificationVibration, R.string.vibration) { - enabled = Build.VERSION.SDK_INT < 26 - } - - checkbox(Pref.bpNotificationLED, R.string.led) { - enabled = Build.VERSION.SDK_INT < 26 - } - - sample(R.layout.setting_sample_notification_desc) - } - - text( + + section(R.string.notifications) { + + group(R.string.notification_style_before_oreo) { + + checkbox(Pref.bpNotificationSound, R.string.sound) { + enabled = Build.VERSION.SDK_INT < 26 + } + + checkbox(Pref.bpNotificationVibration, R.string.vibration) { + enabled = Build.VERSION.SDK_INT < 26 + } + + checkbox(Pref.bpNotificationLED, R.string.led) { + enabled = Build.VERSION.SDK_INT < 26 + } + + sample(R.layout.setting_sample_notification_desc) + } + + text( Pref.spPullNotificationCheckInterval, R.string.pull_notification_check_interval, InputTypeEx.number ) - - sw(Pref.bpShowAcctInSystemNotification, R.string.show_acct_in_system_notification) - - sw(Pref.bpSeparateReplyNotificationGroup, R.string.separate_notification_group_for_reply) { - enabled = Build.VERSION.SDK_INT >= 26 - } - - sw(Pref.bpDivideNotification, R.string.divide_notification) - } - - section(R.string.behavior) { - - sw(Pref.bpDontConfirmBeforeCloseColumn, R.string.dont_confirm_before_close_column) - - spinner( + + sw(Pref.bpShowAcctInSystemNotification, R.string.show_acct_in_system_notification) + + sw(Pref.bpSeparateReplyNotificationGroup, R.string.separate_notification_group_for_reply) { + enabled = Build.VERSION.SDK_INT >= 26 + } + + sw(Pref.bpDivideNotification, R.string.divide_notification) + } + + section(R.string.behavior) { + + sw(Pref.bpDontConfirmBeforeCloseColumn, R.string.dont_confirm_before_close_column) + + spinner( Pref.ipBackButtonAction, R.string.back_button_action, R.string.ask_always, @@ -253,87 +248,126 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett R.string.open_column_list, R.string.app_exit ) - - sw(Pref.bpExitAppWhenCloseProtectedColumn, R.string.exit_app_when_close_protected_column) - sw(Pref.bpScrollTopFromColumnStrip, R.string.scroll_top_from_column_strip) - sw(Pref.bpDontScreenOff, R.string.dont_screen_off) - sw(Pref.bpDontUseCustomTabs, R.string.dont_use_custom_tabs) - sw(Pref.bpPriorChrome, R.string.prior_chrome_custom_tabs) - sw(Pref.bpAllowColumnDuplication, R.string.allow_column_duplication) - sw(Pref.bpForceGap, R.string.force_gap_when_refresh) - spinner( + + sw(Pref.bpExitAppWhenCloseProtectedColumn, R.string.exit_app_when_close_protected_column) + sw(Pref.bpScrollTopFromColumnStrip, R.string.scroll_top_from_column_strip) + sw(Pref.bpDontScreenOff, R.string.dont_screen_off) + sw(Pref.bpDontUseCustomTabs, R.string.dont_use_custom_tabs) + sw(Pref.bpPriorChrome, R.string.prior_chrome_custom_tabs) + + item( + SettingType.TextWithSelector, + Pref.spWebBrowser, + R.string.web_browser + ) { + onClickEdit = { + openWebBrowserChooser( + this@item, + intent = Intent(Intent.ACTION_VIEW, "https://joinmastodon.org/".toUri()).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addCategory(Intent.CATEGORY_BROWSABLE) + }, + filter = { + when { + it.activityInfo.packageName == packageName -> false + !it.activityInfo.exported -> false + + // Huaweiの謎Activityのせいでうまく働かないことがある + -1 != it.activityInfo.packageName.indexOf("com.huawei.android.internal") -> false + + // 標準アプリが設定されていない場合、アプリを選択するためのActivityが出てくる場合がある + it.activityInfo.packageName == "android" -> false + it.activityInfo.javaClass.name.startsWith("com.android.internal") -> false + it.activityInfo.javaClass.name.startsWith("com.android.systemui") -> false + + // たぶんChromeとかfirefoxとか + else -> true + } + } + ) + } + onClickReset = { setWebBrowser(this@item, "") } + showTextView = { + showWebBrowser(it, this@item.pref.cast()!!.invoke(pref)) + } + } + + sw(Pref.bpAllowColumnDuplication, R.string.allow_column_duplication) + sw(Pref.bpForceGap, R.string.force_gap_when_refresh) + spinner( Pref.ipGapHeadScrollPosition, R.string.scroll_position_after_read_gap_from_head, R.string.gap_head, R.string.gap_tail, ) - spinner( + spinner( Pref.ipGapTailScrollPosition, R.string.scroll_position_after_read_gap_from_tail, R.string.gap_head, R.string.gap_tail, ) - text(Pref.spClientName, R.string.client_name, InputTypeEx.text) - - text(Pref.spUserAgent, R.string.user_agent, InputTypeEx.textMultiLine) { - hint = App1.userAgentDefault - filter = { it.replace(ActAppSetting.reLinefeed, " ").trim() } - getError = { - val m = App1.reNotAllowedInUserAgent.matcher(it) - when(m.find()) { + text(Pref.spClientName, R.string.client_name, InputTypeEx.text) + + text(Pref.spUserAgent, R.string.user_agent, InputTypeEx.textMultiLine) { + hint = App1.userAgentDefault + filter = { it.replace(ActAppSetting.reLinefeed, " ").trim() } + getError = { + val m = App1.reNotAllowedInUserAgent.matcher(it) + when (m.find()) { true -> getString(R.string.user_agent_error, m.group()) - else -> null - } - } - } - - sw(Pref.bpDontRemoveDeletedToot, R.string.dont_remove_deleted_toot_from_timeline) - sw(Pref.bpCustomEmojiSeparatorZwsp, R.string.custom_emoji_separator_zwsp) - sw(Pref.bpShowTranslateButton, R.string.show_translate_button) - - AppSettingItem.CUSTOM_TRANSLATE = item( + else -> null + } + } + } + + sw(Pref.bpDontRemoveDeletedToot, R.string.dont_remove_deleted_toot_from_timeline) + sw(Pref.bpCustomEmojiSeparatorZwsp, R.string.custom_emoji_separator_zwsp) + sw(Pref.bpShowTranslateButton, R.string.show_translate_button) + + item( SettingType.TextWithSelector, Pref.spTranslateAppComponent, R.string.translation_app ) { - val target = CustomShareTarget.Translate - onClickEdit = { openCustomShareChooser(target) } - onClickReset = { setCustomShare(target, "") } - showTextView = { showCustomShareIcon(it, target) } - } - - AppSettingItem.CUSTOM_SHARE_1 = item( + val target = CustomShareTarget.Translate + onClickEdit = { openCustomShareChooser(this@item, target) } + onClickReset = { setCustomShare(this@item, target, "") } + showTextView = { showCustomShareIcon(it, target) } + } + + item( SettingType.TextWithSelector, Pref.spCustomShare1, R.string.custom_share_button_1 ) { - val target = CustomShareTarget.CustomShare1 - onClickEdit = { openCustomShareChooser(target) } - onClickReset = { setCustomShare(target, "") } - showTextView = { showCustomShareIcon(it, target) } - } - AppSettingItem.CUSTOM_SHARE_2 = item( + val target = CustomShareTarget.CustomShare1 + onClickEdit = { openCustomShareChooser(this@item, target) } + onClickReset = { setCustomShare(this@item, target, "") } + showTextView = { showCustomShareIcon(it, target) } + } + + item( SettingType.TextWithSelector, Pref.spCustomShare2, R.string.custom_share_button_2 ) { - val target = CustomShareTarget.CustomShare2 - onClickEdit = { openCustomShareChooser(target) } - onClickReset = { setCustomShare(target, "") } - showTextView = { showCustomShareIcon(it, target) } - } - AppSettingItem.CUSTOM_SHARE_3 = item( + val target = CustomShareTarget.CustomShare2 + onClickEdit = { openCustomShareChooser(this@item, target) } + onClickReset = { setCustomShare(this@item, target, "") } + showTextView = { showCustomShareIcon(it, target) } + } + item( SettingType.TextWithSelector, Pref.spCustomShare3, R.string.custom_share_button_3 ) { - val target = CustomShareTarget.CustomShare3 - onClickEdit = { openCustomShareChooser(target) } - onClickReset = { setCustomShare(target, "") } - showTextView = { showCustomShareIcon(it, target) } - } - - spinner( + val target = CustomShareTarget.CustomShare3 + onClickEdit = { openCustomShareChooser(this@item, target) } + onClickReset = { setCustomShare(this@item, target, "") } + showTextView = { showCustomShareIcon(it, target) } + } + + spinner( Pref.ipAdditionalButtonsPosition, R.string.additional_buttons_position, R.string.top, @@ -341,17 +375,17 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett R.string.start, R.string.end ) - - sw(Pref.bpEnablePixelfed, R.string.enable_connect_to_pixelfed_server) - sw(Pref.bpShowFilteredWord, R.string.show_filtered_word) - sw(Pref.bpEnableDomainTimeline, R.string.enable_domain_timeline) - } - - section(R.string.post) { - - spinner(Pref.ipResizeImage, R.string.resize_image) { activity -> - ActPost.resizeConfigList.map { - when(it.type) { + + sw(Pref.bpEnablePixelfed, R.string.enable_connect_to_pixelfed_server) + sw(Pref.bpShowFilteredWord, R.string.show_filtered_word) + sw(Pref.bpEnableDomainTimeline, R.string.enable_domain_timeline) + } + + section(R.string.post) { + + spinner(Pref.ipResizeImage, R.string.resize_image) { activity -> + ActPost.resizeConfigList.map { + when (it.type) { ResizeType.None -> activity.getString(R.string.dont_resize) ResizeType.LongSide -> activity.getString(R.string.long_side_pixel, it.size) ResizeType.SquarePixel -> activity.getString( @@ -359,623 +393,623 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett it.size * it.size, it.size ) - } - } - } - - text(Pref.spMediaSizeMax, R.string.media_attachment_max_byte_size, InputTypeEx.number) - text(Pref.spMovieSizeMax, R.string.media_attachment_max_byte_size_movie, InputTypeEx.number) - text( + } + } + } + + text(Pref.spMediaSizeMax, R.string.media_attachment_max_byte_size, InputTypeEx.number) + text(Pref.spMovieSizeMax, R.string.media_attachment_max_byte_size_movie, InputTypeEx.number) + text( Pref.spMediaSizeMaxPixelfed, R.string.media_attachment_max_byte_size_pixelfed, InputTypeEx.number ) - - spinner( + + spinner( Pref.ipRefreshAfterToot, R.string.refresh_after_toot, R.string.refresh_scroll_to_toot, R.string.refresh_no_scroll, R.string.dont_refresh ) - - sw(Pref.bpPostButtonBarTop, R.string.show_post_button_bar_top) - - sw( + + sw(Pref.bpPostButtonBarTop, R.string.show_post_button_bar_top) + + sw( Pref.bpDontDuplicationCheck, R.string.dont_add_duplication_check_header ) - - sw(Pref.bpQuickTootBar, R.string.show_quick_toot_bar) - - sw( + + sw(Pref.bpQuickTootBar, R.string.show_quick_toot_bar) + + sw( Pref.bpDontUseActionButtonWithQuickTootBar, R.string.dont_use_action_button_with_quick_toot_bar ) - - text(Pref.spQuoteNameFormat, R.string.format_of_quote_name, InputTypeEx.text) { - filter = { it } // don't trim - } - - sw( + + text(Pref.spQuoteNameFormat, R.string.format_of_quote_name, InputTypeEx.text) { + filter = { it } // don't trim + } + + sw( Pref.bpAppendAttachmentUrlToContent, R.string.append_attachment_url_to_content ) - - sw( + + sw( Pref.bpWarnHashtagAsciiAndNonAscii, R.string.warn_hashtag_ascii_and_non_ascii ) - - sw( + + sw( Pref.bpEmojiPickerCloseOnSelected, R.string.close_emoji_picker_when_selected ) - - sw(Pref.bpIgnoreTextInSharedMedia, R.string.ignore_text_in_shared_media) - } - - section(R.string.tablet_mode) { - - sw(Pref.bpDisableTabletMode, R.string.disable_tablet_mode) - - text(Pref.spColumnWidth, R.string.minimum_column_width, InputTypeEx.number) - - item( + + sw(Pref.bpIgnoreTextInSharedMedia, R.string.ignore_text_in_shared_media) + } + + section(R.string.tablet_mode) { + + sw(Pref.bpDisableTabletMode, R.string.disable_tablet_mode) + + text(Pref.spColumnWidth, R.string.minimum_column_width, InputTypeEx.number) + + item( SettingType.Spinner, Pref.lpTabletTootDefaultAccount, R.string.toot_button_default_account ) { - val lp = pref.cast() !! - spinnerInitializer = { spinner -> - val adapter = AccountAdapter() - spinner.adapter = adapter - spinner.setSelection(adapter.getIndexFromId(lp(pref))) - } - spinnerOnSelected = { spinner, index -> - val adapter = spinner.adapter.cast() - ?: error("spinnerOnSelected: missing AccountAdapter") - pref.edit().put(lp, adapter.getIdFromIndex(index)).apply() - } - } - - sw( + val lp = pref.cast()!! + spinnerInitializer = { spinner -> + val adapter = AccountAdapter() + spinner.adapter = adapter + spinner.setSelection(adapter.getIndexFromId(lp(pref))) + } + spinnerOnSelected = { spinner, index -> + val adapter = spinner.adapter.cast() + ?: error("spinnerOnSelected: missing AccountAdapter") + pref.edit().put(lp, adapter.getIdFromIndex(index)).apply() + } + } + + sw( Pref.bpQuickTootOmitAccountSelection, R.string.quick_toot_omit_account_selection ) - - spinner( + + spinner( Pref.ipJustifyWindowContentPortrait, R.string.justify_window_content_portrait, R.string.default_, R.string.start, R.string.end ) - } - - section(R.string.media_attachment) { - sw(Pref.bpUseInternalMediaViewer, R.string.use_internal_media_viewer) - sw(Pref.bpPriorLocalURL, R.string.prior_local_url_when_open_attachment) - text(Pref.spMediaThumbHeight, R.string.media_thumbnail_height, InputTypeEx.number) - sw(Pref.bpDontCropMediaThumb, R.string.dont_crop_media_thumbnail) - sw(Pref.bpVerticalArrangeThumbnails, R.string.thumbnails_arrange_vertically) - } - - section(R.string.animation) { - sw(Pref.bpEnableGifAnimation, R.string.enable_gif_animation) - sw(Pref.bpDisableEmojiAnimation, R.string.disable_custom_emoji_animation) - } - - section(R.string.appearance) { - sw(Pref.bpSimpleList, R.string.simple_list) - sw(Pref.bpShowFollowButtonInButtonBar, R.string.show_follow_button_in_button_bar) - sw(Pref.bpDontShowPreviewCard, R.string.dont_show_preview_card) - sw(Pref.bpShortAcctLocalUser, R.string.short_acct_local_user) - sw(Pref.bpMentionFullAcct, R.string.mention_full_acct) - sw(Pref.bpRelativeTimestamp, R.string.relative_timestamp) - - item( + } + + section(R.string.media_attachment) { + sw(Pref.bpUseInternalMediaViewer, R.string.use_internal_media_viewer) + sw(Pref.bpPriorLocalURL, R.string.prior_local_url_when_open_attachment) + text(Pref.spMediaThumbHeight, R.string.media_thumbnail_height, InputTypeEx.number) + sw(Pref.bpDontCropMediaThumb, R.string.dont_crop_media_thumbnail) + sw(Pref.bpVerticalArrangeThumbnails, R.string.thumbnails_arrange_vertically) + } + + section(R.string.animation) { + sw(Pref.bpEnableGifAnimation, R.string.enable_gif_animation) + sw(Pref.bpDisableEmojiAnimation, R.string.disable_custom_emoji_animation) + } + + section(R.string.appearance) { + sw(Pref.bpSimpleList, R.string.simple_list) + sw(Pref.bpShowFollowButtonInButtonBar, R.string.show_follow_button_in_button_bar) + sw(Pref.bpDontShowPreviewCard, R.string.dont_show_preview_card) + sw(Pref.bpShortAcctLocalUser, R.string.short_acct_local_user) + sw(Pref.bpMentionFullAcct, R.string.mention_full_acct) + sw(Pref.bpRelativeTimestamp, R.string.relative_timestamp) + + item( SettingType.Spinner, Pref.spTimeZone, R.string.timezone ) { - val sp : StringPref = pref.cast() !! - spinnerInitializer = { spinner -> - val adapter = TimeZoneAdapter() - spinner.adapter = adapter - spinner.setSelection(adapter.getIndexFromId(sp(pref))) - } - spinnerOnSelected = { spinner, index -> - val adapter = spinner.adapter.cast() - ?: error("spinnerOnSelected: missing TimeZoneAdapter") - pref.edit().put(sp, adapter.getIdFromIndex(index)).apply() - } - } - - sw(Pref.bpShowAppName, R.string.always_show_application) - sw(Pref.bpShowLanguage, R.string.always_show_language) - text(Pref.spAutoCWLines, R.string.auto_cw, InputTypeEx.number) - text(Pref.spCardDescriptionLength, R.string.card_description_length, InputTypeEx.number) - - spinner( + val sp: StringPref = pref.cast()!! + spinnerInitializer = { spinner -> + val adapter = TimeZoneAdapter() + spinner.adapter = adapter + spinner.setSelection(adapter.getIndexFromId(sp(pref))) + } + spinnerOnSelected = { spinner, index -> + val adapter = spinner.adapter.cast() + ?: error("spinnerOnSelected: missing TimeZoneAdapter") + pref.edit().put(sp, adapter.getIdFromIndex(index)).apply() + } + } + + sw(Pref.bpShowAppName, R.string.always_show_application) + sw(Pref.bpShowLanguage, R.string.always_show_language) + text(Pref.spAutoCWLines, R.string.auto_cw, InputTypeEx.number) + text(Pref.spCardDescriptionLength, R.string.card_description_length, InputTypeEx.number) + + spinner( Pref.ipRepliesCount, R.string.display_replies_count, R.string.replies_count_simple, R.string.replies_count_actual, R.string.replies_count_none ) - spinner( + spinner( Pref.ipBoostsCount, R.string.display_boost_count, R.string.replies_count_simple, R.string.replies_count_actual, R.string.replies_count_none ) - spinner( + spinner( Pref.ipFavouritesCount, R.string.display_favourite_count, R.string.replies_count_simple, R.string.replies_count_actual, R.string.replies_count_none ) - - spinner( + + spinner( Pref.ipVisibilityStyle, R.string.visibility_style, R.string.visibility_style_by_account, R.string.mastodon, R.string.misskey ) - - AppSettingItem.TIMELINE_FONT = item( + + AppSettingItem.TIMELINE_FONT = item( SettingType.TextWithSelector, Pref.spTimelineFont, R.string.timeline_font ) { - val item = this - onClickEdit = { - try { - val intent = intentOpenDocument("*/*") - startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT) - } catch(ex : Throwable) { - showToast(ex, "could not open picker for font") - } - } - onClickReset = { - pref.edit().remove(item.pref?.key).apply() - showTimelineFont(item) - } - showTextView = { showTimelineFont(item, it) } - } - - - AppSettingItem.TIMELINE_FONT_BOLD = item( + val item = this + onClickEdit = { + try { + val intent = intentOpenDocument("*/*") + startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT) + } catch (ex: Throwable) { + showToast(ex, "could not open picker for font") + } + } + onClickReset = { + pref.edit().remove(item.pref?.key).apply() + showTimelineFont(item) + } + showTextView = { showTimelineFont(item, it) } + } + + + AppSettingItem.TIMELINE_FONT_BOLD = item( SettingType.TextWithSelector, Pref.spTimelineFontBold, R.string.timeline_font_bold ) { - val item = this - onClickEdit = { - try { - val intent = intentOpenDocument("*/*") - startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT_BOLD) - } catch(ex : Throwable) { - showToast(ex, "could not open picker for font") - } - } - onClickReset = { - pref.edit().remove(item.pref?.key).apply() - showTimelineFont(AppSettingItem.TIMELINE_FONT_BOLD) - } - showTextView = { showTimelineFont(item, it) } - } - - AppSettingItem.FONT_SIZE_TIMELINE = textX( + val item = this + onClickEdit = { + try { + val intent = intentOpenDocument("*/*") + startActivityForResult(intent, ActAppSetting.REQUEST_CODE_TIMELINE_FONT_BOLD) + } catch (ex: Throwable) { + showToast(ex, "could not open picker for font") + } + } + onClickReset = { + pref.edit().remove(item.pref?.key).apply() + showTimelineFont(AppSettingItem.TIMELINE_FONT_BOLD) + } + showTextView = { showTimelineFont(item, it) } + } + + AppSettingItem.FONT_SIZE_TIMELINE = textX( Pref.fpTimelineFontSize, R.string.timeline_font_size, InputTypeEx.numberDecimal ) { - - val item = this - val fp : FloatPref = item.pref.cast() !! - - toFloat = { parseFontSize(it) } - fromFloat = { formatFontSize(it) } - - captionFontSize = { - val fv = fp(pref) - when { - ! fv.isFinite() -> Pref.default_timeline_font_size - fv < 1f -> 1f - else -> fv - } - } - captionSpacing = { - Pref.spTimelineSpacing(pref).toFloatOrNull() - } - changed = { - findItemViewHolder(item)?.updateCaption() - } - } - - textX(Pref.fpAcctFontSize, R.string.acct_font_size, InputTypeEx.numberDecimal) { - val item = this - val fp : FloatPref = item.pref.cast() !! - - toFloat = { parseFontSize(it) } - fromFloat = { formatFontSize(it) } - - captionFontSize = { - val fv = fp(pref) - when { - ! fv.isFinite() -> Pref.default_acct_font_size - fv < 1f -> 1f - else -> fv - } - } - - changed = { findItemViewHolder(item)?.updateCaption() } - } - - AppSettingItem.FONT_SIZE_NOTIFICATION_TL = textX( + + val item = this + val fp: FloatPref = item.pref.cast()!! + + toFloat = { parseFontSize(it) } + fromFloat = { formatFontSize(it) } + + captionFontSize = { + val fv = fp(pref) + when { + !fv.isFinite() -> Pref.default_timeline_font_size + fv < 1f -> 1f + else -> fv + } + } + captionSpacing = { + Pref.spTimelineSpacing(pref).toFloatOrNull() + } + changed = { + findItemViewHolder(item)?.updateCaption() + } + } + + textX(Pref.fpAcctFontSize, R.string.acct_font_size, InputTypeEx.numberDecimal) { + val item = this + val fp: FloatPref = item.pref.cast()!! + + toFloat = { parseFontSize(it) } + fromFloat = { formatFontSize(it) } + + captionFontSize = { + val fv = fp(pref) + when { + !fv.isFinite() -> Pref.default_acct_font_size + fv < 1f -> 1f + else -> fv + } + } + + changed = { findItemViewHolder(item)?.updateCaption() } + } + + AppSettingItem.FONT_SIZE_NOTIFICATION_TL = textX( Pref.fpNotificationTlFontSize, R.string.notification_tl_font_size, InputTypeEx.numberDecimal ) { - val item = this - val fp : FloatPref = item.pref.cast() !! - - toFloat = { parseFontSize(it) } - fromFloat = { formatFontSize(it) } - - captionFontSize = { - val fv = fp(pref) - when { - ! fv.isFinite() -> Pref.default_notification_tl_font_size - fv < 1f -> 1f - else -> fv - } - } - captionSpacing = { - Pref.spTimelineSpacing(pref).toFloatOrNull() - } - changed = { - findItemViewHolder(item)?.updateCaption() - } - } - - text( + val item = this + val fp: FloatPref = item.pref.cast()!! + + toFloat = { parseFontSize(it) } + fromFloat = { formatFontSize(it) } + + captionFontSize = { + val fv = fp(pref) + when { + !fv.isFinite() -> Pref.default_notification_tl_font_size + fv < 1f -> 1f + else -> fv + } + } + captionSpacing = { + Pref.spTimelineSpacing(pref).toFloatOrNull() + } + changed = { + findItemViewHolder(item)?.updateCaption() + } + } + + text( Pref.spNotificationTlIconSize, R.string.notification_tl_icon_size, InputTypeEx.numberDecimal ) - - text(Pref.spTimelineSpacing, R.string.timeline_line_spacing, InputTypeEx.numberDecimal) { - changed = { - findItemViewHolder(AppSettingItem.FONT_SIZE_TIMELINE)?.updateCaption() - findItemViewHolder(AppSettingItem.FONT_SIZE_NOTIFICATION_TL)?.updateCaption() - } - } - - text(Pref.spBoostButtonSize, R.string.boost_button_size, InputTypeEx.numberDecimal) - - spinner( + + text(Pref.spTimelineSpacing, R.string.timeline_line_spacing, InputTypeEx.numberDecimal) { + changed = { + findItemViewHolder(AppSettingItem.FONT_SIZE_TIMELINE)?.updateCaption() + findItemViewHolder(AppSettingItem.FONT_SIZE_NOTIFICATION_TL)?.updateCaption() + } + } + + text(Pref.spBoostButtonSize, R.string.boost_button_size, InputTypeEx.numberDecimal) + + spinner( Pref.ipBoostButtonJustify, R.string.boost_button_alignment, R.string.start, R.string.center, R.string.end ) - - text(Pref.spAvatarIconSize, R.string.avatar_icon_size, InputTypeEx.numberDecimal) - text(Pref.spRoundRatio, R.string.avatar_icon_round_ratio, InputTypeEx.numberDecimal) - sw(Pref.bpDontRound, R.string.avatar_icon_dont_round) - text(Pref.spReplyIconSize, R.string.reply_icon_size, InputTypeEx.numberDecimal) - text(Pref.spHeaderIconSize, R.string.header_icon_size, InputTypeEx.numberDecimal) - textX(Pref.fpHeaderTextSize, R.string.header_text_size, InputTypeEx.numberDecimal) { - val item = this - val fp : FloatPref = item.pref.cast() !! - - toFloat = { parseFontSize(it) } - fromFloat = { formatFontSize(it) } - - captionFontSize = { - val fv = fp(pref) - when { - ! fv.isFinite() -> Pref.default_header_font_size - fv < 1f -> 1f - else -> fv - } - } - - changed = { - findItemViewHolder(item)?.updateCaption() - } - } - - text(Pref.spStripIconSize, R.string.strip_icon_size, InputTypeEx.numberDecimal) - - text(Pref.spScreenBottomPadding, R.string.screen_bottom_padding, InputTypeEx.numberDecimal) - - - - sw(Pref.bpOpenSticker, R.string.show_open_sticker) { - desc = R.string.powered_by_open_sticker - descClick = {openBrowser("https://github.com/cutls/OpenSticker") } - } - - sw(Pref.bpLinksInContextMenu, R.string.show_links_in_context_menu) - sw(Pref.bpShowLinkUnderline, R.string.show_link_underline) - sw( + + text(Pref.spAvatarIconSize, R.string.avatar_icon_size, InputTypeEx.numberDecimal) + text(Pref.spRoundRatio, R.string.avatar_icon_round_ratio, InputTypeEx.numberDecimal) + sw(Pref.bpDontRound, R.string.avatar_icon_dont_round) + text(Pref.spReplyIconSize, R.string.reply_icon_size, InputTypeEx.numberDecimal) + text(Pref.spHeaderIconSize, R.string.header_icon_size, InputTypeEx.numberDecimal) + textX(Pref.fpHeaderTextSize, R.string.header_text_size, InputTypeEx.numberDecimal) { + val item = this + val fp: FloatPref = item.pref.cast()!! + + toFloat = { parseFontSize(it) } + fromFloat = { formatFontSize(it) } + + captionFontSize = { + val fv = fp(pref) + when { + !fv.isFinite() -> Pref.default_header_font_size + fv < 1f -> 1f + else -> fv + } + } + + changed = { + findItemViewHolder(item)?.updateCaption() + } + } + + text(Pref.spStripIconSize, R.string.strip_icon_size, InputTypeEx.numberDecimal) + + text(Pref.spScreenBottomPadding, R.string.screen_bottom_padding, InputTypeEx.numberDecimal) + + + + sw(Pref.bpOpenSticker, R.string.show_open_sticker) { + desc = R.string.powered_by_open_sticker + descClick = { openBrowser("https://github.com/cutls/OpenSticker") } + } + + sw(Pref.bpLinksInContextMenu, R.string.show_links_in_context_menu) + sw(Pref.bpShowLinkUnderline, R.string.show_link_underline) + sw( Pref.bpMoveNotificationsQuickFilter, R.string.move_notifications_quick_filter_to_column_setting ) - sw(Pref.bpShowSearchClear, R.string.show_clear_button_in_search_bar) - sw( + sw(Pref.bpShowSearchClear, R.string.show_clear_button_in_search_bar) + sw( Pref.bpDontShowColumnBackgroundImage, R.string.dont_show_column_background_image ) - - group(R.string.show_in_directory) { - checkbox(Pref.bpDirectoryLastActive, R.string.last_active) - checkbox(Pref.bpDirectoryFollowers, R.string.followers) - checkbox(Pref.bpDirectoryTootCount, R.string.toot_count) - checkbox(Pref.bpDirectoryNote, R.string.note) - } - - sw( + + group(R.string.show_in_directory) { + checkbox(Pref.bpDirectoryLastActive, R.string.last_active) + checkbox(Pref.bpDirectoryFollowers, R.string.followers) + checkbox(Pref.bpDirectoryTootCount, R.string.toot_count) + checkbox(Pref.bpDirectoryNote, R.string.note) + } + + sw( Pref.bpAlwaysExpandContextMenuItems, R.string.always_expand_context_menu_sub_items ) - sw(Pref.bpShowBookmarkButton, R.string.show_bookmark_button) - sw(Pref.bpHideFollowCount, R.string.hide_followers_count) - sw(Pref.bpEmojioneShortcode, R.string.emojione_shortcode_support) { - desc = R.string.emojione_shortcode_support_desc - } - } - - section(R.string.color) { - - spinner( + sw(Pref.bpShowBookmarkButton, R.string.show_bookmark_button) + sw(Pref.bpHideFollowCount, R.string.hide_followers_count) + sw(Pref.bpEmojioneShortcode, R.string.emojione_shortcode_support) { + desc = R.string.emojione_shortcode_support_desc + } + } + + section(R.string.color) { + + spinner( Pref.ipUiTheme, R.string.ui_theme, R.string.theme_light, R.string.theme_dark ) - - colorAlpha(Pref.ipListDividerColor, R.string.list_divider_color) - colorAlpha(Pref.ipLinkColor, R.string.link_color) - - group(R.string.toot_background_color) { - colorAlpha(Pref.ipTootColorUnlisted, R.string.unlisted_visibility) - colorAlpha(Pref.ipTootColorFollower, R.string.followers_visibility) - colorAlpha(Pref.ipTootColorDirectUser, R.string.direct_with_user_visibility) - colorAlpha(Pref.ipTootColorDirectMe, R.string.direct_only_me_visibility) - } - - group(R.string.event_background_color) { - colorAlpha(Pref.ipEventBgColorBoost, R.string.boost) - colorAlpha(Pref.ipEventBgColorFavourite, R.string.favourites) - colorAlpha(Pref.ipEventBgColorBookmark, R.string.bookmarks) - colorAlpha(Pref.ipEventBgColorMention, R.string.reply) - colorAlpha(Pref.ipEventBgColorFollow, R.string.follow) - colorAlpha(Pref.ipEventBgColorUnfollow, R.string.unfollow_misskey) - colorAlpha(Pref.ipEventBgColorFollowRequest, R.string.follow_request) - colorAlpha(Pref.ipEventBgColorReaction, R.string.reaction) - colorAlpha(Pref.ipEventBgColorQuote, R.string.quote_renote) - colorAlpha(Pref.ipEventBgColorVote, R.string.vote_polls) - colorAlpha(Pref.ipEventBgColorStatus, R.string.status) - - colorAlpha( + + colorAlpha(Pref.ipListDividerColor, R.string.list_divider_color) + colorAlpha(Pref.ipLinkColor, R.string.link_color) + + group(R.string.toot_background_color) { + colorAlpha(Pref.ipTootColorUnlisted, R.string.unlisted_visibility) + colorAlpha(Pref.ipTootColorFollower, R.string.followers_visibility) + colorAlpha(Pref.ipTootColorDirectUser, R.string.direct_with_user_visibility) + colorAlpha(Pref.ipTootColorDirectMe, R.string.direct_only_me_visibility) + } + + group(R.string.event_background_color) { + colorAlpha(Pref.ipEventBgColorBoost, R.string.boost) + colorAlpha(Pref.ipEventBgColorFavourite, R.string.favourites) + colorAlpha(Pref.ipEventBgColorBookmark, R.string.bookmarks) + colorAlpha(Pref.ipEventBgColorMention, R.string.reply) + colorAlpha(Pref.ipEventBgColorFollow, R.string.follow) + colorAlpha(Pref.ipEventBgColorUnfollow, R.string.unfollow_misskey) + colorAlpha(Pref.ipEventBgColorFollowRequest, R.string.follow_request) + colorAlpha(Pref.ipEventBgColorReaction, R.string.reaction) + 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) - } - - - group(R.string.button_accent_color) { - colorAlpha(Pref.ipButtonBoostedColor, R.string.boost) - colorAlpha(Pref.ipButtonFavoritedColor, R.string.favourites) - colorAlpha(Pref.ipButtonBookmarkedColor, R.string.bookmarks) - colorAlpha(Pref.ipButtonFollowingColor, R.string.follow) - colorAlpha(Pref.ipButtonFollowRequestColor, R.string.follow_request) - } - - group(R.string.column_color_default) { - AppSettingItem.SAMPLE_CCD_HEADER = - sample(R.layout.setting_sample_column_header) { activity, viewRoot -> - - val llColumnHeader : View = viewRoot.findViewById(R.id.llColumnHeader) - val ivColumnHeader : ImageView = viewRoot.findViewById(R.id.ivColumnHeader) - val tvColumnName : TextView = viewRoot.findViewById(R.id.tvColumnName) - - val color_column_header_bg = Pref.ipCcdHeaderBg(activity.pref) - val color_column_header_fg = Pref.ipCcdHeaderFg(activity.pref) - - val header_bg = when { - color_column_header_bg != 0 -> color_column_header_bg - else -> activity.getAttributeColor(R.attr.color_column_header) - } - - val header_fg = when { - color_column_header_fg != 0 -> color_column_header_fg - else -> activity.getAttributeColor(R.attr.colorColumnHeaderName) - } - - llColumnHeader.background = getAdaptiveRippleDrawable(header_bg, header_fg) - - tvColumnName.setTextColor(header_fg) - ivColumnHeader.setImageResource(R.drawable.ic_bike) - ivColumnHeader.imageTintList = ColorStateList.valueOf(header_fg) - } - - colorOpaque(Pref.ipCcdHeaderBg, R.string.header_background_color) { - changed = { showSample(AppSettingItem.SAMPLE_CCD_HEADER) } - } - colorOpaque(Pref.ipCcdHeaderFg, R.string.header_foreground_color) { - changed = { showSample(AppSettingItem.SAMPLE_CCD_HEADER) } - } - - AppSettingItem.SAMPLE_CCD_BODY = - sample(R.layout.setting_sample_column_body) { activity, viewRoot -> - val flColumnBackground : View = viewRoot.findViewById(R.id.flColumnBackground) - val tvSampleAcct : TextView = viewRoot.findViewById(R.id.tvSampleAcct) - val tvSampleContent : TextView = viewRoot.findViewById(R.id.tvSampleContent) - - val color_column_bg = Pref.ipCcdContentBg(activity.pref) - val color_column_acct = Pref.ipCcdContentAcct(activity.pref) - val color_column_text = Pref.ipCcdContentText(activity.pref) - - flColumnBackground.setBackgroundColor(color_column_bg) // may 0 - - tvSampleAcct.setTextColor( + + colorAlpha(Pref.ipEventBgColorGap, R.string.gap) + } + + + group(R.string.button_accent_color) { + colorAlpha(Pref.ipButtonBoostedColor, R.string.boost) + colorAlpha(Pref.ipButtonFavoritedColor, R.string.favourites) + colorAlpha(Pref.ipButtonBookmarkedColor, R.string.bookmarks) + colorAlpha(Pref.ipButtonFollowingColor, R.string.follow) + colorAlpha(Pref.ipButtonFollowRequestColor, R.string.follow_request) + } + + group(R.string.column_color_default) { + AppSettingItem.SAMPLE_CCD_HEADER = + sample(R.layout.setting_sample_column_header) { activity, viewRoot -> + + val llColumnHeader: View = viewRoot.findViewById(R.id.llColumnHeader) + val ivColumnHeader: ImageView = viewRoot.findViewById(R.id.ivColumnHeader) + val tvColumnName: TextView = viewRoot.findViewById(R.id.tvColumnName) + + val color_column_header_bg = Pref.ipCcdHeaderBg(activity.pref) + val color_column_header_fg = Pref.ipCcdHeaderFg(activity.pref) + + val header_bg = when { + color_column_header_bg != 0 -> color_column_header_bg + else -> activity.getAttributeColor(R.attr.color_column_header) + } + + val header_fg = when { + color_column_header_fg != 0 -> color_column_header_fg + else -> activity.getAttributeColor(R.attr.colorColumnHeaderName) + } + + llColumnHeader.background = getAdaptiveRippleDrawable(header_bg, header_fg) + + tvColumnName.setTextColor(header_fg) + ivColumnHeader.setImageResource(R.drawable.ic_bike) + ivColumnHeader.imageTintList = ColorStateList.valueOf(header_fg) + } + + colorOpaque(Pref.ipCcdHeaderBg, R.string.header_background_color) { + changed = { showSample(AppSettingItem.SAMPLE_CCD_HEADER) } + } + colorOpaque(Pref.ipCcdHeaderFg, R.string.header_foreground_color) { + changed = { showSample(AppSettingItem.SAMPLE_CCD_HEADER) } + } + + AppSettingItem.SAMPLE_CCD_BODY = + sample(R.layout.setting_sample_column_body) { activity, viewRoot -> + val flColumnBackground: View = viewRoot.findViewById(R.id.flColumnBackground) + val tvSampleAcct: TextView = viewRoot.findViewById(R.id.tvSampleAcct) + val tvSampleContent: TextView = viewRoot.findViewById(R.id.tvSampleContent) + + val color_column_bg = Pref.ipCcdContentBg(activity.pref) + val color_column_acct = Pref.ipCcdContentAcct(activity.pref) + val color_column_text = Pref.ipCcdContentText(activity.pref) + + flColumnBackground.setBackgroundColor(color_column_bg) // may 0 + + tvSampleAcct.setTextColor( color_column_acct.notZero() ?: activity.getAttributeColor(R.attr.colorTimeSmall) ) - - tvSampleContent.setTextColor( + + tvSampleContent.setTextColor( color_column_text.notZero() ?: activity.getAttributeColor(R.attr.colorContentText) ) - } - - colorOpaque(Pref.ipCcdContentBg, R.string.content_background_color) { - changed = { showSample(AppSettingItem.SAMPLE_CCD_BODY) } - } - colorAlpha(Pref.ipCcdContentAcct, R.string.content_acct_color) { - changed = { showSample(AppSettingItem.SAMPLE_CCD_BODY) } - } - colorAlpha(Pref.ipCcdContentText, R.string.content_text_color) { - changed = { showSample(AppSettingItem.SAMPLE_CCD_BODY) } - } - } - - text(Pref.spBoostAlpha, R.string.boost_button_alpha, InputTypeEx.numberDecimal) - - group(R.string.footer_color) { - AppSettingItem.SAMPLE_FOOTER = - sample(R.layout.setting_sample_footer) { activity, viewRoot -> - val pref = activity.pref - val ivFooterToot : AppCompatImageView = viewRoot.findViewById(R.id.ivFooterToot) - val ivFooterMenu : AppCompatImageView = viewRoot.findViewById(R.id.ivFooterMenu) - val llFooterBG : View = viewRoot.findViewById(R.id.llFooterBG) - val vFooterDivider1 : View = viewRoot.findViewById(R.id.vFooterDivider1) - val vFooterDivider2 : View = viewRoot.findViewById(R.id.vFooterDivider2) - val vIndicator : View = viewRoot.findViewById(R.id.vIndicator) - - val footer_button_bg_color = Pref.ipFooterButtonBgColor(pref) - val footer_button_fg_color = Pref.ipFooterButtonFgColor(pref) - val footer_tab_bg_color = Pref.ipFooterTabBgColor(pref) - val footer_tab_divider_color = Pref.ipFooterTabDividerColor(pref) - val footer_tab_indicator_color = Pref.ipFooterTabIndicatorColor(pref) - - val colorColumnStripBackground = footer_tab_bg_color.notZero() - ?: activity.getAttributeColor(R.attr.colorColumnStripBackground) - - llFooterBG.setBackgroundColor(colorColumnStripBackground) - - val colorButtonBg = footer_button_bg_color.notZero() - ?: colorColumnStripBackground - - val colorButtonFg = footer_button_fg_color.notZero() - ?: activity.getAttributeColor(R.attr.colorRippleEffect) - - ivFooterMenu.backgroundDrawable = - getAdaptiveRippleDrawableRound(activity, colorButtonBg, colorButtonFg) - ivFooterToot.backgroundDrawable = - getAdaptiveRippleDrawableRound(activity, colorButtonBg, colorButtonFg) - - val csl = ColorStateList.valueOf( + } + + colorOpaque(Pref.ipCcdContentBg, R.string.content_background_color) { + changed = { showSample(AppSettingItem.SAMPLE_CCD_BODY) } + } + colorAlpha(Pref.ipCcdContentAcct, R.string.content_acct_color) { + changed = { showSample(AppSettingItem.SAMPLE_CCD_BODY) } + } + colorAlpha(Pref.ipCcdContentText, R.string.content_text_color) { + changed = { showSample(AppSettingItem.SAMPLE_CCD_BODY) } + } + } + + text(Pref.spBoostAlpha, R.string.boost_button_alpha, InputTypeEx.numberDecimal) + + group(R.string.footer_color) { + AppSettingItem.SAMPLE_FOOTER = + sample(R.layout.setting_sample_footer) { activity, viewRoot -> + val pref = activity.pref + val ivFooterToot: AppCompatImageView = viewRoot.findViewById(R.id.ivFooterToot) + val ivFooterMenu: AppCompatImageView = viewRoot.findViewById(R.id.ivFooterMenu) + val llFooterBG: View = viewRoot.findViewById(R.id.llFooterBG) + val vFooterDivider1: View = viewRoot.findViewById(R.id.vFooterDivider1) + val vFooterDivider2: View = viewRoot.findViewById(R.id.vFooterDivider2) + val vIndicator: View = viewRoot.findViewById(R.id.vIndicator) + + val footer_button_bg_color = Pref.ipFooterButtonBgColor(pref) + val footer_button_fg_color = Pref.ipFooterButtonFgColor(pref) + val footer_tab_bg_color = Pref.ipFooterTabBgColor(pref) + val footer_tab_divider_color = Pref.ipFooterTabDividerColor(pref) + val footer_tab_indicator_color = Pref.ipFooterTabIndicatorColor(pref) + + val colorColumnStripBackground = footer_tab_bg_color.notZero() + ?: activity.getAttributeColor(R.attr.colorColumnStripBackground) + + llFooterBG.setBackgroundColor(colorColumnStripBackground) + + val colorButtonBg = footer_button_bg_color.notZero() + ?: colorColumnStripBackground + + val colorButtonFg = footer_button_fg_color.notZero() + ?: activity.getAttributeColor(R.attr.colorRippleEffect) + + ivFooterMenu.backgroundDrawable = + getAdaptiveRippleDrawableRound(activity, colorButtonBg, colorButtonFg) + ivFooterToot.backgroundDrawable = + getAdaptiveRippleDrawableRound(activity, colorButtonBg, colorButtonFg) + + val csl = ColorStateList.valueOf( footer_button_fg_color.notZero() ?: activity.getAttributeColor(R.attr.colorVectorDrawable) ) - ivFooterToot.imageTintList = csl - ivFooterMenu.imageTintList = csl - - val c = footer_tab_divider_color.notZero() - ?: colorColumnStripBackground - vFooterDivider1.setBackgroundColor(c) - vFooterDivider2.setBackgroundColor(c) - - vIndicator.setBackgroundColor( + ivFooterToot.imageTintList = csl + ivFooterMenu.imageTintList = csl + + val c = footer_tab_divider_color.notZero() + ?: colorColumnStripBackground + vFooterDivider1.setBackgroundColor(c) + vFooterDivider2.setBackgroundColor(c) + + vIndicator.setBackgroundColor( footer_tab_indicator_color.notZero() ?: activity.getAttributeColor(R.attr.colorAccent) ) - } - - colorOpaque(Pref.ipFooterButtonBgColor, R.string.button_background_color) { - changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } - } - colorOpaque(Pref.ipFooterButtonFgColor, R.string.button_foreground_color) { - changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } - } - colorOpaque(Pref.ipFooterTabBgColor, R.string.quick_toot_bar_background_color) { - changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } - } - colorOpaque(Pref.ipFooterTabDividerColor, R.string.tab_divider_color) { - changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } - } - colorAlpha(Pref.ipFooterTabIndicatorColor, R.string.tab_indicator_color) { - changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } - } - } - - colorOpaque(Pref.ipSwitchOnColor, R.string.switch_button_color) { - changed = { setSwitchColor() } - } - - colorOpaque(Pref.ipStatusBarColor, R.string.status_bar_color) { - changed = { setStatusBarColor() } - } - - colorOpaque(Pref.ipNavigationBarColor, R.string.navigation_bar_color) { - changed = { setStatusBarColor() } - } - - colorOpaque(Pref.ipSearchBgColor, R.string.search_bar_background_color) - colorAlpha(Pref.ipAnnouncementsBgColor, R.string.announcement_background_color) - colorAlpha(Pref.ipVerifiedLinkBgColor, R.string.verified_link_background_color) - colorAlpha(Pref.ipVerifiedLinkFgColor, R.string.verified_link_foreground_color) - } - - section(R.string.performance) { - sw(Pref.bpShareViewPool, R.string.share_view_pool) - sw(Pref.bpDontUseStreaming, R.string.dont_use_streaming_api) - sw(Pref.bpDontRefreshOnResume, R.string.dont_refresh_on_activity_resume) - text(Pref.spMediaReadTimeout, R.string.timeout_for_embed_media_viewer, InputTypeEx.number) - action(R.string.delete_custom_emoji_cache) { - action = { - App1.custom_emoji_cache.delete() - } - } - } - - 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) { - startActivity(Intent(this, ActExitReasons::class.java)) - } else { - showToast(false, "this feature requires Android 11") - } - } - } - - } - - action(R.string.app_data_export) { - action = { exportAppData() } - } - - action(R.string.app_data_import) { - action = { importAppData1() } - desc = R.string.app_data_import_desc - } + } + + colorOpaque(Pref.ipFooterButtonBgColor, R.string.button_background_color) { + changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } + } + colorOpaque(Pref.ipFooterButtonFgColor, R.string.button_foreground_color) { + changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } + } + colorOpaque(Pref.ipFooterTabBgColor, R.string.quick_toot_bar_background_color) { + changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } + } + colorOpaque(Pref.ipFooterTabDividerColor, R.string.tab_divider_color) { + changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } + } + colorAlpha(Pref.ipFooterTabIndicatorColor, R.string.tab_indicator_color) { + changed = { showSample(AppSettingItem.SAMPLE_FOOTER) } + } + } + + colorOpaque(Pref.ipSwitchOnColor, R.string.switch_button_color) { + changed = { setSwitchColor() } + } + + colorOpaque(Pref.ipStatusBarColor, R.string.status_bar_color) { + changed = { setStatusBarColor() } + } + + colorOpaque(Pref.ipNavigationBarColor, R.string.navigation_bar_color) { + changed = { setStatusBarColor() } + } + + colorOpaque(Pref.ipSearchBgColor, R.string.search_bar_background_color) + colorAlpha(Pref.ipAnnouncementsBgColor, R.string.announcement_background_color) + colorAlpha(Pref.ipVerifiedLinkBgColor, R.string.verified_link_background_color) + colorAlpha(Pref.ipVerifiedLinkFgColor, R.string.verified_link_foreground_color) + } + + section(R.string.performance) { + sw(Pref.bpShareViewPool, R.string.share_view_pool) + sw(Pref.bpDontUseStreaming, R.string.dont_use_streaming_api) + sw(Pref.bpDontRefreshOnResume, R.string.dont_refresh_on_activity_resume) + text(Pref.spMediaReadTimeout, R.string.timeout_for_embed_media_viewer, InputTypeEx.number) + action(R.string.delete_custom_emoji_cache) { + action = { + App1.custom_emoji_cache.delete() + } + } + } + + 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) { + startActivity(Intent(this, ActExitReasons::class.java)) + } else { + showToast(false, "this feature requires Android 11") + } + } + } + + } + + action(R.string.app_data_export) { + action = { exportAppData() } + } + + action(R.string.app_data_import) { + action = { importAppData1() } + desc = R.string.app_data_import_desc + } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/Pref.kt b/app/src/main/java/jp/juggler/subwaytooter/Pref.kt index 1e750bf0..5dd22036 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Pref.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/Pref.kt @@ -591,7 +591,8 @@ object Pref { val spCustomShare1 = StringPref("CustomShare1", "") val spCustomShare2 = StringPref("CustomShare2", "") val spCustomShare3 = StringPref("CustomShare3", "") - + val spWebBrowser = StringPref("WebBrowser", "") + val spTimelineSpacing = StringPref("TimelineSpacing", "") // long diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgAppPicker.kt b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgAppPicker.kt index 51ba5d6d..98117008 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgAppPicker.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgAppPicker.kt @@ -21,8 +21,9 @@ class DlgAppPicker( val activity: Activity, val intent: Intent, val autoSelect: Boolean = false, + val addCopyAction:Boolean= false, val filter: (ResolveInfo) -> Boolean = { true }, - val callback: (String) -> Unit + val callback: (String) -> Unit, ) { companion object { @@ -55,7 +56,7 @@ class DlgAppPicker( } // 自動選択オフの場合、末尾にクリップボード項目を追加する - if (!autoSelect) { + if (addCopyAction && !autoSelect) { val (label, icon) = CustomShare.getInfo(activity, CustomShare.CN_CLIPBOARD.cn()) add(ListItem(icon, label.toString(), CustomShare.CN_CLIPBOARD)) } diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/AppOpener.kt b/app/src/main/java/jp/juggler/subwaytooter/util/AppOpener.kt index 761bac2f..c6c3eab6 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/AppOpener.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/AppOpener.kt @@ -8,6 +8,7 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.app.Activity +import android.content.SharedPreferences import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabsIntent import jp.juggler.subwaytooter.ActMain @@ -40,15 +41,23 @@ private val log = LogCategory("AppOpener") // returns true if activity is opened. // returns false if fallback required private fun Activity.startActivityExcludeMyApp( + pref:SharedPreferences, intent: Intent, startAnimationBundle: Bundle? = null ): Boolean { try { + if( intent.component == null){ + val cn = Pref.spWebBrowser(pref).cn() + if( cn?.exists(this) == true){ + intent.component = cn + } + } + // このアプリのパッケージ名 val myName = packageName val filter: (ResolveInfo) -> Boolean = { - when{ + when { it.activityInfo.packageName == myName -> false !it.activityInfo.exported -> false @@ -57,7 +66,7 @@ private fun Activity.startActivityExcludeMyApp( // 標準アプリが設定されていない場合、アプリを選択するためのActivityが出てくる場合がある it.activityInfo.packageName == "android" -> false - it.activityInfo.javaClass.name.startsWith( "com.android.internal") -> false + it.activityInfo.javaClass.name.startsWith("com.android.internal") -> false it.activityInfo.javaClass.name.startsWith("com.android.systemui") -> false // たぶんChromeとかfirefoxとか @@ -89,7 +98,8 @@ private fun Activity.startActivityExcludeMyApp( this, intent, autoSelect = true, - filter = filter + filter = filter, + addCopyAction = false ) { try { intent.component = it.cn() @@ -108,16 +118,20 @@ private fun Activity.startActivityExcludeMyApp( } } -fun Activity.openBrowser(uri: Uri?) { +fun Activity.openBrowser(uri: Uri? , pref:SharedPreferences = pref()) { uri ?: return - val rv = startActivityExcludeMyApp(Intent(Intent.ACTION_VIEW, uri)) + val rv = startActivityExcludeMyApp( + pref, + Intent(Intent.ACTION_VIEW, uri) + .apply { addCategory(Intent.CATEGORY_BROWSABLE) } + ) if (!rv) showToast(true, "there is no app that can open $uri") } -fun Activity.openBrowser(url: String?) = openBrowser(url.mayUri()) +fun Activity.openBrowser(url: String?, pref:SharedPreferences = pref()) = openBrowser(url.mayUri(),pref) // Chrome Custom Tab を開く -fun Activity.openCustomTab(url: String?) { +fun Activity.openCustomTab(url: String?, pref:SharedPreferences = pref()) { url ?: return if (url.isEmpty()) { @@ -125,9 +139,8 @@ fun Activity.openCustomTab(url: String?) { return } - val pref = pref() if (Pref.bpDontUseCustomTabs(pref)) { - openBrowser(url) + openBrowser(url,pref) return } @@ -144,6 +157,7 @@ fun Activity.openCustomTab(url: String?) { .let { log.w("startCustomTabIntent ComponentName=$cn") startActivityExcludeMyApp( + pref, it.intent.also { intent -> if (cn != null) intent.component = cn intent.data = url.toUri() diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/CustomShare.kt b/app/src/main/java/jp/juggler/subwaytooter/util/CustomShare.kt index ee7a381d..131e5e79 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/CustomShare.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/CustomShare.kt @@ -15,170 +15,179 @@ import jp.juggler.util.showToast import jp.juggler.util.systemService enum class CustomShareTarget { - Translate, - CustomShare1, - CustomShare2, - CustomShare3, + Translate, + CustomShare1, + CustomShare2, + CustomShare3, } object CustomShare { - - val log = LogCategory("CustomShare") - - const val CN_CLIPBOARD = "/CopyToClipboard" - - private const val translate_app_component_default = - "com.google.android.apps.translate/com.google.android.apps.translate.TranslateActivity" - - fun getCustomShareComponentName( - pref : SharedPreferences, - target : CustomShareTarget - ) : ComponentName? { - val src : String - val defaultComponentName : String? - when(target) { + + val log = LogCategory("CustomShare") + + const val CN_CLIPBOARD = "/CopyToClipboard" + + private const val translate_app_component_default = + "com.google.android.apps.translate/com.google.android.apps.translate.TranslateActivity" + + fun getCustomShareComponentName( + pref: SharedPreferences, + target: CustomShareTarget + ): ComponentName? { + val src: String + val defaultComponentName: String? + when (target) { CustomShareTarget.Translate -> { src = Pref.spTranslateAppComponent(pref) defaultComponentName = translate_app_component_default } - + CustomShareTarget.CustomShare1 -> { src = Pref.spCustomShare1(pref) defaultComponentName = null } - + CustomShareTarget.CustomShare2 -> { src = Pref.spCustomShare2(pref) defaultComponentName = null } - + CustomShareTarget.CustomShare3 -> { src = Pref.spCustomShare3(pref) defaultComponentName = null } - } - return src.cn() ?: defaultComponentName?.cn() - } - - fun getInfo(context : Context, cn : ComponentName?) : Pair { - var label : CharSequence? = null - var icon : Drawable? = null - try { - if(cn != null) { - val cnStr = "${cn.packageName}/${cn.className}" - label = cnStr - if(cnStr == CN_CLIPBOARD) { - 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(context.getAttributeColor(R.attr.colorVectorDrawable)) - setTintMode(PorterDuff.Mode.SRC_IN) - } - } else { - val pm = context.packageManager - val ri = pm.resolveActivity(Intent().apply { component = cn }, 0) - if(ri != null) { - try { - label = ri.loadLabel(pm) - } catch(ex : Throwable) { - log.e(ex, "loadLabel failed.") - } - try { - icon = ri.loadIcon(pm) - } catch(ex : Throwable) { - log.e(ex, "loadIcon failed.") - } - } - } - } - } catch(ex : Throwable) { - log.e(ex, "getInfo failed.") - } - return Pair(label, icon) - } - - fun invoke( - context : Context, - text : String, - target : CustomShareTarget + } + return src.cn() ?: defaultComponentName?.cn() + } + + fun getInfo(context: Context, cn: ComponentName?): Pair { + var label: CharSequence? = null + var icon: Drawable? = null + try { + if (cn != null) { + val cnStr = "${cn.packageName}/${cn.className}" + label = cnStr + if (cnStr == CN_CLIPBOARD) { + 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(context.getAttributeColor(R.attr.colorVectorDrawable)) + setTintMode(PorterDuff.Mode.SRC_IN) + } + } else { + val pm = context.packageManager + val ri = pm.resolveActivity(Intent().apply { component = cn }, 0) + if (ri != null) { + try { + label = ri.loadLabel(pm) + } catch (ex: Throwable) { + log.e(ex, "loadLabel failed.") + } + try { + icon = ri.loadIcon(pm) + } catch (ex: Throwable) { + log.e(ex, "loadIcon failed.") + } + } + } + } + } catch (ex: Throwable) { + log.e(ex, "getInfo failed.") + } + return Pair(label, icon) + } + + fun invoke( + context: Context, + text: String, + target: CustomShareTarget ) { - // convert "pkgName/className" string to ComponentName object. - val cn = getCustomShareComponentName(App1.pref, target) - if(cn == null) { - context.showToast(true, R.string.custom_share_app_not_found) - return - } - val cnStr = "${cn.packageName}/${cn.className}" - if(cnStr == CN_CLIPBOARD) { - try { - val cm : ClipboardManager = systemService(context) !! - cm.setPrimaryClip(ClipData.newPlainText("", text)) - context.showToast(false, R.string.copied_to_clipboard) - } catch(ex : Throwable) { - context.showToast(ex, "copy to clipboard failed.") - } - return - } - try { - val intent = Intent() - intent.action = Intent.ACTION_SEND - intent.type = "text/plain" - intent.putExtra(Intent.EXTRA_TEXT, text) - intent.component = cn - context.startActivity(intent) - } catch(ex : ActivityNotFoundException) { - log.trace(ex) - context.showToast(true, R.string.custom_share_app_not_found) - } catch(ex : Throwable) { - log.trace(ex) - context.showToast(ex, "invoke() failed.") - } - - } - - fun invoke( - context : Context, - access_info : SavedAccount, - status : TootStatus?, - target : CustomShareTarget + // convert "pkgName/className" string to ComponentName object. + val cn = getCustomShareComponentName(App1.pref, target) + if (cn == null) { + context.showToast(true, R.string.custom_share_app_not_found) + return + } + val cnStr = "${cn.packageName}/${cn.className}" + if (cnStr == CN_CLIPBOARD) { + try { + val cm: ClipboardManager = systemService(context)!! + cm.setPrimaryClip(ClipData.newPlainText("", text)) + context.showToast(false, R.string.copied_to_clipboard) + } catch (ex: Throwable) { + context.showToast(ex, "copy to clipboard failed.") + } + return + } + try { + val intent = Intent() + intent.action = Intent.ACTION_SEND + intent.type = "text/plain" + intent.putExtra(Intent.EXTRA_TEXT, text) + intent.component = cn + context.startActivity(intent) + } catch (ex: ActivityNotFoundException) { + log.trace(ex) + context.showToast(true, R.string.custom_share_app_not_found) + } catch (ex: Throwable) { + log.trace(ex) + context.showToast(ex, "invoke() failed.") + } + + } + + fun invoke( + context: Context, + access_info: SavedAccount, + status: TootStatus?, + target: CustomShareTarget ) { - status ?: return - try { - // convert "pkgName/className" string to ComponentName object. - val cn = getCustomShareComponentName(App1.pref, target) - if(cn == null) { - context.showToast(true, R.string.custom_share_app_not_found) - return - } - - val sv = TootTextEncoder.encodeStatusForTranslate(context, access_info, status) - invoke(context, sv, target) - } catch(ex : Throwable) { - log.trace(ex) - context.showToast(ex, "invoke() failed.") - } - } - - private val cache = HashMap>() - - fun getCache(target : CustomShareTarget) = cache[target] - - fun reloadCache(context : Context, pref : SharedPreferences) { - CustomShareTarget.values().forEach { target -> - val cn = getCustomShareComponentName(pref, target) - val pair = getInfo(context, cn) - cache[target] = pair - } - } + status ?: return + try { + // convert "pkgName/className" string to ComponentName object. + val cn = getCustomShareComponentName(App1.pref, target) + if (cn == null) { + context.showToast(true, R.string.custom_share_app_not_found) + return + } + + val sv = TootTextEncoder.encodeStatusForTranslate(context, access_info, status) + invoke(context, sv, target) + } catch (ex: Throwable) { + log.trace(ex) + context.showToast(ex, "invoke() failed.") + } + } + + private val cache = HashMap>() + + fun getCache(target: CustomShareTarget) = cache[target] + + fun reloadCache(context: Context, pref: SharedPreferences) { + CustomShareTarget.values().forEach { target -> + val cn = getCustomShareComponentName(pref, target) + val pair = getInfo(context, cn) + cache[target] = pair + } + } } // convert "pkgName/className" string to ComponentName object. -fun String.cn() : ComponentName? { - try { - val idx = indexOf('/') - if(idx >= 1) return ComponentName(substring(0 until idx), substring(idx + 1)) - } catch(ex : Throwable) { - CustomShare.log.e(ex, "incorrect component name $this") - } - return null +fun String.cn(): ComponentName? { + try { + val idx = indexOf('/') + if (idx >= 1) return ComponentName(substring(0 until idx), substring(idx + 1)) + } catch (ex: Throwable) { + CustomShare.log.e(ex, "incorrect component name $this") + } + return null } + +fun ComponentName.exists(context: Context): Boolean { + return try { + context.packageManager.resolveActivity(Intent().apply { component = this@exists }, 0) + ?.activityInfo?.exported ?: false + } catch (_: Throwable) { + false + } +} \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 369c1408..d80c23d6 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1065,5 +1065,6 @@ ユーザ名に@や/ を含めることはできません 読み上げ 既読状態をリセット + Webブラウザー diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7ac7c83d..b354b584 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1076,4 +1076,5 @@ notestock search \"%1$s\" Update push subscription(not force) Reset notification tracking status + Web browser