diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActColumnCustomize.kt b/app/src/main/java/jp/juggler/subwaytooter/ActColumnCustomize.kt index c861a439..280c0dae 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActColumnCustomize.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActColumnCustomize.kt @@ -1,6 +1,5 @@ package jp.juggler.subwaytooter -import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.net.Uri @@ -18,6 +17,10 @@ import android.widget.TextView import com.jrummyapps.android.colorpicker.ColorPickerDialog import com.jrummyapps.android.colorpicker.ColorPickerDialogListener +import jp.juggler.subwaytooter.api.TootApiClient +import jp.juggler.subwaytooter.api.TootApiResult +import jp.juggler.subwaytooter.api.TootTask +import jp.juggler.subwaytooter.api.TootTaskRunner import jp.juggler.subwaytooter.util.* import org.apache.commons.io.IOUtils import java.io.File @@ -25,6 +28,7 @@ import java.io.FileOutputStream import java.text.NumberFormat import java.util.Locale +import kotlin.math.max class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPickerDialogListener { @@ -183,7 +187,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke } R.id.btnColumnBackgroundImage -> { - val intent = intentOpenDocument("image/*") + val intent = intentGetContent(false, getString(R.string.pick_image), "image/*") startActivityForResult(intent, REQUEST_CODE_PICK_BACKGROUND) } @@ -221,24 +225,76 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) { if(requestCode == REQUEST_CODE_PICK_BACKGROUND && data != null && resultCode == RESULT_OK) { - data.handleGetContentResult(contentResolver).firstOrNull()?.let { pair-> - try{ - val backgroundDir = getDir(Column.DIR_BACKGROUND_IMAGE, Context.MODE_PRIVATE) - val file = File(backgroundDir,column.column_id) - FileOutputStream(file).use{ outStream-> - contentResolver.openInputStream(pair.first).use{ inStream-> - IOUtils.copy(inStream,outStream) - } - } - column.column_bg_image = Uri.fromFile(file).toString() - show() - }catch(ex:Throwable){ - showToast(this@ActColumnCustomize,true,ex.withCaption("can't update background image.")) - } + data.handleGetContentResult(contentResolver).firstOrNull()?.let { pair -> + updateBackground(pair.first) } } } + private fun updateBackground(uriArg : Uri) { + TootTaskRunner(this).run(object : TootTask { + override fun background(client : TootApiClient) : TootApiResult? { + try { + val backgroundDir = Column.getBackgroundImageDir(this@ActColumnCustomize) + val file = + File(backgroundDir, "${column.column_id}:${System.currentTimeMillis()}") + val fileUri = Uri.fromFile(file) + + client.publishApiProgress("loading image from ${uriArg}") + contentResolver.openInputStream(uriArg).use { inStream -> + FileOutputStream(file).use { outStream -> + IOUtils.copy(inStream, outStream) + } + } + + // リサイズや回転が必要ならする + client.publishApiProgress("check resize/rotation…") + + val size = (max( + resources.displayMetrics.widthPixels, + resources.displayMetrics.heightPixels + ) * 1.5f ).toInt() + + val bitmap = createResizedBitmap( + this@ActColumnCustomize, + 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() + } + } + + val result = TootApiResult() + result.data = fileUri.toString() + return result + } catch(ex : Throwable) { + log.trace(ex) + return TootApiResult(ex.withCaption("can't update background image.")) + } + } + + override fun handleResult(result : TootApiResult?) { + when { + result == null -> return + result.error != null -> showToast(this@ActColumnCustomize, true, result.error) + + else -> { + column.column_bg_image = result.data as String + show() + } + } + } + }) + } + private fun initUI() { setContentView(R.layout.act_column_customize) @@ -443,7 +499,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke // 画像をロードして、成功したら表示してURLを覚える val resize_max = (0.5f + 64f * density).toInt() val uri = Uri.parse(url) - last_image_bitmap = createResizedBitmap( this, uri, resize_max ) + last_image_bitmap = createResizedBitmap(this, uri, resize_max) if(last_image_bitmap != null) { ivColumnBackground.setImageBitmap(last_image_bitmap) last_image_uri = url diff --git a/app/src/main/java/jp/juggler/subwaytooter/AppState.kt b/app/src/main/java/jp/juggler/subwaytooter/AppState.kt index 792c349f..e1005211 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/AppState.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/AppState.kt @@ -225,7 +225,7 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere } - internal fun restartTTS() { + fun restartTTS() { log.d("restart TextToSpeech") tts?.shutdown() tts = null @@ -280,11 +280,13 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere enableSpeech() // 背景フォルダの掃除 - val backgroundDir = context.getDir(Column.DIR_BACKGROUND_IMAGE,Context.MODE_PRIVATE) - backgroundDir.list().forEach {name-> - val file = File(backgroundDir,name) + val backgroundImageDir = Column.getBackgroundImageDir(context) + backgroundImageDir.list().forEach {name-> + val file = File(backgroundImageDir,name) if( file.isFile ){ - val column = Column.findColumnById( name ) + val delm = name.indexOf(':') + val id = if(delm!=-1) name.substring(0, delm) else name + val column = Column.findColumnById( id ) if( column == null) file.delete() } } @@ -330,7 +332,7 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere log.d("initializing TextToSpeech…") object : AsyncTask() { - internal var tmp_tts : TextToSpeech? = null + var tmp_tts : TextToSpeech? = null override fun doInBackground(vararg params : Void) : TextToSpeech { val tts = TextToSpeech(context, tts_init_listener) @@ -338,7 +340,7 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere return tts } - internal val tts_init_listener : TextToSpeech.OnInitListener = + val tts_init_listener : TextToSpeech.OnInitListener = TextToSpeech.OnInitListener { status -> val tts = this.tmp_tts diff --git a/app/src/main/java/jp/juggler/subwaytooter/Column.kt b/app/src/main/java/jp/juggler/subwaytooter/Column.kt index c3090aa9..3bb2bb69 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Column.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/Column.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.content.Context import android.net.Uri import android.os.AsyncTask +import android.os.Environment import android.os.SystemClock import android.view.Gravity import jp.juggler.subwaytooter.api.* @@ -13,6 +14,7 @@ import jp.juggler.subwaytooter.util.* import org.json.JSONArray import org.json.JSONException import org.json.JSONObject +import java.io.File import java.lang.ref.WeakReference import java.nio.ByteBuffer import java.text.SimpleDateFormat @@ -55,7 +57,7 @@ class Column( companion object { private val log = LogCategory("Column") - const val DIR_BACKGROUND_IMAGE = "columnBackground" + private const val DIR_BACKGROUND_IMAGE = "columnBackground" private const val READ_LIMIT = 80 // API側の上限が80です。ただし指定しても40しか返ってこないことが多い private const val LOOP_TIMEOUT = 10000L @@ -403,6 +405,28 @@ class Column( return columnIdMap[id]?.get() } } + + fun getBackgroundImageDir(context : Context) : File { + val externalDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + if( externalDir == null) { + log.e("getExternalFilesDir is null.") + }else{ + val state = Environment.getExternalStorageState() + if( state != Environment.MEDIA_MOUNTED ){ + log.e("getExternalStorageState: ${state}") + }else { + log.i("externalDir: ${externalDir}") + externalDir.mkdir() + val backgroundDir = File(externalDir,DIR_BACKGROUND_IMAGE) + backgroundDir.mkdir() + log.i("backgroundDir: ${backgroundDir} exists=${backgroundDir.exists()}") + return backgroundDir + } + } + val backgroundDir = context.getDir(Column.DIR_BACKGROUND_IMAGE,Context.MODE_PRIVATE) + log.i("backgroundDir: ${backgroundDir} exists=${backgroundDir.exists()}") + return backgroundDir + } } private var callback_ref : WeakReference? = null @@ -2196,15 +2220,15 @@ class Column( TYPE_DOMAIN_BLOCKS -> return parseDomainList(client, PATH_DOMAIN_BLOCK) - TYPE_LIST_LIST -> if(isMisskey){ + TYPE_LIST_LIST -> return if(isMisskey){ val params = makeMisskeyBaseParameter(parser) - return parseListList( + parseListList( client, "/api/users/lists/list", misskeyParams = params ) }else{ - return parseListList(client, PATH_LIST_LIST) + parseListList(client, PATH_LIST_LIST) }