Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve sorting functionality of Track folders / Tracks #21310

Open
wants to merge 18 commits into
base: r4.9
Choose a base branch
from

Conversation

nazar-kutz
Copy link
Contributor

@nazar-kutz nazar-kutz commented Nov 12, 2024

Summary of Changes and Future Considerations

1. Unified Interfaces

Implemented shared interfaces TracksGroup and ComparableTracksGroup for:

  • TrackTab, TracksFolder, SmartFolder.

Added a getId() method to TracksGroup, returning:

  • TrackFolder: Relative path (e.g., "A/B/C" for "tracks/A/B/C"). Relative path doesn't include global tracks root folder ("tracks" in Adnroid, "GPX" in iOS).
  • SmartFolder: Prefixed name, e.g., for "test" folder name, id is "SMART_FOLDER___test". The prefixe "SMART_FOLDERS___" is ​​used to determine whether a given id belongs to a smart folder or not.
  • TrackTab: Replaces previously implemented method getTypeName() on getId() to return folder/smart folder ID or type name (ON_MAP, ALL, FOLDERS).

2. Enhanced TrackFolder Functionality

  • getRootFolder() returns root folder ("tracks" for Android, "GPX" for iOS).
    Updated getDirName() to support an extended name format (useExtendedName parameter):
  • TrackFolder: Returns relative path.
  • SmartFolder: Unaffected by parameter.
  • TrackTab: Includes parent folder if not root.

3. Optimized PreselectedTabParams

Replaced name with id field and removed redundant code for parsing SmartFolder IDs.

4. Refactored TrackTabsHelper

Created SelectTrackTabsHelper subclass for logic specific to SelectTrackTabsFragment.

5. TrackFolder ID Methodology

Replaced usage of folder name as ID with the getId() method that will return a relative path to the folder from the root folder ("tracks" for Android, "GPX" for "iOS"). Also fixed relative path retrieving to always exclude root folder name. It meens that previously for root folder getRelativePath() returned a string "tracks". Now it returns an empty string "". It was implemented because of different names of root tracks forlder for Android and iOS for implementing consistency between these platforms.

6. TrackSortModesCollection Wrapper

Implemented a new class TrackSortModesCollection. It centralized sort mode management:

  • Supports both relative path (new key) and folder name (legacy key). This is required to ensure the ability to read the sort mode using the new key, even if the settings are stored with the old key (e.g., after importing settings from previous app versions).
  • Auto-upgrades keys via askUpgradeCachedKeys during runtime. We try to update the keys each time we request TrackSortModesCollection from OsmandSettings. To ensure the keys are updated correctly, access to all TrackFolders is required. This means that at the time of the update, all track folders must be loaded using TrackFolderLoaderTask. The key upgrade to the new version occurs only once per application session. This is done to avoid redundant operations, as all cached keys are updated during the first run, and new keys are immediately added in the form of a relative path.
  • Dynamically updates keys on folder rename/delete.

7. Improved TrackTab sorting functionality

  • To implement sorting by distance and duration we calculate and cache TrackFolderAnalysis. Currently without recalculating on tracks changes, such as moving track to another folder or remove it.
  • Implemented getSortedTrackTabs() using TracksComparator for TrackTab-s.
  • Sorting adapts to UI context:
    • Horizontal tab menu (no parent folder).
    • Dialog window (includes parent folder).

8. Sorting Logic depends on context

Sorting is applied differently depending on the context:

  • My PlacesTracks screen
    • Regular folders and smart folders are displayed as a single, combined list.
    • They are sorted according to the mode selected for the root folder "Tracks."
  • Configure MapTracks (tabs and bottom sheet)
    • All smart folders are displayed regardless of whether they contain tracks.
    • Regular folders appear only if they contain one or more tracks (excluding subfolders content).
    • Tabs display only the folder name.
    • In the bottom sheet, the folder name is accompanied by its parent folder name if it is not the root folder ("tracks").
    • Smart folders and regular folders are separated into two distinct lists, each sorted independently but using the same sorting mode (as set for the root "tracks" folder).
    • The list starts with global types (ON_MAP and ALL), followed by sorted smart folders and regular folders.

