アプリ設定/タブレットモード/投稿画面を別ウィンドウで表示する」を追加

This commit is contained in:
tateisu 2021-05-30 11:01:12 +09:00
parent 60224dc3f8
commit 18c355715c
12 changed files with 767 additions and 547 deletions

View File

@ -197,7 +197,18 @@
android:name=".ActPost"
android:label="@string/act_post"
android:windowSoftInputMode="adjustResize" />
android:windowSoftInputMode="adjustResize" >
<!--suppress AndroidElementNotAllowed -->
<layout
android:defaultWidth="320dp"
android:defaultHeight="480dp"
android:gravity="center"
android:minWidth="64dp"
android:minHeight="64dp"
tools:ignore="UnusedAttribute" />
</activity>
<activity
android:name=".ActAccountSetting"

View File

@ -33,6 +33,7 @@ import jp.juggler.subwaytooter.dialog.*
import jp.juggler.subwaytooter.notification.PollingWorker
import jp.juggler.subwaytooter.notification.PushSubscriptionHelper
import jp.juggler.subwaytooter.span.MyClickableSpan
import jp.juggler.subwaytooter.span.MyClickableSpanHandler
import jp.juggler.subwaytooter.table.AcctColor
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.*
@ -54,8 +55,11 @@ import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
class ActMain : AppCompatActivity(), View.OnClickListener,
ViewPager.OnPageChangeListener, DrawerLayout.DrawerListener {
class ActMain : AppCompatActivity(),
View.OnClickListener,
ViewPager.OnPageChangeListener,
DrawerLayout.DrawerListener,
MyClickableSpanHandler {
class PhoneEnv {
@ -79,17 +83,20 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
const val RESULT_APP_DATA_IMPORT = Activity.RESULT_FIRST_USER
// リクエスト
const val REQUEST_CODE_COLUMN_LIST = 1
const val REQUEST_APP_ABOUT = 3
const val REQUEST_CODE_NICKNAME = 4
const val REQUEST_CODE_POST = 5
const val REQUEST_CODE_TEXT = 8
const val REQUEST_CODE_LANGUAGE_FILTER = 9
// const val REQUEST_CODE_COLUMN_LIST = 1
// const val REQUEST_APP_ABOUT = 3
// const val REQUEST_CODE_NICKNAME = 4
// const val REQUEST_CODE_POST = 5
// const val REQUEST_CODE_TEXT = 8
// const val REQUEST_CODE_LANGUAGE_FILTER = 9
const val COLUMN_WIDTH_MIN_DP = 300
const val STATE_CURRENT_PAGE = "current_page"
// ActPostから参照される
var refActMain: WeakReference<ActMain>? = null
// 外部からインテントを受信した後、アカウント選択中に画面回転したらアカウント選択からやり直す
internal var sent_intent2: Intent? = null
@ -117,6 +124,9 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
var avatarIconSize: Int = 0
var notificationTlIconSize: Int = 0
// マルチウィンドウモードで子ウィンドウを閉じるのに使う
val closeList = LinkedList<WeakReference<AppCompatActivity>>()
// onResume() .. onPause() の間なら真
private var isResumed = false
@ -223,7 +233,7 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
}
}
private val link_click_listener: (View, MyClickableSpan) -> Unit = { viewClicked, span ->
override fun onMyClickableSpanClicked(viewClicked: View, span: MyClickableSpan) {
// ビュー階層を下から辿って文脈を取得する
var column: Column? = null
@ -496,6 +506,7 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
override fun onCreate(savedInstanceState: Bundle?) {
log.d("onCreate")
super.onCreate(savedInstanceState)
refActMain = WeakReference(this)
arColumnColor.register(this, log)
arLanguageFilter.register(this, log)
@ -560,8 +571,19 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
override fun onDestroy() {
log.d("onDestroy")
super.onDestroy()
refActMain = null
post_helper.onDestroy()
// 子画面を全て閉じる
closeList.forEach {
try {
it.get()?.finish()
} catch (ex: Throwable) {
log.e(ex, "close failed?")
}
}
closeList.clear()
// このアクティビティに関連する ColumnViewHolder への参照を全カラムから除去する
app_state.columnList.forEach {
it.removeColumnViewHolderByActivity(this)
@ -807,7 +829,7 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
at android.os.Binder.execTransact (Binder.java:739)
*/
MyClickableSpan.link_callback = WeakReference(link_click_listener)
// TODO MyClickableSpan.link_callback = WeakReference(link_click_listener)
if (Pref.bpDontScreenOff(pref)) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
@ -826,7 +848,6 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
if (intent != null) {
handleSentIntent(intent)
}
}
override fun onPause() {
@ -937,6 +958,31 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
dlgQuickTootMenu.toggle()
}
private fun updatePostedStatus(data: Intent) {
posted_acct = data.getStringExtra(ActPost.EXTRA_POSTED_ACCT)?.let { Acct.parse(it) }
if (data.extras?.containsKey(ActPost.EXTRA_POSTED_STATUS_ID) == true) {
posted_status_id = EntityId.from(data, ActPost.EXTRA_POSTED_STATUS_ID)
posted_reply_id = EntityId.from(data, ActPost.EXTRA_POSTED_REPLY_ID)
posted_redraft_id = EntityId.from(data, ActPost.EXTRA_POSTED_REDRAFT_ID)
} else {
posted_status_id = null
}
}
val arActPost = activityResultHandler { ar ->
val data = ar?.data
if (data != null && ar.resultCode == Activity.RESULT_OK) {
etQuickToot.setText("")
updatePostedStatus(data)
}
}
fun onMultiWindowPostComplete(data: Intent) {
if (!isLiveActivity) return
updatePostedStatus(data)
if (isStart_) refreshAfterPost()
}
private fun refreshAfterPost() {
val posted_acct = this.posted_acct
val posted_status_id = this.posted_status_id
@ -949,11 +995,8 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
) {
column.startLoading()
}
}
} else if (posted_acct != null && posted_status_id != null) {
val posted_redraft_id = this.posted_redraft_id
if (posted_redraft_id != null) {
val host = posted_acct.host
@ -1074,20 +1117,6 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
return false
}
val arActPost = activityResultHandler { ar ->
val data = ar?.data
if (data != null && ar.resultCode == Activity.RESULT_OK) {
etQuickToot.setText("")
posted_acct = data.getStringExtra(ActPost.EXTRA_POSTED_ACCT)?.let { Acct.parse(it) }
if (data.extras?.containsKey(ActPost.EXTRA_POSTED_STATUS_ID) == true) {
posted_status_id = EntityId.from(data, ActPost.EXTRA_POSTED_STATUS_ID)
posted_reply_id = EntityId.from(data, ActPost.EXTRA_POSTED_REPLY_ID)
posted_redraft_id = EntityId.from(data, ActPost.EXTRA_POSTED_REDRAFT_ID)
} else {
posted_status_id = null
}
}
}
private val arActText = activityResultHandler { ar ->
when (ar?.resultCode) {
@ -1704,7 +1733,7 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
userProfile(
defaultInsertPosition,
null,
Acct.parse(user,instance),
Acct.parse(user, instance),
userUrl = "https://$instance/@$user",
original_url = url
)
@ -1712,7 +1741,7 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
userProfile(
defaultInsertPosition,
null,
acct = Acct.parse(user,host),
acct = Acct.parse(user, host),
userUrl = url,
)
}
@ -1728,7 +1757,7 @@ class ActMain : AppCompatActivity(), View.OnClickListener,
userProfile(
defaultInsertPosition,
null,
acct = Acct.parse(user,host),
acct = Acct.parse(user, host),
userUrl = url,
)
return

File diff suppressed because it is too large Load Diff

View File

@ -485,6 +485,15 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
R.string.start,
R.string.end
)
sw(
Pref.bpMultiWindowPost,
R.string.multi_window_post
)
sw(
Pref.bpManyWindowPost,
R.string.many_window_post
)
}
section(R.string.media_attachment) {

View File

@ -450,6 +450,15 @@ object Pref {
false
)
val bpMultiWindowPost = BooleanPref(
"MultiWindowPost",
false
)
val bpManyWindowPost = BooleanPref(
"ManyWindowPost",
false
)
// int
val ipBackButtonAction = IntPref("back_button_action", 0)

View File

@ -275,7 +275,9 @@ internal class ViewHolderHeaderProfile(
append(tagWithSharp)
val end = length
tag.url?.notEmpty()?.let { url ->
val span = MyClickableSpan(LinkInfo(url = url, tag = tag.name, caption = tagWithSharp))
val span = MyClickableSpan(
LinkInfo(url = url, tag = tag.name, caption = tagWithSharp)
)
setSpan(span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}

View File

@ -3,6 +3,7 @@ package jp.juggler.subwaytooter.action
import android.content.Intent
import jp.juggler.subwaytooter.ActMain
import jp.juggler.subwaytooter.ActPost
import jp.juggler.subwaytooter.Pref
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.entity.TootAccount
import jp.juggler.subwaytooter.api.entity.TootScheduled
@ -12,6 +13,7 @@ import jp.juggler.subwaytooter.api.syncStatus
import jp.juggler.subwaytooter.dialog.pickAccount
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.matchHost
import jp.juggler.util.isLiveActivity
import jp.juggler.util.launchMain
import jp.juggler.util.showToast
@ -35,8 +37,12 @@ fun ActMain.openActPostImpl(
//(Mastodon) 予約投稿の編集
scheduledStatus: TootScheduled? = null
) = arActPost.launch(
ActPost.createIntent(
) {
val useManyWindow = Pref.bpManyWindowPost(pref)
val useMultiWindow = useManyWindow || Pref.bpMultiWindowPost(pref)
val intent = ActPost.createIntent(
activity = this,
account_db_id = account_db_id,
redraft_status = redraft_status,
@ -45,8 +51,27 @@ fun ActMain.openActPostImpl(
sent_intent = sent_intent,
quote = quote,
scheduledStatus = scheduledStatus,
multiWindowMode = useMultiWindow
)
)
if (!useMultiWindow) {
arActPost.launch(intent)
} else {
if (!useManyWindow)
ActPost.refActPost?.get()
?.takeIf { it.isLiveActivity }
?.let {
it.updateText(intent)
return
}
// fall thru
arActPost.launch(intent.apply{
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK )
})
}
}
// 投稿画面を開く。初期テキストを指定する
fun ActMain.openPost(

View File

@ -5,9 +5,13 @@ import android.text.style.ClickableSpan
import android.view.View
import jp.juggler.subwaytooter.api.entity.TootMention
import jp.juggler.subwaytooter.table.AcctColor
import jp.juggler.util.activity
import jp.juggler.util.cast
import jp.juggler.util.notZero
import java.lang.ref.WeakReference
interface MyClickableSpanHandler{
fun onMyClickableSpanClicked(viewClicked:View,span:MyClickableSpan)
}
class LinkInfo(
var url : String,
@ -23,11 +27,10 @@ class LinkInfo(
class MyClickableSpan(val linkInfo : LinkInfo) : ClickableSpan() {
companion object {
var link_callback : WeakReference<(View, MyClickableSpan) -> Unit>? = null
var defaultLinkColor : Int = 0
var showLinkUnderline = true
}
val color_fg : Int
val color_bg : Int
@ -43,7 +46,9 @@ class MyClickableSpan(val linkInfo : LinkInfo) : ClickableSpan() {
}
override fun onClick(view : View) {
link_callback?.get()?.invoke(view, this)
view.activity
?.cast<MyClickableSpanHandler>()
?.onMyClickableSpanClicked(view,this)
}
override fun updateDrawState(ds : TextPaint) {

View File

@ -23,6 +23,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.R
import java.util.*
@ -384,3 +385,6 @@ class ActivityResultHandler<A : ComponentActivity>(
@Suppress("unused")
fun <A : ComponentActivity> A.activityResultHandler(callback: A.(ActivityResult?) -> Unit) =
ActivityResultHandler(callback)
val AppCompatActivity.isLiveActivity: Boolean
get() = !(isFinishing || isDestroyed)

View File

@ -1,35 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
android:orientation="vertical">
<DatePicker
android:id="@+id/datePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:datePickerMode="spinner"
android:calendarViewShown="false"
android:spinnersShown="true"
android:layout_gravity="center_horizontal"
/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fadeScrollbars="false"
android:fillViewport="true"
android:scrollbarStyle="outsideOverlay">
<TimePicker
android:id="@+id/timePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:timePickerMode="spinner"
android:layout_gravity="center_horizontal"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<DatePicker
android:id="@+id/datePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:calendarViewShown="false"
android:datePickerMode="spinner"
android:spinnersShown="true" />
<TimePicker
android:id="@+id/timePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:timePickerMode="spinner" />
</LinearLayout>
</ScrollView>
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
android:orientation="horizontal">
<Button
android:id="@+id/btnCancel"
@ -37,8 +48,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/cancel"
/>
android:text="@string/cancel" />
<Button
android:id="@+id/btnOk"
@ -46,7 +56,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/ok"
/>
android:text="@string/ok" />
</LinearLayout>
</LinearLayout>

View File

@ -1093,4 +1093,8 @@
<string name="not_available_for_current_accounts">この機能を利用できるアカウントがありません</string>
<string name="confirm_reaction">%2$s から %1$s でリアクションしますか?</string>
<string name="confirm_reaction_to_pleroma">%2$s からカスタム絵文字 %1$s でリアクションしようとしていますが、送り先 %3$s はカスタム絵文字のリアクションに対応してないかもしれません。続けますか?</string>
<string name="multi_window_post">投稿画面を別ウィンドウで表示する</string>
<string name="many_window_post">投稿画面を多くのウィンドウで表示する</string>
</resources>

View File

@ -1106,4 +1106,6 @@
<string name="not_available_for_current_accounts">Unavailable for current accounts</string>
<string name="confirm_reaction">Reaction %1$s from %2$s?</string>
<string name="confirm_reaction_to_pleroma">Reaction custom emoji %1$s from %2$s to server %3$s that may not support custom emoji reaction. Continue?</string>
<string name="multi_window_post">Multi window for post activity</string>
<string name="many_window_post">Many window for post activity</string>
</resources>