From 1ecd3acdba546d97cf3f8b15803d0a461d94dfcb Mon Sep 17 00:00:00 2001 From: Tlaster Date: Mon, 20 Apr 2020 15:10:15 +0800 Subject: [PATCH 01/13] Fix #1254 --- .../java/org/mariotaku/twidere/util/MicroBlogAPIFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/MicroBlogAPIFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/MicroBlogAPIFactory.java index 3446d8e0fe..d3004522a4 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/MicroBlogAPIFactory.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/MicroBlogAPIFactory.java @@ -111,7 +111,7 @@ public static String getApiBaseUrl(@NonNull String format, @Nullable final Strin } else if (TextUtils.isEmpty(domain)) { baseUrl = matcher.replaceAll(""); } else { - baseUrl = matcher.replaceAll("$1" + domain + "." + "$2"); + baseUrl = matcher.replaceAll("$1" + domain + "$2" + "$3"); } // In case someone set invalid base url if (HttpUrl.parse(baseUrl) == null) { From aab797dae71f5f743cd96300a7e27bec84dfea07 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Mon, 20 Apr 2020 18:14:47 +0800 Subject: [PATCH 02/13] Fix #1251 --- ...xportImportTypeSelectorDialogFragment.java | 5 +- .../twidere/util/DataImportExportUtils.java | 216 ++++++++++-------- .../twidere/activity/DataExportActivity.kt | 23 +- .../twidere/activity/DataImportActivity.kt | 31 +-- .../twidere/activity/FileSelectorActivity.kt | 50 +++- 5 files changed, 196 insertions(+), 129 deletions(-) diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/DataExportImportTypeSelectorDialogFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/DataExportImportTypeSelectorDialogFragment.java index cd4ea42b06..ab3f95d0af 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/fragment/DataExportImportTypeSelectorDialogFragment.java +++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/DataExportImportTypeSelectorDialogFragment.java @@ -25,6 +25,7 @@ import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.content.DialogInterface.OnShowListener; +import android.net.Uri; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -157,7 +158,7 @@ private void onPositiveButtonClicked(final int flags) { final FragmentActivity a = getActivity(); final Bundle args = getArguments(); if (args == null) return; - final String path = args.getString(EXTRA_PATH); + final Uri path = args.getParcelable(EXTRA_PATH); if (a instanceof Callback) { ((Callback) a).onPositiveButtonClicked(path, flags); } @@ -171,7 +172,7 @@ private void updatePositiveButton(final DialogInterface dialog) { } public interface Callback extends ISupportDialogFragmentCallback { - void onPositiveButtonClicked(String path, int flags); + void onPositiveButtonClicked(Uri path, int flags); } private static class Type { diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java b/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java index 09ba124a86..775fb8efc4 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java @@ -28,12 +28,14 @@ import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; +import androidx.documentfile.provider.DocumentFile; import com.bluelinelabs.logansquare.LoganSquare; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; +import org.mariotaku.commons.logansquare.LoganSquareMapperFinder; import org.mariotaku.library.exportablepreferences.PreferencesExporter; import org.mariotaku.library.exportablepreferences.annotation.PreferenceType; import org.mariotaku.library.objectcursor.ObjectCursor; @@ -44,20 +46,29 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Filters; import org.mariotaku.twidere.provider.TwidereDataStore.Tabs; import org.mariotaku.twidere.util.content.ContentResolverUtils; +import org.osmdroid.tileprovider.modules.ZipFileArchive; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import javax.annotation.Nonnull; + public class DataImportExportUtils implements Constants { public static final String ENTRY_PREFERENCES = "preferences.json"; @@ -79,9 +90,8 @@ public class DataImportExportUtils implements Constants { | FLAG_HOST_MAPPING | FLAG_KEYBOARD_SHORTCUTS | FLAG_FILTERS | FLAG_TABS; @WorkerThread - public static void exportData(final Context context, @NonNull final File dst, final int flags) throws IOException { - dst.delete(); - try (FileOutputStream fos = new FileOutputStream(dst); + public static void exportData(final Context context, @NonNull final DocumentFile dst, final int flags) throws IOException { + try (OutputStream fos = context.getContentResolver().openOutputStream(dst.getUri()); ZipOutputStream zos = new ZipOutputStream(fos)) { if (hasFlag(flags, FLAG_PREFERENCES)) { exportSharedPreferencesData(zos, context, SHARED_PREFERENCES_NAME, ENTRY_PREFERENCES, @@ -161,104 +171,122 @@ private static List queryAll(ContentResolver cr, Uri uri, String[] projec } @WorkerThread - public static int getImportedSettingsFlags(@NonNull final File src) throws IOException { - try (ZipFile zipFile = new ZipFile(src)) { + public static int getImportedSettingsFlags(@NonNull final Context context, @NonNull final DocumentFile src) throws IOException { + try (InputStream inputStream = context.getContentResolver().openInputStream(src.getUri()); + ZipInputStream zipInputStream = new ZipInputStream(inputStream)) { int flags = 0; - if (zipFile.getEntry(ENTRY_PREFERENCES) != null) { + List entryNames = new ArrayList<>(); + ZipEntry entry = null; + while ((entry = zipInputStream.getNextEntry()) != null) { + entryNames.add(entry.getName()); + } + if (entryNames.contains(ENTRY_PREFERENCES)) { flags |= FLAG_PREFERENCES; } - if (zipFile.getEntry(ENTRY_NICKNAMES) != null) { + if (entryNames.contains(ENTRY_NICKNAMES)) { flags |= FLAG_NICKNAMES; } - if (zipFile.getEntry(ENTRY_USER_COLORS) != null) { + if (entryNames.contains(ENTRY_USER_COLORS)) { flags |= FLAG_USER_COLORS; } - if (zipFile.getEntry(ENTRY_HOST_MAPPING) != null) { + if (entryNames.contains(ENTRY_HOST_MAPPING)) { flags |= FLAG_HOST_MAPPING; } - if (zipFile.getEntry(ENTRY_KEYBOARD_SHORTCUTS) != null) { + if (entryNames.contains(ENTRY_KEYBOARD_SHORTCUTS)) { flags |= FLAG_KEYBOARD_SHORTCUTS; } - if (zipFile.getEntry(ENTRY_FILTERS) != null) { + if (entryNames.contains(ENTRY_FILTERS)) { flags |= FLAG_FILTERS; } - if (zipFile.getEntry(ENTRY_TABS) != null) { + if (entryNames.contains(ENTRY_TABS)) { flags |= FLAG_TABS; } return flags; } } - public static void importData(final Context context, final File src, final int flags) throws IOException { + public static void importData(final Context context, final DocumentFile src, final int flags) throws IOException { if (src == null) throw new FileNotFoundException(); - try (ZipFile zipFile = new ZipFile(src)) { - if (hasFlag(flags, FLAG_PREFERENCES)) { - importSharedPreferencesData(zipFile, context, SHARED_PREFERENCES_NAME, ENTRY_PREFERENCES, - new PreferencesExporterStrategy(SharedPreferenceConstants.class)); - } - if (hasFlag(flags, FLAG_NICKNAMES)) { - importSharedPreferencesData(zipFile, context, USER_NICKNAME_PREFERENCES_NAME, ENTRY_NICKNAMES, - ConvertToStringProcessStrategy.SINGLETON); - } - if (hasFlag(flags, FLAG_USER_COLORS)) { - importSharedPreferencesData(zipFile, context, USER_COLOR_PREFERENCES_NAME, ENTRY_USER_COLORS, - ConvertToIntProcessStrategy.SINGLETON); - } - if (hasFlag(flags, FLAG_HOST_MAPPING)) { - importSharedPreferencesData(zipFile, context, HOST_MAPPING_PREFERENCES_NAME, ENTRY_HOST_MAPPING, - ConvertToStringProcessStrategy.SINGLETON); - } - if (hasFlag(flags, FLAG_KEYBOARD_SHORTCUTS)) { - importSharedPreferencesData(zipFile, context, KEYBOARD_SHORTCUTS_PREFERENCES_NAME, - ENTRY_KEYBOARD_SHORTCUTS, ConvertToStringProcessStrategy.SINGLETON); - } - if (hasFlag(flags, FLAG_FILTERS)) { - importItem(context, zipFile, ENTRY_FILTERS, FiltersData.class, new ContentResolverProcessStrategy() { - @Override - public boolean importItem(ContentResolver cr, FiltersData filtersData) throws IOException { - if (filtersData == null) return false; - insertBase(cr, Filters.Keywords.CONTENT_URI, filtersData.getKeywords()); - insertBase(cr, Filters.Sources.CONTENT_URI, filtersData.getSources()); - insertBase(cr, Filters.Links.CONTENT_URI, filtersData.getLinks()); - insertUser(cr, Filters.Users.CONTENT_URI, filtersData.getUsers()); - return true; - } + try (InputStream inputStream = context.getContentResolver().openInputStream(src.getUri()); + ZipInputStream zipInputStream = new ZipInputStream(inputStream) + ) { + ZipEntry entry = null; + while ((entry = zipInputStream.getNextEntry()) != null) { + StringBuilder stringBuilder = new StringBuilder(); + byte[] buffer = new byte[1024]; + int read = 0; + while ((read = zipInputStream.read(buffer, 0, 1024)) >= 0) { + stringBuilder.append(new String(buffer, 0, read)); + } + String data = stringBuilder.toString(); + if (hasFlag(flags, FLAG_PREFERENCES)) { + importSharedPreferencesData(entry, context, SHARED_PREFERENCES_NAME, ENTRY_PREFERENCES, + new PreferencesExporterStrategy(SharedPreferenceConstants.class), data); + } + if (hasFlag(flags, FLAG_NICKNAMES)) { + importSharedPreferencesData(entry, context, USER_NICKNAME_PREFERENCES_NAME, ENTRY_NICKNAMES, + ConvertToStringProcessStrategy.SINGLETON, data); + } + if (hasFlag(flags, FLAG_USER_COLORS)) { + importSharedPreferencesData(entry, context, USER_COLOR_PREFERENCES_NAME, ENTRY_USER_COLORS, + ConvertToIntProcessStrategy.SINGLETON, data); + } + if (hasFlag(flags, FLAG_HOST_MAPPING)) { + importSharedPreferencesData(entry, context, HOST_MAPPING_PREFERENCES_NAME, ENTRY_HOST_MAPPING, + ConvertToStringProcessStrategy.SINGLETON, data); + } + if (hasFlag(flags, FLAG_KEYBOARD_SHORTCUTS)) { + importSharedPreferencesData(entry, context, KEYBOARD_SHORTCUTS_PREFERENCES_NAME, + ENTRY_KEYBOARD_SHORTCUTS, ConvertToStringProcessStrategy.SINGLETON, data); + } + if (hasFlag(flags, FLAG_FILTERS)) { + importItem(context, entry, ENTRY_FILTERS, FiltersData.class, data, new ContentResolverProcessStrategy() { + @Override + public boolean importItem(ContentResolver cr, FiltersData filtersData) throws IOException { + if (filtersData == null) return false; + insertBase(cr, Filters.Keywords.CONTENT_URI, filtersData.getKeywords()); + insertBase(cr, Filters.Sources.CONTENT_URI, filtersData.getSources()); + insertBase(cr, Filters.Links.CONTENT_URI, filtersData.getLinks()); + insertUser(cr, Filters.Users.CONTENT_URI, filtersData.getUsers()); + return true; + } - void insertBase(ContentResolver cr, Uri uri, List items) throws IOException { - if (items == null) return; - final ObjectCursor.ValuesCreator baseItemCreator = - ObjectCursor.valuesCreatorFrom(FiltersData.BaseItem.class); - List values = new ArrayList<>(items.size()); - for (FiltersData.BaseItem item : items) { - values.add(baseItemCreator.create(item)); + void insertBase(ContentResolver cr, Uri uri, List items) throws IOException { + if (items == null) return; + final ObjectCursor.ValuesCreator baseItemCreator = + ObjectCursor.valuesCreatorFrom(FiltersData.BaseItem.class); + List values = new ArrayList<>(items.size()); + for (FiltersData.BaseItem item : items) { + values.add(baseItemCreator.create(item)); + } + ContentResolverUtils.bulkInsert(cr, uri, values); } - ContentResolverUtils.bulkInsert(cr, uri, values); - } - void insertUser(ContentResolver cr, Uri uri, List items) throws IOException { - if (items == null) return; - final ObjectCursor.ValuesCreator userItemCreator = - ObjectCursor.valuesCreatorFrom(FiltersData.UserItem.class); + void insertUser(ContentResolver cr, Uri uri, List items) throws IOException { + if (items == null) return; + final ObjectCursor.ValuesCreator userItemCreator = + ObjectCursor.valuesCreatorFrom(FiltersData.UserItem.class); + List values = new ArrayList<>(items.size()); + for (FiltersData.UserItem item : items) { + values.add(userItemCreator.create(item)); + } + ContentResolverUtils.bulkInsert(cr, uri, values); + } + }); + } + if (hasFlag(flags, FLAG_TABS)) { + final ObjectCursor.ValuesCreator creator = ObjectCursor.valuesCreatorFrom(Tab.class); + importItemsList(context, entry, ENTRY_TABS, Tab.class, data, (cr, items) -> { + if (items == null) return false; List values = new ArrayList<>(items.size()); - for (FiltersData.UserItem item : items) { - values.add(userItemCreator.create(item)); + for (Tab item : items) { + values.add(creator.create(item)); } - ContentResolverUtils.bulkInsert(cr, uri, values); - } - }); - } - if (hasFlag(flags, FLAG_TABS)) { - final ObjectCursor.ValuesCreator creator = ObjectCursor.valuesCreatorFrom(Tab.class); - importItemsList(context, zipFile, ENTRY_TABS, Tab.class, (cr, items) -> { - if (items == null) return false; - List values = new ArrayList<>(items.size()); - for (Tab item : items) { - values.add(creator.create(item)); - } - cr.delete(Tabs.CONTENT_URI, null, null); - ContentResolverUtils.bulkInsert(cr, Tabs.CONTENT_URI, values); - return true; - }); + cr.delete(Tabs.CONTENT_URI, null, null); + ContentResolverUtils.bulkInsert(cr, Tabs.CONTENT_URI, values); + return true; + }); + } } } } @@ -267,12 +295,12 @@ private static boolean hasFlag(final int flags, final int flag) { return (flags & flag) != 0; } - private static void importSharedPreferencesData(@NonNull final ZipFile zipFile, @NonNull final Context context, + private static void importSharedPreferencesData(@NonNull final ZipEntry entry, @NonNull final Context context, @NonNull final String preferencesName, @NonNull final String entryName, - @NonNull final SharedPreferencesProcessStrategy strategy) throws IOException { - final ZipEntry entry = zipFile.getEntry(entryName); - if (entry == null) return; - final JsonParser jsonParser = LoganSquare.JSON_FACTORY.createParser(zipFile.getInputStream(entry)); + @NonNull final SharedPreferencesProcessStrategy strategy, + @NonNull final String data) throws IOException { + if (!Objects.equals(entry.getName(), entryName)) return; + final JsonParser jsonParser = LoganSquare.JSON_FACTORY.createParser(data); if (jsonParser.getCurrentToken() == null) { jsonParser.nextToken(); } @@ -300,14 +328,14 @@ private static void exportSharedPreferencesData(@NonNull final ZipOutputStream z } private static void importItemsList(@NonNull final Context context, - @NonNull final ZipFile zipFile, + @NonNull final ZipEntry entry, @NonNull final String entryName, @NonNull final Class itemCls, + @NonNull final String data, @NonNull final ContentResolverProcessStrategy> strategy) throws IOException { - final ZipEntry entry = zipFile.getEntry(entryName); - if (entry == null) return; - List itemsList = JsonSerializer.parseList(zipFile.getInputStream(entry), itemCls); + if (!Objects.equals(entry.getName(), entryName)) return; + List itemsList = JsonSerializer.parseList(data, itemCls); strategy.importItem(context.getContentResolver(), itemsList); } @@ -317,19 +345,22 @@ private static void exportItemsList(@NonNull final ZipOutputStream zos, @NonNull final Class itemCls, @NonNull final List itemList) throws IOException { zos.putNextEntry(new ZipEntry(entryName)); - JsonSerializer.serialize(itemList, zos, itemCls); + String json = LoganSquare.serialize(itemList); + OutputStreamWriter writer = new OutputStreamWriter(zos); + writer.write(json); + writer.flush(); zos.closeEntry(); } private static void importItem(@NonNull final Context context, - @NonNull final ZipFile zipFile, + @NonNull final ZipEntry entry, @NonNull final String entryName, @NonNull final Class itemCls, + @NonNull final String data, @NonNull final ContentResolverProcessStrategy strategy) throws IOException { - final ZipEntry entry = zipFile.getEntry(entryName); - if (entry == null) return; - T item = JsonSerializer.parse(zipFile.getInputStream(entry), itemCls); + if (!Objects.equals(entry.getName(), entryName)) return; + T item = JsonSerializer.parse(data, itemCls); strategy.importItem(context.getContentResolver(), item); } @@ -339,7 +370,10 @@ private static void exportItem(@NonNull final ZipOutputStream zos, @NonNull final Class itemCls, @NonNull final T item) throws IOException { zos.putNextEntry(new ZipEntry(entryName)); - JsonSerializer.serialize(item, zos, itemCls); + String json = LoganSquare.serialize(item); + OutputStreamWriter writer = new OutputStreamWriter(zos); + writer.write(json); + writer.flush(); zos.closeEntry(); } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt index 6e19b828cf..094f7909c1 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt @@ -2,10 +2,12 @@ package org.mariotaku.twidere.activity import android.app.Activity import android.content.Intent +import android.net.Uri import android.os.AsyncTask import android.os.Bundle -import androidx.fragment.app.DialogFragment import android.util.Log +import androidx.documentfile.provider.DocumentFile +import androidx.fragment.app.DialogFragment import org.mariotaku.ktextension.dismissDialogFragment import org.mariotaku.twidere.Constants.* import org.mariotaku.twidere.R @@ -13,7 +15,6 @@ import org.mariotaku.twidere.constant.IntentConstants import org.mariotaku.twidere.fragment.DataExportImportTypeSelectorDialogFragment import org.mariotaku.twidere.fragment.ProgressDialogFragment import org.mariotaku.twidere.util.DataImportExportUtils -import java.io.File import java.io.IOException import java.text.SimpleDateFormat import java.util.* @@ -39,10 +40,10 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra REQUEST_PICK_DIRECTORY -> { executeAfterFragmentResumed { if (resultCode == RESULT_OK && data != null) { - val path = data.data?.path + val path = data.data val df = DataExportImportTypeSelectorDialogFragment() val args = Bundle() - args.putString(EXTRA_PATH, path) + args.putParcelable(EXTRA_PATH, path) args.putString(EXTRA_TITLE, getString(R.string.export_settings_type_dialog_title)) df.arguments = args df.show(supportFragmentManager, "select_export_type") @@ -58,13 +59,13 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra super.onActivityResult(requestCode, resultCode, data) } - override fun onPositiveButtonClicked(path: String?, flags: Int) { + override fun onPositiveButtonClicked(path: Uri?, flags: Int) { if (path == null || flags == 0) { finish() return } if (task == null || task!!.status != AsyncTask.Status.RUNNING) { - task = ExportSettingsTask(this, path, flags) + task = ExportSettingsTask(this, DocumentFile.fromTreeUri(this, path), flags) task!!.execute() } } @@ -85,16 +86,18 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra internal class ExportSettingsTask( private val activity: DataExportActivity, - private val path: String?, + private val folder: DocumentFile?, private val flags: Int ) : AsyncTask() { override fun doInBackground(vararg params: Any): Boolean? { - if (path == null) return false + if (folder == null || !folder.isDirectory) return false val sdf = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US) val fileName = String.format("Twidere_Settings_%s.zip", sdf.format(Date())) - val file = File(path, fileName) - file.delete() + val file = folder.findFile(fileName) ?: folder.createFile("application/zip", fileName) + ?: return false +// val file = File(folder, fileName) +// file.delete() try { DataImportExportUtils.exportData(activity, file, flags) return true diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt index 97623cacdd..c4ac8d46dd 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt @@ -1,17 +1,18 @@ package org.mariotaku.twidere.activity import android.content.Intent +import android.net.Uri import android.os.AsyncTask import android.os.Bundle -import androidx.fragment.app.DialogFragment import android.util.Log +import androidx.documentfile.provider.DocumentFile +import androidx.fragment.app.DialogFragment import org.mariotaku.ktextension.dismissDialogFragment import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.* import org.mariotaku.twidere.fragment.DataExportImportTypeSelectorDialogFragment import org.mariotaku.twidere.fragment.ProgressDialogFragment import org.mariotaku.twidere.util.DataImportExportUtils -import java.io.File import java.io.IOException class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFragment.Callback { @@ -37,9 +38,9 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra REQUEST_PICK_FILE -> { resumeFragmentsRunnable = Runnable { if (resultCode == RESULT_OK && data != null) { - val path = data.data?.path + val path = data.data!! if (openImportTypeTask == null || openImportTypeTask!!.status != AsyncTask.Status.RUNNING) { - openImportTypeTask = OpenImportTypeTask(this@DataImportActivity, path) + openImportTypeTask = OpenImportTypeTask(this@DataImportActivity, DocumentFile.fromSingleUri(this, path)) openImportTypeTask!!.execute() } } else { @@ -62,13 +63,13 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra } } - override fun onPositiveButtonClicked(path: String?, flags: Int) { + override fun onPositiveButtonClicked(path: Uri?, flags: Int) { if (path == null || flags == 0) { finish() return } if (importSettingsTask == null || importSettingsTask!!.status != AsyncTask.Status.RUNNING) { - importSettingsTask = ImportSettingsTask(this, path, flags) + importSettingsTask = ImportSettingsTask(this, DocumentFile.fromSingleUri(this, path), flags) importSettingsTask!!.execute() } } @@ -89,13 +90,14 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra internal class ImportSettingsTask( private val activity: DataImportActivity, - private val path: String?, + private val file: DocumentFile?, private val flags: Int ) : AsyncTask() { override fun doInBackground(vararg params: Any): Boolean? { - if (path == null) return false - val file = File(path) + if (file == null) { + return false + } if (!file.isFile) return false try { DataImportExportUtils.importData(activity, file, flags) @@ -131,14 +133,15 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra } - internal class OpenImportTypeTask(private val activity: DataImportActivity, private val path: String?) : AsyncTask() { + internal class OpenImportTypeTask(private val activity: DataImportActivity, private val file: DocumentFile?) : AsyncTask() { override fun doInBackground(vararg params: Any): Int? { - if (path == null) return 0 - val file = File(path) + if (file == null) { + return 0 + } if (!file.isFile) return 0 try { - return DataImportExportUtils.getImportedSettingsFlags(file) + return DataImportExportUtils.getImportedSettingsFlags(activity, file) } catch (e: IOException) { return 0 } @@ -151,7 +154,7 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra } val df = DataExportImportTypeSelectorDialogFragment() val args = Bundle() - args.putString(EXTRA_PATH, path) + args.putParcelable(EXTRA_PATH, file?.uri) args.putString(EXTRA_TITLE, activity.getString(R.string.import_settings_type_dialog_title)) if (flags != null) { args.putInt(EXTRA_FLAGS, flags) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt index 85a84df2da..8ab5ef903a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt @@ -24,22 +24,22 @@ import android.content.Intent import android.net.Uri import android.os.Build import android.os.Bundle -import android.os.Environment.getExternalStorageDirectory +import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.fragment.app.DialogFragment -import android.widget.Toast -import org.mariotaku.ktextension.Bundle import org.mariotaku.ktextension.checkAllSelfPermissionsGranted -import org.mariotaku.ktextension.set import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.REQUEST_REQUEST_PERMISSIONS -import org.mariotaku.twidere.constant.IntentConstants.* +import org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_PICK_DIRECTORY +import org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_PICK_FILE import org.mariotaku.twidere.fragment.FileSelectorDialogFragment import java.io.File import android.Manifest.permission as AndroidPermissions class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback { + private val PICKER_REQUEST_CODE: Int = 54837 + override fun onCancelled(df: DialogFragment) { if (!isFinishing) { finish() @@ -101,15 +101,41 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback finish() } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == PICKER_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) { + setResult(Activity.RESULT_OK, Intent().also { it.data = data.data }) + finish() + } else { + if (!isFinishing) { + finish() + } + } + } + private fun showPickFileDialog() { - val initialDirectory = intent?.data?.path?.let(::File) ?: getExternalStorageDirectory() ?: File("/") - val f = FileSelectorDialogFragment() - f.arguments = Bundle { - this[EXTRA_ACTION] = intent.action - this[EXTRA_PATH] = initialDirectory.absolutePath - this[EXTRA_FILE_EXTENSIONS] = intent.getStringArrayExtra(EXTRA_FILE_EXTENSIONS) + Intent().apply { + if (intent.action == INTENT_ACTION_PICK_FILE) { + action = Intent.ACTION_GET_CONTENT + type = "*/*" + } else if (intent.action == INTENT_ACTION_PICK_DIRECTORY) { + action = Intent.ACTION_OPEN_DOCUMENT_TREE + } + }.also { + startActivityForResult( + Intent.createChooser(it, getString(R.string.pick_file)), + PICKER_REQUEST_CODE + ) } - f.show(supportFragmentManager, "select_file") + +// val initialDirectory = intent?.data?.path?.let(::File) ?: getExternalStorageDirectory() ?: File("/") +// val f = FileSelectorDialogFragment() +// f.arguments = Bundle { +// this[EXTRA_ACTION] = intent.action +// this[EXTRA_PATH] = initialDirectory.absolutePath +// this[EXTRA_FILE_EXTENSIONS] = intent.getStringArrayExtra(EXTRA_FILE_EXTENSIONS) +// } +// f.show(supportFragmentManager, "select_file") } } From f0d3865141b42874ca72a57029a3c4623e8a104b Mon Sep 17 00:00:00 2001 From: Tlaster Date: Mon, 20 Apr 2020 19:06:42 +0800 Subject: [PATCH 03/13] Clean up import of DataImportExportUtils.java --- .../mariotaku/twidere/util/DataImportExportUtils.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java b/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java index 775fb8efc4..65d4dbe699 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/DataImportExportUtils.java @@ -26,6 +26,7 @@ import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; + import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import androidx.documentfile.provider.DocumentFile; @@ -35,7 +36,6 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; -import org.mariotaku.commons.logansquare.LoganSquareMapperFinder; import org.mariotaku.library.exportablepreferences.PreferencesExporter; import org.mariotaku.library.exportablepreferences.annotation.PreferenceType; import org.mariotaku.library.objectcursor.ObjectCursor; @@ -46,11 +46,8 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Filters; import org.mariotaku.twidere.provider.TwidereDataStore.Tabs; import org.mariotaku.twidere.util.content.ContentResolverUtils; -import org.osmdroid.tileprovider.modules.ZipFileArchive; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -61,14 +58,10 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import javax.annotation.Nonnull; - public class DataImportExportUtils implements Constants { public static final String ENTRY_PREFERENCES = "preferences.json"; From d2e98524aca2fdd4bd30f3fdb0aee88cbbcb0b34 Mon Sep 17 00:00:00 2001 From: Michel Roux Date: Mon, 20 Apr 2020 19:28:01 +0200 Subject: [PATCH 04/13] Backport #1038 : Mastodon's API doesn't have `/api/direct_messages.json` --- .../twidere/extension/model/AccountDetailsExtensions.kt | 3 +++ .../mariotaku/twidere/task/twitter/message/GetMessagesTask.kt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt index 4007130fb2..0739981377 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt @@ -40,6 +40,9 @@ val AccountExtras.official: Boolean return false } +val AccountDetails.hasDm: Boolean + get() = type in arrayOf(AccountType.FANFOU, AccountType.TWITTER) + fun AccountDetails.newMicroBlogInstance(context: Context, cls: Class): T { return credentials.newMicroBlogInstance(context, type, cls) } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt index b294b2b425..4765f3e36b 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt @@ -37,6 +37,7 @@ import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_SHOW_NOTIFICATION import org.mariotaku.twidere.annotation.AccountType +import org.mariotaku.twidere.exception.APINotSupportedException import org.mariotaku.twidere.extension.findFieldByTypes import org.mariotaku.twidere.extension.model.* import org.mariotaku.twidere.extension.model.api.target @@ -85,6 +86,7 @@ class GetMessagesTask( } val microBlog = details.newMicroBlogInstance(context, cls = MicroBlog::class.java) val messages = try { + if (!details.hasDm) throw APINotSupportedException(details.type) getMessages(microBlog, details, param, i) } catch (e: MicroBlogException) { return@forEachIndexed From 3c241048719a761f53367748bac8347fe236b444 Mon Sep 17 00:00:00 2001 From: Michel Roux Date: Mon, 20 Apr 2020 19:50:09 +0200 Subject: [PATCH 05/13] Backport #999 : Search bar should consider the selected account --- .../org/mariotaku/twidere/fragment/search/SearchFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/search/SearchFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/search/SearchFragment.kt index 7d38f60897..929ca1674c 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/search/SearchFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/search/SearchFragment.kt @@ -111,6 +111,7 @@ class SearchFragment : AbsToolbarTabPagesFragment(), RefreshScrollTopInterface, customView.setOnClickListener { val searchIntent = Intent(context, QuickSearchBarActivity::class.java).apply { putExtra(EXTRA_QUERY, query) + putExtra(EXTRA_ACCOUNT_KEY, accountKey) } startActivityForResult(searchIntent, REQUEST_OPEN_SEARCH) } From a9c355d0e9eb34494405b7de6f39877c7abd38a0 Mon Sep 17 00:00:00 2001 From: Michel Roux Date: Mon, 20 Apr 2020 19:54:04 +0200 Subject: [PATCH 06/13] Gradle update (and only gradle) + fix insecable caracter --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 6 +++--- twidere/build.gradle | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 2c05856f05..83a4815ad9 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:3.6.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 38a8a7d457..649149d92c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Oct 24 17:45:27 JST 2019 +#Mon Apr 20 10:36:29 CEST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/twidere/build.gradle b/twidere/build.gradle index 82a3adfa02..ec64610eb3 100644 --- a/twidere/build.gradle +++ b/twidere/build.gradle @@ -144,7 +144,7 @@ android { exclude 'jsr305_annotations/**' exclude 'error_prone/**' exclude 'third_party/java_src/**' - exclude 'sdk-version.​txt' + exclude 'sdk-version.txt' exclude 'build-data.properties' } From 412891fc0992a217d3898dc4e9d4509f807e0914 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Tue, 21 Apr 2020 14:59:15 +0800 Subject: [PATCH 07/13] Fix #1246 --- .../androidx/core/os/LocaleHelperAccessor.kt | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/twidere/src/main/kotlin/androidx/core/os/LocaleHelperAccessor.kt b/twidere/src/main/kotlin/androidx/core/os/LocaleHelperAccessor.kt index c830579e9f..5a1e268c91 100644 --- a/twidere/src/main/kotlin/androidx/core/os/LocaleHelperAccessor.kt +++ b/twidere/src/main/kotlin/androidx/core/os/LocaleHelperAccessor.kt @@ -20,16 +20,33 @@ package androidx.core.os import android.annotation.SuppressLint -import android.os.Build import java.util.* @SuppressLint("RestrictedApi") object LocaleHelperAccessor { + fun forLanguageTag(str: String): Locale { + if (str.contains("-")) { + val args = str.split("-").dropLastWhile { it.isEmpty() }.toTypedArray() + if (args.size > 2) { + return Locale(args[0], args[1], args[2]) + } else if (args.size > 1) { + return Locale(args[0], args[1]) + } else if (args.size == 1) { + return Locale(args[0]) + } + } else if (str.contains("_")) { + val args = str.split("_").dropLastWhile { it.isEmpty() }.toTypedArray() + if (args.size > 2) { + return Locale(args[0], args[1], args[2]) + } else if (args.size > 1) { + return Locale(args[0], args[1]) + } else if (args.size == 1) { + return Locale(args[0]) + } + } else { + return Locale(str) + } - fun forLanguageTag(str: String): Locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Locale.forLanguageTag(str) - } else { - Locale(str)// TODO: Dose it work? -// TODO("VERSION.SDK_INT < LOLLIPOP") + throw IllegalArgumentException("Can not parse language tag: [$str]") } } From 642d89696549a550a2f00600cdd5258719ae543b Mon Sep 17 00:00:00 2001 From: Tlaster Date: Tue, 21 Apr 2020 15:16:41 +0800 Subject: [PATCH 08/13] Fix #1244 --- .../org/mariotaku/twidere/task/SaveMediaToGalleryTask.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/SaveMediaToGalleryTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/SaveMediaToGalleryTask.kt index f1f5b1c7b2..b935361f3c 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/SaveMediaToGalleryTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/SaveMediaToGalleryTask.kt @@ -43,8 +43,6 @@ class SaveMediaToGalleryTask( override fun onFileSaved(savedFile: File, mimeType: String?) { val context = context ?: return - MediaScannerConnection.scanFile(context, arrayOf(savedFile.path), - arrayOf(mimeType), null) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val type = (fileInfo as? CacheProvider.CacheFileTypeSupport)?.cacheFileType val path = when (type) { @@ -80,9 +78,14 @@ class SaveMediaToGalleryTask( fileInputStream.copyTo(it) } } + MediaScannerConnection.scanFile(context, arrayOf(uri.path), + arrayOf(fileInfo.mimeType), null) } + savedFile.delete() + } else { + MediaScannerConnection.scanFile(context, arrayOf(savedFile.path), + arrayOf(fileInfo.mimeType), null) } - savedFile.delete() Toast.makeText(context, R.string.message_toast_saved_to_gallery, Toast.LENGTH_SHORT).show() } From cdc5a241026b6ef949140565bedfe6476e33cb17 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Tue, 21 Apr 2020 15:33:55 +0800 Subject: [PATCH 09/13] Use FileSelectorDialogFragment when sdk < Q --- .../twidere/activity/FileSelectorActivity.kt | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt index 8ab5ef903a..b808436fde 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/FileSelectorActivity.kt @@ -24,14 +24,16 @@ import android.content.Intent import android.net.Uri import android.os.Build import android.os.Bundle +import android.os.Environment.getExternalStorageDirectory import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.fragment.app.DialogFragment +import org.mariotaku.ktextension.Bundle import org.mariotaku.ktextension.checkAllSelfPermissionsGranted +import org.mariotaku.ktextension.set import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.REQUEST_REQUEST_PERMISSIONS -import org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_PICK_DIRECTORY -import org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_PICK_FILE +import org.mariotaku.twidere.constant.IntentConstants.* import org.mariotaku.twidere.fragment.FileSelectorDialogFragment import java.io.File import android.Manifest.permission as AndroidPermissions @@ -65,7 +67,7 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, - grantResults: IntArray) { + grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_REQUEST_PERMISSIONS) { executeAfterFragmentResumed { @@ -114,28 +116,31 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback } private fun showPickFileDialog() { - Intent().apply { - if (intent.action == INTENT_ACTION_PICK_FILE) { - action = Intent.ACTION_GET_CONTENT - type = "*/*" - } else if (intent.action == INTENT_ACTION_PICK_DIRECTORY) { - action = Intent.ACTION_OPEN_DOCUMENT_TREE + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Intent().apply { + if (intent.action == INTENT_ACTION_PICK_FILE) { + action = Intent.ACTION_GET_CONTENT + type = "*/*" + } else if (intent.action == INTENT_ACTION_PICK_DIRECTORY) { + action = Intent.ACTION_OPEN_DOCUMENT_TREE + } + }.also { + startActivityForResult( + Intent.createChooser(it, getString(R.string.pick_file)), + PICKER_REQUEST_CODE + ) + } + } else { + val initialDirectory = intent?.data?.path?.let(::File) ?: getExternalStorageDirectory() + ?: File("/") + val f = FileSelectorDialogFragment() + f.arguments = Bundle { + this[EXTRA_ACTION] = intent.action + this[EXTRA_PATH] = initialDirectory.absolutePath + this[EXTRA_FILE_EXTENSIONS] = intent.getStringArrayExtra(EXTRA_FILE_EXTENSIONS) } - }.also { - startActivityForResult( - Intent.createChooser(it, getString(R.string.pick_file)), - PICKER_REQUEST_CODE - ) + f.show(supportFragmentManager, "select_file") } - -// val initialDirectory = intent?.data?.path?.let(::File) ?: getExternalStorageDirectory() ?: File("/") -// val f = FileSelectorDialogFragment() -// f.arguments = Bundle { -// this[EXTRA_ACTION] = intent.action -// this[EXTRA_PATH] = initialDirectory.absolutePath -// this[EXTRA_FILE_EXTENSIONS] = intent.getStringArrayExtra(EXTRA_FILE_EXTENSIONS) -// } -// f.show(supportFragmentManager, "select_file") } } From cd6250b647b991eea4f2ccb1e5f6fde6c897babe Mon Sep 17 00:00:00 2001 From: Tlaster Date: Tue, 21 Apr 2020 16:05:56 +0800 Subject: [PATCH 10/13] Fix data import/export DocumentFile error when sdk < q --- .../twidere/activity/DataExportActivity.kt | 9 ++++++++- .../twidere/activity/DataImportActivity.kt | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt index 094f7909c1..3af8d91651 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataExportActivity.kt @@ -4,6 +4,7 @@ import android.app.Activity import android.content.Intent import android.net.Uri import android.os.AsyncTask +import android.os.Build import android.os.Bundle import android.util.Log import androidx.documentfile.provider.DocumentFile @@ -15,6 +16,7 @@ import org.mariotaku.twidere.constant.IntentConstants import org.mariotaku.twidere.fragment.DataExportImportTypeSelectorDialogFragment import org.mariotaku.twidere.fragment.ProgressDialogFragment import org.mariotaku.twidere.util.DataImportExportUtils +import java.io.File import java.io.IOException import java.text.SimpleDateFormat import java.util.* @@ -65,7 +67,12 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra return } if (task == null || task!!.status != AsyncTask.Status.RUNNING) { - task = ExportSettingsTask(this, DocumentFile.fromTreeUri(this, path), flags) + val folder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + DocumentFile.fromTreeUri(this, path) + } else { + DocumentFile.fromFile(File(path.path)) + } + task = ExportSettingsTask(this, folder, flags) task!!.execute() } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt index c4ac8d46dd..7d2826064c 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/DataImportActivity.kt @@ -3,6 +3,7 @@ package org.mariotaku.twidere.activity import android.content.Intent import android.net.Uri import android.os.AsyncTask +import android.os.Build import android.os.Bundle import android.util.Log import androidx.documentfile.provider.DocumentFile @@ -13,6 +14,7 @@ import org.mariotaku.twidere.TwidereConstants.* import org.mariotaku.twidere.fragment.DataExportImportTypeSelectorDialogFragment import org.mariotaku.twidere.fragment.ProgressDialogFragment import org.mariotaku.twidere.util.DataImportExportUtils +import java.io.File import java.io.IOException class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFragment.Callback { @@ -40,7 +42,12 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra if (resultCode == RESULT_OK && data != null) { val path = data.data!! if (openImportTypeTask == null || openImportTypeTask!!.status != AsyncTask.Status.RUNNING) { - openImportTypeTask = OpenImportTypeTask(this@DataImportActivity, DocumentFile.fromSingleUri(this, path)) + val file = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + DocumentFile.fromSingleUri(this, path) + } else { + DocumentFile.fromFile(File(path.path)) + } + openImportTypeTask = OpenImportTypeTask(this@DataImportActivity, file) openImportTypeTask!!.execute() } } else { @@ -69,7 +76,12 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra return } if (importSettingsTask == null || importSettingsTask!!.status != AsyncTask.Status.RUNNING) { - importSettingsTask = ImportSettingsTask(this, DocumentFile.fromSingleUri(this, path), flags) + val file = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + DocumentFile.fromSingleUri(this, path) + } else { + DocumentFile.fromFile(File(path.path)) + } + importSettingsTask = ImportSettingsTask(this, file, flags) importSettingsTask!!.execute() } } From 4842388cb7f9dd087f9e776ff03577c379c6acad Mon Sep 17 00:00:00 2001 From: Tlaster Date: Tue, 21 Apr 2020 16:47:24 +0800 Subject: [PATCH 11/13] Fix #1245 --- twidere/src/main/res/values/themes_base_dark.xml | 4 ++-- twidere/src/main/res/values/themes_base_light.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/twidere/src/main/res/values/themes_base_dark.xml b/twidere/src/main/res/values/themes_base_dark.xml index 8c7f1909ef..877fad2f08 100644 --- a/twidere/src/main/res/values/themes_base_dark.xml +++ b/twidere/src/main/res/values/themes_base_dark.xml @@ -19,7 +19,7 @@ -