package net.osmand.plus.dashboard; import android.annotation.SuppressLint; import android.content.Intent; import android.content.res.Resources; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewCompat; import android.support.v7.widget.Toolbar; import android.util.TypedValue; import android.view.Gravity; import android.view.MenuItem; import android.view.View; import android.view.ViewTreeObserver; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.TranslateAnimation; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CompoundButton; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.ListView; import android.widget.ScrollView; import android.widget.TextView; import com.github.ksoichiro.android.observablescrollview.ObservableScrollView; import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks; import com.github.ksoichiro.android.observablescrollview.ScrollState; import net.osmand.AndroidUtils; import net.osmand.PlatformUtil; import net.osmand.ValueHolder; import net.osmand.data.LatLon; import net.osmand.data.RotatedTileBox; import net.osmand.plus.ApplicationMode; import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuAdapter.OnRowItemClick; import net.osmand.plus.ContextMenuItem; import net.osmand.plus.IconsCache; import net.osmand.plus.MapMarkersHelper; import net.osmand.plus.MapMarkersHelper.MapMarker; import net.osmand.plus.MapMarkersHelper.MapMarkerChangedListener; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.TargetPointsHelper.TargetPoint; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.dashboard.tools.DashFragmentData; import net.osmand.plus.dashboard.tools.DashboardSettingsDialogFragment; import net.osmand.plus.dashboard.tools.TransactionBuilder; import net.osmand.plus.dialogs.ConfigureMapMenu; import net.osmand.plus.dialogs.RasterMapMenu; import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadIndexesThread; import net.osmand.plus.download.IndexItem; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.MapMarkerDialogHelper; import net.osmand.plus.helpers.MapMarkerDialogHelper.MapMarkersDialogHelperCallbacks; import net.osmand.plus.helpers.WaypointDialogHelper; import net.osmand.plus.helpers.WaypointDialogHelper.WaypointDialogHelperCallbacks; import net.osmand.plus.helpers.WaypointHelper.LocationPointWrapper; import net.osmand.plus.mapcontextmenu.other.MapRouteInfoMenu; import net.osmand.plus.mapcontextmenu.other.RoutePreferencesMenu; import net.osmand.plus.mapcontextmenu.other.RoutePreferencesMenu.LocalRoutingParameter; import net.osmand.plus.mapillary.MapillaryPlugin; import net.osmand.plus.mapillary.MapillaryPlugin.MapillaryFirstDialogFragment; import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin; import net.osmand.plus.routing.RoutingHelper; import net.osmand.plus.routing.RoutingHelper.IRouteInformationListener; import net.osmand.plus.srtmplugin.ContourLinesMenu; import net.osmand.plus.srtmplugin.HillshadeMenu; import net.osmand.plus.srtmplugin.SRTMPlugin; import net.osmand.plus.views.DownloadedRegionsLayer; import net.osmand.plus.views.MapInfoLayer; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.controls.DynamicListView; import net.osmand.plus.views.controls.DynamicListViewCallbacks; import net.osmand.plus.views.controls.StableArrayAdapter; import net.osmand.plus.views.controls.SwipeDismissListViewTouchListener; import net.osmand.plus.views.controls.SwipeDismissListViewTouchListener.DismissCallbacks; import net.osmand.plus.views.controls.SwipeDismissListViewTouchListener.Undoable; import net.osmand.plus.views.mapwidgets.MapWidgetRegistry; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import static android.util.TypedValue.COMPLEX_UNIT_DIP; public class DashboardOnMap implements ObservableScrollViewCallbacks, DynamicListViewCallbacks, IRouteInformationListener, WaypointDialogHelperCallbacks, MapMarkersDialogHelperCallbacks, MapMarkerChangedListener { private static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(DashboardOnMap.class); private static final String TAG = "DashboardOnMap"; public static boolean staticVisible = false; public static DashboardType staticVisibleType = DashboardType.DASHBOARD; public static final String SHOULD_SHOW = "should_show"; private final DashFragmentData[] fragmentsData = new DashFragmentData[]{ new DashFragmentData(DashRateUsFragment.TAG, DashRateUsFragment.class, DashRateUsFragment.SHOULD_SHOW_FUNCTION, 0, null), new DashFragmentData(DashDashboardOrDrawerFragment.TAG, DashDashboardOrDrawerFragment.class, DashDashboardOrDrawerFragment.SHOULD_SHOW_FUNCTION, 5, null), new DashFragmentData(DashErrorFragment.TAG, DashErrorFragment.class, DashErrorFragment.SHOULD_SHOW_FUNCTION, 30, null), new DashFragmentData(DashSearchFragment.TAG, DashSearchFragment.class, DashSearchFragment.SHOULD_SHOW_FUNCTION, 35, null), new DashFragmentData(DashNavigationFragment.TAG, DashNavigationFragment.class, DashNavigationFragment.SHOULD_SHOW_FUNCTION, 40, null), new DashFragmentData(DashWaypointsFragment.TAG, DashWaypointsFragment.class, DashWaypointsFragment.SHOULD_SHOW_FUNCTION, 60, null), DashRecentsFragment.FRAGMENT_DATA, DashFavoritesFragment.FRAGMENT_DATA, new DashFragmentData(DashPluginsFragment.TAG, DashPluginsFragment.class, DashPluginsFragment.SHOULD_SHOW_FUNCTION, 140, null) }; private MapActivity mapActivity; private ImageView actionButton; private View compassButton; private FrameLayout dashboardView; private float cachedRotate = 0; private ArrayAdapter<?> listAdapter; private OnItemClickListener listAdapterOnClickListener; private SwipeDismissListViewTouchListener swipeDismissListener; private boolean visible = false; private DashboardType visibleType; private DashboardType previousVisibleType; private ApplicationMode previousAppMode; private boolean landscape; private List<WeakReference<DashBaseFragment>> fragList = new LinkedList<>(); private net.osmand.Location myLocation; private LatLon mapViewLocation; private float heading; private boolean mapLinkedToLocation; private float mapRotation; private boolean inLocationUpdate = false; private DynamicListView listView; private View listBackgroundView; private Toolbar toolbar; private View paddingView; private int mFlexibleSpaceImageHeight; private int mFlexibleBlurSpaceHeight; private boolean portrait; private long lastUpOrCancelMotionEventTime; private TextView listEmptyTextView; int baseColor; private WaypointDialogHelper waypointDialogHelper; private MapMarkerDialogHelper mapMarkerDialogHelper; private final int[] running = new int[]{-1}; private List<LocationPointWrapper> deletedPoints = new ArrayList<>(); private Drawable gradientToolbar; boolean nightMode; public DashFragmentData[] getFragmentsData() { return fragmentsData; } public enum DashboardType { WAYPOINTS, WAYPOINTS_FLAT, CONFIGURE_SCREEN, CONFIGURE_MAP, LIST_MENU, ROUTE_PREFERENCES, DASHBOARD, OVERLAY_MAP, UNDERLAY_MAP, CONTOUR_LINES, HILLSHADE, MAP_MARKERS, MAP_MARKERS_SELECTION } private Map<DashboardActionButtonType, DashboardActionButton> actionButtons = new HashMap<>(); public enum DashboardActionButtonType { MY_LOCATION, NAVIGATE, ROUTE, MARKERS_SELECTION } private class DashboardActionButton { private Drawable icon; private String text; private View.OnClickListener onClickListener; } public DashboardOnMap(MapActivity ma) { this.mapActivity = ma; } public void createDashboardView() { baseColor = ContextCompat.getColor(mapActivity, R.color.osmand_orange) & 0x00ffffff; waypointDialogHelper = new WaypointDialogHelper(mapActivity); waypointDialogHelper.setHelperCallbacks(this); mapMarkerDialogHelper = new MapMarkerDialogHelper(mapActivity); mapMarkerDialogHelper.setHelperCallbacks(this); landscape = !AndroidUiHelper.isOrientationPortrait(mapActivity); dashboardView = (FrameLayout) mapActivity.findViewById(R.id.dashboard); final View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { hideDashboard(); } }; toolbar = ((Toolbar) dashboardView.findViewById(R.id.toolbar)); ObservableScrollView scrollView = ((ObservableScrollView) dashboardView.findViewById(R.id.main_scroll)); listView = (DynamicListView) dashboardView.findViewById(R.id.dash_list_view); //listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setDrawSelectorOnTop(true); listView.setDynamicListViewCallbacks(this); listEmptyTextView = (TextView) dashboardView.findViewById(R.id.emptyTextView); // Create a ListView-specific touch listener. ListViews are given special treatment because // by default they handle touches for their list items... i.e. they're in charge of drawing // the pressed state (the list selector), handling list item clicks, etc. swipeDismissListener = new SwipeDismissListViewTouchListener( mapActivity, listView, new DismissCallbacks() { private List<Object> deletedMarkers = new ArrayList<>(); @Override public boolean canDismiss(int position) { boolean res = false; if (listAdapter instanceof StableArrayAdapter) { if (visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT) { List<Object> activeObjects = ((StableArrayAdapter) listAdapter).getActiveObjects(); Object obj = listAdapter.getItem(position); res = activeObjects.contains(obj); } else if (visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) { Object obj = listAdapter.getItem(position); res = obj instanceof MapMarker; } } return res; } @Override public Undoable onDismiss(final int position) { final Object item; final StableArrayAdapter stableAdapter; final int activeObjPos; if (listAdapter instanceof StableArrayAdapter) { stableAdapter = (StableArrayAdapter) listAdapter; item = stableAdapter.getItem(position); if (visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) { if (!((MapMarker) item).history) { deletedMarkers.add(item); } } stableAdapter.setNotifyOnChange(false); stableAdapter.remove(item); stableAdapter.getObjects().remove(item); activeObjPos = stableAdapter.getActiveObjects().indexOf(item); stableAdapter.getActiveObjects().remove(item); stableAdapter.refreshData(); stableAdapter.notifyDataSetChanged(); } else { item = null; stableAdapter = null; activeObjPos = 0; } return new Undoable() { @Override public void undo() { if (item != null) { stableAdapter.setNotifyOnChange(false); stableAdapter.insert(item, position); stableAdapter.getObjects().add(position, item); stableAdapter.getActiveObjects().add(activeObjPos, item); stableAdapter.refreshData(); if (visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT) { onItemsSwapped(stableAdapter.getActiveObjects()); } else if (visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) { deletedMarkers.remove(item); updateMapMarkers(stableAdapter.getActiveObjects()); reloadAdapter(); } } } @Override public String getTitle() { if ((visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT) && (getMyApplication().getRoutingHelper().isRoutePlanningMode() || getMyApplication().getRoutingHelper().isFollowingMode()) && item != null && stableAdapter.getActiveObjects().size() == 0) { return mapActivity.getResources().getString(R.string.cancel_navigation); } else { return null; } } }; } @Override public void onHidePopup() { if (listAdapter instanceof StableArrayAdapter) { StableArrayAdapter stableAdapter = (StableArrayAdapter) listAdapter; stableAdapter.refreshData(); if (visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT) { onItemsSwapped(stableAdapter.getActiveObjects()); } else if (visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) { updateMapMarkers(stableAdapter.getActiveObjects()); reloadAdapter(); } if (stableAdapter.getActiveObjects().size() == 0) { hideDashboard(); if (visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT) { mapActivity.getMapActions().stopNavigationWithoutConfirm(); if (getMyApplication().getSettings().USE_MAP_MARKERS.get()) { getMyApplication().getTargetPointsHelper().removeAllWayPoints(false, true); } mapActivity.getMapLayers().getMapControlsLayer().getMapRouteInfoMenu().hide(); } } } } private void updateMapMarkers(List<Object> objects) { List<MapMarker> markers = new ArrayList<>(); List<MapMarker> markersHistory = new ArrayList<>(); for (Object obj : objects) { MapMarker marker = (MapMarker) obj; if (!marker.history) { markers.add(marker); } else { markersHistory.add(marker); } } for (int i = 0; i <= deletedMarkers.size() - 1; i++) { markersHistory.add(0, (MapMarker) deletedMarkers.get(i)); } deletedMarkers.clear(); getMyApplication().getMapMarkersHelper().saveMapMarkers(markers, markersHistory); } }); gradientToolbar = ContextCompat.getDrawable(mapActivity, R.drawable.gradient_toolbar).mutate(); if (AndroidUiHelper.isOrientationPortrait(mapActivity)) { this.portrait = true; scrollView.setScrollViewCallbacks(this); listView.setScrollViewCallbacks(this); mFlexibleSpaceImageHeight = mapActivity.getResources().getDimensionPixelSize( R.dimen.dashboard_map_top_padding); mFlexibleBlurSpaceHeight = mapActivity.getResources().getDimensionPixelSize( R.dimen.dashboard_map_toolbar); // Set padding view for ListView. This is the flexible space. paddingView = new FrameLayout(mapActivity); AbsListView.LayoutParams lp = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, mFlexibleSpaceImageHeight); paddingView.setLayoutParams(lp); // This is required to disable header's list selector effect paddingView.setClickable(true); paddingView.setOnClickListener(listener); FrameLayout shadowContainer = new FrameLayout(mapActivity); FrameLayout.LayoutParams fl = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); fl.gravity = Gravity.BOTTOM; shadowContainer.setLayoutParams(fl); ImageView shadow = new ImageView(mapActivity); shadow.setImageDrawable(ContextCompat.getDrawable(mapActivity, R.drawable.bg_shadow_onmap)); shadow.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM)); shadow.setScaleType(ScaleType.FIT_XY); shadowContainer.addView(shadow); ((FrameLayout) paddingView).addView(shadowContainer); listView.addHeaderView(paddingView); listBackgroundView = mapActivity.findViewById(R.id.dash_list_background); } dashboardView.findViewById(R.id.animateContent).setOnClickListener(listener); dashboardView.findViewById(R.id.map_part_dashboard).setOnClickListener(listener); initActionButtons(); dashboardView.addView(actionButton); } @Override public void onMapMarkerChanged(MapMarker mapMarker) { if (visible && visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) { mapMarkerDialogHelper.updateMarkerView(listView, mapMarker); } } @Override public void onMapMarkersChanged() { } private void updateListBackgroundHeight() { if (listBackgroundView != null) { final View contentView = mapActivity.getWindow().getDecorView().findViewById(android.R.id.content); ViewTreeObserver vto = contentView.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ViewTreeObserver obs = contentView.getViewTreeObserver(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { obs.removeOnGlobalLayoutListener(this); } else { //noinspection deprecation obs.removeGlobalOnLayoutListener(this); } listBackgroundView.getLayoutParams().height = contentView.getHeight(); } }); } } private void updateToolbarActions() { TextView tv = (TextView) dashboardView.findViewById(R.id.toolbar_text); tv.setText(""); boolean waypointsVisible = visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT; if (waypointsVisible) { tv.setText(R.string.waypoints); } else if (visibleType == DashboardType.CONFIGURE_MAP) { tv.setText(R.string.configure_map); } else if (visibleType == DashboardType.CONFIGURE_SCREEN) { tv.setText(R.string.layer_map_appearance); } else if (visibleType == DashboardType.ROUTE_PREFERENCES) { tv.setText(R.string.shared_string_settings); } else if (visibleType == DashboardType.UNDERLAY_MAP) { tv.setText(R.string.map_underlay); } else if (visibleType == DashboardType.OVERLAY_MAP) { tv.setText(R.string.map_overlay); } else if (visibleType == DashboardType.MAP_MARKERS) { tv.setText(R.string.map_markers); } else if (visibleType == DashboardType.MAP_MARKERS_SELECTION) { tv.setText(R.string.select_map_markers); } else if (visibleType == DashboardType.CONTOUR_LINES) { tv.setText(R.string.srtm_plugin_name); } else if (visibleType == DashboardType.HILLSHADE) { tv.setText(R.string.layer_hillshade); } ImageView edit = (ImageView) dashboardView.findViewById(R.id.toolbar_edit); edit.setVisibility(View.GONE); ImageView sort = (ImageView) dashboardView.findViewById(R.id.toolbar_sort); sort.setVisibility(View.GONE); ImageView ok = (ImageView) dashboardView.findViewById(R.id.toolbar_ok); ok.setVisibility(View.GONE); ImageView flat = (ImageView) dashboardView.findViewById(R.id.toolbar_flat); flat.setVisibility(View.GONE); ImageView settingsButton = (ImageView) dashboardView.findViewById(R.id.toolbar_settings); settingsButton.setVisibility(View.GONE); IconsCache iconsCache = mapActivity.getMyApplication().getIconsCache(); ImageView lst = (ImageView) dashboardView.findViewById(R.id.toolbar_list); lst.setVisibility(View.GONE); ImageView back = (ImageView) dashboardView.findViewById(R.id.toolbar_back); back.setImageDrawable( getMyApplication().getIconsCache().getIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha)); back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { backPressed(); } }); if (waypointsVisible && getMyApplication().getWaypointHelper().getAllPoints().size() > 0) { if (getMyApplication().getWaypointHelper().isRouteCalculated()) { flat.setVisibility(View.VISIBLE); final boolean flatNow = visibleType == DashboardType.WAYPOINTS_FLAT; flat.setImageDrawable(iconsCache.getIcon(flatNow ? R.drawable.ic_tree_list_dark : R.drawable.ic_flat_list_dark)); flat.setContentDescription(mapActivity.getString(flatNow ? R.string.access_tree_list : R.string.drawer)); flat.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setDashboardVisibility(true, flatNow ? DashboardType.WAYPOINTS : DashboardType.WAYPOINTS_FLAT, previousVisibleType, false); } }); } } if (visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION && getMyApplication().getMapMarkersHelper().getMapMarkers().size() > 0) { sort.setVisibility(View.VISIBLE); sort.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mapMarkerDialogHelper.setSorted(!mapMarkerDialogHelper.isSorted()); reloadAdapter(); } }); } if (visibleType == DashboardType.DASHBOARD || visibleType == DashboardType.LIST_MENU) { settingsButton.setVisibility(View.VISIBLE); settingsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new DashboardSettingsDialogFragment().show( mapActivity.getSupportFragmentManager(), "dashboard_settings"); } }); lst.setVisibility(View.VISIBLE); lst.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { hideDashboard(false); mapActivity.openDrawer(); } }); } toolbar.getMenu().clear(); if (visibleType == DashboardType.CONFIGURE_SCREEN) { toolbar.inflateMenu(R.menu.refresh_menu); toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { if (menuItem.getItemId() == R.id.action_refresh) { MapWidgetRegistry registry = mapActivity.getMapLayers().getMapWidgetRegistry(); registry.resetToDefault(); MapInfoLayer mil = mapActivity.getMapLayers().getMapInfoLayer(); if (mil != null) { mil.recreateControls(); } updateListAdapter(registry.getViewConfigureMenuAdapter(mapActivity)); } return false; } }); } } private FrameLayout.LayoutParams getActionButtonLayoutParams(int btnSizePx) { int topPadPx = mapActivity.getResources().getDimensionPixelSize(R.dimen.dashboard_map_top_padding); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(btnSizePx, btnSizePx); int marginRight = btnSizePx / 4; params.setMargins(0, landscape ? 0 : topPadPx - 2 * btnSizePx, marginRight, landscape ? marginRight : 0); params.gravity = landscape ? Gravity.BOTTOM | Gravity.RIGHT : Gravity.TOP | Gravity.RIGHT; return params; } private void initActionButtons() { actionButton = new ImageView(mapActivity); int btnSizePx = mapActivity.getResources().getDimensionPixelSize(R.dimen.map_button_size); actionButton.setLayoutParams(getActionButtonLayoutParams(btnSizePx)); actionButton.setScaleType(ScaleType.CENTER); actionButton.setBackgroundResource(R.drawable.btn_circle_blue); hideActionButton(); DashboardActionButton myLocationButton = new DashboardActionButton(); myLocationButton.icon = ContextCompat.getDrawable(mapActivity, R.drawable.map_my_location); myLocationButton.text = mapActivity.getString(R.string.map_widget_back_to_loc); myLocationButton.onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { if (getMyApplication().accessibilityEnabled()) { mapActivity.getMapActions().whereAmIDialog(); } else { mapActivity.getMapViewTrackingUtilities().backToLocationImpl(); } hideDashboard(); } }; DashboardActionButton navigateButton = new DashboardActionButton(); navigateButton.icon = ContextCompat.getDrawable(mapActivity, R.drawable.map_start_navigation); navigateButton.text = mapActivity.getString(R.string.follow); navigateButton.onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { mapActivity.getMapLayers().getMapControlsLayer().doNavigate(); hideDashboard(); } }; DashboardActionButton routeButton = new DashboardActionButton(); routeButton.icon = ContextCompat.getDrawable(mapActivity, R.drawable.map_directions); routeButton.text = mapActivity.getString(R.string.layer_route); routeButton.onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { boolean hasTargets = false; if (visibleType == DashboardType.MAP_MARKERS_SELECTION) { TargetPointsHelper targetPointsHelper = getMyApplication().getTargetPointsHelper(); MapMarkersHelper markersHelper = getMyApplication().getMapMarkersHelper(); List<MapMarker> markers = markersHelper.getSelectedMarkers(); if (markers.size() > 0) { int i = 0; if (markersHelper.isStartFromMyLocation()) { targetPointsHelper.clearStartPoint(false); } else { MapMarker m = markers.get(i++); targetPointsHelper.setStartPoint(new LatLon(m.getLatitude(), m.getLongitude()), false, m.getPointDescription(mapActivity)); } List<TargetPoint> targetPoints = new ArrayList<>(); for (int k = i; k < markers.size(); k++) { MapMarker m = markers.get(k); TargetPoint t = new TargetPoint(new LatLon(m.getLatitude(), m.getLongitude()), m.getPointDescription(mapActivity)); targetPoints.add(t); } RoutingHelper routingHelper = mapActivity.getRoutingHelper(); boolean updateRoute = routingHelper.isFollowingMode() || routingHelper.isRoutePlanningMode(); targetPointsHelper.reorderAllTargetPoints(targetPoints, updateRoute); hasTargets = true; } else { targetPointsHelper.clearStartPoint(false); targetPointsHelper.clearPointToNavigate(false); } } hideDashboard(); mapActivity.getMapLayers().getMapControlsLayer().doRoute(hasTargets); } }; DashboardActionButton markersSelectionButton = new DashboardActionButton(); markersSelectionButton.icon = ContextCompat.getDrawable(mapActivity, R.drawable.map_start_navigation); markersSelectionButton.text = mapActivity.getString(R.string.map_markers); markersSelectionButton.onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { setDashboardVisibility(true, DashboardType.MAP_MARKERS_SELECTION); } }; actionButtons.put(DashboardActionButtonType.MY_LOCATION, myLocationButton); actionButtons.put(DashboardActionButtonType.NAVIGATE, navigateButton); actionButtons.put(DashboardActionButtonType.ROUTE, routeButton); actionButtons.put(DashboardActionButtonType.MARKERS_SELECTION, markersSelectionButton); } private void setActionButton(DashboardType type) { DashboardActionButton button = null; if (type == DashboardType.DASHBOARD || type == DashboardType.LIST_MENU || type == DashboardType.CONFIGURE_SCREEN) { button = actionButtons.get(DashboardActionButtonType.MY_LOCATION); } else if (type == DashboardType.ROUTE_PREFERENCES) { button = actionButtons.get(DashboardActionButtonType.NAVIGATE); } else if (type == DashboardType.WAYPOINTS || type == DashboardType.WAYPOINTS_FLAT) { if (isInRouteOrPlannigMode()) { button = actionButtons.get(DashboardActionButtonType.NAVIGATE); } else { button = actionButtons.get(DashboardActionButtonType.ROUTE); } } else if (type == DashboardType.MAP_MARKERS) { button = actionButtons.get(DashboardActionButtonType.MARKERS_SELECTION); } else if (type == DashboardType.MAP_MARKERS_SELECTION) { button = actionButtons.get(DashboardActionButtonType.ROUTE); } if (button != null) { actionButton.setImageDrawable(button.icon); actionButton.setContentDescription(button.text); actionButton.setOnClickListener(button.onClickListener); } } private boolean isInRouteOrPlannigMode() { boolean routePlanningMode = false; RoutingHelper rh = mapActivity.getRoutingHelper(); if (rh.isRoutePlanningMode()) { routePlanningMode = true; } else if ((rh.isRouteCalculated() || rh.isRouteBeingCalculated()) && !rh.isFollowingMode()) { routePlanningMode = true; } boolean routeFollowingMode = !routePlanningMode && rh.isFollowingMode(); return routePlanningMode || routeFollowingMode; } private void hideActionButton() { actionButton.setVisibility(View.GONE); if (compassButton != null) { compassButton.setVisibility(View.GONE); } } public net.osmand.Location getMyLocation() { return myLocation; } public LatLon getMapViewLocation() { return mapViewLocation; } public float getHeading() { return heading; } public float getMapRotation() { return mapRotation; } public boolean isMapLinkedToLocation() { return mapLinkedToLocation; } protected OsmandApplication getMyApplication() { return mapActivity.getMyApplication(); } public ArrayAdapter<?> getListAdapter() { return listAdapter; } public OnItemClickListener getListAdapterOnClickListener() { return listAdapterOnClickListener; } public void hideDashboard() { setDashboardVisibility(false, visibleType); } public void hideDashboard(boolean animation) { setDashboardVisibility(false, visibleType, animation); } public void setDashboardVisibility(boolean visible, DashboardType type) { setDashboardVisibility(visible, type, this.visible ? visibleType : null, true); } public void setDashboardVisibility(boolean visible, DashboardType type, boolean animation) { setDashboardVisibility(visible, type, this.visible ? visibleType : null, animation); } public void refreshDashboardFragments() { addOrUpdateDashboardFragments(); } public void setDashboardVisibility(boolean visible, DashboardType type, DashboardType prevItem, boolean animation) { if (visible == this.visible && type == visibleType) { return; } mapActivity.getRoutingHelper().removeListener(this); nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls(); this.previousVisibleType = prevItem; this.visible = visible; ApplicationMode currentAppMode = getMyApplication().getSettings().APPLICATION_MODE.get(); boolean appModeChanged = currentAppMode != previousAppMode; boolean refresh = this.visibleType == type && !appModeChanged; previousAppMode = currentAppMode; this.visibleType = type; DashboardOnMap.staticVisible = visible; DashboardOnMap.staticVisibleType = type; mapActivity.enableDrawer(); getMyApplication().getMapMarkersHelper().removeListener(this); if (mapActivity.getMapLayers().getMapMarkersLayer().clearRoute()) { mapActivity.refreshMap(); } if (swipeDismissListener != null) { swipeDismissListener.discardUndo(); } if (visible) { mapActivity.getContextMenu().hideMenues(); mapViewLocation = mapActivity.getMapLocation(); mapRotation = mapActivity.getMapRotate(); mapLinkedToLocation = mapActivity.getMapViewTrackingUtilities().isMapLinkedToLocation(); myLocation = mapActivity.getMyApplication().getLocationProvider().getLastKnownLocation(); mapActivity.getMapViewTrackingUtilities().setDashboard(this); mapActivity.disableDrawer(); dashboardView.setVisibility(View.VISIBLE); if (isActionButtonVisible()) { setActionButton(visibleType); actionButton.setVisibility(View.VISIBLE); } else { hideActionButton(); if (visibleType == DashboardType.CONFIGURE_MAP) { int btnSizePx = mapActivity.getResources().getDimensionPixelSize(R.dimen.map_small_button_size); compassButton = mapActivity.getMapLayers().getMapControlsLayer() .moveCompassButton(dashboardView, getActionButtonLayoutParams(btnSizePx), nightMode); } } updateDownloadBtn(); View listViewLayout = dashboardView.findViewById(R.id.dash_list_view_layout); ScrollView scrollView = (ScrollView) dashboardView.findViewById(R.id.main_scroll); if (visibleType == DashboardType.DASHBOARD) { addOrUpdateDashboardFragments(); scrollView.setVisibility(View.VISIBLE); scrollView.scrollTo(0, 0); listViewLayout.setVisibility(View.GONE); onScrollChanged(scrollView.getScrollY(), false, false); } else { scrollView.setVisibility(View.GONE); listViewLayout.setVisibility(View.VISIBLE); if (refresh) { refreshContent(false); } else { listView.scrollTo(0, 0); listView.clearParams(); onScrollChanged(listView.getScrollY(), false, false); updateListAdapter(); } updateListBackgroundHeight(); applyDayNightMode(); if (visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) { getMyApplication().getMapMarkersHelper().addListener(this); } } mapActivity.findViewById(R.id.toolbar_back).setVisibility(isBackButtonVisible() ? View.VISIBLE : View.GONE); mapActivity.findViewById(R.id.MapHudButtonsOverlay).setVisibility(View.INVISIBLE); boolean portrait = AndroidUiHelper.isOrientationPortrait(mapActivity); if (!portrait) { AndroidUiHelper.updateVisibility(mapActivity.findViewById(R.id.map_route_land_left_margin_external), true); mapActivity.getMapView().setMapPositionX(1); mapActivity.refreshMap(); } updateToolbarActions(); //fabButton.showFloatingActionButton(); open(dashboardView.findViewById(R.id.animateContent), animation); updateLocation(true, true, false); // addOrUpdateDashboardFragments(); mapActivity.getRoutingHelper().addListener(this); } else { mapActivity.getMapViewTrackingUtilities().setDashboard(null); hide(dashboardView.findViewById(R.id.animateContent), animation); if (!MapRouteInfoMenu.isVisible()) { AndroidUiHelper.updateVisibility(mapActivity.findViewById(R.id.map_route_land_left_margin_external), false); mapActivity.getMapView().setMapPositionX(0); mapActivity.getMapView().refreshMap(); } mapActivity.findViewById(R.id.MapHudButtonsOverlay).setVisibility(View.VISIBLE); hideActionButton(); for (WeakReference<DashBaseFragment> df : fragList) { if (df.get() != null) { df.get().onCloseDash(); } } OsmandSettings settings = getMyApplication().getSettings(); if (settings.SHOW_MAPILLARY.get() && !settings.MAPILLARY_FIRST_DIALOG_SHOWN.get()) { MapillaryFirstDialogFragment fragment = new MapillaryFirstDialogFragment(); fragment.show(mapActivity.getSupportFragmentManager(), MapillaryFirstDialogFragment.TAG); settings.MAPILLARY_FIRST_DIALOG_SHOWN.set(true); } } } public void updateDashboard() { if (visibleType == DashboardType.ROUTE_PREFERENCES) { refreshContent(false); } } private void applyDayNightMode() { final int backgroundColor; backgroundColor = ContextCompat.getColor(mapActivity, nightMode ? R.color.ctx_menu_info_view_bg_dark : R.color.ctx_menu_info_view_bg_light); Drawable dividerDrawable = new ColorDrawable(ContextCompat.getColor(mapActivity, nightMode ? R.color.dashboard_divider_dark : R.color.dashboard_divider_light)); if (listBackgroundView != null) { listBackgroundView.setBackgroundColor(backgroundColor); } else { // listView.setBackgroundColor(backgroundColor); listEmptyTextView.setBackgroundColor(backgroundColor); } if (visibleType != DashboardType.WAYPOINTS && visibleType != DashboardType.MAP_MARKERS && visibleType != DashboardType.MAP_MARKERS_SELECTION && visibleType != DashboardType.CONFIGURE_SCREEN && visibleType != DashboardType.CONFIGURE_MAP && visibleType != DashboardType.CONTOUR_LINES && visibleType != DashboardType.HILLSHADE) { listView.setDivider(dividerDrawable); listView.setDividerHeight(dpToPx(1f)); } else { listView.setDivider(null); } AndroidUtils.setTextSecondaryColor(mapActivity, listEmptyTextView, nightMode); } private int dpToPx(float dp) { Resources r = mapActivity.getResources(); return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); } private void updateListAdapter() { listEmptyTextView.setVisibility(View.GONE); listView.setEmptyView(null); ContextMenuAdapter cm = null; if (DashboardType.WAYPOINTS == visibleType || DashboardType.WAYPOINTS_FLAT == visibleType) { StableArrayAdapter listAdapter = waypointDialogHelper.getWaypointsDrawerAdapter(true, deletedPoints, mapActivity, running, DashboardType.WAYPOINTS_FLAT == visibleType, nightMode); OnItemClickListener listener = waypointDialogHelper.getDrawerItemClickListener(mapActivity, running, listAdapter); setDynamicListItems(listView, listAdapter); updateListAdapter(listAdapter, listener); if (listAdapter.getObjects().size() == 0) { listEmptyTextView.setText(mapActivity.getString(R.string.no_waypoints_found)); if (landscape) { listView.setEmptyView(listEmptyTextView); } else { listEmptyTextView.setVisibility(View.VISIBLE); } } } else if (DashboardType.MAP_MARKERS == visibleType || visibleType == DashboardType.MAP_MARKERS_SELECTION) { mapMarkerDialogHelper.setSelectionMode(visibleType == DashboardType.MAP_MARKERS_SELECTION); mapMarkerDialogHelper.setNightMode(nightMode); StableArrayAdapter listAdapter = mapMarkerDialogHelper.getMapMarkersListAdapter(); OnItemClickListener listener = mapMarkerDialogHelper.getItemClickListener(listAdapter); setDynamicListItems(listView, listAdapter); updateListAdapter(listAdapter, listener); if (visibleType == DashboardType.MAP_MARKERS_SELECTION) { showMarkersRouteOnMap(); } if (listAdapter.getObjects().size() == 0) { listEmptyTextView.setText(mapActivity.getString(R.string.no_map_markers_found)); if (landscape) { listView.setEmptyView(listEmptyTextView); } else { listEmptyTextView.setVisibility(View.VISIBLE); } } } else { if (visibleType == DashboardType.CONFIGURE_SCREEN) { cm = mapActivity.getMapLayers().getMapWidgetRegistry().getViewConfigureMenuAdapter(mapActivity); } else if (visibleType == DashboardType.CONFIGURE_MAP) { cm = new ConfigureMapMenu().createListAdapter(mapActivity); } else if (visibleType == DashboardType.LIST_MENU) { cm = mapActivity.getMapActions().createMainOptionsMenu(); } else if (visibleType == DashboardType.ROUTE_PREFERENCES) { RoutePreferencesMenu routePreferencesMenu = new RoutePreferencesMenu(mapActivity); ArrayAdapter<LocalRoutingParameter> listAdapter = routePreferencesMenu.getRoutePreferencesDrawerAdapter(nightMode); OnItemClickListener listener = routePreferencesMenu.getItemClickListener(listAdapter); updateListAdapter(listAdapter, listener); } else if (visibleType == DashboardType.UNDERLAY_MAP) { cm = RasterMapMenu.createListAdapter(mapActivity, OsmandRasterMapsPlugin.RasterMapType.UNDERLAY); } else if (visibleType == DashboardType.OVERLAY_MAP) { cm = RasterMapMenu.createListAdapter(mapActivity, OsmandRasterMapsPlugin.RasterMapType.OVERLAY); } else if (visibleType == DashboardType.CONTOUR_LINES) { cm = ContourLinesMenu.createListAdapter(mapActivity); } else if (visibleType == DashboardType.HILLSHADE) { cm = HillshadeMenu.createListAdapter(mapActivity); } if (cm != null) { updateListAdapter(cm); } } } public void updateListAdapter(ContextMenuAdapter cm) { boolean nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls(); if (this.nightMode != nightMode) { this.nightMode = nightMode; applyDayNightMode(); } final ArrayAdapter<ContextMenuItem> listAdapter = cm.createListAdapter(mapActivity, !nightMode); OnItemClickListener listener = getOptionsMenuOnClickListener(cm, listAdapter); updateListAdapter(listAdapter, listener); } public void onNewDownloadIndexes() { if (visibleType == DashboardType.CONTOUR_LINES || visibleType == DashboardType.HILLSHADE) { refreshContent(true); } } @SuppressWarnings("unchecked") public void onDownloadInProgress() { if (visibleType == DashboardType.CONTOUR_LINES || visibleType == DashboardType.HILLSHADE) { DownloadIndexesThread downloadThread = getMyApplication().getDownloadThread(); IndexItem downloadIndexItem = downloadThread.getCurrentDownloadingItem(); if (downloadIndexItem != null) { int downloadProgress = downloadThread.getCurrentDownloadingItemProgress(); ArrayAdapter<ContextMenuItem> adapter = (ArrayAdapter<ContextMenuItem>) listAdapter; for (int i = 0; i < adapter.getCount(); i++) { ContextMenuItem item = adapter.getItem(i); if (item != null && item.getProgressListener() != null) { item.getProgressListener().onProgressChanged( downloadIndexItem, downloadProgress, adapter, (int) adapter.getItemId(i), i); } } } } } public void onDownloadHasFinished() { if (visibleType == DashboardType.CONTOUR_LINES || visibleType == DashboardType.HILLSHADE) { refreshContent(true); if (visibleType == DashboardType.HILLSHADE) { SRTMPlugin plugin = OsmandPlugin.getEnabledPlugin(SRTMPlugin.class); if (plugin != null && plugin.isHillShadeLayerEnabled()) { plugin.registerLayers(mapActivity); } } SRTMPlugin.refreshMapComplete(mapActivity); } } public void refreshContent(boolean force) { if (visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION || visibleType == DashboardType.CONFIGURE_SCREEN || force) { updateListAdapter(); } else if (visibleType == DashboardType.CONFIGURE_MAP || visibleType == DashboardType.ROUTE_PREFERENCES) { int index = listView.getFirstVisiblePosition(); View v = listView.getChildAt(0); int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop()); updateListAdapter(); ((ListView) listView).setSelectionFromTop(index, top); } else { listAdapter.notifyDataSetChanged(); } } private void setDynamicListItems(DynamicListView listView, StableArrayAdapter listAdapter) { listView.setItemsList(listAdapter.getObjects()); if (DashboardType.WAYPOINTS == visibleType || DashboardType.WAYPOINTS_FLAT == visibleType) { listView.setActiveItemsList(listAdapter.getActiveObjects()); } else if (DashboardType.MAP_MARKERS == visibleType || visibleType == DashboardType.MAP_MARKERS_SELECTION) { List<Object> activeMarkers = new ArrayList<>(); for (Object obj : listAdapter.getActiveObjects()) { if (obj instanceof MapMarker && !((MapMarker) obj).history) { activeMarkers.add(obj); } } listView.setActiveItemsList(activeMarkers); } } private OnItemClickListener getOptionsMenuOnClickListener(final ContextMenuAdapter cm, final ArrayAdapter<ContextMenuItem> listAdapter) { return new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int which, long id) { ContextMenuItem item = cm.getItem(which); ContextMenuAdapter.ItemClickListener click = item.getItemClickListener(); if (click instanceof OnRowItemClick) { boolean cl = ((OnRowItemClick) click).onRowItemClick(listAdapter, view, item.getTitleId(), which); if (cl) { hideDashboard(); } } else if (click != null) { CompoundButton btn = (CompoundButton) view.findViewById(R.id.toggle_item); if (btn != null && btn.getVisibility() == View.VISIBLE) { btn.setChecked(!btn.isChecked()); } else { if (click.onContextMenuClick(listAdapter, item.getTitleId(), which, false)) { hideDashboard(); } } } else { if (!item.isCategory()) { hideDashboard(); } } } }; } private void updateDownloadBtn() { Button btn = (Button) dashboardView.findViewById(R.id.map_download_button); String filter = null; String txt = ""; OsmandMapTileView mv = mapActivity.getMapView(); if (mv != null && !mapActivity.getMyApplication().isApplicationInitializing()) { if (mv.getZoom() < 11 && !mapActivity.getMyApplication().getResourceManager().containsBasemap()) { filter = "basemap"; txt = mapActivity.getString(R.string.shared_string_download) + " " + mapActivity.getString(R.string.base_world_map); } else { DownloadedRegionsLayer dl = mv.getLayerByClass(DownloadedRegionsLayer.class); if (dl != null) { StringBuilder btnName = new StringBuilder(); filter = dl.getFilter(btnName); txt = btnName.toString(); } } } btn.setText(txt); btn.setVisibility(filter == null ? View.GONE : View.VISIBLE); final String f = filter; btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { hideDashboard(false); final Intent intent = new Intent(mapActivity, mapActivity.getMyApplication().getAppCustomization() .getDownloadIndexActivity()); if (f != null && !f.equals("basemap")) { intent.putExtra(DownloadActivity.FILTER_KEY, f); } intent.putExtra(DownloadActivity.TAB_TO_OPEN, DownloadActivity.DOWNLOAD_TAB); mapActivity.startActivity(intent); } }); scheduleDownloadButtonCheck(); } private void scheduleDownloadButtonCheck() { mapActivity.getMyApplication().runInUIThread(new Runnable() { @Override public void run() { if (isVisible()) { updateDownloadBtn(); } } }, 4000); } public void navigationAction() { RoutingHelper routingHelper = mapActivity.getRoutingHelper(); if (!routingHelper.isFollowingMode() && !routingHelper.isRoutePlanningMode()) { mapActivity.getMapActions().enterRoutePlanningMode(null, null); } else { mapActivity.getRoutingHelper().setRoutePlanningMode(true); mapActivity.getMapViewTrackingUtilities().switchToRoutePlanningMode(); mapActivity.refreshMap(); } hideDashboard(true); } // To animate view slide out from right to left private void open(View view, boolean animation) { if (animation) { TranslateAnimation animate = new TranslateAnimation(-mapActivity.findViewById(R.id.MapHudButtonsOverlay) .getWidth(), 0, 0, 0); animate.setDuration(500); animate.setFillAfter(true); view.startAnimation(animate); view.setVisibility(View.VISIBLE); } else { view.setVisibility(View.VISIBLE); } } private void hide(View view, boolean animation) { if (compassButton != null) { mapActivity.getMapLayers().getMapControlsLayer().restoreCompassButton(nightMode); compassButton = null; } if (!animation) { dashboardView.setVisibility(View.GONE); } else { TranslateAnimation animate = new TranslateAnimation(0, -mapActivity.findViewById(R.id.MapHudButtonsOverlay) .getWidth(), 0, 0); animate.setDuration(500); animate.setFillAfter(true); animate.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { dashboardView.setVisibility(View.GONE); } }); view.startAnimation(animate); } view.setVisibility(View.GONE); } private void addOrUpdateDashboardFragments() { OsmandSettings settings = getMyApplication().getSettings(); TransactionBuilder builder = new TransactionBuilder(mapActivity.getSupportFragmentManager(), settings, mapActivity); builder.addFragmentsData(fragmentsData) .addFragmentsData(OsmandPlugin.getPluginsCardsList()) .getFragmentTransaction().commit(); } public boolean isVisible() { return visible; } public void onDetach(DashBaseFragment dashBaseFragment) { Iterator<WeakReference<DashBaseFragment>> it = fragList.iterator(); while (it.hasNext()) { WeakReference<DashBaseFragment> wr = it.next(); if (wr.get() == dashBaseFragment) { it.remove(); } } } public void updateLocation(final boolean centerChanged, final boolean locationChanged, final boolean compassChanged) { if (inLocationUpdate) { return; } inLocationUpdate = true; mapActivity.runOnUiThread(new Runnable() { @Override public void run() { inLocationUpdate = false; for (WeakReference<DashBaseFragment> df : fragList) { if (df.get() instanceof DashLocationFragment) { ((DashLocationFragment) df.get()).updateLocation(centerChanged, locationChanged, compassChanged); } } if ((visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) && !listView.isDragging() && System.currentTimeMillis() - lastUpOrCancelMotionEventTime > 1000) { mapMarkerDialogHelper.updateLocation(listView, compassChanged); } } }); } public void updateMyLocation(net.osmand.Location location) { myLocation = location; updateLocation(false, true, false); } public void updateCompassValue(double heading) { this.heading = (float) heading; updateLocation(false, false, true); } public void onAttach(DashBaseFragment dashBaseFragment) { fragList.add(new WeakReference<>(dashBaseFragment)); } public void requestLayout() { dashboardView.requestLayout(); } public void onMenuPressed() { if (!isVisible()) { setDashboardVisibility(true, DashboardType.DASHBOARD); } else { hideDashboard(); } } public boolean onBackPressed() { if (isVisible()) { backPressed(); return true; } return false; } private void backPressed() { if (previousVisibleType != visibleType && previousVisibleType != null) { visibleType = null; setDashboardVisibility(true, previousVisibleType); } else { hideDashboard(); } } @Override public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) { // Translate list background if (portrait) { if (listBackgroundView != null) { setTranslationY(listBackgroundView, Math.max(0, -scrollY + mFlexibleSpaceImageHeight)); } } if (portrait) { setTranslationY(toolbar, Math.min(0, -scrollY + mFlexibleSpaceImageHeight - mFlexibleBlurSpaceHeight)); } updateColorOfToolbar(scrollY); updateTopButton(scrollY); } private boolean isActionButtonVisible() { return visibleType == DashboardType.DASHBOARD || visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT || visibleType == DashboardType.LIST_MENU || visibleType == DashboardType.ROUTE_PREFERENCES || visibleType == DashboardType.CONFIGURE_SCREEN || (visibleType == DashboardType.MAP_MARKERS && mapMarkerDialogHelper.hasActiveMarkers()) || (visibleType == DashboardType.MAP_MARKERS_SELECTION && mapMarkerDialogHelper.hasActiveMarkers()); } private boolean isBackButtonVisible() { return !(visibleType == DashboardType.DASHBOARD || visibleType == DashboardType.LIST_MENU); } private void updateTopButton(int scrollY) { if (actionButton != null && portrait && isActionButtonVisible()) { double scale = mapActivity.getResources().getDisplayMetrics().density; int originalPosition = mFlexibleSpaceImageHeight - (int) (80 * scale); int minTop = mFlexibleBlurSpaceHeight + (int) (5 * scale); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) actionButton.getLayoutParams(); if (minTop > originalPosition - scrollY) { hideActionButton(); } else { actionButton.setVisibility(View.VISIBLE); lp.topMargin = originalPosition - scrollY; ((FrameLayout) actionButton.getParent()).updateViewLayout(actionButton, lp); } } else if (compassButton != null) { double scale = mapActivity.getResources().getDisplayMetrics().density; int originalPosition = mFlexibleSpaceImageHeight - (int) (64 * scale); int minTop = mFlexibleBlurSpaceHeight + (int) (5 * scale); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) compassButton.getLayoutParams(); if (minTop > originalPosition - scrollY) { hideActionButton(); } else { compassButton.setVisibility(View.VISIBLE); lp.topMargin = originalPosition - scrollY; ((FrameLayout) compassButton.getParent()).updateViewLayout(compassButton, lp); } } } private void updateColorOfToolbar(int scrollY) { if (portrait) { float sh = mFlexibleSpaceImageHeight - mFlexibleBlurSpaceHeight; float t = sh == 0 ? 1 : (1 - Math.max(0, -scrollY + sh) / sh); t = Math.max(0, t); int alpha = (int) (t * 255); // in order to have proper fast scroll down int malpha = t == 1 ? 0 : alpha; setAlpha(paddingView, malpha, baseColor); setAlpha(dashboardView.findViewById(R.id.map_part_dashboard), malpha, baseColor); gradientToolbar.setAlpha((int) ((1 - t) * 255)); setAlpha(dashboardView, (int) (t * 128), 0); View toolbar = dashboardView.findViewById(R.id.toolbar); if (t < 1) { //noinspection deprecation toolbar.setBackgroundDrawable(gradientToolbar); } else { toolbar.setBackgroundColor(0xff000000 | baseColor); } } } private void updateListAdapter(ArrayAdapter<?> listAdapter, OnItemClickListener listener) { this.listAdapter = listAdapter; this.listAdapterOnClickListener = listener; if (this.listView != null) { listView.setAdapter(listAdapter); if (!portrait) { listView.setOnItemClickListener(this.listAdapterOnClickListener); } else if (this.listAdapterOnClickListener != null) { listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { listAdapterOnClickListener.onItemClick(parent, view, position - 1, id); } }); } else { listView.setOnItemClickListener(null); } } } private void setTranslationY(View v, int y) { ViewCompat.setTranslationY(v, y); } @SuppressLint("NewApi") private void setAlpha(View v, int alpha, int clr) { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // v.setAlpha(alpha/255.f); // } else { int colr = (alpha << 24) | clr; v.setBackgroundColor(colr); // } } @Override public void onDownMotionEvent() { } @Override public void onUpOrCancelMotionEvent(ScrollState scrollState) { lastUpOrCancelMotionEventTime = System.currentTimeMillis(); } public <T extends DashBaseFragment> T getFragmentByClass(Class<T> class1) { for (WeakReference<DashBaseFragment> f : fragList) { DashBaseFragment b = f.get(); if (b != null && !b.isDetached() && class1.isInstance(b)) { //noinspection unchecked return (T) b; } } return null; } public void blacklistFragmentByTag(String tag) { hideFragmentByTag(tag); getMyApplication().getSettings().registerBooleanPreference(SHOULD_SHOW + tag, true) .makeGlobal().set(false); } public void hideFragmentByTag(String tag) { FragmentManager manager = mapActivity.getSupportFragmentManager(); FragmentTransaction transaction = manager.beginTransaction(); Fragment frag = manager.findFragmentByTag(tag); transaction.hide(frag).commit(); } public void unblacklistFragmentClass(String tag) { unhideFragmentByTag(tag); getMyApplication().getSettings().registerBooleanPreference(SHOULD_SHOW + tag, true) .makeGlobal().set(true); } public void unhideFragmentByTag(String tag) { FragmentManager manager = mapActivity.getSupportFragmentManager(); FragmentTransaction transaction = manager.beginTransaction(); Fragment frag = manager.findFragmentByTag(tag); transaction.show(frag).commit(); } public void clearDeletedPoints() { deletedPoints.clear(); } View getParentView() { return dashboardView; } public static <T> List<T> handleNumberOfRows(List<T> list, OsmandSettings settings, String rowNumberTag) { int numberOfRows = settings.registerIntPreference(rowNumberTag, 3) .makeGlobal().get(); if (list.size() > numberOfRows) { while (list.size() != numberOfRows) { list.remove(numberOfRows); } } return list; } public static class DefaultShouldShow extends DashFragmentData.ShouldShowFunction { public boolean shouldShow(OsmandSettings settings, MapActivity activity, String tag) { return settings.registerBooleanPreference(SHOULD_SHOW + tag, true).makeGlobal().get(); } } @Override public void onItemSwapping(int position) { } @SuppressWarnings("unchecked") @Override public void onItemsSwapped(final List<Object> items) { getMyApplication().runInUIThread(new Runnable() { @Override public void run() { if (visibleType == DashboardType.WAYPOINTS || visibleType == DashboardType.WAYPOINTS_FLAT) { List<TargetPoint> allTargets = new ArrayList<>(); if (items != null) { for (Object obj : items) { if (obj instanceof LocationPointWrapper) { LocationPointWrapper p = (LocationPointWrapper) obj; if (p.getPoint() instanceof TargetPoint) { TargetPoint t = (TargetPoint) p.getPoint(); if (!t.start) { t.intermediate = true; allTargets.add(t); } } } } if (allTargets.size() > 0) { allTargets.get(allTargets.size() - 1).intermediate = false; } } getMyApplication().getTargetPointsHelper().reorderAllTargetPoints(allTargets, false); newRouteIsCalculated(false, new ValueHolder<Boolean>()); getMyApplication().getTargetPointsHelper().updateRouteAndRefresh(true); } else if (visibleType == DashboardType.MAP_MARKERS || visibleType == DashboardType.MAP_MARKERS_SELECTION) { List<MapMarker> markers = (List<MapMarker>) (Object) items; getMyApplication().getMapMarkersHelper().saveMapMarkers(markers, null); reloadAdapter(); } } }, 50); } @Override public void newRouteIsCalculated(boolean newRoute, ValueHolder<Boolean> showToast) { reloadAdapter(); showToast.value = false; } @Override public void routeWasCancelled() { } @Override public void routeWasFinished() { } @Override public void onWindowVisibilityChanged(int visibility) { if (visibility != View.VISIBLE && swipeDismissListener != null) { swipeDismissListener.discardUndo(); } } @Override public void reloadAdapter() { if (listAdapter != null && listAdapter instanceof StableArrayAdapter) { StableArrayAdapter stableAdapter = (StableArrayAdapter) listAdapter; if (DashboardType.WAYPOINTS == visibleType || DashboardType.WAYPOINTS_FLAT == visibleType) { waypointDialogHelper.reloadListAdapter(stableAdapter); } else if (DashboardType.MAP_MARKERS == visibleType || visibleType == DashboardType.MAP_MARKERS_SELECTION) { mapMarkerDialogHelper.reloadListAdapter(stableAdapter); if (visibleType == DashboardType.MAP_MARKERS_SELECTION) { showMarkersRouteOnMap(); } } setDynamicListItems(listView, stableAdapter); } } private void deleteSwipeItem(int position) { if (swipeDismissListener != null) { swipeDismissListener.delete(position); } } @Override public void deleteWaypoint(int position) { deleteSwipeItem(position); } @Override public void exchangeWaypoints(int pos1, int pos2) { if (swipeDismissListener != null) { swipeDismissListener.discardUndo(); } if (pos1 != -1 && pos2 != -1) { StableArrayAdapter stableAdapter = (StableArrayAdapter) listAdapter; Object item1 = stableAdapter.getActiveObjects().get(pos1); Object item2 = stableAdapter.getActiveObjects().get(pos2); stableAdapter.getActiveObjects().set(pos1, item2); stableAdapter.getActiveObjects().set(pos2, item1); stableAdapter.refreshData(); onItemsSwapped(stableAdapter.getActiveObjects()); } } @Override public void deleteMapMarker(int position) { deleteSwipeItem(position); } @Override public void showMarkersRouteOnMap() { MapMarkersHelper helper = getMyApplication().getMapMarkersHelper(); List<LatLon> points = helper.getSelectedMarkersLatLon(); mapActivity.getMapLayers().getMapMarkersLayer().setRoute(points); showRouteOnMap(points); } public void showRouteOnMap(List<LatLon> points) { if (points.size() > 0 && mapActivity != null) { OsmandMapTileView mapView = mapActivity.getMapView(); double left = 0, right = 0; double top = 0, bottom = 0; if (getMyApplication().getMapMarkersHelper().isStartFromMyLocation() && myLocation != null) { left = myLocation.getLongitude(); right = myLocation.getLongitude(); top = myLocation.getLatitude(); bottom = myLocation.getLatitude(); } for (LatLon l : points) { if (left == 0) { left = l.getLongitude(); right = l.getLongitude(); top = l.getLatitude(); bottom = l.getLatitude(); } else { left = Math.min(left, l.getLongitude()); right = Math.max(right, l.getLongitude()); top = Math.max(top, l.getLatitude()); bottom = Math.min(bottom, l.getLatitude()); } } RotatedTileBox tb = mapView.getCurrentRotatedTileBox().copy(); int tileBoxWidthPx = 0; int tileBoxHeightPx = 0; if (landscape) { tileBoxWidthPx = tb.getPixWidth() - dashboardView.getWidth(); } else if (listBackgroundView != null) { tileBoxHeightPx = 3 * (mFlexibleSpaceImageHeight - mFlexibleBlurSpaceHeight) / 4; } mapView.fitRectToMap(left, right, top, bottom, tileBoxWidthPx, tileBoxHeightPx, mFlexibleBlurSpaceHeight * 3 / 2); } } }