AsyncTaskからkotlin coroutinesへの移行
This commit is contained in:
parent
2c77eaafae
commit
3defbe0cf3
|
@ -10,7 +10,6 @@ import android.content.pm.PackageManager
|
|||
import android.graphics.Bitmap
|
||||
import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
|
@ -21,19 +20,20 @@ import android.text.TextWatcher
|
|||
import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import jp.juggler.subwaytooter.Styler.defaultColorIcon
|
||||
import jp.juggler.subwaytooter.api.*
|
||||
import jp.juggler.subwaytooter.api.entity.*
|
||||
import jp.juggler.subwaytooter.dialog.ActionsDialog
|
||||
import jp.juggler.subwaytooter.dialog.ProgressDialogEx
|
||||
import jp.juggler.subwaytooter.table.AcctColor
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.subwaytooter.util.*
|
||||
import jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
import jp.juggler.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
|
@ -44,8 +44,8 @@ import org.jetbrains.anko.textColor
|
|||
import java.io.*
|
||||
import kotlin.math.max
|
||||
|
||||
class ActAccountSetting
|
||||
: AppCompatActivity(), View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||
class ActAccountSetting : AsyncActivity(), View.OnClickListener,
|
||||
CompoundButton.OnCheckedChangeListener {
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -313,14 +313,14 @@ class ActAccountSetting
|
|||
R.id.etFieldName2,
|
||||
R.id.etFieldName3,
|
||||
R.id.etFieldName4
|
||||
).map { requireNotNull(findViewById<EditText>(it)) }
|
||||
).map { findViewById<EditText>(it) } // 型指定を除去してはいけない
|
||||
|
||||
listEtFieldValue = arrayOf(
|
||||
R.id.etFieldValue1,
|
||||
R.id.etFieldValue2,
|
||||
R.id.etFieldValue3,
|
||||
R.id.etFieldValue4
|
||||
).map { requireNotNull(findViewById<EditText>(it)) }
|
||||
).map { findViewById<EditText>(it) } // 型指定を除去してはいけない
|
||||
|
||||
btnFields = findViewById(R.id.btnFields)
|
||||
|
||||
|
@ -743,63 +743,37 @@ class ActAccountSetting
|
|||
|
||||
finish()
|
||||
|
||||
val task = @SuppressLint("StaticFieldLeak")
|
||||
object : AsyncTask<Void, Void, String?>() {
|
||||
|
||||
fun unregister() {
|
||||
try {
|
||||
|
||||
val install_id = PrefDevice.prefDevice(this@ActAccountSetting)
|
||||
.getString(PrefDevice.KEY_INSTALL_ID, null)
|
||||
if(install_id?.isEmpty() != false) {
|
||||
log.d("performAccountRemove: missing install_id")
|
||||
return
|
||||
}
|
||||
|
||||
val tag = account.notification_tag
|
||||
if(tag?.isEmpty() != false) {
|
||||
log.d("performAccountRemove: missing notification_tag")
|
||||
return
|
||||
}
|
||||
|
||||
val call = App1.ok_http_client.newCall(
|
||||
("instance_url=" + "https://${account.host.ascii}".encodePercent()
|
||||
+ "&app_id=" + packageName.encodePercent()
|
||||
+ "&tag=" + tag
|
||||
)
|
||||
.toFormRequestBody()
|
||||
.toPost()
|
||||
.url(PollingWorker.APP_SERVER + "/unregister")
|
||||
.build()
|
||||
)
|
||||
|
||||
val response = call.execute()
|
||||
|
||||
log.e("performAccountRemove: %s", response)
|
||||
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex, "performAccountRemove failed.")
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val install_id = PrefDevice.prefDevice(this@ActAccountSetting)
|
||||
.getString(PrefDevice.KEY_INSTALL_ID, null)
|
||||
if(install_id?.isEmpty() != false)
|
||||
error("missing install_id")
|
||||
|
||||
}
|
||||
|
||||
override fun doInBackground(vararg params : Void) : String? {
|
||||
unregister()
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCancelled(s : String?) {
|
||||
onPostExecute(s)
|
||||
}
|
||||
|
||||
override fun onPostExecute(s : String?) {
|
||||
|
||||
val tag = account.notification_tag
|
||||
if(tag?.isEmpty() != false)
|
||||
error("missing notification_tag")
|
||||
|
||||
val call = App1.ok_http_client.newCall(
|
||||
("instance_url=" + "https://${account.host.ascii}".encodePercent()
|
||||
+ "&app_id=" + packageName.encodePercent()
|
||||
+ "&tag=" + tag
|
||||
)
|
||||
.toFormRequestBody()
|
||||
.toPost()
|
||||
.url(PollingWorker.APP_SERVER + "/unregister")
|
||||
.build()
|
||||
)
|
||||
|
||||
val response = call.execute()
|
||||
|
||||
log.e("performAccountRemove: %s", response)
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex, "performAccountRemove failed.")
|
||||
}
|
||||
}
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
}
|
||||
.show()
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
@ -1579,41 +1553,19 @@ class ActAccountSetting
|
|||
return
|
||||
}
|
||||
|
||||
val progress = ProgressDialogEx(this)
|
||||
|
||||
val task = @SuppressLint("StaticFieldLeak")
|
||||
object : AsyncTask<Void, Void, InputStreamOpener?>() {
|
||||
|
||||
override fun doInBackground(vararg params : Void) : InputStreamOpener? {
|
||||
return try {
|
||||
createOpener(uri, mime_type)
|
||||
} catch(ex : Throwable) {
|
||||
showToast(this@ActAccountSetting, ex, "image converting failed.")
|
||||
null
|
||||
}
|
||||
runWithProgress(
|
||||
"preparing image",
|
||||
{ createOpener(uri, mime_type) },
|
||||
{
|
||||
updateCredential(
|
||||
when(request_code) {
|
||||
REQUEST_CODE_HEADER_ATTACHMENT, REQUEST_CODE_HEADER_CAMERA -> "header"
|
||||
else -> "avatar"
|
||||
},
|
||||
it
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPostExecute(opener : InputStreamOpener?) {
|
||||
progress.dismissSafe()
|
||||
if(opener != null) {
|
||||
updateCredential(
|
||||
when(request_code) {
|
||||
REQUEST_CODE_HEADER_ATTACHMENT, REQUEST_CODE_HEADER_CAMERA -> "header"
|
||||
else -> "avatar"
|
||||
},
|
||||
opener
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setMessageEx("preparing image…")
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.show()
|
||||
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package jp.juggler.subwaytooter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.text.Editable
|
||||
|
@ -18,7 +16,6 @@ import android.view.Window
|
|||
import android.widget.*
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.jrummyapps.android.colorpicker.ColorPickerDialog
|
||||
|
@ -26,7 +23,6 @@ import com.jrummyapps.android.colorpicker.ColorPickerDialogListener
|
|||
import jp.juggler.subwaytooter.action.CustomShare
|
||||
import jp.juggler.subwaytooter.action.CustomShareTarget
|
||||
import jp.juggler.subwaytooter.dialog.DlgAppPicker
|
||||
import jp.juggler.subwaytooter.dialog.ProgressDialogEx
|
||||
import jp.juggler.subwaytooter.table.AcctColor
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.util.*
|
||||
|
@ -44,7 +40,7 @@ import kotlin.Comparator
|
|||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.abs
|
||||
|
||||
class ActAppSetting : AppCompatActivity(), ColorPickerDialogListener, View.OnClickListener {
|
||||
class ActAppSetting : AsyncActivity(), ColorPickerDialogListener, View.OnClickListener {
|
||||
|
||||
companion object {
|
||||
internal val log = LogCategory("ActAppSetting")
|
||||
|
@ -780,93 +776,58 @@ class ActAppSetting : AppCompatActivity(), ColorPickerDialogListener, View.OnCli
|
|||
|
||||
fun exportAppData() {
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val progress = ProgressDialogEx(this)
|
||||
|
||||
val task = @SuppressLint("StaticFieldLeak")
|
||||
object : AsyncTask<Void, String, File?>() {
|
||||
|
||||
override fun doInBackground(vararg params : Void) : File? {
|
||||
runWithProgress(
|
||||
"export app data",
|
||||
{
|
||||
val cache_dir = cacheDir
|
||||
cache_dir.mkdir()
|
||||
|
||||
try {
|
||||
val cache_dir = cacheDir
|
||||
cache_dir.mkdir()
|
||||
val file = File(
|
||||
cache_dir,
|
||||
"SubwayTooter.${android.os.Process.myPid()}.${android.os.Process.myTid()}.zip"
|
||||
)
|
||||
|
||||
// ZipOutputStreamオブジェクトの作成
|
||||
ZipOutputStream(FileOutputStream(file)).use { zipStream ->
|
||||
|
||||
val file = File(
|
||||
cache_dir,
|
||||
"SubwayTooter.${android.os.Process.myPid()}.${android.os.Process.myTid()}.zip"
|
||||
)
|
||||
|
||||
// ZipOutputStreamオブジェクトの作成
|
||||
ZipOutputStream(FileOutputStream(file)).use { zipStream ->
|
||||
|
||||
// アプリデータjson
|
||||
zipStream.putNextEntry(ZipEntry("AppData.json"))
|
||||
try {
|
||||
val jw = JsonWriter(OutputStreamWriter(zipStream, "UTF-8"))
|
||||
AppDataExporter.encodeAppData(this@ActAppSetting, jw)
|
||||
jw.flush()
|
||||
} finally {
|
||||
zipStream.closeEntry()
|
||||
}
|
||||
|
||||
// カラム背景画像
|
||||
val appState = App1.getAppState(this@ActAppSetting)
|
||||
for(column in appState.column_list) {
|
||||
AppDataExporter.saveBackgroundImage(
|
||||
this@ActAppSetting,
|
||||
zipStream,
|
||||
column
|
||||
)
|
||||
}
|
||||
// アプリデータjson
|
||||
zipStream.putNextEntry(ZipEntry("AppData.json"))
|
||||
try {
|
||||
val jw = JsonWriter(OutputStreamWriter(zipStream, "UTF-8"))
|
||||
AppDataExporter.encodeAppData(this@ActAppSetting, jw)
|
||||
jw.flush()
|
||||
} finally {
|
||||
zipStream.closeEntry()
|
||||
}
|
||||
|
||||
return file
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(this@ActAppSetting, ex, "exportAppData failed.")
|
||||
// カラム背景画像
|
||||
val appState = App1.getAppState(this@ActAppSetting)
|
||||
for(column in appState.column_list) {
|
||||
AppDataExporter.saveBackgroundImage(
|
||||
this@ActAppSetting,
|
||||
zipStream,
|
||||
column
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCancelled(result : File?) {
|
||||
onPostExecute(result)
|
||||
}
|
||||
|
||||
override fun onPostExecute(result : File?) {
|
||||
progress.dismissSafe()
|
||||
file
|
||||
},
|
||||
{
|
||||
val uri = FileProvider.getUriForFile(
|
||||
this@ActAppSetting,
|
||||
App1.FILE_PROVIDER_AUTHORITY,
|
||||
it
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = contentResolver.getType(uri)
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter app data")
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
|
||||
if(isCancelled || result == null) {
|
||||
// cancelled.
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
this@ActAppSetting,
|
||||
App1.FILE_PROVIDER_AUTHORITY,
|
||||
result
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = contentResolver.getType(uri)
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter app data")
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
startActivityForResult(intent, REQUEST_CODE_OTHER)
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(this@ActAppSetting, ex, "exportAppData failed.")
|
||||
}
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
startActivityForResult(intent, REQUEST_CODE_OTHER)
|
||||
}
|
||||
}
|
||||
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setCancelable(true)
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.show()
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
)
|
||||
}
|
||||
|
||||
// open data picker
|
||||
|
|
|
@ -3,7 +3,6 @@ package jp.juggler.subwaytooter
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.os.Process
|
||||
|
@ -13,11 +12,9 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.FileProvider
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||
import jp.juggler.subwaytooter.dialog.ActionsDialog
|
||||
import jp.juggler.subwaytooter.dialog.ProgressDialogEx
|
||||
import jp.juggler.util.*
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.jetbrains.anko.textColor
|
||||
|
@ -27,8 +24,7 @@ import java.io.FileOutputStream
|
|||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
|
||||
|
||||
class ActLanguageFilter : AsyncActivity(), View.OnClickListener {
|
||||
|
||||
private class MyItem(
|
||||
val code : String,
|
||||
|
@ -397,84 +393,42 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun export() {
|
||||
|
||||
val progress = ProgressDialogEx(this)
|
||||
|
||||
val data = JsonObject().apply {
|
||||
for(item in languageList) {
|
||||
put(item.code, item.allow)
|
||||
private fun export() = runWithProgress(
|
||||
"export language filter",
|
||||
{
|
||||
val data = JsonObject().apply {
|
||||
for(item in languageList) {
|
||||
put(item.code, item.allow)
|
||||
}
|
||||
}
|
||||
.toString()
|
||||
.encodeUTF8()
|
||||
|
||||
val cache_dir = cacheDir
|
||||
cache_dir.mkdir()
|
||||
|
||||
val file = File(
|
||||
cache_dir,
|
||||
"SubwayTooter-language-filter.${Process.myPid()}.${Process.myTid()}.json"
|
||||
)
|
||||
FileOutputStream(file).use { it.write(data) }
|
||||
file
|
||||
},
|
||||
{
|
||||
val uri = FileProvider.getUriForFile(
|
||||
this@ActLanguageFilter,
|
||||
App1.FILE_PROVIDER_AUTHORITY,
|
||||
it
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = contentResolver.getType(uri)
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter language filter data")
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
startActivityForResult(intent, REQUEST_CODE_OTHER)
|
||||
}
|
||||
.toString()
|
||||
.encodeUTF8()
|
||||
|
||||
val task = @SuppressLint("StaticFieldLeak")
|
||||
object : AsyncTask<Void, String, File?>() {
|
||||
|
||||
override fun doInBackground(vararg params : Void) : File? {
|
||||
|
||||
try {
|
||||
val cache_dir = cacheDir
|
||||
cache_dir.mkdir()
|
||||
|
||||
val file = File(
|
||||
cache_dir,
|
||||
"SubwayTooter-language-filter.${Process.myPid()}.${Process.myTid()}.json"
|
||||
)
|
||||
FileOutputStream(file).use { it.write(data) }
|
||||
return file
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(
|
||||
this@ActLanguageFilter,
|
||||
ex,
|
||||
"can't save filter data to temporary file."
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCancelled(result : File?) {
|
||||
onPostExecute(result)
|
||||
}
|
||||
|
||||
override fun onPostExecute(result : File?) {
|
||||
progress.dismissSafe()
|
||||
|
||||
if(isCancelled || result == null) {
|
||||
// cancelled.
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
this@ActLanguageFilter,
|
||||
App1.FILE_PROVIDER_AUTHORITY,
|
||||
result
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = contentResolver.getType(uri)
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter language filter data")
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
startActivityForResult(intent, REQUEST_CODE_OTHER)
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(this@ActLanguageFilter, ex, "export failed.")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setCancelable(true)
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.show()
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
}
|
||||
)
|
||||
|
||||
private fun import() {
|
||||
try {
|
||||
|
@ -495,53 +449,22 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
|
|||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun import2(uri : Uri) {
|
||||
|
||||
val type = contentResolver.getType(uri)
|
||||
log.d("import2 type=%s", type)
|
||||
|
||||
val progress = ProgressDialogEx(this)
|
||||
|
||||
val task = @SuppressLint("StaticFieldLeak")
|
||||
object : AsyncTask<Void, String, JsonObject?>() {
|
||||
|
||||
override fun doInBackground(vararg params : Void) : JsonObject? {
|
||||
try {
|
||||
val source = contentResolver.openInputStream(uri)
|
||||
if(source == null) {
|
||||
showToast(this@ActLanguageFilter, true, "openInputStream failed.")
|
||||
return null
|
||||
}
|
||||
return source.use { inStream ->
|
||||
val bao = ByteArrayOutputStream()
|
||||
IOUtils.copy(inStream, bao)
|
||||
bao.toByteArray().decodeUTF8().decodeJsonObject()
|
||||
}
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(this@ActLanguageFilter, ex, "can't load filter data.")
|
||||
return null
|
||||
private fun import2(uri : Uri) = runWithProgress(
|
||||
"import language filter",
|
||||
{
|
||||
log.d("import2 type=${contentResolver.getType(uri)}")
|
||||
val source = contentResolver.openInputStream(uri)
|
||||
if(source == null) {
|
||||
showToast( true, "openInputStream failed.")
|
||||
null
|
||||
} else {
|
||||
source.use { inStream ->
|
||||
val bao = ByteArrayOutputStream()
|
||||
IOUtils.copy(inStream, bao)
|
||||
bao.toByteArray().decodeUTF8().decodeJsonObject()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(result : JsonObject?) {
|
||||
onPostExecute(result)
|
||||
}
|
||||
|
||||
override fun onPostExecute(result : JsonObject?) {
|
||||
progress.dismissSafe()
|
||||
|
||||
// cancelled.
|
||||
if(isCancelled || result == null) return
|
||||
|
||||
load(result)
|
||||
}
|
||||
}
|
||||
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setCancelable(true)
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.show()
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
}
|
||||
},
|
||||
{ if(it != null) load(it) }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package jp.juggler.subwaytooter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
|
@ -19,8 +18,6 @@ import android.view.*
|
|||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -31,13 +28,17 @@ import jp.juggler.subwaytooter.api.*
|
|||
import jp.juggler.subwaytooter.api.entity.*
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus.Companion.findStatusIdFromUrl
|
||||
import jp.juggler.subwaytooter.api.entity.TootTag.Companion.findHashtagFromUrl
|
||||
import jp.juggler.subwaytooter.dialog.*
|
||||
import jp.juggler.subwaytooter.dialog.AccountPicker
|
||||
import jp.juggler.subwaytooter.dialog.ActionsDialog
|
||||
import jp.juggler.subwaytooter.dialog.DlgQuickTootMenu
|
||||
import jp.juggler.subwaytooter.dialog.DlgTextInput
|
||||
import jp.juggler.subwaytooter.span.MyClickableSpan
|
||||
import jp.juggler.subwaytooter.table.AcctColor
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.subwaytooter.util.*
|
||||
import jp.juggler.subwaytooter.view.*
|
||||
import jp.juggler.util.*
|
||||
import kotlinx.coroutines.delay
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.jetbrains.anko.backgroundDrawable
|
||||
import java.io.File
|
||||
|
@ -51,7 +52,7 @@ import kotlin.math.abs
|
|||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class ActMain : AppCompatActivity()
|
||||
class ActMain : AsyncActivity()
|
||||
, Column.Callback
|
||||
, View.OnClickListener
|
||||
, ViewPager.OnPageChangeListener
|
||||
|
@ -1320,7 +1321,7 @@ class ActMain : AppCompatActivity()
|
|||
drawer = findViewById(R.id.drawer_layout)
|
||||
drawer.addDrawerListener(this)
|
||||
|
||||
drawer.setExclusionSize( stripIconSize)
|
||||
drawer.setExclusionSize(stripIconSize)
|
||||
|
||||
|
||||
|
||||
|
@ -1548,7 +1549,7 @@ class ActMain : AppCompatActivity()
|
|||
}
|
||||
)
|
||||
|
||||
internal fun updateColumnStrip() {
|
||||
private fun updateColumnStrip() {
|
||||
llEmpty.vg(app_state.column_list.isEmpty())
|
||||
|
||||
val iconSize = stripIconSize
|
||||
|
@ -1599,7 +1600,7 @@ class ActMain : AppCompatActivity()
|
|||
scrollToColumn(idx)
|
||||
}
|
||||
viewRoot.contentDescription = column.getColumnName(true)
|
||||
|
||||
|
||||
viewRoot.backgroundDrawable = getAdaptiveRippleDrawableRound(
|
||||
this,
|
||||
column.getHeaderBackgroundColor(),
|
||||
|
@ -2523,10 +2524,11 @@ class ActMain : AppCompatActivity()
|
|||
)
|
||||
val colorRipple =
|
||||
footer_button_fg_color.notZero() ?: getAttributeColor(this, R.attr.colorRippleEffect)
|
||||
btnMenu.backgroundDrawable = getAdaptiveRippleDrawableRound(this,colorBg, colorRipple)
|
||||
btnToot.backgroundDrawable = getAdaptiveRippleDrawableRound(this,colorBg, colorRipple)
|
||||
btnQuickToot.backgroundDrawable = getAdaptiveRippleDrawableRound(this,colorBg, colorRipple)
|
||||
btnQuickTootMenu.backgroundDrawable = getAdaptiveRippleDrawableRound(this,colorBg, colorRipple)
|
||||
btnMenu.backgroundDrawable = getAdaptiveRippleDrawableRound(this, colorBg, colorRipple)
|
||||
btnToot.backgroundDrawable = getAdaptiveRippleDrawableRound(this, colorBg, colorRipple)
|
||||
btnQuickToot.backgroundDrawable = getAdaptiveRippleDrawableRound(this, colorBg, colorRipple)
|
||||
btnQuickTootMenu.backgroundDrawable =
|
||||
getAdaptiveRippleDrawableRound(this, colorBg, colorRipple)
|
||||
|
||||
val csl = ColorStateList.valueOf(
|
||||
footer_button_fg_color.notZero()
|
||||
|
@ -2738,159 +2740,125 @@ class ActMain : AppCompatActivity()
|
|||
uri ?: return
|
||||
|
||||
// remove all columns
|
||||
run {
|
||||
phoneOnly { env -> env.pager.adapter = null }
|
||||
|
||||
for(c in app_state.column_list) {
|
||||
c.dispose()
|
||||
}
|
||||
app_state.column_list.clear()
|
||||
|
||||
phoneTab(
|
||||
{ env -> env.pager.adapter = env.pager_adapter },
|
||||
{ env -> resizeColumnWidth(env) }
|
||||
)
|
||||
|
||||
|
||||
updateColumnStrip()
|
||||
phoneOnly { env -> env.pager.adapter = null }
|
||||
|
||||
for(c in app_state.column_list) {
|
||||
c.dispose()
|
||||
}
|
||||
app_state.column_list.clear()
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val progress = ProgressDialogEx(this)
|
||||
phoneTab(
|
||||
{ env -> env.pager.adapter = env.pager_adapter },
|
||||
{ env -> resizeColumnWidth(env) }
|
||||
)
|
||||
|
||||
val task = @SuppressLint("StaticFieldLeak") object :
|
||||
AsyncTask<Void, String, ArrayList<Column>?>() {
|
||||
updateColumnStrip()
|
||||
|
||||
|
||||
runWithProgress(
|
||||
"importing app data",
|
||||
|
||||
fun setProgressMessage(sv : String) {
|
||||
runOnMainLooper {
|
||||
progress.setMessageEx(sv)
|
||||
}
|
||||
}
|
||||
|
||||
override fun doInBackground(vararg params : Void) : ArrayList<Column>? {
|
||||
doInBackground = { progress ->
|
||||
fun setProgressMessage(sv : String) =
|
||||
runOnMainLooper { progress.setMessageEx(sv) }
|
||||
|
||||
var newColumnList : ArrayList<Column>? = null
|
||||
|
||||
setProgressMessage("import data to local storage...")
|
||||
|
||||
// アプリ内領域に一時ファイルを作ってコピーする
|
||||
val cacheDir = cacheDir
|
||||
cacheDir.mkdir()
|
||||
val file = File(
|
||||
cacheDir,
|
||||
"SubwayTooter.${Process.myPid()}.${Process.myTid()}.tmp"
|
||||
)
|
||||
val source = contentResolver.openInputStream(uri)
|
||||
if(source == null) {
|
||||
showToast(true, "openInputStream failed.")
|
||||
return@runWithProgress null
|
||||
}
|
||||
source.use { inStream ->
|
||||
FileOutputStream(file).use { outStream ->
|
||||
IOUtils.copy(inStream, outStream)
|
||||
}
|
||||
}
|
||||
|
||||
// 通知サービスを止める
|
||||
setProgressMessage("syncing notification poller…")
|
||||
PollingWorker.queueAppDataImportBefore(this@ActMain)
|
||||
while(PollingWorker.mBusyAppDataImportBefore.get()) {
|
||||
delay(1000L)
|
||||
log.d("syncing polling task...")
|
||||
}
|
||||
|
||||
// データを読み込む
|
||||
setProgressMessage("reading app data...")
|
||||
var zipEntryCount = 0
|
||||
try {
|
||||
|
||||
setProgressMessage("import data to local storage...")
|
||||
|
||||
// アプリ内領域に一時ファイルを作ってコピーする
|
||||
val cacheDir = cacheDir
|
||||
cacheDir.mkdir()
|
||||
val file = File(
|
||||
cacheDir,
|
||||
"SubwayTooter.${Process.myPid()}.${Process.myTid()}.tmp"
|
||||
)
|
||||
val source = contentResolver.openInputStream(uri)
|
||||
if(source == null) {
|
||||
showToast(this@ActMain, true, "openInputStream failed.")
|
||||
return null
|
||||
}
|
||||
source.use { inStream ->
|
||||
FileOutputStream(file).use { outStream ->
|
||||
IOUtils.copy(inStream, outStream)
|
||||
}
|
||||
}
|
||||
|
||||
// 通知サービスを止める
|
||||
setProgressMessage("syncing notification poller…")
|
||||
PollingWorker.queueAppDataImportBefore(this@ActMain)
|
||||
while(PollingWorker.mBusyAppDataImportBefore.get()) {
|
||||
Thread.sleep(1000L)
|
||||
log.d("syncing polling task...")
|
||||
}
|
||||
|
||||
// データを読み込む
|
||||
setProgressMessage("reading app data...")
|
||||
var zipEntryCount = 0
|
||||
try {
|
||||
ZipInputStream(FileInputStream(file)).use { zipStream ->
|
||||
while(true) {
|
||||
val entry = zipStream.nextEntry ?: break
|
||||
++ zipEntryCount
|
||||
try {
|
||||
//
|
||||
val entryName = entry.name
|
||||
if(entryName.endsWith(".json")) {
|
||||
newColumnList = AppDataExporter.decodeAppData(
|
||||
this@ActMain,
|
||||
JsonReader(InputStreamReader(zipStream, "UTF-8"))
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if(AppDataExporter.restoreBackgroundImage(
|
||||
this@ActMain,
|
||||
newColumnList,
|
||||
zipStream,
|
||||
entryName
|
||||
)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
} finally {
|
||||
zipStream.closeEntry()
|
||||
ZipInputStream(FileInputStream(file)).use { zipStream ->
|
||||
while(true) {
|
||||
val entry = zipStream.nextEntry ?: break
|
||||
++ zipEntryCount
|
||||
try {
|
||||
//
|
||||
val entryName = entry.name
|
||||
if(entryName.endsWith(".json")) {
|
||||
newColumnList = AppDataExporter.decodeAppData(
|
||||
this@ActMain,
|
||||
JsonReader(InputStreamReader(zipStream, "UTF-8"))
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if(AppDataExporter.restoreBackgroundImage(
|
||||
this@ActMain,
|
||||
newColumnList,
|
||||
zipStream,
|
||||
entryName
|
||||
)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
} finally {
|
||||
zipStream.closeEntry()
|
||||
}
|
||||
}
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
if(zipEntryCount != 0) {
|
||||
showToast(this@ActMain, ex, "importAppData failed.")
|
||||
}
|
||||
}
|
||||
// zipではなかった場合、zipEntryがない状態になる。例外はPH-1では出なかったが、出ても問題ないようにする。
|
||||
if(zipEntryCount == 0) {
|
||||
InputStreamReader(FileInputStream(file), "UTF-8").use { inStream ->
|
||||
newColumnList = AppDataExporter.decodeAppData(
|
||||
this@ActMain,
|
||||
JsonReader(inStream)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(this@ActMain, ex, "importAppData failed.")
|
||||
}
|
||||
|
||||
return newColumnList
|
||||
}
|
||||
|
||||
override fun onCancelled(result : ArrayList<Column>?) {
|
||||
onPostExecute(result)
|
||||
}
|
||||
|
||||
override fun onPostExecute(result : ArrayList<Column>?) {
|
||||
|
||||
progress.dismissSafe()
|
||||
|
||||
try {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} catch(ignored : Throwable) {
|
||||
}
|
||||
|
||||
try {
|
||||
if(isCancelled || result == null) {
|
||||
// cancelled.
|
||||
return
|
||||
if(zipEntryCount != 0) {
|
||||
showToast(this@ActMain, ex, "importAppData failed.")
|
||||
}
|
||||
|
||||
run {
|
||||
|
||||
phoneOnly { env -> env.pager.adapter = null }
|
||||
|
||||
app_state.column_list.clear()
|
||||
app_state.column_list.addAll(result)
|
||||
app_state.saveColumnList()
|
||||
|
||||
phoneTab(
|
||||
{ env -> env.pager.adapter = env.pager_adapter },
|
||||
{ env -> resizeColumnWidth(env) }
|
||||
}
|
||||
// zipではなかった場合、zipEntryがない状態になる。例外はPH-1では出なかったが、出ても問題ないようにする。
|
||||
if(zipEntryCount == 0) {
|
||||
InputStreamReader(FileInputStream(file), "UTF-8").use { inStream ->
|
||||
newColumnList = AppDataExporter.decodeAppData(
|
||||
this@ActMain,
|
||||
JsonReader(inStream)
|
||||
)
|
||||
updateColumnStrip()
|
||||
}
|
||||
}
|
||||
|
||||
newColumnList
|
||||
},
|
||||
afterProc = {
|
||||
// cancelled.
|
||||
if(it == null) return@runWithProgress
|
||||
|
||||
try {
|
||||
phoneOnly { env -> env.pager.adapter = null }
|
||||
|
||||
app_state.column_list.clear()
|
||||
app_state.column_list.addAll(it)
|
||||
app_state.saveColumnList()
|
||||
|
||||
phoneTab(
|
||||
{ env -> env.pager.adapter = env.pager_adapter },
|
||||
{ env -> resizeColumnWidth(env) }
|
||||
)
|
||||
updateColumnStrip()
|
||||
} finally {
|
||||
// 通知サービスをリスタート
|
||||
PollingWorker.queueAppDataImportAfter(this@ActMain)
|
||||
|
@ -2898,19 +2866,14 @@ class ActMain : AppCompatActivity()
|
|||
|
||||
showToast(this@ActMain, true, R.string.import_completed_please_restart_app)
|
||||
finish()
|
||||
},
|
||||
preProc = {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
},
|
||||
postProc = {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} catch(ignored : Throwable) {
|
||||
}
|
||||
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setCancelable(false)
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.show()
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDrawerSlide(drawerView : View, slideOffset : Float) {
|
||||
|
|
|
@ -11,21 +11,25 @@ import android.content.SharedPreferences
|
|||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.*
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.SystemClock
|
||||
import android.provider.MediaStore
|
||||
import android.text.*
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.text.Editable
|
||||
import android.text.InputType
|
||||
import android.text.TextWatcher
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
||||
import jp.juggler.subwaytooter.Styler.defaultColorIcon
|
||||
import jp.juggler.subwaytooter.api.*
|
||||
import jp.juggler.subwaytooter.api.entity.*
|
||||
|
@ -39,6 +43,7 @@ import jp.juggler.subwaytooter.view.FocusPointView
|
|||
import jp.juggler.subwaytooter.view.MyEditText
|
||||
import jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
import jp.juggler.util.*
|
||||
import kotlinx.coroutines.isActive
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
|
@ -54,7 +59,7 @@ import java.util.concurrent.ConcurrentLinkedQueue
|
|||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.math.max
|
||||
|
||||
class ActPost : AppCompatActivity(),
|
||||
class ActPost : AsyncActivity(),
|
||||
View.OnClickListener,
|
||||
PostAttachment.Callback {
|
||||
|
||||
|
@ -397,17 +402,17 @@ class ActPost : AppCompatActivity(),
|
|||
private lateinit var btnPost : ImageButton
|
||||
private lateinit var llAttachment : View
|
||||
private lateinit var ivMedia : List<MyNetworkImageView>
|
||||
internal lateinit var cbNSFW : CheckBox
|
||||
internal lateinit var cbContentWarning : CheckBox
|
||||
internal lateinit var etContentWarning : MyEditText
|
||||
internal lateinit var etContent : MyEditText
|
||||
private lateinit var cbNSFW : CheckBox
|
||||
private lateinit var cbContentWarning : CheckBox
|
||||
private lateinit var etContentWarning : MyEditText
|
||||
private lateinit var etContent : MyEditText
|
||||
private lateinit var btnFeaturedTag : ImageButton
|
||||
|
||||
internal lateinit var cbQuote : CheckBox
|
||||
private lateinit var cbQuote : CheckBox
|
||||
|
||||
internal lateinit var spEnquete : Spinner
|
||||
private lateinit var spEnquete : Spinner
|
||||
private lateinit var llEnquete : View
|
||||
internal lateinit var list_etChoice : List<MyEditText>
|
||||
private lateinit var list_etChoice : List<MyEditText>
|
||||
|
||||
private lateinit var cbMultipleChoice : CheckBox
|
||||
private lateinit var cbHideTotals : CheckBox
|
||||
|
@ -433,7 +438,7 @@ class ActPost : AppCompatActivity(),
|
|||
internal lateinit var pref : SharedPreferences
|
||||
internal lateinit var app_state : AppState
|
||||
private lateinit var post_helper : PostHelper
|
||||
internal var attachment_list = ArrayList<PostAttachment>()
|
||||
private var attachment_list = ArrayList<PostAttachment>()
|
||||
private var isPostComplete : Boolean = false
|
||||
|
||||
internal var density : Float = 0f
|
||||
|
@ -478,9 +483,9 @@ class ActPost : AppCompatActivity(),
|
|||
/////////////////////////////////////////////////
|
||||
|
||||
internal var in_reply_to_id : EntityId? = null
|
||||
internal var in_reply_to_text : String? = null
|
||||
internal var in_reply_to_image : String? = null
|
||||
internal var in_reply_to_url : String? = null
|
||||
private var in_reply_to_text : String? = null
|
||||
private var in_reply_to_image : String? = null
|
||||
private var in_reply_to_url : String? = null
|
||||
private var mushroom_input : Int = 0
|
||||
private var mushroom_start : Int = 0
|
||||
private var mushroom_end : Int = 0
|
||||
|
@ -812,7 +817,7 @@ class ActPost : AppCompatActivity(),
|
|||
// 比較する前にデフォルトの公開範囲を計算する
|
||||
visibility = visibility
|
||||
?: account.visibility
|
||||
?: TootVisibility.Public
|
||||
// ?: TootVisibility.Public
|
||||
// VISIBILITY_WEB_SETTING だと 1.5未満のタンスでトラブルになる
|
||||
|
||||
if(TootVisibility.WebSetting == visibility) {
|
||||
|
@ -1446,7 +1451,7 @@ class ActPost : AppCompatActivity(),
|
|||
etContentWarning.visibility = if(cbContentWarning.isChecked) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
internal fun selectAccount(a : SavedAccount?) {
|
||||
private fun selectAccount(a : SavedAccount?) {
|
||||
this.account = a
|
||||
if(a == null) {
|
||||
post_helper.setInstance(null, false)
|
||||
|
@ -2661,7 +2666,7 @@ class ActPost : AppCompatActivity(),
|
|||
cbQuote.visibility = if(in_reply_to_id != null) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
internal fun showReplyTo() {
|
||||
private fun showReplyTo() {
|
||||
if(in_reply_to_id == null) {
|
||||
llReply.visibility = View.GONE
|
||||
} else {
|
||||
|
@ -2773,16 +2778,13 @@ class ActPost : AppCompatActivity(),
|
|||
|
||||
private fun restoreDraft(draft : JsonObject) {
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val progress = ProgressDialogEx(this)
|
||||
|
||||
val task = @SuppressLint("StaticFieldLeak")
|
||||
object : AsyncTask<Void, String, String?>() {
|
||||
|
||||
val list_warning = ArrayList<String>()
|
||||
var account : SavedAccount? = null
|
||||
|
||||
override fun doInBackground(vararg params : Void) : String? {
|
||||
val list_warning = ArrayList<String>()
|
||||
var target_account : SavedAccount? = null
|
||||
|
||||
runWithProgress(
|
||||
"restore from draft",
|
||||
{progress->
|
||||
fun isTaskCancelled() = !this.coroutineContext.isActive
|
||||
|
||||
var content = draft.string(DRAFT_CONTENT) ?: ""
|
||||
val account_db_id = draft.long(DRAFT_ACCOUNT_DB_ID) ?: - 1L
|
||||
|
@ -2812,15 +2814,16 @@ class ActPost : AppCompatActivity(),
|
|||
} catch(ignored : JsonException) {
|
||||
}
|
||||
|
||||
return "OK"
|
||||
return@runWithProgress "OK"
|
||||
}
|
||||
this.account = account
|
||||
|
||||
target_account = account
|
||||
|
||||
// アカウントがあるなら基本的にはすべての情報を復元できるはずだが、いくつか確認が必要だ
|
||||
val api_client = TootApiClient(this@ActPost, callback = object : TootApiCallback {
|
||||
|
||||
override val isApiCancelled : Boolean
|
||||
get() = isCancelled
|
||||
get() = isTaskCancelled()
|
||||
|
||||
override fun publishApiProgress(s : String) {
|
||||
runOnMainLooper {
|
||||
|
@ -2833,7 +2836,7 @@ class ActPost : AppCompatActivity(),
|
|||
|
||||
if(in_reply_to_id != null) {
|
||||
val result = api_client.request("/api/v1/statuses/$in_reply_to_id")
|
||||
if(isCancelled) return null
|
||||
if(isTaskCancelled()) return@runWithProgress null
|
||||
val jsonObject = result?.jsonObject
|
||||
if(jsonObject == null) {
|
||||
list_warning.add(getString(R.string.reply_to_in_draft_is_lost))
|
||||
|
@ -2848,7 +2851,7 @@ class ActPost : AppCompatActivity(),
|
|||
var isSomeAttachmentRemoved = false
|
||||
val it = tmp_attachment_list.iterator()
|
||||
while(it.hasNext()) {
|
||||
if(isCancelled) return null
|
||||
if(isTaskCancelled()) return@runWithProgress null
|
||||
val ta = TootAttachment.decodeJson(it.next())
|
||||
if(check_exist(ta.url)) continue
|
||||
it.remove()
|
||||
|
@ -2869,20 +2872,11 @@ class ActPost : AppCompatActivity(),
|
|||
log.trace(ex)
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
override fun onCancelled(result : String?) {
|
||||
onPostExecute(result)
|
||||
}
|
||||
|
||||
override fun onPostExecute(result : String?) {
|
||||
progress.dismissSafe()
|
||||
|
||||
if(isCancelled || result == null) {
|
||||
// cancelled.
|
||||
return
|
||||
}
|
||||
"OK"
|
||||
},
|
||||
{result->
|
||||
// cancelled.
|
||||
if( result == null) return@runWithProgress
|
||||
|
||||
val content = draft.string(DRAFT_CONTENT) ?: ""
|
||||
val content_warning = draft.string(DRAFT_CONTENT_WARNING) ?: ""
|
||||
|
@ -2935,7 +2929,7 @@ class ActPost : AppCompatActivity(),
|
|||
}
|
||||
}
|
||||
|
||||
if(account != null) selectAccount(account)
|
||||
if(target_account != null) selectAccount(target_account)
|
||||
|
||||
if(tmp_attachment_list?.isNotEmpty() == true) {
|
||||
attachment_list.clear()
|
||||
|
@ -2973,13 +2967,7 @@ class ActPost : AppCompatActivity(),
|
|||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setCancelable(true)
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.show()
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
)
|
||||
}
|
||||
|
||||
private fun prepareMushroomText(et : EditText) : String {
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.content.*
|
|||
import android.media.Ringtone
|
||||
import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Handler
|
||||
import android.os.SystemClock
|
||||
import android.speech.tts.TextToSpeech
|
||||
|
@ -20,6 +19,10 @@ import jp.juggler.subwaytooter.table.SavedAccount
|
|||
import jp.juggler.subwaytooter.util.NetworkStateTracker
|
||||
import jp.juggler.subwaytooter.util.PostAttachment
|
||||
import jp.juggler.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.apache.commons.io.IOUtils
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
|
@ -352,19 +355,14 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere
|
|||
showToast(context, false, R.string.text_to_speech_initializing)
|
||||
log.d("initializing TextToSpeech…")
|
||||
|
||||
object : AsyncTask<Void, Void, TextToSpeech?>() {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
|
||||
var tmp_tts : TextToSpeech? = null
|
||||
|
||||
override fun doInBackground(vararg params : Void) : TextToSpeech {
|
||||
val tts = TextToSpeech(context, tts_init_listener)
|
||||
this.tmp_tts = tts
|
||||
return tts
|
||||
}
|
||||
|
||||
val tts_init_listener : TextToSpeech.OnInitListener =
|
||||
TextToSpeech.OnInitListener { status ->
|
||||
|
||||
val tts = this.tmp_tts
|
||||
val tts = tmp_tts
|
||||
if(tts == null || TextToSpeech.SUCCESS != status) {
|
||||
showToast(
|
||||
context,
|
||||
|
@ -443,8 +441,11 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere
|
|||
}
|
||||
}
|
||||
|
||||
}.executeOnExecutor(App1.task_executor)
|
||||
tmp_tts = TextToSpeech(context, tts_init_listener)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if(! willSpeechEnabled && tts != null) {
|
||||
showToast(context, false, R.string.text_to_speech_shutdown)
|
||||
log.d("shutdown TextToSpeech…")
|
||||
|
@ -516,18 +517,18 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere
|
|||
|
||||
if(dedupMode != DedupMode.None) {
|
||||
synchronized(this) {
|
||||
val check = duplication_check.find { it.text.equals(sv,ignoreCase = true) }
|
||||
val check = duplication_check.find { it.text.equals(sv, ignoreCase = true) }
|
||||
if(check == null) {
|
||||
duplication_check.addLast(DedupItem(sv))
|
||||
if(duplication_check.size > 60) duplication_check.removeFirst()
|
||||
} else{
|
||||
} else {
|
||||
val now = SystemClock.elapsedRealtime()
|
||||
val delta = now - check.time
|
||||
// 古い項目が残っていることがあるので、check.timeの更新は必須
|
||||
check.time = now
|
||||
|
||||
|
||||
if(dedupMode == DedupMode.Recent) return
|
||||
if(dedupMode == DedupMode.RecentExpire && delta < 5000L ) return
|
||||
if(dedupMode == DedupMode.RecentExpire && delta < 5000L) return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -576,7 +577,8 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere
|
|||
return false
|
||||
}
|
||||
|
||||
if(item.sound_type == HighlightWord.SOUND_TYPE_CUSTOM && item.sound_uri.mayUri().tryRingtone()) return
|
||||
if(item.sound_type == HighlightWord.SOUND_TYPE_CUSTOM && item.sound_uri.mayUri()
|
||||
.tryRingtone()) return
|
||||
|
||||
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION).tryRingtone()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package jp.juggler.subwaytooter
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import jp.juggler.subwaytooter.dialog.ProgressDialogEx
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.dismissSafe
|
||||
import jp.juggler.util.showToast
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
abstract class AsyncActivity : AppCompatActivity(), CoroutineScope {
|
||||
|
||||
companion object{
|
||||
private val log =LogCategory("AsyncActivity")
|
||||
}
|
||||
|
||||
private lateinit var job : Job
|
||||
|
||||
override val coroutineContext : CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
override fun onCreate(savedInstanceState : Bundle?, persistentState : PersistableBundle?) {
|
||||
super.onCreate(savedInstanceState, persistentState)
|
||||
job = Job()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
(job + Dispatchers.Default).cancel()
|
||||
}
|
||||
|
||||
fun showToast(bLong : Boolean, fmt : String?, vararg args : Any) =
|
||||
showToast(this, bLong, fmt, *args)
|
||||
|
||||
fun showToast(ex : Throwable, fmt : String?, vararg args : Any) =
|
||||
showToast(this, ex, fmt, *args)
|
||||
|
||||
fun showToast(bLong : Boolean, string_id : Int, vararg args : Any) =
|
||||
showToast(this, bLong, string_id, *args)
|
||||
|
||||
fun showToast(ex : Throwable, string_id : Int, vararg args : Any) =
|
||||
showToast(this, ex, string_id, *args)
|
||||
|
||||
fun <T : Any?> runWithProgress(
|
||||
caption : String,
|
||||
doInBackground : suspend CoroutineScope.(ProgressDialogEx) -> T,
|
||||
afterProc : suspend CoroutineScope.(result : T) -> Unit = {},
|
||||
progressInitializer : suspend CoroutineScope.(ProgressDialogEx) -> Unit = {},
|
||||
preProc : suspend CoroutineScope.() -> Unit ={},
|
||||
postProc : suspend CoroutineScope.() -> Unit ={}
|
||||
) {
|
||||
|
||||
val progress = ProgressDialogEx(this)
|
||||
|
||||
val task = async(Dispatchers.IO) {
|
||||
doInBackground(progress)
|
||||
}
|
||||
|
||||
launch {
|
||||
try{
|
||||
preProc()
|
||||
}catch(ex:Throwable){
|
||||
log.trace(ex)
|
||||
}
|
||||
progress.setCancelable(true)
|
||||
progress.setOnCancelListener {task.cancel()}
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setMessageEx("${caption}…")
|
||||
progressInitializer(progress)
|
||||
progress.show()
|
||||
|
||||
try {
|
||||
val result = try {
|
||||
task.await()
|
||||
}catch(ex:CancellationException){
|
||||
null
|
||||
}
|
||||
// TODO キャンセル時に呼ぶ必要がある利用例があるかどうか調べる
|
||||
if(result!=null) afterProc(result)
|
||||
} catch(ex : Throwable) {
|
||||
showToast(this@AsyncActivity, ex, "$caption failed.")
|
||||
} finally {
|
||||
progress.dismissSafe()
|
||||
try{
|
||||
postProc()
|
||||
}catch(ex:Throwable){
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1450,7 +1450,7 @@ class Column(
|
|||
|
||||
private fun cancelLastTask() {
|
||||
if(lastTask != null) {
|
||||
lastTask?.cancel(true)
|
||||
lastTask?.cancel()
|
||||
lastTask = null
|
||||
//
|
||||
bInitialLoading = false
|
||||
|
@ -1929,7 +1929,7 @@ class Column(
|
|||
@SuppressLint("StaticFieldLeak")
|
||||
val task = ColumnTask_Loading(this)
|
||||
this.lastTask = task
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
task.start()
|
||||
}
|
||||
|
||||
private var bMinIdMatched : Boolean = false
|
||||
|
@ -2141,7 +2141,7 @@ class Column(
|
|||
@SuppressLint("StaticFieldLeak")
|
||||
val task = ColumnTask_Refresh(this, bSilent, bBottom, posted_status_id, refresh_after_toot)
|
||||
this.lastTask = task
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
task.start()
|
||||
fireShowColumnStatus()
|
||||
}
|
||||
|
||||
|
@ -2165,9 +2165,8 @@ class Column(
|
|||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
val task = ColumnTask_Gap(this, gap)
|
||||
|
||||
this.lastTask = task
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
task.start()
|
||||
fireShowColumnStatus()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package jp.juggler.subwaytooter
|
|||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.AsyncTask
|
||||
import android.os.SystemClock
|
||||
import jp.juggler.subwaytooter.api.TootApiClient
|
||||
import jp.juggler.subwaytooter.api.TootApiResult
|
||||
|
@ -12,6 +11,8 @@ import jp.juggler.subwaytooter.table.SavedAccount
|
|||
import jp.juggler.util.JsonObject
|
||||
import jp.juggler.util.WordTrieTree
|
||||
import jp.juggler.util.notEmpty
|
||||
import jp.juggler.util.withCaption
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
enum class ColumnTaskType {
|
||||
|
@ -24,15 +25,17 @@ enum class ColumnTaskType {
|
|||
abstract class ColumnTask(
|
||||
val column : Column,
|
||||
val ctType : ColumnTaskType
|
||||
) : AsyncTask<Void, Void, TootApiResult?>() {
|
||||
|
||||
override fun onCancelled(result : TootApiResult?) {
|
||||
onPostExecute(null)
|
||||
}
|
||||
) {
|
||||
|
||||
val ctStarted = AtomicBoolean(false)
|
||||
val ctClosed = AtomicBoolean(false)
|
||||
|
||||
var job : Job? = null
|
||||
|
||||
val isCancelled :Boolean
|
||||
get()= job?.isCancelled ?: false
|
||||
|
||||
|
||||
var parser = TootParser(context, access_info, highlightTrie = highlight_trie)
|
||||
|
||||
var list_tmp : ArrayList<TimelineItem>? = null
|
||||
|
@ -170,4 +173,28 @@ abstract class ColumnTask(
|
|||
}
|
||||
return TootApiResult()
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
job?.cancel()
|
||||
}
|
||||
|
||||
abstract fun doInBackground() : TootApiResult?
|
||||
abstract fun onPostExecute(result : TootApiResult?)
|
||||
|
||||
fun start() {
|
||||
job = GlobalScope.launch(Dispatchers.Main){
|
||||
|
||||
val result = try {
|
||||
withContext(Dispatchers.IO){
|
||||
doInBackground()
|
||||
}
|
||||
}catch(ex:CancellationException){
|
||||
null // キャンセルされたらresult==nullとする
|
||||
}catch(ex:Throwable){
|
||||
// その他のエラー
|
||||
TootApiResult(ex.withCaption("error"))
|
||||
}
|
||||
onPostExecute(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class ColumnTask_Gap(
|
|||
private var max_id : EntityId? = (gap as? TootGap)?.max_id
|
||||
private var since_id : EntityId? = (gap as? TootGap)?.since_id
|
||||
|
||||
override fun doInBackground(vararg unused : Void) : TootApiResult? {
|
||||
override fun doInBackground() : TootApiResult? {
|
||||
ctStarted.set(true)
|
||||
|
||||
val client = TootApiClient(context, callback = object : TootApiCallback {
|
||||
|
|
|
@ -18,7 +18,7 @@ class ColumnTask_Loading(
|
|||
|
||||
internal var list_pinned : ArrayList<TimelineItem>? = null
|
||||
|
||||
override fun doInBackground(vararg unused : Void) : TootApiResult? {
|
||||
override fun doInBackground() : TootApiResult? {
|
||||
ctStarted.set(true)
|
||||
|
||||
if(Pref.bpInstanceTicker(pref)) {
|
||||
|
|
|
@ -26,7 +26,7 @@ class ColumnTask_Refresh(
|
|||
|
||||
private var filterUpdated = false
|
||||
|
||||
override fun doInBackground(vararg unused : Void) : TootApiResult? {
|
||||
override fun doInBackground() : TootApiResult? {
|
||||
ctStarted.set(true)
|
||||
|
||||
val client = TootApiClient(context, callback = object : TootApiCallback {
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.graphics.Bitmap
|
|||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Path
|
||||
import android.os.AsyncTask
|
||||
import android.os.SystemClock
|
||||
import android.text.InputType
|
||||
import android.text.Spannable
|
||||
|
@ -38,11 +37,16 @@ import jp.juggler.subwaytooter.dialog.EmojiPicker
|
|||
import jp.juggler.subwaytooter.span.NetworkEmojiSpan
|
||||
import jp.juggler.subwaytooter.table.AcctColor
|
||||
import jp.juggler.subwaytooter.util.*
|
||||
import jp.juggler.subwaytooter.view.*
|
||||
import jp.juggler.subwaytooter.view.ListDivider
|
||||
import jp.juggler.subwaytooter.view.MyLinkMovementMethod
|
||||
import jp.juggler.subwaytooter.view.MyTextView
|
||||
import jp.juggler.subwaytooter.view.OutsideDrawerLayout
|
||||
import jp.juggler.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.anko.*
|
||||
import org.jetbrains.anko.custom.customView
|
||||
import java.io.Closeable
|
||||
import java.lang.Runnable
|
||||
import java.lang.reflect.Field
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
@ -178,7 +182,7 @@ class ColumnViewHolder(
|
|||
|
||||
private var last_image_uri : String? = null
|
||||
private var last_image_bitmap : Bitmap? = null
|
||||
private var last_image_task : AsyncTask<Void, Void, Bitmap?>? = null
|
||||
private var last_image_task : Job? = null
|
||||
|
||||
private fun checkRegexFilterError(src : String) : String? {
|
||||
try {
|
||||
|
@ -808,7 +812,7 @@ class ColumnViewHolder(
|
|||
last_image_bitmap?.recycle()
|
||||
last_image_bitmap = null
|
||||
|
||||
last_image_task?.cancel(true)
|
||||
last_image_task?.cancel()
|
||||
last_image_task = null
|
||||
|
||||
last_image_uri = null
|
||||
|
@ -842,41 +846,35 @@ class ColumnViewHolder(
|
|||
val screen_h = iv.resources.displayMetrics.heightPixels
|
||||
|
||||
// 非同期処理を開始
|
||||
val task = object : AsyncTask<Void, Void, Bitmap?>() {
|
||||
override fun doInBackground(vararg params : Void) : Bitmap? {
|
||||
return try {
|
||||
createResizedBitmap(
|
||||
activity, url.toUri(),
|
||||
if(screen_w > screen_h)
|
||||
screen_w
|
||||
else
|
||||
screen_h
|
||||
)
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(bitmap : Bitmap?) {
|
||||
onPostExecute(bitmap)
|
||||
}
|
||||
|
||||
override fun onPostExecute(bitmap : Bitmap?) {
|
||||
if(bitmap != null) {
|
||||
if(isCancelled || url != last_image_uri) {
|
||||
bitmap.recycle()
|
||||
} else {
|
||||
last_image_bitmap = bitmap
|
||||
iv.setImageBitmap(last_image_bitmap)
|
||||
iv.visibility = View.VISIBLE
|
||||
last_image_task = GlobalScope.launch(Dispatchers.Main){
|
||||
val bitmap = try{
|
||||
withContext(Dispatchers.IO){
|
||||
try {
|
||||
createResizedBitmap(
|
||||
activity, url.toUri(),
|
||||
if(screen_w > screen_h)
|
||||
screen_w
|
||||
else
|
||||
screen_h
|
||||
)
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
null
|
||||
}
|
||||
}
|
||||
}catch(ex:Throwable){
|
||||
null
|
||||
}
|
||||
if(bitmap != null) {
|
||||
if(!coroutineContext.isActive || url != last_image_uri) {
|
||||
bitmap.recycle()
|
||||
} else {
|
||||
last_image_bitmap = bitmap
|
||||
iv.setImageBitmap(last_image_bitmap)
|
||||
iv.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
last_image_task = task
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
}
|
||||
|
|
|
@ -2,22 +2,21 @@ package jp.juggler.subwaytooter.api
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.AsyncTask
|
||||
import android.os.Handler
|
||||
import android.os.SystemClock
|
||||
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.NumberFormat
|
||||
|
||||
import jp.juggler.subwaytooter.App1
|
||||
import jp.juggler.subwaytooter.api.entity.Host
|
||||
import jp.juggler.subwaytooter.dialog.ProgressDialogEx
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.util.dismissSafe
|
||||
import jp.juggler.util.withCaption
|
||||
import kotlinx.coroutines.*
|
||||
import java.lang.Runnable
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.NumberFormat
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/*
|
||||
非同期タスク(TootTask)を実行します。
|
||||
- 内部でAsyncTaskを使います。Android Lintの警告を抑制します
|
||||
APIクライアントを必要とする非同期タスク(TootTask)を実行します。
|
||||
- ProgressDialogを表示します。抑制することも可能です。
|
||||
- TootApiClientの初期化を行います
|
||||
- TootApiClientからの進捗イベントをProgressDialogに伝達します。
|
||||
|
@ -52,43 +51,15 @@ class TootTaskRunner(
|
|||
internal var max = 1
|
||||
}
|
||||
|
||||
// has AsyncTask
|
||||
private class MyTask(
|
||||
private val runner : TootTaskRunner
|
||||
) : AsyncTask<Void, Void, TootApiResult?>() {
|
||||
|
||||
var isActive : Boolean = true
|
||||
|
||||
override fun doInBackground(vararg voids : Void) : TootApiResult? {
|
||||
val callback = runner.callback
|
||||
return if(callback == null) {
|
||||
TootApiResult("callback is null")
|
||||
} else {
|
||||
callback.background(runner.client)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(result : TootApiResult?) {
|
||||
onPostExecute(result)
|
||||
}
|
||||
|
||||
override fun onPostExecute(result : TootApiResult?) {
|
||||
isActive = false
|
||||
runner.dismissProgress()
|
||||
runner.callback?.handleResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
private val handler : Handler
|
||||
private val client : TootApiClient
|
||||
private val task : MyTask
|
||||
private val info = ProgressInfo()
|
||||
private var progress : ProgressDialogEx? = null
|
||||
private var progress_prefix : String? = null
|
||||
private var task : Deferred<TootApiResult?>? = null
|
||||
|
||||
private val refContext : WeakReference<Context>
|
||||
|
||||
private var callback : TootTask? = null
|
||||
private var last_message_shown : Long = 0
|
||||
|
||||
private val proc_progress_message = object : Runnable {
|
||||
|
@ -105,19 +76,29 @@ class TootTaskRunner(
|
|||
this.refContext = WeakReference(context)
|
||||
this.handler = Handler(context.mainLooper)
|
||||
this.client = TootApiClient(context, callback = this)
|
||||
this.task = MyTask(this)
|
||||
}
|
||||
|
||||
private val _isActive = AtomicBoolean(true)
|
||||
|
||||
val isActive : Boolean
|
||||
get() = task.isActive
|
||||
get() = _isActive.get()
|
||||
|
||||
fun run(callback : TootTask) : TootTaskRunner {
|
||||
openProgress()
|
||||
|
||||
this.callback = callback
|
||||
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
openProgress()
|
||||
val result = try {
|
||||
withContext(Dispatchers.IO) {
|
||||
callback.background(client)
|
||||
}
|
||||
}catch(ex:CancellationException){
|
||||
null
|
||||
} catch(ex : Throwable) {
|
||||
TootApiResult(ex.withCaption("error"))
|
||||
}
|
||||
_isActive.set(false)
|
||||
dismissProgress()
|
||||
callback.handleResult(result)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -141,7 +122,7 @@ class TootTaskRunner(
|
|||
// implements TootApiClient.Callback
|
||||
|
||||
override val isApiCancelled : Boolean
|
||||
get() = task.isCancelled
|
||||
get() = task?.isActive == false
|
||||
|
||||
override fun publishApiProgress(s : String) {
|
||||
synchronized(this) {
|
||||
|
@ -171,7 +152,7 @@ class TootTaskRunner(
|
|||
val progress = ProgressDialogEx(context)
|
||||
this.progress = progress
|
||||
progress.setCancelable(true)
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.setOnCancelListener { task?.cancel() }
|
||||
progress.setProgressStyle(progress_style)
|
||||
progressSetupCallback(progress)
|
||||
showProgressMessage()
|
||||
|
|
|
@ -6,7 +6,7 @@ import jp.juggler.util.JsonObject
|
|||
|
||||
class MisskeyAntenna(parser:TootParser,src: JsonObject) :TimelineItem(){
|
||||
|
||||
val timeCreatedAt:Long // "2020-02-19T09:08:41.929Z"
|
||||
private val timeCreatedAt:Long // "2020-02-19T09:08:41.929Z"
|
||||
|
||||
val id: EntityId
|
||||
|
||||
|
@ -19,7 +19,7 @@ class MisskeyAntenna(parser:TootParser,src: JsonObject) :TimelineItem(){
|
|||
// "src":"list",
|
||||
// "src":"users",
|
||||
|
||||
val keywords: Array<Array<String>>
|
||||
private val keywords: Array<Array<String>>
|
||||
// "keywords":[[""]],
|
||||
// "keywords":[[""]],
|
||||
// "keywords":[[""]],
|
||||
|
@ -28,20 +28,20 @@ class MisskeyAntenna(parser:TootParser,src: JsonObject) :TimelineItem(){
|
|||
// "keywords":[["test"]],
|
||||
|
||||
// src=="group" の場合。他はnull
|
||||
val userGroupId : EntityId?
|
||||
private val userGroupId : EntityId?
|
||||
|
||||
// src=="list" の場合。他はnull
|
||||
val userListId : EntityId?
|
||||
private val userListId : EntityId?
|
||||
|
||||
val users : Array<String>
|
||||
// "users":[""],
|
||||
// "users":["@tateisu","@syuilo"],
|
||||
|
||||
val caseSensitive:Boolean
|
||||
val hasUnreadNote:Boolean
|
||||
val notify: Boolean
|
||||
val withFile : Boolean
|
||||
val withReplies : Boolean
|
||||
private val caseSensitive:Boolean
|
||||
private val hasUnreadNote:Boolean
|
||||
private val notify: Boolean
|
||||
private val withFile : Boolean
|
||||
private val withReplies : Boolean
|
||||
|
||||
init{
|
||||
timeCreatedAt = TootStatus.parseTime(src.string("createdAt"))
|
||||
|
|
|
@ -3,7 +3,6 @@ package jp.juggler.subwaytooter.dialog
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.DialogInterface
|
||||
import android.database.Cursor
|
||||
import android.os.AsyncTask
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
|
@ -12,17 +11,22 @@ import android.widget.ListView
|
|||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import jp.juggler.subwaytooter.ActPost
|
||||
import jp.juggler.subwaytooter.App1
|
||||
import jp.juggler.subwaytooter.R
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||
import jp.juggler.subwaytooter.table.PostDraft
|
||||
import jp.juggler.util.JsonObject
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.dismissSafe
|
||||
import jp.juggler.util.showToast
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener,
|
||||
DialogInterface.OnDismissListener {
|
||||
|
||||
companion object{
|
||||
private val log = LogCategory("DlgDraftPicker")
|
||||
}
|
||||
|
||||
private lateinit var activity : ActPost
|
||||
private lateinit var callback : (draft : JsonObject) -> Unit
|
||||
private lateinit var lvDraft : ListView
|
||||
|
@ -32,7 +36,7 @@ class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongCl
|
|||
private var cursor : Cursor? = null
|
||||
private var colIdx : PostDraft.ColIdx? = null
|
||||
|
||||
private var task : AsyncTask<Void, Void, Cursor?>? = null
|
||||
private var task : Job? = null
|
||||
|
||||
override fun onItemClick(parent : AdapterView<*>, view : View, position : Int, id : Long) {
|
||||
val json = getPostDraft(position)?.json
|
||||
|
@ -61,7 +65,7 @@ class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongCl
|
|||
}
|
||||
|
||||
override fun onDismiss(dialog : DialogInterface) {
|
||||
task?.cancel(true)
|
||||
task?.cancel()
|
||||
task = null
|
||||
|
||||
lvDraft.adapter = null
|
||||
|
@ -98,37 +102,32 @@ class DlgDraftPicker : AdapterView.OnItemClickListener, AdapterView.OnItemLongCl
|
|||
private fun reload() {
|
||||
|
||||
// cancel old task
|
||||
task?.cancel(true)
|
||||
task?.cancel()
|
||||
|
||||
val new_task = @SuppressLint("StaticFieldLeak")
|
||||
object : AsyncTask<Void, Void, Cursor?>() {
|
||||
override fun doInBackground(vararg params : Void) : Cursor? {
|
||||
return PostDraft.createCursor()
|
||||
task = GlobalScope.launch(Dispatchers.Main){
|
||||
val cursor =try {
|
||||
withContext(Dispatchers.IO) {
|
||||
PostDraft.createCursor()
|
||||
} ?: error("cursor is null")
|
||||
}catch(ex:CancellationException) {
|
||||
return@launch
|
||||
}catch(ex:Throwable){
|
||||
log.trace(ex)
|
||||
showToast(activity,ex, "failed to loading drafts.")
|
||||
return@launch
|
||||
}
|
||||
|
||||
override fun onCancelled(cursor : Cursor?) {
|
||||
onPostExecute(cursor)
|
||||
}
|
||||
|
||||
override fun onPostExecute(cursor : Cursor?) {
|
||||
if(! dialog.isShowing) {
|
||||
// dialog is already closed.
|
||||
cursor?.close()
|
||||
return
|
||||
}
|
||||
|
||||
if(cursor == null) {
|
||||
// load failed.
|
||||
showToast(activity, true, "failed to loading drafts.")
|
||||
} else {
|
||||
this@DlgDraftPicker.cursor = cursor
|
||||
colIdx = PostDraft.ColIdx(cursor)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
if(! dialog.isShowing) {
|
||||
// dialog is already closed.
|
||||
cursor.close()
|
||||
} else {
|
||||
val old = this@DlgDraftPicker.cursor
|
||||
this@DlgDraftPicker.cursor = cursor
|
||||
colIdx = PostDraft.ColIdx(cursor)
|
||||
adapter.notifyDataSetChanged()
|
||||
old?.close()
|
||||
}
|
||||
}
|
||||
this.task = new_task
|
||||
new_task.executeOnExecutor(App1.task_executor)
|
||||
}
|
||||
|
||||
private fun getPostDraft(position : Int) : PostDraft? {
|
||||
|
|
|
@ -3,23 +3,16 @@ package jp.juggler.subwaytooter.dialog
|
|||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.graphics.Bitmap
|
||||
import android.os.AsyncTask
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import jp.juggler.subwaytooter.ActMain
|
||||
import jp.juggler.subwaytooter.App1
|
||||
import jp.juggler.subwaytooter.R
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.dismissSafe
|
||||
import jp.juggler.util.showToast
|
||||
import net.glxn.qrgen.android.QRCode
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object DlgQRCode {
|
||||
|
||||
private val log = LogCategory("DlgQRCode")
|
||||
|
||||
internal interface QrCodeCallback {
|
||||
fun onQrCode(bitmap : Bitmap?)
|
||||
}
|
||||
|
@ -30,39 +23,18 @@ object DlgQRCode {
|
|||
url : String,
|
||||
callback : QrCodeCallback
|
||||
) {
|
||||
@Suppress("DEPRECATION")
|
||||
val progress = ProgressDialogEx(activity)
|
||||
val task = object : AsyncTask<Void, Void, Bitmap?>() {
|
||||
|
||||
override fun doInBackground(vararg params : Void) : Bitmap? {
|
||||
return try {
|
||||
QRCode.from(url).withSize(size, size).bitmap()
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(activity, ex, "makeQrCode failed.")
|
||||
null
|
||||
}
|
||||
activity.runWithProgress(
|
||||
"making QR code",
|
||||
{
|
||||
QRCode.from(url).withSize(size, size).bitmap()
|
||||
},
|
||||
{
|
||||
if(it != null) callback.onQrCode(it)
|
||||
},
|
||||
progressInitializer = {
|
||||
it.setMessageEx(activity.getString(R.string.generating_qr_code))
|
||||
}
|
||||
|
||||
override fun onCancelled(result : Bitmap?) {
|
||||
onPostExecute(result)
|
||||
}
|
||||
|
||||
override fun onPostExecute(result : Bitmap?) {
|
||||
progress.dismissSafe()
|
||||
if(result != null) {
|
||||
callback.onQrCode(result)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
progress.isIndeterminateEx = true
|
||||
progress.setCancelable(true)
|
||||
progress.setMessageEx(activity.getString(R.string.generating_qr_code))
|
||||
progress.setOnCancelListener { task.cancel(true) }
|
||||
progress.show()
|
||||
|
||||
task.executeOnExecutor(App1.task_executor)
|
||||
)
|
||||
}
|
||||
|
||||
fun open(activity : ActMain, message : CharSequence, url : String) {
|
||||
|
@ -96,10 +68,7 @@ object DlgQRCode {
|
|||
viewRoot.findViewById<View>(R.id.btnCancel).setOnClickListener { dialog.cancel() }
|
||||
|
||||
dialog.show()
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,4 +24,3 @@ org.gradle.caching=true
|
|||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.debug.obsoleteApi=true
|
||||
android.enableR8=true
|
||||
|
|
Loading…
Reference in New Issue