improved draft deletion
This commit is contained in:
parent
4e47cbb387
commit
ce4d921d7a
|
@ -34,8 +34,8 @@ android {
|
||||||
applicationId "org.mariotaku.twidere"
|
applicationId "org.mariotaku.twidere"
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 256
|
versionCode 257
|
||||||
versionName '3.3.38'
|
versionName '3.3.39'
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
|
|
||||||
buildConfigField 'boolean', 'LEAK_CANARY_ENABLED', 'Boolean.parseBoolean("true")'
|
buildConfigField 'boolean', 'LEAK_CANARY_ENABLED', 'Boolean.parseBoolean("true")'
|
||||||
|
|
|
@ -36,7 +36,6 @@ import android.support.v4.app.LoaderManager.LoaderCallbacks
|
||||||
import android.support.v4.content.CursorLoader
|
import android.support.v4.content.CursorLoader
|
||||||
import android.support.v4.content.Loader
|
import android.support.v4.content.Loader
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.AbsListView.MultiChoiceModeListener
|
import android.widget.AbsListView.MultiChoiceModeListener
|
||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
|
@ -44,7 +43,6 @@ import android.widget.AdapterView.OnItemClickListener
|
||||||
import android.widget.ListView
|
import android.widget.ListView
|
||||||
import kotlinx.android.synthetic.main.fragment_drafts.*
|
import kotlinx.android.synthetic.main.fragment_drafts.*
|
||||||
import org.mariotaku.kpreferences.get
|
import org.mariotaku.kpreferences.get
|
||||||
import org.mariotaku.ktextension.toStringArray
|
|
||||||
import org.mariotaku.sqliteqb.library.Columns.Column
|
import org.mariotaku.sqliteqb.library.Columns.Column
|
||||||
import org.mariotaku.sqliteqb.library.Expression
|
import org.mariotaku.sqliteqb.library.Expression
|
||||||
import org.mariotaku.sqliteqb.library.RawItemArray
|
import org.mariotaku.sqliteqb.library.RawItemArray
|
||||||
|
@ -59,14 +57,13 @@ import org.mariotaku.twidere.extension.selectAll
|
||||||
import org.mariotaku.twidere.extension.selectNone
|
import org.mariotaku.twidere.extension.selectNone
|
||||||
import org.mariotaku.twidere.extension.updateSelectionItems
|
import org.mariotaku.twidere.extension.updateSelectionItems
|
||||||
import org.mariotaku.twidere.model.Draft
|
import org.mariotaku.twidere.model.Draft
|
||||||
import org.mariotaku.twidere.model.ParcelableMediaUpdate
|
|
||||||
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras
|
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras
|
||||||
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts
|
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts
|
||||||
import org.mariotaku.twidere.service.LengthyOperationsService
|
import org.mariotaku.twidere.service.LengthyOperationsService
|
||||||
import org.mariotaku.twidere.util.AsyncTaskUtils
|
import org.mariotaku.twidere.util.AsyncTaskUtils
|
||||||
import org.mariotaku.twidere.util.JsonSerializer
|
import org.mariotaku.twidere.util.deleteDrafts
|
||||||
import java.io.File
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class DraftsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, OnItemClickListener, MultiChoiceModeListener {
|
class DraftsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, OnItemClickListener, MultiChoiceModeListener {
|
||||||
|
@ -264,43 +261,19 @@ class DraftsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, OnItemClickList
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DeleteDraftsTask(
|
private class DeleteDraftsTask(
|
||||||
private val activity: FragmentActivity,
|
activity: FragmentActivity,
|
||||||
private val ids: LongArray
|
private val ids: LongArray
|
||||||
) : AsyncTask<Any, Any, Unit>() {
|
) : AsyncTask<Any, Any, Unit>() {
|
||||||
private val notificationManager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
|
private val activityRef = WeakReference(activity)
|
||||||
|
|
||||||
override fun doInBackground(vararg params: Any) {
|
override fun doInBackground(vararg params: Any) {
|
||||||
val resolver = activity.contentResolver
|
val activity = activityRef.get() ?: return
|
||||||
val where = Expression.inArgs(Column(Drafts._ID), ids.size)
|
deleteDrafts(activity, ids)
|
||||||
val projection = arrayOf(Drafts.MEDIA)
|
|
||||||
val selection = where.sql
|
|
||||||
val selectionArgs = ids.toStringArray()
|
|
||||||
val c = resolver.query(Drafts.CONTENT_URI, projection, selection, selectionArgs, null) ?: return
|
|
||||||
@Suppress("ConvertTryFinallyToUseCall")
|
|
||||||
try {
|
|
||||||
val idxMedia = c.getColumnIndex(Drafts.MEDIA)
|
|
||||||
c.moveToFirst()
|
|
||||||
while (!c.isAfterLast) {
|
|
||||||
val mediaArray = JsonSerializer.parseArray(c.getString(idxMedia), ParcelableMediaUpdate::class.java)
|
|
||||||
mediaArray?.forEach { media ->
|
|
||||||
val uri = Uri.parse(media.uri)
|
|
||||||
if ("file" == uri.scheme) {
|
|
||||||
val file = File(uri.path)
|
|
||||||
if (!file.delete()) {
|
|
||||||
Log.w(LOGTAG, String.format("Unable to delete %s", file))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.moveToNext()
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close()
|
|
||||||
}
|
|
||||||
resolver.delete(Drafts.CONTENT_URI, selection, selectionArgs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPreExecute() {
|
override fun onPreExecute() {
|
||||||
super.onPreExecute()
|
val activity = activityRef.get() ?: return
|
||||||
(activity as IExtendedActivity<*>).executeAfterFragmentResumed { activity ->
|
(activity as IExtendedActivity<*>).executeAfterFragmentResumed { activity ->
|
||||||
val f = ProgressDialogFragment.show(activity.supportFragmentManager, FRAGMENT_TAG_DELETING_DRAFTS)
|
val f = ProgressDialogFragment.show(activity.supportFragmentManager, FRAGMENT_TAG_DELETING_DRAFTS)
|
||||||
f.isCancelable = false
|
f.isCancelable = false
|
||||||
|
@ -308,7 +281,7 @@ class DraftsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, OnItemClickList
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPostExecute(result: Unit) {
|
override fun onPostExecute(result: Unit) {
|
||||||
super.onPostExecute(result)
|
val activity = activityRef.get() ?: return
|
||||||
(activity as IExtendedActivity<*>).executeAfterFragmentResumed { activity ->
|
(activity as IExtendedActivity<*>).executeAfterFragmentResumed { activity ->
|
||||||
val fm = activity.supportFragmentManager
|
val fm = activity.supportFragmentManager
|
||||||
val f = fm.findFragmentByTag(FRAGMENT_TAG_DELETING_DRAFTS)
|
val f = fm.findFragmentByTag(FRAGMENT_TAG_DELETING_DRAFTS)
|
||||||
|
@ -316,6 +289,7 @@ class DraftsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, OnItemClickList
|
||||||
f.dismiss()
|
f.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val notificationManager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
ids.forEach { id ->
|
ids.forEach { id ->
|
||||||
val tag = Uri.withAppendedPath(Drafts.CONTENT_URI, id.toString()).toString()
|
val tag = Uri.withAppendedPath(Drafts.CONTENT_URI, id.toString()).toString()
|
||||||
notificationManager.cancel(tag, NOTIFICATION_ID_DRAFTS)
|
notificationManager.cancel(tag, NOTIFICATION_ID_DRAFTS)
|
||||||
|
|
|
@ -26,7 +26,6 @@ import android.app.Service
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Point
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
@ -41,6 +40,8 @@ import android.widget.Toast
|
||||||
import edu.tsinghua.hotmobi.HotMobiLogger
|
import edu.tsinghua.hotmobi.HotMobiLogger
|
||||||
import edu.tsinghua.hotmobi.model.TimelineType
|
import edu.tsinghua.hotmobi.model.TimelineType
|
||||||
import edu.tsinghua.hotmobi.model.TweetEvent
|
import edu.tsinghua.hotmobi.model.TweetEvent
|
||||||
|
import nl.komponents.kovenant.task
|
||||||
|
import nl.komponents.kovenant.ui.successUi
|
||||||
import org.mariotaku.abstask.library.ManualTaskStarter
|
import org.mariotaku.abstask.library.ManualTaskStarter
|
||||||
import org.mariotaku.ktextension.configure
|
import org.mariotaku.ktextension.configure
|
||||||
import org.mariotaku.ktextension.toLong
|
import org.mariotaku.ktextension.toLong
|
||||||
|
@ -70,8 +71,8 @@ import org.mariotaku.twidere.task.twitter.UpdateStatusTask
|
||||||
import org.mariotaku.twidere.util.ContentValuesCreator
|
import org.mariotaku.twidere.util.ContentValuesCreator
|
||||||
import org.mariotaku.twidere.util.NotificationManagerWrapper
|
import org.mariotaku.twidere.util.NotificationManagerWrapper
|
||||||
import org.mariotaku.twidere.util.Utils
|
import org.mariotaku.twidere.util.Utils
|
||||||
|
import org.mariotaku.twidere.util.deleteDrafts
|
||||||
import org.mariotaku.twidere.util.io.ContentLengthInputStream.ReadListener
|
import org.mariotaku.twidere.util.io.ContentLengthInputStream.ReadListener
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@ -147,12 +148,17 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("Recycle")
|
||||||
private fun handleDiscardDraftIntent(intent: Intent) {
|
private fun handleDiscardDraftIntent(intent: Intent) {
|
||||||
val data = intent.data ?: return
|
val data = intent.data ?: return
|
||||||
notificationManager.cancel(data.toString(), NOTIFICATION_ID_DRAFTS)
|
task {
|
||||||
val id = data.lastPathSegment.toLong(-1)
|
if (deleteDrafts(this, longArrayOf(data.lastPathSegment.toLong(-1))) < 1) {
|
||||||
val where = Expression.equals(Drafts._ID, id)
|
throw IOException()
|
||||||
contentResolver.delete(Drafts.CONTENT_URI, where.sql, null)
|
}
|
||||||
|
return@task data
|
||||||
|
}.successUi { uri ->
|
||||||
|
notificationManager.cancel(data.toString(), NOTIFICATION_ID_DRAFTS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSendDirectMessageIntent(intent: Intent) {
|
private fun handleSendDirectMessageIntent(intent: Intent) {
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
package org.mariotaku.twidere.util
|
package org.mariotaku.twidere.util
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.net.Uri
|
||||||
import org.mariotaku.kpreferences.get
|
import org.mariotaku.kpreferences.get
|
||||||
|
import org.mariotaku.ktextension.useCursor
|
||||||
|
import org.mariotaku.pickncrop.library.PNCUtils
|
||||||
import org.mariotaku.sqliteqb.library.*
|
import org.mariotaku.sqliteqb.library.*
|
||||||
import org.mariotaku.twidere.constant.filterPossibilitySensitiveStatusesKey
|
import org.mariotaku.twidere.constant.filterPossibilitySensitiveStatusesKey
|
||||||
import org.mariotaku.twidere.constant.filterUnavailableQuoteStatusesKey
|
import org.mariotaku.twidere.constant.filterUnavailableQuoteStatusesKey
|
||||||
|
import org.mariotaku.twidere.model.DraftCursorIndices
|
||||||
import org.mariotaku.twidere.model.ParcelableStatus.FilterFlags
|
import org.mariotaku.twidere.model.ParcelableStatus.FilterFlags
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
|
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mariotaku on 2016/12/24.
|
* Created by mariotaku on 2016/12/24.
|
||||||
|
@ -76,3 +81,27 @@ fun buildStatusFilterWhereClause(preferences: SharedPreferences,
|
||||||
}
|
}
|
||||||
return filterExpression
|
return filterExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("Recycle")
|
||||||
|
fun deleteDrafts(context: Context, draftIds: LongArray): Int {
|
||||||
|
val where = Expression.inArgs(Drafts._ID, draftIds.size).sql
|
||||||
|
val whereArgs = draftIds.map(Long::toString).toTypedArray()
|
||||||
|
|
||||||
|
context.contentResolver.query(Drafts.CONTENT_URI, Drafts.COLUMNS, where, whereArgs,
|
||||||
|
null).useCursor { cursor ->
|
||||||
|
val indices = DraftCursorIndices(cursor)
|
||||||
|
cursor.moveToFirst()
|
||||||
|
while (!cursor.isAfterLast) {
|
||||||
|
val draft = indices.newObject(cursor)
|
||||||
|
draft.media?.forEach { item ->
|
||||||
|
try {
|
||||||
|
PNCUtils.deleteMedia(context, Uri.parse(item.uri))
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.moveToNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return context.contentResolver.delete(Drafts.CONTENT_URI, where, whereArgs)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue