diff --git a/OsmAnd/res/layout/fragment_import.xml b/OsmAnd/res/layout/fragment_import.xml index baca708d0e..9921ff27d2 100644 --- a/OsmAnd/res/layout/fragment_import.xml +++ b/OsmAnd/res/layout/fragment_import.xml @@ -128,6 +128,16 @@ + + diff --git a/OsmAnd/res/layout/fragment_import_complete.xml b/OsmAnd/res/layout/fragment_import_complete.xml new file mode 100644 index 0000000000..b0af290996 --- /dev/null +++ b/OsmAnd/res/layout/fragment_import_complete.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/layout/fragment_import_duplicates.xml b/OsmAnd/res/layout/fragment_import_duplicates.xml index dc1fdf7d8f..d5f25eb5af 100644 --- a/OsmAnd/res/layout/fragment_import_duplicates.xml +++ b/OsmAnd/res/layout/fragment_import_duplicates.xml @@ -3,6 +3,7 @@ xmlns:osmand="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" android:background="?attr/activity_background_basic"> + tools:title="@string/import_duplicates_title"> + + diff --git a/OsmAnd/res/layout/list_item_import.xml b/OsmAnd/res/layout/list_item_import.xml index 25042fd505..9f489889b7 100644 --- a/OsmAnd/res/layout/list_item_import.xml +++ b/OsmAnd/res/layout/list_item_import.xml @@ -7,49 +7,57 @@ android:minHeight="@dimen/setting_list_item_small_height" android:orientation="vertical"> - - - + android:layout_width="match_parent" + android:layout_height="wrap_content"> + android:layout_height="match_parent" + android:background="?attr/selectableItemBackground" + android:gravity="center_vertical" + android:orientation="horizontal"> - + + + android:orientation="vertical" + android:paddingTop="@dimen/content_padding_small" + android:paddingBottom="@dimen/content_padding_small"> - + + + + + - + Restore all profile settings? Saving new profile Could not back up profile. + Importing data from %1$s + Importing + OsmAnd check %1$s for duplicates with existing items in the application.\n\nIt may take some time. + Items added + Import complete + All data from the %1$s is imported, you can use buttons below to open needed part of the application to manage it. Hillshade Enable to view hillshade or slope map. You can read more about this map types on our site Legend diff --git a/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java b/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java index fde2f7f9b0..82e4df2762 100644 --- a/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java +++ b/OsmAnd/src/net/osmand/plus/SQLiteTileSource.java @@ -126,9 +126,9 @@ public class SQLiteTileSource implements ITileSource { db = ctx.getSQLiteAPI().getOrCreateDatabase( ctx.getAppPath(TILES_INDEX_DIR).getAbsolutePath() + "/" + name + SQLITE_EXT, true); - db.execSQL("CREATE TABLE tiles (x int, y int, z int, s int, image blob, time long, PRIMARY KEY (x,y,z,s))"); - db.execSQL("CREATE INDEX IND on tiles (x,y,z,s)"); - db.execSQL("CREATE TABLE info(tilenumbering,minzoom,maxzoom)"); + db.execSQL("CREATE TABLE IF NOT EXISTS tiles (x int, y int, z int, s int, image blob, time long, PRIMARY KEY (x,y,z,s))"); + db.execSQL("CREATE INDEX IF NOT EXISTS IND on tiles (x,y,z,s)"); + db.execSQL("CREATE TABLE IF NOT EXISTS info(tilenumbering,minzoom,maxzoom)"); db.execSQL("INSERT INTO info (tilenumbering,minzoom,maxzoom) VALUES ('simple','" + minZoom + "','" + maxZoom + "');"); addInfoColumn(URL, urlTemplate); diff --git a/OsmAnd/src/net/osmand/plus/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/SettingsHelper.java index 8006749062..a3abaa1b10 100644 --- a/OsmAnd/src/net/osmand/plus/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/SettingsHelper.java @@ -1,13 +1,11 @@ package net.osmand.plus; import android.annotation.SuppressLint; -import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -96,16 +94,20 @@ public class SettingsHelper { private static final int BUFFER = 1024; private OsmandApplication app; - private Activity activity; - private boolean importing; - private boolean importSuspended; - private boolean collectOnly; private ImportAsyncTask importTask; private Map exportAsyncTasks = new HashMap<>(); public interface SettingsImportListener { - void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List items); + void onSettingsImportFinished(boolean succeed, @NonNull List items); + } + + public interface SettingsCollectListener { + void onSettingsCollectFinished(boolean succeed, boolean empty, @NonNull List items); + } + + public interface CheckDuplicatesListener { + void onDuplicatesChecked(@NonNull List duplicates, List items); } public interface SettingsExportListener { @@ -116,31 +118,6 @@ public class SettingsHelper { this.app = app; } - public Activity getActivity() { - return activity; - } - - public void setActivity(Activity activity) { - this.activity = activity; - if (importing && !collectOnly) { - importTask.processNextItem(); - } - } - - public void resetActivity(Activity activity) { - if (this.activity == activity) { - if (importing) { - importTask.suspendImport(); - importSuspended = true; - } - this.activity = null; - } - } - - public boolean isImporting() { - return importing; - } - public enum SettingsItemType { GLOBAL, PROFILE, @@ -263,6 +240,11 @@ public class SettingsHelper { return items; } + @NonNull + public List getDuplicateItems() { + return duplicateItems; + } + @NonNull public List excludeDuplicateItems() { if (!items.isEmpty()) { @@ -1801,135 +1783,179 @@ public class SettingsHelper { } @SuppressLint("StaticFieldLeak") - private class ImportAsyncTask extends AsyncTask> { + public class ImportAsyncTask extends AsyncTask> { private File file; private String latestChanges; private int version; - private SettingsImportListener listener; + private SettingsImportListener importListener; + private SettingsCollectListener collectListener; + private CheckDuplicatesListener duplicatesListener; private SettingsImporter importer; - private List items = new ArrayList<>(); - private List processedItems = new ArrayList<>(); - private SettingsItem currentItem; - private AlertDialog dialog; - ImportAsyncTask(@NonNull File settingsFile, String latestChanges, int version, @Nullable SettingsImportListener listener) { - this.file = settingsFile; - this.listener = listener; + private List items = new ArrayList<>(); + private List selectedItems = new ArrayList<>(); + private List duplicates; + + private ImportType importType; + private boolean importDone; + + ImportAsyncTask(@NonNull File file, String latestChanges, int version, @Nullable SettingsCollectListener collectListener) { + this.file = file; + this.collectListener = collectListener; this.latestChanges = latestChanges; this.version = version; importer = new SettingsImporter(app); - collectOnly = true; + importType = ImportType.COLLECT; } - ImportAsyncTask(@NonNull File settingsFile, @NonNull List items, String latestChanges, int version, @Nullable SettingsImportListener listener) { - this.file = settingsFile; - this.listener = listener; + ImportAsyncTask(@NonNull File file, @NonNull List items, String latestChanges, int version, @Nullable SettingsImportListener importListener) { + this.file = file; + this.importListener = importListener; this.items = items; this.latestChanges = latestChanges; this.version = version; importer = new SettingsImporter(app); - collectOnly = false; + importType = ImportType.IMPORT; + } + + ImportAsyncTask(@NonNull File file, @NonNull List items, @NonNull List selectedItems, @Nullable CheckDuplicatesListener duplicatesListener) { + this.file = file; + this.items = items; + this.duplicatesListener = duplicatesListener; + this.selectedItems = selectedItems; + importer = new SettingsImporter(app); + importType = ImportType.CHECK_DUPLICATES; } @Override protected void onPreExecute() { - if (importing) { - finishImport(listener, false, false, items); + ImportAsyncTask importTask = SettingsHelper.this.importTask; + if (importTask != null && !importTask.importDone) { + finishImport(importListener, false, items); } - importing = true; - importSuspended = false; - importTask = this; + SettingsHelper.this.importTask = this; } @Override protected List doInBackground(Void... voids) { - if (collectOnly) { - try { - return importer.collectItems(file); - } catch (IllegalArgumentException e) { - LOG.error("Failed to collect items from: " + file.getName(), e); - } catch (IOException e) { - LOG.error("Failed to collect items from: " + file.getName(), e); - } - } else { - return this.items; + switch (importType) { + case COLLECT: + try { + return importer.collectItems(file); + } catch (IllegalArgumentException e) { + LOG.error("Failed to collect items from: " + file.getName(), e); + } catch (IOException e) { + LOG.error("Failed to collect items from: " + file.getName(), e); + } + break; + case CHECK_DUPLICATES: + this.duplicates = getDuplicatesData(selectedItems); + return selectedItems; + case IMPORT: + return items; } return null; } @Override protected void onPostExecute(@Nullable List items) { - if (items != null) { + if (items != null && importType != ImportType.CHECK_DUPLICATES) { this.items = items; - } - if (collectOnly) { - listener.onSettingsImportFinished(true, false, this.items); - } else if (items != null && items.size() > 0) { - processNextItem(); - } - } - - private void processNextItem() { - if (activity == null) { - return; - } - if (items.size() == 0 && !importSuspended) { - if (processedItems.size() > 0) { - new ImportItemsAsyncTask(file, listener, processedItems).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - finishImport(listener, false, true, items); - } - return; - } - final SettingsItem item; - if (importSuspended && currentItem != null) { - item = currentItem; - } else if (items.size() > 0) { - item = items.remove(0); - currentItem = item; } else { - item = null; + selectedItems = items; } - importSuspended = false; - if (item != null) { - acceptItem(item); - } else { - processNextItem(); + switch (importType) { + case COLLECT: + importDone = true; + collectListener.onSettingsCollectFinished(true, false, this.items); + break; + case CHECK_DUPLICATES: + importDone = true; + if (duplicatesListener != null) { + duplicatesListener.onDuplicatesChecked(duplicates, selectedItems); + } + break; + case IMPORT: + if (items != null && items.size() > 0) { + for (SettingsItem item : items) { + item.apply(); + } + new ImportItemsAsyncTask(file, importListener, items).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + break; } } - private void suspendImport() { - if (dialog != null) { - dialog.dismiss(); - dialog = null; - } - } - - private void acceptItem(SettingsItem item) { - item.apply(); - processedItems.add(item); - processNextItem(); - } - public List getItems() { - return this.items; + return items; } public File getFile() { - return this.file; + return file; + } + + public void setImportListener(SettingsImportListener importListener) { + this.importListener = importListener; + } + + public void setDuplicatesListener(CheckDuplicatesListener duplicatesListener) { + this.duplicatesListener = duplicatesListener; + } + + ImportType getImportType() { + return importType; + } + + boolean isImportDone() { + return importDone; + } + + public List getDuplicates() { + return duplicates; + } + + public List getSelectedItems() { + return selectedItems; + } + + private List getDuplicatesData(List items) { + List duplicateItems = new ArrayList<>(); + for (SettingsItem item : items) { + if (item instanceof ProfileSettingsItem) { + if (item.exists()) { + duplicateItems.add(((ProfileSettingsItem) item).getModeBean()); + } + } else if (item instanceof CollectionSettingsItem) { + List duplicates = ((CollectionSettingsItem) item).excludeDuplicateItems(); + if (!duplicates.isEmpty()) { + duplicateItems.addAll(duplicates); + } + } else if (item instanceof FileSettingsItem) { + if (item.exists()) { + duplicateItems.add(((FileSettingsItem) item).getFile()); + } + } + } + return duplicateItems; } } @Nullable - public List getSettingsItems() { - return this.importTask.getItems(); + public ImportAsyncTask getImportTask() { + return importTask; } @Nullable - public File getSettingsFile() { - return this.importTask.getFile(); + public ImportType getImportTaskType() { + ImportAsyncTask importTask = this.importTask; + return importTask != null ? importTask.getImportType() : null; + } + + public boolean isImportDone() { + ImportAsyncTask importTask = this.importTask; + return importTask == null || importTask.isImportDone(); } public boolean isFileExporting(File file) { @@ -1975,16 +2001,14 @@ public class SettingsHelper { @Override protected void onPostExecute(Boolean success) { - finishImport(listener, success, false, items); + finishImport(listener, success, items); } } - private void finishImport(@Nullable SettingsImportListener listener, boolean success, boolean empty, @NonNull List items) { - importing = false; - importSuspended = false; + private void finishImport(@Nullable SettingsImportListener listener, boolean success, @NonNull List items) { importTask = null; if (listener != null) { - listener.onSettingsImportFinished(success, empty, items); + listener.onSettingsImportFinished(success, items); } } @@ -2028,10 +2052,15 @@ public class SettingsHelper { } } - public void importSettings(@NonNull File settingsFile, String latestChanges, int version, @Nullable SettingsImportListener listener) { + public void collectSettings(@NonNull File settingsFile, String latestChanges, int version, + @Nullable SettingsCollectListener listener) { new ImportAsyncTask(settingsFile, latestChanges, version, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } + public void checkDuplicates(@NonNull File file, @NonNull List items, @NonNull List selectedItems, CheckDuplicatesListener listener) { + new ImportAsyncTask(file, items, selectedItems, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + public void importSettings(@NonNull File settingsFile, @NonNull List items, String latestChanges, int version, @Nullable SettingsImportListener listener) { new ImportAsyncTask(settingsFile, items, latestChanges, version, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -2047,4 +2076,10 @@ public class SettingsHelper { @NonNull SettingsItem... items) { exportSettings(fileDir, fileName, listener, new ArrayList<>(Arrays.asList(items))); } + + public enum ImportType { + COLLECT, + CHECK_DUPLICATES, + IMPORT + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/UiUtilities.java b/OsmAnd/src/net/osmand/plus/UiUtilities.java index cc1d2e58aa..c7c8cbc447 100644 --- a/OsmAnd/src/net/osmand/plus/UiUtilities.java +++ b/OsmAnd/src/net/osmand/plus/UiUtilities.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.PorterDuff; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; @@ -11,6 +12,9 @@ import android.graphics.drawable.RippleDrawable; import android.hardware.Sensor; import android.hardware.SensorManager; import android.os.Build; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.StyleSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -36,14 +40,21 @@ import com.google.android.material.snackbar.Snackbar; import net.osmand.AndroidUtils; import net.osmand.Location; +import net.osmand.PlatformUtil; import net.osmand.data.LatLon; import net.osmand.plus.views.DirectionDrawable; import net.osmand.plus.widgets.TextViewEx; +import org.apache.commons.logging.Log; + +import java.util.Locale; + import gnu.trove.map.hash.TLongObjectHashMap; public class UiUtilities { + private static final Log LOG = PlatformUtil.getLog(UiUtilities.class); + private TLongObjectHashMap drawableCache = new TLongObjectHashMap<>(); private OsmandApplication app; private static final int ORIENTATION_0 = 0; @@ -554,4 +565,20 @@ public class UiUtilities { v.requestLayout(); } } + + public static SpannableString createSpannableString(@NonNull String text, @NonNull String textToStyle, @NonNull StyleSpan styleSpan) { + SpannableString spannable = new SpannableString(text); + try { + int startIndex = text.indexOf(textToStyle); + spannable.setSpan( + styleSpan, + startIndex, + startIndex + textToStyle.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + return spannable; + } catch (RuntimeException e) { + LOG.error("Error trying to find index of " + textToStyle + " " + e); + return spannable; + } + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/activities/FavoritesSearchFragment.java b/OsmAnd/src/net/osmand/plus/activities/FavoritesSearchFragment.java index 2bdd750655..34265a37b2 100644 --- a/OsmAnd/src/net/osmand/plus/activities/FavoritesSearchFragment.java +++ b/OsmAnd/src/net/osmand/plus/activities/FavoritesSearchFragment.java @@ -33,6 +33,7 @@ import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; import net.osmand.AndroidUtils; import net.osmand.access.AccessibilityAssistant; @@ -221,7 +222,10 @@ public class FavoritesSearchFragment extends DialogFragment { public void onDismiss(DialogInterface dialog) { Activity activity = getActivity(); if (activity != null) { - getChildFragmentManager().popBackStack(); + FragmentManager fragmentManager = getChildFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(); + } } super.onDismiss(dialog); } diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java index 48726c6d7c..b7f163f14c 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java @@ -136,6 +136,7 @@ import net.osmand.plus.settings.BaseSettingsFragment; import net.osmand.plus.settings.BaseSettingsFragment.SettingsScreenType; import net.osmand.plus.settings.ConfigureProfileFragment; import net.osmand.plus.settings.DataStorageFragment; +import net.osmand.plus.settings.ImportCompleteFragment; import net.osmand.plus.settings.ImportSettingsFragment; import net.osmand.plus.settings.ProfileAppearanceFragment; import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint; @@ -734,6 +735,11 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven importSettingsFragment.showExitDialog(); return; } + ImportCompleteFragment importCompleteFragment = getImportCompleteFragment(); + if (importCompleteFragment != null) { + importCompleteFragment.dismissFragment(); + return; + } super.onBackPressed(); } @@ -903,7 +909,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven } app.getDownloadThread().setUiActivity(this); - app.getSettingsHelper().setActivity(this); boolean routeWasFinished = routingHelper.isRouteWasFinished(); if (routeWasFinished && !DestinationReachedMenu.wasShown()) { @@ -1128,10 +1133,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven } public void dismissCardDialog() { - try { - getSupportFragmentManager().popBackStack(ContextMenuCardDialogFragment.TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); - } catch (Exception e) { - e.printStackTrace(); + FragmentManager fragmentManager = getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(ContextMenuCardDialogFragment.TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); } } @@ -1504,7 +1508,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven app.getMapMarkersHelper().removeListener(this); app.getRoutingHelper().removeListener(this); app.getDownloadThread().resetUiActivity(this); - app.getSettingsHelper().resetActivity(this); if (atlasMapRendererView != null) { atlasMapRendererView.handleOnPause(); } @@ -2166,10 +2169,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven } public void dismissSettingsScreens() { - try { - getSupportFragmentManager().popBackStack(DRAWER_SETTINGS_ID + ".new", FragmentManager.POP_BACK_STACK_INCLUSIVE); - } catch (Exception e) { - e.printStackTrace(); + FragmentManager fragmentManager = getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(DRAWER_SETTINGS_ID + ".new", FragmentManager.POP_BACK_STACK_INCLUSIVE); } } @@ -2453,10 +2455,14 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven return getFragment(ImportSettingsFragment.TAG); } + public ImportCompleteFragment getImportCompleteFragment() { + return getFragment(ImportCompleteFragment.TAG); + } + public void backToConfigureProfileFragment() { FragmentManager fragmentManager = getSupportFragmentManager(); int backStackEntryCount = fragmentManager.getBackStackEntryCount(); - if (backStackEntryCount > 0) { + if (backStackEntryCount > 0 && !fragmentManager.isStateSaved()) { BackStackEntry entry = fragmentManager.getBackStackEntryAt(backStackEntryCount - 1); if (ConfigureProfileFragment.TAG.equals(entry.getName())) { fragmentManager.popBackStack(); diff --git a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java index e38ecfa892..a594c9ec72 100644 --- a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java +++ b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java @@ -8,6 +8,7 @@ import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import net.osmand.plus.R; @@ -59,6 +60,12 @@ public class AudioVideoNoteRecordingMenuFullScreenFragment extends Fragment { public void dismiss() { dismissing = true; - getActivity().getSupportFragmentManager().popBackStack(); + FragmentActivity activity = getActivity(); + if (activity != null) { + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(); + } + } } } diff --git a/OsmAnd/src/net/osmand/plus/base/ContextMenuFragment.java b/OsmAnd/src/net/osmand/plus/base/ContextMenuFragment.java index 64b0d8b4a0..1e0b10ee31 100644 --- a/OsmAnd/src/net/osmand/plus/base/ContextMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/base/ContextMenuFragment.java @@ -937,11 +937,9 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment { if (isSingleFragment()) { FragmentActivity activity = getActivity(); if (activity != null) { - try { - activity.getSupportFragmentManager().popBackStack(getFragmentTag(), - FragmentManager.POP_BACK_STACK_INCLUSIVE); - } catch (Exception e) { - // + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(getFragmentTag(), FragmentManager.POP_BACK_STACK_INCLUSIVE); } } } diff --git a/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java b/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java index 4411ef4551..bfdf30b031 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java @@ -1,7 +1,6 @@ package net.osmand.plus.helpers; import android.annotation.SuppressLint; -import android.app.Activity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; @@ -48,6 +47,7 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.SettingsHelper; +import net.osmand.plus.SettingsHelper.SettingsCollectListener; import net.osmand.plus.SettingsHelper.SettingsImportListener; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.ActivityResultListener; @@ -341,9 +341,10 @@ public class ImportHelper { @Override protected void onPreExecute() { - progress = ProgressDialog - .show(activity, app.getString(R.string.loading_smth, ""), - app.getString(R.string.loading_data)); + if (AndroidUtils.isActivityNotDestroyed(activity)) { + progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), + app.getString(R.string.loading_data)); + } } @Override @@ -362,7 +363,7 @@ public class ImportHelper { @Override protected void onPostExecute(GPXFile result) { - if (AndroidUtils.isActivityNotDestroyed(activity)) { + if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) { progress.dismiss(); } Toast.makeText(activity, R.string.fav_imported_sucessfully, Toast.LENGTH_LONG) @@ -679,7 +680,9 @@ public class ImportHelper { @Override protected void onPreExecute() { - progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data)); + if (AndroidUtils.isActivityNotDestroyed(activity)) { + progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data)); + } mFileName = fileName; } @@ -705,7 +708,7 @@ public class ImportHelper { loadRoutingFiles(app, new AppInitializer.LoadRoutingFilesCallback() { @Override public void onRoutingFilesLoaded() { - if (AndroidUtils.isActivityNotDestroyed(activity)) { + if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) { progress.dismiss(); } RoutingConfiguration.Builder builder = app.getCustomRoutingConfig(mFileName); @@ -720,7 +723,7 @@ public class ImportHelper { } }); } else { - if (AndroidUtils.isActivityNotDestroyed(activity)) { + if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) { progress.dismiss(); } app.showShortToastMessage(app.getString(R.string.file_import_error, mFileName, error)); @@ -762,7 +765,9 @@ public class ImportHelper { @Override protected void onPreExecute() { - progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data)); + if (AndroidUtils.isActivityNotDestroyed(activity)) { + progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data)); + } } @Override @@ -780,24 +785,21 @@ public class ImportHelper { File tempDir = app.getAppPath(IndexConstants.TEMP_DIR); final File file = new File(tempDir, name); if (error == null && file.exists()) { - app.getSettingsHelper().importSettings(file, latestChanges, version, new SettingsImportListener() { + app.getSettingsHelper().collectSettings(file, latestChanges, version, new SettingsCollectListener() { @Override - public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List items) { - if (AndroidUtils.isActivityNotDestroyed(activity)) { + public void onSettingsCollectFinished(boolean succeed, boolean empty, @NonNull List items) { + if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) { progress.dismiss(); } if (succeed) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); - if (fragmentManager != null) { - ImportSettingsFragment.showInstance(fragmentManager, items, file); - } + ImportSettingsFragment.showInstance(activity.getSupportFragmentManager(), items, file); } else if (empty) { app.showShortToastMessage(app.getString(R.string.file_import_error, name, app.getString(R.string.shared_string_unexpected_error))); } } }); } else { - if (AndroidUtils.isActivityNotDestroyed(activity)) { + if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) { progress.dismiss(); } app.showShortToastMessage(app.getString(R.string.file_import_error, name, error)); @@ -889,7 +891,9 @@ public class ImportHelper { @Override protected void onPreExecute() { - progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data)); + if (AndroidUtils.isActivityNotDestroyed(activity)) { + progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data)); + } mFileName = fileName; } @@ -916,7 +920,7 @@ public class ImportHelper { } else { app.showShortToastMessage(app.getString(R.string.file_import_error, mFileName, error)); } - if (AndroidUtils.isActivityNotDestroyed(activity)) { + if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) { progress.dismiss(); } } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java index 5153698081..dbb14182d7 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java @@ -2120,9 +2120,9 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo public void dismissMenu() { FragmentActivity activity = getActivity(); if (activity != null) { - try { - activity.getSupportFragmentManager().popBackStack(TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); - } catch (Exception e) { + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); } } } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/dialogs/ContextMenuCardDialogFragment.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/dialogs/ContextMenuCardDialogFragment.java index 8b2934241b..541bbef145 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/dialogs/ContextMenuCardDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/dialogs/ContextMenuCardDialogFragment.java @@ -134,11 +134,9 @@ public class ContextMenuCardDialogFragment extends BaseOsmAndFragment { public void dismiss() { MapActivity activity = dialog.getMapActivity(); if (activity != null) { - try { - activity.getSupportFragmentManager().popBackStack(TAG, - FragmentManager.POP_BACK_STACK_INCLUSIVE); - } catch (Exception e) { - e.printStackTrace(); + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); } } } diff --git a/OsmAnd/src/net/osmand/plus/profiles/AdditionalDataWrapper.java b/OsmAnd/src/net/osmand/plus/profiles/AdditionalDataWrapper.java deleted file mode 100644 index c0300b6e9b..0000000000 --- a/OsmAnd/src/net/osmand/plus/profiles/AdditionalDataWrapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.osmand.plus.profiles; - -import java.util.List; - -public class AdditionalDataWrapper { - - private Type type; - - private List items; - - public AdditionalDataWrapper(Type type, List items) { - this.type = type; - this.items = items; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - - public List getItems() { - return items; - } - - public enum Type { - PROFILE, - QUICK_ACTIONS, - POI_TYPES, - MAP_SOURCES, - CUSTOM_RENDER_STYLE, - CUSTOM_ROUTING, - AVOID_ROADS - } -} diff --git a/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java b/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java index 68544590f4..9d25e244cd 100644 --- a/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java @@ -1023,7 +1023,10 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC hideToolbar(); mapActivity.updateStatusBarColor(); mapActivity.refreshMap(); - getChildFragmentManager().popBackStack(); + FragmentManager fragmentManager = getChildFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(); + } } super.onDismiss(dialog); } diff --git a/OsmAnd/src/net/osmand/plus/settings/BaseSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/BaseSettingsFragment.java index 27758dc6e2..f07bf164ec 100644 --- a/OsmAnd/src/net/osmand/plus/settings/BaseSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/BaseSettingsFragment.java @@ -585,7 +585,10 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl public void dismiss() { FragmentActivity activity = getActivity(); if (activity != null) { - activity.getSupportFragmentManager().popBackStack(); + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(); + } } } diff --git a/OsmAnd/src/net/osmand/plus/settings/ConfigureProfileFragment.java b/OsmAnd/src/net/osmand/plus/settings/ConfigureProfileFragment.java index c139c607e7..7238fde88f 100644 --- a/OsmAnd/src/net/osmand/plus/settings/ConfigureProfileFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/ConfigureProfileFragment.java @@ -36,6 +36,7 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.SettingsHelper; +import net.osmand.plus.SettingsHelper.SettingsCollectListener; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.AndroidUiHelper; @@ -182,9 +183,9 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co } private void restoreCustomModeFromFile(final File file) { - app.getSettingsHelper().importSettings(file, "", 1, new SettingsHelper.SettingsImportListener() { + app.getSettingsHelper().collectSettings(file, "", 1, new SettingsCollectListener() { @Override - public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List items) { + public void onSettingsCollectFinished(boolean succeed, boolean empty, @NonNull List items) { if (succeed) { for (SettingsHelper.SettingsItem item : items) { item.setShouldReplace(true); @@ -198,7 +199,7 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co private void importBackupSettingsItems(File file, List items) { app.getSettingsHelper().importSettings(file, items, "", 1, new SettingsHelper.SettingsImportListener() { @Override - public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List items) { + public void onSettingsImportFinished(boolean succeed, @NonNull List items) { app.showToastMessage(R.string.profile_prefs_reset_successful); updateCopiedOrResetPrefs(); } diff --git a/OsmAnd/src/net/osmand/plus/settings/DuplicatesSettingsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/DuplicatesSettingsAdapter.java index be8b05e1da..a667905b91 100644 --- a/OsmAnd/src/net/osmand/plus/settings/DuplicatesSettingsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/settings/DuplicatesSettingsAdapter.java @@ -10,6 +10,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import net.osmand.AndroidUtils; +import net.osmand.IndexConstants; import net.osmand.map.ITileSource; import net.osmand.plus.ApplicationMode; import net.osmand.plus.ApplicationMode.ApplicationModeBean; @@ -111,12 +112,12 @@ public class DuplicatesSettingsAdapter extends RecyclerView.Adapter dataToOperate; - private List dataList; + private Map> itemsMap; + private List itemsTypes; private boolean nightMode; private boolean importState; private int profileColor; - ExportImportSettingsAdapter(OsmandApplication app, List dataList, boolean nightMode, boolean importState) { + ExportImportSettingsAdapter(OsmandApplication app, boolean nightMode, boolean importState) { this.app = app; - this.dataList = dataList; this.nightMode = nightMode; this.importState = importState; - this.dataToOperate = new ArrayList<>(); - this.profileColor = app.getSettings().getApplicationMode().getIconColorInfo().getColor(nightMode); - } - - ExportImportSettingsAdapter(OsmandApplication app, boolean nightMode) { - this.app = app; - this.nightMode = nightMode; - this.dataList = new ArrayList<>(); + this.itemsMap = new HashMap<>(); + this.itemsTypes = new ArrayList<>(); this.dataToOperate = new ArrayList<>(); this.profileColor = app.getSettings().getApplicationMode().getIconColorInfo().getColor(nightMode); } @@ -71,7 +68,7 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { } boolean isLastGroup = groupPosition == getGroupCount() - 1; - final AdditionalDataWrapper.Type type = dataList.get(groupPosition).getType(); + final Type type = itemsTypes.get(groupPosition); TextView titleTv = group.findViewById(R.id.title_tv); TextView subTextTv = group.findViewById(R.id.sub_text_tv); @@ -88,7 +85,7 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { cardBottomDivider.setVisibility(importState && !isExpanded ? View.VISIBLE : View.GONE); CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, profileColor))); - final List listItems = dataList.get(groupPosition).getItems(); + final List listItems = itemsMap.get(type); subTextTv.setText(String.valueOf(listItems.size())); if (dataToOperate.containsAll(listItems)) { @@ -119,7 +116,7 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { notifyDataSetChanged(); } }); - adjustIndicator(app, groupPosition, isExpanded, group, true); + adjustIndicator(app, groupPosition, isExpanded, group, nightMode); return group; } @@ -130,10 +127,10 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { LayoutInflater inflater = UiUtilities.getInflater(app, nightMode); child = inflater.inflate(R.layout.profile_data_list_item_child, parent, false); } - final Object currentItem = dataList.get(groupPosition).getItems().get(childPosition); + final Object currentItem = itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition); boolean isLastGroup = groupPosition == getGroupCount() - 1; - final AdditionalDataWrapper.Type type = dataList.get(groupPosition).getType(); + final Type type = itemsTypes.get(groupPosition); TextView title = child.findViewById(R.id.title_tv); TextView subText = child.findViewById(R.id.sub_title_tv); @@ -204,17 +201,17 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { break; case CUSTOM_RENDER_STYLE: String renderName = ((File) currentItem).getName(); - renderName = renderName.replace('_', ' ').replaceAll(".render.xml", ""); + renderName = renderName.replace('_', ' ').replaceAll(IndexConstants.RENDERER_INDEX_EXT, ""); title.setText(renderName); - icon.setImageResource(R.drawable.ic_action_info_dark); - icon.setVisibility(View.INVISIBLE); + icon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_action_map_style, nightMode)); + icon.setVisibility(View.VISIBLE); subText.setVisibility(View.GONE); break; case CUSTOM_ROUTING: String routingName = ((File) currentItem).getName(); routingName = routingName.replace('_', ' ').replaceAll(".xml", ""); title.setText(routingName); - icon.setImageResource(R.drawable.ic_action_map_style); + icon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_action_route_distance, nightMode)); icon.setVisibility(View.VISIBLE); subText.setVisibility(View.GONE); break; @@ -233,22 +230,22 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { @Override public int getGroupCount() { - return dataList.size(); + return itemsTypes.size(); } @Override public int getChildrenCount(int i) { - return dataList.get(i).getItems().size(); + return itemsMap.get(itemsTypes.get(i)).size(); } @Override public Object getGroup(int i) { - return dataList.get(i); + return itemsMap.get(itemsTypes.get(i)); } @Override public Object getChild(int groupPosition, int childPosition) { - return dataList.get(groupPosition).getItems().get(childPosition); + return itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition); } @Override @@ -271,7 +268,7 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { return true; } - private int getGroupTitle(AdditionalDataWrapper.Type type) { + private int getGroupTitle(Type type) { switch (type) { case PROFILE: return R.string.shared_string_profiles; @@ -292,21 +289,24 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { } } - public void updateSettingsList(List settingsList) { - this.dataList = settingsList; + public void updateSettingsList(Map> itemsMap) { + this.itemsMap = itemsMap; + this.itemsTypes = new ArrayList<>(itemsMap.keySet()); + Collections.sort(itemsTypes); notifyDataSetChanged(); } public void clearSettingsList() { - this.dataList.clear(); + this.itemsMap.clear(); + this.itemsTypes.clear(); notifyDataSetChanged(); } public void selectAll(boolean selectAll) { dataToOperate.clear(); if (selectAll) { - for (AdditionalDataWrapper item : dataList) { - dataToOperate.addAll(item.getItems()); + for (List values : itemsMap.values()) { + dataToOperate.addAll(values); } } notifyDataSetChanged(); @@ -315,4 +315,14 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { List getDataToOperate() { return this.dataToOperate; } + + public enum Type { + PROFILE, + QUICK_ACTIONS, + POI_TYPES, + MAP_SOURCES, + CUSTOM_RENDER_STYLE, + CUSTOM_ROUTING, + AVOID_ROADS + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/ExportProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/ExportProfileBottomSheet.java index 5f4788b585..b6ac83cf9f 100644 --- a/OsmAnd/src/net/osmand/plus/settings/ExportProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/ExportProfileBottomSheet.java @@ -38,16 +38,17 @@ import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; import net.osmand.plus.poi.PoiUIFilter; -import net.osmand.plus.profiles.AdditionalDataWrapper; import net.osmand.plus.quickaction.QuickAction; import net.osmand.plus.quickaction.QuickActionFactory; import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet; +import net.osmand.plus.settings.ExportImportSettingsAdapter.Type; import org.apache.commons.logging.Log; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -63,7 +64,7 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { private OsmandApplication app; private ApplicationMode profile; - private List dataList = new ArrayList<>(); + private Map> dataList = new HashMap<>(); private ExportImportSettingsAdapter adapter; private SettingsHelper.SettingsExportListener exportListener; @@ -122,7 +123,7 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { if (!dataList.isEmpty()) { final View additionalDataView = inflater.inflate(R.layout.bottom_sheet_item_additional_data, null); ExpandableListView listView = additionalDataView.findViewById(R.id.list); - adapter = new ExportImportSettingsAdapter(app, nightMode); + adapter = new ExportImportSettingsAdapter(app, nightMode, false); View listHeader = inflater.inflate(R.layout.item_header_export_expand_list, null); final View topSwitchDivider = listHeader.findViewById(R.id.topSwitchDivider); final View bottomSwitchDivider = listHeader.findViewById(R.id.bottomSwitchDivider); @@ -214,22 +215,18 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { } } - private List getAdditionalData() { - List dataList = new ArrayList<>(); + private Map> getAdditionalData() { + Map> dataList = new HashMap<>(); QuickActionFactory factory = new QuickActionFactory(); List actionsList = factory.parseActiveActionsList(app.getSettings().QUICK_ACTION_LIST.get()); if (!actionsList.isEmpty()) { - dataList.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.QUICK_ACTIONS, actionsList)); + dataList.put(Type.QUICK_ACTIONS, actionsList); } List poiList = app.getPoiFilters().getUserDefinedPoiFilters(false); if (!poiList.isEmpty()) { - dataList.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.POI_TYPES, - poiList - )); + dataList.put(Type.POI_TYPES, poiList); } List iTileSources = new ArrayList<>(); @@ -249,37 +246,25 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { } } if (!iTileSources.isEmpty()) { - dataList.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.MAP_SOURCES, - iTileSources - )); + dataList.put(Type.MAP_SOURCES, iTileSources); } Map externalRenderers = app.getRendererRegistry().getExternalRenderers(); if (!externalRenderers.isEmpty()) { - dataList.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE, - new ArrayList<>(externalRenderers.values()) - )); + dataList.put(Type.CUSTOM_RENDER_STYLE, new ArrayList<>(externalRenderers.values())); } File routingProfilesFolder = app.getAppPath(IndexConstants.ROUTING_PROFILES_DIR); if (routingProfilesFolder.exists() && routingProfilesFolder.isDirectory()) { File[] fl = routingProfilesFolder.listFiles(); if (fl != null && fl.length > 0) { - dataList.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.CUSTOM_ROUTING, - Arrays.asList(fl) - )); + dataList.put(Type.CUSTOM_ROUTING, Arrays.asList(fl)); } } Map impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads(); if (!impassableRoads.isEmpty()) { - dataList.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.AVOID_ROADS, - new ArrayList<>(impassableRoads.values()) - )); + dataList.put(Type.AVOID_ROADS, new ArrayList<>(impassableRoads.values())); } return dataList; } diff --git a/OsmAnd/src/net/osmand/plus/settings/ImportCompleteFragment.java b/OsmAnd/src/net/osmand/plus/settings/ImportCompleteFragment.java new file mode 100644 index 0000000000..725281c31f --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/ImportCompleteFragment.java @@ -0,0 +1,184 @@ +package net.osmand.plus.settings; + +import android.app.Activity; +import android.graphics.Typeface; +import android.os.Build; +import android.os.Bundle; +import android.text.style.StyleSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import net.osmand.AndroidUtils; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.SettingsHelper.SettingsItem; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.base.BaseOsmAndFragment; +import net.osmand.plus.dashboard.DashboardOnMap; +import net.osmand.plus.dialogs.SelectMapStyleBottomSheetDialogFragment; +import net.osmand.plus.quickaction.QuickActionListFragment; +import net.osmand.plus.routepreparationmenu.AvoidRoadsBottomSheetDialogFragment; +import net.osmand.plus.search.QuickSearchDialogFragment; +import net.osmand.plus.settings.ExportImportSettingsAdapter.Type; + +import java.util.List; + +import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SETTINGS_ID; +import static net.osmand.plus.settings.ImportSettingsFragment.IMPORT_SETTINGS_TAG; +import static net.osmand.plus.settings.ImportSettingsFragment.getSettingsToOperate; + +public class ImportCompleteFragment extends BaseOsmAndFragment { + public static final String TAG = ImportCompleteFragment.class.getSimpleName(); + private OsmandApplication app; + private RecyclerView recyclerView; + private List settingsItems; + private String fileName; + private boolean nightMode; + + public static void showInstance(FragmentManager fm, @NonNull List settingsItems, + @NonNull String fileName) { + ImportCompleteFragment fragment = new ImportCompleteFragment(); + fragment.setSettingsItems(settingsItems); + fragment.setFileName(fileName); + fragment.setRetainInstance(true); + fm.beginTransaction() + .replace(R.id.fragmentContainer, fragment, TAG) + .addToBackStack(IMPORT_SETTINGS_TAG) + .commitAllowingStateLoss(); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + app = requireMyApplication(); + nightMode = !app.getSettings().isLightContent(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + inflater = UiUtilities.getInflater(app, nightMode); + View root = inflater.inflate(R.layout.fragment_import_complete, container, false); + TextView description = root.findViewById(R.id.description); + TextView btnClose = root.findViewById(R.id.button_close); + recyclerView = root.findViewById(R.id.list); + description.setText(UiUtilities.createSpannableString( + String.format(getString(R.string.import_complete_description), fileName), + fileName, + new StyleSpan(Typeface.BOLD) + )); + btnClose.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismissFragment(); + } + }); + if (Build.VERSION.SDK_INT >= 21) { + AndroidUtils.addStatusBarPadding21v(app, root); + } + return root; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (settingsItems != null) { + ImportedSettingsItemsAdapter adapter = new ImportedSettingsItemsAdapter( + app, + getSettingsToOperate(settingsItems), + nightMode, + new ImportedSettingsItemsAdapter.OnItemClickListener() { + @Override + public void onItemClick(Type type) { + navigateTo(type); + } + }); + recyclerView.setLayoutManager(new LinearLayoutManager(getMyApplication())); + recyclerView.setAdapter(adapter); + } + } + + public void dismissFragment() { + FragmentManager fm = getFragmentManager(); + if (fm != null && !fm.isStateSaved()) { + fm.popBackStack(IMPORT_SETTINGS_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + } + + private void navigateTo(Type type) { + FragmentManager fm = getFragmentManager(); + Activity activity = requireActivity(); + if (fm == null || fm.isStateSaved()) { + return; + } + dismissFragment(); + fm.popBackStack(DRAWER_SETTINGS_ID + ".new", FragmentManager.POP_BACK_STACK_INCLUSIVE); + switch (type) { + case CUSTOM_ROUTING: + case PROFILE: + BaseSettingsFragment.showInstance( + requireActivity(), + BaseSettingsFragment.SettingsScreenType.MAIN_SETTINGS + ); + break; + case QUICK_ACTIONS: + fm.beginTransaction() + .add(R.id.fragmentContainer, new QuickActionListFragment(), QuickActionListFragment.TAG) + .addToBackStack(QuickActionListFragment.TAG).commit(); + break; + case POI_TYPES: + if (activity instanceof MapActivity) { + QuickSearchDialogFragment.showInstance( + (MapActivity) activity, + "", + null, + QuickSearchDialogFragment.QuickSearchType.REGULAR, + QuickSearchDialogFragment.QuickSearchTab.CATEGORIES, + null + ); + } + break; + case MAP_SOURCES: + if (activity instanceof MapActivity) { + ((MapActivity) activity).getDashboard() + .setDashboardVisibility( + true, + DashboardOnMap.DashboardType.CONFIGURE_MAP, + null + ); + } + break; + case CUSTOM_RENDER_STYLE: + new SelectMapStyleBottomSheetDialogFragment().show(fm, SelectMapStyleBottomSheetDialogFragment.TAG); + break; + case AVOID_ROADS: + new AvoidRoadsBottomSheetDialogFragment().show(fm, AvoidRoadsBottomSheetDialogFragment.TAG); + break; + default: + break; + } + } + + @Override + public int getStatusBarColorId() { + return nightMode ? R.color.status_bar_color_dark : R.color.status_bar_color_light; + } + + public void setSettingsItems(List settingsItems) { + this.settingsItems = settingsItems; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/ImportDuplicatesFragment.java b/OsmAnd/src/net/osmand/plus/settings/ImportDuplicatesFragment.java index 69b30b77d4..fa702f252d 100644 --- a/OsmAnd/src/net/osmand/plus/settings/ImportDuplicatesFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/ImportDuplicatesFragment.java @@ -1,23 +1,27 @@ package net.osmand.plus.settings; -import android.graphics.drawable.Drawable; +import android.graphics.Typeface; import android.os.Build; import android.os.Bundle; +import android.text.style.StyleSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.core.widget.NestedScrollView; -import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.material.appbar.CollapsingToolbarLayout; + import net.osmand.AndroidUtils; import net.osmand.map.ITileSource; import net.osmand.plus.AppInitializer; @@ -25,6 +29,8 @@ import net.osmand.plus.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.SettingsHelper; +import net.osmand.plus.SettingsHelper.ImportAsyncTask; +import net.osmand.plus.SettingsHelper.ImportType; import net.osmand.plus.SettingsHelper.SettingsItem; import net.osmand.plus.UiUtilities; import net.osmand.plus.base.BaseOsmAndFragment; @@ -37,7 +43,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import static net.osmand.plus.settings.ImportSettingsFragment.getDuplicatesData; +import static net.osmand.plus.settings.ImportSettingsFragment.IMPORT_SETTINGS_TAG; public class ImportDuplicatesFragment extends BaseOsmAndFragment implements View.OnClickListener { @@ -51,6 +57,10 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment implements View private List settingsItems; private File file; private boolean nightMode; + private ProgressBar progressBar; + private CollapsingToolbarLayout toolbarLayout; + private TextView description; + private SettingsHelper settingsHelper; public static void showInstance(@NonNull FragmentManager fm, List duplicatesList, List settingsItems, File file) { @@ -58,20 +68,30 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment implements View fragment.setDuplicatesList(duplicatesList); fragment.setSettingsItems(settingsItems); fragment.setFile(file); - fm.beginTransaction().replace(R.id.fragmentContainer, fragment, TAG).addToBackStack(null).commit(); + fm.beginTransaction() + .replace(R.id.fragmentContainer, fragment, TAG) + .addToBackStack(IMPORT_SETTINGS_TAG) + .commitAllowingStateLoss(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); app = requireMyApplication(); + settingsHelper = app.getSettingsHelper(); nightMode = !app.getSettings().isLightContent(); - if (settingsItems == null) { - settingsItems = app.getSettingsHelper().getSettingsItems(); - duplicatesList = getDuplicatesData(settingsItems); - } - if (file == null) { - file = app.getSettingsHelper().getSettingsFile(); + ImportAsyncTask importTask = settingsHelper.getImportTask(); + if (importTask != null) { + if (settingsItems == null) { + settingsItems = importTask.getSelectedItems(); + } + if (duplicatesList == null) { + duplicatesList = importTask.getDuplicates(); + } + if (file == null) { + file = importTask.getFile(); + } + importTask.setImportListener(getImportListener()); } } @@ -80,11 +100,15 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment implements View public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { inflater = UiUtilities.getInflater(app, nightMode); View root = inflater.inflate(R.layout.fragment_import_duplicates, container, false); - setupToolbar((Toolbar) root.findViewById(R.id.toolbar)); + Toolbar toolbar = root.findViewById(R.id.toolbar); + setupToolbar(toolbar); ComplexButton replaceAllBtn = root.findViewById(R.id.replace_all_btn); ComplexButton keepBothBtn = root.findViewById(R.id.keep_both_btn); buttonsContainer = root.findViewById(R.id.buttons_container); nestedScroll = root.findViewById(R.id.nested_scroll); + description = root.findViewById(R.id.description); + progressBar = root.findViewById(R.id.progress_bar); + toolbarLayout = root.findViewById(R.id.toolbar_layout); keepBothBtn.setIcon(getPaintedContentIcon(R.drawable.ic_action_keep_both, nightMode ? getResources().getColor(R.color.icon_color_active_dark) @@ -121,16 +145,23 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment implements View return root; } - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - DuplicatesSettingsAdapter adapter = new DuplicatesSettingsAdapter(app, prepareDuplicates(), nightMode); - list.setLayoutManager(new LinearLayoutManager(getMyApplication())); - list.setAdapter(adapter); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (duplicatesList != null) { + DuplicatesSettingsAdapter adapter = new DuplicatesSettingsAdapter(app, prepareDuplicates(duplicatesList), nightMode); + list.setLayoutManager(new LinearLayoutManager(getMyApplication())); + list.setAdapter(adapter); + } + if (settingsHelper.getImportTaskType() == ImportType.IMPORT) { + setupImportingUi(); + } else { + toolbarLayout.setTitle(getString(R.string.import_duplicates_title)); + } + toolbarLayout.setTitle(getString(R.string.import_duplicates_title)); } - private List prepareDuplicates() { + private List prepareDuplicates(List duplicatesList) { List duplicates = new ArrayList<>(); List profiles = new ArrayList<>(); List actions = new ArrayList<>(); @@ -211,50 +242,60 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment implements View } private void importItems(boolean shouldReplace) { - for (SettingsItem item : settingsItems) { - item.setShouldReplace(shouldReplace); + if (settingsItems != null && file != null) { + setupImportingUi(); + for (SettingsItem item : settingsItems) { + item.setShouldReplace(shouldReplace); + } + settingsHelper.importSettings(file, settingsItems, "", 1, getImportListener()); } - app.getSettingsHelper().importSettings(file, settingsItems, "", 1, new SettingsHelper.SettingsImportListener() { + } + + private void setupImportingUi() { + toolbarLayout.setTitle(getString(R.string.shared_string_importing)); + description.setText(UiUtilities.createSpannableString( + String.format(getString(R.string.importing_from), file.getName()), + file.getName(), + new StyleSpan(Typeface.BOLD) + )); + progressBar.setVisibility(View.VISIBLE); + list.setVisibility(View.GONE); + buttonsContainer.setVisibility(View.GONE); + } + + private SettingsHelper.SettingsImportListener getImportListener() { + return new SettingsHelper.SettingsImportListener() { @Override - public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List items) { + public void onSettingsImportFinished(boolean succeed, @NonNull List items) { if (succeed) { - app.showShortToastMessage(app.getString(R.string.file_imported_successfully, file.getName())); app.getRendererRegistry().updateExternalRenderers(); AppInitializer.loadRoutingFiles(app, new AppInitializer.LoadRoutingFilesCallback() { @Override public void onRoutingFilesLoaded() { } }); - } else if (empty) { - app.showShortToastMessage(app.getString(R.string.file_import_error, file.getName(), app.getString(R.string.shared_string_unexpected_error))); + FragmentManager fm = getFragmentManager(); + if (fm != null && file != null) { + ImportCompleteFragment.showInstance(fm, items, file.getName()); + } } } - }); - FragmentManager fm = getFragmentManager(); - if (fm != null) { - fm.popBackStackImmediate(); - Fragment fragment = fm.findFragmentByTag(ImportSettingsFragment.TAG); - if (fragment != null) { - fm.beginTransaction().remove(fragment).commit(); - fm.popBackStackImmediate(); - } - } + }; } private void setupToolbar(Toolbar toolbar) { - Drawable icBack = getPaintedContentIcon(AndroidUtils.getNavigationIconResId(getContext()), + toolbar.setTitle(R.string.import_duplicates_title); + toolbar.setNavigationIcon(getPaintedContentIcon(R.drawable.ic_arrow_back, nightMode ? getResources().getColor(R.color.active_buttons_and_links_text_dark) - : getResources().getColor(R.color.active_buttons_and_links_text_light)); - toolbar.setNavigationIcon(icBack); + : getResources().getColor(R.color.active_buttons_and_links_text_light))); toolbar.setNavigationContentDescription(R.string.access_shared_string_navigate_up); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fm = getFragmentManager(); - if (fm != null) { + if (fm != null && !fm.isStateSaved()) { fm.popBackStackImmediate(); - ImportSettingsFragment.showInstance(fm, null, file); } } }); diff --git a/OsmAnd/src/net/osmand/plus/settings/ImportSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/ImportSettingsFragment.java index 563e634d4e..2ba4a77817 100644 --- a/OsmAnd/src/net/osmand/plus/settings/ImportSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/ImportSettingsFragment.java @@ -2,12 +2,16 @@ package net.osmand.plus.settings; import android.content.Context; import android.content.DialogInterface; +import android.graphics.Typeface; import android.os.Build; import android.os.Bundle; +import android.text.style.StyleSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ExpandableListView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.NonNull; @@ -17,7 +21,11 @@ import androidx.appcompat.widget.Toolbar; import androidx.core.view.ViewCompat; import androidx.fragment.app.FragmentManager; +import com.google.android.material.appbar.CollapsingToolbarLayout; + import net.osmand.AndroidUtils; +import net.osmand.IndexConstants; +import net.osmand.PlatformUtil; import net.osmand.map.ITileSource; import net.osmand.map.TileSourceManager; import net.osmand.plus.AppInitializer; @@ -26,50 +34,66 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.SettingsHelper; -import net.osmand.plus.SettingsHelper.SettingsItem; +import net.osmand.plus.SettingsHelper.*; import net.osmand.plus.UiUtilities; import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; import net.osmand.plus.poi.PoiUIFilter; -import net.osmand.plus.profiles.AdditionalDataWrapper; import net.osmand.plus.quickaction.QuickAction; import net.osmand.plus.widgets.TextViewEx; +import net.osmand.plus.settings.ExportImportSettingsAdapter.Type; + + +import org.apache.commons.logging.Log; import java.io.File; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class ImportSettingsFragment extends BaseOsmAndFragment implements View.OnClickListener { public static final String TAG = ImportSettingsFragment.class.getSimpleName(); + public static final Log LOG = PlatformUtil.getLog(ImportSettingsFragment.class.getSimpleName()); + private static final String DUPLICATES_START_TIME_KEY = "duplicates_start_time"; + private static final long MIN_DELAY_TIME_MS = 500; + static final String IMPORT_SETTINGS_TAG = "import_settings_tag"; private OsmandApplication app; private ExportImportSettingsAdapter adapter; private ExpandableListView expandableList; private TextViewEx selectBtn; + private TextView description; private List settingsItems; private File file; private boolean allSelected; private boolean nightMode; + private LinearLayout buttonsContainer; + private ProgressBar progressBar; + private CollapsingToolbarLayout toolbarLayout; + private SettingsHelper settingsHelper; + private long duplicateStartTime; - public static void showInstance(@NonNull FragmentManager fm, List settingsItems, @NonNull File file) { + public static void showInstance(@NonNull FragmentManager fm, @NonNull List settingsItems, @NonNull File file) { ImportSettingsFragment fragment = new ImportSettingsFragment(); fragment.setSettingsItems(settingsItems); fragment.setFile(file); - fm.beginTransaction().replace(R.id.fragmentContainer, fragment, TAG).addToBackStack(null).commit(); + fm.beginTransaction(). + replace(R.id.fragmentContainer, fragment, TAG) + .addToBackStack(IMPORT_SETTINGS_TAG) + .commitAllowingStateLoss(); } @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + duplicateStartTime = savedInstanceState.getLong(DUPLICATES_START_TIME_KEY); + } app = requireMyApplication(); + settingsHelper = app.getSettingsHelper(); nightMode = !app.getSettings().isLightContent(); - if (settingsItems == null) { - settingsItems = app.getSettingsHelper().getSettingsItems(); - } - if (file == null) { - file = app.getSettingsHelper().getSettingsFile(); - } } @Nullable @@ -77,13 +101,17 @@ public class ImportSettingsFragment extends BaseOsmAndFragment public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { inflater = UiUtilities.getInflater(app, nightMode); View root = inflater.inflate(R.layout.fragment_import, container, false); - setupToolbar((Toolbar) root.findViewById(R.id.toolbar)); + Toolbar toolbar = root.findViewById(R.id.toolbar); TextViewEx continueBtn = root.findViewById(R.id.continue_button); + toolbarLayout = root.findViewById(R.id.toolbar_layout); selectBtn = root.findViewById(R.id.select_button); expandableList = root.findViewById(R.id.list); + buttonsContainer = root.findViewById(R.id.buttons_container); + progressBar = root.findViewById(R.id.progress_bar); + setupToolbar(toolbar); ViewCompat.setNestedScrollingEnabled(expandableList, true); View header = inflater.inflate(R.layout.list_item_description_header, null); - TextView description = header.findViewById(R.id.description); + description = header.findViewById(R.id.description); description.setText(R.string.select_data_to_import); expandableList.addHeaderView(header); continueBtn.setOnClickListener(this); @@ -95,10 +123,48 @@ public class ImportSettingsFragment extends BaseOsmAndFragment } @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - adapter = new ExportImportSettingsAdapter(app, getSettingsToOperate(), nightMode, true); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + ImportAsyncTask importTask = settingsHelper.getImportTask(); + if (importTask != null) { + if (settingsItems == null) { + settingsItems = importTask.getItems(); + } + if (file == null) { + file = importTask.getFile(); + } + List duplicates = importTask.getDuplicates(); + List selectedItems = importTask.getSelectedItems(); + if (duplicates == null) { + importTask.setDuplicatesListener(getDuplicatesListener()); + } else if (duplicates.isEmpty()) { + if (selectedItems != null && file != null) { + settingsHelper.importSettings(file, selectedItems, "", 1, getImportListener()); + } + } + } + + adapter = new ExportImportSettingsAdapter(app, nightMode, true); + if (settingsItems != null) { + adapter.updateSettingsList(getSettingsToOperate(settingsItems)); + } expandableList.setAdapter(adapter); + toolbarLayout.setTitle(getString(R.string.shared_string_import)); + + ImportType importTaskType = settingsHelper.getImportTaskType(); + if (importTaskType == ImportType.CHECK_DUPLICATES && !settingsHelper.isImportDone()) { + updateUi(R.string.shared_string_preparing, R.string.checking_for_duplicate_description); + } else if (importTaskType == ImportType.IMPORT) { + updateUi(R.string.shared_string_importing, R.string.importing_from); + } else { + toolbarLayout.setTitle(getString(R.string.shared_string_import)); + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putLong(DUPLICATES_START_TIME_KEY, duplicateStartTime); } @Override @@ -121,69 +187,89 @@ public class ImportSettingsFragment extends BaseOsmAndFragment } } - private void importItems() { - List settingsItems = getSettingsItemsFromData(adapter.getDataToOperate()); - List duplicateItems = getDuplicatesData(settingsItems); - if (duplicateItems.isEmpty()) { - app.getSettingsHelper().importSettings(file, settingsItems, "", 1, new SettingsHelper.SettingsImportListener() { - @Override - public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List items) { - if (succeed) { - app.showShortToastMessage(app.getString(R.string.file_imported_successfully, file.getName())); - app.getRendererRegistry().updateExternalRenderers(); - AppInitializer.loadRoutingFiles(app, new AppInitializer.LoadRoutingFilesCallback() { - @Override - public void onRoutingFilesLoaded() { - } - }); - } else if (empty) { - app.showShortToastMessage(app.getString(R.string.file_import_error, file.getName(), app.getString(R.string.shared_string_unexpected_error))); - } - } - }); - FragmentManager fm = getFragmentManager(); - if (fm != null) { - fm.popBackStackImmediate(); - } - } else { - ImportDuplicatesFragment.showInstance(requireActivity().getSupportFragmentManager(), duplicateItems, settingsItems, file); + private void updateUi(int toolbarTitleRes, int descriptionRes) { + if (file != null) { + String fileName = file.getName(); + toolbarLayout.setTitle(getString(toolbarTitleRes)); + description.setText(UiUtilities.createSpannableString( + String.format(getString(descriptionRes), fileName), + fileName, + new StyleSpan(Typeface.BOLD) + )); + buttonsContainer.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); + adapter.clearSettingsList(); } } - public static List getDuplicatesData(List items) { - List duplicateItems = new ArrayList<>(); - for (SettingsItem item : items) { - if (item instanceof SettingsHelper.ProfileSettingsItem) { - if (item.exists()) { - duplicateItems.add(((SettingsHelper.ProfileSettingsItem) item).getModeBean()); - } - } else if (item instanceof SettingsHelper.QuickActionSettingsItem) { - List duplicates = ((SettingsHelper.QuickActionSettingsItem) item).excludeDuplicateItems(); - if (!duplicates.isEmpty()) { - duplicateItems.addAll(duplicates); - } - } else if (item instanceof SettingsHelper.PoiUiFilterSettingsItem) { - List duplicates = ((SettingsHelper.PoiUiFilterSettingsItem) item).excludeDuplicateItems(); - if (!duplicates.isEmpty()) { - duplicateItems.addAll(duplicates); - } - } else if (item instanceof SettingsHelper.MapSourcesSettingsItem) { - List duplicates = ((SettingsHelper.MapSourcesSettingsItem) item).excludeDuplicateItems(); - if (!duplicates.isEmpty()) { - duplicateItems.addAll(duplicates); - } - } else if (item instanceof SettingsHelper.FileSettingsItem) { - if (item.exists()) { - duplicateItems.add(((SettingsHelper.FileSettingsItem) item).getFile()); - } - } else if (item instanceof SettingsHelper.AvoidRoadsSettingsItem) { - List avoidRoads = ((SettingsHelper.AvoidRoadsSettingsItem) item).excludeDuplicateItems(); - if (!avoidRoads.isEmpty()) { - duplicateItems.addAll(avoidRoads); + private void importItems() { + updateUi(R.string.shared_string_preparing, R.string.checking_for_duplicate_description); + List selectedItems = getSettingsItemsFromData(adapter.getDataToOperate()); + if (file != null && settingsItems != null) { + duplicateStartTime = System.currentTimeMillis(); + settingsHelper.checkDuplicates(file, settingsItems, selectedItems, getDuplicatesListener()); + } + } + + private SettingsHelper.SettingsImportListener getImportListener() { + return new SettingsHelper.SettingsImportListener() { + @Override + public void onSettingsImportFinished(boolean succeed, @NonNull List items) { + FragmentManager fm = getFragmentManager(); + if (succeed) { + app.getRendererRegistry().updateExternalRenderers(); + AppInitializer.loadRoutingFiles(app, new AppInitializer.LoadRoutingFilesCallback() { + @Override + public void onRoutingFilesLoaded() { + } + }); + if (fm != null && file != null) { + ImportCompleteFragment.showInstance(fm, items, file.getName()); + } } } + }; + } + + private SettingsHelper.CheckDuplicatesListener getDuplicatesListener() { + return new SettingsHelper.CheckDuplicatesListener() { + @Override + public void onDuplicatesChecked(@NonNull final List duplicates, final List items) { + long spentTime = System.currentTimeMillis() - duplicateStartTime; + if (spentTime < MIN_DELAY_TIME_MS) { + long delay = MIN_DELAY_TIME_MS - spentTime; + app.runInUIThread(new Runnable() { + @Override + public void run() { + processDuplicates(duplicates, items); + } + }, delay); + } else { + processDuplicates(duplicates, items); + } + } + }; + } + + private void processDuplicates(List duplicates, List items) { + FragmentManager fm = getFragmentManager(); + if (file != null) { + if (duplicates.isEmpty()) { + if (isAdded()) { + updateUi(R.string.shared_string_importing, R.string.importing_from); + } + settingsHelper.importSettings(file, items, "", 1, getImportListener()); + } else if (fm != null && !isStateSaved()) { + ImportDuplicatesFragment.showInstance(fm, duplicates, items, file); + } + } + } + + private void dismissFragment() { + FragmentManager fm = getFragmentManager(); + if (fm != null && !fm.isStateSaved()) { + getFragmentManager().popBackStack(IMPORT_SETTINGS_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); } - return duplicateItems; } public void setSettingsItems(List settingsItems) { @@ -228,8 +314,8 @@ public class ImportSettingsFragment extends BaseOsmAndFragment return settingsItems; } - private List getSettingsToOperate() { - List settingsToOperate = new ArrayList<>(); + public static Map> getSettingsToOperate(List settingsItems) { + Map> settingsToOperate = new HashMap<>(); List profiles = new ArrayList<>(); List quickActions = new ArrayList<>(); List poiUIFilters = new ArrayList<>(); @@ -238,64 +324,50 @@ public class ImportSettingsFragment extends BaseOsmAndFragment List renderFilesList = new ArrayList<>(); List avoidRoads = new ArrayList<>(); - for (SettingsHelper.SettingsItem item : settingsItems) { - if (item.getType().equals(SettingsHelper.SettingsItemType.PROFILE)) { - profiles.add(((SettingsHelper.ProfileSettingsItem) item).getModeBean()); - } else if (item.getType().equals(SettingsHelper.SettingsItemType.QUICK_ACTION)) { - quickActions.addAll(((SettingsHelper.QuickActionSettingsItem) item).getItems()); - } else if (item.getType().equals(SettingsHelper.SettingsItemType.POI_UI_FILTERS)) { - poiUIFilters.addAll(((SettingsHelper.PoiUiFilterSettingsItem) item).getItems()); - } else if (item.getType().equals(SettingsHelper.SettingsItemType.MAP_SOURCES)) { - tileSourceTemplates.addAll(((SettingsHelper.MapSourcesSettingsItem) item).getItems()); - } else if (item.getType().equals(SettingsHelper.SettingsItemType.FILE)) { - if (item.getName().startsWith("/rendering/")) { - renderFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile()); - } else if (item.getName().startsWith("/routing/")) { - routingFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile()); + for (SettingsItem item : settingsItems) { + if (item.getType().equals(SettingsItemType.PROFILE)) { + profiles.add(((ProfileSettingsItem) item).getModeBean()); + } else if (item.getType().equals(SettingsItemType.QUICK_ACTION)) { + quickActions.addAll(((QuickActionSettingsItem) item).getItems()); + quickActions.addAll(((QuickActionSettingsItem) item).getDuplicateItems()); + } else if (item.getType().equals(SettingsItemType.POI_UI_FILTERS)) { + poiUIFilters.addAll(((PoiUiFilterSettingsItem) item).getItems()); + poiUIFilters.addAll(((PoiUiFilterSettingsItem) item).getDuplicateItems()); + } else if (item.getType().equals(SettingsItemType.MAP_SOURCES)) { + tileSourceTemplates.addAll(((MapSourcesSettingsItem) item).getItems()); + tileSourceTemplates.addAll(((MapSourcesSettingsItem) item).getDuplicateItems()); + } else if (item.getType().equals(SettingsItemType.FILE)) { + if (item.getName().contains(IndexConstants.RENDERERS_DIR)) { + renderFilesList.add(((FileSettingsItem) item).getFile()); + } else if (item.getName().contains(IndexConstants.ROUTING_PROFILES_DIR)) { + routingFilesList.add(((FileSettingsItem) item).getFile()); } - } else if (item.getType().equals(SettingsHelper.SettingsItemType.AVOID_ROADS)) { - avoidRoads.addAll(((SettingsHelper.AvoidRoadsSettingsItem) item).getItems()); + } else if (item.getType().equals(SettingsItemType.AVOID_ROADS)) { + avoidRoads.addAll(((AvoidRoadsSettingsItem) item).getItems()); + avoidRoads.addAll(((AvoidRoadsSettingsItem) item).getDuplicateItems()); } } if (!profiles.isEmpty()) { - settingsToOperate.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.PROFILE, - profiles)); + settingsToOperate.put(Type.PROFILE, profiles); } if (!quickActions.isEmpty()) { - settingsToOperate.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.QUICK_ACTIONS, - quickActions)); + settingsToOperate.put(Type.QUICK_ACTIONS, quickActions); } if (!poiUIFilters.isEmpty()) { - settingsToOperate.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.POI_TYPES, - poiUIFilters)); + settingsToOperate.put(Type.POI_TYPES, poiUIFilters); } if (!tileSourceTemplates.isEmpty()) { - settingsToOperate.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.MAP_SOURCES, - tileSourceTemplates - )); + settingsToOperate.put(Type.MAP_SOURCES, tileSourceTemplates); } if (!renderFilesList.isEmpty()) { - settingsToOperate.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE, - renderFilesList - )); + settingsToOperate.put(Type.CUSTOM_RENDER_STYLE, renderFilesList); } if (!routingFilesList.isEmpty()) { - settingsToOperate.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.CUSTOM_ROUTING, - routingFilesList - )); + settingsToOperate.put(Type.CUSTOM_ROUTING, routingFilesList); } if (!avoidRoads.isEmpty()) { - settingsToOperate.add(new AdditionalDataWrapper( - AdditionalDataWrapper.Type.AVOID_ROADS, - avoidRoads - )); + settingsToOperate.put(Type.AVOID_ROADS, avoidRoads); } return settingsToOperate; } @@ -314,10 +386,7 @@ public class ImportSettingsFragment extends BaseOsmAndFragment dismissDialog.setPositiveButton(R.string.shared_string_exit, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - FragmentManager fm = getFragmentManager(); - if (fm != null) { - fm.popBackStackImmediate(); - } + dismissFragment(); } }); dismissDialog.show(); diff --git a/OsmAnd/src/net/osmand/plus/settings/ImportedSettingsItemsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/ImportedSettingsItemsAdapter.java new file mode 100644 index 0000000000..bdd66578a7 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/ImportedSettingsItemsAdapter.java @@ -0,0 +1,131 @@ +package net.osmand.plus.settings; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import net.osmand.AndroidUtils; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.settings.ExportImportSettingsAdapter.Type; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + + +public class ImportedSettingsItemsAdapter extends + RecyclerView.Adapter { + private Map> itemsMap; + private List itemsTypes; + private UiUtilities uiUtils; + private OsmandApplication app; + private boolean nightMode; + private OnItemClickListener listener; + + ImportedSettingsItemsAdapter(@NonNull OsmandApplication app, Map> itemsMap, + boolean nightMode, OnItemClickListener listener) { + this.app = app; + this.itemsMap = itemsMap; + this.nightMode = nightMode; + this.listener = listener; + uiUtils = app.getUIUtilities(); + itemsTypes = new ArrayList<>(itemsMap.keySet()); + Collections.sort(itemsTypes); + } + + @NonNull + @Override + public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = UiUtilities.getInflater(app, nightMode); + View view = inflater.inflate(R.layout.list_item_import, parent, false); + return new ItemViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) { + final Type currentItemType = itemsTypes.get(position); + boolean isLastItem = itemsTypes.size() - 1 == position; + int activeColorRes = nightMode + ? R.color.active_color_primary_dark + : R.color.active_color_primary_light; + + holder.icon.setPadding(0, 0, AndroidUtils.dpToPx(app, 16), 0); + holder.title.setTextColor(app.getResources().getColor(activeColorRes)); + holder.divider.setVisibility(isLastItem ? View.VISIBLE : View.GONE); + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + listener.onItemClick(currentItemType); + } + }); + holder.subTitle.setText(String.format( + app.getString(R.string.ltr_or_rtl_combine_via_colon), + app.getString(R.string.items_added), + String.valueOf(itemsMap.get(currentItemType).size())) + ); + + switch (currentItemType) { + case PROFILE: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.map_action_settings, activeColorRes)); + holder.title.setText(R.string.shared_string_settings); + break; + case QUICK_ACTIONS: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.map_quick_action, activeColorRes)); + holder.title.setText(R.string.configure_screen_quick_action); + break; + case POI_TYPES: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_search_dark, activeColorRes)); + holder.title.setText(R.string.search_activity); + break; + case MAP_SOURCES: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_layers, activeColorRes)); + holder.title.setText(R.string.configure_map); + break; + case CUSTOM_RENDER_STYLE: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_map_style, activeColorRes)); + holder.title.setText(R.string.shared_string_rendering_style); + break; + case CUSTOM_ROUTING: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_route_distance, activeColorRes)); + holder.title.setText(R.string.shared_string_routing); + break; + case AVOID_ROADS: + holder.icon.setImageDrawable(uiUtils.getIcon(R.drawable.ic_action_alert, activeColorRes)); + holder.title.setText(R.string.avoid_road); + break; + } + } + + @Override + public int getItemCount() { + return itemsMap.keySet().size(); + } + + public static class ItemViewHolder extends RecyclerView.ViewHolder { + ImageView icon; + TextView title; + TextView subTitle; + View divider; + + ItemViewHolder(View itemView) { + super(itemView); + title = itemView.findViewById(R.id.title); + subTitle = itemView.findViewById(R.id.sub_title); + icon = itemView.findViewById(R.id.icon); + divider = itemView.findViewById(R.id.bottom_divider); + } + } + + interface OnItemClickListener { + void onItemClick(Type type); + } +}