From 357ab00ed60df90daa8f61db5dbf5e271840aa91 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Fri, 12 Feb 2021 21:38:28 +0200 Subject: [PATCH 1/3] Download all button implementation --- .../java/net/osmand/map/OsmandRegions.java | 39 ++ .../main/java/net/osmand/map/WorldRegion.java | 29 ++ OsmAnd/res/values/strings.xml | 2 + .../download/AbstractDownloadActivity.java | 2 +- .../osmand/plus/download/CustomIndexItem.java | 3 +- .../plus/download/DownloadActivity.java | 1 - .../plus/download/DownloadActivityType.java | 27 +- .../plus/download/DownloadIndexesThread.java | 10 + .../osmand/plus/download/DownloadItem.java | 76 ++++ .../plus/download/DownloadResourceGroup.java | 80 ++-- .../plus/download/DownloadResources.java | 158 ++++++-- .../download/DownloadValidationManager.java | 2 +- .../net/osmand/plus/download/IndexItem.java | 85 ++-- .../plus/download/MultipleIndexItem.java | 122 ++++++ .../ui/DownloadResourceGroupAdapter.java | 6 +- .../plus/download/ui/ItemViewHolder.java | 367 ++++++++++++------ .../download/ui/UpdatesIndexFragment.java | 3 +- 17 files changed, 763 insertions(+), 249 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/download/DownloadItem.java create mode 100644 OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java diff --git a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java index 033beb3789..eba0d94b2b 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java @@ -10,6 +10,7 @@ import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.data.QuadTree; +import net.osmand.map.WorldRegion.RegionBoundingBox; import net.osmand.util.Algorithms; import net.osmand.util.MapAlgorithms; import net.osmand.util.MapUtils; @@ -436,6 +437,7 @@ public class OsmandRegions { cx /= object.getPointsLength(); cy /= object.getPointsLength(); rd.regionCenter = new LatLon(MapUtils.get31LatitudeY((int) cy), MapUtils.get31LongitudeX((int) cx)); + rd.boundingBox = findBoundingBox(object); } rd.regionParentFullName = mapIndexFields.get(mapIndexFields.parentFullName, object); @@ -461,6 +463,43 @@ public class OsmandRegions { return rd; } + private RegionBoundingBox findBoundingBox(BinaryMapDataObject object) { + if (object.getPointsLength() == 0) { + return new RegionBoundingBox(0, 0, 0, 0); + } + + double currentX = object.getPoint31XTile(0); + double currentY = object.getPoint31YTile(0); + double minX = currentX; + double maxX = currentX; + double minY = currentY; + double maxY = currentY; + + if (object.getPointsLength() > 1) { + for (int i = 1; i < object.getPointsLength(); i++) { + currentX = object.getPoint31XTile(i); + currentY = object.getPoint31YTile(i); + if (currentX > maxX) { + maxX = currentX; + } else if (currentX < minX) { + minX = currentX; + } + if (currentY > maxY) { + maxY = currentY; + } else if (currentY < minY) { + minY = currentY; + } + } + } + + minX = MapUtils.get31LongitudeX((int) minX); + maxX = MapUtils.get31LongitudeX((int) maxX); + double revertedMinY = MapUtils.get31LatitudeY((int) maxY); + double revertedMaxY = MapUtils.get31LatitudeY((int) minY); + + return new RegionBoundingBox(minX, maxX, revertedMinY, revertedMaxY); + } + private String getSearchIndex(BinaryMapDataObject object) { MapIndex mi = object.getMapIndex(); TIntObjectIterator it = object.getObjectNames().iterator(); diff --git a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java index 38fbc40c3d..e95efb4f5b 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java @@ -40,6 +40,7 @@ public class WorldRegion implements Serializable { protected String regionDownloadName; protected boolean regionMapDownload; protected LatLon regionCenter; + protected RegionBoundingBox boundingBox; public static class RegionParams { protected String regionLeftHandDriving; @@ -182,4 +183,32 @@ public class WorldRegion implements Serializable { } return res; } + + public static boolean isFirstRegionInsideTheSecond(WorldRegion first, + WorldRegion second) { + RegionBoundingBox bbox1 = first.boundingBox; + RegionBoundingBox bbox2 = second.boundingBox; + if ((bbox1.minX > bbox2.minX) && (bbox1.maxX < bbox2.maxX)) { + if ((bbox1.minY > bbox2.minY) && (bbox1.maxY < bbox2.maxY)) { + return true; + } + } + return false; + } + + public static class RegionBoundingBox { + + double minX; + double maxX; + double minY; + double maxY; + + public RegionBoundingBox(double minX, double maxX, double minY, double maxY) { + this.minX = minX; + this.maxX = maxX; + this.minY = minY; + this.maxY = maxY; + } + + } } \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 8b1a73aa95..71c3591ade 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,8 @@ --> + Delete %1$d files? + All regions Car Motorbike Off-road diff --git a/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java b/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java index 9bcb0ebb6c..93b887ea1c 100644 --- a/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java +++ b/OsmAnd/src/net/osmand/plus/download/AbstractDownloadActivity.java @@ -17,7 +17,7 @@ public class AbstractDownloadActivity extends ActionBarProgressActivity { downloadValidationManager.startDownload(this, indexItem); } - public void makeSureUserCancelDownload(IndexItem item) { + public void makeSureUserCancelDownload(DownloadItem item) { downloadValidationManager.makeSureUserCancelDownload(this, item); } } diff --git a/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java b/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java index 16067b7c04..885e28fdf6 100644 --- a/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java @@ -56,7 +56,8 @@ public class CustomIndexItem extends IndexItem { } @Override - public File getTargetFile(OsmandApplication ctx) { + @NonNull + public File getTargetFile(@NonNull OsmandApplication ctx) { String basename = getTranslatedBasename(); if (!Algorithms.isEmpty(subfolder)) { basename = subfolder + "/" + basename; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java index d076f329f0..bc92fc050f 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivity.java @@ -1,7 +1,6 @@ package net.osmand.plus.download; import android.Manifest; -import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java index 298e3fc287..b78617d426 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.net.URLEncoder; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Locale; @@ -113,6 +114,10 @@ public class DownloadActivityType { public static DownloadActivityType getIndexType(String tagName) { return byTag.get(tagName); } + + public static Collection values() { + return byTag.values(); + } protected static String addVersionToExt(String ext, int version) { return "_" + version + ext; @@ -318,7 +323,7 @@ public class DownloadActivityType { } } - public String getVisibleDescription(IndexItem indexItem, Context ctx) { + public String getVisibleDescription(DownloadItem downloadItem, Context ctx) { if (this == SRTM_COUNTRY_FILE) { return ctx.getString(R.string.download_srtm_maps); } else if (this == WIKIPEDIA_FILE) { @@ -337,20 +342,20 @@ public class DownloadActivityType { return ""; } - public String getVisibleName(IndexItem indexItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) { + public String getVisibleName(DownloadItem downloadItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) { if (this == VOICE_FILE) { - String fileName = indexItem.fileName; + String fileName = downloadItem.getFileName(); if (fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)) { - return FileNameTranslationHelper.getVoiceName(ctx, getBasename(indexItem)); + return FileNameTranslationHelper.getVoiceName(ctx, getBasename(downloadItem)); } else if (fileName.endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) { - return FileNameTranslationHelper.getVoiceName(ctx, getBasename(indexItem)); + return FileNameTranslationHelper.getVoiceName(ctx, getBasename(downloadItem)); } - return getBasename(indexItem); + return getBasename(downloadItem); } if (this == FONT_FILE) { - return FileNameTranslationHelper.getFontName(ctx, getBasename(indexItem)); + return FileNameTranslationHelper.getFontName(ctx, getBasename(downloadItem)); } - final String basename = getBasename(indexItem); + final String basename = getBasename(downloadItem); if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) { return FileNameTranslationHelper.getWikiName(ctx, basename); } @@ -442,8 +447,8 @@ public class DownloadActivityType { } - public String getBasename(IndexItem indexItem) { - String fileName = indexItem.fileName; + public String getBasename(DownloadItem downloadItem) { + String fileName = downloadItem.getFileName(); if (fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.EXTRA_ZIP_EXT.length()); } @@ -458,7 +463,7 @@ public class DownloadActivityType { if (fileName.endsWith(IndexConstants.SQLITE_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()); } - if (indexItem.getType() == WIKIVOYAGE_FILE && + if (downloadItem.getType() == WIKIVOYAGE_FILE && fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length()); } diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java index 9d47f57762..20ac836139 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java @@ -239,6 +239,16 @@ public class DownloadIndexesThread { } } + public void cancelDownload(DownloadItem item) { + if (item instanceof MultipleIndexItem) { + MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; + cancelDownload(multipleIndexItem.getAllIndexes()); + } else if (item instanceof IndexItem) { + IndexItem indexItem = (IndexItem) item; + cancelDownload(indexItem); + } + } + public void cancelDownload(IndexItem item) { app.logMapDownloadEvent("cancel", item); if (currentDownloadingItem == item) { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java new file mode 100644 index 0000000000..f0a566cea6 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java @@ -0,0 +1,76 @@ +package net.osmand.plus.download; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import net.osmand.map.OsmandRegions; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; + +import java.io.File; +import java.util.List; +import java.util.Locale; + +public abstract class DownloadItem { + + protected DownloadActivityType type; + protected DownloadResourceGroup relatedGroup; + + public DownloadItem(DownloadActivityType type) { + this.type = type; + } + + public DownloadActivityType getType() { + return type; + } + + public void setRelatedGroup(DownloadResourceGroup relatedGroup) { + this.relatedGroup = relatedGroup; + } + + public DownloadResourceGroup getRelatedGroup() { + return relatedGroup; + } + + @NonNull + public String getSizeDescription(Context ctx) { + String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_space); + String size = String.format(Locale.US, "%.2f", getSizeToDownloadInMb()); + return String.format(pattern, size, "MB"); + } + + public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { + return type.getVisibleName(this, ctx, osmandRegions, true); + } + + public String getVisibleName(Context ctx, OsmandRegions osmandRegions, boolean includingParent) { + return type.getVisibleName(this, ctx, osmandRegions, includingParent); + } + + public String getVisibleDescription(OsmandApplication clctx) { + return type.getVisibleDescription(this, clctx); + } + + public String getBasename() { + return type.getBasename(this); + } + + protected abstract double getSizeToDownloadInMb(); + + public abstract double getArchiveSizeMB(); + + public abstract boolean isDownloaded(); + + public abstract boolean isOutdated(); + + public abstract boolean hasActualDataToDownload(); + + public abstract boolean isDownloading(DownloadIndexesThread thread); + + public abstract String getFileName(); + + @NonNull + public abstract List getDownloadedFiles(OsmandApplication app); + +} diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java index 416e20bc94..dc4e697cb4 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java @@ -8,6 +8,7 @@ import net.osmand.map.OsmandRegions; import net.osmand.map.WorldRegion; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; +import net.osmand.util.Algorithms; import java.util.ArrayList; import java.util.Collections; @@ -20,8 +21,8 @@ public class DownloadResourceGroup { private final DownloadResourceGroupType type; private final DownloadResourceGroup parentGroup; - // ASSERT: individualResources are not empty if and only if groups are empty - private final List individualResources; + // ASSERT: individualDisplayItems are not empty if and only if groups are empty + private final List individualDownloadItems; private final List groups; protected final String id; @@ -107,10 +108,10 @@ public class DownloadResourceGroup { public DownloadResourceGroup(DownloadResourceGroup parentGroup, DownloadResourceGroupType type, String id) { boolean flat = type.containsIndexItem(); if (flat) { - this.individualResources = new ArrayList(); + this.individualDownloadItems = new ArrayList(); this.groups = null; } else { - this.individualResources = null; + this.individualDownloadItems = null; this.groups = new ArrayList(); } this.id = id; @@ -173,7 +174,7 @@ public class DownloadResourceGroup { DownloadResourceGroup regionMaps = getSubGroupById(DownloadResourceGroupType.REGION_MAPS.getDefaultId()); if(regionMaps != null && regionMaps.size() == 1 && parentGroup != null && parentGroup.getParentGroup() != null && isEmpty(getSubGroupById(DownloadResourceGroupType.SUBREGIONS.getDefaultId()))) { - IndexItem item = regionMaps.individualResources.get(0); + IndexItem item = regionMaps.getIndividualResources().get(0); DownloadResourceGroup screenParent = parentGroup.getParentGroup(); if(item.getType() == DownloadActivityType.HILLSHADE_FILE) { DownloadResourceGroup hillshades = @@ -183,7 +184,7 @@ public class DownloadResourceGroup { screenParent.addGroup(hillshades); } hillshades.addItem(item); - regionMaps.individualResources.remove(0); + regionMaps.individualDownloadItems.remove(0); } else if (item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) { DownloadResourceGroup hillshades = screenParent .getSubGroupById(DownloadResourceGroupType.SRTM_HEADER.getDefaultId()); @@ -192,7 +193,7 @@ public class DownloadResourceGroup { screenParent.addGroup(hillshades); } hillshades.addItem(item); - regionMaps.individualResources.remove(0); + regionMaps.individualDownloadItems.remove(0); } } @@ -221,35 +222,38 @@ public class DownloadResourceGroup { } } groups.add(g); - if (g.individualResources != null) { - final net.osmand.Collator collator = OsmAndCollator.primaryCollator(); - final OsmandApplication app = getRoot().app; - final OsmandRegions osmandRegions = app.getRegions(); - Collections.sort(g.individualResources, new Comparator() { - @Override - public int compare(IndexItem lhs, IndexItem rhs) { - int lli = lhs.getType().getOrderIndex(); - int rri = rhs.getType().getOrderIndex(); - if(lli < rri) { - return -1; - } else if(lli > rri) { - return 1; - } + sortDownloadItems(g.individualDownloadItems); + } - return collator.compare(lhs.getVisibleName(app.getApplicationContext(), osmandRegions), - rhs.getVisibleName(app.getApplicationContext(), osmandRegions)); + protected void sortDownloadItems(List items) { + if (Algorithms.isEmpty(items)) return; + final net.osmand.Collator collator = OsmAndCollator.primaryCollator(); + final OsmandApplication app = getRoot().app; + final OsmandRegions osmandRegions = app.getRegions(); + Collections.sort(items, new Comparator() { + @Override + public int compare(DownloadItem firstItem, DownloadItem secondItem) { + int firstOrder = firstItem.getType().getOrderIndex(); + int secondOrder = secondItem.getType().getOrderIndex(); + if(firstOrder < secondOrder) { + return -1; + } else if(firstOrder > secondOrder) { + return 1; } - }); - } + String firstName = firstItem.getVisibleName(app, osmandRegions); + String secondName = secondItem.getVisibleName(app, osmandRegions); + return collator.compare(firstName, secondName); + } + }); } - public void addItem(IndexItem i) { + public void addItem(DownloadItem i) { i.setRelatedGroup(this); - individualResources.add(i); + individualDownloadItems.add(i); } public boolean isEmpty() { - return isEmpty(individualResources) && isEmpty(groups); + return isEmpty(individualDownloadItems) && isEmpty(groups); } private boolean isEmpty(List l) { @@ -265,7 +269,7 @@ public class DownloadResourceGroup { } public int size() { - return groups != null ? groups.size() : individualResources.size(); + return groups != null ? groups.size() : individualDownloadItems.size(); } public DownloadResourceGroup getGroupByIndex(int ind) { @@ -275,9 +279,9 @@ public class DownloadResourceGroup { return null; } - public IndexItem getItemByIndex(int ind) { - if (individualResources != null && ind >= 0 && ind < individualResources.size()) { - return individualResources.get(ind); + public DownloadItem getItemByIndex(int ind) { + if (individualDownloadItems != null && ind >= 0 && ind < individualDownloadItems.size()) { + return individualDownloadItems.get(ind); } return null; } @@ -306,8 +310,20 @@ public class DownloadResourceGroup { } public List getIndividualResources() { + List individualResources = new ArrayList<>(); + if (individualDownloadItems != null) { + for (DownloadItem item : individualDownloadItems) { + if (item instanceof IndexItem) { + individualResources.add((IndexItem) item); + } + } + } return individualResources; } + + public List getIndividualDownloadItems() { + return individualDownloadItems; + } public WorldRegion getRegion() { return region; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java index 56d137a696..a3aa20c79f 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java @@ -25,10 +25,14 @@ import java.io.InputStream; import java.text.DateFormat; import java.text.ParseException; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; + +import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS; public class DownloadResources extends DownloadResourceGroup { private static final String TAG = DownloadResources.class.getSimpleName(); @@ -40,7 +44,7 @@ public class DownloadResources extends DownloadResourceGroup { private Map indexFileNames = new LinkedHashMap<>(); private Map indexActivatedFileNames = new LinkedHashMap<>(); private List rawResources; - private Map > groupByRegion; + private Map> groupByRegion; private List itemsToUpdate = new ArrayList<>(); public static final String WORLD_SEAMARKS_KEY = "world_seamarks"; public static final String WORLD_SEAMARKS_NAME = "World_seamarks"; @@ -55,7 +59,7 @@ public class DownloadResources extends DownloadResourceGroup { this.region = app.getRegions().getWorldRegion(); this.app = app; } - + public List getItemsToUpdate() { return itemsToUpdate; } @@ -260,7 +264,7 @@ public class DownloadResources extends DownloadResourceGroup { } private Map listWithAlternatives(final java.text.DateFormat dateFormat, File file, - final String ext, final Map files) { + final String ext, final Map files) { if (file.isDirectory()) { file.list(new FilenameFilter() { @Override @@ -292,7 +296,7 @@ public class DownloadResources extends DownloadResourceGroup { } return file; } - + private void prepareFilesToUpdate() { List filtered = rawResources; if (filtered != null) { @@ -307,7 +311,7 @@ public class DownloadResources extends DownloadResourceGroup { } } } - + protected boolean prepareData(List resources) { this.rawResources = resources; @@ -332,18 +336,18 @@ public class DownloadResources extends DownloadResourceGroup { DownloadResourceGroup nauticalMapsGroup = new DownloadResourceGroup(this, DownloadResourceGroupType.NAUTICAL_MAPS_GROUP); DownloadResourceGroup nauticalMapsScreen = new DownloadResourceGroup(nauticalMapsGroup, DownloadResourceGroupType.NAUTICAL_MAPS); DownloadResourceGroup nauticalMaps = new DownloadResourceGroup(nauticalMapsGroup, DownloadResourceGroupType.NAUTICAL_MAPS_HEADER); - + DownloadResourceGroup wikivoyageMapsGroup = new DownloadResourceGroup(this, DownloadResourceGroupType.TRAVEL_GROUP); DownloadResourceGroup wikivoyageMapsScreen = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_MAPS); DownloadResourceGroup wikivoyageMaps = new DownloadResourceGroup(wikivoyageMapsGroup, DownloadResourceGroupType.WIKIVOYAGE_HEADER); - Map > groupByRegion = new LinkedHashMap>(); + Map> groupByRegion = new LinkedHashMap<>(); OsmandRegions regs = app.getRegions(); for (IndexItem ii : resources) { if (ii.getType() == DownloadActivityType.VOICE_FILE) { - if (ii.getFileName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)){ + if (ii.getFileName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) { voiceTTS.addItem(ii); - } else if (ii.getFileName().endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)){ + } else if (ii.getFileName().endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP)) { voiceRec.addItem(ii); } continue; @@ -377,7 +381,7 @@ public class DownloadResources extends DownloadResourceGroup { groupByRegion.get(wg).add(ii); } else { if (ii.getFileName().startsWith("World_")) { - if (ii.getFileName().toLowerCase().startsWith(WORLD_SEAMARKS_KEY) || + if (ii.getFileName().toLowerCase().startsWith(WORLD_SEAMARKS_KEY) || ii.getFileName().toLowerCase().startsWith(WORLD_SEAMARKS_OLD_KEY)) { nauticalMaps.addItem(ii); } else { @@ -402,22 +406,22 @@ public class DownloadResources extends DownloadResourceGroup { LinkedList parent = new LinkedList(); DownloadResourceGroup worldSubregions = new DownloadResourceGroup(this, DownloadResourceGroupType.SUBREGIONS); addGroup(worldSubregions); - for(WorldRegion rg : region.getSubregions()) { + for (WorldRegion rg : region.getSubregions()) { queue.add(rg); parent.add(worldSubregions); } - while(!queue.isEmpty()) { + while (!queue.isEmpty()) { WorldRegion reg = queue.pollFirst(); DownloadResourceGroup parentGroup = parent.pollFirst(); List subregions = reg.getSubregions(); DownloadResourceGroup mainGrp = new DownloadResourceGroup(parentGroup, DownloadResourceGroupType.REGION, reg.getRegionId()); mainGrp.region = reg; parentGroup.addGroup(mainGrp); - + List list = groupByRegion.get(reg); - if(list != null) { - DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS); - for(IndexItem ii : list) { + if (list != null) { + DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS); + for (IndexItem ii : list) { flatFiles.addItem(ii); } mainGrp.addGroup(flatFiles); @@ -425,10 +429,10 @@ public class DownloadResources extends DownloadResourceGroup { DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.SUBREGIONS); mainGrp.addGroup(subRegions); // add to processing queue - for(WorldRegion rg : subregions) { + for (WorldRegion rg : subregions) { queue.add(rg); parent.add(subRegions); - } + } } // Possible improvements // 1. if there is no subregions no need to create resource group REGIONS_MAPS - objection raise diversity and there is no value @@ -455,8 +459,8 @@ public class DownloadResources extends DownloadResourceGroup { } otherGroup.addGroup(voiceScreenTTS); otherGroup.addGroup(voiceScreenRec); - - + + if (fonts.getIndividualResources() != null) { otherGroup.addGroup(fontScreen); } @@ -465,9 +469,87 @@ public class DownloadResources extends DownloadResourceGroup { createHillshadeSRTMGroups(); trimEmptyGroups(); updateLoadedFiles(); + collectMultipleIndexesItems(region); return true; } + private void collectMultipleIndexesItems(@NonNull WorldRegion region) { + List subRegions = region.getSubregions(); + if (Algorithms.isEmpty(subRegions)) return; + + DownloadResourceGroup group = getRegionMapsGroup(region); + if (group != null) { + boolean listModified = false; + List indexesList = group.getIndividualResources(); + for (DownloadActivityType type : DownloadActivityType.values()) { + if (!doesListContainIndexWithType(indexesList, type)) { + List indexesFromSubRegions = collectIndexesOfType(subRegions, type); + if (indexesFromSubRegions != null) { + group.addItem(new MultipleIndexItem(region, indexesFromSubRegions, type)); + listModified = true; + } + } + } + if (listModified) { + sortDownloadItems(group.getIndividualDownloadItems()); + } + } + for (WorldRegion subRegion : subRegions) { + collectMultipleIndexesItems(subRegion); + } + } + + private DownloadResourceGroup getRegionMapsGroup(WorldRegion region) { + DownloadResourceGroup group = getRegionGroup(region); + if (group != null) { + return group.getSubGroupById(REGION_MAPS.getDefaultId()); + } + return null; + } + + @Nullable + private List collectIndexesOfType(@NonNull List regions, + @NonNull DownloadActivityType type) { + Map collectedIndexes = new LinkedHashMap<>(); + for (WorldRegion region : regions) { + List regionIndexes = getIndexItems(region); + boolean found = false; + if (regionIndexes != null) { + for (IndexItem index : regionIndexes) { + if (index.getType() == type) { + found = true; + collectedIndexes.put(region, index); + break; + } + } + } + if (!found) return null; + } + return removeDuplicates(collectedIndexes); + } + + private List removeDuplicates(Map collectedIndexes) { + List regions = new ArrayList<>(collectedIndexes.keySet()); + // collect duplicates + Set duplicates = new HashSet<>(); + for (int i = 0; i < regions.size() - 1; i++) { + WorldRegion firstRegion = regions.get(i); + for (int j = i + 1; j < regions.size(); j++) { + WorldRegion secondRegion = regions.get(j); + if (WorldRegion.isFirstRegionInsideTheSecond(firstRegion, secondRegion)) { + duplicates.add(firstRegion); + } else if (WorldRegion.isFirstRegionInsideTheSecond(secondRegion, firstRegion)) { + duplicates.add(secondRegion); + } + } + } + // remove duplicates + for (WorldRegion key : duplicates) { + collectedIndexes.remove(key); + } + return new ArrayList<>(collectedIndexes.values()); + } + private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) { LinkedList queue = new LinkedList(); LinkedList parent = new LinkedList(); @@ -485,7 +567,7 @@ public class DownloadResources extends DownloadResourceGroup { CustomRegion customRegion = (CustomRegion) reg; List indexItems = customRegion.loadIndexItems(); if (!Algorithms.isEmpty(indexItems)) { - DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS); + DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, REGION_MAPS); for (IndexItem ii : indexItems) { flatFiles.addItem(ii); } @@ -557,7 +639,11 @@ public class DownloadResources extends DownloadResourceGroup { return res; } - public static List findIndexItemsAt(OsmandApplication app, List names, DownloadActivityType type, boolean includeDownloaded, int limit) { + public static List findIndexItemsAt(OsmandApplication app, + List names, + DownloadActivityType type, + boolean includeDownloaded, + int limit) { List res = new ArrayList<>(); OsmandRegions regions = app.getRegions(); DownloadIndexesThread downloadThread = app.getDownloadThread(); @@ -573,8 +659,12 @@ public class DownloadResources extends DownloadResourceGroup { return res; } - private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List res) { - List otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); + private static boolean isIndexItemDownloaded(DownloadIndexesThread downloadThread, + DownloadActivityType type, + WorldRegion downloadRegion, + List res) { + List otherIndexItems = + new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); for (IndexItem indexItem : otherIndexItems) { if (indexItem.getType() == type && indexItem.isDownloaded()) { return true; @@ -584,8 +674,24 @@ public class DownloadResources extends DownloadResourceGroup { && isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res); } - private static boolean addIndexItem(DownloadIndexesThread downloadThread, DownloadActivityType type, WorldRegion downloadRegion, List res) { - List otherIndexItems = new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); + private boolean doesListContainIndexWithType(List indexItems, + DownloadActivityType type) { + if (indexItems != null) { + for (IndexItem indexItem : indexItems) { + if (indexItem.getType() == type) { + return true; + } + } + } + return false; + } + + private static boolean addIndexItem(DownloadIndexesThread downloadThread, + DownloadActivityType type, + WorldRegion downloadRegion, + List res) { + List otherIndexItems = + new ArrayList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); for (IndexItem indexItem : otherIndexItems) { if (indexItem.getType() == type && !res.contains(indexItem)) { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java b/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java index 8e03b2c1e5..6b12fb6713 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadValidationManager.java @@ -192,7 +192,7 @@ public class DownloadValidationManager { } - public void makeSureUserCancelDownload(FragmentActivity ctx, final IndexItem item) { + public void makeSureUserCancelDownload(FragmentActivity ctx, final DownloadItem item) { AlertDialog.Builder bld = new AlertDialog.Builder(ctx); bld.setTitle(ctx.getString(R.string.shared_string_cancel)); bld.setMessage(R.string.confirm_interrupt_download); diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index 650ab0679b..a746d4aa90 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -1,12 +1,9 @@ package net.osmand.plus.download; -import android.content.Context; - import androidx.annotation.NonNull; import net.osmand.IndexConstants; import net.osmand.PlatformUtil; -import net.osmand.map.OsmandRegions; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.helpers.FileNameTranslationHelper; @@ -16,9 +13,11 @@ import org.apache.commons.logging.Log; import java.io.File; import java.io.IOException; import java.text.DateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; -public class IndexItem implements Comparable { +public class IndexItem extends DownloadItem implements Comparable { private static final Log log = PlatformUtil.getLog(IndexItem.class); String description; @@ -27,43 +26,44 @@ public class IndexItem implements Comparable { long timestamp; long contentSize; long containerSize; - DownloadActivityType type; boolean extra; // Update information boolean outdated; boolean downloaded; long localTimestamp; - DownloadResourceGroup relatedGroup; - - public IndexItem(String fileName, String description, long timestamp, String size, long contentSize, - long containerSize, @NonNull DownloadActivityType tp) { + public IndexItem(String fileName, + String description, + long timestamp, + String size, + long contentSize, + long containerSize, + @NonNull DownloadActivityType type) { + super(type); this.fileName = fileName; this.description = description; this.timestamp = timestamp; this.size = size; this.contentSize = contentSize; this.containerSize = containerSize; - this.type = tp; - } - - public DownloadActivityType getType() { - return type; - } - - public void setRelatedGroup(DownloadResourceGroup relatedGroup) { - this.relatedGroup = relatedGroup; - } - - public DownloadResourceGroup getRelatedGroup() { - return relatedGroup; } + @Override public String getFileName() { return fileName; } + @NonNull + @Override + public List getDownloadedFiles(OsmandApplication app) { + File targetFile = getTargetFile(app); + List result = new ArrayList<>(); + if (targetFile.exists()) { + result.add(targetFile); + } + return result; + } public String getDescription() { return description; @@ -89,10 +89,14 @@ public class IndexItem implements Comparable { return ((double)containerSize) / (1 << 20); } - public String getSizeDescription(Context ctx) { - return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB"); + @Override + protected double getSizeToDownloadInMb() { + try { + return Double.parseDouble(size); + } catch (Exception e) { + return 0; + } } - public DownloadEntry createDownloadEntry(OsmandApplication ctx) { String fileName = this.fileName; @@ -132,11 +136,8 @@ public class IndexItem implements Comparable { return type.getTargetFileName(this); } - public String getBasename() { - return type.getBasename(this); - } - - public File getTargetFile(OsmandApplication ctx) { + @NonNull + public File getTargetFile(@NonNull OsmandApplication ctx) { String basename = getTranslatedBasename(); return new File(type.getDownloadFolder(ctx, this), basename + type.getUnzipExtension(ctx, this)); } @@ -190,7 +191,7 @@ public class IndexItem implements Comparable { && getType() != DownloadActivityType.HILLSHADE_FILE && getType() != DownloadActivityType.SLOPE_FILE; } - + public void setOutdated(boolean outdated) { this.outdated = outdated; } @@ -198,7 +199,12 @@ public class IndexItem implements Comparable { public void setDownloaded(boolean downloaded) { this.downloaded = downloaded; } - + + @Override + public boolean hasActualDataToDownload() { + return !isDownloaded() || isOutdated(); + } + public void setLocalTimestamp(long localTimestamp) { this.localTimestamp = localTimestamp; } @@ -211,20 +217,11 @@ public class IndexItem implements Comparable { return downloaded; } - public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { - return type.getVisibleName(this, ctx, osmandRegions, true); + @Override + public boolean isDownloading(DownloadIndexesThread thread) { + return thread.isDownloading(this); } - public String getVisibleName(Context ctx, OsmandRegions osmandRegions, boolean includingParent) { - return type.getVisibleName(this, ctx, osmandRegions, includingParent); - } - - public String getVisibleDescription(OsmandApplication clctx) { - return type.getVisibleDescription(this, clctx); - } - - - public String getDate(java.text.DateFormat format) { return format.format(new Date(timestamp)); } diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java new file mode 100644 index 0000000000..e28d606653 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java @@ -0,0 +1,122 @@ +package net.osmand.plus.download; + +import androidx.annotation.NonNull; + +import net.osmand.map.WorldRegion; +import net.osmand.plus.OsmandApplication; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class MultipleIndexItem extends DownloadItem { + + private final List items; + + public MultipleIndexItem(@NonNull WorldRegion region, + @NonNull List items, + @NonNull DownloadActivityType type) { + super(type); + this.items = items; + } + + public List getAllIndexes() { + return items; + } + + @Override + public boolean isOutdated() { + for (IndexItem item : items) { + if (item.isOutdated()) { + return true; + } + } + return false; + } + + @Override + public boolean isDownloaded() { + for (IndexItem item : items) { + if (item.isDownloaded()) { + return true; + } + } + return false; + } + + @Override + public boolean isDownloading(DownloadIndexesThread thread) { + for (IndexItem item : items) { + if (thread.isDownloading(item)) { + return true; + } + } + return false; + } + + @Override + public String getFileName() { + // The file name is used in many places. + // But in the case of a Multiple Indexes element it's not use in most cases. + // File is not created for Multiple Indexes element, + // and all file names are available in internal IndexItem elements. + + // The only one place where a filename may be needed + // is to generate the base and display names. + // Since these names are generated based on the filename. + // But now we don't need a name for display, + // because on all screens where we now use multiple elements item, + // for display used a type name instead of a file name. + + // Later, if you need a file name, + // you can try to create it based on the WorldRegion + // and file name of one of the internal IndexItem elements. + return ""; + } + + @NonNull + @Override + public List getDownloadedFiles(OsmandApplication app) { + List result = new ArrayList<>(); + for (IndexItem item : items) { + result.addAll(item.getDownloadedFiles(app)); + } + return result; + } + + public List getIndexesToDownload() { + List indexesToDownload = new ArrayList<>(); + for (IndexItem item : items) { + if (item.hasActualDataToDownload()) { + indexesToDownload.add(item); + } + } + return indexesToDownload; + } + + @Override + public boolean hasActualDataToDownload() { + return getIndexesToDownload().size() > 0; + } + + @Override + public double getSizeToDownloadInMb() { + double totalSizeMb = 0.0d; + for (IndexItem item : items) { + if (item.hasActualDataToDownload()) { + totalSizeMb += Double.parseDouble(item.size); + } + } + return totalSizeMb; + } + + @Override + public double getArchiveSizeMB() { + double result = 0.0d; + for (IndexItem item : items) { + result += item.getArchiveSizeMB(); + } + return result; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java index a212dd5e31..d2e281bbfc 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java @@ -10,9 +10,9 @@ import android.widget.TextView; import net.osmand.plus.R; import net.osmand.plus.activities.OsmandBaseExpandableListAdapter; import net.osmand.plus.download.CustomIndexItem; +import net.osmand.plus.download.DownloadItem; import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadResourceGroup; -import net.osmand.plus.download.IndexItem; import java.util.ArrayList; import java.util.List; @@ -52,9 +52,9 @@ public class DownloadResourceGroupAdapter extends OsmandBaseExpandableListAdapte public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final Object child = getChild(groupPosition, childPosition); - if (child instanceof IndexItem) { + if (child instanceof DownloadItem) { - IndexItem item = (IndexItem) child; + DownloadItem item = (DownloadItem) child; DownloadResourceGroup group = getGroupObj(groupPosition); ItemViewHolder viewHolder; if (convertView != null && convertView.getTag() instanceof ItemViewHolder) { diff --git a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java index 70041a525e..7fd4172fce 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java @@ -17,11 +17,14 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.PopupMenu; import androidx.core.view.ViewCompat; +import net.osmand.map.OsmandRegions; import net.osmand.map.WorldRegion; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.activities.LocalIndexHelper.LocalIndexType; @@ -31,11 +34,13 @@ import net.osmand.plus.activities.PluginsFragment; import net.osmand.plus.chooseplan.ChoosePlanDialogFragment; import net.osmand.plus.download.CityItem; import net.osmand.plus.download.CustomIndexItem; +import net.osmand.plus.download.DownloadItem; import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivityType; import net.osmand.plus.download.DownloadResourceGroup; import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.IndexItem; +import net.osmand.plus.download.MultipleIndexItem; import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask; import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.inapp.InAppPurchaseHelper; @@ -43,6 +48,8 @@ import net.osmand.util.Algorithms; import java.io.File; import java.text.DateFormat; +import java.util.ArrayList; +import java.util.List; public class ItemViewHolder { @@ -137,24 +144,24 @@ public class ItemViewHolder { depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication()); } - public void bindIndexItem(final IndexItem indexItem) { - bindIndexItem(indexItem, null); + public void bindIndexItem(final DownloadItem downloadItem) { + bindIndexItem(downloadItem, null); } - public void bindIndexItem(final IndexItem indexItem, final String cityName) { + public void bindIndexItem(final DownloadItem downloadItem, final String cityName) { initAppStatusVariables(); - boolean isDownloading = context.getDownloadThread().isDownloading(indexItem); + boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread()); int progress = -1; - if (context.getDownloadThread().getCurrentDownloadingItem() == indexItem) { + if (context.getDownloadThread().getCurrentDownloadingItem() == downloadItem) { progress = context.getDownloadThread().getCurrentDownloadingItemProgress(); } - boolean disabled = checkDisabledAndClickAction(indexItem); + boolean disabled = checkDisabledAndClickAction(downloadItem); /// name and left item String name; if(showTypeInName) { - name = indexItem.getType().getString(context); + name = downloadItem.getType().getString(context); } else { - name = indexItem.getVisibleName(context, context.getMyApplication().getRegions(), showParentRegionName); + name = downloadItem.getVisibleName(context, context.getMyApplication().getRegions(), showParentRegionName); } String text = (!Algorithms.isEmpty(cityName) && !cityName.equals(name) ? cityName + "\n" : "") + name; nameTextView.setText(text); @@ -164,43 +171,78 @@ public class ItemViewHolder { nameTextView.setTextColor(textColorSecondary); } int color = textColorSecondary; - if(indexItem.isDownloaded() && !isDownloading) { - int colorId = indexItem.isOutdated() ? R.color.color_distance : R.color.color_ok; + if(downloadItem.isDownloaded() && !isDownloading) { + int colorId = downloadItem.isOutdated() ? R.color.color_distance : R.color.color_ok; color = context.getResources().getColor(colorId); } - if (indexItem.isDownloaded()) { + if (downloadItem.isDownloaded()) { leftImageView.setImageDrawable(getContentIcon(context, - indexItem.getType().getIconResource(), color)); + downloadItem.getType().getIconResource(), color)); } else if (disabled) { leftImageView.setImageDrawable(getContentIcon(context, - indexItem.getType().getIconResource(), textColorSecondary)); + downloadItem.getType().getIconResource(), textColorSecondary)); } else { leftImageView.setImageDrawable(getContentIcon(context, - indexItem.getType().getIconResource())); + downloadItem.getType().getIconResource())); } descrTextView.setTextColor(textColorSecondary); if (!isDownloading) { progressBar.setVisibility(View.GONE); descrTextView.setVisibility(View.VISIBLE); - if (indexItem instanceof CustomIndexItem && (((CustomIndexItem) indexItem).getSubName(context) != null)) { - descrTextView.setText(((CustomIndexItem) indexItem).getSubName(context)); - } else if (indexItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { + if (downloadItem instanceof CustomIndexItem && (((CustomIndexItem) downloadItem).getSubName(context) != null)) { + descrTextView.setText(((CustomIndexItem) downloadItem).getSubName(context)); + } else if (downloadItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { descrTextView.setText(context.getString(R.string.depth_contour_descr)); - } else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE - || indexItem.getType() == DownloadActivityType.HILLSHADE_FILE - || indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { + } else if ((downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE + || downloadItem.getType() == DownloadActivityType.HILLSHADE_FILE + || downloadItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { if (showTypeInName) { descrTextView.setText(""); } else { - descrTextView.setText(indexItem.getType().getString(context)); + descrTextView.setText(downloadItem.getType().getString(context)); } - } else if (showTypeInDesc) { - descrTextView.setText(indexItem.getType().getString(context) + - " • " + indexItem.getSizeDescription(context) + - " • " + (showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat))); + } else if (downloadItem instanceof MultipleIndexItem) { + MultipleIndexItem item = (MultipleIndexItem) downloadItem; + String allRegionsHeader = context.getString(R.string.shared_strings_all_regions); + String regionsHeader = context.getString(R.string.regions); + String allRegionsCount = String.valueOf(item.getAllIndexes().size()); + String leftToDownloadCount = String.valueOf(item.getIndexesToDownload().size()); + String header; + String count; + if (item.hasActualDataToDownload()) { + if (!item.isDownloaded()) { + header = allRegionsHeader; + count = leftToDownloadCount; + } else { + header = regionsHeader; + count = String.format( + context.getString(R.string.ltr_or_rtl_combine_via_slash), + leftToDownloadCount, + allRegionsCount); + } + } else { + header = allRegionsHeader; + count = allRegionsCount; + } + String fullDescription = + context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count); + if (item.hasActualDataToDownload()) { + fullDescription = context.getString( + R.string.ltr_or_rtl_combine_via_bold_point, fullDescription, + item.getSizeDescription(context)); + } + descrTextView.setText(fullDescription); } else { - descrTextView.setText(indexItem.getSizeDescription(context) + " • " + - (showRemoteDate ? indexItem.getRemoteDate(dateFormat) : indexItem.getLocalDate(dateFormat))); + IndexItem item = (IndexItem) downloadItem; + String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point); + String type = item.getType().getString(context); + String size = item.getSizeDescription(context); + String date = showRemoteDate ? item.getRemoteDate(dateFormat) : item.getLocalDate(dateFormat); + String fullDescription = String.format(pattern, size, date); + if (showTypeInDesc) { + fullDescription = String.format(pattern, type, fullDescription); + } + descrTextView.setText(fullDescription); } } else { @@ -209,18 +251,19 @@ public class ItemViewHolder { progressBar.setProgress(progress); if (showProgressInDesc) { - double mb = indexItem.getArchiveSizeMB(); + double mb = downloadItem.getArchiveSizeMB(); String v ; if (progress != -1) { v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb); } else { v = context.getString(R.string.file_size_in_mb, mb); } - if(showTypeInDesc && indexItem.getType() == DownloadActivityType.ROADS_FILE) { - descrTextView.setText(indexItem.getType().getString(context) + " • " + v); - } else { - descrTextView.setText(v); + String fullDescription = v; + if(showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) { + fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_bold_point, + downloadItem.getType().getString(context), fullDescription); } + descrTextView.setText(fullDescription); descrTextView.setVisibility(View.VISIBLE); } else { descrTextView.setVisibility(View.GONE); @@ -241,44 +284,7 @@ public class ItemViewHolder { } } - protected void download(IndexItem indexItem, DownloadResourceGroup parentOptional) { - boolean handled = false; - if(parentOptional != null) { - WorldRegion region = DownloadResourceGroup.getRegion(parentOptional); - context.setDownloadItem(region, indexItem.getTargetFile(context.getMyApplication()).getAbsolutePath()); - } - if (indexItem.getType() == DownloadActivityType.ROADS_FILE && parentOptional != null) { - for (IndexItem ii : parentOptional.getIndividualResources()) { - if (ii.getType() == DownloadActivityType.NORMAL_FILE) { - if (ii.isDownloaded()) { - handled = true; - confirmDownload(indexItem); - } - break; - } - } - } - if(!handled) { - context.startDownload(indexItem); - } - } - private void confirmDownload(final IndexItem indexItem) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.are_you_sure); - builder.setMessage(R.string.confirm_download_roadmaps); - builder.setNegativeButton(R.string.shared_string_cancel, null).setPositiveButton( - R.string.shared_string_download, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (indexItem != null) { - context.startDownload(indexItem); - } - } - }); - builder.show(); - } - - private boolean checkDisabledAndClickAction(final IndexItem item) { + private boolean checkDisabledAndClickAction(final DownloadItem item) { RightButtonAction clickAction = getClickAction(item); boolean disabled = clickAction != RightButtonAction.DOWNLOAD; OnClickListener action = getRightButtonAction(item, clickAction); @@ -290,15 +296,15 @@ public class ItemViewHolder { } else { rightButton.setVisibility(View.GONE); rightImageButton.setVisibility(View.VISIBLE); - final boolean isDownloading = context.getDownloadThread().isDownloading(item); + final boolean isDownloading = item.isDownloading(context.getDownloadThread()); if (isDownloading) { rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel)); - } else if(item.isDownloaded() && !item.isOutdated()) { + } else if(!item.hasActualDataToDownload()) { rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_more)); } else { - rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_import)); + rightImageButton.setImageDrawable(getContentIcon(context, getDownloadActionIconId(item))); rightImageButton.setContentDescription(context.getString(R.string.shared_string_download)); } rightImageButton.setOnClickListener(action); @@ -307,31 +313,37 @@ public class ItemViewHolder { return disabled; } + private int getDownloadActionIconId(@NonNull DownloadItem item) { + return item instanceof MultipleIndexItem ? + R.drawable.ic_action_multi_download : + R.drawable.ic_action_import; + } + @SuppressLint("DefaultLocale") - public RightButtonAction getClickAction(final IndexItem indexItem) { + public RightButtonAction getClickAction(final DownloadItem item) { RightButtonAction clickAction = RightButtonAction.DOWNLOAD; - if (indexItem.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY) + if (item.getBasename().toLowerCase().equals(DownloadResources.WORLD_SEAMARKS_KEY) && nauticalPluginDisabled) { clickAction = RightButtonAction.ASK_FOR_SEAMARKS_PLUGIN; - } else if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE - || indexItem.getType() == DownloadActivityType.HILLSHADE_FILE - || indexItem.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { + } else if ((item.getType() == DownloadActivityType.SRTM_COUNTRY_FILE + || item.getType() == DownloadActivityType.HILLSHADE_FILE + || item.getType() == DownloadActivityType.SLOPE_FILE) && srtmDisabled) { if (srtmNeedsInstallation) { clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_PURCHASE; } else { clickAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_ENABLE; } - } else if (indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE + } else if (item.getType() == DownloadActivityType.WIKIPEDIA_FILE && !Version.isPaidVersion(context.getMyApplication())) { clickAction = RightButtonAction.ASK_FOR_FULL_VERSION_PURCHASE; - } else if (indexItem.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { + } else if (item.getType() == DownloadActivityType.DEPTH_CONTOUR_FILE && !depthContoursPurchased) { clickAction = RightButtonAction.ASK_FOR_DEPTH_CONTOURS_PURCHASE; } return clickAction; } - public OnClickListener getRightButtonAction(final IndexItem item, final RightButtonAction clickAction) { + public OnClickListener getRightButtonAction(final DownloadItem item, final RightButtonAction clickAction) { if (clickAction != RightButtonAction.DOWNLOAD) { return new View.OnClickListener() { @Override @@ -370,7 +382,7 @@ public class ItemViewHolder { } }; } else { - final boolean isDownloading = context.getDownloadThread().isDownloading(item); + final boolean isDownloading = item.isDownloading(context.getDownloadThread()); return new View.OnClickListener() { @Override public void onClick(View v) { @@ -380,8 +392,8 @@ public class ItemViewHolder { } else { context.makeSureUserCancelDownload(item); } - } else if(item.isDownloaded() && !item.isOutdated()){ - contextMenu(v, item, item.getRelatedGroup()); + } else if(!item.hasActualDataToDownload()){ + showContextMenu(v, item, item.getRelatedGroup()); } else { download(item, item.getRelatedGroup()); } @@ -390,52 +402,21 @@ public class ItemViewHolder { } } - protected void contextMenu(View v, final IndexItem indexItem, final DownloadResourceGroup parentOptional) { - final PopupMenu optionsMenu = new PopupMenu(context, v); + protected void showContextMenu(View v, + final DownloadItem downloadItem, + final DownloadResourceGroup parentOptional) { + OsmandApplication app = context.getMyApplication(); + PopupMenu optionsMenu = new PopupMenu(context, v); MenuItem item; - - final File fl = indexItem.getTargetFile(context.getMyApplication()); - if (fl.exists()) { - item = optionsMenu.getMenu().add(R.string.shared_string_remove).setIcon( - context.getMyApplication().getUIUtilities().getThemedIcon(R.drawable.ic_action_remove_dark)); + + final List downloadedFiles = downloadItem.getDownloadedFiles(app); + if (!Algorithms.isEmpty(downloadedFiles)) { + item = optionsMenu.getMenu().add(R.string.shared_string_remove) + .setIcon(getThemedIcon(context, R.drawable.ic_action_remove_dark)); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - LocalIndexType tp = LocalIndexType.MAP_DATA; - if (indexItem.getType() == DownloadActivityType.HILLSHADE_FILE) { - tp = LocalIndexType.TILES_DATA; - } else if (indexItem.getType() == DownloadActivityType.SLOPE_FILE) { - tp = LocalIndexType.TILES_DATA; - } else if (indexItem.getType() == DownloadActivityType.ROADS_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) { - tp = LocalIndexType.SRTM_DATA; - } else if (indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.WIKIVOYAGE_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.TRAVEL_FILE) { - tp = LocalIndexType.MAP_DATA; - } else if (indexItem.getType() == DownloadActivityType.FONT_FILE) { - tp = LocalIndexType.FONT_DATA; - } else if (indexItem.getType() == DownloadActivityType.VOICE_FILE) { - tp = indexItem.getBasename().contains("tts") ? LocalIndexType.TTS_VOICE_DATA - : LocalIndexType.VOICE_DATA; - } - final LocalIndexInfo info = new LocalIndexInfo(tp, fl, false, context.getMyApplication()); - AlertDialog.Builder confirm = new AlertDialog.Builder(context); - confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LocalIndexOperationTask(context, null, LocalIndexOperationTask.DELETE_OPERATION) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info); - } - }); - confirm.setNegativeButton(R.string.shared_string_no, null); - String fn = FileNameTranslationHelper.getFileName(context, context.getMyApplication().getRegions(), - indexItem.getVisibleName(context, context.getMyApplication().getRegions())); - confirm.setMessage(context.getString(R.string.delete_confirmation_msg, fn)); - confirm.show(); + confirmRemove(downloadItem, downloadedFiles); return true; } }); @@ -445,14 +426,144 @@ public class ItemViewHolder { item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - download(indexItem, parentOptional); + download(downloadItem, parentOptional); return true; } }); - + optionsMenu.show(); } + protected void download(DownloadItem item, DownloadResourceGroup parentOptional) { + boolean handled = false; + if (parentOptional != null && item instanceof IndexItem) { + IndexItem indexItem = (IndexItem) item; + WorldRegion region = DownloadResourceGroup.getRegion(parentOptional); + context.setDownloadItem(region, indexItem.getTargetFile(context.getMyApplication()).getAbsolutePath()); + } + if (item.getType() == DownloadActivityType.ROADS_FILE && parentOptional != null) { + for (IndexItem ii : parentOptional.getIndividualResources()) { + if (ii.getType() == DownloadActivityType.NORMAL_FILE) { + if (ii.isDownloaded()) { + handled = true; + confirmDownload(item); + } + break; + } + } + } + if(!handled) { + startDownload(item); + } + } + private void confirmDownload(final DownloadItem item) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.are_you_sure); + builder.setMessage(R.string.confirm_download_roadmaps); + builder.setNegativeButton(R.string.shared_string_cancel, null).setPositiveButton( + R.string.shared_string_download, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (item != null) { + startDownload(item); + } + } + }); + builder.show(); + } + + private void startDownload(DownloadItem item) { + if (item instanceof MultipleIndexItem) { + MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; + List indexes; + if (multipleIndexItem.hasActualDataToDownload()) { + // download left regions + indexes = multipleIndexItem.getIndexesToDownload(); + } else { + // download all regions again + indexes = multipleIndexItem.getAllIndexes(); + } + IndexItem[] indexesArray = new IndexItem[indexes.size()]; + context.startDownload(indexes.toArray(indexesArray)); + } else if (item instanceof IndexItem) { + IndexItem indexItem = (IndexItem) item; + context.startDownload(indexItem); + } + } + + private void confirmRemove(@NonNull final DownloadItem downloadItem, + @NonNull final List downloadedFiles) { + OsmandApplication app = context.getMyApplication(); + AlertDialog.Builder confirm = new AlertDialog.Builder(context); + + String message; + if (downloadedFiles.size() > 1) { + message = context.getString(R.string.delete_number_files_question, downloadedFiles.size()); + } else { + OsmandRegions regions = app.getRegions(); + String visibleName = downloadItem.getVisibleName(context, regions); + String fileName = FileNameTranslationHelper.getFileName(context, regions, visibleName); + message = context.getString(R.string.delete_confirmation_msg, fileName); + } + confirm.setMessage(message); + + confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + LocalIndexType type = getLocalIndexType(downloadItem); + remove(type, downloadedFiles); + } + }); + confirm.setNegativeButton(R.string.shared_string_no, null); + + confirm.show(); + } + + private void remove(@NonNull LocalIndexType type, + @NonNull List filesToDelete) { + OsmandApplication app = context.getMyApplication(); + LocalIndexOperationTask removeTask = new LocalIndexOperationTask( + context, + null, + LocalIndexOperationTask.DELETE_OPERATION); + LocalIndexInfo[] params = new LocalIndexInfo[filesToDelete.size()]; + for (int i = 0; i < filesToDelete.size(); i++) { + File file = filesToDelete.get(i); + params[i] = new LocalIndexInfo(type, file, false, app); + } + removeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); + } + + @NonNull + private LocalIndexType getLocalIndexType(@NonNull DownloadItem downloadItem) { + LocalIndexType type = LocalIndexType.MAP_DATA; + if (downloadItem.getType() == DownloadActivityType.HILLSHADE_FILE) { + type = LocalIndexType.TILES_DATA; + } else if (downloadItem.getType() == DownloadActivityType.SLOPE_FILE) { + type = LocalIndexType.TILES_DATA; + } else if (downloadItem.getType() == DownloadActivityType.ROADS_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) { + type = LocalIndexType.SRTM_DATA; + } else if (downloadItem.getType() == DownloadActivityType.WIKIPEDIA_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.WIKIVOYAGE_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.TRAVEL_FILE) { + type = LocalIndexType.MAP_DATA; + } else if (downloadItem.getType() == DownloadActivityType.FONT_FILE) { + type = LocalIndexType.FONT_DATA; + } else if (downloadItem.getType() == DownloadActivityType.VOICE_FILE) { + type = downloadItem.getBasename().contains("tts") ? LocalIndexType.TTS_VOICE_DATA + : LocalIndexType.VOICE_DATA; + } + return type; + } + + private Drawable getThemedIcon(DownloadActivity context, int resourceId) { + return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); + } + private Drawable getContentIcon(DownloadActivity context, int resourceId) { return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); } diff --git a/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java index f7362edc76..faf39a56f7 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java @@ -153,7 +153,8 @@ public class UpdatesIndexFragment extends OsmAndListFragment implements Download for (IndexItem indexItem : indexItems) { downloadsSize += indexItem.getSize(); } - String updateAllText = getActivity().getString(R.string.update_all, downloadsSize >> 20); + String updateAllText = getActivity().getString( + R.string.update_all, String.valueOf(downloadsSize >> 20)); updateAllButton.setText(updateAllText); updateAllButton.setOnClickListener(new View.OnClickListener() { @Override From 454831591bd2bb06fbaee7c4d1e4aa437656950f Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 15 Feb 2021 13:39:43 +0200 Subject: [PATCH 2/3] Fix "Download all button" request after code review --- .../java/net/osmand/map/OsmandRegions.java | 7 ++--- .../main/java/net/osmand/map/WorldRegion.java | 30 ++++--------------- .../main/java/net/osmand/util/Algorithms.java | 11 +++++++ .../osmand/plus/download/DownloadItem.java | 7 ++--- .../plus/download/DownloadResourceGroup.java | 2 +- .../plus/download/DownloadResources.java | 12 ++++---- .../net/osmand/plus/download/IndexItem.java | 14 ++++----- .../plus/download/MultipleIndexItem.java | 2 +- .../plus/download/ui/ItemViewHolder.java | 7 +---- 9 files changed, 36 insertions(+), 56 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java index eba0d94b2b..882231d8a6 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/OsmandRegions.java @@ -10,7 +10,6 @@ import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.data.QuadTree; -import net.osmand.map.WorldRegion.RegionBoundingBox; import net.osmand.util.Algorithms; import net.osmand.util.MapAlgorithms; import net.osmand.util.MapUtils; @@ -463,9 +462,9 @@ public class OsmandRegions { return rd; } - private RegionBoundingBox findBoundingBox(BinaryMapDataObject object) { + private QuadRect findBoundingBox(BinaryMapDataObject object) { if (object.getPointsLength() == 0) { - return new RegionBoundingBox(0, 0, 0, 0); + return new QuadRect(0, 0, 0, 0); } double currentX = object.getPoint31XTile(0); @@ -497,7 +496,7 @@ public class OsmandRegions { double revertedMinY = MapUtils.get31LatitudeY((int) maxY); double revertedMaxY = MapUtils.get31LatitudeY((int) minY); - return new RegionBoundingBox(minX, maxX, revertedMinY, revertedMaxY); + return new QuadRect(minX, revertedMinY, maxX, revertedMaxY); } private String getSearchIndex(BinaryMapDataObject object) { diff --git a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java index e95efb4f5b..99eca34f19 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java @@ -1,6 +1,7 @@ package net.osmand.map; import net.osmand.data.LatLon; +import net.osmand.data.QuadRect; import net.osmand.util.Algorithms; import java.io.Serializable; @@ -40,7 +41,7 @@ public class WorldRegion implements Serializable { protected String regionDownloadName; protected boolean regionMapDownload; protected LatLon regionCenter; - protected RegionBoundingBox boundingBox; + protected QuadRect boundingBox; public static class RegionParams { protected String regionLeftHandDriving; @@ -184,31 +185,10 @@ public class WorldRegion implements Serializable { return res; } - public static boolean isFirstRegionInsideTheSecond(WorldRegion first, - WorldRegion second) { - RegionBoundingBox bbox1 = first.boundingBox; - RegionBoundingBox bbox2 = second.boundingBox; - if ((bbox1.minX > bbox2.minX) && (bbox1.maxX < bbox2.maxX)) { - if ((bbox1.minY > bbox2.minY) && (bbox1.maxY < bbox2.maxY)) { - return true; - } + public boolean containsRegion(WorldRegion region) { + if (this.boundingBox != null && region.boundingBox != null) { + return this.boundingBox.contains(region.boundingBox); } return false; } - - public static class RegionBoundingBox { - - double minX; - double maxX; - double minY; - double maxY; - - public RegionBoundingBox(double minX, double maxX, double minY, double maxY) { - this.minX = minX; - this.maxX = maxX; - this.minY = minY; - this.maxY = maxY; - } - - } } \ No newline at end of file diff --git a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java index a9d85ce118..83b7c14b44 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -127,6 +127,17 @@ public class Algorithms { return def; } + public static double parseDoubleSilently(String input, double def) { + if (input != null && input.length() > 0) { + try { + return Double.parseDouble(input); + } catch (NumberFormatException e) { + return def; + } + } + return def; + } + public static String getFileNameWithoutExtension(File f) { return getFileNameWithoutExtension(f.getName()); } diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java index f0a566cea6..23e9f410a7 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java @@ -35,9 +35,8 @@ public abstract class DownloadItem { @NonNull public String getSizeDescription(Context ctx) { - String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_space); String size = String.format(Locale.US, "%.2f", getSizeToDownloadInMb()); - return String.format(pattern, size, "MB"); + return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB"); } public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { @@ -48,8 +47,8 @@ public abstract class DownloadItem { return type.getVisibleName(this, ctx, osmandRegions, includingParent); } - public String getVisibleDescription(OsmandApplication clctx) { - return type.getVisibleDescription(this, clctx); + public String getVisibleDescription(OsmandApplication ctx) { + return type.getVisibleDescription(this, ctx); } public String getBasename() { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java index dc4e697cb4..5d34c95ec4 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java @@ -21,7 +21,7 @@ public class DownloadResourceGroup { private final DownloadResourceGroupType type; private final DownloadResourceGroup parentGroup; - // ASSERT: individualDisplayItems are not empty if and only if groups are empty + // ASSERT: individualDownloadItems are not empty if and only if groups are empty private final List individualDownloadItems; private final List groups; protected final String id; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java index a3aa20c79f..86c89f9cc5 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java @@ -533,13 +533,13 @@ public class DownloadResources extends DownloadResourceGroup { // collect duplicates Set duplicates = new HashSet<>(); for (int i = 0; i < regions.size() - 1; i++) { - WorldRegion firstRegion = regions.get(i); + WorldRegion r1 = regions.get(i); for (int j = i + 1; j < regions.size(); j++) { - WorldRegion secondRegion = regions.get(j); - if (WorldRegion.isFirstRegionInsideTheSecond(firstRegion, secondRegion)) { - duplicates.add(firstRegion); - } else if (WorldRegion.isFirstRegionInsideTheSecond(secondRegion, firstRegion)) { - duplicates.add(secondRegion); + WorldRegion r2 = regions.get(j); + if (r1.containsRegion(r2)) { + duplicates.add(r1); + } else if (r2.containsRegion(r1)) { + duplicates.add(r2); } } } diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index a746d4aa90..637b1f5467 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -7,13 +7,14 @@ import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.helpers.FileNameTranslationHelper; +import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; import java.io.File; import java.io.IOException; import java.text.DateFormat; -import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -58,11 +59,10 @@ public class IndexItem extends DownloadItem implements Comparable { @Override public List getDownloadedFiles(OsmandApplication app) { File targetFile = getTargetFile(app); - List result = new ArrayList<>(); if (targetFile.exists()) { - result.add(targetFile); + return Collections.singletonList(targetFile); } - return result; + return Collections.emptyList(); } public String getDescription() { @@ -91,11 +91,7 @@ public class IndexItem extends DownloadItem implements Comparable { @Override protected double getSizeToDownloadInMb() { - try { - return Double.parseDouble(size); - } catch (Exception e) { - return 0; - } + return Algorithms.parseDoubleSilently(size, 0.0); } public DownloadEntry createDownloadEntry(OsmandApplication ctx) { diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java index e28d606653..9e58db0655 100644 --- a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java @@ -104,7 +104,7 @@ public class MultipleIndexItem extends DownloadItem { double totalSizeMb = 0.0d; for (IndexItem item : items) { if (item.hasActualDataToDownload()) { - totalSizeMb += Double.parseDouble(item.size); + totalSizeMb += item.getSizeToDownloadInMb(); } } return totalSizeMb; diff --git a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java index 7fd4172fce..5c71fa342b 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java @@ -48,7 +48,6 @@ import net.osmand.util.Algorithms; import java.io.File; import java.text.DateFormat; -import java.util.ArrayList; import java.util.List; public class ItemViewHolder { @@ -412,7 +411,7 @@ public class ItemViewHolder { final List downloadedFiles = downloadItem.getDownloadedFiles(app); if (!Algorithms.isEmpty(downloadedFiles)) { item = optionsMenu.getMenu().add(R.string.shared_string_remove) - .setIcon(getThemedIcon(context, R.drawable.ic_action_remove_dark)); + .setIcon(getContentIcon(context, R.drawable.ic_action_remove_dark)); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { @@ -560,10 +559,6 @@ public class ItemViewHolder { return type; } - private Drawable getThemedIcon(DownloadActivity context, int resourceId) { - return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); - } - private Drawable getContentIcon(DownloadActivity context, int resourceId) { return context.getMyApplication().getUIUtilities().getThemedIcon(resourceId); } From 86ee2c1c9283e0b1db330dad49b081d2feeb8f4f Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 15 Feb 2021 21:45:56 +0200 Subject: [PATCH 3/3] Add dialog to choose multiple maps to download --- OsmAnd/res/layout/settings_group_title.xml | 1 + .../base/MenuBottomSheetDialogFragment.java | 2 +- .../base/SelectMultipleItemsBottomSheet.java | 301 ++++++++++++++++++ .../plus/download/DownloadActivityType.java | 8 +- .../osmand/plus/download/DownloadItem.java | 14 +- .../plus/download/DownloadResources.java | 24 +- .../net/osmand/plus/download/IndexItem.java | 10 +- .../plus/download/MultipleIndexItem.java | 4 +- .../download/MultipleIndexesUiHelper.java | 113 +++++++ .../ui/DownloadResourceGroupFragment.java | 7 +- .../plus/download/ui/ItemViewHolder.java | 57 ++-- 11 files changed, 487 insertions(+), 54 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/base/SelectMultipleItemsBottomSheet.java create mode 100644 OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java diff --git a/OsmAnd/res/layout/settings_group_title.xml b/OsmAnd/res/layout/settings_group_title.xml index 32629ed2de..456a3aace1 100644 --- a/OsmAnd/res/layout/settings_group_title.xml +++ b/OsmAnd/res/layout/settings_group_title.xml @@ -73,6 +73,7 @@ android:paddingBottom="@dimen/content_padding_small"> allItems = new ArrayList<>(); + private final List selectedItems = new ArrayList<>(); + private SelectionUpdateListener selectionUpdateListener; + private OnApplySelectionListener onApplySelectionListener; + + public static final String TAG = SelectMultipleItemsBottomSheet.class.getSimpleName(); + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { + View mainView = super.onCreateView(inflater, parent, savedInstanceState); + onSelectedItemsChanged(); + return mainView; + } + + @Override + public void createMenuItems(Bundle savedInstanceState) { + app = requiredMyApplication(); + uiUtilities = app.getUIUtilities(); + activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light; + secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light; + + items.add(createTitleItem()); + items.add(new SimpleDividerItem(app)); + createListItems(); + } + + private BaseBottomSheetItem createTitleItem() { + LayoutInflater themedInflater = UiUtilities.getInflater(requireContext(), nightMode); + View view = themedInflater.inflate(R.layout.settings_group_title, null); + + checkBox = view.findViewById(R.id.check_box); + checkBoxTitle = view.findViewById(R.id.check_box_title); + description = view.findViewById(R.id.description); + selectedSize = view.findViewById(R.id.selected_size); + title = view.findViewById(R.id.title); + View selectAllButton = view.findViewById(R.id.select_all_button); + selectAllButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkBox.performClick(); + boolean checked = checkBox.getState() == CHECKED; + if (checked) { + selectedItems.addAll(allItems); + } else { + selectedItems.clear(); + } + onSelectedItemsChanged(); + updateItems(checked); + } + }); + return new SimpleBottomSheetItem.Builder().setCustomView(view).create(); + } + + private void createListItems() { + for (final SelectableItem item : allItems) { + boolean checked = selectedItems.contains(item); + final BottomSheetItemWithCompoundButton[] uiItem = new BottomSheetItemWithCompoundButton[1]; + final Builder builder = (BottomSheetItemWithCompoundButton.Builder) new Builder(); + builder.setChecked(checked) + .setButtonTintList(AndroidUtils.createCheckedColorStateList(app, secondaryColorRes, activeColorRes)) + .setLayoutId(R.layout.bottom_sheet_item_with_descr_and_checkbox_56dp) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean checked = !uiItem[0].isChecked(); + uiItem[0].setChecked(checked); + SelectableItem tag = (SelectableItem) uiItem[0].getTag(); + if (checked) { + selectedItems.add(tag); + } else { + selectedItems.remove(tag); + } + onSelectedItemsChanged(); + } + }) + .setTag(item); + setupListItem(builder, item); + uiItem[0] = builder.create(); + items.add(uiItem[0]); + } + } + + @Override + protected void setupRightButton() { + super.setupRightButton(); + applyButtonTitle = rightButton.findViewById(R.id.button_text); + } + + @Override + protected void onRightBottomButtonClick() { + if (onApplySelectionListener != null) { + onApplySelectionListener.onSelectionApplied(selectedItems); + } + dismiss(); + } + + private void onSelectedItemsChanged() { + updateSelectAllButton(); + updateSelectedSizeView(); + updateApplyButtonEnable(); + if (selectionUpdateListener != null) { + selectionUpdateListener.onSelectionUpdate(); + } + } + + @Override + protected int getRightBottomButtonTextId() { + return R.string.shared_string_apply; + } + + @Override + protected boolean useVerticalButtons() { + return true; + } + + private void setupListItem(Builder builder, SelectableItem item) { + builder.setTitle(item.title); + builder.setDescription(item.description); + builder.setIcon(uiUtilities.getIcon(item.iconId, activeColorRes)); + } + + private void updateSelectAllButton() { + String checkBoxTitle; + if (Algorithms.isEmpty(selectedItems)) { + checkBox.setState(UNCHECKED); + checkBoxTitle = getString(R.string.shared_string_select_all); + } else { + checkBox.setState(selectedItems.containsAll(allItems) ? CHECKED : MISC); + checkBoxTitle = getString(R.string.shared_string_deselect_all); + } + int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes; + CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor))); + this.checkBoxTitle.setText(checkBoxTitle); + } + + private void updateSelectedSizeView() { + String selected = String.valueOf(selectedItems.size()); + String all = String.valueOf(allItems.size()); + selectedSize.setText(getString(R.string.ltr_or_rtl_combine_via_slash, selected, all)); + } + + private void updateApplyButtonEnable() { + if (Algorithms.isEmpty(selectedItems)) { + rightButton.setEnabled(false); + } else { + rightButton.setEnabled(true); + } + } + + private void updateItems(boolean checked) { + for (BaseBottomSheetItem item : items) { + if (item instanceof BottomSheetItemWithCompoundButton) { + ((BottomSheetItemWithCompoundButton) item).setChecked(checked); + } + } + } + + public void setTitle(@NonNull String title) { + this.title.setText(title); + } + + public void setDescription(@NonNull String description) { + this.description.setText(description); + } + + public void setConfirmButtonTitle(@NonNull String confirmButtonTitle) { + applyButtonTitle.setText(confirmButtonTitle); + } + + private void setItems(List allItems) { + if (!Algorithms.isEmpty(allItems)) { + this.allItems.addAll(allItems); + } + } + + private void setSelectedItems(List selected) { + if (!Algorithms.isEmpty(selected)) { + this.selectedItems.addAll(selected); + } + } + + public List getSelectedItems() { + return selectedItems; + } + + @Override + public void onPause() { + super.onPause(); + if (requireActivity().isChangingConfigurations()) { + dismiss(); + } + } + + public static SelectMultipleItemsBottomSheet showInstance(@NonNull AppCompatActivity activity, + @NonNull List items, + @Nullable List selected, + boolean usedOnMap) { + SelectMultipleItemsBottomSheet fragment = new SelectMultipleItemsBottomSheet(); + fragment.setUsedOnMap(usedOnMap); + fragment.setItems(items); + fragment.setSelectedItems(selected); + FragmentManager fm = activity.getSupportFragmentManager(); + fragment.show(fm, TAG); + return fragment; + } + + public void setSelectionUpdateListener(SelectionUpdateListener selectionUpdateListener) { + this.selectionUpdateListener = selectionUpdateListener; + } + + public void setOnApplySelectionListener(OnApplySelectionListener onApplySelectionListener) { + this.onApplySelectionListener = onApplySelectionListener; + } + + public interface SelectionUpdateListener { + void onSelectionUpdate(); + } + + public interface OnApplySelectionListener { + void onSelectionApplied(List selectedItems); + } + + public static class SelectableItem { + private String title; + private String description; + private int iconId; + private Object object; + + public void setTitle(String title) { + this.title = title; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setIconId(int iconId) { + this.iconId = iconId; + } + + public void setObject(Object object) { + this.object = object; + } + + public Object getObject() { + return object; + } + } + +} diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java index b78617d426..071a856454 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java @@ -2,6 +2,8 @@ package net.osmand.plus.download; import android.content.Context; +import androidx.annotation.NonNull; + import net.osmand.AndroidUtils; import net.osmand.IndexConstants; import net.osmand.map.OsmandRegions; @@ -446,9 +448,11 @@ public class DownloadActivityType { return fileName; } - - public String getBasename(DownloadItem downloadItem) { + @NonNull + public String getBasename(@NonNull DownloadItem downloadItem) { String fileName = downloadItem.getFileName(); + if (Algorithms.isEmpty(fileName)) return fileName; + if (fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.EXTRA_ZIP_EXT.length()); } diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java index 23e9f410a7..366f3554a7 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java @@ -35,8 +35,7 @@ public abstract class DownloadItem { @NonNull public String getSizeDescription(Context ctx) { - String size = String.format(Locale.US, "%.2f", getSizeToDownloadInMb()); - return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB"); + return getFormattedMb(ctx, getSizeToDownloadInMb()); } public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { @@ -51,6 +50,7 @@ public abstract class DownloadItem { return type.getVisibleDescription(this, ctx); } + @NonNull public String getBasename() { return type.getBasename(this); } @@ -65,11 +65,17 @@ public abstract class DownloadItem { public abstract boolean hasActualDataToDownload(); - public abstract boolean isDownloading(DownloadIndexesThread thread); + public abstract boolean isDownloading(@NonNull DownloadIndexesThread thread); public abstract String getFileName(); @NonNull - public abstract List getDownloadedFiles(OsmandApplication app); + public abstract List getDownloadedFiles(@NonNull OsmandApplication app); + + @NonNull + public static String getFormattedMb(@NonNull Context ctx, double sizeInMb) { + String size = String.format(Locale.US, "%.2f", sizeInMb); + return ctx.getString(R.string.ltr_or_rtl_combine_via_space, size, "MB"); + } } diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java index 86c89f9cc5..66a6621851 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java @@ -481,9 +481,10 @@ public class DownloadResources extends DownloadResourceGroup { if (group != null) { boolean listModified = false; List indexesList = group.getIndividualResources(); + List regionsToCollect = removeDuplicateRegions(subRegions); for (DownloadActivityType type : DownloadActivityType.values()) { if (!doesListContainIndexWithType(indexesList, type)) { - List indexesFromSubRegions = collectIndexesOfType(subRegions, type); + List indexesFromSubRegions = collectIndexesOfType(regionsToCollect, type); if (indexesFromSubRegions != null) { group.addItem(new MultipleIndexItem(region, indexesFromSubRegions, type)); listModified = true; @@ -510,7 +511,7 @@ public class DownloadResources extends DownloadResourceGroup { @Nullable private List collectIndexesOfType(@NonNull List regions, @NonNull DownloadActivityType type) { - Map collectedIndexes = new LinkedHashMap<>(); + List collectedIndexes = new ArrayList<>(); for (WorldRegion region : regions) { List regionIndexes = getIndexItems(region); boolean found = false; @@ -518,36 +519,33 @@ public class DownloadResources extends DownloadResourceGroup { for (IndexItem index : regionIndexes) { if (index.getType() == type) { found = true; - collectedIndexes.put(region, index); + collectedIndexes.add(index); break; } } } if (!found) return null; } - return removeDuplicates(collectedIndexes); + return collectedIndexes; } - private List removeDuplicates(Map collectedIndexes) { - List regions = new ArrayList<>(collectedIndexes.keySet()); - // collect duplicates + private List removeDuplicateRegions(List regions) { Set duplicates = new HashSet<>(); for (int i = 0; i < regions.size() - 1; i++) { WorldRegion r1 = regions.get(i); for (int j = i + 1; j < regions.size(); j++) { WorldRegion r2 = regions.get(j); if (r1.containsRegion(r2)) { - duplicates.add(r1); - } else if (r2.containsRegion(r1)) { duplicates.add(r2); + } else if (r2.containsRegion(r1)) { + duplicates.add(r1); } } } - // remove duplicates - for (WorldRegion key : duplicates) { - collectedIndexes.remove(key); + for (WorldRegion region : duplicates) { + regions.remove(region); } - return new ArrayList<>(collectedIndexes.values()); + return regions; } private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) { diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index 637b1f5467..da0103fdb0 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -57,7 +57,7 @@ public class IndexItem extends DownloadItem implements Comparable { @NonNull @Override - public List getDownloadedFiles(OsmandApplication app) { + public List getDownloadedFiles(@NonNull OsmandApplication app) { File targetFile = getTargetFile(app); if (targetFile.exists()) { return Collections.singletonList(targetFile); @@ -166,6 +166,10 @@ public class IndexItem extends DownloadItem implements Comparable { } return ""; } + + public String getDate(@NonNull DateFormat dateFormat, boolean remote) { + return remote ? getRemoteDate(dateFormat) : getLocalDate(dateFormat); + } public String getRemoteDate(DateFormat dateFormat) { if(timestamp <= 0) { @@ -175,7 +179,7 @@ public class IndexItem extends DownloadItem implements Comparable { } - public String getLocalDate(DateFormat dateFormat) { + private String getLocalDate(@NonNull DateFormat dateFormat) { if(localTimestamp <= 0) { return ""; } @@ -214,7 +218,7 @@ public class IndexItem extends DownloadItem implements Comparable { } @Override - public boolean isDownloading(DownloadIndexesThread thread) { + public boolean isDownloading(@NonNull DownloadIndexesThread thread) { return thread.isDownloading(this); } diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java index 9e58db0655..5f5ff9c297 100644 --- a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java @@ -45,7 +45,7 @@ public class MultipleIndexItem extends DownloadItem { } @Override - public boolean isDownloading(DownloadIndexesThread thread) { + public boolean isDownloading(@NonNull DownloadIndexesThread thread) { for (IndexItem item : items) { if (thread.isDownloading(item)) { return true; @@ -76,7 +76,7 @@ public class MultipleIndexItem extends DownloadItem { @NonNull @Override - public List getDownloadedFiles(OsmandApplication app) { + public List getDownloadedFiles(@NonNull OsmandApplication app) { List result = new ArrayList<>(); for (IndexItem item : items) { result.addAll(item.getDownloadedFiles(app)); diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java b/OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java new file mode 100644 index 0000000000..c7e9a05b66 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java @@ -0,0 +1,113 @@ +package net.osmand.plus.download; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import net.osmand.map.OsmandRegions; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.base.SelectMultipleItemsBottomSheet; +import net.osmand.plus.base.SelectMultipleItemsBottomSheet.OnApplySelectionListener; +import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectableItem; +import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectionUpdateListener; + +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.List; + +public class MultipleIndexesUiHelper { + + public static void showDialog(@NonNull MultipleIndexItem multipleIndexItem, + @NonNull AppCompatActivity activity, + @NonNull final OsmandApplication app, + @NonNull DateFormat dateFormat, + boolean showRemoteDate, + @NonNull final SelectItemsToDownloadListener listener) { + List indexesToDownload = getIndexesToDownload(multipleIndexItem); + List allItems = new ArrayList<>(); + List selectedItems = new ArrayList<>(); + OsmandRegions osmandRegions = app.getRegions(); + for (IndexItem indexItem : multipleIndexItem.getAllIndexes()) { + SelectableItem selectableItem = new SelectableItem(); + selectableItem.setTitle(indexItem.getVisibleName(app, osmandRegions)); + + String size = indexItem.getSizeDescription(app); + String date = indexItem.getDate(dateFormat, showRemoteDate); + String description = app.getString(R.string.ltr_or_rtl_combine_via_bold_point, size, date); + selectableItem.setDescription(description); + + selectableItem.setIconId(indexItem.getType().getIconResource()); + selectableItem.setObject(indexItem); + allItems.add(selectableItem); + + if (indexesToDownload.contains(indexItem)) { + selectedItems.add(selectableItem); + } + } + + final SelectMultipleItemsBottomSheet dialog = + SelectMultipleItemsBottomSheet.showInstance(activity, allItems, selectedItems, true); + + dialog.setSelectionUpdateListener(new SelectionUpdateListener() { + @Override + public void onSelectionUpdate() { + dialog.setTitle(app.getString(R.string.welmode_download_maps)); + String total = app.getString(R.string.shared_string_total); + double sizeToDownload = getDownloadSizeInMb(dialog.getSelectedItems()); + String size = DownloadItem.getFormattedMb(app, sizeToDownload); + String description = + app.getString(R.string.ltr_or_rtl_combine_via_colon, total, size); + dialog.setDescription(description); + String btnTitle = app.getString(R.string.shared_string_download); + if (sizeToDownload > 0) { + btnTitle = app.getString(R.string.ltr_or_rtl_combine_via_dash, btnTitle, size); + } + dialog.setConfirmButtonTitle(btnTitle); + } + }); + + dialog.setOnApplySelectionListener(new OnApplySelectionListener() { + @Override + public void onSelectionApplied(List selectedItems) { + List indexItems = new ArrayList<>(); + for (SelectableItem item : selectedItems) { + Object obj = item.getObject(); + if (obj instanceof IndexItem) { + indexItems.add((IndexItem) obj); + } + } + listener.onItemsToDownloadSelected(indexItems); + } + }); + } + + private static List getIndexesToDownload(MultipleIndexItem multipleIndexItem) { + if (multipleIndexItem.hasActualDataToDownload()) { + // download left regions + return multipleIndexItem.getIndexesToDownload(); + } else { + // download all regions again + return multipleIndexItem.getAllIndexes(); + } + } + + private static double getDownloadSizeInMb(@NonNull List selectableItems) { + List indexItems = new ArrayList<>(); + for (SelectableItem i : selectableItems) { + Object obj = i.getObject(); + if (obj instanceof IndexItem) { + indexItems.add((IndexItem) obj); + } + } + double totalSizeMb = 0.0d; + for (IndexItem item : indexItems) { + totalSizeMb += item.getSizeToDownloadInMb(); + } + return totalSizeMb; + } + + public interface SelectItemsToDownloadListener { + void onItemsToDownloadSelected(List items); + } + +} diff --git a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java index 388efca2bb..fd5d4bc365 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java @@ -35,6 +35,7 @@ import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivity.BannerAndDownloadFreeVersion; import net.osmand.plus.download.DownloadActivityType; import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents; +import net.osmand.plus.download.DownloadItem; import net.osmand.plus.download.DownloadResourceGroup; import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.DownloadValidationManager; @@ -504,10 +505,10 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow DownloadItemFragment downloadItemFragment = DownloadItemFragment.createInstance(regionId, childPosition); ((DownloadActivity) getActivity()).showDialog(getActivity(), downloadItemFragment); - } else if (child instanceof IndexItem) { - IndexItem indexItem = (IndexItem) child; + } else if (child instanceof DownloadItem) { + DownloadItem downloadItem = (DownloadItem) child; ItemViewHolder vh = (ItemViewHolder) v.getTag(); - OnClickListener ls = vh.getRightButtonAction(indexItem, vh.getClickAction(indexItem)); + OnClickListener ls = vh.getRightButtonAction(downloadItem, vh.getClickAction(downloadItem)); ls.onClick(v); return true; } diff --git a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java index 5c71fa342b..1a4449132d 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java @@ -40,6 +40,8 @@ import net.osmand.plus.download.DownloadActivityType; import net.osmand.plus.download.DownloadResourceGroup; import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.IndexItem; +import net.osmand.plus.download.MultipleIndexesUiHelper; +import net.osmand.plus.download.MultipleIndexesUiHelper.SelectItemsToDownloadListener; import net.osmand.plus.download.MultipleIndexItem; import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask; import net.osmand.plus.helpers.FileNameTranslationHelper; @@ -65,17 +67,17 @@ public class ItemViewHolder { private boolean depthContoursPurchased; protected final DownloadActivity context; - + private int textColorPrimary; private int textColorSecondary; - + boolean showTypeInDesc; boolean showTypeInName; boolean showParentRegionName; boolean showRemoteDate; boolean silentCancelDownload; boolean showProgressInDesc; - + private DateFormat dateFormat; @@ -87,7 +89,7 @@ public class ItemViewHolder { ASK_FOR_FULL_VERSION_PURCHASE, ASK_FOR_DEPTH_CONTOURS_PURCHASE } - + public ItemViewHolder(View view, DownloadActivity context) { this.context = context; @@ -110,28 +112,28 @@ public class ItemViewHolder { theme.resolveAttribute(android.R.attr.textColorSecondary, typedValue, true); textColorSecondary = typedValue.data; } - + public void setShowRemoteDate(boolean showRemoteDate) { this.showRemoteDate = showRemoteDate; } - - + + public void setShowParentRegionName(boolean showParentRegionName) { this.showParentRegionName = showParentRegionName; } - + public void setShowProgressInDescr(boolean b) { showProgressInDesc = b; } - + public void setSilentCancelDownload(boolean silentCancelDownload) { this.silentCancelDownload = silentCancelDownload; } - + public void setShowTypeInDesc(boolean showTypeInDesc) { this.showTypeInDesc = showTypeInDesc; } - + public void setShowTypeInName(boolean showTypeInName) { this.showTypeInName = showTypeInName; } @@ -236,7 +238,7 @@ public class ItemViewHolder { String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point); String type = item.getType().getString(context); String size = item.getSizeDescription(context); - String date = showRemoteDate ? item.getRemoteDate(dateFormat) : item.getLocalDate(dateFormat); + String date = item.getDate(dateFormat, showRemoteDate); String fullDescription = String.format(pattern, size, date); if (showTypeInDesc) { fullDescription = String.format(pattern, type, fullDescription); @@ -248,7 +250,7 @@ public class ItemViewHolder { progressBar.setVisibility(View.VISIBLE); progressBar.setIndeterminate(progress == -1); progressBar.setProgress(progress); - + if (showProgressInDesc) { double mb = downloadItem.getArchiveSizeMB(); String v ; @@ -267,7 +269,7 @@ public class ItemViewHolder { } else { descrTextView.setVisibility(View.GONE); } - + } } @@ -308,7 +310,7 @@ public class ItemViewHolder { } rightImageButton.setOnClickListener(action); } - + return disabled; } @@ -473,23 +475,26 @@ public class ItemViewHolder { private void startDownload(DownloadItem item) { if (item instanceof MultipleIndexItem) { - MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; - List indexes; - if (multipleIndexItem.hasActualDataToDownload()) { - // download left regions - indexes = multipleIndexItem.getIndexesToDownload(); - } else { - // download all regions again - indexes = multipleIndexItem.getAllIndexes(); - } - IndexItem[] indexesArray = new IndexItem[indexes.size()]; - context.startDownload(indexes.toArray(indexesArray)); + selectIndexesToDownload((MultipleIndexItem) item); } else if (item instanceof IndexItem) { IndexItem indexItem = (IndexItem) item; context.startDownload(indexItem); } } + private void selectIndexesToDownload(MultipleIndexItem item) { + OsmandApplication app = context.getMyApplication(); + MultipleIndexesUiHelper.showDialog(item, context, app, dateFormat, showRemoteDate, + new SelectItemsToDownloadListener() { + @Override + public void onItemsToDownloadSelected(List indexes) { + IndexItem[] indexesArray = new IndexItem[indexes.size()]; + context.startDownload(indexes.toArray(indexesArray)); + } + } + ); + } + private void confirmRemove(@NonNull final DownloadItem downloadItem, @NonNull final List downloadedFiles) { OsmandApplication app = context.getMyApplication();