To account for tab type during sorting, the ComparableTracksGroup class introduces the getDefaultOrder() method:

  • This method applies only to TrackTab and returns the index of the tab type via TrackTabType.ordinal().
  • It allows different types to be divided into separate lists and sorted independently during the creation of the overall list.

Suggestions for iOS

Unifying sort modes handling across Android and iOS

To ensure better compatibility between Android and iOS, consider implementing functionality similar to TrackSortModesCollection. While it doesn’t have to be an identical bundle, the following should be ensured:

  • Ability to fetch sort modes from settings using old keys (folder name) if the settings were imported from a previous app version.
  • Update keys from folder name to folder path as implemented in method askUpgradeKeysWithSync.
    This will help maintain consistency across Android and iOS implementations, improving support for shared features.

Updating the getRelativePath method for TrackFolder

The getRelativePath method in TrackFolder has been modified to no longer return "GPX" as the relative path for the root folder. This change ensures key consistency between Android and iOS.
However, on iOS, it is necessary to verify whether this update disrupts existing logic. Other settings might have used the path as a key, and if so, they should be adjusted accordingly.

Replacing getRelativePath with getId

It is recommended to replace all calls to getRelativePath() with getId() for TrackFolder. Although both methods currently return the same value, using getId explicitly makes the code clearer and better reflects its purpose.

@nazar-kutz nazar-kutz linked an issue Nov 12, 2024 that may be closed by this pull request
@nazar-kutz nazar-kutz marked this pull request as draft November 18, 2024 16:16
@nazar-kutz nazar-kutz changed the title Use TracksComparator to sort TrackTab instances Improve sorting functionality of Track folders / Tracks Nov 19, 2024
@nazar-kutz nazar-kutz marked this pull request as ready for review November 22, 2024 15:22
@@ -4,6 +4,7 @@ import net.osmand.shared.gpx.filters.TrackFolderAnalysis

interface ComparableTracksGroup {
fun getFolderAnalysis(): TrackFolderAnalysis
fun getDirName(): String
fun getDirName(useExtendedName: Boolean): String
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useExtendedName > includingSubdirs

@@ -33,15 +35,22 @@ public class TracksComparator implements Comparator<Object> {
public final TrackTab trackTab;
public final TracksSortMode sortMode;
public final Collator collator = OsmAndCollator.primaryCollator();
private boolean useExtendedName = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useExtendedName > useSubdirs

return name;
}

@NonNull
public static String getExtendedFolderName(@NonNull File directory, @NonNull String initialName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getFolderPath

@nazar-kutz
Copy link
Contributor Author

nazar-kutz commented Nov 24, 2024

Changes implemented after the Last Review

  • Parameter useExtendedName was renamed to useSubdirs
  • TrackSortModesCollection renamed to TrackSortModesHelper and moved to store in application as other global helpers. Now is accessable by calling app.getTrackSortModesHelper().
  • All keys upgrading logic was moved to a new class UpgradeTrackSortModeKeysAlgorithm, that is called only once during each application session, after all needed resources for upgrading (e.g. track folders and smart folders paths info) are initialized.

@nazar-kutz
Copy link
Contributor Author

@alex-osm There's also an issue I noticed but haven't fixed yet. The getDirItems() method in the GpxDbHelper class only returns first-level folders, i.e., those located directly in the root folder "tracks", but does not include subfolders. As a result, during the sort modes keys upgrade process, we will consistently lose sorting for subfolders. It seems this is the only remaining issue to address at the moment.

If the logic for reading subfolders from the database is fixed so that they are also stored in the dirItems variable, the rest of the sorting code should function correctly without further modifications.

Link to mentioned variable in the repository

putUpgradedKey(upgradedCache, TrackTabType.ON_MAP.name());
putUpgradedKey(upgradedCache, TrackTabType.ALL.name());
putUpgradedKey(upgradedCache, TrackTabType.FOLDERS.name());
List<GpxDirItem> gpxDirs = gpxDbHelper.getDirItems();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use GpxDirItem-s here in request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tracks folder listing is mixed up (Configure map>tracks>menu)
2 participants