diff --git a/OsmAnd/build-common.gradle b/OsmAnd/build-common.gradle index 54d0cbffe60..bc023a70851 100644 --- a/OsmAnd/build-common.gradle +++ b/OsmAnd/build-common.gradle @@ -389,7 +389,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' implementation 'androidx.browser:browser:1.0.0' - implementation 'androidx.preference:preference:1.1.0' + implementation 'androidx.preference:preference:1.2.1' implementation 'androidx.lifecycle:lifecycle-process:2.6.0' implementation fileTree(include: ['gnu-trove-osmand.jar', 'icu4j-49_1_patched.jar'], dir: 'libs') @@ -433,6 +433,9 @@ dependencies { implementation "androidx.car.app:app-projected:1.4.0" implementation 'com.google.android.gms:play-services-location:21.3.0' + implementation 'com.github.KnollFrank:SettingsSearch:2304bd2c97' + // https://mvnrepository.com/artifact/com.google.guava/guava + implementation 'com.google.guava:guava:33.3.1-android' //implementation "androidx.tracing:tracing:1.1.0" //debugImplementation 'androidx.test:monitor:1.6.1' diff --git a/OsmAnd/res/layout/custom_searchpreference_fragment.xml b/OsmAnd/res/layout/custom_searchpreference_fragment.xml new file mode 100644 index 00000000000..c6908ed4b6c --- /dev/null +++ b/OsmAnd/res/layout/custom_searchpreference_fragment.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + diff --git a/OsmAnd/res/layout/custom_searchresults_fragment.xml b/OsmAnd/res/layout/custom_searchresults_fragment.xml new file mode 100644 index 00000000000..0a1031f39ee --- /dev/null +++ b/OsmAnd/res/layout/custom_searchresults_fragment.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/OsmAnd/res/layout/distance_during_navigation_bottom_sheet.xml b/OsmAnd/res/layout/distance_during_navigation_bottom_sheet.xml index e7c717eed2a..a26ad81dd90 100644 --- a/OsmAnd/res/layout/distance_during_navigation_bottom_sheet.xml +++ b/OsmAnd/res/layout/distance_during_navigation_bottom_sheet.xml @@ -7,6 +7,7 @@ android:orientation="vertical"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/list_background_color" + android:gravity="center_vertical"> - + - + - + - + - + - + - + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/preference_category_title.xml b/OsmAnd/res/layout/preference_category_title.xml index e6d9eb5f021..6108b0b9240 100644 --- a/OsmAnd/res/layout/preference_category_title.xml +++ b/OsmAnd/res/layout/preference_category_title.xml @@ -1,37 +1,46 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/list_background_color" + android:gravity="center_vertical" + android:minHeight="@dimen/bottom_sheet_cancel_button_height_small" + android:orientation="horizontal"> - + - - + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/preference_info.xml b/OsmAnd/res/layout/preference_info.xml index 7499dbd8641..ec25e493700 100644 --- a/OsmAnd/res/layout/preference_info.xml +++ b/OsmAnd/res/layout/preference_info.xml @@ -1,37 +1,52 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/list_background_color" + android:gravity="center_vertical" + android:minHeight="@dimen/bottom_sheet_list_item_height"> - + - + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/preference_switch.xml b/OsmAnd/res/layout/preference_switch.xml index 2f5d9911007..520a6ca348b 100644 --- a/OsmAnd/res/layout/preference_switch.xml +++ b/OsmAnd/res/layout/preference_switch.xml @@ -1,56 +1,75 @@ - - - - - - - - - - + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/list_background_color" + android:gravity="center_vertical"> + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/preference_with_descr_and_divider.xml b/OsmAnd/res/layout/preference_with_descr_and_divider.xml index 3116a3ab34d..6a30492a17d 100644 --- a/OsmAnd/res/layout/preference_with_descr_and_divider.xml +++ b/OsmAnd/res/layout/preference_with_descr_and_divider.xml @@ -31,7 +31,7 @@ + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/simulate_location_fragment.xml b/OsmAnd/res/layout/simulate_location_fragment.xml index dab9945810a..0d7da730714 100644 --- a/OsmAnd/res/layout/simulate_location_fragment.xml +++ b/OsmAnd/res/layout/simulate_location_fragment.xml @@ -21,6 +21,7 @@ Arrive at destination Turn Time and distance intervals - The anouncement timing of different voice prompts depends on prompt type, current navigation speed, and default navigation speed. + The announcement timing of different voice prompts depends on prompt type, current navigation speed, and default navigation speed. Announcement time Start recording Show track on map diff --git a/OsmAnd/res/values/attrs.xml b/OsmAnd/res/values/attrs.xml index dee8dedf6b9..c0f57a17994 100644 --- a/OsmAnd/res/values/attrs.xml +++ b/OsmAnd/res/values/attrs.xml @@ -4,6 +4,7 @@ + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 8af4d0a5d52..88f485d4a67 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -5999,4 +5999,5 @@ Download tile maps directly, or copy them as SQLite database files to OsmAnd\'s Off-piste \'Freeride\' and \'Off-piste\' are unofficial routes and passages. Typically ungroomed, unmaintained and not checked in the evening. Enter at your own risk. Voice prompts times + search inside disabled profiles diff --git a/OsmAnd/res/values/styles.xml b/OsmAnd/res/values/styles.xml index fded886fd1a..1e58bd04d2e 100644 --- a/OsmAnd/res/values/styles.xml +++ b/OsmAnd/res/values/styles.xml @@ -174,14 +174,14 @@ - - - + + + + + + diff --git a/OsmAnd/src/net/osmand/plus/AppInitializer.java b/OsmAnd/src/net/osmand/plus/AppInitializer.java index 639568a1110..a7e58c1f912 100644 --- a/OsmAnd/src/net/osmand/plus/AppInitializer.java +++ b/OsmAnd/src/net/osmand/plus/AppInitializer.java @@ -71,6 +71,7 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.backend.backup.FileSettingsHelper; +import net.osmand.plus.settings.fragments.search.SettingsSearchInitializer; import net.osmand.plus.track.helpers.GpsFilterHelper; import net.osmand.plus.track.helpers.GpxDisplayHelper; import net.osmand.plus.track.helpers.GpxSelectionHelper; @@ -126,6 +127,7 @@ public class AppInitializer implements IProgress { private boolean routingConfigInitialized; private String taskName; private SharedPreferences startPrefs; + private SettingsSearchInitializer settingsSearchInitializer; public interface LoadRoutingFilesCallback { void onRoutingFilesLoaded(); @@ -277,6 +279,8 @@ public void onCreateApplication() { } else { settings.setApplicationMode(settings.DEFAULT_APPLICATION_MODE.get()); } + settingsSearchInitializer = new SettingsSearchInitializer(app); + settingsSearchInitializer.rebuildSearchDatabaseOnAppProfileChanged(); startTime = System.currentTimeMillis(); getLazyRoutingConfig(); app.applyTheme(app); @@ -542,6 +546,7 @@ private void startApplicationBackground() { } } } + private void checkLiveUpdatesAlerts() { OsmandSettings settings = app.getSettings(); if (InAppPurchaseUtils.isLiveUpdatesAvailable(app) && settings.IS_LIVE_UPDATES_ON.get()) { diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java index c1497b4ea8a..90688c30037 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java @@ -25,6 +25,7 @@ import android.view.WindowManager; import android.widget.ProgressBar; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; @@ -105,7 +106,9 @@ import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.datastorage.SharedStorageWarningFragment; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.MainSettingsFragment; import net.osmand.plus.settings.fragments.SettingsScreenType; +import net.osmand.plus.settings.fragments.search.SettingsSearchButtonHelper; import net.osmand.plus.simulation.LoadSimulatedLocationsTask.LoadSimulatedLocationsListener; import net.osmand.plus.simulation.OsmAndLocationSimulation; import net.osmand.plus.simulation.SimulatedLocation; @@ -135,11 +138,16 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import de.KnollFrank.lib.settingssearch.client.CreateSearchDatabaseTaskProvider; +import de.KnollFrank.lib.settingssearch.common.task.AsyncTaskWithProgressUpdateListeners; +import de.KnollFrank.lib.settingssearch.common.task.Tasks; + public class MapActivity extends OsmandActionBarActivity implements DownloadEvents, IRouteInformationListener, AMapPointUpdateListener, MapMarkerChangedListener, OnDrawMapListener, OsmAndAppCustomizationListener, LockUIAdapter, @@ -160,6 +168,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven @Nullable private static Intent prevActivityIntent = null; + private static final @IdRes int FRAGMENT_CONTAINER_VIEW_ID = View.generateViewId(); + private Optional> createSearchDatabaseTask = Optional.empty(); + private final List activityResultListeners = new ArrayList<>(); private BroadcastReceiver screenOffReceiver; @@ -337,6 +348,10 @@ public void enterToFullScreen() { } } + public Optional> getCreateSearchDatabaseTask() { + return createSearchDatabaseTask; + } + @Override protected void onSaveInstanceState(@NonNull Bundle outState) { if (fragmentsHelper.removeFragment(PlanRouteFragment.TAG)) { @@ -693,7 +708,7 @@ protected void onResume() { BaseSettingsFragment.showInstance(this, SettingsScreenType.DATA_STORAGE, null, args, null); } else { ActivityCompat.requestPermissions(this, - new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, DownloadActivity.PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE); } } @@ -719,7 +734,9 @@ protected void onResume() { if (showWelcomeScreen && FirstUsageWizardFragment.showFragment(this)) { SecondSplashScreenFragment.SHOW = false; } else if (SendAnalyticsBottomSheetDialogFragment.shouldShowDialog(app)) { - SendAnalyticsBottomSheetDialogFragment.showInstance(app, fragmentManager, null); + SendAnalyticsBottomSheetDialogFragment + .createInstance(null) + .show(fragmentManager); } if (fragmentsHelper.isFirstScreenShowing() && (!settings.SHOW_OSMAND_WELCOME_SCREEN.get() || !showOsmAndWelcomeScreen)) { fragmentsHelper.disableFirstUsageFragment(); @@ -925,6 +942,19 @@ protected void onStart() { lockHelper.onStart(); getMyApplication().getNotificationHelper().showNotifications(); extendedMapActivity.onStart(this); + // FK-FIXME: the following code block makes the magnifying glass freeze when the user clicks on it on installed OsmAnd-nightlyFree-legacy-fat-debug.apk +// { +// createSearchDatabaseTask = +// Optional.of( +// CreateSearchDatabaseTaskProvider.getCreateSearchDatabaseTask( +// SettingsSearchButtonHelper.createSearchPreferenceFragments( +// this::getCreateSearchDatabaseTask, +// this, +// FRAGMENT_CONTAINER_VIEW_ID, +// MainSettingsFragment.class), +// this)); +// Tasks.executeTaskInParallelWithOtherTasks(createSearchDatabaseTask.get()); +// } } @Override diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index 9d783c75f12..ead770309e8 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -569,7 +569,9 @@ private ContextMenuAdapter createNormalOptionsMenu(@NonNull MapActivity activity .setListener((uiAdapter, view, item, isChecked) -> { app.logEvent("drawer_config_screen_open"); MapActivity.clearPrevActivityIntent(); - ConfigureScreenFragment.showInstance(activity); + ConfigureScreenFragment + .createInstance() + .show(activity.getSupportFragmentManager()); return true; })); diff --git a/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BottomSheetItemWithDescription.java b/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BottomSheetItemWithDescription.java index be729d56fda..c43fa0ab2fd 100644 --- a/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BottomSheetItemWithDescription.java +++ b/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BottomSheetItemWithDescription.java @@ -56,6 +56,10 @@ public void setDescription(CharSequence description) { changeDescriptionVisibility(); } + public CharSequence getDescription() { + return description; + } + public void setDescriptionMaxLines(int maxLines) { this.descriptionMaxLines = maxLines; descriptionTv.setMaxLines(maxLines); diff --git a/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapFragment.java b/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapFragment.java index 8d1e26f2f2b..f6d0237400c 100644 --- a/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapFragment.java +++ b/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapFragment.java @@ -2,6 +2,7 @@ import static net.osmand.aidlapi.OsmAndCustomizationConstants.GPX_FILES_ID; +import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.LayoutInflater; @@ -15,6 +16,9 @@ import androidx.annotation.Nullable; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; @@ -37,10 +41,10 @@ import net.osmand.plus.widgets.ctxmenu.callback.OnRowItemClick; import net.osmand.plus.widgets.ctxmenu.data.ContextMenuItem; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.client.searchDatabaseConfig.InitializePreferenceFragmentWithFragmentBeforeOnCreate; public class ConfigureMapFragment extends BaseOsmAndFragment implements OnDataChangeUiAdapter, InAppPurchaseListener, SelectGpxTaskListener { @@ -76,8 +80,8 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { updateNightMode(); View view = inflater.inflate(R.layout.fragment_configure_map, container, false); itemsContainer = view.findViewById(R.id.list); @@ -166,7 +170,7 @@ private void updateItemsView() { } private void bindCategoryView(@NonNull ContextMenuItem category, - @NonNull List nestedItems) { + @NonNull List nestedItems) { // Use the same layout for all categories views category.setLayout(R.layout.list_item_expandable_category); category.setDescription(ContextMenuUtils.getCategoryDescription(nestedItems)); @@ -314,4 +318,40 @@ public static void showInstance(@NonNull FragmentManager fm) { } } + public static class PreferenceFragment extends PreferenceFragmentCompat implements InitializePreferenceFragmentWithFragmentBeforeOnCreate { + + private List items; + + @Override + public void initializePreferenceFragmentWithFragmentBeforeOnCreate(final ConfigureMapFragment configureMapFragment) { + items = configureMapFragment.adapter.getItems(); + } + + @Override + public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { + final Context context = getPreferenceManager().getContext(); + final PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(context); + screen.setTitle("screen title"); + screen.setSummary("screen summary"); + PreferenceFragment + .asPreferences(items, context) + .forEach(screen::addPreference); + setPreferenceScreen(screen); + } + + private static List asPreferences(final List contextMenuItems, final Context context) { + return contextMenuItems + .stream() + .map(contextMenuItem -> asPreference(contextMenuItem, context)) + .collect(Collectors.toList()); + } + + private static Preference asPreference(final ContextMenuItem contextMenuItem, final Context context) { + final Preference preference = new Preference(context); + preference.setKey(contextMenuItem.getId()); + preference.setTitle(contextMenuItem.getTitle()); + preference.setSummary(contextMenuItem.getDescription()); + return preference; + } + } } diff --git a/OsmAnd/src/net/osmand/plus/dialogs/MapRenderingEngineDialog.java b/OsmAnd/src/net/osmand/plus/dialogs/MapRenderingEngineDialog.java index dd65f5b2857..3f80ddc7ebf 100644 --- a/OsmAnd/src/net/osmand/plus/dialogs/MapRenderingEngineDialog.java +++ b/OsmAnd/src/net/osmand/plus/dialogs/MapRenderingEngineDialog.java @@ -1,100 +1,121 @@ package net.osmand.plus.dialogs; +import android.app.Dialog; import android.app.ProgressDialog; -import android.content.Context; -import android.view.LayoutInflater; +import android.os.Bundle; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.AppCompatRadioButton; +import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; -import net.osmand.plus.AppInitializer; import net.osmand.plus.AppInitializeListener; +import net.osmand.plus.AppInitializer; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.views.corenative.NativeCoreContext; import net.osmand.plus.widgets.TextViewEx; -public class MapRenderingEngineDialog { +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class MapRenderingEngineDialog extends DialogFragment implements SearchablePreferenceDialog { + private final OsmandApplication app; private final FragmentActivity fragmentActivity; - private AppCompatRadioButton radioButtonLegacy; - private AppCompatRadioButton radioButtonOpengl; - private AlertDialog alertDialog; + @Nullable + private final OnRenderChangeListener renderChangeListener; - public MapRenderingEngineDialog(OsmandApplication app, FragmentActivity fragmentActivity) { + public MapRenderingEngineDialog(final OsmandApplication app, + final FragmentActivity fragmentActivity, + @Nullable final OnRenderChangeListener renderChangeListener) { this.app = app; this.fragmentActivity = fragmentActivity; + this.renderChangeListener = renderChangeListener; } - private AlertDialog createDialog(@Nullable OnRenderChangeListener renderChangeListener) { - boolean nightMode = app.getDaynightHelper().isNightModeForMapControls(); - Context themedContext = UiUtilities.getThemedContext(fragmentActivity, nightMode); - AlertDialog.Builder builder = new AlertDialog.Builder(themedContext); - View alertDialogView = LayoutInflater.from(themedContext).inflate(R.layout.alert_dialog_message_with_choice_list, null, false); + @NonNull + @Override + public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { + AlertDialog.Builder builder = + new AlertDialog.Builder( + UiUtilities.getThemedContext( + fragmentActivity, + app.getDaynightHelper().isNightModeForMapControls())); + final View alertDialogView = getLayoutInflater().inflate(R.layout.alert_dialog_message_with_choice_list, null, false); builder.setView(alertDialogView); - View legacyRenderingView = alertDialogView.findViewById(R.id.legacy_rendering); - radioButtonLegacy = setupRadioItem(legacyRenderingView, app.getResources().getString(R.string.map_rendering_engine_v1)); - View openglRenderingView = alertDialogView.findViewById(R.id.opengl_rendering); - radioButtonOpengl = setupRadioItem(openglRenderingView, app.getResources().getString(R.string.map_rendering_engine_v2)); - updateRadioButtons(app.getSettings().USE_OPENGL_RENDER.get()); + final View legacyRenderingView = alertDialogView.findViewById(R.id.legacy_rendering); + final AppCompatRadioButton radioButtonLegacy = setupRadioItem(legacyRenderingView, app.getString(getMapRenderingEngineV1())); + final View openglRenderingView = alertDialogView.findViewById(R.id.opengl_rendering); + final AppCompatRadioButton radioButtonOpengl = setupRadioItem(openglRenderingView, app.getString(getMapRenderingEngineV2())); + updateRadioButtons(app.getSettings().USE_OPENGL_RENDER.get(), radioButtonLegacy, radioButtonOpengl); radioButtonOpengl.setEnabled(Version.isOpenGlAvailable(app)); openglRenderingView.findViewById(R.id.button).setEnabled(Version.isOpenGlAvailable(app)); - legacyRenderingView.findViewById(R.id.button).setOnClickListener(view -> { - updateRenderingEngineSetting(false, renderChangeListener); - alertDialog.dismiss(); + updateRenderingEngineSetting(false, radioButtonLegacy, radioButtonOpengl); + dismiss(); }); - openglRenderingView.findViewById(R.id.button).setOnClickListener(view -> { - updateRenderingEngineSetting(true, renderChangeListener); - alertDialog.dismiss(); + updateRenderingEngineSetting(true, radioButtonLegacy, radioButtonOpengl); + dismiss(); }); return builder.create(); } + private static @StringRes int getMapRenderingEngineV1() { + return R.string.map_rendering_engine_v1; + } + + private static @StringRes int getMapRenderingEngineV2() { + return R.string.map_rendering_engine_v2; + } + private AppCompatRadioButton setupRadioItem(View view, String name) { - AppCompatRadioButton radioButton = view.findViewById(R.id.radio); - TextViewEx text = view.findViewById(R.id.text); + final AppCompatRadioButton radioButton = view.findViewById(R.id.radio); + final TextViewEx text = view.findViewById(R.id.text); text.setText(name); radioButton.setVisibility(View.VISIBLE); - return radioButton; } - private void updateRenderingEngineSetting(boolean openglEnabled, @Nullable OnRenderChangeListener listener) { - updateRadioButtons(openglEnabled); + private void updateRenderingEngineSetting(final boolean openglEnabled, + final AppCompatRadioButton radioButtonLegacy, + final AppCompatRadioButton radioButtonOpengl) { + updateRadioButtons(openglEnabled, radioButtonLegacy, radioButtonOpengl); app.getSettings().USE_OPENGL_RENDER.set(openglEnabled); if (app.isApplicationInitializing()) { - String title = app.getString(R.string.loading_smth, ""); - ProgressDialog progress = ProgressDialog.show(fragmentActivity, title, app.getString(R.string.loading_data)); + final String title = app.getString(R.string.loading_smth, ""); + final ProgressDialog progress = ProgressDialog.show(fragmentActivity, title, app.getString(R.string.loading_data)); app.getAppInitializer().addListener(new AppInitializeListener() { @Override public void onFinish(@NonNull AppInitializer init) { if (AndroidUtils.isActivityNotDestroyed(fragmentActivity)) { progress.dismiss(); } - updateRenderingEngine(openglEnabled, listener); + updateRenderingEngine(openglEnabled); } }); } else { - updateRenderingEngine(openglEnabled, listener); + updateRenderingEngine(openglEnabled); } } - private void updateRenderingEngine(boolean openglEnabled, @Nullable OnRenderChangeListener listener) { + private void updateRenderingEngine(boolean openglEnabled) { if (openglEnabled && !NativeCoreContext.isInit()) { - String title = app.getString(R.string.loading_smth, ""); - ProgressDialog progress = ProgressDialog.show(fragmentActivity, title, app.getString(R.string.loading_data)); + final String title = app.getString(R.string.loading_smth, ""); + final ProgressDialog progress = ProgressDialog.show(fragmentActivity, title, app.getString(R.string.loading_data)); app.getAppInitializer().initOpenglAsync(() -> { updateDependentAppComponents(); if (AndroidUtils.isActivityNotDestroyed(fragmentActivity)) { @@ -107,15 +128,15 @@ private void updateRenderingEngine(boolean openglEnabled, @Nullable OnRenderChan app.getOsmandMap().getMapLayers().getMapVectorLayer().setAlpha(255); } } - if (listener != null) { - listener.onRenderChange(); + if (renderChangeListener != null) { + renderChangeListener.onRenderChange(); } } private void updateDependentAppComponents() { app.getOsmandMap().setupRenderingView(); - MapActivity mapActivity = app.getOsmandMap().getMapView().getMapActivity(); + final MapActivity mapActivity = app.getOsmandMap().getMapView().getMapActivity(); if (mapActivity != null) { mapActivity.refreshMapComplete(); } @@ -123,14 +144,27 @@ private void updateDependentAppComponents() { app.getDownloadThread().runReloadIndexFilesSilent(); } - private void updateRadioButtons(boolean openglEnabled) { + private void updateRadioButtons(final boolean openglEnabled, + final AppCompatRadioButton radioButtonLegacy, + final AppCompatRadioButton radioButtonOpengl) { radioButtonLegacy.setChecked(!openglEnabled); radioButtonOpengl.setChecked(openglEnabled); } - public void showDialog(@Nullable OnRenderChangeListener renderChangeListener) { - alertDialog = createDialog(renderChangeListener); - alertDialog.show(); + @Override + public void show(final FragmentManager fragmentManager) { + show(fragmentManager, null); + } + + @Override + public String getSearchableInfo() { + return Stream + .of( + R.string.map_rendering_engine_descr, + getMapRenderingEngineV1(), + getMapRenderingEngineV2()) + .map(app::getString) + .collect(Collectors.joining(", ")); } public interface OnRenderChangeListener { diff --git a/OsmAnd/src/net/osmand/plus/feedback/SendAnalyticsBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/feedback/SendAnalyticsBottomSheetDialogFragment.java index 2f94a8784fa..843f8233bd5 100644 --- a/OsmAnd/src/net/osmand/plus/feedback/SendAnalyticsBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/feedback/SendAnalyticsBottomSheetDialogFragment.java @@ -30,10 +30,11 @@ import net.osmand.plus.base.bottomsheetmenu.simpleitems.SubtitmeListDividerItem; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.backend.preferences.OsmandPreference; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import org.apache.commons.logging.Log; -public class SendAnalyticsBottomSheetDialogFragment extends MenuBottomSheetDialogFragment { +public class SendAnalyticsBottomSheetDialogFragment extends MenuBottomSheetDialogFragment implements SearchablePreferenceDialog { public static final String TAG = "SendAnalyticsBottomSheetDialogFragment"; private static final Log LOG = PlatformUtil.getLog(SendAnalyticsBottomSheetDialogFragment.class); @@ -189,15 +190,20 @@ public static boolean shouldShowDialog(@NonNull OsmandApplication app) { return false; } - public static void showInstance(@NonNull OsmandApplication app, @NonNull FragmentManager fm, @Nullable Fragment target) { + public static @NonNull SendAnalyticsBottomSheetDialogFragment createInstance(final @Nullable Fragment target) { + final SendAnalyticsBottomSheetDialogFragment fragment = new SendAnalyticsBottomSheetDialogFragment(); + fragment.setTargetFragment(target, 0); + return fragment; + } + + @Override + public void show(final @NonNull FragmentManager fm) { try { if (fm.findFragmentByTag(TAG) == null) { - SendAnalyticsBottomSheetDialogFragment fragment = new SendAnalyticsBottomSheetDialogFragment(); - fragment.setTargetFragment(target, 0); - fragment.show(fm, TAG); + show(fm, TAG); - OsmandSettings settings = app.getSettings(); - int numberOfStarts = app.getAppInitializer().getNumberOfStarts(); + OsmandSettings settings = requiredMyApplication().getSettings(); + int numberOfStarts = requiredMyApplication().getAppInitializer().getNumberOfStarts(); OsmandPreference lastRequestNS = settings.SEND_ANONYMOUS_DATA_LAST_REQUEST_NS; if (numberOfStarts != lastRequestNS.get()) { OsmandPreference counter = settings.SEND_ANONYMOUS_DATA_REQUESTS_COUNT; @@ -210,6 +216,11 @@ public static void showInstance(@NonNull OsmandApplication app, @NonNull Fragmen } } + @Override + public String getSearchableInfo() { + return new SendAnalyticsSearchableInfoProvider(items).getSearchableInfo(); + } + public interface OnSendAnalyticsPrefsUpdate { void onAnalyticsPrefsUpdate(); diff --git a/OsmAnd/src/net/osmand/plus/feedback/SendAnalyticsSearchableInfoProvider.java b/OsmAnd/src/net/osmand/plus/feedback/SendAnalyticsSearchableInfoProvider.java new file mode 100644 index 00000000000..ab44f3b1ce0 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/feedback/SendAnalyticsSearchableInfoProvider.java @@ -0,0 +1,64 @@ +package net.osmand.plus.feedback; + +import android.view.View; +import android.widget.TextView; + +import net.osmand.plus.R; +import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; +import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton; +import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; +import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem; +import net.osmand.plus.widgets.TextViewEx; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class SendAnalyticsSearchableInfoProvider { + + private final List items; + + public SendAnalyticsSearchableInfoProvider(final List items) { + this.items = items; + } + + public String getSearchableInfo() { + return String.join(", ", getTitle(), getButtonTitles(), getLongDescriptions()); + } + + private String getTitle() { + final View titleView = items.get(0).getView(); + final CharSequence titleTop = titleView.findViewById(R.id.titleTop).getText(); + final CharSequence titleMiddle = titleView.findViewById(R.id.titleMiddle).getText(); + final CharSequence titleBottom = titleView.findViewById(R.id.titleBottom).getText(); + return String.join(", ", titleTop, titleMiddle, titleBottom); + } + + private String getButtonTitles() { + return this + .getButtons() + .map(baseBottomSheetItem -> baseBottomSheetItem.getView().findViewById(R.id.title).getText()) + .collect(Collectors.joining(", ")); + } + + private Stream getButtons() { + return items + .stream() + .filter(BottomSheetItemWithCompoundButton.class::isInstance) + .map(BottomSheetItemWithCompoundButton.class::cast); + } + + private String getLongDescriptions() { + return this + ._getLongDescriptions() + .map(BottomSheetItemWithDescription::getDescription) + .collect(Collectors.joining(", ")); + } + + private Stream _getLongDescriptions() { + return items + .stream() + .filter(LongDescriptionItem.class::isInstance) + .map(LongDescriptionItem.class::cast); + } +} diff --git a/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java b/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java index b7c97af043d..f24b44e1c2c 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java @@ -544,7 +544,9 @@ public void parseContentIntent() { break; case BaseSettingsFragment.SCREEN_CONFIG: - ConfigureScreenFragment.showInstance(mapActivity); + ConfigureScreenFragment + .createInstance() + .show(mapActivity.getSupportFragmentManager()); break; } clearIntent(intent); diff --git a/OsmAnd/src/net/osmand/plus/plugins/accessibility/AccessibilitySettingsFragment.java b/OsmAnd/src/net/osmand/plus/plugins/accessibility/AccessibilitySettingsFragment.java index 8fe999b5326..bda3a3c7947 100644 --- a/OsmAnd/src/net/osmand/plus/plugins/accessibility/AccessibilitySettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/plugins/accessibility/AccessibilitySettingsFragment.java @@ -1,6 +1,9 @@ package net.osmand.plus.plugins.accessibility; import static net.osmand.plus.plugins.PluginInfoFragment.PLUGIN_INFO; +import static net.osmand.plus.settings.fragments.ResetProfilePrefsBottomSheetFactory.createResetProfilePrefsBottomSheet; +import static net.osmand.plus.settings.fragments.SelectCopyAppModeBottomSheetFactory.createSelectCopyAppModeBottomSheet; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import android.content.Context; import android.content.Intent; @@ -14,7 +17,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.Fragment; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceViewHolder; @@ -23,16 +26,18 @@ import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.plugins.PluginsHelper; import net.osmand.plus.plugins.monitoring.OsmandMonitoringPlugin; -import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet; import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener; import net.osmand.plus.settings.backend.ApplicationMode; -import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet; import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet.ResetAppModePrefsListener; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; -public class AccessibilitySettingsFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, ResetAppModePrefsListener { +import java.util.Optional; + +public class AccessibilitySettingsFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, ResetAppModePrefsListener, ShowableSearchablePreferenceDialogProvider { private static final String ACCESSIBILITY_OPTIONS = "accessibility_options"; private static final String COPY_PLUGIN_SETTINGS = "copy_plugin_settings"; @@ -250,22 +255,24 @@ public void onPreferenceChanged(@NonNull String prefId) { } @Override - public boolean onPreferenceClick(Preference preference) { - String prefId = preference.getKey(); - if (COPY_PLUGIN_SETTINGS.equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - SelectCopyAppModeBottomSheet.showInstance(fragmentManager, this, getSelectedAppMode()); - } - } else if (RESET_TO_DEFAULT.equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - ResetProfilePrefsBottomSheet.showInstance(fragmentManager, getSelectedAppMode(), this); - } + public boolean onPreferenceClick(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return true; } return super.onPreferenceClick(preference); } + @Override + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (RESET_TO_DEFAULT.equals(preference.getKey())) { + return Optional.of(createResetProfilePrefsBottomSheet(target, this)); + } + if (COPY_PLUGIN_SETTINGS.equals(preference.getKey())) { + return Optional.of(createSelectCopyAppModeBottomSheet(target, this)); + } + return Optional.empty(); + } + @Override public void copyAppModePrefs(@NonNull ApplicationMode appMode) { OsmandMonitoringPlugin plugin = PluginsHelper.getPlugin(OsmandMonitoringPlugin.class); diff --git a/OsmAnd/src/net/osmand/plus/plugins/audionotes/MultimediaNotesFragment.java b/OsmAnd/src/net/osmand/plus/plugins/audionotes/MultimediaNotesFragment.java index 4d4d4d48bcb..6e850447233 100644 --- a/OsmAnd/src/net/osmand/plus/plugins/audionotes/MultimediaNotesFragment.java +++ b/OsmAnd/src/net/osmand/plus/plugins/audionotes/MultimediaNotesFragment.java @@ -2,7 +2,21 @@ import static net.osmand.plus.myplaces.MyPlacesActivity.TAB_ID; import static net.osmand.plus.plugins.PluginInfoFragment.PLUGIN_INFO; -import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.*; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.AV_CAMERA_FOCUS_AUTO; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.AV_CAMERA_FOCUS_CONTINUOUS; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.AV_CAMERA_FOCUS_EDOF; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.AV_CAMERA_FOCUS_HIPERFOCAL; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.AV_CAMERA_FOCUS_INFINITY; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.AV_CAMERA_FOCUS_MACRO; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.AV_PHOTO_SIZE_DEFAULT; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.EXTERNAL_PHOTO_CAM_SETTING_ID; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.EXTERNAL_RECORDER_SETTING_ID; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.NOTES_TAB; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.cameraPictureSizeDefault; +import static net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin.canDisableShutterSound; +import static net.osmand.plus.settings.fragments.ResetProfilePrefsBottomSheetFactory.createResetProfilePrefsBottomSheet; +import static net.osmand.plus.settings.fragments.SelectCopyAppModeBottomSheetFactory.createSelectCopyAppModeBottomSheet; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import android.Manifest; import android.content.Context; @@ -21,7 +35,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; -import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.Fragment; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; @@ -30,15 +44,15 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.plugins.PluginsHelper; -import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet; import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmAndAppCustomization; import net.osmand.plus.settings.backend.preferences.CommonPreference; -import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet; import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet.ResetAppModePrefsListener; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import net.osmand.plus.utils.AndroidUtils; @@ -51,8 +65,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; -public class MultimediaNotesFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, ResetAppModePrefsListener { +public class MultimediaNotesFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, ResetAppModePrefsListener, ShowableSearchablePreferenceDialogProvider { public static final int CAMERA_FOR_PHOTO_PARAMS_REQUEST_CODE = 104; @@ -466,7 +481,10 @@ private void setupResetToDefaultPref() { } @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return true; + } String prefId = preference.getKey(); if (OPEN_NOTES.equals(prefId)) { Bundle bundle = new Bundle(); @@ -478,18 +496,8 @@ public boolean onPreferenceClick(Preference preference) { favorites.putExtra(MapActivity.INTENT_PARAMS, bundle); startActivity(favorites); return true; - } else if (COPY_PLUGIN_SETTINGS.equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - SelectCopyAppModeBottomSheet.showInstance(fragmentManager, this, getSelectedAppMode()); - } - } else if (RESET_TO_DEFAULT.equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - ResetProfilePrefsBottomSheet.showInstance(fragmentManager, getSelectedAppMode(), this); - } } else if (CAMERA_PERMISSION.equals(prefId)) { - requestPermissions(new String[] {Manifest.permission.CAMERA}, CAMERA_FOR_PHOTO_PARAMS_REQUEST_CODE); + requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_FOR_PHOTO_PARAMS_REQUEST_CODE); } else if (EXTERNAL_RECORDER_SETTING_ID.equals(prefId)) { AudioVideoNotesPlugin plugin = PluginsHelper.getPlugin(AudioVideoNotesPlugin.class); if (plugin != null) { @@ -506,6 +514,17 @@ public boolean onPreferenceClick(Preference preference) { return super.onPreferenceClick(preference); } + @Override + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (RESET_TO_DEFAULT.equals(preference.getKey())) { + return Optional.of(createResetProfilePrefsBottomSheet(target, this)); + } + if (COPY_PLUGIN_SETTINGS.equals(preference.getKey())) { + return Optional.of(createSelectCopyAppModeBottomSheet(target, this)); + } + return Optional.empty(); + } + private void showSelectCameraAppDialog(@NonNull CommonPreference preference) { Context ctx = getContext(); if (ctx == null) { @@ -516,7 +535,7 @@ private void showSelectCameraAppDialog(@NonNull CommonPreference prefer int profileColor = appMode.getProfileColor(nightMode); int selected = preference.getModeValue(appMode) ? 0 : 1; - String[] entries = new String[] { + String[] entries = new String[]{ getCameraAppTitle(true), getCameraAppTitle(false) }; diff --git a/OsmAnd/src/net/osmand/plus/plugins/development/AllocatedRoutingMemoryBottomSheet.java b/OsmAnd/src/net/osmand/plus/plugins/development/AllocatedRoutingMemoryBottomSheet.java index f4594b5a88f..0c8607269e3 100644 --- a/OsmAnd/src/net/osmand/plus/plugins/development/AllocatedRoutingMemoryBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/plugins/development/AllocatedRoutingMemoryBottomSheet.java @@ -1,5 +1,7 @@ package net.osmand.plus.plugins.development; +import static android.content.Context.ACTIVITY_SERVICE; + import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.MemoryInfo; @@ -17,11 +19,8 @@ import com.google.android.material.slider.Slider; -import net.osmand.plus.utils.AndroidUtils; -import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; @@ -29,13 +28,15 @@ import net.osmand.plus.settings.backend.preferences.CommonPreference; import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; +import net.osmand.plus.utils.AndroidUtils; +import net.osmand.plus.utils.ColorUtilities; +import net.osmand.plus.utils.UiUtilities; import java.util.ArrayList; import java.util.List; -import static android.content.Context.ACTIVITY_SERVICE; - -public class AllocatedRoutingMemoryBottomSheet extends BasePreferenceBottomSheet { +public class AllocatedRoutingMemoryBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = AllocatedRoutingMemoryBottomSheet.class.getSimpleName(); @@ -79,11 +80,8 @@ private void initData() { public void createMenuItems(Bundle savedInstanceState) { LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); - String title = getString(R.string.memory_allocated_for_routing); - items.add(new TitleItem(title)); - - String description = getString(R.string.memory_allocated_for_routing_ds); - items.add(new LongDescriptionItem(description)); + items.add(new TitleItem(getTitle())); + items.add(new LongDescriptionItem(getDescription())); View view = inflater.inflate(R.layout.bottom_sheet_allocated_routing_memory, null); items.add(new BaseBottomSheetItem.Builder().setCustomView(view).create()); @@ -95,6 +93,14 @@ public void createMenuItems(Bundle savedInstanceState) { setupResetButton(buttonView); } + private @NonNull String getTitle() { + return getString(R.string.memory_allocated_for_routing); + } + + private @NonNull String getDescription() { + return getString(R.string.memory_allocated_for_routing_ds); + } + private void setupSliderView(View container) { TextView title = container.findViewById(R.id.title); TextView summary = container.findViewById(R.id.summary); @@ -205,20 +211,30 @@ private boolean isChanged() { return initialValue != currentValue; } - public static void showInstance(@NonNull FragmentManager fragmentManager, - @NonNull String key, - @NonNull Fragment target, - @Nullable ApplicationMode appMode) { + public static @NonNull AllocatedRoutingMemoryBottomSheet createInstance( + final @NonNull String key, + final @NonNull Fragment target, + final @Nullable ApplicationMode appMode) { + final Bundle args = new Bundle(); + args.putString(PREFERENCE_ID, key); + + final AllocatedRoutingMemoryBottomSheet fragment = new AllocatedRoutingMemoryBottomSheet(); + fragment.setArguments(args); + fragment.setUsedOnMap(false); + fragment.setAppMode(appMode); + fragment.setTargetFragment(target, 0); + return fragment; + } + + @Override + public void show(final FragmentManager fragmentManager) { if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, key); - AllocatedRoutingMemoryBottomSheet fragment = new AllocatedRoutingMemoryBottomSheet(); - fragment.setArguments(args); - fragment.setUsedOnMap(false); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(fragmentManager, TAG); + show(fragmentManager, TAG); } } + @Override + public String getSearchableInfo() { + return String.join(", ", getTitle(), getDescription()); + } } diff --git a/OsmAnd/src/net/osmand/plus/plugins/development/DevelopmentSettingsFragment.java b/OsmAnd/src/net/osmand/plus/plugins/development/DevelopmentSettingsFragment.java index f4eb92bb769..d106a6800ca 100644 --- a/OsmAnd/src/net/osmand/plus/plugins/development/DevelopmentSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/plugins/development/DevelopmentSettingsFragment.java @@ -1,6 +1,7 @@ package net.osmand.plus.plugins.development; import static net.osmand.plus.settings.bottomsheets.ConfirmationBottomSheet.showResetSettingsDialog; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import static net.osmand.plus.simulation.OsmAndLocationSimulation.LocationSimulationListener; import android.content.Intent; @@ -9,6 +10,7 @@ import android.os.Debug; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; @@ -23,6 +25,8 @@ import net.osmand.plus.settings.bottomsheets.BooleanRadioButtonsBottomSheet; import net.osmand.plus.settings.bottomsheets.ConfirmationBottomSheet.ConfirmationDialogListener; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import net.osmand.plus.simulation.OsmAndLocationSimulation; import net.osmand.plus.simulation.SimulateLocationFragment; @@ -30,8 +34,9 @@ import net.osmand.util.SunriseSunset; import java.text.SimpleDateFormat; +import java.util.Optional; -public class DevelopmentSettingsFragment extends BaseSettingsFragment implements ConfirmationDialogListener { +public class DevelopmentSettingsFragment extends BaseSettingsFragment implements ConfirmationDialogListener, ShowableSearchablePreferenceDialogProvider { private static final String SIMULATE_INITIAL_STARTUP = "simulate_initial_startup"; private static final String SIMULATE_YOUR_LOCATION = "simulate_your_location"; @@ -286,7 +291,8 @@ private void setupLoadAvgInfoPref() { // in microamperes (µA) as specified in the API documentation. if (Math.abs(m1.energyConsumption) > AUTO_DETECT_MICROAMPERES) m1.energyConsumption /= 1000; if (Math.abs(m5.energyConsumption) > AUTO_DETECT_MICROAMPERES) m5.energyConsumption /= 1000; - if (Math.abs(m15.energyConsumption) > AUTO_DETECT_MICROAMPERES) m15.energyConsumption /= 1000; + if (Math.abs(m15.energyConsumption) > AUTO_DETECT_MICROAMPERES) + m15.energyConsumption /= 1000; String fps = String.format("%.0f / %.0f / %.0f", m1.fps1k, m5.fps1k, m15.fps1k); String gpu = String.format("%.2f / %.2f / %.2f", m1.gpu1k, m5.gpu1k, m15.gpu1k); @@ -311,12 +317,8 @@ private void setupResetToDefaultButton() { @Override public boolean onPreferenceClick(Preference preference) { - String prefId = preference.getKey(); - if (SIMULATE_YOUR_LOCATION.equals(prefId)) { - FragmentActivity activity = getActivity(); - if (activity != null) { - SimulateLocationFragment.showInstance(activity.getSupportFragmentManager(), null, false); - } + final String prefId = preference.getKey(); + if (showDialogForPreference(preference, this)) { return true; } else if (SIMULATE_INITIAL_STARTUP.equals(prefId)) { app.getAppInitializer().resetFirstTimeRun(); @@ -337,16 +339,6 @@ public boolean onPreferenceClick(Preference preference) { preference.setSummary(getAgpsDataDownloadedSummary()); } return true; - } else if (settings.LOCATION_INTERPOLATION_PERCENT.getId().equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - LocationInterpolationBottomSheet.showInstance(fragmentManager, preference.getKey(), this, getSelectedAppMode()); - } - } else if (settings.MEMORY_ALLOCATED_FOR_ROUTING.getId().equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - AllocatedRoutingMemoryBottomSheet.showInstance(fragmentManager, preference.getKey(), this, getSelectedAppMode()); - } } else if (RESET_TO_DEFAULT.equals(prefId)) { FragmentManager fragmentManager = getFragmentManager(); if (fragmentManager != null) { @@ -356,6 +348,61 @@ public boolean onPreferenceClick(Preference preference) { return super.onPreferenceClick(preference); } + @Override + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (SIMULATE_YOUR_LOCATION.equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + SimulateLocationFragment.createInstance( + null, + false)) { + + @Override + protected void show(final SimulateLocationFragment simulateLocationFragment) { + final FragmentActivity activity = getActivity(); + if (activity != null) { + simulateLocationFragment.show(activity.getSupportFragmentManager()); + } + } + }); + } + if (settings.MEMORY_ALLOCATED_FOR_ROUTING.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + AllocatedRoutingMemoryBottomSheet.createInstance( + preference.getKey(), + target.orElse(null), + getSelectedAppMode())) { + + @Override + protected void show(final AllocatedRoutingMemoryBottomSheet allocatedRoutingMemoryBottomSheet) { + final FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager != null) { + allocatedRoutingMemoryBottomSheet.show(fragmentManager); + } + } + }); + } + if (settings.LOCATION_INTERPOLATION_PERCENT.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + LocationInterpolationBottomSheet.createInstance( + preference, + target, + getSelectedAppMode())) { + + @Override + protected void show(final LocationInterpolationBottomSheet locationInterpolationBottomSheet) { + final FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager != null) { + locationInterpolationBottomSheet.show(fragmentManager); + } + } + }); + } + return Optional.empty(); + } + @Override public void onApplyPreferenceChange(String prefId, boolean applyToAllProfiles, Object newValue) { if (prefId.equals(settings.LOCATION_INTERPOLATION_PERCENT.getId())) { diff --git a/OsmAnd/src/net/osmand/plus/plugins/development/LocationInterpolationBottomSheet.java b/OsmAnd/src/net/osmand/plus/plugins/development/LocationInterpolationBottomSheet.java index 93a4ce5d1f7..e494739c039 100644 --- a/OsmAnd/src/net/osmand/plus/plugins/development/LocationInterpolationBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/plugins/development/LocationInterpolationBottomSheet.java @@ -9,9 +9,9 @@ import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import com.google.android.material.slider.Slider; @@ -23,15 +23,18 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.preferences.CommonPreference; import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet; +import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheetInitializer; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.UiUtilities; import java.util.ArrayList; import java.util.List; +import java.util.Optional; -public class LocationInterpolationBottomSheet extends BasePreferenceBottomSheet { +public class LocationInterpolationBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = LocationInterpolationBottomSheet.class.getSimpleName(); @@ -73,11 +76,8 @@ private void initData() { public void createMenuItems(Bundle savedInstanceState) { LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode); - String title = getString(R.string.location_interpolation_percent); - items.add(new TitleItem(title)); - - String description = getString(R.string.location_interpolation_percent_desc); - items.add(new LongDescriptionItem(description)); + items.add(new TitleItem(getTitle())); + items.add(new LongDescriptionItem(getDescription())); View view = inflater.inflate(R.layout.bottom_sheet_allocated_routing_memory, null); items.add(new BaseBottomSheetItem.Builder().setCustomView(view).create()); @@ -89,6 +89,16 @@ public void createMenuItems(Bundle savedInstanceState) { setupResetButton(buttonView); } + @NonNull + private String getTitle() { + return getString(R.string.location_interpolation_percent); + } + + @NonNull + private String getDescription() { + return getString(R.string.location_interpolation_percent_desc); + } + @SuppressLint("SetTextI18n") private void setupSliderView(View container) { TextView title = container.findViewById(R.id.title); @@ -161,7 +171,7 @@ protected int getRightBottomButtonTextId() { private List getAvailableRange() { List powRange = new ArrayList<>(); - for (int i = 0; i <= 100; i+=10) { + for (int i = 0; i <= 100; i += 10) { powRange.add(i); } return powRange; @@ -180,19 +190,23 @@ private boolean isChanged() { return initialValue != currentValue; } - public static void showInstance(@NonNull FragmentManager fragmentManager, - @NonNull String key, - @NonNull Fragment target, - @Nullable ApplicationMode appMode) { + public static LocationInterpolationBottomSheet createInstance(final Preference preference, + final Optional target, + final ApplicationMode appMode) { + return BasePreferenceBottomSheetInitializer + .initialize(new LocationInterpolationBottomSheet()) + .with(Optional.of(preference), appMode, false, target); + } + + @Override + public void show(final FragmentManager fragmentManager) { if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, key); - LocationInterpolationBottomSheet fragment = new LocationInterpolationBottomSheet(); - fragment.setArguments(args); - fragment.setUsedOnMap(false); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(fragmentManager, TAG); + show(fragmentManager, TAG); } } + + @Override + public String getSearchableInfo() { + return String.join(", ", getTitle(), getDescription()); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/plugins/monitoring/MonitoringSettingsFragment.java b/OsmAnd/src/net/osmand/plus/plugins/monitoring/MonitoringSettingsFragment.java index 1d55971c254..a72d86b69c9 100644 --- a/OsmAnd/src/net/osmand/plus/plugins/monitoring/MonitoringSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/plugins/monitoring/MonitoringSettingsFragment.java @@ -7,6 +7,9 @@ import static net.osmand.plus.settings.backend.OsmandSettings.MONTHLY_DIRECTORY; import static net.osmand.plus.settings.backend.OsmandSettings.REC_DIRECTORY; import static net.osmand.plus.settings.controllers.BatteryOptimizationController.isIgnoringBatteryOptimizations; +import static net.osmand.plus.settings.fragments.ResetProfilePrefsBottomSheetFactory.createResetProfilePrefsBottomSheet; +import static net.osmand.plus.settings.fragments.SelectCopyAppModeBottomSheetFactory.createSelectCopyAppModeBottomSheet; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -32,23 +35,22 @@ import net.osmand.plus.chooseplan.OsmAndFeature; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.inapp.InAppPurchaseUtils; -import net.osmand.plus.plugins.odb.VehicleMetricsPlugin; -import net.osmand.shared.gpx.RouteActivityHelper; import net.osmand.plus.myplaces.MyPlacesActivity; import net.osmand.plus.plugins.PluginsHelper; import net.osmand.plus.plugins.externalsensors.ExternalSensorTrackDataType; import net.osmand.plus.plugins.externalsensors.ExternalSensorsPlugin; -import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet; +import net.osmand.plus.plugins.odb.VehicleMetricsPlugin; import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmAndAppCustomization; import net.osmand.plus.settings.backend.preferences.CommonPreference; import net.osmand.plus.settings.backend.preferences.OsmandPreference; -import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet; import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet.ResetAppModePrefsListener; import net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet; import net.osmand.plus.settings.controllers.BatteryOptimizationController; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import net.osmand.plus.track.fragments.controller.SelectRouteActivityController; @@ -56,6 +58,7 @@ import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.FontCache; import net.osmand.plus.widgets.style.CustomTypefaceSpan; +import net.osmand.shared.gpx.RouteActivityHelper; import net.osmand.shared.gpx.primitives.RouteActivity; import net.osmand.util.Algorithms; @@ -63,8 +66,9 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Optional; -public class MonitoringSettingsFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, ResetAppModePrefsListener { +public class MonitoringSettingsFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, ResetAppModePrefsListener, ShowableSearchablePreferenceDialogProvider { private static final String DISABLE_BATTERY_OPTIMIZATION = "disable_battery_optimization"; private static final String COPY_PLUGIN_SETTINGS = "copy_plugin_settings"; @@ -457,7 +461,21 @@ protected void onBindPreferenceViewHolder(@NonNull Preference preference, @NonNu } @Override - public boolean onPreferenceClick(Preference preference) { + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (RESET_TO_DEFAULT.equals(preference.getKey())) { + return Optional.of(createResetProfilePrefsBottomSheet(target, this)); + } + if (COPY_PLUGIN_SETTINGS.equals(preference.getKey())) { + return Optional.of(createSelectCopyAppModeBottomSheet(target, this)); + } + return Optional.empty(); + } + + @Override + public boolean onPreferenceClick(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return true; + } String prefId = preference.getKey(); if (OPEN_TRACKS.equals(prefId)) { Bundle bundle = new Bundle(); @@ -469,16 +487,6 @@ public boolean onPreferenceClick(Preference preference) { favorites.putExtra(MapActivity.INTENT_PARAMS, bundle); startActivity(favorites); return true; - } else if (COPY_PLUGIN_SETTINGS.equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - SelectCopyAppModeBottomSheet.showInstance(fragmentManager, this, getSelectedAppMode()); - } - } else if (RESET_TO_DEFAULT.equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - ResetProfilePrefsBottomSheet.showInstance(fragmentManager, getSelectedAppMode(), this); - } } else if (DISABLE_BATTERY_OPTIMIZATION.endsWith(prefId)) { MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { diff --git a/OsmAnd/src/net/osmand/plus/plugins/weather/dialogs/WeatherSettingsFragment.java b/OsmAnd/src/net/osmand/plus/plugins/weather/dialogs/WeatherSettingsFragment.java index 0d8854eb0ab..8eb97c80370 100644 --- a/OsmAnd/src/net/osmand/plus/plugins/weather/dialogs/WeatherSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/plugins/weather/dialogs/WeatherSettingsFragment.java @@ -1,5 +1,9 @@ package net.osmand.plus.plugins.weather.dialogs; +import static net.osmand.plus.settings.fragments.ResetProfilePrefsBottomSheetFactory.createResetProfilePrefsBottomSheet; +import static net.osmand.plus.settings.fragments.SelectCopyAppModeBottomSheetFactory.createSelectCopyAppModeBottomSheet; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; + import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -7,7 +11,6 @@ import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceViewHolder; @@ -23,22 +26,23 @@ import net.osmand.plus.plugins.weather.listener.WeatherCacheSizeChangeListener; import net.osmand.plus.plugins.weather.units.WeatherUnit; import net.osmand.plus.plugins.weather.viewholder.WeatherTotalCacheSizeViewHolder; -import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet; import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener; import net.osmand.plus.settings.backend.ApplicationMode; -import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet; import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet.ResetAppModePrefsListener; import net.osmand.plus.settings.fragments.BaseSettingsFragment; import net.osmand.plus.settings.fragments.OnPreferenceChanged; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.util.CollectionUtils; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; public class WeatherSettingsFragment extends BaseSettingsFragment implements WeatherCacheSizeChangeListener, - CopyAppModePrefsListener, ResetAppModePrefsListener { + CopyAppModePrefsListener, ResetAppModePrefsListener, ShowableSearchablePreferenceDialogProvider { private static final String WEATHER_ONLINE_CACHE = "weather_online_cache"; private static final String WEATHER_OFFLINE_CACHE = "weather_offline_cache"; @@ -162,7 +166,21 @@ protected void onBindPreferenceViewHolder(@NonNull Preference preference, @NonNu } @Override - public boolean onPreferenceClick(Preference preference) { + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (RESET_TO_DEFAULT.equals(preference.getKey())) { + return Optional.of(createResetProfilePrefsBottomSheet(target, this)); + } + if (COPY_PLUGIN_SETTINGS.equals(preference.getKey())) { + return Optional.of(createSelectCopyAppModeBottomSheet(target, this)); + } + return Optional.empty(); + } + + @Override + public boolean onPreferenceClick(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return true; + } String key = preference.getKey(); if (WEATHER_ONLINE_CACHE.equals(key) && offlineForecastHelper.canClearOnlineCache()) { Context ctx = getContext(); @@ -170,16 +188,6 @@ public boolean onPreferenceClick(Preference preference) { WeatherDialogs.showClearOnlineCacheDialog(ctx, isNightMode()); } return false; - } else if (RESET_TO_DEFAULT.equals(key)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - ResetProfilePrefsBottomSheet.showInstance(fragmentManager, getSelectedAppMode(), this); - } - } else if (COPY_PLUGIN_SETTINGS.equals(key)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - SelectCopyAppModeBottomSheet.showInstance(fragmentManager, this, getSelectedAppMode()); - } } return super.onPreferenceClick(preference); } diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectBaseProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/profiles/SelectBaseProfileBottomSheet.java index 604baa45aa0..1b4fc9878f0 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectBaseProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectBaseProfileBottomSheet.java @@ -1,60 +1,97 @@ package net.osmand.plus.profiles; +import static net.osmand.plus.settings.fragments.search.SearchableInfoHelper.getProfileDescriptions; + import android.os.Bundle; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; +import com.google.common.collect.ImmutableList; + import net.osmand.plus.R; import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; import net.osmand.plus.profiles.data.ProfileDataObject; import net.osmand.plus.profiles.data.ProfileDataUtils; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheetInitializer; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import java.util.ArrayList; import java.util.List; +import java.util.Optional; -public class SelectBaseProfileBottomSheet extends SelectProfileBottomSheet { +public class SelectBaseProfileBottomSheet extends SelectProfileBottomSheet implements SearchablePreferenceDialog { private final List profiles = new ArrayList<>(); - public static void showInstance(@NonNull FragmentActivity activity, - @Nullable Fragment target, - ApplicationMode appMode, - String selectedItemKey, - boolean usedOnMap) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); - if (!fragmentManager.isStateSaved()) { - SelectBaseProfileBottomSheet fragment = new SelectBaseProfileBottomSheet(); - Bundle args = new Bundle(); + @NonNull + public static SelectBaseProfileBottomSheet createInstance(final Optional target, + final ApplicationMode appMode, + final String selectedItemKey, + final boolean usedOnMap) { + final SelectBaseProfileBottomSheet bottomSheet = new SelectBaseProfileBottomSheet(); + { + final Bundle args = new Bundle(); args.putString(SELECTED_KEY, selectedItemKey); - fragment.setArguments(args); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(fragmentManager, TAG); + bottomSheet.setArguments(args); } + return BasePreferenceBottomSheetInitializer + .initialize(bottomSheet) + .with(Optional.empty(), appMode, usedOnMap, target); + } @Override public void createMenuItems(Bundle savedInstanceState) { - items.add(new TitleItem(getString(R.string.select_base_profile_dialog_title))); - items.add(new LongDescriptionItem(getString(R.string.select_base_profile_dialog_message))); + items.add(new TitleItem(getTitle())); + items.add(new LongDescriptionItem(getDescription())); for (int i = 0; i < profiles.size(); i++) { addProfileItem(profiles.get(i)); } } + @NonNull + private String getTitle() { + return getString(R.string.select_base_profile_dialog_title); + } + + @NonNull + private String getDescription() { + return getString(R.string.select_base_profile_dialog_message); + } + @Override protected void refreshProfiles() { profiles.clear(); - List appModes = new ArrayList<>(ApplicationMode.allPossibleValues()); + profiles.addAll(getProfiles()); + } + + @NonNull + private List getProfiles() { + final List appModes = new ArrayList<>(ApplicationMode.allPossibleValues()); appModes.remove(ApplicationMode.DEFAULT); - profiles.addAll(ProfileDataUtils.getDataObjects(app, appModes)); + return ProfileDataUtils.getDataObjects(app, appModes); + } + + @Override + public void show(final FragmentManager fragmentManager) { + if (!fragmentManager.isStateSaved()) { + show(fragmentManager, TAG); + } } + @Override + public String getSearchableInfo() { + return String.join( + ", ", + ImmutableList + .builder() + .add(getTitle()) + .add(getDescription()) + .addAll(getProfileDescriptions(getProfiles())) + .build()); + } } diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectCopyAppModeBottomSheet.java b/OsmAnd/src/net/osmand/plus/profiles/SelectCopyAppModeBottomSheet.java index 5b3741c9d00..5fb972f607e 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectCopyAppModeBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectCopyAppModeBottomSheet.java @@ -3,20 +3,23 @@ import android.os.Bundle; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import net.osmand.PlatformUtil; -import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; +import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import org.apache.commons.logging.Log; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; -public class SelectCopyAppModeBottomSheet extends AppModesBottomSheetDialogFragment { +public class SelectCopyAppModeBottomSheet extends AppModesBottomSheetDialogFragment implements SearchablePreferenceDialog { public static final String TAG = "SelectCopyAppModeBottomSheet"; @@ -112,29 +115,34 @@ protected void onRightBottomButtonClick() { dismiss(); } - public static void showInstance(@NonNull FragmentManager fm, Fragment target, - @NonNull ApplicationMode currentMode) { - showInstance(fm, target, false, currentMode); + public static SelectCopyAppModeBottomSheet createInstance(final @Nullable Fragment target, + final @NonNull ApplicationMode currentMode) { + final SelectCopyAppModeBottomSheet bottomSheet = new SelectCopyAppModeBottomSheet(); + { + final Bundle args = new Bundle(); + args.putString(CURRENT_APP_MODE_KEY, currentMode.getStringKey()); + bottomSheet.setArguments(args); + } + bottomSheet.setTargetFragment(target, 0); + bottomSheet.setUsedOnMap(false); + return bottomSheet; } - public static void showInstance(@NonNull FragmentManager fm, Fragment target, - boolean usedOnMap, @NonNull ApplicationMode currentMode) { - try { - if (fm.findFragmentByTag(TAG) == null) { - Bundle args = new Bundle(); - args.putString(CURRENT_APP_MODE_KEY, currentMode.getStringKey()); - - SelectCopyAppModeBottomSheet fragment = new SelectCopyAppModeBottomSheet(); - fragment.setTargetFragment(target, 0); - fragment.setUsedOnMap(usedOnMap); - fragment.setArguments(args); - fragment.show(fm, TAG); - } - } catch (RuntimeException e) { - LOG.error("showInstance", e); + @Override + public void show(final FragmentManager fragmentManager) { + if (fragmentManager.findFragmentByTag(TAG) == null) { + show(fragmentManager, TAG); } } + @Override + public String getSearchableInfo() { + return appModes + .stream() + .map(ApplicationMode::toHumanString) + .collect(Collectors.joining(", ")); + } + public interface CopyAppModePrefsListener { void copyAppModePrefs(@NonNull ApplicationMode appMode); } diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectDefaultProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/profiles/SelectDefaultProfileBottomSheet.java index 098c4b652a5..38ff9a65d3b 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectDefaultProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectDefaultProfileBottomSheet.java @@ -1,5 +1,7 @@ package net.osmand.plus.profiles; +import static net.osmand.plus.settings.fragments.search.SearchableInfoHelper.getProfileDescriptions; + import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; @@ -7,9 +9,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; +import com.google.common.collect.ImmutableList; + import net.osmand.plus.R; import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem; @@ -17,30 +20,30 @@ import net.osmand.plus.profiles.data.ProfileDataObject; import net.osmand.plus.profiles.data.ProfileDataUtils; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheetInitializer; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import java.util.ArrayList; import java.util.List; +import java.util.Optional; -public class SelectDefaultProfileBottomSheet extends SelectProfileBottomSheet { +public class SelectDefaultProfileBottomSheet extends SelectProfileBottomSheet implements SearchablePreferenceDialog { private final List profiles = new ArrayList<>(); - public static void showInstance(@NonNull FragmentActivity activity, - @Nullable Fragment target, - ApplicationMode appMode, - String selectedItemKey, - boolean usedOnMap) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); - if (!fragmentManager.isStateSaved()) { - SelectDefaultProfileBottomSheet fragment = new SelectDefaultProfileBottomSheet(); - Bundle args = new Bundle(); + public static SelectDefaultProfileBottomSheet createInstance(final Optional target, + final ApplicationMode appMode, + final String selectedItemKey, + final boolean usedOnMap) { + final SelectDefaultProfileBottomSheet bottomSheet = new SelectDefaultProfileBottomSheet(); + { + final Bundle args = new Bundle(); args.putString(SELECTED_KEY, selectedItemKey); - fragment.setArguments(args); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(fragmentManager, TAG); + bottomSheet.setArguments(args); } + return BasePreferenceBottomSheetInitializer + .initialize(bottomSheet) + .with(Optional.empty(), appMode, usedOnMap, target); } @Override @@ -77,7 +80,29 @@ protected boolean isSelected(ProfileDataObject profile) { @Override protected void refreshProfiles() { profiles.clear(); - profiles.addAll(ProfileDataUtils.getDataObjects(app, ApplicationMode.values(app))); + profiles.addAll(getProfiles()); + } + + @NonNull + private List getProfiles() { + return ProfileDataUtils.getDataObjects(app, ApplicationMode.values(app)); + } + + @Override + public void show(final FragmentManager fragmentManager) { + if (!fragmentManager.isStateSaved()) { + show(fragmentManager, TAG); + } } + @Override + public String getSearchableInfo() { + return String.join( + ", ", + ImmutableList + .builder() + .add(getString(R.string.profile_by_default_description)) + .addAll(getProfileDescriptions(getProfiles())) + .build()); + } } diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectNavProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/profiles/SelectNavProfileBottomSheet.java index 8c6dc1f541e..732e22e9da0 100644 --- a/OsmAnd/src/net/osmand/plus/profiles/SelectNavProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/profiles/SelectNavProfileBottomSheet.java @@ -2,6 +2,7 @@ import static net.osmand.plus.importfiles.ImportType.ROUTING; import static net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.NONE_VEHICLE; +import static net.osmand.plus.settings.fragments.search.SearchableInfoHelper.getProfileNames; import android.content.Context; import android.graphics.drawable.Drawable; @@ -17,9 +18,10 @@ import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; +import com.google.common.collect.ImmutableList; + import net.osmand.IndexConstants; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; @@ -39,7 +41,9 @@ import net.osmand.plus.profiles.data.RoutingDataObject; import net.osmand.plus.profiles.data.RoutingDataUtils; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheetInitializer; import net.osmand.plus.settings.fragments.NavigationFragment; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem; @@ -54,8 +58,12 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.common.Lists; -public class SelectNavProfileBottomSheet extends SelectProfileBottomSheet implements ImportTaskListener { +public class SelectNavProfileBottomSheet extends SelectProfileBottomSheet implements ImportTaskListener, SearchablePreferenceDialog { private static final String DOWNLOADED_PREDEFINED_JSON = "downloaded_predefined_json"; private static final String DIALOG_TYPE = "dialog_type"; @@ -79,24 +87,23 @@ public enum DialogMode { int titleId; } - public static void showInstance(@NonNull FragmentActivity activity, - @Nullable Fragment target, - ApplicationMode appMode, - String selectedItemKey, - boolean usedOnMap) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); - if (!fragmentManager.isStateSaved()) { - SelectNavProfileBottomSheet fragment = new SelectNavProfileBottomSheet(); - Bundle args = new Bundle(); + public static SelectNavProfileBottomSheet createInstance(final Optional target, + final ApplicationMode appMode, + final String selectedItemKey, + final boolean usedOnMap) { + final SelectNavProfileBottomSheet bottomSheet = new SelectNavProfileBottomSheet(); + { + final Bundle args = new Bundle(); args.putString(SELECTED_KEY, selectedItemKey); - fragment.setArguments(args); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - boolean isOnline = OnlineRoutingEngine.isOnlineEngineKey(selectedItemKey); - fragment.setDialogMode(isOnline ? DialogMode.ONLINE : DialogMode.OFFLINE); - fragment.show(fragmentManager, TAG); + bottomSheet.setArguments(args); } + bottomSheet.setDialogMode( + OnlineRoutingEngine.isOnlineEngineKey(selectedItemKey) ? + DialogMode.ONLINE : + DialogMode.OFFLINE); + return BasePreferenceBottomSheetInitializer + .initialize(bottomSheet) + .with(Optional.empty(), appMode, usedOnMap, target); } @Override @@ -515,4 +522,41 @@ public void setDialogMode(DialogMode dialogMode) { this.dialogMode = dialogMode; } + @Override + public void show(final FragmentManager fragmentManager) { + if (!fragmentManager.isStateSaved()) { + show(fragmentManager, TAG); + } + } + + @Override + public String getSearchableInfo() { + return String.join( + ", ", + ImmutableList + .builder() + .add(getString(R.string.select_nav_profile_dialog_message)) + .addAll(getProfilesNames(DialogMode.OFFLINE)) + .addAll(getProfilesNames(DialogMode.ONLINE)) + .build()); + } + + private List getProfilesNames(final DialogMode dialogMode) { + return getProfileNames(getProfilesList(getProfilesGroups(dialogMode))); + } + + private List getProfilesGroups(final DialogMode dialogMode) { + return switch (dialogMode) { + case ONLINE -> getDataUtils().getOnlineProfiles(predefinedGroups); + case OFFLINE -> getDataUtils().getOfflineProfiles(); + }; + } + + private List getProfilesList(final List profilesGroups) { + return Lists.concat( + profilesGroups + .stream() + .map(ProfilesGroup::getProfiles) + .collect(Collectors.toList())); + } } diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java index bab37856838..89e00d699f1 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java @@ -45,18 +45,13 @@ import net.osmand.PlatformUtil; import net.osmand.StateChangedListener; import net.osmand.core.android.MapRendererView; -import net.osmand.data.*; -import net.osmand.plus.routepreparationmenu.data.RouteMenuAppModes; -import net.osmand.plus.routepreparationmenu.data.parameters.AvoidPTTypesRoutingParameter; -import net.osmand.plus.routepreparationmenu.data.parameters.AvoidRoadsRoutingParameter; -import net.osmand.plus.routepreparationmenu.data.parameters.LocalRoutingParameter; -import net.osmand.plus.routepreparationmenu.data.parameters.LocalRoutingParameterGroup; -import net.osmand.plus.routepreparationmenu.data.parameters.MuteSoundRoutingParameter; -import net.osmand.plus.routepreparationmenu.data.parameters.OtherLocalRoutingParameter; -import net.osmand.plus.routepreparationmenu.data.parameters.ShowAlongTheRouteItem; -import net.osmand.shared.gpx.GpxFile; -import net.osmand.shared.gpx.GpxHelper; -import net.osmand.shared.gpx.primitives.WptPt; +import net.osmand.data.FavouritePoint; +import net.osmand.data.LatLon; +import net.osmand.data.PointDescription; +import net.osmand.data.QuadRect; +import net.osmand.data.RotatedTileBox; +import net.osmand.data.SpecialPointType; +import net.osmand.data.ValueHolder; import net.osmand.plus.GeocodingLookupService.AddressLookupRequest; import net.osmand.plus.OsmAndLocationProvider; import net.osmand.plus.OsmandApplication; @@ -81,8 +76,32 @@ import net.osmand.plus.myplaces.favorites.FavouritesHelper; import net.osmand.plus.poi.PoiUIFilter; import net.osmand.plus.profiles.ConfigureAppModesBottomSheetDialogFragment; -import net.osmand.plus.routepreparationmenu.cards.*; +import net.osmand.plus.routepreparationmenu.cards.AttachTrackToRoadsBannerCard; +import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener; +import net.osmand.plus.routepreparationmenu.cards.HistoryCard; +import net.osmand.plus.routepreparationmenu.cards.HomeWorkCard; +import net.osmand.plus.routepreparationmenu.cards.LongDistanceWarningCard; +import net.osmand.plus.routepreparationmenu.cards.MapMarkersCard; +import net.osmand.plus.routepreparationmenu.cards.MissingMapsWarningCard; +import net.osmand.plus.routepreparationmenu.cards.NauticalBridgeHeightWarningCard; +import net.osmand.plus.routepreparationmenu.cards.PedestrianRouteCard; +import net.osmand.plus.routepreparationmenu.cards.PreviousRouteCard; +import net.osmand.plus.routepreparationmenu.cards.PublicTransportBetaWarningCard; +import net.osmand.plus.routepreparationmenu.cards.PublicTransportCard; +import net.osmand.plus.routepreparationmenu.cards.PublicTransportNotFoundSettingsWarningCard; +import net.osmand.plus.routepreparationmenu.cards.PublicTransportNotFoundWarningCard; +import net.osmand.plus.routepreparationmenu.cards.SimpleRouteCard; +import net.osmand.plus.routepreparationmenu.cards.TrackEditCard; +import net.osmand.plus.routepreparationmenu.cards.TracksCard; +import net.osmand.plus.routepreparationmenu.data.RouteMenuAppModes; +import net.osmand.plus.routepreparationmenu.data.parameters.AvoidPTTypesRoutingParameter; +import net.osmand.plus.routepreparationmenu.data.parameters.AvoidRoadsRoutingParameter; +import net.osmand.plus.routepreparationmenu.data.parameters.LocalRoutingParameter; +import net.osmand.plus.routepreparationmenu.data.parameters.LocalRoutingParameterGroup; +import net.osmand.plus.routepreparationmenu.data.parameters.MuteSoundRoutingParameter; +import net.osmand.plus.routepreparationmenu.data.parameters.OtherLocalRoutingParameter; +import net.osmand.plus.routepreparationmenu.data.parameters.ShowAlongTheRouteItem; import net.osmand.plus.routing.GPXRouteParams.GPXRouteParamsBuilder; import net.osmand.plus.routing.IRouteInformationListener; import net.osmand.plus.routing.RouteCalculationResult; @@ -115,6 +134,9 @@ import net.osmand.router.GeneralRouter.RoutingParameter; import net.osmand.router.TransportRouteResult; import net.osmand.search.core.SearchResult; +import net.osmand.shared.gpx.GpxFile; +import net.osmand.shared.gpx.GpxHelper; +import net.osmand.shared.gpx.primitives.WptPt; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; @@ -122,7 +144,14 @@ import java.io.File; import java.lang.ref.WeakReference; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.Stack; public class MapRouteInfoMenu implements IRouteInformationListener, CardListener, FavoritesListener { @@ -1184,8 +1213,9 @@ private void createMuteSoundRoutingParameterButton(MapActivity mapActivity, OsmandApplication app = getApp(); if (app != null) { if (app.getSettings().isVoiceProviderNotSelected(appMode)) { - VoiceLanguageBottomSheetFragment.showInstance(mapActivity.getSupportFragmentManager(), - null, appMode, true); + VoiceLanguageBottomSheetFragment + .createInstance(Optional.empty(), appMode, true) + .show(mapActivity.getSupportFragmentManager()); } else { app.getRoutingOptionsHelper().switchSound(); } diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java index 2617417522b..2dd0dc04f6c 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteOptionsBottomSheet.java @@ -28,15 +28,12 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import net.osmand.plus.routepreparationmenu.data.parameters.OtherLocalRoutingParameter; -import net.osmand.shared.gpx.GpxFile; import net.osmand.PlatformUtil; import net.osmand.StateChangedListener; -import net.osmand.plus.avoidroads.AvoidRoadsBottomSheetDialogFragment; -import net.osmand.plus.simulation.OsmAndLocationSimulation; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.avoidroads.AvoidRoadsBottomSheetDialogFragment; import net.osmand.plus.base.MenuBottomSheetDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton; @@ -44,7 +41,6 @@ import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerStartItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; -import net.osmand.plus.track.helpers.GpxUiHelper; import net.osmand.plus.measurementtool.MeasurementToolFragment; import net.osmand.plus.routepreparationmenu.data.parameters.AvoidPTTypesRoutingParameter; import net.osmand.plus.routepreparationmenu.data.parameters.AvoidRoadsRoutingParameter; @@ -55,6 +51,7 @@ import net.osmand.plus.routepreparationmenu.data.parameters.LocalRoutingParameter; import net.osmand.plus.routepreparationmenu.data.parameters.LocalRoutingParameterGroup; import net.osmand.plus.routepreparationmenu.data.parameters.MuteSoundRoutingParameter; +import net.osmand.plus.routepreparationmenu.data.parameters.OtherLocalRoutingParameter; import net.osmand.plus.routepreparationmenu.data.parameters.OtherSettingsRoutingParameter; import net.osmand.plus.routepreparationmenu.data.parameters.RouteSimulationItem; import net.osmand.plus.routepreparationmenu.data.parameters.ShowAlongTheRouteItem; @@ -71,8 +68,10 @@ import net.osmand.plus.settings.fragments.BaseSettingsFragment; import net.osmand.plus.settings.fragments.SettingsScreenType; import net.osmand.plus.settings.fragments.voice.VoiceLanguageBottomSheetFragment; +import net.osmand.plus.simulation.OsmAndLocationSimulation; import net.osmand.plus.track.fragments.TrackAltitudeBottomSheet; import net.osmand.plus.track.fragments.TrackAltitudeBottomSheet.CalculateAltitudeListener; +import net.osmand.plus.track.helpers.GpxUiHelper; import net.osmand.plus.track.helpers.save.SaveGpxHelper; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; @@ -80,6 +79,7 @@ import net.osmand.plus.utils.UiUtilities; import net.osmand.router.GeneralRouter; import net.osmand.router.GeneralRouter.RoutingParameter; +import net.osmand.shared.gpx.GpxFile; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -89,6 +89,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Optional; public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment implements CalculateAltitudeListener { @@ -319,8 +320,9 @@ public void onClick(View v) { routingHelper.getVoiceRouter().setMuteForMode(applicationMode, active); String voiceProvider = app.getSettings().VOICE_PROVIDER.getModeValue(applicationMode); if (voiceProvider == null || OsmandSettings.VOICE_PROVIDER_NOT_USE.equals(voiceProvider)) { - VoiceLanguageBottomSheetFragment.showInstance(mapActivity.getSupportFragmentManager(), - RouteOptionsBottomSheet.this, applicationMode, usedOnMap); + VoiceLanguageBottomSheetFragment + .createInstance(Optional.of(RouteOptionsBottomSheet.this), applicationMode, usedOnMap) + .show(mapActivity.getSupportFragmentManager()); } else { cb.setChecked(!active); icon.setImageDrawable(getPaintedContentIcon(!active ? optionsItem.getActiveIconId() : optionsItem.getDisabledIconId())); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java index 6e051904e2f..372f0fc9495 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java @@ -479,7 +479,7 @@ public boolean setApplicationMode(ApplicationMode appMode, boolean markAsLastUse return valueSaved; } - public final OsmandPreference APPLICATION_MODE = new PreferenceWithListener() { + public final OsmandPreference APPLICATION_MODE = new PreferenceWithListener<>() { @Override public String getId() { @@ -1700,6 +1700,7 @@ protected boolean setValue(Object prefs, Boolean val) { public final CommonPreference GRADIENT_PALETTES = new StringPreference(this, "gradient_color_palettes", null).makeGlobal().makeShared(); public final ListStringPreference LAST_USED_FAV_ICONS = (ListStringPreference) new ListStringPreference(this, "last_used_favorite_icons", null, ",").makeShared().makeGlobal(); + public final ListStringPreference PLUGINS_COVERED_BY_SETTINGS_SEARCH = (ListStringPreference) new ListStringPreference(this, "plugins_covered_by_settings_search", null, ",").makeGlobal().makeShared(); public final CommonPreference SAVE_TRACK_INTERVAL = new IntPreference(this, "save_track_interval", 5000).makeProfile(); diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/AnnouncementTimeBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/AnnouncementTimeBottomSheet.java index 45f729033bd..eca80d24905 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/AnnouncementTimeBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/AnnouncementTimeBottomSheet.java @@ -1,5 +1,7 @@ package net.osmand.plus.settings.bottomsheets; +import static net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet.SELECTED_ENTRY_INDEX_KEY; + import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; @@ -9,6 +11,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import com.google.android.material.slider.Slider; import com.google.android.material.slider.Slider.OnChangeListener; @@ -16,22 +19,22 @@ import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem.Builder; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.routing.data.AnnounceTimeDistances; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.fragments.OnPreferenceChanged; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.settings.preferences.ListPreferenceEx; +import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.widgets.TextViewEx; import org.apache.commons.logging.Log; -import static net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet.SELECTED_ENTRY_INDEX_KEY; - +import java.util.Optional; -public class AnnouncementTimeBottomSheet extends BasePreferenceBottomSheet { +public class AnnouncementTimeBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = AnnouncementTimeBottomSheet.class.getSimpleName(); private static final Log LOG = PlatformUtil.getLog(AnnouncementTimeBottomSheet.class); @@ -43,7 +46,6 @@ public class AnnouncementTimeBottomSheet extends BasePreferenceBottomSheet { private int selectedEntryIndex = -1; private TextViewEx tvSeekBarLabel; - private Slider slider; private ImageView ivArrow; private TextViewEx tvIntervalsDescr; @@ -116,7 +118,7 @@ private BaseBottomSheetItem createBottomSheetItem() { .inflate(R.layout.bottom_sheet_announcement_time, null); tvSeekBarLabel = rootView.findViewById(R.id.tv_seek_bar_label); - slider = rootView.findViewById(R.id.arrival_slider); + Slider slider = rootView.findViewById(R.id.arrival_slider); ivArrow = rootView.findViewById(R.id.iv_arrow); tvIntervalsDescr = rootView.findViewById(R.id.tv_interval_descr); int appModeColor = getAppMode().getProfileColor(nightMode); @@ -161,21 +163,34 @@ private void toggleDescriptionVisibility() { AndroidUiHelper.updateVisibility(tvIntervalsDescr, !collapsed); } - public static void showInstance(@NonNull FragmentManager fm, String prefKey, Fragment target, - @Nullable ApplicationMode appMode, boolean usedOnMap) { + @NonNull + public static AnnouncementTimeBottomSheet createInstance(final Preference preference, + final Optional target, + final @Nullable ApplicationMode appMode, + final boolean usedOnMap) { + return BasePreferenceBottomSheetInitializer + .initialize(new AnnouncementTimeBottomSheet()) + .with(Optional.of(preference), appMode, usedOnMap, target); + } + + @Override + public void show(final FragmentManager fragmentManager) { try { - if (!fm.isStateSaved()) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, prefKey); - AnnouncementTimeBottomSheet fragment = new AnnouncementTimeBottomSheet(); - fragment.setArguments(args); - fragment.setAppMode(appMode); - fragment.setUsedOnMap(usedOnMap); - fragment.setTargetFragment(target, 0); - fragment.show(fm, TAG); + if (!fragmentManager.isStateSaved()) { + show(fragmentManager, TAG); } - } catch (RuntimeException e) { + } catch (final RuntimeException e) { LOG.error("showInstance", e); } } + + @Override + public String getSearchableInfo() { + return String.join( + ", ", + getString(R.string.announcement_time_title), + getString(R.string.announcement_time_descr), + getString(R.string.announcement_time_intervals), + tvIntervalsDescr.getText()); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BasePreferenceBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BasePreferenceBottomSheet.java index 528015535b1..f46c30c7bf4 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BasePreferenceBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BasePreferenceBottomSheet.java @@ -10,9 +10,9 @@ import androidx.preference.DialogPreference.TargetFragment; import androidx.preference.Preference; -import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.base.MenuBottomSheetDialogFragment; +import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.fragments.ApplyQueryType; import java.util.List; @@ -77,6 +77,10 @@ public String getPrefId() { return prefId; } + public void setPreference(final Preference preference) { + this.preference = preference; + } + public Preference getPreference() { if (preference == null) { String prefId = getPrefId(); diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BasePreferenceBottomSheetInitializer.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BasePreferenceBottomSheetInitializer.java new file mode 100644 index 00000000000..3574a6c789e --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BasePreferenceBottomSheetInitializer.java @@ -0,0 +1,51 @@ +package net.osmand.plus.settings.bottomsheets; + +import static net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet.PREFERENCE_ID; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.preference.Preference; + +import net.osmand.plus.settings.backend.ApplicationMode; + +import java.util.Optional; + +public class BasePreferenceBottomSheetInitializer { + + private final T bottomSheet; + + private BasePreferenceBottomSheetInitializer(final T bottomSheet) { + this.bottomSheet = bottomSheet; + } + + public static BasePreferenceBottomSheetInitializer initialize(final T basePreferenceBottomSheet) { + return new BasePreferenceBottomSheetInitializer<>(basePreferenceBottomSheet); + } + + public T with(final Optional preference, + final @Nullable ApplicationMode appMode, + final boolean usedOnMap, + final Optional target) { + preference.ifPresent(this::setPreference); + bottomSheet.setUsedOnMap(usedOnMap); + bottomSheet.setAppMode(appMode); + bottomSheet.setTargetFragment(target.orElse(null), 0); + return bottomSheet; + } + + private void setPreference(final Preference preference) { + bottomSheet.setPreference(preference); + getArguments(bottomSheet).putString(PREFERENCE_ID, preference.getKey()); + } + + @NonNull + private static Bundle getArguments(final Fragment fragment) { + if (fragment.getArguments() == null) { + fragment.setArguments(new Bundle()); + } + return fragment.getArguments(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BaseTextFieldBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BaseTextFieldBottomSheet.java index 2930f051e95..090312eff92 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BaseTextFieldBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/BaseTextFieldBottomSheet.java @@ -41,12 +41,17 @@ public abstract class BaseTextFieldBottomSheet extends BasePreferenceBottomSheet protected int contentHeightPrevious; protected float currentValue; + private boolean configureSettingsSearch = false; + + public void setConfigureSettingsSearch(final boolean configureSettingsSearch) { + this.configureSettingsSearch = configureSettingsSearch; + } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { View view = super.onCreateView(inflater, parent, savedInstanceState); - if (view != null) { + if (view != null && !configureSettingsSearch) { view.getViewTreeObserver().addOnGlobalLayoutListener(getOnGlobalLayoutListener()); } return view; diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/CustomizableSingleSelectionBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/CustomizableSingleSelectionBottomSheet.java index c29ba4a3831..ec820753352 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/CustomizableSingleSelectionBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/CustomizableSingleSelectionBottomSheet.java @@ -18,6 +18,7 @@ import net.osmand.plus.base.bottomsheetmenu.simpleitems.LongDescriptionItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; import net.osmand.plus.base.dialog.data.DisplayItem; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.UiUtilities; import java.util.List; @@ -28,7 +29,7 @@ * When choosing one of the options, the selected option is passed to the controller * and dialog automatically closed without the need for confirmation by the user. */ -public class CustomizableSingleSelectionBottomSheet extends CustomizableBottomSheet { +public class CustomizableSingleSelectionBottomSheet extends CustomizableBottomSheet implements SearchablePreferenceDialog { public static final String TAG = CustomizableSingleSelectionBottomSheet.class.getSimpleName(); @@ -40,19 +41,19 @@ public void createMenuItems(Bundle savedInstanceState) { } ctx = UiUtilities.getThemedContext(ctx, nightMode); - String title = (String) displayData.getExtra(TITLE); + String title = getTitle(); if (title != null) { TitleItem titleItem = new TitleItem(title); items.add(titleItem); } - String description = (String) displayData.getExtra(SUBTITLE); + String description = getDescription(); if (description != null) { LongDescriptionItem descriptionItem = new LongDescriptionItem(description); items.add(descriptionItem); } - List displayItems = displayData.getDisplayItems(); + List displayItems = getDisplayItems(); for (int i = 0; i < displayItems.size(); i++) { DisplayItem displayItem = displayItems.get(i); Integer selectedIndex = (Integer) displayData.getExtra(SELECTED_INDEX); @@ -88,17 +89,35 @@ protected boolean hideButtonsContainer() { return show == null || !show; } - public static boolean showInstance(@NonNull FragmentManager fragmentManager, - @NonNull String processId, boolean usedOnMap) { - try { - CustomizableSingleSelectionBottomSheet fragment = new CustomizableSingleSelectionBottomSheet(); - fragment.setProcessId(processId); - fragment.setUsedOnMap(usedOnMap); - fragment.show(fragmentManager, TAG); - return true; - } catch (RuntimeException e) { - return false; - } + public static @NonNull CustomizableSingleSelectionBottomSheet createInstance(final @NonNull String processId, final boolean usedOnMap) { + final CustomizableSingleSelectionBottomSheet fragment = new CustomizableSingleSelectionBottomSheet(); + fragment.setProcessId(processId); + fragment.setUsedOnMap(usedOnMap); + return fragment; + } + + @Override + public void show(final FragmentManager fragmentManager) { + show(fragmentManager, TAG); + } + + @Override + public String getSearchableInfo() { + return CustomizableSingleSelectionBottomSheetSearchableInfoProvider.getSearchableInfo( + getTitle(), + getDescription(), + getDisplayItems()); + } + + private String getTitle() { + return (String) displayData.getExtra(TITLE); } + private String getDescription() { + return (String) displayData.getExtra(SUBTITLE); + } + + private List getDisplayItems() { + return displayData.getDisplayItems(); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/CustomizableSingleSelectionBottomSheetSearchableInfoProvider.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/CustomizableSingleSelectionBottomSheetSearchableInfoProvider.java new file mode 100644 index 00000000000..cf44dd97c77 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/CustomizableSingleSelectionBottomSheetSearchableInfoProvider.java @@ -0,0 +1,33 @@ +package net.osmand.plus.settings.bottomsheets; + +import net.osmand.plus.base.dialog.data.DisplayItem; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.common.Optionals; + +public class CustomizableSingleSelectionBottomSheetSearchableInfoProvider { + + public static String getSearchableInfo(final String title, + final String description, + final List displayItems) { + return String.join(", ", title, description, asString(displayItems)); + } + + private static String asString(final List displayItems) { + return displayItems + .stream() + .map(CustomizableSingleSelectionBottomSheetSearchableInfoProvider::asString) + .collect(Collectors.joining(", ")); + } + + private static String asString(final DisplayItem displayItem) { + return Optionals + .streamOfPresentElements( + Optional.ofNullable(displayItem.getTitle()), + Optional.ofNullable(displayItem.getDescription())) + .collect(Collectors.joining(", ")); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/DistanceDuringNavigationBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/DistanceDuringNavigationBottomSheet.java index 59fdc44af1a..8d940c03a4c 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/DistanceDuringNavigationBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/DistanceDuringNavigationBottomSheet.java @@ -9,11 +9,13 @@ import android.widget.TextView; import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; @@ -24,16 +26,20 @@ import net.osmand.plus.settings.backend.preferences.OsmandPreference; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.OnConfirmPreferenceChange; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.UiUtilities; -public class DistanceDuringNavigationBottomSheet extends BasePreferenceBottomSheet { +import java.util.Optional; + +public class DistanceDuringNavigationBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = DistanceDuringNavigationBottomSheet.class.getSimpleName(); private UiUtilities uiUtilities; private BooleanPreference preference; + private BaseBottomSheetItem bottomSheetItem; @Override public void createMenuItems(Bundle savedInstanceState) { @@ -47,7 +53,8 @@ public void createMenuItems(Bundle savedInstanceState) { } preference = (BooleanPreference) osmandPreference; uiUtilities = app.getUIUtilities(); - items.add(createBottomSheetItem()); + bottomSheetItem = createBottomSheetItem(); + items.add(bottomSheetItem); } private BaseBottomSheetItem createBottomSheetItem() { @@ -117,20 +124,43 @@ protected int getDismissButtonTextId() { return R.string.shared_string_close; } - public static void showInstance(@NonNull FragmentManager manager, String prefKey, Fragment target, - @Nullable ApplicationMode appMode, boolean usedOnMap) { - if (AndroidUtils.isFragmentCanBeAdded(manager, TAG)) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, prefKey); - DistanceDuringNavigationBottomSheet fragment = new DistanceDuringNavigationBottomSheet(); - fragment.setArguments(args); - fragment.setAppMode(appMode); - fragment.setUsedOnMap(usedOnMap); - fragment.setTargetFragment(target, 0); - fragment.show(manager, TAG); + public static @NonNull DistanceDuringNavigationBottomSheet createInstance( + final Preference preference, + final Optional target, + final @Nullable ApplicationMode appMode, + final boolean usedOnMap) { + return BasePreferenceBottomSheetInitializer + .initialize(new DistanceDuringNavigationBottomSheet()) + .with(Optional.of(preference), appMode, usedOnMap, target); + } + + @Override + public void show(final FragmentManager fragmentManager) { + if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { + show(fragmentManager, TAG); } } + @Override + public String getSearchableInfo() { + return String.join( + ", ", + getTitle(bottomSheetItem.getView()), + getDescription(bottomSheetItem.getView())); + } + + private static CharSequence getTitle(final View view) { + return getText(view, R.id.title); + } + + private static CharSequence getDescription(final View view) { + return getText(view, R.id.description); + } + + private static CharSequence getText(final View view, final @IdRes int id) { + return view.findViewById(id).getText(); + } + public enum DistanceDuringNavigationMode { PRECISE(R.string.precise, R.drawable.ic_action_distance_number_precise), ROUND_UP(R.string.round_up, R.drawable.ic_action_distance_number_rounded); diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/FuelTankCapacityBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/FuelTankCapacityBottomSheet.java index 7d0e6b96718..13e0f0fb9ac 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/FuelTankCapacityBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/FuelTankCapacityBottomSheet.java @@ -1,14 +1,15 @@ package net.osmand.plus.settings.bottomsheets; import android.annotation.SuppressLint; -import android.os.Bundle; import android.text.Editable; import android.view.View; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; @@ -19,6 +20,7 @@ import net.osmand.plus.settings.enums.VolumeUnit; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.OnConfirmPreferenceChange; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.OsmAndFormatter; import net.osmand.plus.widgets.chips.ChipItem; import net.osmand.plus.widgets.dialogbutton.DialogButtonType; @@ -32,8 +34,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; -public class FuelTankCapacityBottomSheet extends BaseTextFieldBottomSheet { +public class FuelTankCapacityBottomSheet extends BaseTextFieldBottomSheet implements SearchablePreferenceDialog { private static final Log LOG = PlatformUtil.getLog(VehicleParametersBottomSheet.class); public static final String TAG = FuelTankCapacityBottomSheet.class.getSimpleName(); @@ -77,7 +82,7 @@ public void afterTextChanged(Editable s) { @NonNull public List collectChipItems(@NonNull OsmandApplication app, - @NonNull VolumeUnit volumeUnit) { + @NonNull VolumeUnit volumeUnit) { List chips = new ArrayList<>(); String none = app.getString(R.string.shared_string_none); ChipItem chip = new ChipItem(none); @@ -129,21 +134,34 @@ protected String formatInputValue(float input) { return formatter.format(input); } - public static void showInstance(@NonNull FragmentManager fm, String key, Fragment target, - boolean usedOnMap, @Nullable ApplicationMode appMode) { + @NonNull + public static FuelTankCapacityBottomSheet createInstance(final Preference preference, + final Optional target, + final boolean usedOnMap, + final @Nullable ApplicationMode appMode) { + final FuelTankCapacityBottomSheet fragment = new FuelTankCapacityBottomSheet(); + fragment.setConfigureSettingsSearch(target.isEmpty()); + return BasePreferenceBottomSheetInitializer + .initialize(fragment) + .with(Optional.of(preference), appMode, usedOnMap, target); + } + + @Override + public void show(final FragmentManager fragmentManager) { try { - if (!fm.isStateSaved()) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, key); - FuelTankCapacityBottomSheet fragment = new FuelTankCapacityBottomSheet(); - fragment.setArguments(args); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(fm, TAG); + if (!fragmentManager.isStateSaved()) { + show(fragmentManager, TAG); } - } catch (RuntimeException e) { + } catch (final RuntimeException e) { LOG.error("showInstance", e); } } + + @Override + public String getSearchableInfo() { + return Stream + .of(title, tvDescription) + .map(TextView::getText) + .collect(Collectors.joining(", ")); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/GoodsRestrictionsBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/GoodsRestrictionsBottomSheet.java index b359e9a1201..0979b74c9de 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/GoodsRestrictionsBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/GoodsRestrictionsBottomSheet.java @@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; @@ -19,14 +20,17 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.OnConfirmPreferenceChange; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.widgets.multistatetoggle.TextToggleButton; import net.osmand.plus.widgets.multistatetoggle.TextToggleButton.TextRadioItem; -import org.jetbrains.annotations.NotNull; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; -public class GoodsRestrictionsBottomSheet extends BasePreferenceBottomSheet { +public class GoodsRestrictionsBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = GoodsRestrictionsBottomSheet.class.getSimpleName(); @@ -38,20 +42,20 @@ public class GoodsRestrictionsBottomSheet extends BasePreferenceBottomSheet { private boolean isSelected; private boolean hasChangesToApply = false; - public static void showInstance(@NonNull FragmentManager fm, @NonNull Fragment target, - @NonNull String key, @NonNull ApplicationMode appMode, - boolean usedOnMap, boolean selected) { - if (AndroidUtils.isFragmentCanBeAdded(fm, TAG)) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, key); + public static GoodsRestrictionsBottomSheet createInstance(final Optional target, + final @NonNull Preference preference, + final @NonNull ApplicationMode appMode, + final boolean usedOnMap, + final boolean selected) { + final GoodsRestrictionsBottomSheet bottomSheet = new GoodsRestrictionsBottomSheet(); + { + final Bundle args = new Bundle(); args.putBoolean(SELECTED_KEY, selected); - GoodsRestrictionsBottomSheet fragment = new GoodsRestrictionsBottomSheet(); - fragment.setArguments(args); - fragment.setAppMode(appMode); - fragment.setUsedOnMap(usedOnMap); - fragment.setTargetFragment(target, 0); - fragment.show(fm, TAG); + bottomSheet.setArguments(args); } + return BasePreferenceBottomSheetInitializer + .initialize(bottomSheet) + .with(Optional.of(preference), appMode, usedOnMap, target); } @Override @@ -140,4 +144,23 @@ private void onApply() { } } + @Override + public void show(final FragmentManager fragmentManager) { + if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { + show(fragmentManager, TAG); + } + } + + @Override + public String getSearchableInfo() { + return Stream + .of( + R.string.routing_attr_goods_restrictions_name, + R.string.goods_delivery_desc, + R.string.goods_delivery_desc_2, + R.string.goods_delivery_desc_3, + R.string.goods_delivery_desc_4) + .map(this::getString) + .collect(Collectors.joining(", ")); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/RecalculateRouteInDeviationBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/RecalculateRouteInDeviationBottomSheet.java index 3765b87019d..2908c21d8a9 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/RecalculateRouteInDeviationBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/RecalculateRouteInDeviationBottomSheet.java @@ -13,6 +13,7 @@ import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import com.google.android.material.slider.Slider; @@ -30,6 +31,7 @@ import net.osmand.plus.settings.backend.preferences.CommonPreference; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.OnConfirmPreferenceChange; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.OsmAndFormatter; @@ -37,7 +39,9 @@ import net.osmand.plus.utils.UiUtilities; import net.osmand.shared.settings.enums.MetricsConstants; -public class RecalculateRouteInDeviationBottomSheet extends BooleanPreferenceBottomSheet { +import java.util.Optional; + +public class RecalculateRouteInDeviationBottomSheet extends BooleanPreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = RecalculateRouteInDeviationBottomSheet.class.getSimpleName(); @@ -89,8 +93,7 @@ public void createMenuItems(Bundle savedInstanceState) { int activeColor = AndroidUtils.resolveAttribute(themedCtx, R.attr.active_color_basic); int disabledColor = AndroidUtils.resolveAttribute(themedCtx, android.R.attr.textColorSecondary); - String title = getString(R.string.recalculate_route_in_deviation); - items.add(new TitleItem(title)); + items.add(new TitleItem(getTitle())); View sliderView = UiUtilities.getInflater(getContext(), nightMode) .inflate(R.layout.bottom_sheet_item_slider_with_two_text, null); @@ -135,7 +138,7 @@ public void onClick(View v) { .create(); items.add(preferenceBtn[0]); items.add(new DividerSpaceItem(app, contentPaddingSmall)); - items.add(new LongDescriptionItem(getString(R.string.select_distance_route_will_recalc))); + items.add(new LongDescriptionItem(getDescription())); items.add(new DividerSpaceItem(app, contentPadding)); slider.addOnChangeListener(new Slider.OnChangeListener() { @@ -154,7 +157,22 @@ public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) .create()); items.add(new SubtitmeListDividerItem(getContext())); items.add(new DividerSpaceItem(app, contentPaddingSmall)); - items.add(new LongDescriptionItem(getString(R.string.recalculate_route_distance_promo))); + items.add(new LongDescriptionItem(getLongDescription())); + } + + @NonNull + private String getTitle() { + return getString(R.string.recalculate_route_in_deviation); + } + + @NonNull + private String getDescription() { + return getString(R.string.select_distance_route_will_recalc); + } + + @NonNull + private String getLongDescription() { + return getString(R.string.recalculate_route_distance_promo); } @Override @@ -227,21 +245,23 @@ private static String getFormattedDistance(@NonNull OsmandApplication app, float return OsmAndFormatter.getFormattedDistance(value, app, OsmAndFormatterParams.NO_TRAILING_ZEROS); } - public static boolean showInstance(@NonNull FragmentManager fragmentManager, String key, Fragment target, - boolean usedOnMap, @Nullable ApplicationMode appMode) { - try { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, key); - - RecalculateRouteInDeviationBottomSheet fragment = new RecalculateRouteInDeviationBottomSheet(); - fragment.setArguments(args); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(fragmentManager, TAG); - return true; - } catch (RuntimeException e) { - return false; - } + @NonNull + public static RecalculateRouteInDeviationBottomSheet createInstance(final Preference preference, + final Optional target, + final boolean usedOnMap, + final @Nullable ApplicationMode appMode) { + return BasePreferenceBottomSheetInitializer + .initialize(new RecalculateRouteInDeviationBottomSheet()) + .with(Optional.of(preference), appMode, usedOnMap, target); + } + + @Override + public void show(final FragmentManager fragmentManager) { + show(fragmentManager, TAG); + } + + @Override + public String getSearchableInfo() { + return String.join(", ", getTitle(), getDescription(), getLongDescription()); } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/ResetProfilePrefsBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/ResetProfilePrefsBottomSheet.java index d1e5c7fd08b..741ee72af4f 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/ResetProfilePrefsBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/ResetProfilePrefsBottomSheet.java @@ -8,7 +8,6 @@ import android.os.Bundle; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -19,11 +18,14 @@ import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; import net.osmand.plus.profiles.data.ProfileDataUtils; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.widgets.dialogbutton.DialogButtonType; -public class ResetProfilePrefsBottomSheet extends BasePreferenceBottomSheet { +import java.util.Optional; + +public class ResetProfilePrefsBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = ResetProfilePrefsBottomSheet.class.getSimpleName(); @@ -35,10 +37,8 @@ public void createMenuItems(Bundle savedInstanceState) { } ApplicationMode mode = getAppMode(); - boolean customProfile = mode.isCustomProfile(); - String title = getString(customProfile ? R.string.restore_all_profile_settings : R.string.reset_all_profile_settings); - items.add(new TitleItem(title)); + items.add(new TitleItem(getTitle())); int colorNoAlpha = mode.getProfileColor(nightMode); @@ -57,20 +57,26 @@ public void createMenuItems(Bundle savedInstanceState) { .create(); items.add(profileItem); - String restoreDescr = getString(customProfile ? R.string.shared_string_restore : R.string.shared_string_reset); - String description = getString(customProfile ? R.string.restore_all_profile_settings_descr : R.string.reset_all_profile_settings_descr); - - StringBuilder stringBuilder = new StringBuilder(description); - stringBuilder.append("\n\n"); - stringBuilder.append(getString(R.string.reset_confirmation_descr, restoreDescr)); - BaseBottomSheetItem resetAllSettings = new BottomSheetItemWithDescription.Builder() - .setDescription(stringBuilder) + .setDescription(getDescription()) .setLayoutId(R.layout.bottom_sheet_item_pref_info) .create(); items.add(resetAllSettings); } + @NonNull + private String getTitle() { + return getString(getAppMode().isCustomProfile() ? R.string.restore_all_profile_settings : R.string.reset_all_profile_settings); + } + + @NonNull + private String getDescription() { + final boolean customProfile = getAppMode().isCustomProfile(); + final String restoreDescr = getString(customProfile ? R.string.shared_string_restore : R.string.shared_string_reset); + final String description = getString(customProfile ? R.string.restore_all_profile_settings_descr : R.string.reset_all_profile_settings_descr); + return description + "\n\n" + getString(R.string.reset_confirmation_descr, restoreDescr); + } + @Override protected int getRightBottomButtonTextId() { return getAppMode().isCustomProfile() ? R.string.shared_string_restore : R.string.shared_string_reset; @@ -91,26 +97,21 @@ protected DialogButtonType getRightBottomButtonType() { return DialogButtonType.SECONDARY; } - public static boolean showInstance(@NonNull FragmentManager manager, - @NonNull ApplicationMode appMode, - @Nullable Fragment target) { - return showInstance(manager, appMode, target, false); + public static ResetProfilePrefsBottomSheet createInstance(final @NonNull ApplicationMode appMode, + final Optional target) { + return BasePreferenceBottomSheetInitializer + .initialize(new ResetProfilePrefsBottomSheet()) + .with(Optional.empty(), appMode, false, target); } - public static boolean showInstance(@NonNull FragmentManager manager, - @NonNull ApplicationMode appMode, - @Nullable Fragment target, - boolean usedOnMap) { - try { - ResetProfilePrefsBottomSheet fragment = new ResetProfilePrefsBottomSheet(); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(manager, TAG); - return true; - } catch (RuntimeException e) { - return false; - } + @Override + public void show(final FragmentManager fragmentManager) { + show(fragmentManager, TAG); + } + + @Override + public String getSearchableInfo() { + return String.join(", ", getTitle(), getDescription()); } public interface ResetAppModePrefsListener { diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/SimpleSingleSelectionBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/SimpleSingleSelectionBottomSheet.java index 3365241eb18..0a76efa882b 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/SimpleSingleSelectionBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/SimpleSingleSelectionBottomSheet.java @@ -10,9 +10,11 @@ import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; + +import com.google.common.collect.ImmutableList; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; @@ -20,13 +22,15 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.OnConfirmPreferenceChange; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.UiUtilities; import java.util.ArrayList; import java.util.List; +import java.util.Optional; -public class SimpleSingleSelectionBottomSheet extends BasePreferenceBottomSheet { +public class SimpleSingleSelectionBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = SimpleSingleSelectionBottomSheet.class.getSimpleName(); @@ -48,21 +52,46 @@ public class SimpleSingleSelectionBottomSheet extends BasePreferenceBottomSheet private Object[] values; private int selectedEntryIndex; - public static void showInstance(@NonNull FragmentManager fm, @NonNull Fragment target, - @NonNull String key, @NonNull String title, @NonNull String description, - @NonNull ApplicationMode appMode, boolean usedOnMap, - @NonNull String[] names, @NonNull Object[] values, - int selectedIndex) { - if (AndroidUtils.isFragmentCanBeAdded(fm, TAG)) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, key); - SimpleSingleSelectionBottomSheet fragment = new SimpleSingleSelectionBottomSheet(); - fragment.setArguments(args); - fragment.setAppMode(appMode); - fragment.setUsedOnMap(usedOnMap); - fragment.setTargetFragment(target, 0); - fragment.setParameters(title, description, names, values, selectedIndex); - fragment.show(fm, TAG); + public static @NonNull SimpleSingleSelectionBottomSheet createInstance( + final Optional target, + final @NonNull Preference preference, + final @NonNull String title, + final @NonNull String description, + final @NonNull ApplicationMode appMode, + final boolean usedOnMap, + final @NonNull String[] names, + final @NonNull Object[] values, + final int selectedIndex) { + return BasePreferenceBottomSheetInitializer + .initialize( + new SimpleSingleSelectionBottomSheet( + title, + description, + names, + values, + selectedIndex)) + .with(Optional.of(preference), appMode, usedOnMap, target); + } + + public SimpleSingleSelectionBottomSheet() { + } + + public SimpleSingleSelectionBottomSheet(@NonNull String title, + @NonNull String description, + @NonNull String[] names, + @NonNull Object[] values, + int selectedEntryIndex) { + this.title = title; + this.description = description; + this.names = names; + this.values = values; + this.selectedEntryIndex = selectedEntryIndex; + } + + @Override + public void show(final FragmentManager fragmentManager) { + if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { + show(fragmentManager, TAG); } } @@ -128,15 +157,6 @@ private void updateRadioButtons() { } } - public void setParameters(@NonNull String title, @NonNull String description, @NonNull String[] names, - @NonNull Object[] values, @Nullable Integer selectedEntryIndex) { - this.title = title; - this.description = description; - this.names = names; - this.values = values; - this.selectedEntryIndex = selectedEntryIndex != null ? selectedEntryIndex : 0; - } - @Override protected int getDismissButtonTextId() { return R.string.shared_string_close; @@ -168,4 +188,16 @@ private void onApply() { } dismiss(); } + + @Override + public String getSearchableInfo() { + return String.join( + ", ", + ImmutableList + .builder() + .add(title) + .add(description) + .add(names) + .build()); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/VehicleParametersBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/VehicleParametersBottomSheet.java index a9a18df32ea..a607745c58b 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/VehicleParametersBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/VehicleParametersBottomSheet.java @@ -2,28 +2,32 @@ import android.annotation.SuppressLint; import android.graphics.drawable.Drawable; -import android.os.Bundle; import android.text.Editable; import android.view.View; +import android.widget.TextView; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.settings.backend.ApplicationMode; -import net.osmand.plus.settings.vehiclesize.SizeData; -import net.osmand.plus.settings.vehiclesize.SizeType; -import net.osmand.plus.settings.vehiclesize.VehicleSizes; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.OnConfirmPreferenceChange; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.settings.preferences.SizePreference; +import net.osmand.plus.settings.vehiclesize.SizeData; +import net.osmand.plus.settings.vehiclesize.SizeType; +import net.osmand.plus.settings.vehiclesize.VehicleSizes; import net.osmand.plus.settings.vehiclesize.containers.Metric; -import net.osmand.plus.widgets.dialogbutton.DialogButtonType; import net.osmand.plus.widgets.chips.ChipItem; +import net.osmand.plus.widgets.dialogbutton.DialogButtonType; import net.osmand.plus.widgets.tools.SimpleTextWatcher; import net.osmand.util.Algorithms; @@ -33,8 +37,11 @@ import java.text.DecimalFormatSymbols; import java.util.List; import java.util.Locale; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; -public class VehicleParametersBottomSheet extends BaseTextFieldBottomSheet { +public class VehicleParametersBottomSheet extends BaseTextFieldBottomSheet implements SearchablePreferenceDialog { private static final Log LOG = PlatformUtil.getLog(VehicleParametersBottomSheet.class); public static final String TAG = VehicleParametersBottomSheet.class.getSimpleName(); @@ -129,21 +136,39 @@ protected String formatInputValue(float input) { return formatter.format(input); } - public static void showInstance(@NonNull FragmentManager fm, String key, Fragment target, - boolean usedOnMap, @Nullable ApplicationMode appMode) { + @NonNull + public static VehicleParametersBottomSheet createInstance(final Preference preference, + final Optional target, + final boolean usedOnMap, + final @Nullable ApplicationMode appMode) { + final VehicleParametersBottomSheet bottomSheet = new VehicleParametersBottomSheet(); + bottomSheet.setConfigureSettingsSearch(target.isEmpty()); + return BasePreferenceBottomSheetInitializer + .initialize(bottomSheet) + .with(Optional.of(preference), appMode, usedOnMap, target); + } + + @Override + public void show(final FragmentManager fragmentManager) { try { - if (!fm.isStateSaved()) { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, key); - VehicleParametersBottomSheet fragment = new VehicleParametersBottomSheet(); - fragment.setArguments(args); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setTargetFragment(target, 0); - fragment.show(fm, TAG); + if (!fragmentManager.isStateSaved()) { + show(fragmentManager, TAG); } - } catch (RuntimeException e) { + } catch (final RuntimeException e) { LOG.error("showInstance", e); } } + + @Override + public String getSearchableInfo() { + return Stream + .of(R.id.title, R.id.description) + .map(this::_getText) + .collect(Collectors.joining(", ")); + } + + private CharSequence _getText(final @IdRes int id) { + final View mainView = items.get(0).getView(); + return mainView.findViewById(id).getText(); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/WakeTimeBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/WakeTimeBottomSheet.java index b186bd49377..7a6e19c4a58 100644 --- a/OsmAnd/src/net/osmand/plus/settings/bottomsheets/WakeTimeBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/bottomsheets/WakeTimeBottomSheet.java @@ -9,11 +9,11 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; import com.google.android.material.slider.Slider; import net.osmand.plus.R; -import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; @@ -24,9 +24,13 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.OnPreferenceChanged; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.settings.preferences.ListPreferenceEx; +import net.osmand.plus.utils.UiUtilities; -public class WakeTimeBottomSheet extends BasePreferenceBottomSheet { +import java.util.Optional; + +public class WakeTimeBottomSheet extends BasePreferenceBottomSheet implements SearchablePreferenceDialog { public static final String TAG = WakeTimeBottomSheet.class.getSimpleName(); @@ -64,8 +68,8 @@ public void createMenuItems(Bundle savedInstanceState) { .create(); items.add(preferenceDescription); - String on = getString(R.string.keep_screen_on); - String off = getString(R.string.keep_screen_on); // also needs to say 'on' the way the dialog is designed. + String on = getKeepScreenOn(); + String off = getKeepScreenOn(); // also needs to say 'on' the way the dialog is designed. BottomSheetItemWithCompoundButton[] preferenceBtn = new BottomSheetItemWithCompoundButton[1]; preferenceBtn[0] = (BottomSheetItemWithCompoundButton) new BottomSheetItemWithCompoundButton.Builder() .setChecked(keepScreenOnEnabled) @@ -94,8 +98,6 @@ public void onClick(View v) { sliderView = UiUtilities.getInflater(ctx, nightMode).inflate(R.layout.bottom_sheet_item_slider_with_two_text, null); AndroidUiHelper.updateVisibility(sliderView, !keepScreenOnEnabled); - Context themedCtx = UiUtilities.getThemedContext(ctx, nightMode); - TextView tvSliderTitle = sliderView.findViewById(android.R.id.title); tvSliderTitle.setText(getString(R.string.wake_time)); @@ -125,17 +127,26 @@ public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) .create()); BaseBottomSheetItem timeoutDescription = new BottomSheetItemWithDescription.Builder() - .setDescription(getString(R.string.screen_timeout_descr, getString(R.string.system_screen_timeout))) + .setDescription(getTimeoutDescription()) .setLayoutId(R.layout.bottom_sheet_item_descr) .create(); items.add(timeoutDescription); } + @NonNull + private String getKeepScreenOn() { + return getString(R.string.keep_screen_on); + } + + @NonNull + private String getTimeoutDescription() { + return getString(R.string.screen_timeout_descr, getString(R.string.system_screen_timeout)); + } + @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { for (BaseBottomSheetItem item : items) { - if (item instanceof BottomSheetItemWithCompoundButton) { - BottomSheetItemWithCompoundButton itemWithCompoundButton = (BottomSheetItemWithCompoundButton) item; + if (item instanceof final BottomSheetItemWithCompoundButton itemWithCompoundButton) { itemWithCompoundButton.getCompoundButton().setSaveEnabled(false); } } @@ -181,24 +192,28 @@ private ListPreferenceEx getListPreference() { return (ListPreferenceEx) getPreference(); } - public static boolean showInstance(@NonNull FragmentManager fragmentManager, String prefId, Fragment target, boolean usedOnMap, - @Nullable ApplicationMode appMode, ApplyQueryType applyQueryType, - boolean profileDependent) { - try { - Bundle args = new Bundle(); - args.putString(PREFERENCE_ID, prefId); - - WakeTimeBottomSheet fragment = new WakeTimeBottomSheet(); - fragment.setArguments(args); - fragment.setUsedOnMap(usedOnMap); - fragment.setAppMode(appMode); - fragment.setApplyQueryType(applyQueryType); - fragment.setTargetFragment(target, 0); - fragment.setProfileDependent(profileDependent); - fragment.show(fragmentManager, TAG); - return true; - } catch (RuntimeException e) { - return false; - } + @NonNull + public static WakeTimeBottomSheet createInstance(final Preference preference, + final Optional target, + final boolean usedOnMap, + final @Nullable ApplicationMode appMode, + final ApplyQueryType applyQueryType, + final boolean profileDependent) { + final WakeTimeBottomSheet bottomSheet = new WakeTimeBottomSheet(); + bottomSheet.setApplyQueryType(applyQueryType); + bottomSheet.setProfileDependent(profileDependent); + return BasePreferenceBottomSheetInitializer + .initialize(bottomSheet) + .with(Optional.of(preference), appMode, usedOnMap, target); + } + + @Override + public void show(final FragmentManager fragmentManager) { + show(fragmentManager, TAG); + } + + @Override + public String getSearchableInfo() { + return String.join(", ", getKeepScreenOn(), getTimeoutDescription()); } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/controllers/CompassModeWidgetDialogController.java b/OsmAnd/src/net/osmand/plus/settings/controllers/CompassModeWidgetDialogController.java index de9bd9cc512..ec856c7e1a1 100644 --- a/OsmAnd/src/net/osmand/plus/settings/controllers/CompassModeWidgetDialogController.java +++ b/OsmAnd/src/net/osmand/plus/settings/controllers/CompassModeWidgetDialogController.java @@ -1,7 +1,6 @@ package net.osmand.plus.settings.controllers; import androidx.annotation.NonNull; -import androidx.fragment.app.FragmentManager; import net.osmand.plus.OsmandApplication; import net.osmand.plus.activities.MapActivity; @@ -39,7 +38,8 @@ public static void showDialog(@NonNull MapActivity mapActivity) { DialogManager dialogManager = app.getDialogManager(); dialogManager.register(PROCESS_ID, controller); - FragmentManager manager = mapActivity.getSupportFragmentManager(); - CustomizableSingleSelectionBottomSheet.showInstance(manager, PROCESS_ID, true); + CustomizableSingleSelectionBottomSheet + .createInstance(PROCESS_ID, true) + .show(mapActivity.getSupportFragmentManager()); } } diff --git a/OsmAnd/src/net/osmand/plus/settings/controllers/MapFocusDialogController.java b/OsmAnd/src/net/osmand/plus/settings/controllers/MapFocusDialogController.java index 8a4d8c6501b..ea3ed6262dc 100644 --- a/OsmAnd/src/net/osmand/plus/settings/controllers/MapFocusDialogController.java +++ b/OsmAnd/src/net/osmand/plus/settings/controllers/MapFocusDialogController.java @@ -6,7 +6,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentManager; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; @@ -15,8 +14,8 @@ import net.osmand.plus.base.dialog.DialogManager; import net.osmand.plus.base.dialog.data.DisplayData; import net.osmand.plus.base.dialog.data.DisplayItem; -import net.osmand.plus.base.dialog.interfaces.controller.IDisplayDataProvider; import net.osmand.plus.base.dialog.interfaces.controller.IDialogItemSelected; +import net.osmand.plus.base.dialog.interfaces.controller.IDisplayDataProvider; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.bottomsheets.CustomizableSingleSelectionBottomSheet; @@ -33,13 +32,14 @@ public class MapFocusDialogController extends BaseDialogController private final OsmandSettings settings; public MapFocusDialogController(@NonNull OsmandApplication app, - @NonNull ApplicationMode appMode) { + @NonNull ApplicationMode appMode) { super(app); this.appMode = appMode; this.settings = app.getSettings(); } - @NonNull @Override + @NonNull + @Override public String getProcessId() { return PROCESS_ID; } @@ -96,7 +96,8 @@ public static void showDialog(@NonNull MapActivity mapActivity, @NonNull Applica DialogManager dialogManager = app.getDialogManager(); dialogManager.register(PROCESS_ID, controller); - FragmentManager manager = mapActivity.getSupportFragmentManager(); - CustomizableSingleSelectionBottomSheet.showInstance(manager, PROCESS_ID, true); + CustomizableSingleSelectionBottomSheet + .createInstance(PROCESS_ID, true) + .show(mapActivity.getSupportFragmentManager()); } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java index 26ba1fb9bb1..d352e523ae5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java @@ -29,9 +29,21 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; -import androidx.preference.*; +import androidx.preference.EditTextPreference; +import androidx.preference.ListPreference; +import androidx.preference.MultiSelectListPreference; +import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.Preference.OnPreferenceClickListener; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceGroupAdapter; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.PreferenceViewHolder; +import androidx.preference.SwitchPreferenceCompat; +import androidx.preference.TwoStatePreference; import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.appbar.AppBarLayout; @@ -58,6 +70,8 @@ import net.osmand.plus.settings.bottomsheets.EditTextPreferenceBottomSheet; import net.osmand.plus.settings.bottomsheets.MultiSelectPreferencesBottomSheet; import net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandler; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandlerProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.MultiSelectBooleanPreference; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; @@ -69,6 +83,7 @@ import org.apache.commons.logging.Log; import java.io.Serializable; +import java.util.Optional; import java.util.Set; public abstract class BaseSettingsFragment extends PreferenceFragmentCompat implements OnPreferenceChangeListener, @@ -82,6 +97,7 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl public static final String OPEN_CONFIG_ON_MAP = "openConfigOnMap"; public static final String MAP_CONFIG = "openMapConfigMenu"; public static final String SCREEN_CONFIG = "screenConfig"; + public static final String CONFIGURE_SETTINGS_SEARCH = "configureSettingsSearch"; protected OsmandApplication app; protected OsmandSettings settings; @@ -96,6 +112,8 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl private int statusBarColor = -1; private boolean nightMode; private boolean wasDrawerDisabled; + // FK-TODO: remove configureSettingsSearch? + private boolean configureSettingsSearch = false; @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -103,6 +121,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { settings = app.getSettings(); appCustomization = app.getAppCustomization(); Bundle args = getArguments(); + configureSettingsSearch = args != null && args.getBoolean(CONFIGURE_SETTINGS_SEARCH, false); if (savedInstanceState != null) { appMode = ApplicationMode.valueOfStringKey(savedInstanceState.getString(APP_MODE_KEY), null); } @@ -137,10 +156,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, } else { updateAllSettings(); } - createToolbar(inflater, view); - setDivider(null); - view.setBackgroundColor(ContextCompat.getColor(app, getBackgroundColorRes())); - AndroidUtils.addStatusBarPadding21v(requireMyActivity(), view); + if (!configureSettingsSearch) { + createToolbar(inflater, view); + setDivider(null); + view.setBackgroundColor(ContextCompat.getColor(app, getBackgroundColorRes())); + AndroidUtils.addStatusBarPadding21v(requireMyActivity(), view); + } } return view; } @@ -156,6 +177,9 @@ private boolean updateTheme() { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + if (configureSettingsSearch) { + return; + } super.onViewCreated(view, savedInstanceState); updateToolbar(); } @@ -194,6 +218,9 @@ public void onSaveInstanceState(Bundle outState) { @Override public void onResume() { super.onResume(); + if (configureSettingsSearch) { + return; + } MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { wasDrawerDisabled = mapActivity.isDrawerDisabled(); @@ -207,7 +234,9 @@ public void onResume() { @Override public void onPause() { super.onPause(); - + if (configureSettingsSearch) { + return; + } Activity activity = getActivity(); if (activity != null) { if (!wasDrawerDisabled && activity instanceof MapActivity) { @@ -223,6 +252,9 @@ public void onPause() { @Override public void onDetach() { super.onDetach(); + if (configureSettingsSearch) { + return; + } if (getStatusBarColorId() != -1) { Activity activity = getActivity(); if (activity instanceof MapActivity) { @@ -301,10 +333,23 @@ public final boolean onConfirmPreferenceChange(String prefId, Object newValue, A } @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(final Preference preference) { + if (this instanceof final PreferenceFragmentHandlerProvider preferenceFragmentHandlerProvider) { + return preferenceFragmentHandlerProvider + .getPreferenceFragmentHandler(preference) + .map(this::showPreferenceFragment) + .orElse(false); + } return false; } + private boolean showPreferenceFragment(final PreferenceFragmentHandler preferenceFragmentHandler) { + return preferenceFragmentHandler.showPreferenceFragment( + preferenceFragmentHandler.createPreferenceFragment( + getContext(), + Optional.of(this))); + } + public boolean isProfileDependent() { return currentScreenType != null && currentScreenType.profileDependent; } @@ -348,7 +393,9 @@ public void onAppModeChanged(ApplicationMode appMode) { recreate(); } else { getPreferenceManager().setPreferenceDataStore(settings.getDataStore(appMode)); - updateToolbar(); + if (!configureSettingsSearch) { + updateToolbar(); + } updateAllSettings(); } } @@ -760,7 +807,7 @@ protected OsmandSettings requireSettings() { return app.getSettings(); } - protected Drawable getIcon(@DrawableRes int id) { + public Drawable getIcon(@DrawableRes int id) { UiUtilities cache = getIconsCache(); return cache != null ? cache.getIcon(id) : null; } @@ -796,13 +843,15 @@ protected Drawable getPersistentPrefIcon(Drawable enabled, Drawable disabled) { } protected void showSingleSelectionDialog(@NonNull String processId, - @NonNull IDialogController controller) { + @NonNull IDialogController controller) { FragmentActivity activity = getActivity(); if (activity != null) { DialogManager dialogManager = app.getDialogManager(); dialogManager.register(processId, controller); FragmentManager fm = activity.getSupportFragmentManager(); - CustomizableSingleSelectionBottomSheet.showInstance(fm, processId, false); + CustomizableSingleSelectionBottomSheet + .createInstance(processId, false) + .show(fm); } } @@ -829,7 +878,7 @@ public SwitchPreferenceEx createSwitchPreferenceEx(String prefId, String title, } public static SwitchPreferenceEx createSwitchPreferenceEx(@NonNull Context ctx, @NonNull String prefId, - String title, String summary, int layoutId) { + String title, String summary, int layoutId) { SwitchPreferenceEx p = new SwitchPreferenceEx(ctx); p.setKey(prefId); p.setTitle(title); @@ -848,8 +897,8 @@ public ListPreferenceEx createListPreferenceEx(String prefId, String[] names, Ob } public static ListPreferenceEx createListPreferenceEx(@NonNull Context ctx, @NonNull String prefId, - @NonNull String[] names, @NonNull Object[] values, - String title, int layoutId) { + @NonNull String[] names, @NonNull Object[] values, + String title, int layoutId) { ListPreferenceEx listPreference = new ListPreferenceEx(ctx); listPreference.setKey(prefId); listPreference.setTitle(title); @@ -888,33 +937,49 @@ protected Preference requirePreference(@NonNull CharSequence key) { return preference; } + public static @NonNull Fragment createFragment(final String fragmentClassName, + final @NonNull Context context, + final @Nullable ApplicationMode appMode, + final @NonNull Bundle args, + final @Nullable Fragment target) { + final Fragment fragment = Fragment.instantiate(context, fragmentClassName); + if (appMode != null) { + args.putString(APP_MODE_KEY, appMode.getStringKey()); + } + fragment.setArguments(args); + fragment.setTargetFragment(target, 0); + return fragment; + } + public static boolean showInstance(@NonNull FragmentActivity activity, @NonNull SettingsScreenType screenType) { - return showInstance(activity, screenType, null); + final Fragment fragment = createFragment(screenType.fragmentName, activity, null, new Bundle(), null); + return showFragment(fragment, activity, screenType.fragmentName); } public static boolean showInstance(@NonNull FragmentActivity activity, - @NonNull SettingsScreenType screenType, - @Nullable ApplicationMode appMode) { - return showInstance(activity, screenType, appMode, new Bundle(), null); + @NonNull SettingsScreenType screenType, + @Nullable ApplicationMode appMode) { + final Fragment fragment = createFragment(screenType.fragmentName, activity, appMode, new Bundle(), null); + return showFragment(fragment, activity, screenType.fragmentName); } public static boolean showInstance(@NonNull FragmentActivity activity, - @NonNull SettingsScreenType screenType, - @Nullable ApplicationMode appMode, - @NonNull Bundle args, - @Nullable Fragment target) { + @NonNull SettingsScreenType screenType, + @Nullable ApplicationMode appMode, + @NonNull Bundle args, + @Nullable Fragment target) { + final Fragment fragment = createFragment(screenType.fragmentName, activity, appMode, args, target); + return showFragment(fragment, activity, screenType.fragmentName); + } + + public static boolean showFragment(final Fragment fragment, + final @NonNull FragmentActivity activity, + final String fragmentName) { try { FragmentManager fragmentManager = activity.getSupportFragmentManager(); - String tag = screenType.fragmentName; - if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, tag)) { - Fragment fragment = Fragment.instantiate(activity, tag); - if (appMode != null) { - args.putString(APP_MODE_KEY, appMode.getStringKey()); - } - fragment.setArguments(args); - fragment.setTargetFragment(target, 0); + if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, fragmentName)) { fragmentManager.beginTransaction() - .replace(R.id.fragmentContainer, fragment, tag) + .replace(R.id.fragmentContainer, fragment, fragmentName) .addToBackStack(DRAWER_SETTINGS_ID) .commitAllowingStateLoss(); return true; diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ConfigureProfileFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ConfigureProfileFragment.java index 89f1bb1e841..2498ade9904 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ConfigureProfileFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ConfigureProfileFragment.java @@ -1,5 +1,9 @@ package net.osmand.plus.settings.fragments; +import static net.osmand.plus.settings.fragments.ResetProfilePrefsBottomSheetFactory.createResetProfilePrefsBottomSheet; +import static net.osmand.plus.settings.fragments.SelectCopyAppModeBottomSheetFactory.createSelectCopyAppModeBottomSheet; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; +import static net.osmand.plus.settings.fragments.search.PreferenceMarker.markPreferenceAsConnectedToPlugin; import static net.osmand.plus.utils.UiUtilities.CompoundButtonType.TOOLBAR; import android.content.Context; @@ -20,6 +24,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.SwitchCompat; import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; @@ -40,15 +45,15 @@ import net.osmand.plus.plugins.PluginsFragment; import net.osmand.plus.plugins.PluginsHelper; import net.osmand.plus.plugins.development.OsmandDevelopmentPlugin; -import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet; import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.backup.SettingsHelper.ImportListener; import net.osmand.plus.settings.backend.backup.items.SettingsItem; -import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet; import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet.ResetAppModePrefsListener; import net.osmand.plus.settings.fragments.configureitems.ConfigureMenuRootFragment; import net.osmand.plus.settings.fragments.profileappearance.ProfileAppearanceFragment; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.FileUtils; @@ -62,9 +67,9 @@ import java.io.File; import java.util.Collections; import java.util.List; +import java.util.Optional; -public class ConfigureProfileFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, - ResetAppModePrefsListener, PluginStateListener { +public class ConfigureProfileFragment extends BaseSettingsFragment implements CopyAppModePrefsListener, ResetAppModePrefsListener, PluginStateListener, ShowableSearchablePreferenceDialogProvider { public static final String TAG = ConfigureProfileFragment.class.getSimpleName(); @@ -418,6 +423,7 @@ private void setupOsmandPluginsPref() { preference.setIcon(getContentIcon(plugin.getLogoResourceId())); preference.setLayoutResource(R.layout.preference_with_descr); preference.setFragment(plugin.getSettingsScreenType().fragmentName); + markPreferenceAsConnectedToPlugin(preference, plugin.getClass()); category.addPreference(preference); } @@ -431,33 +437,73 @@ private void setupUiCustomizationPref() { } } + @Override + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (RESET_TO_DEFAULT.equals(preference.getKey())) { + return Optional.of(createResetProfilePrefsBottomSheet(target, this)); + } + if (COPY_PROFILE_SETTINGS.equals(preference.getKey())) { + return Optional.of(createSelectCopyAppModeBottomSheet(target, this)); + } + if (isConfigureScreen(preference)) { + return Optional.of(createConfigureScreenFragment()); + } + if (UI_CUSTOMIZATION.equals(preference.getKey())) { + return Optional.of(createConfigureMenuRootFragment(target)); + } + return Optional.empty(); + } + + private static boolean isConfigureScreen(final Preference preference) { + return CONFIGURE_SCREEN.equals(preference.getKey()); + } + + private ShowableSearchablePreferenceDialog createConfigureScreenFragment() { + return new ShowableSearchablePreferenceDialog<>(ConfigureScreenFragment.createInstance()) { + + @Override + protected void show(final ConfigureScreenFragment configureScreenFragment) { + configureScreenFragment.show(getMapActivity().getSupportFragmentManager()); + } + }; + } + + private ShowableSearchablePreferenceDialog createConfigureMenuRootFragment(final Optional target) { + return new ShowableSearchablePreferenceDialog<>( + ConfigureMenuRootFragment.createInstance( + getSelectedAppMode(), + target.orElse(null))) { + + @Override + protected void show(final ConfigureMenuRootFragment searchablePreferenceDialog) { + searchablePreferenceDialog.show(getFragmentManager()); + } + }; + } + @Override public boolean onPreferenceClick(Preference preference) { - MapActivity mapActivity = getMapActivity(); - FragmentManager fragmentManager = getFragmentManager(); + final MapActivity mapActivity = getMapActivity(); + final FragmentManager fragmentManager = getFragmentManager(); if (mapActivity != null && fragmentManager != null) { - String prefId = preference.getKey(); - ApplicationMode selectedMode = getSelectedAppMode(); - + final String prefId = preference.getKey(); + final ApplicationMode selectedMode = getSelectedAppMode(); if (CONFIGURE_MAP.equals(prefId)) { sepAppModeToSelected(); fragmentManager.beginTransaction() .remove(this) .addToBackStack(TAG) .commitAllowingStateLoss(); - } else if (CONFIGURE_SCREEN.equals(prefId)) { + } else if (isConfigureScreen(preference)) { sepAppModeToSelected(); - ConfigureScreenFragment.showInstance(mapActivity); - } else if (COPY_PROFILE_SETTINGS.equals(prefId)) { - SelectCopyAppModeBottomSheet.showInstance(fragmentManager, this, selectedMode); - } else if (RESET_TO_DEFAULT.equals(prefId)) { - ResetProfilePrefsBottomSheet.showInstance(fragmentManager, getSelectedAppMode(), this); + createConfigureScreenFragment().show(); + return true; } else if (EXPORT_PROFILE.equals(prefId)) { ExportSettingsFragment.showInstance(fragmentManager, selectedMode, null, false); } else if (DELETE_PROFILE.equals(prefId)) { showDeleteModeConfirmation(); - } else if (UI_CUSTOMIZATION.equals(prefId)) { - ConfigureMenuRootFragment.showInstance(fragmentManager, selectedMode, this); + } else if (showDialogForPreference(preference, this)) { + return true; } } return super.onPreferenceClick(preference); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/GeneralProfileSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/GeneralProfileSettingsFragment.java index d5157d9a77c..a2fdfb50c08 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/GeneralProfileSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/GeneralProfileSettingsFragment.java @@ -1,7 +1,8 @@ package net.osmand.plus.settings.fragments; -import static net.osmand.plus.settings.bottomsheets.DistanceDuringNavigationBottomSheet.*; +import static net.osmand.plus.settings.bottomsheets.DistanceDuringNavigationBottomSheet.DistanceDuringNavigationMode; import static net.osmand.plus.settings.fragments.SettingsScreenType.EXTERNAL_INPUT_DEVICE; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import android.content.Context; import android.content.pm.ActivityInfo; @@ -17,8 +18,10 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.AppCompatCheckedTextView; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; import net.osmand.data.PointDescription; import net.osmand.plus.R; @@ -33,21 +36,27 @@ import net.osmand.plus.settings.bottomsheets.DistanceDuringNavigationBottomSheet; import net.osmand.plus.settings.controllers.CompassModeDialogController; import net.osmand.plus.settings.enums.AngularConstants; -import net.osmand.plus.settings.enums.DrivingRegion; import net.osmand.plus.settings.enums.CompassMode; +import net.osmand.plus.settings.enums.DrivingRegion; import net.osmand.plus.settings.enums.VolumeUnit; -import net.osmand.router.GeneralRouter; -import net.osmand.shared.settings.enums.MetricsConstants; -import net.osmand.shared.settings.enums.SpeedConstants; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandler; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandlerProvider; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import net.osmand.plus.utils.UiUtilities; +import net.osmand.router.GeneralRouter; +import net.osmand.shared.settings.enums.MetricsConstants; +import net.osmand.shared.settings.enums.SpeedConstants; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; -public class GeneralProfileSettingsFragment extends BaseSettingsFragment { +public class GeneralProfileSettingsFragment extends BaseSettingsFragment implements PreferenceFragmentHandlerProvider, ShowableSearchablePreferenceDialogProvider { public static final String TAG = GeneralProfileSettingsFragment.class.getSimpleName(); @@ -124,8 +133,8 @@ private void setupRotateMapPref() { private void setupMapScreenOrientationPref() { ListPreferenceEx mapScreenOrientation = findPreference(settings.MAP_SCREEN_ORIENTATION.getId()); - mapScreenOrientation.setEntries(new String[] {getString(R.string.map_orientation_portrait), getString(R.string.map_orientation_landscape), getString(R.string.map_orientation_default)}); - mapScreenOrientation.setEntryValues(new Integer[] {ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED}); + mapScreenOrientation.setEntries(new String[]{getString(R.string.map_orientation_portrait), getString(R.string.map_orientation_landscape), getString(R.string.map_orientation_default)}); + mapScreenOrientation.setEntryValues(new Integer[]{ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED}); mapScreenOrientation.setIcon(getMapScreenOrientationIcon()); } @@ -413,29 +422,86 @@ public void onApplyPreferenceChange(String prefId, boolean applyToAllProfiles, O } @Override - public boolean onPreferenceClick(Preference preference) { - String key = preference.getKey(); - ApplicationMode appMode = getSelectedAppMode(); - if (key.equals(settings.DRIVING_REGION.getId())) { + public boolean onPreferenceClick(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return true; + } + if (settings.DRIVING_REGION.getId().equals(preference.getKey())) { showDrivingRegionDialog(); return true; - } else if (key.equals(settings.ROTATE_MAP.getId())) { - CompassModeDialogController controller = new CompassModeDialogController(app, appMode); + } + if (settings.ROTATE_MAP.getId().equals(preference.getKey())) { + CompassModeDialogController controller = new CompassModeDialogController(app, getSelectedAppMode()); showSingleSelectionDialog(CompassModeDialogController.PROCESS_ID, controller); controller.setCallback(this); return true; - } else if (key.equals(settings.EXTERNAL_INPUT_DEVICE.getId())) { - BaseSettingsFragment.showInstance(requireActivity(), EXTERNAL_INPUT_DEVICE, appMode, new Bundle(), this); - return true; - } else if (key.equals(settings.PRECISE_DISTANCE_NUMBERS.getId())) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - DistanceDuringNavigationBottomSheet.showInstance(fragmentManager, preference.getKey(), this, getSelectedAppMode(), false); - } } return super.onPreferenceClick(preference); } + @Override + public Optional getPreferenceFragmentHandler(final Preference preference) { + if (settings.EXTERNAL_INPUT_DEVICE.getId().equals(preference.getKey())) { + return Optional.of( + new PreferenceFragmentHandler() { + + @Override + public Class getClassOfPreferenceFragment() { + return EXTERNAL_INPUT_DEVICE.fragmentClass.asSubclass(PreferenceFragmentCompat.class); + } + + @Override + public PreferenceFragmentCompat createPreferenceFragment(final Context context, final Optional target) { + return (PreferenceFragmentCompat) BaseSettingsFragment.createFragment( + getClassOfPreferenceFragment().getName(), + context, + getSelectedAppMode(), + new Bundle(), + target.orElse(null)); + } + + @Override + public boolean showPreferenceFragment(final PreferenceFragmentCompat preferenceFragment) { + return BaseSettingsFragment.showFragment( + preferenceFragment, + requireActivity(), + getClassOfPreferenceFragment().getName()); + } + } + ); + } + return Optional.empty(); + } + + @Override + public Optional> getShowableSearchablePreferenceDialog( + final Preference preference, + final Optional target) { + if (settings.PRECISE_DISTANCE_NUMBERS.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + DistanceDuringNavigationBottomSheet.createInstance( + preference, + target, + getSelectedAppMode(), + false)) { + + @Override + protected void show(final DistanceDuringNavigationBottomSheet distanceDuringNavigationBottomSheet) { + GeneralProfileSettingsFragment.this.show(distanceDuringNavigationBottomSheet); + } + }); + } + return Optional.empty(); + } + + private void show(final SearchablePreferenceDialog dialog) { + final FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager != null) { + dialog.show(fragmentManager); + } + } + private void updateDialogControllerCallbacks() { IDialogController controller; DialogManager dialogManager = app.getDialogManager(); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java index bd942cea8ea..a9385a89a00 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java @@ -11,6 +11,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; @@ -32,14 +33,17 @@ import net.osmand.plus.settings.datastorage.DataStorageHelper; import net.osmand.plus.settings.datastorage.item.StorageItem; import net.osmand.plus.settings.enums.LocationSource; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import java.util.Map; +import java.util.Optional; public class GlobalSettingsFragment extends BaseSettingsFragment - implements OnSendAnalyticsPrefsUpdate, OnSelectProfileCallback { + implements OnSendAnalyticsPrefsUpdate, OnSelectProfileCallback, ShowableSearchablePreferenceDialogProvider { public static final String TAG = GlobalSettingsFragment.class.getSimpleName(); @@ -68,21 +72,83 @@ protected void setupPreferences() { } @Override - public void onDisplayPreferenceDialog(Preference preference) { - String prefId = preference.getKey(); + public void onDisplayPreferenceDialog(final Preference preference) { + if (isSendAnonymousData(preference)) { + createSendAnonymousDataPreferenceDialog(Optional.of(this)).show(); + } + } - if (prefId.equals(SEND_ANONYMOUS_DATA_PREF_ID)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - SendAnalyticsBottomSheetDialogFragment.showInstance(app, fragmentManager, this); - } - } else { - super.onDisplayPreferenceDialog(preference); + @Override + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (isSendAnonymousData(preference)) { + return Optional.of(createSendAnonymousDataPreferenceDialog(target)); + } + if (isSelectDefaultProfile(preference)) { + return Optional.of(createSelectDefaultProfilePreferenceDialog(target)); } + if (isMapRenderingEngine(preference)) { + return Optional.of(createMapRenderingEngineDialog()); + } + return Optional.empty(); + } + + private static boolean isSendAnonymousData(final Preference preference) { + return SEND_ANONYMOUS_DATA_PREF_ID.equals(preference.getKey()); + } + + private ShowableSearchablePreferenceDialog createSendAnonymousDataPreferenceDialog(final Optional target) { + return new ShowableSearchablePreferenceDialog<>(SendAnalyticsBottomSheetDialogFragment.createInstance(target.orElse(null))) { + + @Override + protected void show(final SendAnalyticsBottomSheetDialogFragment sendAnalyticsBottomSheetDialogFragment) { + final FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager != null) { + sendAnalyticsBottomSheetDialogFragment.show(fragmentManager); + } + } + }; + } + + private boolean isSelectDefaultProfile(final Preference preference) { + return settings.DEFAULT_APPLICATION_MODE.getId().equals(preference.getKey()); + } + + private ShowableSearchablePreferenceDialog createSelectDefaultProfilePreferenceDialog(final Optional target) { + return new ShowableSearchablePreferenceDialog<>( + SelectDefaultProfileBottomSheet.createInstance( + target, + getSelectedAppMode(), + settings.DEFAULT_APPLICATION_MODE.get().getStringKey(), + false)) { + + @Override + protected void show(final SelectDefaultProfileBottomSheet selectDefaultProfileBottomSheet) { + selectDefaultProfileBottomSheet.show(requireActivity().getSupportFragmentManager()); + } + }; + } + + private static boolean isMapRenderingEngine(final Preference preference) { + return MAP_RENDERING_ENGINE_ID.equals(preference.getKey()); + } + + private ShowableSearchablePreferenceDialog createMapRenderingEngineDialog() { + return new ShowableSearchablePreferenceDialog<>( + new MapRenderingEngineDialog( + app, + getActivity(), + this::setupMapRenderingEnginePref)) { + + @Override + protected void show(final MapRenderingEngineDialog mapRenderingEngineDialog) { + mapRenderingEngineDialog.show(getParentFragmentManager()); + } + }; } @Override - protected void onBindPreferenceViewHolder(@NonNull Preference preference, @NonNull PreferenceViewHolder holder) { + protected void onBindPreferenceViewHolder(@NonNull Preference preference, + @NonNull PreferenceViewHolder holder) { super.onBindPreferenceViewHolder(preference, holder); String prefId = preference.getKey(); @@ -128,7 +194,9 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { if (enabled) { FragmentManager fragmentManager = getFragmentManager(); if (fragmentManager != null) { - SendAnalyticsBottomSheetDialogFragment.showInstance(app, fragmentManager, this); + SendAnalyticsBottomSheetDialogFragment + .createInstance(this) + .show(fragmentManager); } } else { settings.SEND_ANONYMOUS_MAP_DOWNLOADS_DATA.set(false); @@ -168,26 +236,28 @@ public void onAnalyticsPrefsUpdate() { } @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(final Preference preference) { String prefId = preference.getKey(); - if (prefId.equals(settings.DEFAULT_APPLICATION_MODE.getId())) { - if (getActivity() != null) { - String defaultModeKey = settings.DEFAULT_APPLICATION_MODE.get().getStringKey(); - SelectDefaultProfileBottomSheet.showInstance( - getActivity(), this, getSelectedAppMode(), defaultModeKey, false); - } + if (isSelectDefaultProfile(preference)) { + this + .createSelectDefaultProfilePreferenceDialog(Optional.of(this)) + .show(); + return true; } else if (settings.SPEED_CAMERAS_UNINSTALLED.getId().equals(prefId) && !settings.SPEED_CAMERAS_UNINSTALLED.get()) { FragmentManager manager = getFragmentManager(); if (manager != null) { SpeedCamerasBottomSheet.showInstance(manager, this); + return true; } - } else if (prefId.equals(settings.LOCATION_SOURCE.getId())) { + } else if (settings.LOCATION_SOURCE.getId().equals(prefId)) { FragmentManager manager = getFragmentManager(); if (manager != null) { LocationSourceBottomSheet.showInstance(manager, this); + return true; } - } else if (prefId.equals(MAP_RENDERING_ENGINE_ID)) { - new MapRenderingEngineDialog(app, getActivity()).showDialog(this::setupMapRenderingEnginePref); + } else if (isMapRenderingEngine(preference)) { + createMapRenderingEngineDialog().show(); + return true; } return super.onPreferenceClick(preference); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java index f867106d6e4..1bd112454c5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/MainSettingsFragment.java @@ -4,19 +4,24 @@ import static net.osmand.plus.importfiles.ImportType.SETTINGS; import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILES_LIST_UPDATED_ARG; import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; +import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import androidx.annotation.ColorRes; import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceViewHolder; import net.osmand.plus.OsmandApplication; @@ -30,6 +35,11 @@ import net.osmand.plus.profiles.data.ProfileDataUtils; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.fragments.profileappearance.ProfileAppearanceFragment; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandler; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandlerProvider; +import net.osmand.plus.settings.fragments.search.SettingsSearchButtonHelper; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import net.osmand.plus.settings.purchase.PurchasesFragment; import net.osmand.plus.utils.AndroidUtils; @@ -39,15 +49,16 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; import java.util.Set; -public class MainSettingsFragment extends BaseSettingsFragment implements OnSelectProfileCallback { +public class MainSettingsFragment extends BaseSettingsFragment implements OnSelectProfileCallback, PreferenceFragmentHandlerProvider, ShowableSearchablePreferenceDialogProvider { public static final String TAG = MainSettingsFragment.class.getName(); private static final String BACKUP_AND_RESTORE = "backup_and_restore"; private static final String CONFIGURE_PROFILE = "configure_profile"; - private static final String APP_PROFILES = "app_profiles"; + public static final String APP_PROFILES = "app_profiles"; private static final String PURCHASES_SETTINGS = "purchases_settings"; private static final String SELECTED_PROFILE = "selected_profile"; private static final String CREATE_PROFILE = "create_profile"; @@ -119,17 +130,11 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { @Override public boolean onPreferenceClick(Preference preference) { - String prefId = preference.getKey(); - if (preference.getParent() != null && APP_PROFILES.equals(preference.getParent().getKey())) { - BaseSettingsFragment.showInstance(getActivity(), SettingsScreenType.CONFIGURE_PROFILE, - ApplicationMode.valueOfStringKey(prefId, null)); + if (showDialogForPreference(preference, this)) { return true; - } else if (CREATE_PROFILE.equals(prefId)) { - if (getActivity() != null) { - SelectBaseProfileBottomSheet.showInstance( - getActivity(), this, getSelectedAppMode(), null, false); - } - } else if (PURCHASES_SETTINGS.equals(prefId)) { + } + String prefId = preference.getKey(); + if (PURCHASES_SETTINGS.equals(prefId)) { MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { FragmentManager fragmentManager = mapActivity.getSupportFragmentManager(); @@ -163,6 +168,60 @@ public boolean onPreferenceClick(Preference preference) { return super.onPreferenceClick(preference); } + @Override + public Optional> getShowableSearchablePreferenceDialog( + final Preference preference, + final Optional target) { + if (CREATE_PROFILE.equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + SelectBaseProfileBottomSheet.createInstance( + target, + getSelectedAppMode(), + null, + false)) { + + @Override + protected void show(final SelectBaseProfileBottomSheet selectBaseProfileBottomSheet) { + selectBaseProfileBottomSheet.show(getActivity().getSupportFragmentManager()); + } + }); + } + return Optional.empty(); + } + + @Override + public Optional getPreferenceFragmentHandler(final Preference preference) { + return Optional + .ofNullable(ApplicationMode.valueOfStringKey(preference.getKey(), null)) + .map(applicationMode -> + new PreferenceFragmentHandler() { + + @Override + public Class getClassOfPreferenceFragment() { + return SettingsScreenType.CONFIGURE_PROFILE.fragmentClass.asSubclass(PreferenceFragmentCompat.class); + } + + @Override + public PreferenceFragmentCompat createPreferenceFragment(final Context context, final Optional target) { + return (PreferenceFragmentCompat) BaseSettingsFragment.createFragment( + getClassOfPreferenceFragment().getName(), + context, + applicationMode, + new Bundle(), + target.orElse(null)); + } + + @Override + public boolean showPreferenceFragment(final PreferenceFragmentCompat preferenceFragment) { + return BaseSettingsFragment.showFragment( + preferenceFragment, + requireActivity(), + getClassOfPreferenceFragment().getName()); + } + }); + } + private void setupLocalBackup() { setupBackupToFilePref(); setupRestoreFromFilePref(); @@ -263,4 +322,16 @@ public void onProfileSelected(Bundle args) { ProfileAppearanceFragment.showInstance(activity, profileKey, imported); } } + + @Override + protected void createToolbar(@NonNull final LayoutInflater inflater, @NonNull final View view) { + super.createToolbar(inflater, view); + final SettingsSearchButtonHelper settingsSearchButtonHelper = + new SettingsSearchButtonHelper( + this, + R.id.fragmentContainer, + app, + getMapActivity()::getCreateSearchDatabaseTask); + settingsSearchButtonHelper.configureSettingsSearchButton(view.findViewById(R.id.action_button)); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java index 1cf0818040c..2c87bfa4c4c 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/NavigationFragment.java @@ -6,6 +6,7 @@ import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG; import static net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DIALOG_MODE_KEY; import static net.osmand.plus.routing.TransportRoutingHelper.PUBLIC_TRANSPORT_KEY; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -32,9 +33,13 @@ import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DialogMode; import net.osmand.plus.routing.RouteService; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.util.Algorithms; -public class NavigationFragment extends BaseSettingsFragment implements OnSelectProfileCallback { +import java.util.Optional; + +public class NavigationFragment extends BaseSettingsFragment implements OnSelectProfileCallback, ShowableSearchablePreferenceDialogProvider { public static final String TAG = NavigationFragment.class.getSimpleName(); public static final String NAVIGATION_TYPE = "navigation_type"; @@ -144,18 +149,37 @@ public void onApplyPreferenceChange(String prefId, boolean applyToAllProfiles, O } @Override - public boolean onPreferenceClick(Preference preference) { - String prefId = preference.getKey(); - MapActivity activity = getMapActivity(); + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + return NAVIGATION_TYPE.equals(preference.getKey()) ? + Optional.of( + new ShowableSearchablePreferenceDialog<>( + SelectNavProfileBottomSheet.createInstance( + target, + getSelectedAppMode(), + getSelectedAppMode().getRoutingProfile(), + false)) { + + @Override + protected void show(final SelectNavProfileBottomSheet selectNavProfileBottomSheet) { + selectNavProfileBottomSheet.show(getMapActivity().getSupportFragmentManager()); + } + }) : + Optional.empty(); + } + + @Override + public boolean onPreferenceClick(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return true; + } + final MapActivity activity = getMapActivity(); if (activity != null) { - ApplicationMode appMode = getSelectedAppMode(); - if (NAVIGATION_TYPE.equals(prefId)) { - String selected = appMode.getRoutingProfile(); - SelectNavProfileBottomSheet.showInstance(activity, this, appMode, selected, false); - } else if (CUSTOMIZE_ROUTE_LINE.equals(prefId)) { - RouteLineAppearanceFragment.showInstance(activity, appMode); - } else if (DETAILED_TRACK_GUIDANCE.equals(prefId)) { - DetailedTrackGuidanceFragment.showInstance(activity, appMode, this); + if (CUSTOMIZE_ROUTE_LINE.equals(preference.getKey())) { + RouteLineAppearanceFragment.showInstance(activity, getSelectedAppMode()); + // TODO: return true because the click was handled? + } else if (DETAILED_TRACK_GUIDANCE.equals(preference.getKey())) { + DetailedTrackGuidanceFragment.showInstance(activity, getSelectedAppMode(), this); + // TODO: return true because the click was handled? } } return false; diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileOptionsDialogController.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileOptionsDialogController.java index 7285b92ce1e..85a4a06cc1c 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileOptionsDialogController.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileOptionsDialogController.java @@ -8,11 +8,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentManager; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.dialog.BaseDialogController; import net.osmand.plus.base.dialog.DialogManager; import net.osmand.plus.base.dialog.data.DisplayData; @@ -79,7 +77,7 @@ public String getProcessId() { return PROCESS_ID; } - public void showDialog(@NonNull MapActivity mapActivity, @NonNull String title, @NonNull String description, @NonNull CommonPreference preference) { + public CustomizableSingleSelectionBottomSheet createDialog(@NonNull String title, @NonNull String description, @NonNull CommonPreference preference) { this.title = title; this.description = description; this.preference = preference; @@ -87,8 +85,7 @@ public void showDialog(@NonNull MapActivity mapActivity, @NonNull String title, DialogManager dialogManager = app.getDialogManager(); dialogManager.register(PROCESS_ID, this); - FragmentManager manager = mapActivity.getSupportFragmentManager(); - CustomizableSingleSelectionBottomSheet.showInstance(manager, PROCESS_ID, true); + return CustomizableSingleSelectionBottomSheet.createInstance(PROCESS_ID, true); } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ResetProfilePrefsBottomSheetFactory.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ResetProfilePrefsBottomSheetFactory.java new file mode 100644 index 00000000000..6bbcb0018fa --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ResetProfilePrefsBottomSheetFactory.java @@ -0,0 +1,26 @@ +package net.osmand.plus.settings.fragments; + +import androidx.fragment.app.Fragment; + +import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; + +import java.util.Optional; + +public class ResetProfilePrefsBottomSheetFactory { + + public static ShowableSearchablePreferenceDialog createResetProfilePrefsBottomSheet( + final Optional target, + final BaseSettingsFragment baseSettingsFragment) { + return new ShowableSearchablePreferenceDialog<>( + ResetProfilePrefsBottomSheet.createInstance( + baseSettingsFragment.getSelectedAppMode(), + target)) { + + @Override + protected void show(final ResetProfilePrefsBottomSheet resetProfilePrefsBottomSheet) { + resetProfilePrefsBottomSheet.show(baseSettingsFragment.getFragmentManager()); + } + }; + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java index 52a38336ee4..73f50e1f8db 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/RouteParametersFragment.java @@ -5,6 +5,7 @@ import static net.osmand.plus.settings.enums.RoutingType.HH_JAVA; import static net.osmand.plus.settings.fragments.DangerousGoodsFragment.getHazmatUsaClass; import static net.osmand.plus.settings.fragments.SettingsScreenType.DANGEROUS_GOODS; +import static net.osmand.plus.settings.fragments.search.PreferenceMarker.markPreferenceAsConnectedToPlugin; import static net.osmand.plus.utils.AndroidUtils.getRoutingStringPropertyName; import static net.osmand.router.GeneralRouter.*; @@ -22,9 +23,11 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceViewHolder; import androidx.preference.TwoStatePreference; @@ -37,6 +40,7 @@ import net.osmand.plus.R; import net.osmand.plus.base.dialog.DialogManager; import net.osmand.plus.base.dialog.interfaces.controller.IDialogController; +import net.osmand.plus.plugins.OsmandPlugin; import net.osmand.plus.plugins.PluginsHelper; import net.osmand.plus.plugins.development.OsmandDevelopmentPlugin; import net.osmand.plus.routing.RouteService; @@ -56,6 +60,10 @@ import net.osmand.plus.settings.enums.ApproximationType; import net.osmand.plus.settings.enums.DrivingRegion; import net.osmand.plus.settings.enums.RoutingType; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandler; +import net.osmand.plus.settings.fragments.search.PreferenceFragmentHandlerProvider; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListParameters; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.MultiSelectBooleanPreference; @@ -76,9 +84,10 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; -public class RouteParametersFragment extends BaseSettingsFragment { +public class RouteParametersFragment extends BaseSettingsFragment implements PreferenceFragmentHandlerProvider, ShowableSearchablePreferenceDialogProvider { public static final String TAG = RouteParametersFragment.class.getSimpleName(); @@ -167,7 +176,7 @@ private void setupTimeConditionalRoutingPref() { getPreferenceScreen().addPreference(timeConditionalRouting); } - private void setupOsmLiveForPublicTransportPref() { + private void setupOsmLiveForPublicTransportPref(final Class plugin) { SwitchPreferenceEx useOsmLiveForPublicTransport = createSwitchPreferenceEx(settings.USE_OSM_LIVE_FOR_PUBLIC_TRANSPORT.getId(), R.string.use_live_public_transport, R.layout.preference_with_descr_dialog_and_switch); useOsmLiveForPublicTransport.setDescription(getString(R.string.use_osm_live_public_transport_description)); @@ -175,20 +184,22 @@ private void setupOsmLiveForPublicTransportPref() { useOsmLiveForPublicTransport.setSummaryOff(R.string.shared_string_disabled); useOsmLiveForPublicTransport.setIcon(getPersistentPrefIcon(R.drawable.ic_action_osm_live)); useOsmLiveForPublicTransport.setIconSpaceReserved(true); + markPreferenceAsConnectedToPlugin(useOsmLiveForPublicTransport, plugin); getPreferenceScreen().addPreference(useOsmLiveForPublicTransport); } - private void setupNativePublicTransport() { + private void setupNativePublicTransport(final Class plugin) { SwitchPreferenceEx setupNativePublicTransport = createSwitchPreferenceEx(settings.PT_SAFE_MODE.getId(), R.string.use_native_pt, R.layout.preference_with_descr_dialog_and_switch); setupNativePublicTransport.setDescription(getString(R.string.use_native_pt_desc)); setupNativePublicTransport.setSummaryOn(R.string.shared_string_enabled); setupNativePublicTransport.setSummaryOff(R.string.shared_string_disabled); setupNativePublicTransport.setIconSpaceReserved(true); + markPreferenceAsConnectedToPlugin(setupNativePublicTransport, plugin); getPreferenceScreen().addPreference(setupNativePublicTransport); } - private void setupOsmLiveForRoutingPref() { + private void setupOsmLiveForRoutingPref(final Class plugin) { SwitchPreferenceEx useOsmLiveForRouting = createSwitchPreferenceEx(settings.USE_OSM_LIVE_FOR_ROUTING.getId(), R.string.use_live_routing, R.layout.preference_with_descr_dialog_and_switch); useOsmLiveForRouting.setDescription(getString(R.string.use_osm_live_routing_description)); @@ -196,6 +207,7 @@ private void setupOsmLiveForRoutingPref() { useOsmLiveForRouting.setSummaryOff(R.string.shared_string_disabled); useOsmLiveForRouting.setIcon(getPersistentPrefIcon(R.drawable.ic_action_osm_live)); useOsmLiveForRouting.setIconSpaceReserved(true); + markPreferenceAsConnectedToPlugin(useOsmLiveForRouting, plugin); getPreferenceScreen().addPreference(useOsmLiveForRouting); } @@ -234,8 +246,9 @@ private void setupRoutingPrefs() { setupSelectRouteRecalcDistance(screen); setupReverseDirectionRecalculation(screen); - if (PluginsHelper.isActive(OsmandDevelopmentPlugin.class)) { - setupDevelopmentCategoryPreferences(screen, am); + final Class plugin = OsmandDevelopmentPlugin.class; + if (PluginsHelper.isActive(plugin)) { + setupDevelopmentCategoryPreferences(screen, am, plugin); } } @@ -395,38 +408,41 @@ private void setupRouteRecalcHeader(PreferenceScreen screen) { PreferenceCategory routingCategory = new PreferenceCategory(requireContext()); routingCategory.setLayoutResource(R.layout.preference_category_with_descr); routingCategory.setTitle(R.string.recalculate_route); + routingCategory.setKey("RouteParametersFragment.recalculate_route.key"); screen.addPreference(routingCategory); } - private void setupDevelopmentCategoryPreferences(PreferenceScreen screen, - ApplicationMode mode) { + private void setupDevelopmentCategoryPreferences(PreferenceScreen screen, ApplicationMode mode, final Class plugin) { addDividerPref(); - setupDevelopmentCategoryHeader(screen); + setupDevelopmentCategoryHeader(screen, plugin); if (mode.isDerivedRoutingFrom(ApplicationMode.PUBLIC_TRANSPORT)) { - setupOsmLiveForPublicTransportPref(); - setupNativePublicTransport(); + setupOsmLiveForPublicTransportPref(plugin); + setupNativePublicTransport(plugin); } else { - setupRoutingTypePref(); - setupApproximationTypePref(); - setupAutoZoomPref(); - setupOsmLiveForRoutingPref(); + setupRoutingTypePref(plugin); + setupApproximationTypePref(plugin); + setupAutoZoomPref(plugin); + setupOsmLiveForRoutingPref(plugin); } } - private void setupDevelopmentCategoryHeader(PreferenceScreen screen) { + private void setupDevelopmentCategoryHeader(PreferenceScreen screen, final Class plugin) { PreferenceCategory developmentCategory = new PreferenceCategory(requireContext()); developmentCategory.setLayoutResource(R.layout.preference_category_with_descr); developmentCategory.setTitle(R.string.development); + developmentCategory.setKey("development"); + markPreferenceAsConnectedToPlugin(developmentCategory, plugin); screen.addPreference(developmentCategory); } - private void setupAutoZoomPref() { + private void setupAutoZoomPref(final Class plugin) { Preference preference = new Preference(requireContext()); preference.setKey(settings.USE_DISCRETE_AUTO_ZOOM.getId()); preference.setTitle(R.string.auto_zoom); preference.setLayoutResource(R.layout.preference_with_descr); preference.setIcon(getContentIcon(R.drawable.ic_action_magnifier_plus)); preference.setSummary(settings.USE_DISCRETE_AUTO_ZOOM.get() ? R.string.auto_zoom_discrete : R.string.auto_zoom_smooth); + markPreferenceAsConnectedToPlugin(preference, plugin); getPreferenceScreen().addPreference(preference); } @@ -479,7 +495,7 @@ private void showRoutingTypeDialog(@NonNull Preference preference) { PopUpMenu.show(displayData); } - private void setupRoutingTypePref() { + private void setupRoutingTypePref(final Class plugin) { RoutingType[] types = RoutingType.values(); String[] names = new String[types.length]; Integer[] values = new Integer[types.length]; @@ -493,6 +509,7 @@ private void setupRoutingTypePref() { ListPreferenceEx preference = createListPreferenceEx(settings.ROUTING_TYPE.getId(), names, values, R.string.routing_type, R.layout.preference_with_descr); preference.setIcon(getContentIcon(R.drawable.ic_action_route_points)); + markPreferenceAsConnectedToPlugin(preference, plugin); getPreferenceScreen().addPreference(preference); } @@ -518,7 +535,7 @@ private void showApproximationTypeDialog(@NonNull Preference preference) { PopUpMenu.show(displayData); } - private void setupApproximationTypePref() { + private void setupApproximationTypePref(final Class plugin) { ApproximationType[] types = ApproximationType.values(); String[] names = new String[types.length]; Integer[] values = new Integer[types.length]; @@ -532,6 +549,7 @@ private void setupApproximationTypePref() { ListPreferenceEx preference = createListPreferenceEx(settings.APPROXIMATION_TYPE.getId(), names, values, R.string.gpx_approximation, R.layout.preference_with_descr); preference.setIcon(getContentIcon(R.drawable.ic_action_attach_track)); + markPreferenceAsConnectedToPlugin(preference, plugin); getPreferenceScreen().addPreference(preference); } @@ -550,12 +568,10 @@ public boolean onPreferenceClick(Preference preference) { Integer selectedValueIndex = enabled ? hazmatParameters.findIndexOfValue(selectedValue) : null; HazmatCategoryBottomSheet.showInstance(manager, this, HAZMAT_TRANSPORTING_ENABLED, appMode, false, hazmatParameters.localizedNames, hazmatParameters.values, selectedValueIndex); } - } else if (GOODS_RESTRICTIONS_PREFERENCE.equals(prefId)) { - FragmentManager manager = getFragmentManager(); - if (manager != null) { - OsmandPreference pref = getGoodsRestrictionPreference(); - GoodsRestrictionsBottomSheet.showInstance(manager, this, GOODS_RESTRICTIONS_PREFERENCE, appMode, false, pref.getModeValue(appMode)); - } + } else if (isGoodsRestrictionsPreference(preference)) { + this + .getPreferenceDialogForGoodsRestrictionsPreference(preference, Optional.of(this)) + .show(); } else if (ALLOW_VIA_FERRATA_PREFERENCE.equals(prefId)) { FragmentManager manager = getFragmentManager(); if (manager != null) { @@ -563,24 +579,111 @@ public boolean onPreferenceClick(Preference preference) { showSingleSelectionDialog(ViaFerrataDialogController.PROCESS_ID, controller); controller.setCallback(this); } - } else if (DANGEROUS_GOODS_USA.equals(prefId)) { - BaseSettingsFragment.showInstance(requireActivity(), DANGEROUS_GOODS, appMode, new Bundle(), this); } else if (settings.USE_DISCRETE_AUTO_ZOOM.getId().equals(prefId)) { showAutoZoomDialog(preference); } return super.onPreferenceClick(preference); } + @Override + public Optional getPreferenceFragmentHandler(final Preference preference) { + if (DANGEROUS_GOODS_USA.equals(preference.getKey())) { + return Optional.of( + new PreferenceFragmentHandler() { + + @Override + public Class getClassOfPreferenceFragment() { + return DANGEROUS_GOODS.fragmentClass.asSubclass(PreferenceFragmentCompat.class); + } + + @Override + public PreferenceFragmentCompat createPreferenceFragment(final Context context, final Optional target) { + return (PreferenceFragmentCompat) BaseSettingsFragment.createFragment( + getClassOfPreferenceFragment().getName(), + context, + getSelectedAppMode(), + new Bundle(), + null); + } + + @Override + public boolean showPreferenceFragment(final PreferenceFragmentCompat preferenceFragment) { + return BaseSettingsFragment.showFragment( + preferenceFragment, + requireActivity(), + getClassOfPreferenceFragment().getName()); + } + }); + } + return Optional.empty(); + } + + @Override + public Optional> getShowableSearchablePreferenceDialog( + final Preference preference, + final Optional target) { + if (isRouteRecalculationDistancePreference(preference)) { + return Optional.of(getPreferenceDialogForRouteRecalculationDistancePreference(preference, target)); + } + if (isGoodsRestrictionsPreference(preference)) { + return Optional.of(getPreferenceDialogForGoodsRestrictionsPreference(preference, target)); + } + return Optional.empty(); + } + + private boolean isRouteRecalculationDistancePreference(final Preference preference) { + return settings.ROUTE_RECALCULATION_DISTANCE.getId().equals(preference.getKey()); + } + + private static boolean isGoodsRestrictionsPreference(final Preference preference) { + return GOODS_RESTRICTIONS_PREFERENCE.equals(preference.getKey()); + } + + private ShowableSearchablePreferenceDialog getPreferenceDialogForRouteRecalculationDistancePreference( + final Preference preference, + final Optional target) { + return new ShowableSearchablePreferenceDialog<>( + RecalculateRouteInDeviationBottomSheet.createInstance( + preference, + target, + false, + getSelectedAppMode())) { + + @Override + protected void show(final RecalculateRouteInDeviationBottomSheet recalculateRouteInDeviationBottomSheet) { + recalculateRouteInDeviationBottomSheet.show(getFragmentManager()); + } + }; + } + + private ShowableSearchablePreferenceDialog getPreferenceDialogForGoodsRestrictionsPreference( + final Preference preference, + final Optional target) { + return new ShowableSearchablePreferenceDialog<>( + GoodsRestrictionsBottomSheet.createInstance( + target, + preference, + getSelectedAppMode(), + false, + getGoodsRestrictionPreference().getModeValue(getSelectedAppMode()))) { + + @Override + protected void show(final GoodsRestrictionsBottomSheet goodsRestrictionsBottomSheet) { + goodsRestrictionsBottomSheet.show(getFragmentManager()); + } + }; + } + @Override public void onDisplayPreferenceDialog(Preference preference) { String prefId = preference.getKey(); ApplicationMode appMode = getSelectedAppMode(); FragmentManager manager = getFragmentManager(); - if (settings.ROUTE_RECALCULATION_DISTANCE.getId().equals(prefId)) { - if (manager != null) { - RecalculateRouteInDeviationBottomSheet.showInstance(manager, prefId, this, false, getSelectedAppMode()); - } + if (isRouteRecalculationDistancePreference(preference)) { + this + .getPreferenceDialogForRouteRecalculationDistancePreference(preference, Optional.of(this)) + .show(); } else if (!reliefFactorParameters.isEmpty() && prefId.equals(ROUTING_PREFERENCE_PREFIX + USE_HEIGHT_OBSTACLES)) { if (manager != null) { ElevationDateBottomSheet.showInstance(manager, appMode, this, false); @@ -622,8 +725,11 @@ private void showSeekbarSettingsDialog(Activity activity, ApplicationMode mode) builder.show(); } - private static void setupAngleSlider(float[] angleValue, View sliderView, boolean nightMode, - int activeColor) { + private static void setupAngleSlider(float[] angleValue, + View sliderView, + boolean nightMode, + int activeColor) { + Slider angleBar = sliderView.findViewById(R.id.angle_slider); TextView angleTv = sliderView.findViewById(R.id.angle_text); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/SelectCopyAppModeBottomSheetFactory.java b/OsmAnd/src/net/osmand/plus/settings/fragments/SelectCopyAppModeBottomSheetFactory.java new file mode 100644 index 00000000000..3be0911ef1d --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/SelectCopyAppModeBottomSheetFactory.java @@ -0,0 +1,26 @@ +package net.osmand.plus.settings.fragments; + +import androidx.fragment.app.Fragment; + +import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; + +import java.util.Optional; + +public class SelectCopyAppModeBottomSheetFactory { + + public static ShowableSearchablePreferenceDialog createSelectCopyAppModeBottomSheet( + final Optional target, + final BaseSettingsFragment baseSettingsFragment) { + return new ShowableSearchablePreferenceDialog<>( + SelectCopyAppModeBottomSheet.createInstance( + target.orElse(null), + baseSettingsFragment.getSelectedAppMode())) { + + @Override + protected void show(final SelectCopyAppModeBottomSheet selectCopyAppModeBottomSheet) { + selectCopyAppModeBottomSheet.show(baseSettingsFragment.getFragmentManager()); + } + }; + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/SettingsScreenType.java b/OsmAnd/src/net/osmand/plus/settings/fragments/SettingsScreenType.java index 757ef1bebed..003ff4da2e9 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/SettingsScreenType.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/SettingsScreenType.java @@ -1,5 +1,7 @@ package net.osmand.plus.settings.fragments; +import androidx.fragment.app.Fragment; + import net.osmand.plus.R; import net.osmand.plus.keyevent.fragments.MainExternalInputDevicesFragment; import net.osmand.plus.plugins.accessibility.AccessibilitySettingsFragment; @@ -18,47 +20,49 @@ public enum SettingsScreenType { - MAIN_SETTINGS(MainSettingsFragment.class.getName(), false, null, R.xml.settings_main_screen, R.layout.global_preference_toolbar), - GLOBAL_SETTINGS(GlobalSettingsFragment.class.getName(), false, null, R.xml.global_settings, R.layout.global_preference_toolbar), - CONFIGURE_PROFILE(ConfigureProfileFragment.class.getName(), true, null, R.xml.configure_profile, R.layout.profile_preference_toolbar_with_switch), - PROXY_SETTINGS(ProxySettingsFragment.class.getName(), false, null, R.xml.proxy_preferences, R.layout.global_preferences_toolbar_with_switch), - SEND_UUID(SendUniqueIdentifiersFragment.class.getName(), false, null, R.xml.send_uuid_preferences, R.layout.global_preference_toolbar), - GENERAL_PROFILE(GeneralProfileSettingsFragment.class.getName(), true, ApplyQueryType.BOTTOM_SHEET, R.xml.general_profile_settings, R.layout.profile_preference_toolbar), - NAVIGATION(NavigationFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.navigation_settings_new, R.layout.profile_preference_toolbar), - COORDINATES_FORMAT(CoordinatesFormatFragment.class.getName(), true, ApplyQueryType.BOTTOM_SHEET, R.xml.coordinates_format, R.layout.profile_preference_toolbar), - ROUTE_PARAMETERS(RouteParametersFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.route_parameters, R.layout.profile_preference_toolbar), - SCREEN_ALERTS(ScreenAlertsFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.screen_alerts, R.layout.profile_preference_toolbar_with_switch), - VOICE_ANNOUNCES(VoiceAnnouncesFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.voice_announces, R.layout.profile_preference_toolbar_with_switch), - VEHICLE_PARAMETERS(VehicleParametersFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.vehicle_parameters, R.layout.profile_preference_toolbar), - MAP_DURING_NAVIGATION(MapDuringNavigationFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.map_during_navigation, R.layout.profile_preference_toolbar), - TURN_SCREEN_ON(TurnScreenOnFragment.class.getName(), true, ApplyQueryType.BOTTOM_SHEET, R.xml.turn_screen_on, R.layout.profile_preference_toolbar), - DATA_STORAGE(DataStorageFragment.class.getName(), false, null, R.xml.data_storage, R.layout.global_preference_toolbar), - DIALOGS_AND_NOTIFICATIONS_SETTINGS(DialogsAndNotificationsSettingsFragment.class.getName(), false, null, R.xml.dialogs_and_notifications_preferences, R.layout.global_preference_toolbar), - HISTORY_SETTINGS(HistorySettingsFragment.class.getName(), false, null, R.xml.history_preferences, R.layout.global_preference_toolbar), - PROFILE_APPEARANCE(ProfileAppearanceFragment.TAG, true, null, R.xml.profile_appearance_screen, R.layout.profile_preference_toolbar), - OPEN_STREET_MAP_EDITING(OsmEditingFragment.class.getName(), false, null, R.xml.osm_editing, R.layout.global_preference_toolbar), - MULTIMEDIA_NOTES(MultimediaNotesFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.multimedia_notes, R.layout.profile_preference_toolbar), - MONITORING_SETTINGS(MonitoringSettingsFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.monitoring_settings, R.layout.profile_preference_toolbar), - LIVE_MONITORING(LiveMonitoringFragment.class.getName(), false, ApplyQueryType.SNACK_BAR, R.xml.live_monitoring, R.layout.global_preferences_toolbar_with_switch), - ACCESSIBILITY_SETTINGS(AccessibilitySettingsFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.accessibility_settings, R.layout.profile_preference_toolbar), - DEVELOPMENT_SETTINGS(DevelopmentSettingsFragment.class.getName(), false, null, R.xml.development_settings, R.layout.global_preference_toolbar), - SIMULATION_NAVIGATION(SimulationNavigationSettingFragment.class.getName(), true, ApplyQueryType.NONE, R.xml.simulation_navigation_setting, R.layout.profile_preference_toolbar_with_switch), - ANT_PLUS_SETTINGS(ExternalDevicesListFragment.class.getName(), false, null, R.xml.antplus_settings, R.layout.global_preference_toolbar), - VEHICLE_METRICS_SETTINGS(OBDDevicesListFragment.class.getName(), false, null, R.xml.antplus_settings, R.layout.global_preference_toolbar), - VEHICLE_CONNECTED_METRICS_SETTINGS(OBDMainFragment.class.getName(), false, null, R.xml.antplus_settings, R.layout.global_preference_toolbar), - WEATHER_SETTINGS(WeatherSettingsFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.weather_settings, R.layout.profile_preference_toolbar), - EXTERNAL_SETTINGS_WRITE_TO_TRACK_SETTINGS(ExternalSettingsWriteToTrackSettingsFragment.class.getName(), true, ApplyQueryType.BOTTOM_SHEET, R.xml.external_sensors_write_to_track_settings, R.layout.profile_preference_toolbar), - DANGEROUS_GOODS(DangerousGoodsFragment.class.getName(), true, ApplyQueryType.NONE, R.xml.dangerous_goods_parameters, R.layout.global_preference_toolbar), - EXTERNAL_INPUT_DEVICE(MainExternalInputDevicesFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.external_input_device_settings, R.layout.profile_preference_toolbar_with_switch); + MAIN_SETTINGS(MainSettingsFragment.class, false, null, R.xml.settings_main_screen, R.layout.global_preference_toolbar), + GLOBAL_SETTINGS(GlobalSettingsFragment.class, false, null, R.xml.global_settings, R.layout.global_preference_toolbar), + CONFIGURE_PROFILE(ConfigureProfileFragment.class, true, null, R.xml.configure_profile, R.layout.profile_preference_toolbar_with_switch), + PROXY_SETTINGS(ProxySettingsFragment.class, false, null, R.xml.proxy_preferences, R.layout.global_preferences_toolbar_with_switch), + SEND_UUID(SendUniqueIdentifiersFragment.class, false, null, R.xml.send_uuid_preferences, R.layout.global_preference_toolbar), + GENERAL_PROFILE(GeneralProfileSettingsFragment.class, true, ApplyQueryType.BOTTOM_SHEET, R.xml.general_profile_settings, R.layout.profile_preference_toolbar), + NAVIGATION(NavigationFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.navigation_settings_new, R.layout.profile_preference_toolbar), + COORDINATES_FORMAT(CoordinatesFormatFragment.class, true, ApplyQueryType.BOTTOM_SHEET, R.xml.coordinates_format, R.layout.profile_preference_toolbar), + ROUTE_PARAMETERS(RouteParametersFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.route_parameters, R.layout.profile_preference_toolbar), + SCREEN_ALERTS(ScreenAlertsFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.screen_alerts, R.layout.profile_preference_toolbar_with_switch), + VOICE_ANNOUNCES(VoiceAnnouncesFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.voice_announces, R.layout.profile_preference_toolbar_with_switch), + VEHICLE_PARAMETERS(VehicleParametersFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.vehicle_parameters, R.layout.profile_preference_toolbar), + MAP_DURING_NAVIGATION(MapDuringNavigationFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.map_during_navigation, R.layout.profile_preference_toolbar), + TURN_SCREEN_ON(TurnScreenOnFragment.class, true, ApplyQueryType.BOTTOM_SHEET, R.xml.turn_screen_on, R.layout.profile_preference_toolbar), + DATA_STORAGE(DataStorageFragment.class, false, null, R.xml.data_storage, R.layout.global_preference_toolbar), + DIALOGS_AND_NOTIFICATIONS_SETTINGS(DialogsAndNotificationsSettingsFragment.class, false, null, R.xml.dialogs_and_notifications_preferences, R.layout.global_preference_toolbar), + HISTORY_SETTINGS(HistorySettingsFragment.class, false, null, R.xml.history_preferences, R.layout.global_preference_toolbar), + PROFILE_APPEARANCE(ProfileAppearanceFragment.class, true, null, R.xml.profile_appearance_screen, R.layout.profile_preference_toolbar), + OPEN_STREET_MAP_EDITING(OsmEditingFragment.class, false, null, R.xml.osm_editing, R.layout.global_preference_toolbar), + MULTIMEDIA_NOTES(MultimediaNotesFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.multimedia_notes, R.layout.profile_preference_toolbar), + MONITORING_SETTINGS(MonitoringSettingsFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.monitoring_settings, R.layout.profile_preference_toolbar), + LIVE_MONITORING(LiveMonitoringFragment.class, false, ApplyQueryType.SNACK_BAR, R.xml.live_monitoring, R.layout.global_preferences_toolbar_with_switch), + ACCESSIBILITY_SETTINGS(AccessibilitySettingsFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.accessibility_settings, R.layout.profile_preference_toolbar), + DEVELOPMENT_SETTINGS(DevelopmentSettingsFragment.class, false, null, R.xml.development_settings, R.layout.global_preference_toolbar), + SIMULATION_NAVIGATION(SimulationNavigationSettingFragment.class, true, ApplyQueryType.NONE, R.xml.simulation_navigation_setting, R.layout.profile_preference_toolbar_with_switch), + ANT_PLUS_SETTINGS(ExternalDevicesListFragment.class, false, null, R.xml.antplus_settings, R.layout.global_preference_toolbar), + VEHICLE_METRICS_SETTINGS(OBDDevicesListFragment.class, false, null, R.xml.antplus_settings, R.layout.global_preference_toolbar), + VEHICLE_CONNECTED_METRICS_SETTINGS(OBDMainFragment.class, false, null, R.xml.antplus_settings, R.layout.global_preference_toolbar), + WEATHER_SETTINGS(WeatherSettingsFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.weather_settings, R.layout.profile_preference_toolbar), + EXTERNAL_SETTINGS_WRITE_TO_TRACK_SETTINGS(ExternalSettingsWriteToTrackSettingsFragment.class, true, ApplyQueryType.BOTTOM_SHEET, R.xml.external_sensors_write_to_track_settings, R.layout.profile_preference_toolbar), + DANGEROUS_GOODS(DangerousGoodsFragment.class, true, ApplyQueryType.NONE, R.xml.dangerous_goods_parameters, R.layout.global_preference_toolbar), + EXTERNAL_INPUT_DEVICE(MainExternalInputDevicesFragment.class, true, ApplyQueryType.SNACK_BAR, R.xml.external_input_device_settings, R.layout.profile_preference_toolbar_with_switch); + public final Class fragmentClass; public final String fragmentName; public final boolean profileDependent; public final ApplyQueryType applyQueryType; public final int preferencesResId; public final int toolbarResId; - SettingsScreenType(String fragmentName, boolean profileDependent, ApplyQueryType applyQueryType, int preferencesResId, int toolbarResId) { - this.fragmentName = fragmentName; + SettingsScreenType(Class fragmentClass, boolean profileDependent, ApplyQueryType applyQueryType, int preferencesResId, int toolbarResId) { + this.fragmentClass = fragmentClass; + this.fragmentName = fragmentClass.getName(); this.profileDependent = profileDependent; this.applyQueryType = applyQueryType; this.preferencesResId = preferencesResId; diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/TurnScreenOnFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/TurnScreenOnFragment.java index f87abd4aec9..2a0cd89a3d6 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/TurnScreenOnFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/TurnScreenOnFragment.java @@ -1,8 +1,11 @@ package net.osmand.plus.settings.fragments; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; + import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; @@ -11,10 +14,14 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.bottomsheets.ScreenTimeoutBottomSheet; import net.osmand.plus.settings.bottomsheets.WakeTimeBottomSheet; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.SwitchPreferenceEx; -public class TurnScreenOnFragment extends BaseSettingsFragment { +import java.util.Optional; + +public class TurnScreenOnFragment extends BaseSettingsFragment implements ShowableSearchablePreferenceDialogProvider { public static final String TAG = TurnScreenOnFragment.class.getSimpleName(); @@ -45,17 +52,35 @@ protected void onBindPreferenceViewHolder(@NonNull Preference preference, @NonNu } @Override - public void onDisplayPreferenceDialog(Preference preference) { + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + return settings.TURN_SCREEN_ON_TIME_INT.getId().equals(preference.getKey()) ? + Optional.of( + new ShowableSearchablePreferenceDialog<>( + WakeTimeBottomSheet.createInstance( + preference, + target, + false, + getSelectedAppMode(), + getApplyQueryType(), + isProfileDependent())) { + @Override + protected void show(final WakeTimeBottomSheet wakeTimeBottomSheet) { + wakeTimeBottomSheet.show(getFragmentManager()); + } + }) : + Optional.empty(); + } + + @Override + public void onDisplayPreferenceDialog(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return; + } FragmentManager fragmentManager = getFragmentManager(); - ApplicationMode appMode = getSelectedAppMode(); String prefId = preference.getKey(); if (settings.USE_SYSTEM_SCREEN_TIMEOUT.getId().equals(prefId)) { if (fragmentManager != null) { - ScreenTimeoutBottomSheet.showInstance(fragmentManager, prefId, this, false, appMode, getApplyQueryType(), isProfileDependent()); - } - } else if (settings.TURN_SCREEN_ON_TIME_INT.getId().equals(prefId)) { - if (fragmentManager != null) { - WakeTimeBottomSheet.showInstance(fragmentManager, prefId, this, false, appMode, getApplyQueryType(), isProfileDependent()); + ScreenTimeoutBottomSheet.showInstance(fragmentManager, prefId, this, false, getSelectedAppMode(), getApplyQueryType(), isProfileDependent()); } } else { super.onDisplayPreferenceDialog(preference); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java index 8899113a368..f2aaba2d1ee 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleParametersFragment.java @@ -2,7 +2,16 @@ import static net.osmand.plus.settings.backend.OsmandSettings.ROUTING_PREFERENCE_PREFIX; import static net.osmand.plus.settings.fragments.RouteParametersFragment.createRoutingParameterPref; -import static net.osmand.router.GeneralRouter.*; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; +import static net.osmand.router.GeneralRouter.DEFAULT_SPEED; +import static net.osmand.router.GeneralRouter.MAX_AXLE_LOAD; +import static net.osmand.router.GeneralRouter.MOTOR_TYPE; +import static net.osmand.router.GeneralRouter.RoutingParameter; +import static net.osmand.router.GeneralRouter.VEHICLE_HEIGHT; +import static net.osmand.router.GeneralRouter.VEHICLE_LENGTH; +import static net.osmand.router.GeneralRouter.VEHICLE_WEIGHT; +import static net.osmand.router.GeneralRouter.VEHICLE_WIDTH; +import static net.osmand.router.GeneralRouter.WEIGHT_RATING; import android.content.Context; import android.graphics.drawable.Drawable; @@ -10,6 +19,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; @@ -27,6 +37,9 @@ import net.osmand.plus.settings.bottomsheets.SimpleSingleSelectionBottomSheet; import net.osmand.plus.settings.bottomsheets.VehicleParametersBottomSheet; import net.osmand.plus.settings.enums.DrivingRegion; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.settings.preferences.SizePreference; import net.osmand.plus.settings.vehiclesize.SizeType; @@ -36,11 +49,13 @@ import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.OsmAndFormatter; import net.osmand.router.GeneralRouter; +import net.osmand.router.GeneralRouter.GeneralRouterProfile; import net.osmand.shared.settings.enums.MetricsConstants; import java.util.Map; +import java.util.Optional; -public class VehicleParametersFragment extends BaseSettingsFragment { +public class VehicleParametersFragment extends BaseSettingsFragment implements ShowableSearchablePreferenceDialogProvider { public static final String TAG = VehicleParametersFragment.class.getSimpleName(); @@ -69,7 +84,7 @@ protected void setupPreferences() { showOtherCategory(parameters, routerProfile); } } else { - setupCategoryPref(R.string.shared_string_other); + setupCategoryPref(R.string.shared_string_other, "VehicleParametersFragment.other"); setupDefaultSpeedPref(); } } @@ -80,7 +95,7 @@ private void showOtherCategory(@NonNull Map parameters || routerProfile != GeneralRouterProfile.PUBLIC_TRANSPORT; if (shouldShowOtherCategory) { addDividerPref(); - setupCategoryPref(R.string.shared_string_other); + setupCategoryPref(R.string.shared_string_other, "VehicleParametersFragment.other2"); } setupRoutingParameterPref(parameters.get(MAX_AXLE_LOAD)); setupRoutingParameterPref(parameters.get(WEIGHT_RATING)); @@ -99,7 +114,7 @@ private void showFuelCategory(@NonNull Map parameters, boolean showCategory = showFuelTankCapacity || motorTypeParameter != null; if (showCategory) { addDividerPref(); - setupCategoryPref(R.string.poi_filter_fuel); + setupCategoryPref(R.string.poi_filter_fuel, "VehicleParametersFragment.poi_filter_fuel"); } setupRoutingParameterPref(motorTypeParameter); if (showFuelTankCapacity) { @@ -108,8 +123,8 @@ private void showFuelCategory(@NonNull Map parameters, } private void showDimensionsCategory(@NonNull Map parameters, - @Nullable GeneralRouterProfile routerProfile, - @Nullable String derivedProfile) { + @Nullable GeneralRouterProfile routerProfile, + @Nullable String derivedProfile) { if (routerProfile == null) { return; } @@ -118,7 +133,7 @@ private void showDimensionsCategory(@NonNull Map param RoutingParameter width = parameters.get(VEHICLE_WIDTH); RoutingParameter length = parameters.get(VEHICLE_LENGTH); if (height != null || weight != null || width != null || length != null) { - setupCategoryPref(R.string.shared_strings_dimensions); + setupCategoryPref(R.string.shared_strings_dimensions, "VehicleParametersFragment.dimensions"); } setupVehiclePropertyPref(height, routerProfile, derivedProfile); @@ -127,10 +142,11 @@ private void showDimensionsCategory(@NonNull Map param setupVehiclePropertyPref(length, routerProfile, derivedProfile); } - private void setupCategoryPref(int titleId) { + private void setupCategoryPref(int titleId, String key) { PreferenceCategory preferenceCategory = new PreferenceCategory(requireContext()); preferenceCategory.setTitle(titleId); preferenceCategory.setLayoutResource(R.layout.preference_category_with_descr); + preferenceCategory.setKey(key); PreferenceScreen screen = getPreferenceScreen(); screen.addPreference(preferenceCategory); @@ -149,8 +165,8 @@ private void setupFuelTankCapacityPref() { } private void setupVehiclePropertyPref(@Nullable RoutingParameter parameter, - @Nullable GeneralRouterProfile profile, - @Nullable String derivedProfile) { + @Nullable GeneralRouterProfile profile, + @Nullable String derivedProfile) { if (parameter == null || profile == null) { return; } @@ -247,43 +263,89 @@ public boolean onPreferenceClick(Preference preference) { } return true; } else if (settings.FUEL_TANK_CAPACITY.getId().equals(key)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - FuelTankCapacityBottomSheet.showInstance(fragmentManager, preference.getKey(), - this, false, getSelectedAppMode()); - } + onDisplayPreferenceDialog(preference); + return true; } return super.onPreferenceClick(preference); } @Override - public void onDisplayPreferenceDialog(Preference preference) { - if (preference instanceof SizePreference) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - VehicleParametersBottomSheet.showInstance(fragmentManager, preference.getKey(), - this, false, getSelectedAppMode()); - } - } else if (MOTOR_TYPE_PREF_ID.equals(preference.getKey())) { - FragmentManager manager = getFragmentManager(); - if (manager != null) { - ListPreferenceEx pref = (ListPreferenceEx) preference; - SimpleSingleSelectionBottomSheet.showInstance(manager, this, preference.getKey(), - pref.getTitle().toString(), pref.getDescription(), - getSelectedAppMode(), false, pref.getEntries(), - pref.getEntryValues(), pref.getValueIndex()); - } - } else { + public void onDisplayPreferenceDialog(final Preference preference) { + final boolean shown = showDialogForPreference(preference, this); + if (!shown) { super.onDisplayPreferenceDialog(preference); } } + @Override + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (preference instanceof SizePreference) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + VehicleParametersBottomSheet.createInstance( + preference, + target, + false, + getSelectedAppMode())) { + + @Override + protected void show(final VehicleParametersBottomSheet vehicleParametersBottomSheet) { + VehicleParametersFragment.this.show(vehicleParametersBottomSheet); + } + }); + } + if (MOTOR_TYPE_PREF_ID.equals(preference.getKey())) { + final ListPreferenceEx pref = (ListPreferenceEx) preference; + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + SimpleSingleSelectionBottomSheet.createInstance( + target, + preference, + pref.getTitle().toString(), + pref.getDescription(), + getSelectedAppMode(), + false, + pref.getEntries(), + pref.getEntryValues(), + pref.getValueIndex())) { + + @Override + protected void show(final SimpleSingleSelectionBottomSheet simpleSingleSelectionBottomSheet) { + VehicleParametersFragment.this.show(simpleSingleSelectionBottomSheet); + } + }); + } + if (settings.FUEL_TANK_CAPACITY.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + FuelTankCapacityBottomSheet.createInstance( + preference, + target, + false, + getSelectedAppMode())) { + + @Override + protected void show(final FuelTankCapacityBottomSheet fuelTankCapacityBottomSheet) { + VehicleParametersFragment.this.show(fuelTankCapacityBottomSheet); + } + }); + } + return Optional.empty(); + } + + private void show(final SearchablePreferenceDialog dialog) { + final FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager != null) { + dialog.show(fragmentManager); + } + } + @Override public void onApplyPreferenceChange(String prefId, boolean applyToAllProfiles, Object newValue) { super.onApplyPreferenceChange(prefId, applyToAllProfiles, newValue); if (MOTOR_TYPE_PREF_ID.equals(prefId)) { - if (getActivity() instanceof MapActivity) { - ((MapActivity) getActivity()).getMapRouteInfoMenu().updateMenu(); + if (getActivity() instanceof MapActivity mapActivity) { + mapActivity.getMapRouteInfoMenu().updateMenu(); } } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleSpeedHelper.java b/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleSpeedHelper.java index 8afae1dd278..2e527d15d13 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleSpeedHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/VehicleSpeedHelper.java @@ -29,11 +29,11 @@ import net.osmand.plus.routing.RouteService; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.shared.settings.enums.SpeedConstants; import net.osmand.plus.settings.enums.SpeedSliderType; import net.osmand.plus.utils.OsmAndFormatter; import net.osmand.plus.utils.UiUtilities; import net.osmand.router.GeneralRouter; +import net.osmand.shared.settings.enums.SpeedConstants; public class VehicleSpeedHelper { @@ -51,6 +51,10 @@ public VehicleSpeedHelper(@NonNull OsmandApplication app, @NonNull ApplicationMo this.nightMode = !settings.isLightContentForMode(mode); } + public String getSearchableInfo() { + return app.getString(R.string.default_speed_dialog_msg); + } + public void showSeekbarSettingsDialog(@NonNull Activity activity) { GeneralRouter router = app.getRouter(mode); RouteService routeService = mode.getRouteService(); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/ConfigureMenuRootFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/ConfigureMenuRootFragment.java index edaeb60b0e6..e9f4db90590 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/ConfigureMenuRootFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/ConfigureMenuRootFragment.java @@ -23,6 +23,7 @@ import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; @@ -30,7 +31,7 @@ import java.util.Arrays; import java.util.List; -public class ConfigureMenuRootFragment extends BaseOsmAndFragment { +public class ConfigureMenuRootFragment extends BaseOsmAndFragment implements SearchablePreferenceDialog { public static final String TAG = ConfigureMenuRootFragment.class.getName(); @@ -95,7 +96,7 @@ private void setupToolbar(@NonNull View view) { private void setupRecyclerView(@NonNull View view) { List items = new ArrayList<>(); - items.add(getString(R.string.ui_customization_description, getString(R.string.prefs_plugins))); + items.add(getDescription()); items.addAll(Arrays.asList(ScreenType.values())); FragmentActivity activity = requireActivity(); @@ -111,6 +112,12 @@ private void setupRecyclerView(@NonNull View view) { recyclerView.setAdapter(adapter); } + private String getDescription() { + return getString( + R.string.ui_customization_description, + getString(R.string.prefs_plugins)); + } + @Override public void onResume() { super.onResume(); @@ -137,16 +144,26 @@ public void onSaveInstanceState(@NonNull Bundle outState) { outState.putString(APP_MODE_KEY, appMode.getStringKey()); } - public static void showInstance(@NonNull FragmentManager manager, @NonNull ApplicationMode appMode, @Nullable Fragment target) { - if (AndroidUtils.isFragmentCanBeAdded(manager, TAG)) { - ConfigureMenuRootFragment fragment = new ConfigureMenuRootFragment(); - fragment.appMode = appMode; - fragment.setTargetFragment(target, 0); + public static ConfigureMenuRootFragment createInstance(final @NonNull ApplicationMode appMode, + final @Nullable Fragment target) { + final ConfigureMenuRootFragment fragment = new ConfigureMenuRootFragment(); + fragment.appMode = appMode; + fragment.setTargetFragment(target, 0); + return fragment; + } - manager.beginTransaction() - .replace(R.id.fragmentContainer, fragment, TAG) + @Override + public void show(final FragmentManager fragmentManager) { + if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { + fragmentManager.beginTransaction() + .replace(R.id.fragmentContainer, this, TAG) .addToBackStack(null) .commitAllowingStateLoss(); } } + + @Override + public String getSearchableInfo() { + return getDescription(); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/RearrangeItemsHelper.java b/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/RearrangeItemsHelper.java index e89300543eb..11b95877f12 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/RearrangeItemsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/configureitems/RearrangeItemsHelper.java @@ -342,7 +342,9 @@ public List getItemsForRearrangeAdapter(@Nullable List hiddenIte public void showCopyAppModeDialog() { FragmentManager manager = fragment.getFragmentManager(); if (manager != null) { - SelectCopyAppModeBottomSheet.showInstance(manager, fragment, appMode); + SelectCopyAppModeBottomSheet + .createInstance(fragment, appMode) + .show(manager); } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/profileappearance/ProfileAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/profileappearance/ProfileAppearanceFragment.java index 3f18d5de162..75ac49a4910 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/profileappearance/ProfileAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/profileappearance/ProfileAppearanceFragment.java @@ -1,6 +1,7 @@ package net.osmand.plus.settings.fragments.profileappearance; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SETTINGS_ID; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import static net.osmand.plus.utils.ColorUtilities.getListBgColorId; import android.annotation.SuppressLint; @@ -38,9 +39,12 @@ import net.osmand.plus.card.icon.IconsPaletteCard; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.routepreparationmenu.cards.BaseCard; +import net.osmand.plus.settings.bottomsheets.CustomizableSingleSelectionBottomSheet; import net.osmand.plus.settings.fragments.BaseSettingsFragment; -import net.osmand.plus.settings.fragments.ProfileOptionsDialogController; import net.osmand.plus.settings.fragments.SettingsScreenType; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.UiUtilities; @@ -51,7 +55,9 @@ import org.apache.commons.logging.Log; -public class ProfileAppearanceFragment extends BaseSettingsFragment implements IProfileAppearanceScreen { +import java.util.Optional; + +public class ProfileAppearanceFragment extends BaseSettingsFragment implements IProfileAppearanceScreen, ShowableSearchablePreferenceDialogProvider { private static final Log LOG = PlatformUtil.getLog(ProfileAppearanceFragment.class); @@ -225,21 +231,54 @@ public void afterTextChanged(Editable s) { } @Override - public boolean onPreferenceClick(Preference preference) { - MapActivity mapActivity = getMapActivity(); - if (mapActivity != null) { - ProfileOptionsDialogController optionsDialogController = screenController.getProfileOptionController(); - if (settings.VIEW_ANGLE_VISIBILITY.getId().equals(preference.getKey())) { - optionsDialogController.showDialog(mapActivity, app.getString(R.string.view_angle), - app.getString(R.string.view_angle_description), settings.VIEW_ANGLE_VISIBILITY); - } else if (settings.LOCATION_RADIUS_VISIBILITY.getId().equals(preference.getKey())) { - optionsDialogController.showDialog(mapActivity, app.getString(R.string.location_radius), - app.getString(R.string.location_radius_description), settings.LOCATION_RADIUS_VISIBILITY); - } + public boolean onPreferenceClick(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return true; } return super.onPreferenceClick(preference); } + @Override + public Optional> getShowableSearchablePreferenceDialog(final Preference preference, final Optional target) { + if (settings.VIEW_ANGLE_VISIBILITY.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + screenController + .getProfileOptionController() + .createDialog( + app.getString(R.string.view_angle), + app.getString(R.string.view_angle_description), + settings.VIEW_ANGLE_VISIBILITY)) { + + @Override + protected void show(final CustomizableSingleSelectionBottomSheet customizableSingleSelectionBottomSheet) { + ProfileAppearanceFragment.this.show(customizableSingleSelectionBottomSheet); + } + }); + } + if (settings.LOCATION_RADIUS_VISIBILITY.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + screenController + .getProfileOptionController() + .createDialog( + app.getString(R.string.location_radius), + app.getString(R.string.location_radius_description), + settings.LOCATION_RADIUS_VISIBILITY)) { + + @Override + protected void show(final CustomizableSingleSelectionBottomSheet customizableSingleSelectionBottomSheet) { + ProfileAppearanceFragment.this.show(customizableSingleSelectionBottomSheet); + } + }); + } + return Optional.empty(); + } + + private void show(final SearchablePreferenceDialog searchablePreferenceDialog) { + searchablePreferenceDialog.show(requireActivity().getSupportFragmentManager()); + } + private void bindCard(@NonNull PreferenceViewHolder holder, @NonNull BaseCard card) { ViewGroup container = (ViewGroup) holder.itemView; container.removeAllViews(); @@ -378,7 +417,7 @@ public void onDestroy() { } public static boolean showInstance(@NonNull FragmentActivity activity, - @Nullable String appModeKey, boolean imported) { + @Nullable String appModeKey, boolean imported) { FragmentManager fragmentManager = activity.getSupportFragmentManager(); if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { Fragment fragment = Fragment.instantiate(activity, TAG); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/FragmentFactory.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/FragmentFactory.java new file mode 100644 index 00000000000..016ee4ff379 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/FragmentFactory.java @@ -0,0 +1,66 @@ +package net.osmand.plus.settings.fragments.search; + +import static net.osmand.plus.settings.fragments.search.SettingsSearchConfigurer.setConfigureSettingsSearch; + +import android.content.Context; + +import androidx.fragment.app.Fragment; + +import net.osmand.plus.settings.fragments.BaseSettingsFragment; + +import java.util.Optional; + +import de.KnollFrank.lib.settingssearch.PreferenceWithHost; +import de.KnollFrank.lib.settingssearch.fragment.DefaultFragmentFactory; +import de.KnollFrank.lib.settingssearch.fragment.InstantiateAndInitializeFragment; + +class FragmentFactory implements de.KnollFrank.lib.settingssearch.fragment.FragmentFactory { + + @Override + public T instantiate(final Class fragmentClass, + final Optional src, + final Context context, + final InstantiateAndInitializeFragment instantiateAndInitializeFragment) { + final T fragment = _instantiate(fragmentClass, src, context, instantiateAndInitializeFragment); + setConfigureSettingsSearch(fragment, true); + return fragment; + } + + private static T _instantiate(final Class fragmentClass, + final Optional src, + final Context context, + final InstantiateAndInitializeFragment instantiateAndInitializeFragment) { + return FragmentFactory + .instantiate(src, context, fragmentClass) + .orElseGet(() -> createDefaultInstance(fragmentClass, src, context, instantiateAndInitializeFragment)); + } + + private static Optional instantiate(final Optional src, + final Context context, + final Class classOfT) { + return src + .filter(preferenceWithHost -> preferenceWithHost.host() instanceof PreferenceFragmentHandlerProvider) + .flatMap(preferenceWithHost -> ((PreferenceFragmentHandlerProvider) preferenceWithHost.host()).getPreferenceFragmentHandler(preferenceWithHost.preference())) + .map(preferenceFragmentHandler -> preferenceFragmentHandler.createPreferenceFragment(context, Optional.empty())) + .flatMap( + preferenceFragment -> + classOfT.isAssignableFrom(preferenceFragment.getClass()) ? + Optional.of((T) preferenceFragment) : + Optional.empty()); + } + + private static T createDefaultInstance(final Class fragmentClass, + final Optional src, + final Context context, + final InstantiateAndInitializeFragment instantiateAndInitializeFragment) { + final T fragment = new DefaultFragmentFactory().instantiate(fragmentClass, src, context, instantiateAndInitializeFragment); + src.ifPresent(_src -> configureFragment(fragment, _src)); + return fragment; + } + + private static void configureFragment(final Fragment fragment, final PreferenceWithHost src) { + if (src.host() instanceof final BaseSettingsFragment baseSettingsFragment) { + fragment.setArguments(baseSettingsFragment.buildArguments()); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/IncludePreferenceInSearchResultsPredicate.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/IncludePreferenceInSearchResultsPredicate.java new file mode 100644 index 00000000000..59e33407068 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/IncludePreferenceInSearchResultsPredicate.java @@ -0,0 +1,43 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.plus.plugins.OsmandPlugin; +import net.osmand.plus.plugins.PluginsHelper; +import net.osmand.plus.settings.fragments.SettingsScreenType; + +import java.util.stream.Stream; + +import javax.annotation.Nullable; + +import de.KnollFrank.lib.settingssearch.db.preference.pojo.SearchablePreference; + +class IncludePreferenceInSearchResultsPredicate implements de.KnollFrank.lib.settingssearch.provider.IncludePreferenceInSearchResultsPredicate { + + @Override + public boolean includePreferenceInSearchResults(final SearchablePreference preference) { + return !isPreferenceConnectedToAnyInactivePlugin(preference); + } + + private static boolean isPreferenceConnectedToAnyInactivePlugin(final SearchablePreference preference) { + return IncludePreferenceInSearchResultsPredicate + .getInactivePlugins() + .anyMatch(inactivePlugin -> isPreferenceConnectedToPlugin(preference, inactivePlugin)); + } + + private static Stream getInactivePlugins() { + return PluginsHelper + .getAvailablePlugins() + .stream() + .filter(plugin -> !plugin.isActive()); + } + + private static boolean isPreferenceConnectedToPlugin(final SearchablePreference preference, + final OsmandPlugin plugin) { + return isPreferenceOnSettingsScreen(preference, plugin.getSettingsScreenType()) || + PreferenceMarker.isPreferenceConnectedToPlugin(preference, plugin.getClass()); + } + + private static boolean isPreferenceOnSettingsScreen(final SearchablePreference preference, + final @Nullable SettingsScreenType settingsScreenType) { + return settingsScreenType != null && settingsScreenType.fragmentClass.equals(preference.getHost()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceDialogAndSearchableInfoProvider.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceDialogAndSearchableInfoProvider.java new file mode 100644 index 00000000000..46d6c5240ee --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceDialogAndSearchableInfoProvider.java @@ -0,0 +1,23 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import java.util.Optional; + +import de.KnollFrank.lib.settingssearch.provider.PreferenceDialogAndSearchableInfoByPreferenceDialogProvider; + +class PreferenceDialogAndSearchableInfoProvider implements de.KnollFrank.lib.settingssearch.provider.PreferenceDialogAndSearchableInfoProvider { + + @Override + public Optional> getPreferenceDialogAndSearchableInfoByPreferenceDialogProvider( + final Preference preference, + final PreferenceFragmentCompat hostOfPreference) { + // FK-TODO: handle more preference dialogs which shall be searchable + return hostOfPreference instanceof final ShowableSearchablePreferenceDialogProvider showableSearchablePreferenceDialogProvider ? + showableSearchablePreferenceDialogProvider + .getShowableSearchablePreferenceDialog(preference, Optional.empty()) + .map(ShowableSearchablePreferenceDialog::asPreferenceDialogAndSearchableInfoByPreferenceDialogProvider) : + Optional.empty(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceDialogs.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceDialogs.java new file mode 100644 index 00000000000..ea1f9e5432e --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceDialogs.java @@ -0,0 +1,23 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.fragment.app.Fragment; +import androidx.preference.Preference; + +import java.util.Optional; + +public class PreferenceDialogs { + + public static boolean showDialogForPreference( + final Preference preference, + final T preferenceDialogProviderAndTarget) { + final Optional> preferenceDialog = + preferenceDialogProviderAndTarget.getShowableSearchablePreferenceDialog( + preference, + Optional.of(preferenceDialogProviderAndTarget)); + if (preferenceDialog.isPresent()) { + preferenceDialog.get().show(); + return true; + } + return false; + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentConnected2PreferenceProvider.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentConnected2PreferenceProvider.java new file mode 100644 index 00000000000..5e001c87040 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentConnected2PreferenceProvider.java @@ -0,0 +1,18 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import java.util.Optional; + +class PreferenceFragmentConnected2PreferenceProvider implements de.KnollFrank.lib.settingssearch.provider.PreferenceFragmentConnected2PreferenceProvider { + + @Override + public Optional> getPreferenceFragmentConnected2Preference(Preference preference, final PreferenceFragmentCompat hostOfPreference) { + return hostOfPreference instanceof final PreferenceFragmentHandlerProvider preferenceFragmentHandlerProvider ? + preferenceFragmentHandlerProvider + .getPreferenceFragmentHandler(preference) + .map(PreferenceFragmentHandler::getClassOfPreferenceFragment) : + Optional.empty(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentHandler.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentHandler.java new file mode 100644 index 00000000000..34cd455ca01 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentHandler.java @@ -0,0 +1,17 @@ +package net.osmand.plus.settings.fragments.search; + +import android.content.Context; + +import androidx.fragment.app.Fragment; +import androidx.preference.PreferenceFragmentCompat; + +import java.util.Optional; + +public interface PreferenceFragmentHandler { + + Class getClassOfPreferenceFragment(); + + PreferenceFragmentCompat createPreferenceFragment(Context context, Optional target); + + boolean showPreferenceFragment(PreferenceFragmentCompat preferenceFragment); +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentHandlerProvider.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentHandlerProvider.java new file mode 100644 index 00000000000..afad920e8e5 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceFragmentHandlerProvider.java @@ -0,0 +1,11 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.preference.Preference; + +import java.util.Optional; + +@FunctionalInterface +public interface PreferenceFragmentHandlerProvider { + + Optional getPreferenceFragmentHandler(Preference preference); +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceMarker.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceMarker.java new file mode 100644 index 00000000000..7feaf2bb70d --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceMarker.java @@ -0,0 +1,20 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.preference.Preference; + +import net.osmand.plus.plugins.OsmandPlugin; + +import de.KnollFrank.lib.settingssearch.db.preference.pojo.SearchablePreference; + +public class PreferenceMarker { + + private static final String KEY = "settings.search.connection2plugin"; + + public static void markPreferenceAsConnectedToPlugin(final Preference preference, final Class plugin) { + preference.getExtras().putString(KEY, plugin.getName()); + } + + public static boolean isPreferenceConnectedToPlugin(final SearchablePreference preference, final Class plugin) { + return plugin.getName().equals(preference.getExtras().getString(KEY)); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferencePathDisplayer.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferencePathDisplayer.java new file mode 100644 index 00000000000..e224347ca9c --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferencePathDisplayer.java @@ -0,0 +1,93 @@ +package net.osmand.plus.settings.fragments.search; + +import android.content.Context; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.text.style.TextAppearanceSpan; + +import net.osmand.plus.R; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import de.KnollFrank.lib.settingssearch.PreferencePath; +import de.KnollFrank.lib.settingssearch.db.preference.pojo.SearchablePreference; + +class PreferencePathDisplayer implements de.KnollFrank.lib.settingssearch.results.recyclerview.PreferencePathDisplayer { + + private final Context context; + private final Set applicationModeKeys; + + public PreferencePathDisplayer(final Context context, final Set applicationModeKeys) { + this.context = context; + this.applicationModeKeys = applicationModeKeys; + } + + @Override + public CharSequence display(final PreferencePath preferencePath) { + return TextUtils.concat("Path: ", asString(preferencePath)); + } + + private SpannableString asString(final PreferencePath preferencePath) { + final List titles = getTitles(preferencePath); + highlightApplicationModeAtStartOfLongPreferencePath(preferencePath, titles); + return join(titles, new SpannableString(" > ")); + } + + private static List getTitles(final PreferencePath preferencePath) { + return preferencePath + .preferences() + .stream() + .map(SearchablePreference::getTitle) + .map(title -> title.orElse("?")) + .map(SpannableString::new) + .collect(Collectors.toList()); + } + + private void highlightApplicationModeAtStartOfLongPreferencePath(final PreferencePath preferencePath, final List titles) { + if (isLong(preferencePath) && isApplicationMode(preferencePath.preferences().get(0))) { + highlight(titles.get(0)); + } + } + + private static boolean isLong(final PreferencePath preferencePath) { + return preferencePath.preferences().size() >= 2; + } + + private boolean isApplicationMode(final SearchablePreference preference) { + return preference + .getKey() + .filter(applicationModeKeys::contains) + .isPresent(); + } + + private void highlight(final Spannable spannable) { + spannable.setSpan( + new TextAppearanceSpan(context, R.style.PreferencePathTextAppearance), + 0, + spannable.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + private static SpannableString join(final List strings, final SpannableString delimiter) { + return concat(insertDelimiterBetweenElements(strings, delimiter)); + } + + private static List insertDelimiterBetweenElements(final List elements, final T delimiter) { + return elements + .stream() + .flatMap(t -> Stream.of(t, delimiter)) + .limit(elements.size() * 2L - 1) + .collect(Collectors.toList()); + } + + private static SpannableString concat(final List charSequences) { + final SpannableStringBuilder builder = new SpannableStringBuilder(); + charSequences.forEach(builder::append); + return new SpannableString(builder); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferencePathDisplayerFactory.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferencePathDisplayerFactory.java new file mode 100644 index 00000000000..36bd1527971 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferencePathDisplayerFactory.java @@ -0,0 +1,23 @@ +package net.osmand.plus.settings.fragments.search; + +import android.content.Context; + +import net.osmand.plus.settings.backend.ApplicationMode; + +import java.util.Set; +import java.util.stream.Collectors; + +class PreferencePathDisplayerFactory { + + public static de.KnollFrank.lib.settingssearch.results.recyclerview.PreferencePathDisplayer createPreferencePathDisplayer(final Context context) { + return new PreferencePathDisplayer(context, getApplicationModeKeys()); + } + + public static Set getApplicationModeKeys() { + return ApplicationMode + .allPossibleValues() + .stream() + .map(ApplicationMode::getStringKey) + .collect(Collectors.toSet()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceSearchablePredicate.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceSearchablePredicate.java new file mode 100644 index 00000000000..a728e83e511 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PreferenceSearchablePredicate.java @@ -0,0 +1,27 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import net.osmand.plus.R; + +import java.util.Set; + +class PreferenceSearchablePredicate implements de.KnollFrank.lib.settingssearch.provider.PreferenceSearchablePredicate { + + private static final Set NON_SEARCHABLE_LAYOUT_RESIDS = + Set.of( + R.layout.simple_divider_item, + R.layout.list_item_divider, + R.layout.card_bottom_divider, + R.layout.divider_half_item, + R.layout.divider_half_item_with_background, + R.layout.divider_item_with_background_56, + R.layout.divider, + R.layout.drawer_divider); + + @Override + public boolean isPreferenceSearchable(final Preference preference, final PreferenceFragmentCompat hostOfPreference) { + return !NON_SEARCHABLE_LAYOUT_RESIDS.contains(preference.getLayoutResource()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/PrepareShow.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PrepareShow.java new file mode 100644 index 00000000000..56aa2178278 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/PrepareShow.java @@ -0,0 +1,13 @@ +package net.osmand.plus.settings.fragments.search; + +import static net.osmand.plus.settings.fragments.search.SettingsSearchConfigurer.setConfigureSettingsSearch; + +import androidx.preference.PreferenceFragmentCompat; + +class PrepareShow implements de.KnollFrank.lib.settingssearch.provider.PrepareShow { + + @Override + public void prepareShow(final PreferenceFragmentCompat preferenceFragment) { + setConfigureSettingsSearch(preferenceFragment, false); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchDatabaseStatusHandler.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchDatabaseStatusHandler.java new file mode 100644 index 00000000000..7338b0a2699 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchDatabaseStatusHandler.java @@ -0,0 +1,32 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.plus.plugins.OsmandPlugin; +import net.osmand.plus.plugins.PluginsHelper; + +import java.util.Set; +import java.util.stream.Collectors; + +class SearchDatabaseStatusHandler { + + private final SetStringPreference pluginsCoveredBySettingsSearch; + + public SearchDatabaseStatusHandler(final SetStringPreference pluginsCoveredBySettingsSearch) { + this.pluginsCoveredBySettingsSearch = pluginsCoveredBySettingsSearch; + } + + public boolean isSearchDatabaseUpToDate() { + return pluginsCoveredBySettingsSearch.get().equals(getEnabledPlugins()); + } + + public void setSearchDatabaseUpToDate() { + pluginsCoveredBySettingsSearch.set(getEnabledPlugins()); + } + + private static Set getEnabledPlugins() { + return PluginsHelper + .getEnabledPlugins() + .stream() + .map(OsmandPlugin::getId) + .collect(Collectors.toSet()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchPreferenceFragmentUI.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchPreferenceFragmentUI.java new file mode 100644 index 00000000000..d792216260d --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchPreferenceFragmentUI.java @@ -0,0 +1,70 @@ +package net.osmand.plus.settings.fragments.search; + +import android.view.View; +import android.widget.CheckBox; +import android.widget.SearchView; +import android.widget.TextView; + +import androidx.annotation.LayoutRes; +import androidx.fragment.app.FragmentContainerView; + +import net.osmand.plus.R; + +import de.KnollFrank.lib.settingssearch.search.SearchForQueryAndDisplayResultsCommand; +import de.KnollFrank.lib.settingssearch.search.ui.ProgressContainerUI; + +class SearchPreferenceFragmentUI implements de.KnollFrank.lib.settingssearch.search.ui.SearchPreferenceFragmentUI { + + private final SearchResultsFilter searchResultsFilter; + + public SearchPreferenceFragmentUI(final SearchResultsFilter searchResultsFilter) { + this.searchResultsFilter = searchResultsFilter; + } + + @Override + public @LayoutRes int getRootViewId() { + return R.layout.custom_searchpreference_fragment; + } + + @Override + public SearchView getSearchView(final View rootView) { + return rootView.findViewById(R.id.searchView); + } + + @Override + public FragmentContainerView getSearchResultsFragmentContainerView(final View rootView) { + return rootView.findViewById(R.id.searchResultsFragmentContainerView); + } + + @Override + public ProgressContainerUI getProgressContainerUI(View rootView) { + return new ProgressContainerUI() { + + @Override + public View getRoot() { + return rootView.findViewById(R.id.progressContainerCustom); + } + + @Override + public TextView getProgressText() { + return getRoot().findViewById(de.KnollFrank.lib.settingssearch.R.id.progressText); + } + }; + } + + @Override + public void onSearchReady(final View rootView, final SearchForQueryAndDisplayResultsCommand searchForQueryAndDisplayResultsCommand) { + configureCheckbox( + rootView.findViewById(R.id.search_inside_disabled_profiles), + searchForQueryAndDisplayResultsCommand); + } + + private void configureCheckbox(final CheckBox searchInsideDisabledProfiles, final SearchForQueryAndDisplayResultsCommand searchForQueryAndDisplayResultsCommand) { + searchInsideDisabledProfiles.setChecked(!searchResultsFilter.shallRemoveSearchResultsConnectedToDisabledProfiles()); + searchInsideDisabledProfiles.setOnCheckedChangeListener( + (_checkBox, _searchInsideDisabledProfiles) -> { + searchResultsFilter.setRemoveSearchResultsConnectedToDisabledProfiles(!_searchInsideDisabledProfiles); + searchForQueryAndDisplayResultsCommand.searchForQueryAndDisplayResults(); + }); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFilter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFilter.java new file mode 100644 index 00000000000..993cdac388f --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFilter.java @@ -0,0 +1,49 @@ +package net.osmand.plus.settings.fragments.search; + +import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.PreferencePath; +import de.KnollFrank.lib.settingssearch.db.preference.pojo.SearchablePreference; + +class SearchResultsFilter implements de.KnollFrank.lib.settingssearch.results.SearchResultsFilter { + + private final Predicate isDisabledProfile; + private boolean removeSearchResultsConnectedToDisabledProfiles = true; + + SearchResultsFilter(final Predicate isDisabledProfile) { + this.isDisabledProfile = isDisabledProfile; + } + + @Override + public boolean includePreferenceInSearchResults(final SearchablePreference preference) { + return removeSearchResultsConnectedToDisabledProfiles ? + !isConnectedToDisabledProfile(preference) : + true; + } + + public boolean shallRemoveSearchResultsConnectedToDisabledProfiles() { + return removeSearchResultsConnectedToDisabledProfiles; + } + + public void setRemoveSearchResultsConnectedToDisabledProfiles(final boolean removeSearchResultsConnectedToDisabledProfiles) { + this.removeSearchResultsConnectedToDisabledProfiles = removeSearchResultsConnectedToDisabledProfiles; + } + + private Collection removeSearchResultsConnectedToDisabledProfiles(final Collection searchResults) { + return searchResults + .stream() + .filter(searchResult -> !isConnectedToDisabledProfile(searchResult)) + .collect(Collectors.toList()); + } + + private boolean isConnectedToDisabledProfile(final SearchablePreference searchablePreference) { + return startsWithDisabledProfile(searchablePreference.getPreferencePath()); + } + + private boolean startsWithDisabledProfile(final PreferencePath preferencePath) { + final var startOfPreferencePath = preferencePath.preferences().get(0); + return isDisabledProfile.test(startOfPreferencePath.getKey().orElseThrow()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFilterFactory.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFilterFactory.java new file mode 100644 index 00000000000..6c8d092af13 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFilterFactory.java @@ -0,0 +1,38 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.plus.settings.backend.preferences.OsmandPreference; + +import java.util.Collection; +import java.util.function.Predicate; + +class SearchResultsFilterFactory { + + public static SearchResultsFilter createSearchResultsFilter(final Collection allProfiles, + final OsmandPreference enabledProfiles) { + return new SearchResultsFilter(isDisabledProfile(allProfiles, enabledProfiles)); + } + + private static Predicate isDisabledProfile(final Collection allProfiles, + final OsmandPreference enabledProfiles) { + return new Predicate<>() { + + @Override + public boolean test(final String key) { + return isDisabledProfile(key); + } + + private boolean isDisabledProfile(final String key) { + return isProfile(key) && isDisabled(key); + } + + private boolean isProfile(final String key) { + return allProfiles.contains(key); + } + + private boolean isDisabled(final String profile) { + return !enabledProfiles.get().contains(profile); + } + }; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFragmentUI.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFragmentUI.java new file mode 100644 index 00000000000..2890cc21eec --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsFragmentUI.java @@ -0,0 +1,27 @@ +package net.osmand.plus.settings.fragments.search; + +import android.view.View; + +import androidx.annotation.IdRes; +import androidx.annotation.LayoutRes; +import androidx.annotation.VisibleForTesting; +import androidx.recyclerview.widget.RecyclerView; + +import net.osmand.plus.R; + +class SearchResultsFragmentUI implements de.KnollFrank.lib.settingssearch.search.ui.SearchResultsFragmentUI { + + @VisibleForTesting + @IdRes + static final int SEARCH_RESULTS_VIEW_ID = R.id.searchResultsCustom; + + @Override + public @LayoutRes int getRootViewId() { + return R.layout.custom_searchresults_fragment; + } + + @Override + public RecyclerView getSearchResultsView(final View rootView) { + return rootView.findViewById(SEARCH_RESULTS_VIEW_ID); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchableInfoHelper.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchableInfoHelper.java new file mode 100644 index 00000000000..d756aba1f2e --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchableInfoHelper.java @@ -0,0 +1,28 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.plus.profiles.data.ProfileDataObject; +import net.osmand.plus.profiles.data.RoutingDataObject; + +import java.util.List; +import java.util.stream.Collectors; + +public class SearchableInfoHelper { + + public static List getProfileDescriptions(final List profiles) { + return profiles + .stream() + .map(SearchableInfoHelper::getProfileDescription) + .collect(Collectors.toList()); + } + + public static List getProfileNames(final List profilesList) { + return profilesList + .stream() + .map(ProfileDataObject::getName) + .collect(Collectors.toList()); + } + + private static String getProfileDescription(final ProfileDataObject profile) { + return String.format("%s (%s)", profile.getName(), profile.getDescription()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchableInfoProvider.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchableInfoProvider.java new file mode 100644 index 00000000000..a6efca71129 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchableInfoProvider.java @@ -0,0 +1,7 @@ +package net.osmand.plus.settings.fragments.search; + +@FunctionalInterface +public interface SearchableInfoProvider { + + String getSearchableInfo(); +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchablePreferenceDialog.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchablePreferenceDialog.java new file mode 100644 index 00000000000..8a050ca642b --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchablePreferenceDialog.java @@ -0,0 +1,10 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.fragment.app.FragmentManager; + +public interface SearchablePreferenceDialog { + + void show(FragmentManager fragmentManager); + + String getSearchableInfo(); +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SetStringPreference.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SetStringPreference.java new file mode 100644 index 00000000000..15e24c2c8e5 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SetStringPreference.java @@ -0,0 +1,33 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.plus.settings.backend.preferences.ListStringPreference; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +class SetStringPreference { + + private final ListStringPreference listStringPreference; + + public SetStringPreference(final ListStringPreference listStringPreference) { + this.listStringPreference = listStringPreference; + } + + public void set(final Set strings) { + listStringPreference.setStringsList(new ArrayList<>(strings)); + } + + public Set get() { + return new HashSet<>(getList()); + } + + private List getList() { + final List strings = listStringPreference.getStringsList(); + return strings != null ? + strings : + Collections.emptyList(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchButtonHelper.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchButtonHelper.java new file mode 100644 index 00000000000..438d679e605 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchButtonHelper.java @@ -0,0 +1,122 @@ +package net.osmand.plus.settings.fragments.search; + +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.IdRes; +import androidx.fragment.app.FragmentActivity; +import androidx.preference.Preference; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.configmap.ConfigureMapFragment; +import net.osmand.plus.settings.backend.preferences.OsmandPreference; +import net.osmand.plus.settings.fragments.BaseSettingsFragment; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +import de.KnollFrank.lib.settingssearch.client.SearchConfig; +import de.KnollFrank.lib.settingssearch.client.SearchPreferenceFragments; +import de.KnollFrank.lib.settingssearch.client.searchDatabaseConfig.*; +import de.KnollFrank.lib.settingssearch.common.task.AsyncTaskWithProgressUpdateListeners; + +public class SettingsSearchButtonHelper { + + private final BaseSettingsFragment rootSearchPreferenceFragment; + private final @IdRes int fragmentContainerViewId; + private final SearchDatabaseStatusHandler searchDatabaseStatusHandler; + private final Supplier>> createSearchDatabaseTaskSupplier; + private final OsmandPreference availableAppModes; + + public SettingsSearchButtonHelper(final BaseSettingsFragment rootSearchPreferenceFragment, + final @IdRes int fragmentContainerViewId, + final OsmandApplication app, + final Supplier>> createSearchDatabaseTaskSupplier) { + this.rootSearchPreferenceFragment = rootSearchPreferenceFragment; + this.fragmentContainerViewId = fragmentContainerViewId; + this.searchDatabaseStatusHandler = + new SearchDatabaseStatusHandler( + new SetStringPreference( + app.getSettings().PLUGINS_COVERED_BY_SETTINGS_SEARCH)); + this.createSearchDatabaseTaskSupplier = createSearchDatabaseTaskSupplier; + this.availableAppModes = app.getSettings().AVAILABLE_APP_MODES; + } + + public void configureSettingsSearchButton(final ImageView settingsSearchButton) { + onClickShowSearchPreferenceFragment(settingsSearchButton); + settingsSearchButton.setImageDrawable(rootSearchPreferenceFragment.getIcon(R.drawable.searchpreference_ic_search)); + settingsSearchButton.setVisibility(View.VISIBLE); + } + + public static SearchPreferenceFragments createSearchPreferenceFragments( + final Supplier>> createSearchDatabaseTaskSupplier, + final FragmentActivity fragmentActivity, + final @IdRes int fragmentContainerViewId, + final Class rootPreferenceFragment, + final OsmandPreference availableAppModes) { + final SearchResultsFilter searchResultsFilter = + SearchResultsFilterFactory.createSearchResultsFilter( + PreferencePathDisplayerFactory.getApplicationModeKeys(), + availableAppModes); + return SearchPreferenceFragments + .builder( + SearchDatabaseConfig + .builder(rootPreferenceFragment) + .withFragmentFactory(new FragmentFactory()) + .withActivitySearchDatabaseConfigs(createActivitySearchDatabaseConfigs()) + .withPreferenceFragmentConnected2PreferenceProvider(new PreferenceFragmentConnected2PreferenceProvider()) + .withSearchableInfoProvider(SettingsSearchButtonHelper::getSearchableInfo) + .withPreferenceDialogAndSearchableInfoProvider(new PreferenceDialogAndSearchableInfoProvider()) + .withPreferenceSearchablePredicate(new PreferenceSearchablePredicate()) + .build(), + SearchConfig + .builder(fragmentContainerViewId, fragmentActivity) + .withQueryHint("Search Settings") + .withSearchResultsFilter(searchResultsFilter) + .withPreferencePathDisplayer(PreferencePathDisplayerFactory.createPreferencePathDisplayer(fragmentActivity)) + .withSearchPreferenceFragmentUI(new SearchPreferenceFragmentUI(searchResultsFilter)) + .withSearchResultsFragmentUI(new SearchResultsFragmentUI()) + .withPrepareShow(new PrepareShow()) + .withIncludePreferenceInSearchResultsPredicate(new IncludePreferenceInSearchResultsPredicate()) + .build(), + fragmentActivity.getSupportFragmentManager(), + fragmentActivity) + .withCreateSearchDatabaseTaskSupplier(createSearchDatabaseTaskSupplier) + .build(); + } + + private static ActivitySearchDatabaseConfigs createActivitySearchDatabaseConfigs() { + return new ActivitySearchDatabaseConfigs( + Map.of(MapActivity.class, ConfigureMapFragment.PreferenceFragment.class), + Set.of(new FragmentWithPreferenceFragmentConnection<>(ConfigureMapFragment.class, ConfigureMapFragment.PreferenceFragment.class))); + } + + private static Optional getSearchableInfo(final Preference preference) { + return preference instanceof final SearchableInfoProvider searchableInfoProvider ? + Optional.of(searchableInfoProvider.getSearchableInfo()) : + Optional.empty(); + } + + private void onClickShowSearchPreferenceFragment(final ImageView searchPreferenceButton) { + final SearchPreferenceFragments searchPreferenceFragments = + createSearchPreferenceFragments( + createSearchDatabaseTaskSupplier, + rootSearchPreferenceFragment.requireActivity(), + fragmentContainerViewId, + rootSearchPreferenceFragment.getClass(), + availableAppModes); + searchPreferenceButton.setOnClickListener(v -> showSearchPreferenceFragment(searchPreferenceFragments)); + } + + private void showSearchPreferenceFragment(final SearchPreferenceFragments searchPreferenceFragments) { + if (!searchDatabaseStatusHandler.isSearchDatabaseUpToDate()) { + searchPreferenceFragments.rebuildSearchDatabase(); + searchDatabaseStatusHandler.setSearchDatabaseUpToDate(); + } + searchPreferenceFragments.showSearchPreferenceFragment(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchConfigurer.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchConfigurer.java new file mode 100644 index 00000000000..be352f53508 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchConfigurer.java @@ -0,0 +1,22 @@ +package net.osmand.plus.settings.fragments.search; + +import android.os.Bundle; + +import androidx.fragment.app.Fragment; + +import net.osmand.plus.settings.fragments.BaseSettingsFragment; + +class SettingsSearchConfigurer { + + public static void setConfigureSettingsSearch(final Fragment fragment, final boolean configureSettingsSearch) { + final Bundle arguments = getBundle(fragment); + arguments.putBoolean(BaseSettingsFragment.CONFIGURE_SETTINGS_SEARCH, configureSettingsSearch); + fragment.setArguments(arguments); + } + + private static Bundle getBundle(final Fragment fragment) { + return fragment.getArguments() != null ? + fragment.getArguments() : + new Bundle(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchInitializer.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchInitializer.java new file mode 100644 index 00000000000..a6986e42bf0 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchInitializer.java @@ -0,0 +1,35 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.StateChangedListener; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.settings.backend.preferences.OsmandPreference; + +import java.util.List; + +import de.KnollFrank.lib.settingssearch.search.SearchDatabaseDirectoryIO; + +public class SettingsSearchInitializer { + + private final OsmandApplication app; + private final StateChangedListener rebuildSearchDatabaseListener = s -> rebuildSearchDatabase(); + + public SettingsSearchInitializer(final OsmandApplication app) { + this.app = app; + } + + public void rebuildSearchDatabaseOnAppProfileChanged() { + for (var appProfilePreference : getAppProfilePreferences()) { + appProfilePreference.addListener(rebuildSearchDatabaseListener); + } + } + + private List> getAppProfilePreferences() { + return List.of( + app.getSettings().CUSTOM_APP_MODES_KEYS, + app.getSettings().USER_PROFILE_NAME); + } + + private void rebuildSearchDatabase() { + new SearchDatabaseDirectoryIO(app).removeSearchDatabaseDirectories4AllLocales(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/ShowableSearchablePreferenceDialog.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/ShowableSearchablePreferenceDialog.java new file mode 100644 index 00000000000..f12f56e2a36 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/ShowableSearchablePreferenceDialog.java @@ -0,0 +1,26 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.fragment.app.Fragment; + +import de.KnollFrank.lib.settingssearch.provider.PreferenceDialogAndSearchableInfoByPreferenceDialogProvider; + +public abstract class ShowableSearchablePreferenceDialog { + + public final T searchablePreferenceDialog; + + public ShowableSearchablePreferenceDialog(final T searchablePreferenceDialog) { + this.searchablePreferenceDialog = searchablePreferenceDialog; + } + + public void show() { + show(searchablePreferenceDialog); + } + + public PreferenceDialogAndSearchableInfoByPreferenceDialogProvider asPreferenceDialogAndSearchableInfoByPreferenceDialogProvider() { + return new PreferenceDialogAndSearchableInfoByPreferenceDialogProvider<>( + searchablePreferenceDialog, + SearchablePreferenceDialog::getSearchableInfo); + } + + protected abstract void show(final T searchablePreferenceDialog); +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/ShowableSearchablePreferenceDialogProvider.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/ShowableSearchablePreferenceDialogProvider.java new file mode 100644 index 00000000000..7b6fcbde9c6 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/ShowableSearchablePreferenceDialogProvider.java @@ -0,0 +1,12 @@ +package net.osmand.plus.settings.fragments.search; + +import androidx.fragment.app.Fragment; +import androidx.preference.Preference; + +import java.util.Optional; + +@FunctionalInterface +public interface ShowableSearchablePreferenceDialogProvider { + + Optional> getShowableSearchablePreferenceDialog(Preference preference, Optional target); +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceAnnouncesFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceAnnouncesFragment.java index 0e834b84c42..1df1db0943f 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceAnnouncesFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceAnnouncesFragment.java @@ -1,5 +1,6 @@ package net.osmand.plus.settings.fragments.voice; +import static net.osmand.plus.settings.fragments.search.PreferenceDialogs.showDialogForPreference; import static net.osmand.plus.utils.UiUtilities.CompoundButtonType.TOOLBAR; import android.graphics.drawable.ColorDrawable; @@ -12,6 +13,7 @@ import androidx.annotation.NonNull; import androidx.appcompat.widget.SwitchCompat; import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; @@ -25,16 +27,21 @@ import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.bottomsheets.AnnouncementTimeBottomSheet; import net.osmand.plus.settings.bottomsheets.SpeedLimitBottomSheet; -import net.osmand.shared.settings.enums.SpeedConstants; import net.osmand.plus.settings.fragments.ApplyQueryType; import net.osmand.plus.settings.fragments.BaseSettingsFragment; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialog; +import net.osmand.plus.settings.fragments.search.ShowableSearchablePreferenceDialogProvider; import net.osmand.plus.settings.preferences.ListPreferenceEx; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.OsmAndFormatter; import net.osmand.plus.utils.UiUtilities; +import net.osmand.shared.settings.enums.SpeedConstants; -public class VoiceAnnouncesFragment extends BaseSettingsFragment { +import java.util.Optional; + +public class VoiceAnnouncesFragment extends BaseSettingsFragment implements ShowableSearchablePreferenceDialogProvider { public static final String TAG = VoiceAnnouncesFragment.class.getSimpleName(); @@ -247,17 +254,53 @@ public boolean onPreferenceClick(Preference preference) { } @Override - public void onDisplayPreferenceDialog(Preference preference) { - String prefId = preference.getKey(); - if (settings.ARRIVAL_DISTANCE_FACTOR.getId().equals(prefId)) { - FragmentManager fragmentManager = getFragmentManager(); - if (fragmentManager != null) { - AnnouncementTimeBottomSheet.showInstance(fragmentManager, preference.getKey(), this, getSelectedAppMode(), false); - } - } else if (settings.VOICE_PROVIDER.getId().equals(prefId)) { - VoiceLanguageBottomSheetFragment.showInstance(requireActivity().getSupportFragmentManager(), this, getSelectedAppMode(), false); - } else { - super.onDisplayPreferenceDialog(preference); + public void onDisplayPreferenceDialog(final Preference preference) { + if (showDialogForPreference(preference, this)) { + return; + } + super.onDisplayPreferenceDialog(preference); + } + + @Override + public Optional> getShowableSearchablePreferenceDialog( + final Preference preference, + final Optional target) { + if (settings.ARRIVAL_DISTANCE_FACTOR.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + AnnouncementTimeBottomSheet.createInstance( + preference, + target, + getSelectedAppMode(), + false)) { + + @Override + protected void show(final AnnouncementTimeBottomSheet announcementTimeBottomSheet) { + VoiceAnnouncesFragment.this.show(announcementTimeBottomSheet); + } + }); + } + if (settings.VOICE_PROVIDER.getId().equals(preference.getKey())) { + return Optional.of( + new ShowableSearchablePreferenceDialog<>( + VoiceLanguageBottomSheetFragment.createInstance( + target, + getSelectedAppMode(), + false)) { + + @Override + protected void show(final VoiceLanguageBottomSheetFragment voiceLanguageBottomSheetFragment) { + voiceLanguageBottomSheetFragment.show(requireActivity().getSupportFragmentManager()); + } + }); + } + return Optional.empty(); + } + + private void show(final SearchablePreferenceDialog dialog) { + final FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager != null) { + dialog.show(fragmentManager); } } @@ -275,5 +318,4 @@ private void setupSpeakCamerasPref() { SwitchPreferenceCompat showCameras = findPreference(settings.SPEAK_SPEED_CAMERA.getId()); showCameras.setVisible(!settings.SPEED_CAMERAS_UNINSTALLED.get()); } - } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceLanguageBottomSheetFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceLanguageBottomSheetFragment.java index 295a74ff12e..90da752af8a 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceLanguageBottomSheetFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/voice/VoiceLanguageBottomSheetFragment.java @@ -30,7 +30,9 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet; +import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheetInitializer; import net.osmand.plus.settings.fragments.OnPreferenceChanged; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.settings.fragments.voice.VoiceItemsAdapter.VoiceItemsListener; import net.osmand.plus.track.fragments.TrackSelectSegmentBottomSheet; import net.osmand.plus.utils.AndroidUtils; @@ -40,8 +42,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; -public class VoiceLanguageBottomSheetFragment extends BasePreferenceBottomSheet implements DownloadEvents, VoiceItemsListener { +public class VoiceLanguageBottomSheetFragment extends BasePreferenceBottomSheet implements DownloadEvents, VoiceItemsListener, SearchablePreferenceDialog { private static final String TAG = TrackSelectSegmentBottomSheet.class.getSimpleName(); @@ -256,15 +261,53 @@ private void addVoiceItem(@NonNull List items, @NonNull VoiceType voi } } - public static void showInstance(@NonNull FragmentManager manager, @Nullable Fragment target, - @Nullable ApplicationMode appMode, boolean usedOnMap) { - if (AndroidUtils.isFragmentCanBeAdded(manager, TAG)) { - VoiceLanguageBottomSheetFragment fragment = new VoiceLanguageBottomSheetFragment(); - fragment.setRetainInstance(true); - fragment.setAppMode(appMode); - fragment.setUsedOnMap(usedOnMap); - fragment.setTargetFragment(target, 0); - fragment.show(manager, TAG); + public static VoiceLanguageBottomSheetFragment createInstance(final Optional target, + final @Nullable ApplicationMode appMode, + final boolean usedOnMap) { + final VoiceLanguageBottomSheetFragment bottomSheet = new VoiceLanguageBottomSheetFragment(); + bottomSheet.setRetainInstance(true); + return BasePreferenceBottomSheetInitializer + .initialize(bottomSheet) + .with(Optional.empty(), appMode, usedOnMap, target); + + } + + @Override + public void show(final FragmentManager fragmentManager) { + if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { + show(fragmentManager, TAG); } } + + @Override + public String getSearchableInfo() { + return Stream + .concat( + getConstantSearchableInfo(), + getSearchableInfoOfItems()) + .collect(Collectors.joining(", ")); + } + + private Stream getConstantSearchableInfo() { + return Stream + .of( + R.string.language_description, + VoiceType.TTS.titleRes, + VoiceType.TTS.descriptionRes, + VoiceType.RECORDED.titleRes, + VoiceType.RECORDED.descriptionRes) + .map(this::getString); + } + + private Stream getSearchableInfoOfItems() { + return Stream + .concat( + ttsItems.stream(), + recordedItems.stream()) + .map(indexItem -> + indexItem.getVisibleName( + app, + app.getRegions(), + false)); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/preferences/EditTextPreferenceEx.java b/OsmAnd/src/net/osmand/plus/settings/preferences/EditTextPreferenceEx.java index 3677c73452b..0b87269f559 100644 --- a/OsmAnd/src/net/osmand/plus/settings/preferences/EditTextPreferenceEx.java +++ b/OsmAnd/src/net/osmand/plus/settings/preferences/EditTextPreferenceEx.java @@ -5,7 +5,14 @@ import androidx.preference.EditTextPreference; -public class EditTextPreferenceEx extends EditTextPreference { +import net.osmand.plus.settings.fragments.search.SearchableInfoProvider; + +import java.util.Optional; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.common.Optionals; + +public class EditTextPreferenceEx extends EditTextPreference implements SearchableInfoProvider { private String description; @@ -36,4 +43,13 @@ public void setDescription(String description) { public void setDescription(int descriptionResId) { setDescription(getContext().getString(descriptionResId)); } + + @Override + public String getSearchableInfo() { + return Optionals + .streamOfPresentElements( + Optional.ofNullable(getText()), + Optional.ofNullable(getDescription())) + .collect(Collectors.joining(", ")); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/preferences/ListPreferenceEx.java b/OsmAnd/src/net/osmand/plus/settings/preferences/ListPreferenceEx.java index aeb9c74ebde..601cbc7d782 100644 --- a/OsmAnd/src/net/osmand/plus/settings/preferences/ListPreferenceEx.java +++ b/OsmAnd/src/net/osmand/plus/settings/preferences/ListPreferenceEx.java @@ -7,10 +7,19 @@ import androidx.preference.DialogPreference; import androidx.preference.PreferenceDataStore; +import com.google.common.collect.ImmutableList; + import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmAndPreferencesDataStore; +import net.osmand.plus.settings.fragments.search.SearchableInfoProvider; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.common.Optionals; -public class ListPreferenceEx extends DialogPreference { +public class ListPreferenceEx extends DialogPreference implements SearchableInfoProvider { private String[] entries; private Object[] entryValues; @@ -148,4 +157,26 @@ private void persistValue(Object value) { ((OsmAndPreferencesDataStore) dataStore).putValue(getKey(), value); } } + + @Override + public String getSearchableInfo() { + return String.join( + ", ", + concat( + Optional.ofNullable(getDialogTitle()), + Optional.ofNullable(getDescription()), + Optional.ofNullable(getEntries()))); + } + + static List concat(final Optional dialogTitle, + final Optional description, + final Optional entries) { + return ImmutableList + .builder() + .addAll(Optionals + .streamOfPresentElements(dialogTitle, description) + .collect(Collectors.toList())) + .addAll(Optionals.asList(entries)) + .build(); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/preferences/MultiSelectBooleanPreference.java b/OsmAnd/src/net/osmand/plus/settings/preferences/MultiSelectBooleanPreference.java index 1f69cd09891..74d4f1c2b59 100644 --- a/OsmAnd/src/net/osmand/plus/settings/preferences/MultiSelectBooleanPreference.java +++ b/OsmAnd/src/net/osmand/plus/settings/preferences/MultiSelectBooleanPreference.java @@ -1,5 +1,7 @@ package net.osmand.plus.settings.preferences; +import static net.osmand.plus.settings.preferences.ListPreferenceEx.concat; + import android.content.Context; import android.util.AttributeSet; @@ -7,11 +9,13 @@ import androidx.preference.PreferenceDataStore; import net.osmand.plus.settings.backend.OsmAndPreferencesDataStore; +import net.osmand.plus.settings.fragments.search.SearchableInfoProvider; import java.util.HashSet; +import java.util.Optional; import java.util.Set; -public class MultiSelectBooleanPreference extends MultiSelectListPreference { +public class MultiSelectBooleanPreference extends MultiSelectListPreference implements SearchableInfoProvider { private String description; @@ -109,4 +113,14 @@ public Set getPersistedBooleanPrefsIds(Set defaultReturnValue) { return enabledPrefs; } + + @Override + public String getSearchableInfo() { + return String.join( + ", ", + concat( + Optional.ofNullable(getDialogTitle()), + Optional.ofNullable(getDescription()), + Optional.ofNullable(getEntries()))); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/preferences/SizePreference.java b/OsmAnd/src/net/osmand/plus/settings/preferences/SizePreference.java index d9289b9332f..cf59811d7fc 100644 --- a/OsmAnd/src/net/osmand/plus/settings/preferences/SizePreference.java +++ b/OsmAnd/src/net/osmand/plus/settings/preferences/SizePreference.java @@ -6,6 +6,7 @@ import androidx.preference.DialogPreference; import net.osmand.plus.R; +import net.osmand.plus.settings.fragments.search.SearchableInfoProvider; import net.osmand.plus.settings.vehiclesize.SizeType; import net.osmand.plus.settings.vehiclesize.VehicleSizes; import net.osmand.plus.settings.vehiclesize.containers.Metric; @@ -13,8 +14,12 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; +import java.util.Optional; +import java.util.stream.Collectors; -public class SizePreference extends DialogPreference { +import de.KnollFrank.lib.settingssearch.common.Optionals; + +public class SizePreference extends DialogPreference implements SearchableInfoProvider { private SizeType sizeType; private Metric metric; @@ -78,7 +83,16 @@ private String getString(int stringId) { return getContext().getString(stringId); } - public String getValue () { + public String getValue() { return getPersistedString(defaultValue); } + + @Override + public String getSearchableInfo() { + return Optionals + .streamOfPresentElements( + Optional.ofNullable(getDialogTitle()), + Optional.ofNullable(getSummary())) + .collect(Collectors.joining(", ")); + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/preferences/SwitchPreferenceEx.java b/OsmAnd/src/net/osmand/plus/settings/preferences/SwitchPreferenceEx.java index 75902f4778c..78fe0875820 100644 --- a/OsmAnd/src/net/osmand/plus/settings/preferences/SwitchPreferenceEx.java +++ b/OsmAnd/src/net/osmand/plus/settings/preferences/SwitchPreferenceEx.java @@ -5,7 +5,14 @@ import androidx.preference.SwitchPreferenceCompat; -public class SwitchPreferenceEx extends SwitchPreferenceCompat { +import net.osmand.plus.settings.fragments.search.SearchableInfoProvider; + +import java.util.Optional; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.common.Optionals; + +public class SwitchPreferenceEx extends SwitchPreferenceCompat implements SearchableInfoProvider { private String description; @@ -43,4 +50,14 @@ protected void onClick() { getPreferenceManager().showDialog(this); } } + + @Override + public String getSearchableInfo() { + return Optionals + .streamOfPresentElements( + Optional.ofNullable(getSummaryOff()), + Optional.ofNullable(getSummaryOn()), + Optional.ofNullable(getDescription())) + .collect(Collectors.joining(", ")); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/simulation/DashSimulateFragment.java b/OsmAnd/src/net/osmand/plus/simulation/DashSimulateFragment.java index 40266069fe2..565c1dc316a 100644 --- a/OsmAnd/src/net/osmand/plus/simulation/DashSimulateFragment.java +++ b/OsmAnd/src/net/osmand/plus/simulation/DashSimulateFragment.java @@ -48,7 +48,9 @@ public View initView(LayoutInflater inflater, @Nullable ViewGroup container, @Nu item.setOnClickListener(v -> { FragmentActivity activity = getActivity(); if (activity != null) { - SimulateLocationFragment.showInstance(activity.getSupportFragmentManager(), null, true); + SimulateLocationFragment + .createInstance(null, true) + .show(activity.getSupportFragmentManager()); dashboard.hideDashboard(); } }); diff --git a/OsmAnd/src/net/osmand/plus/simulation/SimulateLocationFragment.java b/OsmAnd/src/net/osmand/plus/simulation/SimulateLocationFragment.java index 07f1d7579b4..acddf5f3d0b 100644 --- a/OsmAnd/src/net/osmand/plus/simulation/SimulateLocationFragment.java +++ b/OsmAnd/src/net/osmand/plus/simulation/SimulateLocationFragment.java @@ -18,20 +18,22 @@ import androidx.fragment.app.FragmentManager; import net.osmand.IndexConstants; -import net.osmand.shared.gpx.GpxFile; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.track.GpxDialogs; import net.osmand.plus.track.SelectTrackTabsFragment; import net.osmand.plus.track.fragments.TrackMenuFragment; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; +import net.osmand.plus.widgets.TextViewEx; import net.osmand.plus.widgets.alert.AlertDialogData; import net.osmand.plus.widgets.alert.CustomAlert; +import net.osmand.shared.gpx.GpxFile; -public class SimulateLocationFragment extends BaseOsmAndFragment implements SelectTrackTabsFragment.GpxFileSelectionListener { +public class SimulateLocationFragment extends BaseOsmAndFragment implements SelectTrackTabsFragment.GpxFileSelectionListener, SearchablePreferenceDialog { public static final String TAG = SimulateLocationFragment.class.getSimpleName(); @@ -233,7 +235,7 @@ private void updateCard() { TextView startTextview = startItem.findViewById(R.id.title); startTextview.setText(simulation.isRouteAnimating() ? R.string.shared_string_control_stop : R.string.shared_string_control_start); - startIcon.setImageDrawable(app.getUIUtilities().getPaintedIcon(simulation.isRouteAnimating() ? R.drawable.ic_action_stop : R.drawable.ic_play_dark, + startIcon.setImageDrawable(app.getUIUtilities().getPaintedIcon(simulation.isRouteAnimating() ? R.drawable.ic_action_stop : R.drawable.ic_play_dark, gpxFile != null ? ColorUtilities.getActiveIconColor(app, nightMode) : ColorUtilities.getSecondaryIconColor(app, nightMode))); } @@ -267,16 +269,11 @@ private String getSpeedString(int speed) { return speed == 1 ? getString(R.string.shared_string_original) : "x" + speed; } - public static void showInstance(@NonNull FragmentManager manager, @Nullable GpxFile gpxFile, boolean usedOnMap) { - if (AndroidUtils.isFragmentCanBeAdded(manager, TAG)) { - SimulateLocationFragment fragment = new SimulateLocationFragment(); - fragment.setGpxFile(gpxFile); - fragment.usedOnMap = usedOnMap; - manager.beginTransaction() - .replace(R.id.fragmentContainer, fragment, TAG) - .addToBackStack(TAG) - .commitAllowingStateLoss(); - } + public static SimulateLocationFragment createInstance(final @Nullable GpxFile gpxFile, final boolean usedOnMap) { + final SimulateLocationFragment fragment = new SimulateLocationFragment(); + fragment.setGpxFile(gpxFile); + fragment.usedOnMap = usedOnMap; + return fragment; } @Override @@ -284,4 +281,29 @@ public void onSelectGpxFile(@NonNull GpxFile gpxFile) { this.gpxFile = gpxFile; updateCard(); } + + @Override + public void show(final FragmentManager fragmentManager) { + if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { + fragmentManager + .beginTransaction() + .replace(R.id.fragmentContainer, this, TAG) + .addToBackStack(TAG) + .commitAllowingStateLoss(); + } + } + + @Override + public String getSearchableInfo() { + return String.join( + ", ", + requireView().findViewById(R.id.title).getText(), + getTitle(trackItem), + getTitle(speedItem), + getTitle(startItem)); + } + + private CharSequence getTitle(final LinearLayout item) { + return item.findViewById(R.id.title).getText(); + } } diff --git a/OsmAnd/src/net/osmand/plus/track/fragments/TrackMenuFragment.java b/OsmAnd/src/net/osmand/plus/track/fragments/TrackMenuFragment.java index 1634b450a16..e368a59882a 100644 --- a/OsmAnd/src/net/osmand/plus/track/fragments/TrackMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/fragments/TrackMenuFragment.java @@ -64,7 +64,6 @@ import net.osmand.IndexConstants; import net.osmand.Location; import net.osmand.PlatformUtil; -import net.osmand.plus.shared.SharedUtil; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.QuadRect; @@ -99,6 +98,7 @@ import net.osmand.plus.routepreparationmenu.cards.MapBaseCard; import net.osmand.plus.search.ShowQuickSearchMode; import net.osmand.plus.search.dialogs.QuickSearchDialogFragment; +import net.osmand.plus.shared.SharedUtil; import net.osmand.plus.simulation.SimulateLocationFragment; import net.osmand.plus.track.GpxSelectionParams; import net.osmand.plus.track.cards.AuthorCard; @@ -1259,7 +1259,9 @@ public void onCardButtonPressed(@NonNull BaseCard card, int buttonIndex) { showTrackAltitudeDialog(-1); } } else if (buttonIndex == SIMULATE_POSITION_BUTTON_INDEX) { - SimulateLocationFragment.showInstance(fragmentManager, gpxFile, true); + SimulateLocationFragment + .createInstance(gpxFile, true) + .show(fragmentManager); } else if (buttonIndex == DELETE_BUTTON_INDEX) { String fileName = Algorithms.getFileWithoutDirs(gpxFile.getPath()); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonFragment.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonFragment.java index 383cb2de33a..6b333cdc831 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonFragment.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonFragment.java @@ -147,9 +147,9 @@ private void showOptionsMenu(@NonNull View view) { .setOnClickListener(v -> { FragmentActivity activity = getActivity(); if (activity != null) { - ApplicationMode appMode = settings.getApplicationMode(); - FragmentManager manager = activity.getSupportFragmentManager(); - SelectCopyAppModeBottomSheet.showInstance(manager, this, appMode); + SelectCopyAppModeBottomSheet + .createInstance(this, settings.getApplicationMode()) + .show(activity.getSupportFragmentManager()); } }).create()); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java index 5332e64b069..68f1ad14d04 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/buttons/DefaultMapButtonsFragment.java @@ -101,9 +101,9 @@ protected void showOptionsMenu(@NonNull View view) { .setOnClickListener(v -> { FragmentActivity activity = getActivity(); if (activity != null) { - ApplicationMode appMode = settings.getApplicationMode(); - FragmentManager manager = activity.getSupportFragmentManager(); - SelectCopyAppModeBottomSheet.showInstance(manager, this, appMode); + SelectCopyAppModeBottomSheet + .createInstance(this, settings.getApplicationMode()) + .show(activity.getSupportFragmentManager()); } }).create()); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/ConfigureScreenFragment.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/ConfigureScreenFragment.java index 380f010ab29..e8547f41796 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/ConfigureScreenFragment.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/ConfigureScreenFragment.java @@ -30,6 +30,7 @@ import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.bottomsheets.ConfirmationBottomSheet.ConfirmationDialogListener; +import net.osmand.plus.settings.fragments.search.SearchablePreferenceDialog; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.views.layers.MapInfoLayer; @@ -49,7 +50,7 @@ import java.util.List; public class ConfigureScreenFragment extends BaseOsmAndFragment implements QuickActionUpdatesListener, - WidgetsRegistryListener, ConfirmationDialogListener, CopyAppModePrefsListener { + WidgetsRegistryListener, ConfirmationDialogListener, CopyAppModePrefsListener, SearchablePreferenceDialog { public static final String TAG = ConfigureScreenFragment.class.getSimpleName(); @@ -376,14 +377,30 @@ private void updateFragment() { } } - public static void showInstance(@NonNull FragmentActivity activity) { - FragmentManager fragmentManager = activity.getSupportFragmentManager(); + public static ConfigureScreenFragment createInstance() { + return new ConfigureScreenFragment(); + } + + @Override + public void show(final FragmentManager fragmentManager) { if (AndroidUtils.isFragmentCanBeAdded(fragmentManager, TAG)) { - ConfigureScreenFragment fragment = new ConfigureScreenFragment(); - fragmentManager.beginTransaction() - .add(R.id.fragmentContainer, fragment, TAG) + fragmentManager + .beginTransaction() + .add(R.id.fragmentContainer, this, TAG) .addToBackStack(TAG) .commitAllowingStateLoss(); } } + + @Override + public String getSearchableInfo() { + // FK-TODO: add more searchable info + return String.join( + ", ", + getString(R.string.configure_screen_widgets_descr), + widgetsCard.getSearchableInfo(), + buttonsCard.getSearchableInfo(), + otherCard.getSearchableInfo(), + actionsCard.getSearchableInfo()); + } } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureActionsCard.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureActionsCard.java index 98790574387..2601385c406 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureActionsCard.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureActionsCard.java @@ -7,6 +7,7 @@ import android.widget.TextView; import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.fragment.app.Fragment; @@ -53,8 +54,9 @@ private void setupCopyButton() { button.setOnClickListener(v -> { FragmentManager manager = target.getFragmentManager(); if (manager != null) { - ApplicationMode appMode = settings.getApplicationMode(); - SelectCopyAppModeBottomSheet.showInstance(manager, target, appMode); + SelectCopyAppModeBottomSheet + .createInstance(target, settings.getApplicationMode()) + .show(manager); } }); } @@ -81,4 +83,18 @@ private void setupAction(@NonNull View view, @DrawableRes int iconId, @StringRes View container = view.findViewById(R.id.container); UiUtilities.setupListItemBackground(app, container, appMode.getProfileColor(nightMode)); } + + public String getSearchableInfo() { + return String.join( + ", ", + getTitle(R.id.reset_button), + getTitle(R.id.copy_button)); + } + + private CharSequence getTitle(final @IdRes int id) { + return view + .findViewById(id) + .findViewById(R.id.title) + .getText(); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureButtonsCard.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureButtonsCard.java index dd6e9a683f3..c450d5e3801 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureButtonsCard.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureButtonsCard.java @@ -6,6 +6,7 @@ import android.widget.TextView; import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; @@ -103,7 +104,7 @@ public List getDefaultButtonsStates() { } public static void setupButton(@NonNull View view, @NonNull String title, @Nullable String description, - @DrawableRes int iconId, boolean enabled, boolean nightMode) { + @DrawableRes int iconId, boolean enabled, boolean nightMode) { OsmandApplication app = (OsmandApplication) view.getContext().getApplicationContext(); ApplicationMode appMode = app.getSettings().getApplicationMode(); @@ -126,4 +127,18 @@ private static void setupListItemBackground(@NonNull View view, @NonNull Applica Drawable background = UiUtilities.getColoredSelectableDrawable(view.getContext(), color, 0.3f); AndroidUtils.setBackground(view.findViewById(R.id.button_container), background); } + + public String getSearchableInfo() { + return String.join( + ", ", + getTitle(R.id.custom_buttons), + getTitle(R.id.default_buttons)); + } + + private CharSequence getTitle(final @IdRes int id) { + return view + .findViewById(id) + .findViewById(R.id.title) + .getText(); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureOtherCard.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureOtherCard.java index 6e526c3d705..941c6385fea 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureOtherCard.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureOtherCard.java @@ -6,6 +6,7 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import net.osmand.plus.R; @@ -90,4 +91,18 @@ private void setupSpeedometerButton(@NonNull ApplicationMode appMode) { AndroidUiHelper.updateVisibility(description, true); } + + public String getSearchableInfo() { + return String.join( + ", ", + getTitle(R.id.distance_by_tap_button), + getTitle(R.id.speedometer)); + } + + private CharSequence getTitle(final @IdRes int id) { + return view + .findViewById(id) + .findViewById(R.id.title) + .getText(); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureWidgetsCard.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureWidgetsCard.java index 1dc6cc0050b..8e6b4f12b8f 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureWidgetsCard.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/dialogs/cards/ConfigureWidgetsCard.java @@ -14,6 +14,7 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import net.osmand.plus.R; @@ -133,4 +134,22 @@ private void setupListItemBackground(@NonNull View view, @NonNull ApplicationMod Drawable background = UiUtilities.getColoredSelectableDrawable(app, color, 0.3f); AndroidUtils.setBackground(button, background); } + + public String getSearchableInfo() { + return String.join( + ", ", + getString(R.string.shared_string_widgets), + getTitle(R.id.left_panel), + getTitle(R.id.right_panel), + getTitle(R.id.top_panel), + getTitle(R.id.bottom_panel), + getTitle(R.id.transparent_widgets_button)); + } + + private CharSequence getTitle(final @IdRes int id) { + return view + .findViewById(id) + .findViewById(R.id.title) + .getText(); + } } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/reorder/ReorderWidgetsFragment.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/reorder/ReorderWidgetsFragment.java index 45588c297f8..1b8f804077a 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/reorder/ReorderWidgetsFragment.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/configure/reorder/ReorderWidgetsFragment.java @@ -225,7 +225,9 @@ private void dismiss() { private void copyFromProfile() { FragmentActivity activity = getActivity(); if (activity != null) { - SelectCopyAppModeBottomSheet.showInstance(activity.getSupportFragmentManager(), this, selectedAppMode); + SelectCopyAppModeBottomSheet + .createInstance(this, selectedAppMode) + .show(activity.getSupportFragmentManager()); } } diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/ISettingsSearchTest.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/ISettingsSearchTest.java new file mode 100644 index 00000000000..8a883d78010 --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/ISettingsSearchTest.java @@ -0,0 +1,8 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.plus.OsmandApplication; + +interface ISettingsSearchTest { + + void testSearchAndFind(OsmandApplication app); +} diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/PluginsHelper.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/PluginsHelper.java new file mode 100644 index 00000000000..5797bc6e0d4 --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/PluginsHelper.java @@ -0,0 +1,27 @@ +package net.osmand.plus.settings.fragments.search; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.plugins.OsmandPlugin; + +class PluginsHelper { + + public static OsmandPlugin enablePlugin(final Class plugin, final OsmandApplication app) { + final OsmandPlugin osmandPlugin = getPlugin(plugin); + enablePlugin(osmandPlugin, app); + return osmandPlugin; + } + + private static void enablePlugin(final OsmandPlugin plugin, final OsmandApplication app) { + net.osmand.plus.plugins.PluginsHelper.enablePlugin(null, app, plugin, true); + } + + private static T getPlugin(final Class plugin) { + return net.osmand.plus.plugins.PluginsHelper + .getAvailablePlugins() + .stream() + .filter(plugin::isInstance) + .map(plugin::cast) + .findFirst() + .orElseThrow(); + } +} diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SearchButtonClick.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SearchButtonClick.java new file mode 100644 index 00000000000..ba2268da82f --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SearchButtonClick.java @@ -0,0 +1,62 @@ +package net.osmand.plus.settings.fragments.search; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withClassName; +import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static net.osmand.test.common.Matchers.childAtPosition; +import static net.osmand.test.common.OsmAndDialogInteractions.skipAppStartDialogs; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import android.view.View; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; + +import org.hamcrest.Matcher; + +class SearchButtonClick { + + public static void clickSearchButton(final OsmandApplication osmandApplication) { + skipAppStartDialogs(osmandApplication); + onView(mapMenuButton()).perform(click()); + onView(settingsButton()).perform(click()); + onView(searchButton()).perform(click()); + } + + private static Matcher mapMenuButton() { + return allOf( + withId(R.id.map_menu_button), + withContentDescription("Back to menu"), + childAtPosition( + allOf( + withId(R.id.map_hud_layout), + childAtPosition( + withId(R.id.map_hud_container), + 0)), + 10), + isDisplayed()); + } + + private static Matcher settingsButton() { + return allOf( + withText(R.string.shared_string_settings), + isDisplayed()); + } + + private static Matcher searchButton() { + return allOf( + withId(R.id.action_button), + childAtPosition( + allOf(withId(R.id.actions_container), + childAtPosition( + withClassName(is("android.widget.LinearLayout")), + 2)), + 0), + isDisplayed()); + } +} diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTest.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTest.java new file mode 100644 index 00000000000..f102f2d4a8d --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTest.java @@ -0,0 +1,972 @@ +package net.osmand.plus.settings.fragments.search; + +import android.content.Context; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.filters.LargeTest; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.plugins.OsmandPlugin; +import net.osmand.plus.plugins.accessibility.AccessibilityPlugin; +import net.osmand.plus.plugins.audionotes.AudioVideoNotesPlugin; +import net.osmand.plus.plugins.development.OsmandDevelopmentPlugin; +import net.osmand.plus.plugins.monitoring.OsmandMonitoringPlugin; +import net.osmand.plus.plugins.weather.WeatherPlugin; +import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.test.common.AndroidTest; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +@LargeTest +@RunWith(Parameterized.class) +public class SettingsSearchTest extends AndroidTest { + + @Parameterized.Parameter(value = 0) + public String description; + + @Parameterized.Parameter(value = 1) + public ISettingsSearchTest settingsSearchTest; + + @Parameterized.Parameters(name = "{0}") + public static Iterable data() { + return Arrays.asList( + new Object[][]{ + { + "RecalculateRoute", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.recalculate_route); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "AnnouncementTimeBottomSheet: title", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.announcement_time_title); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "AnnouncementTimeBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.announcement_time_descr); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "AnnouncementTimeBottomSheet: time intervals", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.announcement_time_intervals); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "FuelTankCapacityBottomSheet: title", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.fuel_tank_capacity); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "FuelTankCapacityBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.fuel_tank_capacity_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "RecalculateRouteInDeviationBottomSheet: title", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.recalculate_route_in_deviation); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "RecalculateRouteInDeviationBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.select_distance_route_will_recalc); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "RecalculateRouteInDeviationBottomSheet: longDescription", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.recalculate_route_distance_promo); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "ScreenTimeoutBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.system_screen_timeout_descr); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "GoodsRestrictionsBottomSheet: title", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.routing_attr_goods_restrictions_name); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "GoodsRestrictionsBottomSheet: goods_delivery_desc", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.goods_delivery_desc); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "GoodsRestrictionsBottomSheet: goods_delivery_desc_2", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.goods_delivery_desc_2); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "GoodsRestrictionsBottomSheet: goods_delivery_desc_3", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.goods_delivery_desc_3); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "GoodsRestrictionsBottomSheet: goods_delivery_desc_4", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.goods_delivery_desc_4); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "SendAnalyticsBottomSheetDialogFragment: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.make_osmand_better_descr); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "ProfileAppearanceFragment: view_angle_description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.view_angle_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "ProfileAppearanceFragment: location_radius_description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.location_radius_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "RouteParametersFragment: title", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.route_recalculation_dist_title); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "ResetProfilePrefsBottomSheet: title", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.reset_all_profile_settings); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "ResetProfilePrefsBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.reset_all_profile_settings_descr); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "ResetProfilePrefsBottomSheet: reset_confirmation_descr", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return "Tapping Reset discards all your changes"; + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "GeneralProfileSettingsFragment", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.distance_during_navigation); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "DistanceDuringNavigationBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return "Choose how distance information is displayed in navigation widgets"; + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "VehicleParametersFragment: SimpleSingleSelectionBottomSheet, description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.routing_attr_motor_type_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "VoiceLanguageBottomSheetFragment: language_description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.language_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "VoiceLanguageBottomSheetFragment: tts_description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.tts_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "VoiceLanguageBottomSheetFragment: recorded_description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.recorded_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "WakeTimeBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.turn_screen_on_wake_time_descr, context.getString(R.string.keep_screen_on)); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "WakeTimeBottomSheet: keep_screen_on", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.keep_screen_on); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "WakeTimeBottomSheet: timeoutDescription", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.screen_timeout_descr, context.getString(R.string.system_screen_timeout)); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "SelectNavProfileBottomSheet: header", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.select_nav_profile_dialog_message); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "SelectDefaultProfileBottomSheet: description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.profile_by_default_description); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "SelectDefaultProfileBottomSheet: car profile", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return ApplicationMode.CAR.toHumanString(); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "SelectBaseProfileBottomSheet: title", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.select_base_profile_dialog_title); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "SelectBaseProfileBottomSheet: longDescription", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.select_base_profile_dialog_message); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "ConfigureScreenFragment", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.configure_screen_widgets_descr); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "search_map_rendering_engine_v1_find_map_rendering_engine", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.map_rendering_engine_v1); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(context.getString(R.string.map_rendering_engine)); + } + } + }, + { + "search_map_rendering_engine_v2_find_map_rendering_engine", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.map_rendering_engine_v2); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(context.getString(R.string.map_rendering_engine)); + } + } + }, + { + "search_ApplicationMode_find_SelectCopyAppModeBottomSheet", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return ApplicationMode.PEDESTRIAN.toHumanString(); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of( + String.format( + "Path: Driving > %s", + context.getString(R.string.copy_from_other_profile))); + } + } + }, + { + "shouldSearchAndFind_ResetProfilePrefsBottomSheet_within_AccessibilityPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.reset_all_profile_settings_descr); + } + + @Override + protected Class getPluginClass() { + return AccessibilityPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of(String.format("Path: Driving > %s > Reset plugin settings to default", osmandPlugin.getName())); + } + } + }, + { + "shouldSearchAndFind_ResetProfilePrefsBottomSheet_within_AudioVideoNotesPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.reset_all_profile_settings_descr); + } + + @Override + protected Class getPluginClass() { + return AudioVideoNotesPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of(String.format("Path: Driving > %s > Reset plugin settings to default", osmandPlugin.getName())); + } + } + }, + { + "shouldSearchAndFind_ResetProfilePrefsBottomSheet_within_OsmandMonitoringPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.reset_all_profile_settings_descr); + } + + @Override + protected Class getPluginClass() { + return OsmandMonitoringPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of(String.format("Path: Driving > %s > Reset plugin settings to default", osmandPlugin.getName())); + } + } + }, + { + "shouldSearchAndFind_ResetProfilePrefsBottomSheet_within_WeatherPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.reset_all_profile_settings_descr); + } + + @Override + protected Class getPluginClass() { + return WeatherPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of(String.format("Path: Driving > %s > Reset plugin settings to default", osmandPlugin.getName())); + } + } + }, + { + "shouldSearchAndFind_SelectCopyAppModeBottomSheet_within_OsmandMonitoringPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return ApplicationMode.PEDESTRIAN.toHumanString(); + } + + @Override + protected Class getPluginClass() { + return OsmandMonitoringPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of( + String.format( + "Path: Driving > %s > %s", + osmandPlugin.getName(), + context.getString(R.string.copy_from_other_profile))); + } + } + }, + { + "shouldSearchAndFind_SelectCopyAppModeBottomSheet_within_AccessibilityPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return ApplicationMode.PEDESTRIAN.toHumanString(); + } + + @Override + protected Class getPluginClass() { + return AccessibilityPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of( + String.format( + "Path: Driving > %s > %s", + osmandPlugin.getName(), + context.getString(R.string.copy_from_other_profile))); + } + } + }, + { + "shouldSearchAndFind_SelectCopyAppModeBottomSheet_within_AudioVideoNotesPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return ApplicationMode.PEDESTRIAN.toHumanString(); + } + + @Override + protected Class getPluginClass() { + return AudioVideoNotesPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of( + String.format( + "Path: Driving > %s > %s", + osmandPlugin.getName(), + context.getString(R.string.copy_from_other_profile))); + } + } + }, + { + "shouldSearchAndFind_SelectCopyAppModeBottomSheet_within_WeatherPlugin", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return ApplicationMode.PEDESTRIAN.toHumanString(); + } + + @Override + protected Class getPluginClass() { + return WeatherPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of( + String.format( + "Path: Driving > %s > %s", + osmandPlugin.getName(), + context.getString(R.string.copy_from_other_profile))); + } + } + }, + { + "shouldSearchAndFind_LocationInterpolationBottomSheet_title", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.location_interpolation_percent); + } + + @Override + protected Class getPluginClass() { + return OsmandDevelopmentPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of(context.getString(R.string.location_interpolation_percent)); + } + } + }, + { + "shouldSearchAndFind_LocationInterpolationBottomSheet_description", + new SettingsSearchWithPluginTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.location_interpolation_percent); + } + + @Override + protected Class getPluginClass() { + return OsmandDevelopmentPlugin.class; + } + + @Override + protected List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin) { + return List.of(context.getString(R.string.location_interpolation_percent_desc)); + } + } + }, + { + "shouldSearchAndFindProfileAppearanceSettings4EachEnabledApplicationMode", + new SettingsSearchTestTemplate() { + + @Override + protected void initializeTest(final OsmandApplication app) { + Stream + .of(ApplicationMode.CAR, ApplicationMode.MOPED) + .forEach(applicationMode -> ApplicationMode.changeProfileAvailability(applicationMode, true, app)); + } + + @Override + protected String getSearchQuery(final Context context) { + return "profile appearance"; + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return Stream + .of("Driving", "Moped") + .map(applicationMode -> String.format("Path: %s > Profile appearance", applicationMode)) + .toList(); + } + } + }, + { + "shouldNotFindProfileAppearanceSettings4DisabledApplicationModes", + new SettingsSearchTestTemplate() { + + @Override + protected void initializeTest(final OsmandApplication app) { + ApplicationMode.changeProfileAvailability(ApplicationMode.CAR, false, app); + } + + @Override + protected String getSearchQuery(final Context context) { + return "profile appearance"; + } + + @Override + protected List getForbiddenSearchResults(final Context context) { + return List.of("Path: Driving > Profile appearance"); + } + } + }, + { + "shouldSearchAndFindSpeedCameraSettings4EachApplicationMode", + new SettingsSearchTestTemplate() { + + @Override + protected void initializeTest(final OsmandApplication app) { + Stream + .of(ApplicationMode.CAR, ApplicationMode.TRUCK) + .forEach(applicationMode -> ApplicationMode.changeProfileAvailability(applicationMode, true, app)); + } + + @Override + protected String getSearchQuery(final Context context) { + return "speed cameras"; + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return Stream + .of("Driving", "Truck") + .map(applicationMode -> String.format("Path: %s > Navigation settings > Screen alerts > Speed cameras", applicationMode)) + .toList(); + } + } + }, + { + "shouldSearchAndFind_ConfigureMenuRootFragment_description", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.ui_customization_description, context.getString(R.string.prefs_plugins)); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + { + "shouldSearchAndFind_ConfigureScreenFragment_ConfigureMap_TextSize", + new SettingsSearchTestTemplate() { + + @Override + protected String getSearchQuery(final Context context) { + return context.getString(R.string.text_size); + } + + @Override + protected List getExpectedSearchResults(final Context context) { + return List.of(getSearchQuery(context)); + } + } + }, + }); + } + + @Rule + public ActivityScenarioRule mActivityScenarioRule = new ActivityScenarioRule<>(MapActivity.class); + + @Test + public void testSearchAndFind() { + settingsSearchTest.testSearchAndFind(app); + } +} diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTestHelper.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTestHelper.java new file mode 100644 index 00000000000..cef60d41661 --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTestHelper.java @@ -0,0 +1,41 @@ +package net.osmand.plus.settings.fragments.search; + +import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withClassName; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withSubstring; +import static net.osmand.test.common.Matchers.childAtPosition; +import static net.osmand.test.common.Matchers.recyclerViewHasItem; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import android.view.View; + +import org.hamcrest.Matcher; + +class SettingsSearchTestHelper { + + public static Matcher searchView() { + return allOf( + withClassName(is("android.widget.SearchView$SearchAutoComplete")), + childAtPosition( + allOf( + withClassName(is("android.widget.LinearLayout")), + childAtPosition( + withClassName(is("android.widget.LinearLayout")), + 1)), + 0), + isDisplayed()); + } + + public static Matcher searchResultsView() { + return allOf( + withId(SearchResultsFragmentUI.SEARCH_RESULTS_VIEW_ID), + isDisplayed()); + } + + public static Matcher hasSearchResultWithSubstring(final String substring) { + return recyclerViewHasItem(hasDescendant(withSubstring(substring))); + } +} diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTestTemplate.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTestTemplate.java new file mode 100644 index 00000000000..b5976d574fc --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchTestTemplate.java @@ -0,0 +1,65 @@ +package net.osmand.plus.settings.fragments.search; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; +import static androidx.test.espresso.action.ViewActions.replaceText; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static net.osmand.plus.settings.fragments.search.SearchButtonClick.clickSearchButton; +import static net.osmand.plus.settings.fragments.search.SettingsSearchTestHelper.hasSearchResultWithSubstring; +import static net.osmand.plus.settings.fragments.search.SettingsSearchTestHelper.searchResultsView; +import static net.osmand.plus.settings.fragments.search.SettingsSearchTestHelper.searchView; + +import static org.hamcrest.Matchers.not; + +import android.content.Context; +import android.view.View; + +import com.google.common.base.Function; + +import net.osmand.plus.OsmandApplication; + +import org.hamcrest.Matcher; + +import java.util.Collections; +import java.util.List; + +abstract class SettingsSearchTestTemplate implements ISettingsSearchTest { + + @Override + public void testSearchAndFind(final OsmandApplication app) { + // Given + initializeTest(app); + clickSearchButton(app); + + // When + onView(searchView()).perform(replaceText(getSearchQuery(app)), closeSoftKeyboard()); + + // Then + checkSearchResultsViewMatchesSearchResults( + getExpectedSearchResults(app), + SettingsSearchTestHelper::hasSearchResultWithSubstring); + checkSearchResultsViewMatchesSearchResults( + getForbiddenSearchResults(app), + forbidden -> not(hasSearchResultWithSubstring(forbidden))); + } + + protected void initializeTest(final OsmandApplication app) { + } + + protected abstract String getSearchQuery(final Context context); + + protected List getExpectedSearchResults(final Context context) { + return Collections.emptyList(); + } + + protected List getForbiddenSearchResults(final Context context) { + return Collections.emptyList(); + } + + private static void checkSearchResultsViewMatchesSearchResults(final List searchResults, + final Function> getMatcherForSearchResult) { + for (final String searchResult : searchResults) { + onView(searchResultsView()).check(matches(getMatcherForSearchResult.apply(searchResult))); + } + } +} diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchWithPluginTestTemplate.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchWithPluginTestTemplate.java new file mode 100644 index 00000000000..7f96c1ff6a7 --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SettingsSearchWithPluginTestTemplate.java @@ -0,0 +1,41 @@ +package net.osmand.plus.settings.fragments.search; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; +import static androidx.test.espresso.action.ViewActions.replaceText; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static net.osmand.plus.settings.fragments.search.SearchButtonClick.clickSearchButton; +import static net.osmand.plus.settings.fragments.search.SettingsSearchTestHelper.hasSearchResultWithSubstring; +import static net.osmand.plus.settings.fragments.search.SettingsSearchTestHelper.searchResultsView; +import static net.osmand.plus.settings.fragments.search.SettingsSearchTestHelper.searchView; + +import android.content.Context; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.plugins.OsmandPlugin; + +import java.util.List; + +abstract class SettingsSearchWithPluginTestTemplate implements ISettingsSearchTest { + + @Override + public void testSearchAndFind(final OsmandApplication app) { + // Given + final OsmandPlugin osmandPlugin = PluginsHelper.enablePlugin(getPluginClass(), app); + clickSearchButton(app); + + // When + onView(searchView()).perform(replaceText(getSearchQuery(app)), closeSoftKeyboard()); + + // Then + for (final String expectedSearchResult : getExpectedSearchResults(app, osmandPlugin)) { + onView(searchResultsView()).check(matches(hasSearchResultWithSubstring(expectedSearchResult))); + } + } + + protected abstract String getSearchQuery(final Context context); + + protected abstract Class getPluginClass(); + + protected abstract List getExpectedSearchResults(final Context context, final OsmandPlugin osmandPlugin); +} diff --git a/OsmAnd/test/java/net/osmand/test/common/Matchers.java b/OsmAnd/test/java/net/osmand/test/common/Matchers.java index 9ae729b40be..6b158320972 100644 --- a/OsmAnd/test/java/net/osmand/test/common/Matchers.java +++ b/OsmAnd/test/java/net/osmand/test/common/Matchers.java @@ -11,6 +11,10 @@ import org.hamcrest.TypeSafeMatcher; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.Adapter; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import androidx.test.espresso.matcher.BoundedMatcher; public class Matchers { @@ -62,4 +66,30 @@ public void describeTo(Description description) { } }; } + + // adapted from https://stackoverflow.com/a/53289078/12982352 + public static Matcher recyclerViewHasItem(final Matcher matcher) { + return new BoundedMatcher<>(RecyclerView.class) { + + @Override + public void describeTo(Description description) { + description.appendText("has item: "); + matcher.describeTo(description); + } + + @Override + protected boolean matchesSafely(final RecyclerView view) { + final Adapter adapter = view.getAdapter(); + for (int position = 0; position < adapter.getItemCount(); position++) { + final int type = adapter.getItemViewType(position); + final ViewHolder holder = adapter.createViewHolder(view, type); + adapter.onBindViewHolder(holder, position); + if (matcher.matches(holder.itemView)) { + return true; + } + } + return false; + } + }; + } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 6f3bf3d5d5d..7f7979c4e85 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,3 +27,4 @@ android.defaults.buildfeatures.buildconfig=true android.nonTransitiveRClass=false android.nonFinalResIds=false #org.gradle.configuration-cache=true +org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"