SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/ActColumnCustomize.kt

457 lines
16 KiB
Kotlin
Raw Normal View History

package jp.juggler.subwaytooter
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
2021-11-20 13:16:56 +01:00
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.ImageView
import android.widget.SeekBar
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import com.jrummyapps.android.colorpicker.ColorPickerDialog
import com.jrummyapps.android.colorpicker.ColorPickerDialogListener
import jp.juggler.subwaytooter.api.TootApiResult
import jp.juggler.subwaytooter.api.runApiTask
2021-06-28 09:09:00 +02:00
import jp.juggler.subwaytooter.column.*
import jp.juggler.subwaytooter.databinding.ActColumnCustomizeBinding
import jp.juggler.util.backPressed
import jp.juggler.util.coroutine.launchMain
import jp.juggler.util.data.*
import jp.juggler.util.int
import jp.juggler.util.log.LogCategory
import jp.juggler.util.log.showToast
import jp.juggler.util.log.withCaption
import jp.juggler.util.media.createResizedBitmap
import jp.juggler.util.ui.ActivityResultHandler
import jp.juggler.util.ui.hideKeyboard
import jp.juggler.util.ui.isNotOk
import jp.juggler.util.ui.setNavigationBack
import org.jetbrains.anko.textColor
import java.io.File
import java.io.FileOutputStream
import java.text.NumberFormat
import kotlin.math.max
class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPickerDialogListener {
2020-10-24 14:55:51 +02:00
companion object {
internal val log = LogCategory("ActColumnCustomize")
internal const val EXTRA_COLUMN_INDEX = "column_index"
internal const val COLOR_DIALOG_ID_HEADER_BACKGROUND = 1
internal const val COLOR_DIALOG_ID_HEADER_FOREGROUND = 2
internal const val COLOR_DIALOG_ID_COLUMN_BACKGROUND = 3
internal const val COLOR_DIALOG_ID_ACCT_TEXT = 4
internal const val COLOR_DIALOG_ID_CONTENT_TEXT = 5
internal const val PROGRESS_MAX = 65536
fun createIntent(activity: ActMain, idx: Int) =
Intent(activity, ActColumnCustomize::class.java).apply {
putExtra(EXTRA_COLUMN_INDEX, idx)
}
2020-10-24 14:55:51 +02:00
}
private var columnIndex: Int = 0
2020-10-24 14:55:51 +02:00
internal lateinit var column: Column
internal lateinit var appState: AppState
2020-10-24 14:55:51 +02:00
internal var density: Float = 0f
private val views by lazy {
ActColumnCustomizeBinding.inflate(layoutInflater)
}
2020-10-24 14:55:51 +02:00
internal var loadingBusy: Boolean = false
2020-10-24 14:55:51 +02:00
private var lastImageUri: String? = null
private var lastImageBitmap: Bitmap? = null
2020-10-24 14:55:51 +02:00
private val arColumnBackgroundImage = ActivityResultHandler(log) { r ->
if (r.isNotOk) return@ActivityResultHandler
r.data?.handleGetContentResult(contentResolver)
?.firstOrNull()?.uri?.let { updateBackground(it) }
}
2020-10-24 14:55:51 +02:00
private fun makeResult() {
val data = Intent()
data.putExtra(EXTRA_COLUMN_INDEX, columnIndex)
2020-10-24 14:55:51 +02:00
setResult(RESULT_OK, data)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
2022-09-10 23:09:26 +02:00
backPressed {
makeResult()
finish()
}
arColumnBackgroundImage.register(this)
2020-10-24 14:55:51 +02:00
App1.setActivityTheme(this)
initUI()
appState = App1.getAppState(this)
density = appState.density
columnIndex = intent.int(EXTRA_COLUMN_INDEX) ?: 0
column = appState.column(columnIndex)!!
2020-10-24 14:55:51 +02:00
show()
}
override fun onDestroy() {
closeBitmaps()
super.onDestroy()
}
override fun onClick(v: View) {
val builder: ColorPickerDialog.Builder
when (v.id) {
R.id.btnHeaderBackgroundEdit -> {
ColorPickerDialog.newBuilder()
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setAllowPresets(true)
.setShowAlphaSlider(false)
.setDialogId(COLOR_DIALOG_ID_HEADER_BACKGROUND)
.setColor(column.getHeaderBackgroundColor())
.show(this)
}
R.id.btnHeaderBackgroundReset -> {
column.headerBgColor = 0
show()
}
R.id.btnHeaderTextEdit -> {
ColorPickerDialog.newBuilder()
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setAllowPresets(true)
.setShowAlphaSlider(false)
.setDialogId(COLOR_DIALOG_ID_HEADER_FOREGROUND)
.setColor(column.getHeaderNameColor())
.show(this)
}
R.id.btnHeaderTextReset -> {
column.headerFgColor = 0
show()
}
R.id.btnColumnBackgroundColor -> {
builder = ColorPickerDialog.newBuilder()
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setAllowPresets(true)
.setShowAlphaSlider(false)
.setDialogId(COLOR_DIALOG_ID_COLUMN_BACKGROUND)
if (column.columnBgColor != 0) builder.setColor(column.columnBgColor)
builder.show(this)
}
R.id.btnColumnBackgroundColorReset -> {
column.columnBgColor = 0
show()
}
R.id.btnAcctColor -> {
ColorPickerDialog.newBuilder()
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setAllowPresets(true)
.setShowAlphaSlider(true)
.setDialogId(COLOR_DIALOG_ID_ACCT_TEXT)
.setColor(column.getAcctColor())
.show(this)
}
R.id.btnAcctColorReset -> {
column.acctColor = 0
show()
}
R.id.btnContentColor -> {
ColorPickerDialog.newBuilder()
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setAllowPresets(true)
.setShowAlphaSlider(true)
.setDialogId(COLOR_DIALOG_ID_CONTENT_TEXT)
.setColor(column.getContentColor())
.show(this)
}
R.id.btnContentColorReset -> {
column.contentColor = 0
show()
}
R.id.btnColumnBackgroundImage -> {
val intent = intentGetContent(
false,
getString(R.string.pick_image),
arrayOf("image/*")
)
arColumnBackgroundImage.launch(intent)
}
R.id.btnColumnBackgroundImageReset -> {
column.columnBgImage = ""
show()
}
2020-10-24 14:55:51 +02:00
}
}
2021-11-20 13:16:56 +01:00
override fun onColorSelected(dialogId: Int, @ColorInt newColor: Int) {
2020-10-24 14:55:51 +02:00
when (dialogId) {
2021-11-20 13:16:56 +01:00
COLOR_DIALOG_ID_HEADER_BACKGROUND ->
column.headerBgColor = Color.BLACK or newColor
2021-11-20 13:16:56 +01:00
COLOR_DIALOG_ID_HEADER_FOREGROUND ->
column.headerFgColor = Color.BLACK or newColor
COLOR_DIALOG_ID_COLUMN_BACKGROUND ->
column.columnBgColor = Color.BLACK or newColor
COLOR_DIALOG_ID_ACCT_TEXT ->
column.acctColor = newColor.notZero() ?: 1
COLOR_DIALOG_ID_CONTENT_TEXT ->
column.contentColor = newColor.notZero() ?: 1
2020-10-24 14:55:51 +02:00
}
show()
}
override fun onDialogDismissed(dialogId: Int) {}
private fun updateBackground(uriArg: Uri) {
launchMain {
var resultUri: String? = null
runApiTask { client ->
try {
val backgroundDir = getBackgroundImageDir(this@ActColumnCustomize)
2021-11-20 13:16:56 +01:00
val file =
File(backgroundDir, "${column.columnId}:${System.currentTimeMillis()}")
val fileUri = Uri.fromFile(file)
client.publishApiProgress("loading image from $uriArg")
2022-03-13 13:05:54 +01:00
contentResolver.openInputStream(uriArg)?.use { inStream ->
FileOutputStream(file).use { outStream ->
2022-03-13 13:05:54 +01:00
inStream.copyTo(outStream)
}
}
// リサイズや回転が必要ならする
client.publishApiProgress("check resize/rotation…")
val size = (max(
resources.displayMetrics.widthPixels,
resources.displayMetrics.heightPixels
) * 1.5f).toInt()
val bitmap = createResizedBitmap(
this,
fileUri,
size,
skipIfNoNeedToResizeAndRotate = true,
)
if (bitmap != null) {
try {
client.publishApiProgress("save resized(${bitmap.width}x${bitmap.height}) image to $file")
FileOutputStream(file).use { os ->
bitmap.compress(Bitmap.CompressFormat.PNG, 100, os)
}
} finally {
bitmap.recycle()
}
}
resultUri = fileUri.toString()
TootApiResult()
} catch (ex: Throwable) {
log.e(ex, "can't update background image.")
TootApiResult(ex.withCaption("can't update background image."))
}
}?.let { result ->
when (val bgUri = resultUri) {
null -> showToast(true, result.error ?: "?")
else -> {
column.columnBgImage = bgUri
show()
}
}
}
}
2020-10-24 14:55:51 +02:00
}
private fun initUI() {
setContentView(views.root)
setSupportActionBar(views.toolbar)
setNavigationBack(views.toolbar)
fixHorizontalMargin(views.svContent)
arrayOf(
views.btnHeaderBackgroundEdit,
views.btnHeaderBackgroundReset,
views.btnHeaderTextEdit,
views.btnHeaderTextReset,
views.btnColumnBackgroundColor,
views.btnColumnBackgroundColorReset,
views.btnColumnBackgroundImage,
views.btnColumnBackgroundImageReset,
views.btnAcctColor,
views.btnAcctColorReset,
views.btnContentColor,
views.btnContentColorReset,
).forEach {
it.setOnClickListener(this)
}
views.sbColumnBackgroundAlpha.max = PROGRESS_MAX
views.sbColumnBackgroundAlpha.setOnSeekBarChangeListener(object :
2021-11-20 13:16:56 +01:00
SeekBar.OnSeekBarChangeListener {
override fun onStartTrackingTouch(seekBar: SeekBar) {}
2020-10-24 14:55:51 +02:00
override fun onStopTrackingTouch(seekBar: SeekBar) {}
2020-10-24 14:55:51 +02:00
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (loadingBusy) return
if (!fromUser) return
column.columnBgImageAlpha = progress / PROGRESS_MAX.toFloat()
views.ivColumnBackground.alpha = column.columnBgImageAlpha
views.etAlpha.setText(
String.format(
defaultLocale(this@ActColumnCustomize),
"%.4f",
column.columnBgImageAlpha
)
)
}
})
2020-10-24 14:55:51 +02:00
views.etAlpha.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
2020-10-24 14:55:51 +02:00
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
2020-10-24 14:55:51 +02:00
override fun afterTextChanged(s: Editable) {
if (loadingBusy) return
try {
2020-10-24 14:55:51 +02:00
var f = NumberFormat.getInstance(defaultLocale(this@ActColumnCustomize))
.parse(views.etAlpha.text.toString())?.toFloat()
2020-10-24 14:55:51 +02:00
if (f != null && !f.isNaN()) {
if (f < 0f) f = 0f
if (f > 1f) f = 1f
column.columnBgImageAlpha = f
views.ivColumnBackground.alpha = column.columnBgImageAlpha
views.sbColumnBackgroundAlpha.progress = (0.5f + f * PROGRESS_MAX).toInt()
}
} catch (ex: Throwable) {
log.e(ex, "alpha parse failed.")
}
}
})
2020-10-24 14:55:51 +02:00
views.etAlpha.setOnEditorActionListener { _, actionId, _ ->
2020-10-24 14:55:51 +02:00
when (actionId) {
EditorInfo.IME_ACTION_DONE -> {
views.etAlpha.hideKeyboard()
true
}
2020-10-24 14:55:51 +02:00
else -> false
}
}
}
private fun show() {
try {
loadingBusy = true
2020-10-24 14:55:51 +02:00
column.setHeaderBackground(views.llColumnHeader)
2020-10-24 14:55:51 +02:00
val c = column.getHeaderNameColor()
views.tvColumnName.textColor = c
views.ivColumnHeader.setImageResource(column.getIconId())
views.ivColumnHeader.imageTintList = ColorStateList.valueOf(c)
2020-10-24 14:55:51 +02:00
views.tvColumnName.text = column.getColumnName(false)
2020-10-24 14:55:51 +02:00
if (column.columnBgColor != 0) {
views.flColumnBackground.setBackgroundColor(column.columnBgColor)
2020-10-24 14:55:51 +02:00
} else {
ViewCompat.setBackground(views.flColumnBackground, null)
2020-10-24 14:55:51 +02:00
}
var alpha = column.columnBgImageAlpha
2020-10-24 14:55:51 +02:00
if (alpha.isNaN()) {
alpha = 1f
column.columnBgImageAlpha = alpha
2020-10-24 14:55:51 +02:00
}
views.ivColumnBackground.alpha = alpha
views.sbColumnBackgroundAlpha.progress = (0.5f + alpha * PROGRESS_MAX).toInt()
2020-10-24 14:55:51 +02:00
views.etAlpha.setText(
String.format(
defaultLocale(this@ActColumnCustomize),
"%.4f",
column.columnBgImageAlpha
)
)
2020-10-24 14:55:51 +02:00
loadImage(views.ivColumnBackground, column.columnBgImage)
2020-10-24 14:55:51 +02:00
views.tvSampleAcct.setTextColor(column.getAcctColor())
views.tvSampleContent.setTextColor(column.getContentColor())
2020-10-24 14:55:51 +02:00
} finally {
loadingBusy = false
2020-10-24 14:55:51 +02:00
}
}
private fun closeBitmaps() {
try {
views.ivColumnBackground.setImageDrawable(null)
lastImageUri = null
2020-10-24 14:55:51 +02:00
lastImageBitmap?.recycle()
lastImageBitmap = null
2020-10-24 14:55:51 +02:00
} catch (ex: Throwable) {
log.e(ex, "closeBitmaps failed.")
2020-10-24 14:55:51 +02:00
}
}
private fun loadImage(ivColumnBackground: ImageView, url: String) {
try {
if (url.isEmpty()) {
closeBitmaps()
return
} else if (url == lastImageUri) {
2020-10-24 14:55:51 +02:00
// 今表示してるのと同じ
return
}
// 直前のBitmapを掃除する
closeBitmaps()
val uri = url.mayUri() ?: return
// 画像をロードして、成功したら表示してURLを覚える
val resizeMax = (0.5f + 64f * density).toInt()
lastImageBitmap = createResizedBitmap(this, uri, resizeMax)
if (lastImageBitmap != null) {
ivColumnBackground.setImageBitmap(lastImageBitmap)
lastImageUri = url
2020-10-24 14:55:51 +02:00
}
} catch (ex: Throwable) {
log.e(ex, "loadImage failed.")
2020-10-24 14:55:51 +02:00
}
}
}