Repository: cgeo/cgeo (Java)

Issue:
[New filter] Filter definition string in header: "change marker" is too unobtrusive
### Tell us your idea!

When there is a stored filter active, it's name is displayed in the header - which is perfectly fine (and BTW offers a wonderful workaround for the "'Status:3 items' is way too compact" issue #11293 ;) ).

But: 
- When modifying a currently active stored filter using the filter definition dialog, there will still be the stored name displayed, just extended by a tiny little "*", which can easily be overlooked.
- Although the star marker concept is a good idea, esp. when it comes to saving the modifications of a stored filter (cause the old name is suggested as default),  it's meaning is not really obvious to the user (took even me some time to realize).
- Moreover, the displayed name can massively be misleading, esp. when the differences are tiny. And if the filter has changed fundamentally, it would even be completely false.



### What solution would you suggest?

Thus I would suggest to ...

- EITHER entirely drop the name of the stored filter, once it has been changed,
   and display the current filter definition instead
   (if possible, the old name may nevertheless be displayed as default, when the user is going to save his changes)
- OR change the "*" to s/th more noticeable like ``(changed)`` or ``(modified)`` or a mnemonic abbreviation.
- OR ... another idea you possibly have to make unmistakably clear to the user
  that his stored filter is de facto no longer working in it's known way

### Is there an alternative?

_No response_

### Additional Information

_No response_


Discussion: Teammeeting 11.2.24: team is undecided what would be the best way to visualize this. Discussed options:
* use an icon (e.g. warning sign)
* put asterik in parenthesis (e.g. " (*)")
* use colors or other font (e.g. italic)

@murggel will try out some things
I created different variants:
changed the name to italic-font and add a space between name and "*"
used icons (mockup) different icon can be used
changed icon for filter (mockup) different icon can be used

I will post each variant as separate comment for better voting

Current version / normal without space


