2018-01-04 19:52:25 +01:00
|
|
|
package jp.juggler.subwaytooter
|
|
|
|
|
|
|
|
import android.app.Activity
|
|
|
|
import android.content.ContentValues
|
2023-02-04 21:52:26 +01:00
|
|
|
import android.content.Context
|
2018-01-04 19:52:25 +01:00
|
|
|
import android.content.Intent
|
|
|
|
import android.graphics.Bitmap
|
|
|
|
import android.net.Uri
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.os.Handler
|
|
|
|
import android.provider.MediaStore
|
2018-08-04 20:56:51 +02:00
|
|
|
import android.text.Editable
|
2018-09-05 16:03:26 +02:00
|
|
|
import android.text.SpannableString
|
2018-08-04 20:56:51 +02:00
|
|
|
import android.text.TextWatcher
|
2018-01-04 19:52:25 +01:00
|
|
|
import android.view.View
|
2018-08-20 19:37:42 +02:00
|
|
|
import android.widget.*
|
2019-08-24 05:35:22 +02:00
|
|
|
import androidx.appcompat.app.AlertDialog
|
2021-05-27 04:15:59 +02:00
|
|
|
import androidx.appcompat.app.AppCompatActivity
|
2023-01-17 13:42:47 +01:00
|
|
|
import jp.juggler.subwaytooter.api.*
|
|
|
|
import jp.juggler.subwaytooter.api.auth.AuthBase
|
2018-09-05 16:03:26 +02:00
|
|
|
import jp.juggler.subwaytooter.api.entity.*
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.subwaytooter.auth.AuthRepo
|
2021-11-21 08:12:10 +01:00
|
|
|
import jp.juggler.subwaytooter.databinding.ActAccountSettingBinding
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.subwaytooter.dialog.actionsDialog
|
2022-06-14 23:28:19 +02:00
|
|
|
import jp.juggler.subwaytooter.notification.*
|
2021-11-06 04:00:29 +01:00
|
|
|
import jp.juggler.subwaytooter.pref.PrefB
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.subwaytooter.push.PushBase
|
|
|
|
import jp.juggler.subwaytooter.push.pushRepo
|
2018-01-04 19:52:25 +01:00
|
|
|
import jp.juggler.subwaytooter.table.SavedAccount
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.subwaytooter.table.daoAcctColor
|
|
|
|
import jp.juggler.subwaytooter.table.daoSavedAccount
|
2022-05-31 16:39:22 +02:00
|
|
|
import jp.juggler.subwaytooter.util.*
|
2018-12-01 00:02:18 +01:00
|
|
|
import jp.juggler.util.*
|
2023-01-17 13:42:47 +01:00
|
|
|
import jp.juggler.util.coroutine.AppDispatchers
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.util.coroutine.launchAndShowError
|
2023-01-13 13:22:25 +01:00
|
|
|
import jp.juggler.util.coroutine.launchMain
|
|
|
|
import jp.juggler.util.coroutine.launchProgress
|
|
|
|
import jp.juggler.util.data.*
|
|
|
|
import jp.juggler.util.log.LogCategory
|
|
|
|
import jp.juggler.util.log.showToast
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.util.log.withCaption
|
2023-01-13 13:22:25 +01:00
|
|
|
import jp.juggler.util.media.ResizeConfig
|
|
|
|
import jp.juggler.util.media.ResizeType
|
|
|
|
import jp.juggler.util.media.createResizedBitmap
|
|
|
|
import jp.juggler.util.network.toPatch
|
|
|
|
import jp.juggler.util.network.toPost
|
|
|
|
import jp.juggler.util.network.toPostRequestBuilder
|
|
|
|
import jp.juggler.util.ui.*
|
2023-01-17 13:42:47 +01:00
|
|
|
import kotlinx.coroutines.withContext
|
2021-06-23 06:14:25 +02:00
|
|
|
import kotlinx.serialization.decodeFromString
|
|
|
|
import kotlinx.serialization.encodeToString
|
2018-02-12 14:56:37 +01:00
|
|
|
import okhttp3.MediaType
|
2019-08-24 05:35:22 +02:00
|
|
|
import okhttp3.MediaType.Companion.toMediaType
|
2018-02-12 14:56:37 +01:00
|
|
|
import okhttp3.MultipartBody
|
2018-01-04 19:52:25 +01:00
|
|
|
import okhttp3.RequestBody
|
2018-02-12 14:56:37 +01:00
|
|
|
import okio.BufferedSink
|
2019-01-21 00:00:59 +01:00
|
|
|
import org.jetbrains.anko.backgroundColor
|
|
|
|
import org.jetbrains.anko.textColor
|
2022-05-30 22:30:52 +02:00
|
|
|
import java.io.File
|
|
|
|
import java.io.FileInputStream
|
|
|
|
import java.io.FileOutputStream
|
|
|
|
import java.io.InputStream
|
2019-08-24 05:35:22 +02:00
|
|
|
import kotlin.math.max
|
2018-01-04 19:52:25 +01:00
|
|
|
|
2022-06-04 20:35:07 +02:00
|
|
|
class ActAccountSetting : AppCompatActivity(),
|
|
|
|
View.OnClickListener,
|
|
|
|
CompoundButton.OnCheckedChangeListener,
|
|
|
|
AdapterView.OnItemSelectedListener {
|
2021-02-09 23:25:06 +01:00
|
|
|
companion object {
|
|
|
|
|
|
|
|
internal val log = LogCategory("ActAccountSetting")
|
|
|
|
|
|
|
|
internal const val KEY_ACCOUNT_DB_ID = "account_db_id"
|
|
|
|
|
|
|
|
internal const val RESULT_INPUT_ACCESS_TOKEN = Activity.RESULT_FIRST_USER + 10
|
|
|
|
internal const val EXTRA_DB_ID = "db_id"
|
|
|
|
|
|
|
|
internal const val max_length_display_name = 30
|
|
|
|
internal const val max_length_note = 160
|
|
|
|
internal const val max_length_fields = 255
|
|
|
|
|
|
|
|
internal const val MIME_TYPE_JPEG = "image/jpeg"
|
|
|
|
internal const val MIME_TYPE_PNG = "image/png"
|
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
private const val ACTIVITY_STATE = "MyActivityState"
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
fun createIntent(activity: Activity, ai: SavedAccount) =
|
|
|
|
Intent(activity, ActAccountSetting::class.java).apply {
|
|
|
|
putExtra(KEY_ACCOUNT_DB_ID, ai.db_id)
|
|
|
|
}
|
2022-01-05 10:39:48 +01:00
|
|
|
|
|
|
|
fun simpleTextWatcher(block: () -> Unit) = object : TextWatcher {
|
|
|
|
override fun afterTextChanged(s: Editable?) {
|
|
|
|
block()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun beforeTextChanged(
|
|
|
|
s: CharSequence?,
|
|
|
|
start: Int,
|
|
|
|
count: Int,
|
|
|
|
after: Int,
|
|
|
|
) {
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onTextChanged(
|
|
|
|
s: CharSequence?,
|
|
|
|
start: Int,
|
|
|
|
before: Int,
|
|
|
|
count: Int,
|
|
|
|
) {
|
|
|
|
}
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
@kotlinx.serialization.Serializable
|
|
|
|
data class State(
|
|
|
|
var propName: String = "",
|
2021-05-22 11:07:23 +02:00
|
|
|
|
2021-06-23 06:14:25 +02:00
|
|
|
@kotlinx.serialization.Serializable(with = UriSerializer::class)
|
2021-05-22 11:07:23 +02:00
|
|
|
var uriCameraImage: Uri? = null,
|
2021-05-22 00:03:16 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var state = State()
|
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
lateinit var handler: Handler
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
lateinit var account: SavedAccount
|
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
private val views by lazy {
|
2023-01-14 21:37:23 +01:00
|
|
|
ActAccountSettingBinding.inflate(layoutInflater, null, false)
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
private val authRepo by lazy {
|
|
|
|
AuthRepo(this)
|
|
|
|
}
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
private lateinit var nameInvalidator: NetworkEmojiInvalidator
|
|
|
|
private lateinit var noteInvalidator: NetworkEmojiInvalidator
|
|
|
|
private lateinit var defaultTextInvalidator: NetworkEmojiInvalidator
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
private var loadingBusy = false
|
|
|
|
private var profileBusy = false
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
private lateinit var listEtFieldName: List<EditText>
|
|
|
|
private lateinit var listEtFieldValue: List<EditText>
|
|
|
|
private lateinit var listFieldNameInvalidator: List<NetworkEmojiInvalidator>
|
|
|
|
private lateinit var listFieldValueInvalidator: List<NetworkEmojiInvalidator>
|
|
|
|
private lateinit var btnFields: View
|
|
|
|
|
2021-05-11 08:12:43 +02:00
|
|
|
private class ResizeItem(val config: ResizeConfig, val caption: String)
|
|
|
|
|
|
|
|
private lateinit var imageResizeItems: List<ResizeItem>
|
|
|
|
|
|
|
|
private class PushPolicyItem(val id: String?, val caption: String)
|
|
|
|
|
|
|
|
private lateinit var pushPolicyItems: List<PushPolicyItem>
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
internal var visibility = TootVisibility.Public
|
|
|
|
|
2022-03-16 09:04:19 +01:00
|
|
|
private val languages by lazy {
|
2022-05-31 16:39:22 +02:00
|
|
|
loadLanguageList()
|
2022-03-16 09:04:19 +01:00
|
|
|
}
|
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
2022-08-06 00:52:31 +02:00
|
|
|
private val arShowAcctColor = ActivityResultHandler(log) { r ->
|
|
|
|
if (r.isNotOk) return@ActivityResultHandler
|
|
|
|
showAcctColor()
|
2021-05-22 00:03:16 +02:00
|
|
|
}
|
|
|
|
|
2022-08-06 00:52:31 +02:00
|
|
|
private val arAddAttachment = ActivityResultHandler(log) { r ->
|
|
|
|
if (r.isNotOk) return@ActivityResultHandler
|
|
|
|
r.data
|
|
|
|
?.handleGetContentResult(contentResolver)
|
|
|
|
?.firstOrNull()
|
|
|
|
?.let {
|
|
|
|
uploadImage(
|
|
|
|
state.propName,
|
|
|
|
it.uri,
|
|
|
|
it.mimeType?.notEmpty() ?: contentResolver.getType(it.uri)
|
|
|
|
)
|
|
|
|
}
|
2021-05-22 00:03:16 +02:00
|
|
|
}
|
|
|
|
|
2022-08-06 00:52:31 +02:00
|
|
|
private val arCameraImage = ActivityResultHandler(log) { r ->
|
|
|
|
if (r.isNotOk) {
|
2021-05-22 00:03:16 +02:00
|
|
|
// 失敗したら DBからデータを削除
|
2021-05-23 14:54:52 +02:00
|
|
|
state.uriCameraImage?.let {
|
2021-05-22 11:07:23 +02:00
|
|
|
contentResolver.delete(it, null, null)
|
2021-05-22 00:03:16 +02:00
|
|
|
}
|
2021-05-22 11:07:23 +02:00
|
|
|
state.uriCameraImage = null
|
2022-08-06 00:52:31 +02:00
|
|
|
} else {
|
|
|
|
// 画像のURL
|
|
|
|
val uri = r.data?.data ?: state.uriCameraImage
|
|
|
|
if (uri != null) {
|
|
|
|
val type = contentResolver.getType(uri)
|
|
|
|
uploadImage(state.propName, uri, type)
|
|
|
|
}
|
2021-05-22 00:03:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-05 08:26:35 +01:00
|
|
|
private val prPickAvater = permissionSpecImagePicker.requester { openPicker(it) }
|
|
|
|
private val prPickHeader = permissionSpecImagePicker.requester { openPicker(it) }
|
2022-08-06 00:52:31 +02:00
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
///////////////////////////////////////////////////
|
|
|
|
|
2021-02-09 23:25:06 +01:00
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
2022-09-10 23:09:26 +02:00
|
|
|
backPressed {
|
|
|
|
checkNotificationImmediateAll(this, onlySubscription = true)
|
|
|
|
checkNotificationImmediate(this, account.db_id)
|
|
|
|
finish()
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2022-08-06 00:52:31 +02:00
|
|
|
prPickAvater.register(this)
|
|
|
|
prPickHeader.register(this)
|
|
|
|
|
|
|
|
arShowAcctColor.register(this)
|
|
|
|
arAddAttachment.register(this)
|
|
|
|
arCameraImage.register(this)
|
2021-05-22 00:03:16 +02:00
|
|
|
|
|
|
|
if (savedInstanceState != null) {
|
|
|
|
savedInstanceState.getString(ACTIVITY_STATE)
|
2021-06-23 06:14:25 +02:00
|
|
|
?.let { state = kJson.decodeFromString(it) }
|
2021-05-22 00:03:16 +02:00
|
|
|
}
|
|
|
|
|
2021-02-09 23:25:06 +01:00
|
|
|
App1.setActivityTheme(this)
|
|
|
|
|
|
|
|
initUI()
|
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
launchAndShowError {
|
|
|
|
val a = intent.long(KEY_ACCOUNT_DB_ID)
|
|
|
|
?.let { daoSavedAccount.loadAccount(it) }
|
|
|
|
if (a == null) {
|
|
|
|
finish()
|
|
|
|
return@launchAndShowError
|
|
|
|
}
|
|
|
|
supportActionBar?.subtitle = a.acct.pretty
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
loadUIFromData(a)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
initializeProfile()
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
views.btnOpenBrowser.text =
|
|
|
|
getString(R.string.open_instance_website, account.apiHost.pretty)
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
override fun onSaveInstanceState(outState: Bundle) {
|
|
|
|
super.onSaveInstanceState(outState)
|
2021-05-22 11:07:23 +02:00
|
|
|
|
2021-06-23 06:14:25 +02:00
|
|
|
val encodedState = kJson.encodeToString(state)
|
2021-05-22 11:07:23 +02:00
|
|
|
log.d("encodedState=$encodedState")
|
2021-06-23 06:14:25 +02:00
|
|
|
val decodedState: State = kJson.decodeFromString(encodedState)
|
2021-05-22 11:07:23 +02:00
|
|
|
log.d("encodedState.uriCameraImage=${decodedState.uriCameraImage}")
|
2021-05-23 14:54:52 +02:00
|
|
|
outState.putString(ACTIVITY_STATE, encodedState)
|
2021-05-22 00:03:16 +02:00
|
|
|
}
|
|
|
|
|
2021-02-09 23:25:06 +01:00
|
|
|
var density: Float = 1f
|
|
|
|
|
2022-03-11 00:11:49 +01:00
|
|
|
@Suppress("LongMethod")
|
2021-02-09 23:25:06 +01:00
|
|
|
private fun initUI() {
|
|
|
|
this.density = resources.displayMetrics.density
|
|
|
|
this.handler = App1.getAppState(this).handler
|
2023-01-17 13:42:47 +01:00
|
|
|
setContentView(views.root)
|
|
|
|
setSupportActionBar(views.toolbar)
|
|
|
|
fixHorizontalPadding(views.svContent)
|
|
|
|
setSwitchColor(views.root)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
views.apply {
|
2021-11-21 08:12:10 +01:00
|
|
|
btnPushSubscriptionNotForce.vg(BuildConfig.DEBUG)
|
|
|
|
|
|
|
|
imageResizeItems = SavedAccount.resizeConfigList.map {
|
|
|
|
val caption = when (it.type) {
|
|
|
|
ResizeType.None -> getString(R.string.dont_resize)
|
|
|
|
ResizeType.LongSide -> getString(R.string.long_side_pixel, it.size)
|
|
|
|
ResizeType.SquarePixel -> if (it.extraStringId != 0) {
|
|
|
|
getString(
|
|
|
|
R.string.resize_square_pixels_2,
|
|
|
|
it.size * it.size,
|
|
|
|
getString(it.extraStringId)
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
getString(
|
|
|
|
R.string.resize_square_pixels,
|
|
|
|
it.size * it.size,
|
|
|
|
it.size
|
|
|
|
)
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
2021-11-21 08:12:10 +01:00
|
|
|
ResizeItem(it, caption)
|
|
|
|
}
|
|
|
|
spResizeImage.adapter = ArrayAdapter(
|
|
|
|
this@ActAccountSetting,
|
|
|
|
android.R.layout.simple_spinner_item,
|
|
|
|
imageResizeItems.map { it.caption }.toTypedArray()
|
|
|
|
).apply {
|
|
|
|
setDropDownViewResource(R.layout.lv_spinner_dropdown)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2022-03-16 09:04:19 +01:00
|
|
|
spLanguageCode.adapter = ArrayAdapter(
|
|
|
|
this@ActAccountSetting,
|
|
|
|
android.R.layout.simple_spinner_item,
|
|
|
|
languages.map { it.second }.toTypedArray()
|
|
|
|
).apply {
|
|
|
|
setDropDownViewResource(R.layout.lv_spinner_dropdown)
|
|
|
|
}
|
|
|
|
|
2022-01-05 10:39:48 +01:00
|
|
|
spMovieTranscodeMode.adapter = ArrayAdapter(
|
|
|
|
this@ActAccountSetting,
|
|
|
|
android.R.layout.simple_spinner_item,
|
|
|
|
arrayOf(
|
|
|
|
getString(R.string.auto),
|
|
|
|
getString(R.string.no),
|
|
|
|
getString(R.string.always),
|
|
|
|
)
|
|
|
|
).apply {
|
|
|
|
setDropDownViewResource(R.layout.lv_spinner_dropdown)
|
|
|
|
}
|
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
pushPolicyItems = listOf(
|
|
|
|
PushPolicyItem(null, getString(R.string.unspecified)),
|
|
|
|
PushPolicyItem("all", getString(R.string.all)),
|
|
|
|
PushPolicyItem("followed", getString(R.string.following)),
|
|
|
|
PushPolicyItem("follower", getString(R.string.followers)),
|
|
|
|
PushPolicyItem("none", getString(R.string.no_one)),
|
|
|
|
)
|
2021-05-11 08:12:43 +02:00
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
spPushPolicy.adapter = ArrayAdapter(
|
|
|
|
this@ActAccountSetting,
|
|
|
|
android.R.layout.simple_spinner_item,
|
|
|
|
pushPolicyItems.map { it.caption }.toTypedArray()
|
|
|
|
).apply {
|
|
|
|
setDropDownViewResource(R.layout.lv_spinner_dropdown)
|
|
|
|
}
|
2021-05-11 08:12:43 +02:00
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
listEtFieldName = intArrayOf(
|
|
|
|
R.id.etFieldName1,
|
|
|
|
R.id.etFieldName2,
|
|
|
|
R.id.etFieldName3,
|
|
|
|
R.id.etFieldName4
|
|
|
|
).map { findViewById(it) }
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
listEtFieldValue = intArrayOf(
|
|
|
|
R.id.etFieldValue1,
|
|
|
|
R.id.etFieldValue2,
|
|
|
|
R.id.etFieldValue3,
|
|
|
|
R.id.etFieldValue4
|
|
|
|
).map { findViewById(it) }
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
btnNotificationStyleEditReply.vg(PrefB.bpSeparateReplyNotificationGroup.value)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
nameInvalidator = NetworkEmojiInvalidator(handler, etDisplayName)
|
|
|
|
noteInvalidator = NetworkEmojiInvalidator(handler, etNote)
|
|
|
|
defaultTextInvalidator = NetworkEmojiInvalidator(handler, etDefaultText)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
listFieldNameInvalidator = listEtFieldName.map {
|
|
|
|
NetworkEmojiInvalidator(handler, it)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
listFieldValueInvalidator = listEtFieldValue.map {
|
|
|
|
NetworkEmojiInvalidator(handler, it)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2022-03-16 09:04:19 +01:00
|
|
|
val watcher1 = simpleTextWatcher {
|
|
|
|
saveUIToData()
|
2022-01-05 10:39:48 +01:00
|
|
|
}
|
2021-11-21 08:12:10 +01:00
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
views.root.scan {
|
2022-03-16 09:04:19 +01:00
|
|
|
when (it) {
|
|
|
|
etMaxTootChars -> etMaxTootChars.addTextChangedListener(
|
|
|
|
simpleTextWatcher {
|
|
|
|
val num = etMaxTootChars.parseInt()
|
|
|
|
if (num != null && num >= 0) {
|
|
|
|
saveUIToData()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
is EditText ->
|
|
|
|
it.addTextChangedListener(watcher1)
|
|
|
|
is Spinner ->
|
|
|
|
it.onItemSelectedListener = this@ActAccountSetting
|
2022-06-13 19:23:46 +02:00
|
|
|
// CompoundButton はButtonでもあるので上に置く
|
|
|
|
is CompoundButton ->
|
|
|
|
it.setOnCheckedChangeListener(this@ActAccountSetting)
|
|
|
|
is ImageButton ->
|
|
|
|
it.setOnClickListener(this@ActAccountSetting)
|
|
|
|
is Button ->
|
|
|
|
it.setOnClickListener(this@ActAccountSetting)
|
2021-11-21 08:12:10 +01:00
|
|
|
}
|
2022-03-16 09:04:19 +01:00
|
|
|
}
|
2021-11-21 08:12:10 +01:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
private fun EditText.parseInt(): Int? =
|
|
|
|
text?.toString()?.toIntOrNull()
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
private fun loadUIFromData(a: SavedAccount) {
|
|
|
|
this.account = a
|
|
|
|
this.visibility = a.visibility
|
2021-06-20 15:12:25 +02:00
|
|
|
loadingBusy = true
|
2021-11-21 08:12:10 +01:00
|
|
|
try {
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
views.apply {
|
2021-11-21 08:12:10 +01:00
|
|
|
|
|
|
|
tvInstance.text = a.apiHost.pretty
|
|
|
|
tvUser.text = a.acct.pretty
|
2023-02-06 03:10:24 +01:00
|
|
|
swNSFWOpen.isChecked = a.dontHideNsfw
|
|
|
|
swDontShowTimeout.isChecked = a.dontShowTimeout
|
|
|
|
swExpandCW.isChecked = a.expandCw
|
|
|
|
swMarkSensitive.isChecked = a.defaultSensitive
|
|
|
|
cbNotificationMention.isChecked = a.notificationMention
|
|
|
|
cbNotificationBoost.isChecked = a.notificationBoost
|
|
|
|
cbNotificationFavourite.isChecked = a.notificationFavourite
|
|
|
|
cbNotificationFollow.isChecked = a.notificationFollow
|
|
|
|
cbNotificationFollowRequest.isChecked = a.notificationFollowRequest
|
|
|
|
cbNotificationReaction.isChecked = a.notificationReaction
|
|
|
|
cbNotificationVote.isChecked = a.notificationVote
|
|
|
|
cbNotificationPost.isChecked = a.notificationPost
|
|
|
|
cbNotificationUpdate.isChecked = a.notificationUpdate
|
|
|
|
cbNotificationStatusReference.isChecked = a.notificationStatusReference
|
|
|
|
|
|
|
|
cbConfirmFollow.isChecked = a.confirmFollow
|
|
|
|
cbConfirmFollowLockedUser.isChecked = a.confirmFollowLocked
|
|
|
|
cbConfirmUnfollow.isChecked = a.confirmUnfollow
|
|
|
|
cbConfirmBoost.isChecked = a.confirmBoost
|
|
|
|
cbConfirmFavourite.isChecked = a.confirmFavourite
|
|
|
|
cbConfirmUnboost.isChecked = a.confirmUnboost
|
|
|
|
cbConfirmUnfavourite.isChecked = a.confirmUnfavourite
|
|
|
|
cbConfirmToot.isChecked = a.confirmPost
|
|
|
|
cbConfirmReaction.isChecked = a.confirmReaction
|
|
|
|
cbConfirmUnbookmark.isChecked = a.confirmUnbookmark
|
|
|
|
|
|
|
|
etDefaultText.setText(a.defaultText)
|
|
|
|
etMaxTootChars.setText(a.maxTootChars.toString())
|
2021-11-21 08:12:10 +01:00
|
|
|
|
2022-01-05 10:39:48 +01:00
|
|
|
val ti = TootInstance.getCached(a)
|
|
|
|
if (ti == null) {
|
2023-02-06 03:10:24 +01:00
|
|
|
etMediaSizeMax.setText(a.imageMaxMegabytes ?: "")
|
|
|
|
etMovieSizeMax.setText(a.movieMaxMegabytes ?: "")
|
2022-01-05 10:39:48 +01:00
|
|
|
} else {
|
|
|
|
etMediaSizeMax.setText(
|
2023-02-06 03:10:24 +01:00
|
|
|
a.imageMaxMegabytes
|
2022-01-05 10:39:48 +01:00
|
|
|
?: a.getImageMaxBytes(ti).div(1000000).toString()
|
|
|
|
)
|
|
|
|
etMovieSizeMax.setText(
|
2023-02-06 03:10:24 +01:00
|
|
|
a.movieMaxMegabytes
|
2022-01-05 10:39:48 +01:00
|
|
|
?: a.getMovieMaxBytes(ti).div(1000000).toString()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
val currentResizeConfig = a.getResizeConfig()
|
|
|
|
var index =
|
|
|
|
imageResizeItems.indexOfFirst { it.config.spec == currentResizeConfig.spec }
|
|
|
|
log.d("ResizeItem current ${currentResizeConfig.spec} index=$index ")
|
|
|
|
if (index == -1) index =
|
|
|
|
imageResizeItems.indexOfFirst { it.config.spec == SavedAccount.defaultResizeConfig.spec }
|
|
|
|
spResizeImage.setSelection(index, false)
|
|
|
|
|
2023-02-06 03:10:24 +01:00
|
|
|
val currentPushPolicy = a.pushPolicy
|
2022-01-05 10:39:48 +01:00
|
|
|
index = pushPolicyItems.indexOfFirst { it.id == currentPushPolicy }
|
|
|
|
if (index == -1) index = 0
|
|
|
|
spPushPolicy.setSelection(index, false)
|
|
|
|
|
|
|
|
spMovieTranscodeMode.setSelection(max(0, a.movieTranscodeMode), false)
|
|
|
|
etMovieFrameRate.setText(a.movieTranscodeFramerate)
|
|
|
|
etMovieBitrate.setText(a.movieTranscodeBitrate)
|
|
|
|
etMovieSquarePixels.setText(a.movieTranscodeSquarePixels)
|
|
|
|
|
2022-03-16 09:04:19 +01:00
|
|
|
spLanguageCode.setSelection(max(0, languages.indexOfFirst { it.first == a.lang }))
|
|
|
|
|
2022-01-05 10:39:48 +01:00
|
|
|
// アカウントからUIへのデータロードはここまで
|
2021-11-21 08:12:10 +01:00
|
|
|
loadingBusy = false
|
|
|
|
|
|
|
|
val enabled = !a.isPseudo
|
|
|
|
|
|
|
|
arrayOf(
|
|
|
|
btnAccessToken,
|
|
|
|
btnInputAccessToken,
|
|
|
|
btnVisibility,
|
|
|
|
btnPushSubscription,
|
|
|
|
btnPushSubscriptionNotForce,
|
|
|
|
btnResetNotificationTracking,
|
|
|
|
cbNotificationMention,
|
|
|
|
cbNotificationBoost,
|
|
|
|
cbNotificationFavourite,
|
|
|
|
cbNotificationFollow,
|
|
|
|
cbNotificationFollowRequest,
|
|
|
|
cbNotificationReaction,
|
|
|
|
cbNotificationVote,
|
|
|
|
cbNotificationPost,
|
2022-03-15 12:39:37 +01:00
|
|
|
cbNotificationUpdate,
|
2022-03-19 15:42:20 +01:00
|
|
|
cbNotificationStatusReference,
|
2021-11-21 08:12:10 +01:00
|
|
|
cbConfirmFollow,
|
|
|
|
cbConfirmFollowLockedUser,
|
|
|
|
cbConfirmUnfollow,
|
|
|
|
cbConfirmBoost,
|
|
|
|
cbConfirmFavourite,
|
|
|
|
cbConfirmUnboost,
|
|
|
|
cbConfirmUnfavourite,
|
|
|
|
cbConfirmToot,
|
|
|
|
cbConfirmReaction,
|
|
|
|
).forEach { it.isEnabledAlpha = enabled }
|
|
|
|
|
|
|
|
arrayOf(
|
|
|
|
btnNotificationStyleEdit,
|
|
|
|
btnNotificationStyleEditReply,
|
2022-08-11 09:51:49 +02:00
|
|
|
).forEach { it.isEnabledAlpha = enabled }
|
2021-11-21 08:12:10 +01:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-11-21 08:12:10 +01:00
|
|
|
showVisibility()
|
|
|
|
showAcctColor()
|
|
|
|
} finally {
|
|
|
|
loadingBusy = false
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun showAcctColor() {
|
2023-02-04 21:52:26 +01:00
|
|
|
|
2021-02-09 23:25:06 +01:00
|
|
|
val sa = this.account
|
2023-02-04 21:52:26 +01:00
|
|
|
val ac = daoAcctColor.load(sa)
|
2023-01-17 13:42:47 +01:00
|
|
|
views.tvUserCustom.apply {
|
2023-02-04 21:52:26 +01:00
|
|
|
backgroundColor = ac.colorBg
|
2021-11-21 08:12:10 +01:00
|
|
|
text = ac.nickname
|
2023-02-04 21:52:26 +01:00
|
|
|
textColor = ac.colorFg.notZero()
|
|
|
|
?: attrColor(R.attr.colorTimeSmall)
|
2021-11-21 08:12:10 +01:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun saveUIToData() {
|
|
|
|
if (!::account.isInitialized) return
|
2021-06-20 15:12:25 +02:00
|
|
|
if (loadingBusy) return
|
2023-02-04 21:52:26 +01:00
|
|
|
launchAndShowError {
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
account.visibility = visibility
|
2021-11-21 08:12:10 +01:00
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
views.apply {
|
2023-02-06 03:10:24 +01:00
|
|
|
account.dontHideNsfw = swNSFWOpen.isChecked
|
|
|
|
account.dontShowTimeout = swDontShowTimeout.isChecked
|
|
|
|
account.expandCw = swExpandCW.isChecked
|
|
|
|
account.defaultSensitive = swMarkSensitive.isChecked
|
|
|
|
account.notificationMention = cbNotificationMention.isChecked
|
|
|
|
account.notificationBoost = cbNotificationBoost.isChecked
|
|
|
|
account.notificationFavourite = cbNotificationFavourite.isChecked
|
|
|
|
account.notificationFollow = cbNotificationFollow.isChecked
|
|
|
|
account.notificationFollowRequest = cbNotificationFollowRequest.isChecked
|
|
|
|
account.notificationReaction = cbNotificationReaction.isChecked
|
|
|
|
account.notificationVote = cbNotificationVote.isChecked
|
|
|
|
account.notificationPost = cbNotificationPost.isChecked
|
|
|
|
account.notificationUpdate = cbNotificationUpdate.isChecked
|
|
|
|
account.notificationStatusReference = cbNotificationStatusReference.isChecked
|
|
|
|
|
|
|
|
account.confirmFollow = cbConfirmFollow.isChecked
|
|
|
|
account.confirmFollowLocked = cbConfirmFollowLockedUser.isChecked
|
|
|
|
account.confirmUnfollow = cbConfirmUnfollow.isChecked
|
|
|
|
account.confirmBoost = cbConfirmBoost.isChecked
|
|
|
|
account.confirmFavourite = cbConfirmFavourite.isChecked
|
|
|
|
account.confirmUnboost = cbConfirmUnboost.isChecked
|
|
|
|
account.confirmUnfavourite = cbConfirmUnfavourite.isChecked
|
|
|
|
account.confirmPost = cbConfirmToot.isChecked
|
|
|
|
account.confirmReaction = cbConfirmReaction.isChecked
|
|
|
|
account.confirmUnbookmark = cbConfirmUnbookmark.isChecked
|
|
|
|
|
|
|
|
account.soundUri = ""
|
|
|
|
account.defaultText = etDefaultText.text.toString()
|
|
|
|
|
|
|
|
account.maxTootChars = etMaxTootChars.parseInt()?.takeIf { it > 0 } ?: 0
|
|
|
|
|
|
|
|
account.movieMaxMegabytes = etMovieSizeMax.text.toString().trim()
|
|
|
|
account.imageMaxMegabytes = etMediaSizeMax.text.toString().trim()
|
|
|
|
account.imageResize = (
|
2023-02-04 21:52:26 +01:00
|
|
|
imageResizeItems.elementAtOrNull(spResizeImage.selectedItemPosition)?.config
|
|
|
|
?: SavedAccount.defaultResizeConfig
|
|
|
|
).spec
|
|
|
|
|
2023-02-06 03:10:24 +01:00
|
|
|
account.pushPolicy =
|
2023-02-04 21:52:26 +01:00
|
|
|
pushPolicyItems.elementAtOrNull(spPushPolicy.selectedItemPosition)?.id
|
|
|
|
|
|
|
|
account.movieTranscodeMode = spMovieTranscodeMode.selectedItemPosition
|
|
|
|
account.movieTranscodeBitrate = etMovieBitrate.text.toString()
|
|
|
|
account.movieTranscodeFramerate = etMovieFrameRate.text.toString()
|
|
|
|
account.movieTranscodeSquarePixels = etMovieSquarePixels.text.toString()
|
|
|
|
account.lang = languages.elementAtOrNull(spLanguageCode.selectedItemPosition)?.first
|
|
|
|
?: SavedAccount.LANG_WEB
|
|
|
|
}
|
2021-05-11 08:12:43 +02:00
|
|
|
|
2023-02-06 03:10:24 +01:00
|
|
|
daoSavedAccount.save(account)
|
2023-02-04 21:52:26 +01:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
|
2023-01-17 13:42:47 +01:00
|
|
|
if (buttonView == views.cbLocked) {
|
2021-06-20 15:12:25 +02:00
|
|
|
if (!profileBusy) sendLocked(isChecked)
|
2021-02-09 23:25:06 +01:00
|
|
|
} else {
|
|
|
|
saveUIToData()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
|
|
|
saveUIToData()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onNothingSelected(parent: AdapterView<*>?) {
|
|
|
|
saveUIToData()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onClick(v: View) {
|
|
|
|
when (v.id) {
|
|
|
|
R.id.btnAccessToken -> performAccessToken()
|
|
|
|
R.id.btnInputAccessToken -> inputAccessToken()
|
|
|
|
|
|
|
|
R.id.btnAccountRemove -> performAccountRemove()
|
|
|
|
R.id.btnLoadPreference -> performLoadPreference()
|
|
|
|
R.id.btnVisibility -> performVisibility()
|
|
|
|
R.id.btnOpenBrowser -> openBrowser("https://${account.apiHost.ascii}/")
|
2021-05-27 04:15:59 +02:00
|
|
|
R.id.btnPushSubscription -> updatePushSubscription(force = true)
|
|
|
|
R.id.btnPushSubscriptionNotForce -> updatePushSubscription(force = false)
|
2021-02-09 23:25:06 +01:00
|
|
|
R.id.btnResetNotificationTracking ->
|
2022-06-13 19:23:46 +02:00
|
|
|
resetNotificationTracking(account)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
R.id.btnUserCustom -> arShowAcctColor.launch(
|
|
|
|
ActNickname.createIntent(this, account.acct, false),
|
2022-06-13 19:23:46 +02:00
|
|
|
)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
R.id.btnProfileAvatar -> pickAvatarImage()
|
|
|
|
|
|
|
|
R.id.btnProfileHeader -> pickHeaderImage()
|
|
|
|
|
|
|
|
R.id.btnDisplayName -> sendDisplayName()
|
|
|
|
|
|
|
|
R.id.btnNote -> sendNote()
|
|
|
|
|
|
|
|
R.id.btnFields -> sendFields()
|
|
|
|
|
|
|
|
R.id.btnNotificationStyleEdit ->
|
2023-02-04 21:52:26 +01:00
|
|
|
PullNotification.openNotificationChannelSetting(
|
|
|
|
this
|
2021-02-09 23:25:06 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
R.id.btnNotificationStyleEditReply ->
|
2023-02-04 21:52:26 +01:00
|
|
|
PullNotification.openNotificationChannelSetting(
|
|
|
|
this
|
2021-02-09 23:25:06 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun showVisibility() {
|
2023-01-17 13:42:47 +01:00
|
|
|
views.btnVisibility.text =
|
2023-02-04 21:52:26 +01:00
|
|
|
visibility.getVisibilityString(account.isMisskey)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun performVisibility() {
|
|
|
|
|
|
|
|
val list = if (account.isMisskey) {
|
|
|
|
arrayOf(
|
|
|
|
// TootVisibility.WebSetting,
|
|
|
|
TootVisibility.Public,
|
|
|
|
TootVisibility.UnlistedHome,
|
|
|
|
TootVisibility.PrivateFollowers,
|
|
|
|
TootVisibility.LocalPublic,
|
|
|
|
TootVisibility.LocalHome,
|
|
|
|
TootVisibility.LocalFollowers,
|
|
|
|
TootVisibility.DirectSpecified,
|
|
|
|
TootVisibility.DirectPrivate
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
arrayOf(
|
|
|
|
TootVisibility.WebSetting,
|
|
|
|
TootVisibility.Public,
|
|
|
|
TootVisibility.UnlistedHome,
|
|
|
|
TootVisibility.PrivateFollowers,
|
|
|
|
TootVisibility.DirectSpecified
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
val captionList = list.map {
|
2023-01-13 13:22:25 +01:00
|
|
|
getVisibilityCaption(this, account.isMisskey, it)
|
2021-02-09 23:25:06 +01:00
|
|
|
}.toTypedArray()
|
|
|
|
|
|
|
|
AlertDialog.Builder(this)
|
|
|
|
.setTitle(R.string.choose_visibility)
|
2021-06-20 15:12:25 +02:00
|
|
|
.setItems(captionList) { _, which ->
|
2021-02-09 23:25:06 +01:00
|
|
|
if (which in list.indices) {
|
|
|
|
visibility = list[which]
|
|
|
|
showVisibility()
|
|
|
|
saveUIToData()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.show()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun performLoadPreference() {
|
2021-05-27 04:15:59 +02:00
|
|
|
launchMain {
|
|
|
|
runApiTask(account) { client ->
|
|
|
|
client.request("/api/v1/preferences")
|
|
|
|
}?.let { result ->
|
2021-02-09 23:25:06 +01:00
|
|
|
val json = result.jsonObject
|
|
|
|
if (json == null) {
|
|
|
|
showToast(true, result.error)
|
2021-05-27 04:15:59 +02:00
|
|
|
return@let
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var bChanged = false
|
|
|
|
try {
|
2021-06-20 15:12:25 +02:00
|
|
|
loadingBusy = true
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
val tmpVisibility =
|
|
|
|
TootVisibility.parseMastodon(json.string("posting:default:visibility"))
|
|
|
|
if (tmpVisibility != null) {
|
|
|
|
bChanged = true
|
|
|
|
visibility = tmpVisibility
|
|
|
|
showVisibility()
|
|
|
|
}
|
|
|
|
|
|
|
|
val tmpDefaultSensitive = json.boolean("posting:default:sensitive")
|
|
|
|
if (tmpDefaultSensitive != null) {
|
|
|
|
bChanged = true
|
2023-01-17 13:42:47 +01:00
|
|
|
views.swMarkSensitive.isChecked = tmpDefaultSensitive
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
val tmpExpandMedia = json.string("reading:expand:media")
|
|
|
|
if (tmpExpandMedia?.isNotEmpty() == true) {
|
|
|
|
bChanged = true
|
2023-01-17 13:42:47 +01:00
|
|
|
views.swNSFWOpen.isChecked = (tmpExpandMedia == "show_all")
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
val tmpExpandCW = json.boolean("reading:expand:spoilers")
|
|
|
|
if (tmpExpandCW != null) {
|
|
|
|
bChanged = true
|
2023-01-17 13:42:47 +01:00
|
|
|
views.swExpandCW.isChecked = tmpExpandCW
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
} finally {
|
2021-06-20 15:12:25 +02:00
|
|
|
loadingBusy = false
|
2021-02-09 23:25:06 +01:00
|
|
|
if (bChanged) saveUIToData()
|
|
|
|
}
|
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////
|
2021-05-27 04:15:59 +02:00
|
|
|
|
2021-02-09 23:25:06 +01:00
|
|
|
private fun performAccountRemove() {
|
|
|
|
AlertDialog.Builder(this)
|
|
|
|
.setTitle(R.string.confirm)
|
|
|
|
.setMessage(R.string.confirm_account_remove)
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.setPositiveButton(R.string.ok) { _, _ ->
|
2023-02-04 21:52:26 +01:00
|
|
|
launchAndShowError {
|
|
|
|
authRepo.accountRemove(account)
|
|
|
|
finish()
|
|
|
|
}
|
|
|
|
}.show()
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////
|
|
|
|
private fun performAccessToken() {
|
2021-05-27 04:15:59 +02:00
|
|
|
launchMain {
|
2023-01-17 13:42:47 +01:00
|
|
|
try {
|
|
|
|
runApiTask2(account) { client ->
|
|
|
|
val authUrl = client.authStep1(forceUpdateClient = true)
|
|
|
|
withContext(AppDispatchers.MainImmediate) {
|
|
|
|
val resultIntent = Intent().apply { data = authUrl }
|
|
|
|
setResult(Activity.RESULT_OK, resultIntent)
|
2021-02-09 23:25:06 +01:00
|
|
|
finish()
|
|
|
|
}
|
|
|
|
}
|
2023-01-17 13:42:47 +01:00
|
|
|
} catch (ex: Throwable) {
|
|
|
|
showApiError(ex)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun inputAccessToken() {
|
|
|
|
|
|
|
|
val data = Intent()
|
|
|
|
data.putExtra(EXTRA_DB_ID, account.db_id)
|
|
|
|
setResult(RESULT_INPUT_ACCESS_TOKEN, data)
|
|
|
|
finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
private fun initializeProfile() {
|
|
|
|
// 初期状態
|
2021-06-20 15:12:25 +02:00
|
|
|
val questionId = R.drawable.wide_question
|
2021-02-09 23:25:06 +01:00
|
|
|
val loadingText = when (account.isPseudo) {
|
|
|
|
true -> "(disabled for pseudo account)"
|
|
|
|
else -> "(loading…)"
|
|
|
|
}
|
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
views.apply {
|
2021-11-21 08:12:10 +01:00
|
|
|
|
|
|
|
ivProfileAvatar.setErrorImage(defaultColorIcon(this@ActAccountSetting, questionId))
|
|
|
|
ivProfileAvatar.setDefaultImage(defaultColorIcon(this@ActAccountSetting, questionId))
|
|
|
|
|
|
|
|
etDisplayName.setText(loadingText)
|
|
|
|
etNote.setText(loadingText)
|
|
|
|
|
|
|
|
// 初期状態では編集不可能
|
|
|
|
arrayOf(
|
|
|
|
btnProfileAvatar,
|
|
|
|
btnProfileHeader,
|
|
|
|
etDisplayName,
|
|
|
|
btnDisplayName,
|
|
|
|
etNote,
|
|
|
|
btnNote,
|
|
|
|
cbLocked,
|
|
|
|
).forEach { it.isEnabledAlpha = false }
|
|
|
|
|
|
|
|
for (et in listEtFieldName) {
|
|
|
|
et.setText(loadingText)
|
|
|
|
et.isEnabledAlpha = false
|
|
|
|
}
|
|
|
|
for (et in listEtFieldValue) {
|
|
|
|
et.setText(loadingText)
|
|
|
|
et.isEnabledAlpha = false
|
|
|
|
}
|
|
|
|
|
|
|
|
// 疑似アカウントなら編集不可のまま
|
|
|
|
if (!account.isPseudo) loadProfile()
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
// サーバから情報をロードする
|
2021-02-09 23:25:06 +01:00
|
|
|
private fun loadProfile() {
|
2021-05-27 04:15:59 +02:00
|
|
|
launchMain {
|
2023-01-17 13:42:47 +01:00
|
|
|
try {
|
|
|
|
runApiTask2(account) { client ->
|
|
|
|
val json = if (account.isMisskey) {
|
|
|
|
val result = client.request(
|
|
|
|
"/api/i",
|
|
|
|
account.putMisskeyApiToken().toPostRequestBuilder()
|
|
|
|
) ?: return@runApiTask2
|
|
|
|
result.error?.let { error(it) }
|
|
|
|
result.jsonObject
|
|
|
|
} else {
|
|
|
|
// 承認待ち状態のチェック
|
2023-02-04 21:52:26 +01:00
|
|
|
authRepo.checkConfirmed(account, client)
|
2023-01-17 13:42:47 +01:00
|
|
|
|
|
|
|
val result = client.request(
|
|
|
|
"/api/v1/accounts/verify_credentials"
|
|
|
|
) ?: return@runApiTask2
|
|
|
|
result.error?.let { error(it) }
|
|
|
|
result.jsonObject
|
|
|
|
}
|
|
|
|
val newAccount = TootParser(this, account)
|
|
|
|
.account(json) ?: error("parse error.")
|
|
|
|
withContext(AppDispatchers.MainImmediate) {
|
|
|
|
showProfile(newAccount)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-17 13:42:47 +01:00
|
|
|
} catch (ex: Throwable) {
|
|
|
|
showApiError(ex)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2022-03-16 09:04:19 +01:00
|
|
|
private fun showProfile(src: TootAccount) {
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
if (isDestroyed) return
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
profileBusy = true
|
2021-02-09 23:25:06 +01:00
|
|
|
try {
|
2023-01-17 13:42:47 +01:00
|
|
|
views.ivProfileAvatar.setImageUrl(
|
|
|
|
calcIconRound(views.ivProfileAvatar.layoutParams),
|
2021-02-09 23:25:06 +01:00
|
|
|
src.avatar_static,
|
|
|
|
src.avatar
|
|
|
|
)
|
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
views.ivProfileHeader.setImageUrl(
|
2021-02-09 23:25:06 +01:00
|
|
|
0f,
|
|
|
|
src.header_static,
|
|
|
|
src.header
|
|
|
|
)
|
|
|
|
|
|
|
|
val decodeOptions = DecodeOptions(
|
|
|
|
context = this@ActAccountSetting,
|
|
|
|
linkHelper = account,
|
|
|
|
emojiMapProfile = src.profile_emojis,
|
|
|
|
emojiMapCustom = src.custom_emojis,
|
2022-05-30 22:30:52 +02:00
|
|
|
authorDomain = account,
|
2021-02-09 23:25:06 +01:00
|
|
|
)
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
val displayName = src.display_name
|
|
|
|
val name = decodeOptions.decodeEmoji(displayName)
|
2023-01-17 13:42:47 +01:00
|
|
|
views.etDisplayName.setText(name)
|
2021-06-20 15:12:25 +02:00
|
|
|
nameInvalidator.register(name)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
val noteString = src.source?.note ?: src.note
|
|
|
|
val noteSpannable = when {
|
|
|
|
account.isMisskey -> {
|
|
|
|
SpannableString(noteString ?: "")
|
|
|
|
}
|
|
|
|
|
|
|
|
else -> {
|
|
|
|
decodeOptions.decodeEmoji(noteString)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
views.etNote.setText(noteSpannable)
|
2021-06-20 15:12:25 +02:00
|
|
|
noteInvalidator.register(noteSpannable)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2023-01-17 13:42:47 +01:00
|
|
|
views.cbLocked.isChecked = src.locked
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
// 編集可能にする
|
2023-01-17 13:42:47 +01:00
|
|
|
views.apply {
|
2021-11-21 08:12:10 +01:00
|
|
|
arrayOf(
|
|
|
|
btnProfileAvatar,
|
|
|
|
btnProfileHeader,
|
|
|
|
etDisplayName,
|
|
|
|
btnDisplayName,
|
|
|
|
etNote,
|
|
|
|
btnNote,
|
|
|
|
cbLocked,
|
|
|
|
).forEach { it.isEnabledAlpha = true }
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
if (src.source?.fields != null) {
|
|
|
|
val fields = src.source.fields
|
|
|
|
listEtFieldName.forEachIndexed { i, et ->
|
|
|
|
val handler = et.handler // may null
|
|
|
|
if (handler != null) {
|
|
|
|
// いつからかfields name にもカスタム絵文字が使えるようになった
|
|
|
|
// https://github.com/tootsuite/mastodon/pull/11350
|
|
|
|
// しかし
|
|
|
|
val text = decodeOptions.decodeEmoji(
|
|
|
|
when {
|
|
|
|
i >= fields.size -> ""
|
|
|
|
else -> fields[i].name
|
|
|
|
}
|
|
|
|
)
|
|
|
|
et.setText(text)
|
2021-05-22 11:07:23 +02:00
|
|
|
et.isEnabledAlpha = true
|
2021-02-09 23:25:06 +01:00
|
|
|
val invalidator = NetworkEmojiInvalidator(handler, et)
|
|
|
|
invalidator.register(text)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
listEtFieldValue.forEachIndexed { i, et ->
|
|
|
|
val handler = et.handler // may null
|
|
|
|
if (handler != null) {
|
|
|
|
val text = decodeOptions.decodeEmoji(
|
|
|
|
when {
|
|
|
|
i >= fields.size -> ""
|
|
|
|
else -> fields[i].value
|
|
|
|
}
|
|
|
|
)
|
|
|
|
et.setText(text)
|
2021-05-22 11:07:23 +02:00
|
|
|
et.isEnabledAlpha = true
|
2021-02-09 23:25:06 +01:00
|
|
|
val invalidator = NetworkEmojiInvalidator(handler, et)
|
|
|
|
invalidator.register(text)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
val fields = src.fields
|
|
|
|
|
|
|
|
listEtFieldName.forEachIndexed { i, et ->
|
|
|
|
val handler = et.handler // may null
|
|
|
|
if (handler != null) {
|
|
|
|
// いつからかfields name にもカスタム絵文字が使えるようになった
|
|
|
|
// https://github.com/tootsuite/mastodon/pull/11350
|
|
|
|
val text = decodeOptions.decodeEmoji(
|
|
|
|
when {
|
|
|
|
fields == null || i >= fields.size -> ""
|
|
|
|
else -> fields[i].name
|
|
|
|
}
|
|
|
|
)
|
|
|
|
et.setText(text)
|
2021-05-22 11:07:23 +02:00
|
|
|
et.isEnabledAlpha = true
|
2021-02-09 23:25:06 +01:00
|
|
|
val invalidator = NetworkEmojiInvalidator(handler, et)
|
|
|
|
invalidator.register(text)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
listEtFieldValue.forEachIndexed { i, et ->
|
|
|
|
val handler = et.handler // may null
|
|
|
|
if (handler != null) {
|
|
|
|
val text = decodeOptions.decodeHTML(
|
|
|
|
when {
|
|
|
|
fields == null || i >= fields.size -> ""
|
|
|
|
else -> fields[i].value
|
|
|
|
}
|
|
|
|
)
|
|
|
|
et.text = text
|
2021-05-22 11:07:23 +02:00
|
|
|
et.isEnabledAlpha = true
|
2021-02-09 23:25:06 +01:00
|
|
|
val invalidator = NetworkEmojiInvalidator(handler, et)
|
|
|
|
invalidator.register(text)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
2021-06-20 15:12:25 +02:00
|
|
|
profileBusy = false
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun updateCredential(key: String, value: Any) {
|
|
|
|
updateCredential(listOf(Pair(key, value)))
|
|
|
|
}
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
private suspend fun uploadImageMisskey(
|
|
|
|
client: TootApiClient,
|
2021-06-20 15:12:25 +02:00
|
|
|
opener: InputStreamOpener,
|
2021-05-27 04:15:59 +02:00
|
|
|
): Pair<TootApiResult?, TootAttachment?> {
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
val size = getStreamSize(true, opener.open())
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
val multipartBuilder = MultipartBody.Builder()
|
2021-05-27 04:15:59 +02:00
|
|
|
.setType(MultipartBody.FORM)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
val apiKey =
|
2023-02-06 03:10:24 +01:00
|
|
|
account.tokenJson?.string(AuthBase.KEY_API_KEY_MISSKEY)
|
2021-05-27 04:15:59 +02:00
|
|
|
if (apiKey?.isNotEmpty() == true) {
|
2021-06-20 15:12:25 +02:00
|
|
|
multipartBuilder.addFormDataPart("i", apiKey)
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
multipartBuilder.addFormDataPart(
|
2021-05-27 04:15:59 +02:00
|
|
|
"file",
|
|
|
|
getDocumentName(contentResolver, opener.uri),
|
|
|
|
object : RequestBody() {
|
|
|
|
override fun contentType(): MediaType {
|
|
|
|
return opener.mimeType.toMediaType()
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
override fun contentLength(): Long {
|
|
|
|
return size
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
override fun writeTo(sink: BufferedSink) {
|
|
|
|
opener.open().use { inData ->
|
|
|
|
val tmp = ByteArray(4096)
|
|
|
|
while (true) {
|
|
|
|
val r = inData.read(tmp, 0, tmp.size)
|
|
|
|
if (r <= 0) break
|
|
|
|
sink.write(tmp, 0, r)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
|
|
|
)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
var ta: TootAttachment? = null
|
|
|
|
val result = client.request(
|
|
|
|
"/api/drive/files/create",
|
2021-06-20 15:12:25 +02:00
|
|
|
multipartBuilder.build().toPost()
|
2021-05-27 04:15:59 +02:00
|
|
|
)?.also { result ->
|
|
|
|
val jsonObject = result.jsonObject
|
|
|
|
if (jsonObject != null) {
|
|
|
|
ta = parseItem(::TootAttachment, ServiceType.MISSKEY, jsonObject)
|
|
|
|
if (ta == null) result.error = "TootAttachment.parse failed"
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
return Pair(result, ta)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun updateCredential(args: List<Pair<String, Any>>) {
|
|
|
|
launchMain {
|
|
|
|
var resultAccount: TootAccount? = null
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
runApiTask(account) { client ->
|
2021-02-09 23:25:06 +01:00
|
|
|
try {
|
|
|
|
if (account.isMisskey) {
|
|
|
|
val params = account.putMisskeyApiToken()
|
|
|
|
|
|
|
|
for (arg in args) {
|
|
|
|
val key = arg.first
|
|
|
|
val value = arg.second
|
|
|
|
|
|
|
|
val misskeyKey = when (key) {
|
|
|
|
"header" -> "bannerId"
|
|
|
|
"avatar" -> "avatarId"
|
|
|
|
"display_name" -> "name"
|
|
|
|
"note" -> "description"
|
|
|
|
"locked" -> "isLocked"
|
2021-06-20 15:12:25 +02:00
|
|
|
else -> return@runApiTask TootApiResult("Misskey does not support property '$key'")
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
when (value) {
|
|
|
|
is String -> params[misskeyKey] = value
|
|
|
|
is Boolean -> params[misskeyKey] = value
|
|
|
|
|
|
|
|
is InputStreamOpener -> {
|
|
|
|
val (result, ta) = uploadImageMisskey(client, value)
|
2021-05-27 04:15:59 +02:00
|
|
|
ta ?: return@runApiTask result
|
2021-02-09 23:25:06 +01:00
|
|
|
params[misskeyKey] = ta.id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
client.request("/api/i/update", params.toPostRequestBuilder())
|
|
|
|
?.also { result ->
|
|
|
|
result.jsonObject?.let {
|
|
|
|
resultAccount = TootParser(this, account).account(it)
|
|
|
|
?: return@runApiTask TootApiResult("TootAccount parse failed.")
|
|
|
|
}
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
} else {
|
2021-06-20 15:12:25 +02:00
|
|
|
val multipartBodyBuilder = MultipartBody.Builder()
|
2021-02-09 23:25:06 +01:00
|
|
|
.setType(MultipartBody.FORM)
|
|
|
|
|
|
|
|
for (arg in args) {
|
|
|
|
val key = arg.first
|
|
|
|
val value = arg.second
|
|
|
|
|
|
|
|
if (value is String) {
|
2021-06-20 15:12:25 +02:00
|
|
|
multipartBodyBuilder.addFormDataPart(key, value)
|
2021-02-09 23:25:06 +01:00
|
|
|
} else if (value is Boolean) {
|
2021-06-20 15:12:25 +02:00
|
|
|
multipartBodyBuilder.addFormDataPart(
|
2021-02-09 23:25:06 +01:00
|
|
|
key,
|
|
|
|
if (value) "true" else "false"
|
|
|
|
)
|
|
|
|
} else if (value is InputStreamOpener) {
|
|
|
|
|
|
|
|
val fileName = "%x".format(System.currentTimeMillis())
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
multipartBodyBuilder.addFormDataPart(
|
2021-02-09 23:25:06 +01:00
|
|
|
key,
|
|
|
|
fileName,
|
|
|
|
object : RequestBody() {
|
2021-05-22 00:03:16 +02:00
|
|
|
override fun contentType(): MediaType =
|
|
|
|
value.mimeType.toMediaType()
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
override fun writeTo(sink: BufferedSink) {
|
|
|
|
value.open().use { inData ->
|
|
|
|
val tmp = ByteArray(4096)
|
|
|
|
while (true) {
|
|
|
|
val r = inData.read(tmp, 0, tmp.size)
|
|
|
|
if (r <= 0) break
|
|
|
|
sink.write(tmp, 0, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-04 20:35:07 +02:00
|
|
|
}
|
|
|
|
)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
client.request(
|
2021-02-09 23:25:06 +01:00
|
|
|
"/api/v1/accounts/update_credentials",
|
2021-06-20 15:12:25 +02:00
|
|
|
multipartBodyBuilder.build().toPatch()
|
2021-05-27 04:15:59 +02:00
|
|
|
)?.also { result ->
|
|
|
|
result.jsonObject?.let {
|
2021-11-20 01:36:43 +01:00
|
|
|
resultAccount =
|
|
|
|
TootParser(this@ActAccountSetting, account).account(it)
|
|
|
|
?: return@runApiTask TootApiResult("TootAccount parse failed.")
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
for (arg in args) {
|
|
|
|
val value = arg.second
|
|
|
|
(value as? InputStreamOpener)?.deleteTempFile()
|
|
|
|
}
|
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
}?.let { result ->
|
|
|
|
val data = resultAccount
|
2021-02-09 23:25:06 +01:00
|
|
|
if (data != null) {
|
|
|
|
showProfile(data)
|
|
|
|
} else {
|
|
|
|
showToast(true, result.error)
|
|
|
|
for (arg in args) {
|
|
|
|
val key = arg.first
|
|
|
|
val value = arg.second
|
|
|
|
if (key == "locked" && value is Boolean) {
|
2021-06-20 15:12:25 +02:00
|
|
|
profileBusy = true
|
2023-01-17 13:42:47 +01:00
|
|
|
views.cbLocked.isChecked = !value
|
2021-06-20 15:12:25 +02:00
|
|
|
profileBusy = false
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun sendDisplayName(bConfirmed: Boolean = false) {
|
2023-01-17 13:42:47 +01:00
|
|
|
val sv = views.etDisplayName.text.toString()
|
2021-02-09 23:25:06 +01:00
|
|
|
if (!bConfirmed) {
|
|
|
|
val length = sv.codePointCount(0, sv.length)
|
|
|
|
if (length > max_length_display_name) {
|
|
|
|
AlertDialog.Builder(this)
|
|
|
|
.setMessage(
|
|
|
|
getString(
|
|
|
|
R.string.length_warning,
|
|
|
|
getString(R.string.display_name),
|
|
|
|
length,
|
|
|
|
max_length_display_name
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.setPositiveButton(R.string.ok) { _, _ -> sendDisplayName(bConfirmed = true) }
|
|
|
|
.setCancelable(true)
|
|
|
|
.show()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateCredential("display_name", EmojiDecoder.decodeShortCode(sv))
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun sendNote(bConfirmed: Boolean = false) {
|
2023-01-17 13:42:47 +01:00
|
|
|
val sv = views.etNote.text.toString()
|
2021-02-09 23:25:06 +01:00
|
|
|
if (!bConfirmed) {
|
|
|
|
|
|
|
|
val length = TootAccount.countText(sv)
|
|
|
|
if (length > max_length_note) {
|
|
|
|
AlertDialog.Builder(this)
|
|
|
|
.setMessage(
|
|
|
|
getString(
|
|
|
|
R.string.length_warning,
|
|
|
|
getString(R.string.note),
|
|
|
|
length,
|
|
|
|
max_length_note
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.setPositiveButton(R.string.ok) { _, _ -> sendNote(bConfirmed = true) }
|
|
|
|
.setCancelable(true)
|
|
|
|
.show()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateCredential("note", EmojiDecoder.decodeShortCode(sv))
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun sendLocked(willLocked: Boolean) {
|
|
|
|
updateCredential("locked", willLocked)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun sendFields(bConfirmed: Boolean = false) {
|
|
|
|
val args = ArrayList<Pair<String, String>>()
|
|
|
|
var lengthLongest = -1
|
|
|
|
for (i in listEtFieldName.indices) {
|
|
|
|
val k = listEtFieldName[i].text.toString().trim()
|
|
|
|
val v = listEtFieldValue[i].text.toString().trim()
|
|
|
|
args.add(Pair("fields_attributes[$i][name]", k))
|
|
|
|
args.add(Pair("fields_attributes[$i][value]", v))
|
|
|
|
|
|
|
|
lengthLongest = max(
|
|
|
|
lengthLongest,
|
|
|
|
max(
|
|
|
|
k.codePointCount(0, k.length),
|
|
|
|
v.codePointCount(0, v.length)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (!bConfirmed && lengthLongest > max_length_fields) {
|
|
|
|
AlertDialog.Builder(this)
|
|
|
|
.setMessage(
|
|
|
|
getString(
|
|
|
|
R.string.length_warning,
|
|
|
|
getString(R.string.profile_metadata),
|
|
|
|
lengthLongest,
|
|
|
|
max_length_fields
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.setPositiveButton(R.string.ok) { _, _ -> sendFields(bConfirmed = true) }
|
|
|
|
.setCancelable(true)
|
|
|
|
.show()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
updateCredential(args)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun pickAvatarImage() {
|
2022-08-06 00:52:31 +02:00
|
|
|
openPicker(prPickAvater)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun pickHeaderImage() {
|
2022-08-06 00:52:31 +02:00
|
|
|
openPicker(prPickHeader)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2022-08-06 00:52:31 +02:00
|
|
|
private fun openPicker(permissionRequester: PermissionRequester) {
|
2023-02-04 21:52:26 +01:00
|
|
|
launchAndShowError {
|
|
|
|
if (!permissionRequester.checkOrLaunch()) return@launchAndShowError
|
|
|
|
val propName = when (permissionRequester) {
|
|
|
|
prPickHeader -> "header"
|
|
|
|
else -> "avatar"
|
|
|
|
}
|
|
|
|
actionsDialog {
|
|
|
|
action(getString(R.string.pick_image)) {
|
|
|
|
performAttachment(propName)
|
|
|
|
}
|
|
|
|
action(getString(R.string.image_capture)) {
|
|
|
|
performCamera(propName)
|
|
|
|
}
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
private fun performAttachment(propName: String) {
|
2021-02-09 23:25:06 +01:00
|
|
|
try {
|
2021-05-22 00:03:16 +02:00
|
|
|
state.propName = propName
|
2021-02-09 23:25:06 +01:00
|
|
|
val intent = intentGetContent(false, getString(R.string.pick_image), arrayOf("image/*"))
|
2021-05-22 00:03:16 +02:00
|
|
|
arAddAttachment.launch(intent)
|
2021-02-09 23:25:06 +01:00
|
|
|
} catch (ex: Throwable) {
|
2022-12-27 03:54:52 +01:00
|
|
|
log.e(ex, "performAttachment failed.")
|
2021-02-09 23:25:06 +01:00
|
|
|
showToast(ex, "performAttachment failed.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
private fun performCamera(propName: String) {
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
// カメラで撮影
|
|
|
|
val filename = System.currentTimeMillis().toString() + ".jpg"
|
|
|
|
val values = ContentValues()
|
|
|
|
values.put(MediaStore.Images.Media.TITLE, filename)
|
|
|
|
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
2021-05-22 11:07:23 +02:00
|
|
|
val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
|
|
|
|
state.uriCameraImage = uri
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
|
2021-05-22 11:07:23 +02:00
|
|
|
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-05-22 00:03:16 +02:00
|
|
|
state.propName = propName
|
|
|
|
arCameraImage.launch(intent)
|
2021-02-09 23:25:06 +01:00
|
|
|
} catch (ex: Throwable) {
|
2022-12-27 03:54:52 +01:00
|
|
|
log.e(ex, "opening camera app failed.")
|
2021-02-09 23:25:06 +01:00
|
|
|
showToast(ex, "opening camera app failed.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal interface InputStreamOpener {
|
|
|
|
val mimeType: String
|
|
|
|
val uri: Uri
|
|
|
|
fun open(): InputStream
|
|
|
|
fun deleteTempFile()
|
|
|
|
}
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
private fun createOpener(uriArg: Uri, mimeType: String): InputStreamOpener {
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
try {
|
|
|
|
|
|
|
|
// 画像の種別
|
2021-06-20 15:12:25 +02:00
|
|
|
val isJpeg = MIME_TYPE_JPEG == mimeType
|
|
|
|
val isPng = MIME_TYPE_PNG == mimeType
|
|
|
|
if (!isJpeg && !isPng) {
|
2021-02-09 23:25:06 +01:00
|
|
|
log.d("createOpener: source is not jpeg or png")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// 設定からリサイズ指定を読む
|
2021-06-20 15:12:25 +02:00
|
|
|
val resizeTo = 1280
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
val bitmap = createResizedBitmap(this, uriArg, resizeTo)
|
2021-02-09 23:25:06 +01:00
|
|
|
if (bitmap != null) {
|
|
|
|
try {
|
2022-01-05 10:39:48 +01:00
|
|
|
val cacheDir = externalCacheDir?.apply { mkdirs() }
|
2021-06-20 15:12:25 +02:00
|
|
|
if (cacheDir == null) {
|
2021-02-09 23:25:06 +01:00
|
|
|
showToast(false, "getExternalCacheDir returns null.")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
val tempFile = File(
|
|
|
|
cacheDir,
|
2021-02-09 23:25:06 +01:00
|
|
|
"tmp." + System.currentTimeMillis() + "." + Thread.currentThread().id
|
|
|
|
)
|
2021-06-20 15:12:25 +02:00
|
|
|
FileOutputStream(tempFile).use { os ->
|
|
|
|
if (isJpeg) {
|
2021-02-09 23:25:06 +01:00
|
|
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 95, os)
|
|
|
|
} else {
|
|
|
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, os)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return object : InputStreamOpener {
|
|
|
|
|
|
|
|
override val mimeType: String
|
2021-06-20 15:12:25 +02:00
|
|
|
get() = mimeType
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
override val uri: Uri
|
|
|
|
get() = uriArg
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
override fun open() = FileInputStream(tempFile)
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
override fun deleteTempFile() {
|
2021-06-20 15:12:25 +02:00
|
|
|
tempFile.delete()
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
bitmap.recycle()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (ex: Throwable) {
|
2022-12-27 03:54:52 +01:00
|
|
|
log.e(ex, "Resizing image failed.")
|
2021-02-09 23:25:06 +01:00
|
|
|
showToast(ex, "Resizing image failed.")
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
return object : InputStreamOpener {
|
|
|
|
|
|
|
|
override val mimeType: String
|
2021-06-20 15:12:25 +02:00
|
|
|
get() = mimeType
|
2021-02-09 23:25:06 +01:00
|
|
|
|
|
|
|
override val uri: Uri
|
|
|
|
get() = uriArg
|
|
|
|
|
|
|
|
override fun open(): InputStream {
|
|
|
|
return contentResolver.openInputStream(uri) ?: error("openInputStream returns null")
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun deleteTempFile() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-05 04:37:40 +01:00
|
|
|
private fun uploadImage(propName: String, uri: Uri, mimeType: String?) {
|
2021-02-09 23:25:06 +01:00
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
if (mimeType == null) {
|
2021-02-09 23:25:06 +01:00
|
|
|
showToast(false, "mime type is not provided.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
if (!mimeType.startsWith("image/")) {
|
2021-02-09 23:25:06 +01:00
|
|
|
showToast(false, "mime type is not image.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-07-20 06:27:19 +02:00
|
|
|
launchProgress(
|
|
|
|
"preparing image",
|
|
|
|
doInBackground = { createOpener(uri, mimeType) },
|
|
|
|
afterProc = { updateCredential(propName, it) }
|
|
|
|
)
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
private fun updatePushSubscription(force: Boolean) {
|
2023-02-04 21:52:26 +01:00
|
|
|
val activity = this
|
|
|
|
launchAndShowError {
|
2023-02-06 03:10:24 +01:00
|
|
|
val anyNotificationWanted = account.notificationBoost ||
|
|
|
|
account.notificationFavourite ||
|
|
|
|
account.notificationFollow ||
|
|
|
|
account.notificationMention ||
|
|
|
|
account.notificationReaction ||
|
|
|
|
account.notificationVote ||
|
|
|
|
account.notificationFollowRequest ||
|
|
|
|
account.notificationPost ||
|
|
|
|
account.notificationUpdate
|
2023-02-04 21:52:26 +01:00
|
|
|
|
|
|
|
val lines = ArrayList<String>()
|
|
|
|
val subLogger = object : PushBase.SubscriptionLogger {
|
|
|
|
override val context: Context
|
|
|
|
get() = activity
|
|
|
|
|
|
|
|
override fun i(msg: String) {
|
|
|
|
log.w(msg)
|
|
|
|
synchronized(lines) {
|
|
|
|
lines.add(msg)
|
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
2023-02-04 21:52:26 +01:00
|
|
|
|
|
|
|
override fun e(msg: String) {
|
|
|
|
log.e(msg)
|
|
|
|
synchronized(lines) {
|
|
|
|
lines.add(msg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun e(ex: Throwable, msg: String) {
|
|
|
|
log.e(ex, msg)
|
|
|
|
synchronized(lines) {
|
|
|
|
lines.add(ex.withCaption(msg))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
pushRepo.updateSubscription(
|
|
|
|
subLogger,
|
|
|
|
account,
|
|
|
|
willRemoveSubscription = !anyNotificationWanted,
|
2023-02-05 16:44:28 +01:00
|
|
|
forceUpdate = force,
|
2023-02-04 21:52:26 +01:00
|
|
|
)
|
|
|
|
} catch (ex: Throwable) {
|
|
|
|
subLogger.e(ex, "updateSubscription failed.")
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
2023-02-04 21:52:26 +01:00
|
|
|
AlertDialog.Builder(activity)
|
|
|
|
.setMessage("${account.acct}:\n${lines.joinToString("\n")}")
|
|
|
|
.setPositiveButton(android.R.string.ok, null)
|
|
|
|
.show()
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
2021-02-09 23:25:06 +01:00
|
|
|
}
|
2018-01-04 19:52:25 +01:00
|
|
|
}
|