diff --git a/OsmAnd/res/drawable/img_legend_slope.xml b/OsmAnd/res/drawable/img_legend_slope.xml new file mode 100644 index 0000000000..e3a8566e45 --- /dev/null +++ b/OsmAnd/res/drawable/img_legend_slope.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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. Import rendering file Custom profile Angle: %s° 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 09aef61a38..41321c54e5 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, @@ -336,6 +313,11 @@ public class SettingsHelper { return items; } + @NonNull + public List getDuplicateItems() { + return duplicateItems; + } + @NonNull public List excludeDuplicateItems() { if (!items.isEmpty()) { @@ -1897,135 +1879,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) { @@ -2071,16 +2097,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); } } @@ -2124,10 +2148,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); } @@ -2143,4 +2172,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 4c12b41600..4b0492d8bb 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java @@ -48,6 +48,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 +342,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 +364,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 +681,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 +709,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 +724,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 +766,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,10 +786,10 @@ 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) { @@ -819,7 +825,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, name, error)); @@ -911,7 +917,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; } @@ -938,7 +946,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); + } +}