From c5a9984ccd02d034e2953316cb5e2f490ed80343 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 12 Apr 2019 01:13:17 +0200 Subject: [PATCH] refactor filtering, add option to hide traces --- res/layout/bottom_map_sheet.xml | 25 ++++- res/values/strings.xml | 3 +- res/values/styles.xml | 4 + .../securesms/map/MapActivity.java | 10 +- .../securesms/map/MapDataManager.java | 92 ++++++++++--------- .../securesms/map/model/FilterProvider.java | 81 ++++++++++++++++ 6 files changed, 166 insertions(+), 49 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/map/model/FilterProvider.java diff --git a/res/layout/bottom_map_sheet.xml b/res/layout/bottom_map_sheet.xml index dbdd64325..038c28804 100644 --- a/res/layout/bottom_map_sheet.xml +++ b/res/layout/bottom_map_sheet.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="165dp" + android:layout_height="230dp" android:id="@+id/bottom_sheet" app:behavior_hideable="false" app:behavior_peekHeight="35dp" @@ -36,12 +36,13 @@ + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index a46a8b3e4..6f08c72bf 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -220,8 +220,9 @@ No contact requests.\n\nIf you want classic emails to appear here as contact requests, you can change the corresponding setting in the app settings. - Show location traces in time frame + Show locations in time frame Last position + Show traces diff --git a/res/values/styles.xml b/res/values/styles.xml index 3e8120a2e..74e2271ea 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -106,4 +106,8 @@ 12dp + + diff --git a/src/org/thoughtcrime/securesms/map/MapActivity.java b/src/org/thoughtcrime/securesms/map/MapActivity.java index bed27a00c..37cadb9f3 100644 --- a/src/org/thoughtcrime/securesms/map/MapActivity.java +++ b/src/org/thoughtcrime/securesms/map/MapActivity.java @@ -6,6 +6,7 @@ import android.os.Bundle; import android.support.design.widget.BottomSheetBehavior; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; +import android.support.v7.widget.SwitchCompat; import android.util.Log; import android.view.View; import android.widget.RelativeLayout; @@ -49,6 +50,7 @@ public class MapActivity extends BaseActivity implements Observer, TimeRangeSlid private DcLocation dcLocation; private MapDataManager mapDataManager; private MapboxMap mapboxMap; + SupportMapFragment mapFragment; @Override protected void onCreate(Bundle savedInstanceState) { @@ -64,7 +66,6 @@ public class MapActivity extends BaseActivity implements Observer, TimeRangeSlid dcLocation = DcLocation.getInstance(); - SupportMapFragment mapFragment; if (savedInstanceState == null) { final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); mapFragment = SupportMapFragment.newInstance(); @@ -165,6 +166,11 @@ public class MapActivity extends BaseActivity implements Observer, TimeRangeSlid return true; }); } + + SwitchCompat switchCompat = this.findViewById(R.id.locationTraceSwitch); + switchCompat.setOnCheckedChangeListener((buttonView, isChecked) -> { + mapDataManager.showTraces(isChecked); + }); })); TimeRangeSlider timeRangeSlider = this.findViewById(R.id.timeRangeSlider); @@ -230,7 +236,7 @@ public class MapActivity extends BaseActivity implements Observer, TimeRangeSlid if (this.mapboxMap == null) { return; } - mapDataManager.filter(startTimestamp, stopTimestamp); + mapDataManager.filterRange(startTimestamp, stopTimestamp); } diff --git a/src/org/thoughtcrime/securesms/map/MapDataManager.java b/src/org/thoughtcrime/securesms/map/MapDataManager.java index ad4baabec..ec5ef8638 100644 --- a/src/org/thoughtcrime/securesms/map/MapDataManager.java +++ b/src/org/thoughtcrime/securesms/map/MapDataManager.java @@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.ApplicationDcContext; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.map.model.FeatureTreeSet; +import org.thoughtcrime.securesms.map.model.FilterProvider; import org.thoughtcrime.securesms.map.model.MapSource; import org.thoughtcrime.securesms.map.model.TimeComparableFeature; @@ -46,22 +47,23 @@ import java.util.Map; import static com.b44t.messenger.DcContext.DC_EVENT_LOCATION_CHANGED; import static com.b44t.messenger.DcContext.DC_GCL_ADD_SELF; -import static com.mapbox.mapboxsdk.style.expressions.Expression.all; import static com.mapbox.mapboxsdk.style.expressions.Expression.eq; import static com.mapbox.mapboxsdk.style.expressions.Expression.get; -import static com.mapbox.mapboxsdk.style.expressions.Expression.gte; import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; -import static com.mapbox.mapboxsdk.style.expressions.Expression.lte; import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase; import static com.mapbox.mapboxsdk.style.expressions.Expression.toBool; import static com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_BOTTOM_LEFT; +import static com.mapbox.mapboxsdk.style.layers.Property.NONE; +import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAnchor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; import static org.thoughtcrime.securesms.map.model.MapSource.INFO_WINDOW_LAYER; + /** * Created by cyberta on 07.03.19. */ @@ -83,13 +85,15 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn private static final String TAG = MapDataManager.class.getSimpleName(); private Style mapboxStyle; - private HashMap contactMapSources; - private HashMap featureCollections; + private HashMap contactMapSources = new HashMap<>(); + private HashMap featureCollections = new HashMap<>(); + private FilterProvider filterProvider = new FilterProvider(); private Feature selectedFeature; private int chatId; private Context context; private ApplicationDcContext dcContext; private boolean isInitial = true; + private boolean showTraces = false; public interface MapDataState { void onDataInitialized(LatLngBounds bounds); @@ -100,17 +104,18 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn this.context = context; this.dcContext = DcHelper.getContext(context); this.chatId = chatId; - contactMapSources = new HashMap<>(); - featureCollections = new HashMap<>(); LatLngBounds.Builder boundingBuilder = new LatLngBounds.Builder(); int[] contactIds = getContactIds(chatId); initInfoWindowLayer(); - long now = System.currentTimeMillis(); + filterProvider.setMessageFilter(true); + filterProvider.setLastPositionFilter(System.currentTimeMillis() - DEFAULT_LAST_POSITION_DELTA); for (int contactId : contactIds) { updateSource(chatId, contactId, boundingBuilder); - filterLastPosition(contactId, now - DEFAULT_LAST_POSITION_DELTA); + MapSource source = contactMapSources.get(contactId); + applyMarkerFilter(source); + applyLineFilter(source); } dcContext.eventCenter.addObserver(DC_EVENT_LOCATION_CHANGED, this); @@ -208,36 +213,47 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn infoWindowSource.setGeoJson(selectedFeature); } - public void filter(long startTimestamp, long endTimestamp) { + public void filterRange(long startTimestamp, long endTimestamp) { int[] contactIds = getContactIds(chatId); - for (int contactId : contactIds) { - MapSource contactMapMetadata = contactMapSources.get(contactId); - SymbolLayer markerLayer = (SymbolLayer) mapboxStyle.getLayer(contactMapMetadata.getMarkerLayer()); - Expression filter = all( - lte(get(TIMESTAMP), endTimestamp), - gte(get(TIMESTAMP), startTimestamp)); - markerLayer.withFilter(filter); - LineLayer lineLayer = (LineLayer) mapboxStyle.getLayer(contactMapMetadata.getLineLayer()); - lineLayer.withFilter(filter); - } + filterProvider.setRangeFilter(startTimestamp, endTimestamp); + applyFilters(contactIds); } public void filterLastPositions(long startTimestamp) { int[] contactIds = getContactIds(chatId); + filterProvider.setLastPositionFilter(startTimestamp); + applyFilters(contactIds); + } + + public void showTraces(boolean show) { + int[] contactIds = getContactIds(chatId); + this.showTraces = show; + filterProvider.setMessageFilter(!show); + applyFilters(contactIds); + } + + private void showLineLayer(MapSource source) { + LineLayer lineLayer = (LineLayer) mapboxStyle.getLayer(source.getLineLayer()); + lineLayer.setProperties(visibility(showTraces ? VISIBLE : NONE)); + } + + private void applyFilters(int[] contactIds) { for (int contactId : contactIds) { - filterLastPosition(contactId, startTimestamp); + MapSource contactMapMetadata = contactMapSources.get(contactId); + showLineLayer(contactMapMetadata); + applyMarkerFilter(contactMapMetadata); + applyLineFilter(contactMapMetadata); } } - private void filterLastPosition(int contactId, long startTimestamp) { - MapSource contactMapMetadata = contactMapSources.get(contactId); - SymbolLayer markerLayer = (SymbolLayer) mapboxStyle.getLayer(contactMapMetadata.getMarkerLayer()); - Expression filter = all( - eq((get(LAST_LOCATION)), literal(true)), - gte(get(TIMESTAMP), startTimestamp)); - markerLayer.withFilter(filter); - LineLayer lineLayer = (LineLayer) mapboxStyle.getLayer(contactMapMetadata.getLineLayer()); - lineLayer.withFilter(filter); + private void applyMarkerFilter(MapSource source) { + SymbolLayer markerLayer = (SymbolLayer) mapboxStyle.getLayer(source.getMarkerLayer()); + markerLayer.setFilter(filterProvider.getMarkerFilter()); + } + + private void applyLineFilter(MapSource source) { + LineLayer lineLayer = (LineLayer) mapboxStyle.getLayer(source.getLineLayer()); + lineLayer.setFilter(filterProvider.getLineFilter()); } private void updateSource(int chatId, int contactId) { @@ -366,10 +382,12 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn switchCase(toBool(get(LAST_LOCATION)), literal(1.0f), switchCase(eq(get(MESSAGE_ID), literal(0)), literal(0.7f), literal(1.1f)))); Expression markerIcon = switchCase(toBool(get(LAST_LOCATION)), literal(source.getMarkerLastPositon()), literal(source.getMarkerIcon())); + mapboxStyle.addLayerBelow(new SymbolLayer(source.getMarkerLayer(), source.getMarkerSource()) .withProperties( iconImage(markerIcon), - iconSize(markerSize)), + iconSize(markerSize)) + .withFilter(filterProvider.getMarkerFilter()), INFO_WINDOW_LAYER); mapboxStyle.addLayerBelow(new LineLayer(source.getLineLayer(), source.getLineSource()) @@ -377,7 +395,8 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn PropertyFactory.lineJoin(Property.LINE_JOIN_ROUND), PropertyFactory.lineWidth(3f), PropertyFactory.lineOpacity(0.5f), - PropertyFactory.lineColor(source.getColorArgb())), + PropertyFactory.lineColor(source.getColorArgb()), + PropertyFactory.visibility(NONE)), INFO_WINDOW_LAYER); } @@ -430,15 +449,6 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn } } - private void resetSource(int contactId) { - MapSource contactMapMetadata = contactMapSources.get(contactId); - if (contactMapMetadata != null) { - featureCollections.put(contactMapMetadata.getMarkerFeatureCollection(), new FeatureTreeSet()); - GeoJsonSource pointSource = (GeoJsonSource) mapboxStyle.getSource(contactMapMetadata.getMarkerSource()); - pointSource.setGeoJson(FeatureCollection.fromFeatures(new ArrayList<>())); - } - } - private void replaceSelectedMarker(String featureId) { Feature feature = getFeatureWithId(featureId); feature.addBooleanProperty(MARKER_SELECTED, true); diff --git a/src/org/thoughtcrime/securesms/map/model/FilterProvider.java b/src/org/thoughtcrime/securesms/map/model/FilterProvider.java new file mode 100644 index 000000000..ffb42701a --- /dev/null +++ b/src/org/thoughtcrime/securesms/map/model/FilterProvider.java @@ -0,0 +1,81 @@ +package org.thoughtcrime.securesms.map.model; + +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.style.expressions.Expression; + +import java.util.HashMap; + +import static com.mapbox.mapboxsdk.style.expressions.Expression.all; +import static com.mapbox.mapboxsdk.style.expressions.Expression.eq; +import static com.mapbox.mapboxsdk.style.expressions.Expression.get; +import static com.mapbox.mapboxsdk.style.expressions.Expression.gte; +import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; +import static com.mapbox.mapboxsdk.style.expressions.Expression.lte; +import static com.mapbox.mapboxsdk.style.expressions.Expression.neq; +import static org.thoughtcrime.securesms.map.MapDataManager.LAST_LOCATION; +import static org.thoughtcrime.securesms.map.MapDataManager.MESSAGE_ID; +import static org.thoughtcrime.securesms.map.MapDataManager.TIMESTAMP; +import static org.thoughtcrime.securesms.map.model.FilterProvider.FilterType.LAST_POSITION; +import static org.thoughtcrime.securesms.map.model.FilterProvider.FilterType.MESSAGES; +import static org.thoughtcrime.securesms.map.model.FilterProvider.FilterType.RANGE; + +/** + * Created by cyberta on 11.04.19. + */ + +public class FilterProvider { + public enum FilterType { + RANGE, + LAST_POSITION, + MESSAGES + } + + private HashMap expressions = new HashMap(); + + + public void setRangeFilter(long startTimestamp, long endTimestamp) { + expressions.remove(LAST_POSITION); + addFilter(RANGE, all( + lte(get(TIMESTAMP), endTimestamp), + gte(get(TIMESTAMP), startTimestamp))); + + } + public void setLastPositionFilter(long startTimestamp) { + expressions.remove(RANGE); + addFilter(LAST_POSITION, all( + eq((get(LAST_LOCATION)), literal(true)), + gte(get(TIMESTAMP), startTimestamp))); + } + + public void setMessageFilter(boolean filter) { + if (filter) { + addFilter(MESSAGES, neq(get(MESSAGE_ID), literal(0))); + } else { + removeFilter(MESSAGES); + } + } + + private void addFilter(FilterType type, @NonNull Expression expression) { + expressions.put(type, expression); + } + + public void removeFilter(FilterType type) { + expressions.remove(type); + } + + public Expression getMarkerFilter() { + return all(expressions.values().toArray(new Expression[expressions.values().size()])); + } + + public Expression getLineFilter() { + if (expressions.get(LAST_POSITION) != null) { + return expressions.get(LAST_POSITION); + } else if (expressions.get(RANGE) != null) { + return expressions.get(RANGE); + } + + return all(); + } + +}