| View |Unchanged   | Normal without space (current version)   | 
| --- | --- | --- |
| Filter|![image](https://github.com/cgeo/cgeo/assets/70113341/6da1a384-f4d9-4fd0-8854-69b77ca0a035) |![image](https://github.com/cgeo/cgeo/assets/70113341/42213dc0-c110-4ed5-bfa3-bbcebff3fe85)|![image](https://github.com/cgeo/cgeo/assets/70113341/276d05bc-a9ff-4893-82dd-a407627db346)|
| Map|![image](https://github.com/cgeo/cgeo/assets/70113341/66d360b4-9c46-47fc-ad87-56c25c181eb7)|![image](https://github.com/cgeo/cgeo/assets/70113341/453ebcc7-1773-4bd3-91aa-f092df1e159f)|
| List|![image](https://github.com/cgeo/cgeo/assets/70113341/6808f459-1157-4297-aa9a-a67e6f13b393)|![image](https://github.com/cgeo/cgeo/assets/70113341/c4ca4889-2a63-4ed1-9007-67d4f8364a14)|
Italic version without space


| View |Unchanged   |  Italic without space   |
| --- | --- | --- |
| Filter|![image](https://github.com/cgeo/cgeo/assets/70113341/6da1a384-f4d9-4fd0-8854-69b77ca0a035) |![image](https://github.com/cgeo/cgeo/assets/70113341/276d05bc-a9ff-4893-82dd-a407627db346) |
| Map|![image](https://github.com/cgeo/cgeo/assets/70113341/66d360b4-9c46-47fc-ad87-56c25c181eb7)|![image](https://github.com/cgeo/cgeo/assets/70113341/36764d5f-c528-4f34-add9-60f23d1ac899) |
| List|![image](https://github.com/cgeo/cgeo/assets/70113341/6808f459-1157-4297-aa9a-a67e6f13b393)|![image](https://github.com/cgeo/cgeo/assets/70113341/a31fe391-7522-41e9-abad-5e5b1953ed01)|
Italic version with space


| View |Unchanged   | Italic with space   | 
| --- | --- | --- |
| Filter|![image](https://github.com/cgeo/cgeo/assets/70113341/6da1a384-f4d9-4fd0-8854-69b77ca0a035) |![image](https://github.com/cgeo/cgeo/assets/70113341/112b2571-985c-4985-890b-2b29691df833) |
| Map|![image](https://github.com/cgeo/cgeo/assets/70113341/66d360b4-9c46-47fc-ad87-56c25c181eb7)|![image](https://github.com/cgeo/cgeo/assets/70113341/b944ffb8-0f35-4aa4-a282-1685898d4a5e) |
| List|![image](https://github.com/cgeo/cgeo/assets/70113341/6808f459-1157-4297-aa9a-a67e6f13b393)|![image](https://github.com/cgeo/cgeo/assets/70113341/903e2f97-6331-4872-bad0-7b52948a4ef8)|
Italic version with icon



| View |Unchanged   | Icon (mockup e.g. Pencil)   | 
| --- | --- | --- | 
| Filter|![image](https://github.com/cgeo/cgeo/assets/70113341/6da1a384-f4d9-4fd0-8854-69b77ca0a035) |![image](https://github.com/cgeo/cgeo/assets/70113341/e874eacc-1686-47a2-9e69-f4802d18226c)|
| Map|![image](https://github.com/cgeo/cgeo/assets/70113341/66d360b4-9c46-47fc-ad87-56c25c181eb7)|![image](https://github.com/cgeo/cgeo/assets/70113341/78a52311-4584-4194-8f35-95cb03ab30a2)|
| List|![image](https://github.com/cgeo/cgeo/assets/70113341/6808f459-1157-4297-aa9a-a67e6f13b393)|![image](https://github.com/cgeo/cgeo/assets/70113341/33174167-f015-4fe0-b030-f582b4d89ddf) <br> sorry flying pencil|
Thanks for creating those variations. I like the italic version. Maybe we can additionally put the name in brackets to emphasize that this once has been the filter named xxx, but not quite more:

_(Found)*_
Italic version with different filter icon


| View |Unchanged   | Different filter-icon (mockup e.g. filter with pencil)  | Pencil only for Filter View|
| --- | --- | --- | --- | 
| Filter<br> <br>or here just only pencil|![image](https://github.com/cgeo/cgeo/assets/70113341/6da1a384-f4d9-4fd0-8854-69b77ca0a035) | ![image](https://github.com/cgeo/cgeo/assets/70113341/1f7d74d1-ce74-4b3b-8efb-7295edcc17a2)|![image](https://github.com/cgeo/cgeo/assets/70113341/e874eacc-1686-47a2-9e69-f4802d18226c)|
| Map|![image](https://github.com/cgeo/cgeo/assets/70113341/66d360b4-9c46-47fc-ad87-56c25c181eb7)|![image](https://github.com/cgeo/cgeo/assets/70113341/bc02cf34-af16-4ea8-98dc-0e75a0ab9c49)|![image](https://github.com/cgeo/cgeo/assets/70113341/bc02cf34-af16-4ea8-98dc-0e75a0ab9c49)|
| List|![image](https://github.com/cgeo/cgeo/assets/70113341/6808f459-1157-4297-aa9a-a67e6f13b393)| | |
I would suggest to use the vote 👍 / 👎 buttons for the variants and add suggestion as separate comment
> Thanks for creating those variations. I like the italic version. Maybe we can additionally put the name in brackets to emphasize that this once has been the filter named xxx, but not quite more:
> 
> _(Found)*_

Good idea - I will create a new variant
Name in brackets and "*" as postfix

| View |Unchanged   |  Name in brackets and "*" as postfix| 
| --- | --- | --- | 
| Filter|![image](https://github.com/cgeo/cgeo/assets/70113341/6da1a384-f4d9-4fd0-8854-69b77ca0a035) |![image](https://github.com/cgeo/cgeo/assets/70113341/7a93531c-60cd-4e19-b487-9290c5156fc1)|
| Map / List|![image](https://github.com/cgeo/cgeo/assets/70113341/66d360b4-9c46-47fc-ad87-56c25c181eb7) |![image](https://github.com/cgeo/cgeo/assets/70113341/60209df2-96fc-47ee-badd-df63d554fe1f) |


Name in brackets and "*" as prefix

| View |Unchanged   | Name in brackets and "*" as prefix | 
| --- | --- | --- | 
| Filter|![image](https://github.com/cgeo/cgeo/assets/70113341/6da1a384-f4d9-4fd0-8854-69b77ca0a035) | ![image](https://github.com/cgeo/cgeo/assets/70113341/0c8980d9-80c8-40f7-98f6-97b7731ad41e)|
| Map / List|![image](https://github.com/cgeo/cgeo/assets/70113341/66d360b4-9c46-47fc-ad87-56c25c181eb7) |![image](https://github.com/cgeo/cgeo/assets/70113341/4e6a4f4b-bc26-4073-b300-b805f134253c) |




Fix (patch):
diff --git a/main/src/main/java/cgeo/geocaching/CacheListActivity.java b/main/src/main/java/cgeo/geocaching/CacheListActivity.java
index ec97b41325d..61ce1dd3db5 100644
--- a/main/src/main/java/cgeo/geocaching/CacheListActivity.java
+++ b/main/src/main/java/cgeo/geocaching/CacheListActivity.java
@@ -1711,7 +1711,7 @@ public static void startActivityFinder(final Context context, final String userN
     }
 
     private void updateFilterBar() {
-        FilterUtils.updateFilterBar(this, getActiveFilterName());
+        FilterUtils.updateFilterBar(this, getActiveFilterName(), getActiveFilterSavedDifferently());
     }
 
     @Nullable
@@ -1722,6 +1722,14 @@ private String getActiveFilterName() {
         return null;
     }
 
+    @Nullable
+    private Boolean getActiveFilterSavedDifferently() {
+        if (currentCacheFilter.get().isFiltering()) {
+            return currentCacheFilter.get().isSavedDifferently();
+        }
+        return null;
+    }
+
     public static Intent getNearestIntent(final Activity context) {
         return Intents.putListType(new Intent(context, CacheListActivity.class), CacheListType.NEAREST);
     }
diff --git a/main/src/main/java/cgeo/geocaching/filters/core/GeocacheFilter.java b/main/src/main/java/cgeo/geocaching/filters/core/GeocacheFilter.java
index b3d4ef811d8..783381eb2aa 100644
--- a/main/src/main/java/cgeo/geocaching/filters/core/GeocacheFilter.java
+++ b/main/src/main/java/cgeo/geocaching/filters/core/GeocacheFilter.java
@@ -3,6 +3,7 @@
 import cgeo.geocaching.R;
 import cgeo.geocaching.models.Geocache;
 import cgeo.geocaching.storage.DataStore;
+import cgeo.geocaching.utils.FilterUtils;
 import cgeo.geocaching.utils.JsonUtils;
 import cgeo.geocaching.utils.LocalizationUtils;
 import cgeo.geocaching.utils.TextUtils;
@@ -239,7 +240,7 @@ public boolean isSavedDifferently() {
     }
 
     public String getNameForUserDisplay() {
-        return getName() + (isSavedDifferently() ? "*" : "");
+        return FilterUtils.getFilterName(getName(), isSavedDifferently());
     }
 
     /**
diff --git a/main/src/main/java/cgeo/geocaching/filters/gui/GeocacheFilterActivity.java b/main/src/main/java/cgeo/geocaching/filters/gui/GeocacheFilterActivity.java
index 3c9aa5fe7c3..fb116f0a121 100644
--- a/main/src/main/java/cgeo/geocaching/filters/gui/GeocacheFilterActivity.java
+++ b/main/src/main/java/cgeo/geocaching/filters/gui/GeocacheFilterActivity.java
@@ -22,6 +22,7 @@
 import cgeo.geocaching.ui.dialog.SimpleDialog;
 import cgeo.geocaching.ui.recyclerview.ManagedListAdapter;
 import cgeo.geocaching.utils.CollectionStream;
+import cgeo.geocaching.utils.FilterUtils;
 import cgeo.geocaching.utils.Log;
 import cgeo.geocaching.utils.TextUtils;
 import static cgeo.geocaching.filters.core.GeocacheFilterContext.FilterType.TRANSIENT;
@@ -162,10 +163,7 @@ private void initializeStorageOptions() {
 
         //handling of "save" button
         binding.filterStorageSave.setOnClickListener(v -> {
-            String filterName = binding.filterStorageName.getText().toString();
-            if (filterName.endsWith("*")) {
-                filterName = filterName.substring(0, filterName.length() - 1);
-            }
+            final String filterName = FilterUtils.getPurifiedFilterName(binding.filterStorageName.getText().toString());
             SimpleDialog.of(this).setTitle(R.string.cache_filter_storage_save_title)
                     .input(new SimpleDialog.InputOptions().setInitialValue(filterName), newName -> {
                         final GeocacheFilter filter = getFilterFromView();
@@ -291,7 +289,7 @@ private void fillViewFromFilter(final String inputFilter, final boolean forceAdv
             try {
                 final List<IFilterViewHolder<?>> filterList = new ArrayList<>();
                 final GeocacheFilter filter = GeocacheFilter.checkConfig(inputFilter);
-                binding.filterStorageName.setText(filter.getNameForUserDisplay());
+                FilterUtils.setFilterText(binding.filterStorageName, filter.getNameForUserDisplay(), filter.isSavedDifferently());
                 includeInconclusiveFilterCheckbox.setChecked(filter.isIncludeInconclusive());
                 setAdvanced = filter.isOpenInAdvancedMode();
                 IGeocacheFilter filterTree = filter.getTree();
@@ -403,7 +401,7 @@ private GeocacheFilter getFilterFromView() {
         }
 
         return GeocacheFilter.create(
-                binding.filterStorageName.getText().toString(),
+                FilterUtils.getPurifiedFilterName(binding.filterStorageName.getText().toString()),
                 binding.filterBasicAdvanced.isChecked(),
                 this.includeInconclusiveFilterCheckbox.isChecked(),
                 filter);
diff --git a/main/src/main/java/cgeo/geocaching/maps/MapUtils.java b/main/src/main/java/cgeo/geocaching/maps/MapUtils.java
index cbdc716a658..6b94c602f00 100644
--- a/main/src/main/java/cgeo/geocaching/maps/MapUtils.java
+++ b/main/src/main/java/cgeo/geocaching/maps/MapUtils.java
@@ -106,7 +106,7 @@ public static void filter(final Collection<Geocache> caches, final GeocacheFilte
     }
 
     public static void updateFilterBar(final Activity activity, final GeocacheFilterContext filterContext) {
-        FilterUtils.updateFilterBar(activity, getActiveMapFilterName(filterContext));
+        FilterUtils.updateFilterBar(activity, getActiveMapFilterName(filterContext), getActiveMapFilterSavedDifferently(filterContext));
     }
 
     @Nullable
@@ -118,6 +118,15 @@ private static String getActiveMapFilterName(final GeocacheFilterContext filterC
         return null;
     }
 
+    @Nullable
+    private static Boolean getActiveMapFilterSavedDifferently(final GeocacheFilterContext filterContext) {
+        final GeocacheFilter filter = filterContext.get();
+        if (filter.isFiltering()) {
+            return filter.isSavedDifferently();
+        }
+        return null;
+    }
+
     // one-time messages to be shown for maps
     public static void showMapOneTimeMessages(final Activity activity, final MapMode mapMode) {
         Dialogs.basicOneTimeMessage(activity, OneTimeDialogs.DialogType.MAP_QUICK_SETTINGS);
diff --git a/main/src/main/java/cgeo/geocaching/utils/FilterUtils.java b/main/src/main/java/cgeo/geocaching/utils/FilterUtils.java
index d3a560ac5a1..d66aec22c6a 100644
--- a/main/src/main/java/cgeo/geocaching/utils/FilterUtils.java
+++ b/main/src/main/java/cgeo/geocaching/utils/FilterUtils.java
@@ -11,7 +11,9 @@
 import cgeo.geocaching.ui.dialog.SimpleDialog;
 
 import android.app.Activity;
+import android.graphics.Typeface;
 import android.os.Handler;
+import android.text.style.StyleSpan;
 import android.view.View;
 import android.widget.TextView;
 
@@ -24,6 +26,9 @@
 
 public class FilterUtils {
 
+    private static String savedDifferentlyMarkerPreFix = "(";
+    private static String savedDifferentlyMarkerPostFix = ")*";
+
     private FilterUtils() {
         // should not be instantiated
     }
@@ -53,7 +58,7 @@ public static <T extends Activity & FilteredActivity> boolean openFilterList(fin
                 SimpleDialog.of(filteredActivity).setTitle(R.string.cache_filter_storage_select_clear_title)
                     .setNeutralButton(TextParam.id(R.string.cache_filter_storage_clear_button))
                     .setNeutralAction(() ->
-                        filteredActivity.refreshWithFilter(GeocacheFilter.createEmpty(filterContext.get().isOpenInAdvancedMode()))
+                            filteredActivity.refreshWithFilter(GeocacheFilter.createEmpty(filterContext.get().isOpenInAdvancedMode()))
                     ).selectSingle(model, filteredActivity::refreshWithFilter);
             } else {
                 SimpleDialog.of(filteredActivity).setTitle(R.string.cache_filter_storage_select_title)
@@ -63,13 +68,40 @@ public static <T extends Activity & FilteredActivity> boolean openFilterList(fin
         return true;
     }
 
-    public static void updateFilterBar(final Activity activity, @Nullable final String filterName) {
+    public static String getPurifiedFilterName(final String filterName) {
+        if (filterName.endsWith(FilterUtils.savedDifferentlyMarkerPostFix) && filterName.startsWith(FilterUtils.savedDifferentlyMarkerPreFix)) {
+            return filterName.substring(FilterUtils.savedDifferentlyMarkerPreFix.length(), filterName.length() - FilterUtils.savedDifferentlyMarkerPostFix.length());
+        }
+        return filterName;
+    }
+
+    public static String getFilterName(@NonNull final String filterName, final boolean filterChanged) {
+        String changedFilterName = filterName;
+        if (filterChanged) {
+            changedFilterName = FilterUtils.savedDifferentlyMarkerPreFix + filterName + FilterUtils.savedDifferentlyMarkerPostFix;
+        }
+        return changedFilterName;
+    }
+
+    public static void setFilterText(@NonNull final TextView viewField, @Nullable final String filterName, @Nullable final Boolean filterChanged) {
+        if (filterName != null) {
+            if (filterChanged == Boolean.TRUE) {
+                viewField.setText(TextUtils.setSpan(filterName, new StyleSpan(Typeface.ITALIC)));
+            } else {
+                viewField.setText(filterName);
+            }
+        } else {
+            viewField.setText("");
+        }
+    }
+
+    public static void updateFilterBar(final Activity activity, @Nullable final String filterName, @Nullable final Boolean filterChanged) {
         final View filterView = activity.findViewById(R.id.filter_bar);
         if (filterName == null) {
             filterView.setVisibility(View.GONE);
         } else {
             final TextView filterTextView = activity.findViewById(R.id.filter_text);
-            filterTextView.setText(filterName);
+            setFilterText(filterTextView, filterName, filterChanged);
             filterView.setVisibility(View.VISIBLE);
         }
     }