[android] improve map buttons fragment abstraction

Signed-off-by: Arnaud Vergnet <arnaud.vergnet@mailo.com>
This commit is contained in:
Arnaud Vergnet 2023-03-17 21:08:00 +01:00 committed by Alexander Borsuk
parent f5c2df2694
commit f3225be8fa
8 changed files with 249 additions and 192 deletions

View file

@ -26,6 +26,7 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentFactory;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.Framework.PlacePageActivationListener;
import app.organicmaps.api.Const;
@ -56,6 +57,7 @@ import app.organicmaps.location.LocationHelper;
import app.organicmaps.location.LocationListener;
import app.organicmaps.location.LocationState;
import app.organicmaps.maplayer.MapButtonsController;
import app.organicmaps.maplayer.MapButtonsViewModel;
import app.organicmaps.maplayer.Mode;
import app.organicmaps.maplayer.ToggleMapLayerFragment;
import app.organicmaps.maplayer.isolines.IsolinesManager;
@ -113,8 +115,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
NoConnectionListener,
MenuBottomSheetFragment.MenuBottomSheetInterfaceWithHeader,
PlacePageController.PlacePageRouteSettingsListener,
MapButtonsController.MapButtonClickListener,
ToggleMapLayerFragment.LayerItemClickListener,
MapButtonsController.MapButtonClickListener
{
private static final String TAG = MwmActivity.class.getSimpleName();
@ -129,8 +130,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
EditorHostFragment.class.getName(),
ReportFragment.class.getName() };
private static final String EXTRA_CURRENT_LAYOUT_MODE = "CURRENT_LAYOUT_MODE";
private static final String EXTRA_IS_FULLSCREEN = "IS_FULLSCREEN";
public static final int REQ_CODE_ERROR_DRIVING_OPTIONS_DIALOG = 5;
public static final int REQ_CODE_DRIVING_OPTIONS = 6;
private static final int REQ_CODE_ISOLINES_ERROR = 8;
@ -168,12 +167,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
private PanelAnimator mPanelAnimator;
@Nullable
private OnmapDownloader mOnmapDownloader;
@Nullable
private MapButtonsController mMapButtonsController;
private boolean mIsTabletLayout;
private boolean mIsFullscreen;
@SuppressWarnings("NotNullFieldNotInitialized")
@NonNull
private FloatingSearchToolbarController mSearchController;
@ -181,13 +175,14 @@ public class MwmActivity extends BaseMwmFragmentActivity
private boolean mRestoreRoutingPlanFragmentNeeded;
@Nullable
private Bundle mSavedForTabletState;
private MapButtonsController.LayoutMode mCurrentLayoutMode;
private String mDonatesUrl;
private int mNavBarHeight;
private PlacePageViewModel mPlacePageViewModel;
private MapButtonsViewModel mMapButtonsViewModel;
private MapButtonsController.LayoutMode mPreviousMapLayoutMode;
private Mode mPreviousLayerMode;
@Nullable
private WindowInsetsCompat mCurrentWindowInsets;
@ -359,15 +354,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
protected void onSafeCreate(@Nullable Bundle savedInstanceState)
{
super.onSafeCreate(savedInstanceState);
if (savedInstanceState != null)
{
mCurrentLayoutMode = MapButtonsController.LayoutMode.values()[savedInstanceState.getInt(EXTRA_CURRENT_LAYOUT_MODE)];
mIsFullscreen = savedInstanceState.getBoolean(EXTRA_IS_FULLSCREEN);
}
else
{
mCurrentLayoutMode = MapButtonsController.LayoutMode.regular;
}
mIsTabletLayout = getResources().getBoolean(R.bool.tabletLayout);
if (!mIsTabletLayout)
@ -377,6 +363,12 @@ public class MwmActivity extends BaseMwmFragmentActivity
UiUtils.setupTransparentStatusBar(this);
mPlacePageViewModel = new ViewModelProvider(this).get(PlacePageViewModel.class);
mMapButtonsViewModel = new ViewModelProvider(this).get(MapButtonsViewModel.class);
// We don't need to manually handle removing the observers it follows the activity lifecycle
mMapButtonsViewModel.getBottomButtonsHeight().observe(this, this::onMapBottomButtonsHeightChange);
mMapButtonsViewModel.getLayoutMode().observe(this, this::initNavigationButtons);
mPreviousLayerMode = mMapButtonsViewModel.getMapLayerMode().getValue();
mMapButtonsViewModel.getMapLayerMode().observe(this, this::onLayerChange);
mSearchController = new FloatingSearchToolbarController(this, this);
mSearchController.getToolbar()
@ -413,7 +405,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
UiUtils.setViewInsetsPaddingBottom(mPointChooser, windowInsets);
UiUtils.setViewInsetsPaddingNoBottom(mPointChooserToolbar, windowInsets);
mNavBarHeight = mIsFullscreen ? 0 : windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom;
mNavBarHeight = isFullscreen() ? 0 : windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom;
// For the first loading, set compass top margin to status bar size
// The top inset will be then be updated by the routing controller
if (mCurrentWindowInsets == null)
@ -454,7 +446,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
removeCurrentFragment(false);
}
mNavigationController = new NavigationController(this, mMapButtonsController, v -> onSettingsOptionSelected(), this::updateBottomWidgetsOffset);
mNavigationController = new NavigationController(this, v -> onSettingsOptionSelected(), this::updateBottomWidgetsOffset);
//TrafficManager.INSTANCE.attach(mNavigationController);
initMainMenu();
@ -554,7 +546,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
mPointChooserMode = mode;
closeFloatingToolbarsAndPanels(false);
UiUtils.show(mPointChooser);
mMapButtonsController.showMapButtons(false);
mMapButtonsViewModel.setButtonsHidden(true);
Framework.nativeTurnOnChoosePositionMode(isBusiness, applyPosition);
refreshLightStatusBar();
}
@ -563,7 +555,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
{
UiUtils.hide(mPointChooser);
Framework.nativeTurnOffChoosePositionMode();
mMapButtonsController.showMapButtons(true);
mMapButtonsViewModel.setButtonsHidden(false);
if (mPointChooserMode == PointChooserMode.API)
finish();
mPointChooserMode = PointChooserMode.NONE;
@ -596,31 +588,29 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void initNavigationButtons()
{
initNavigationButtons(mCurrentLayoutMode);
initNavigationButtons(mMapButtonsViewModel.getLayoutMode().getValue());
}
private void initNavigationButtons(MapButtonsController.LayoutMode layoutMode)
{
if (mMapButtonsController == null || mMapButtonsController.getLayoutMode() != layoutMode)
// Recreate the navigation buttons with the correct layout when it changes
if (mPreviousMapLayoutMode != layoutMode)
{
mCurrentLayoutMode = layoutMode;
mMapButtonsController = new MapButtonsController();
mMapButtonsController.init(
layoutMode,
LocationState.nativeGetMode(),
this::onMapButtonClick,
(v) -> closeSearchToolbar(true, true),
this::updateBottomWidgetsOffset);
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction().replace(R.id.map_buttons, mMapButtonsController);
.beginTransaction().replace(R.id.map_buttons, new MapButtonsController());
transaction.commit();
mPreviousMapLayoutMode = layoutMode;
}
}
void onMapButtonClick(MapButtonsController.MapButtons button)
@Override
public void onSearchCanceled()
{
closeSearchToolbar(true, true);
}
@Override
public void onMapButtonClick(MapButtonsController.MapButtons button)
{
switch (button)
{
@ -744,7 +734,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
if (stopSearch)
{
mSearchController.cancelSearchApiAndHide(clearText);
mMapButtonsController.resetSearch();
mMapButtonsViewModel.setSearchOption(null);
}
else
{
@ -824,8 +814,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
mNavigationController.onActivitySaveInstanceState(this, outState);
RoutingController.get().onSaveState();
outState.putInt(EXTRA_CURRENT_LAYOUT_MODE, mCurrentLayoutMode.ordinal());
outState.putBoolean(EXTRA_IS_FULLSCREEN, mIsFullscreen);
if (!isChangingConfigurations())
RoutingController.get().saveRoute();
@ -967,11 +955,11 @@ public class MwmActivity extends BaseMwmFragmentActivity
{
super.onResume();
refreshSearchToolbar();
setFullscreen(mIsFullscreen);
setFullscreen(isFullscreen());
if (Framework.nativeIsInChoosePositionMode())
{
UiUtils.show(mPointChooser);
mMapButtonsController.showMapButtons(false);
mMapButtonsViewModel.setButtonsHidden(true);
}
if (mOnmapDownloader != null)
mOnmapDownloader.onResume();
@ -1138,7 +1126,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
UiUtils.isVisible(mSearchController.getToolbar()))
return;
setFullscreen(!mIsFullscreen);
setFullscreen(!isFullscreen());
}
else
{
@ -1153,11 +1141,16 @@ public class MwmActivity extends BaseMwmFragmentActivity
|| RoutingController.get().isPlanning())
return;
mIsFullscreen = isFullscreen;
mMapButtonsController.showMapButtons(!isFullscreen);
mMapButtonsViewModel.setButtonsHidden(isFullscreen);
UiUtils.setFullscreen(this, isFullscreen);
}
private boolean isFullscreen()
{
// Buttons are hidden in position chooser mode but we are not in fullscreen
return Boolean.TRUE.equals(mMapButtonsViewModel.getButtonsHidden().getValue()) && !Framework.nativeIsInChoosePositionMode();
}
@Override
public boolean onTouch(View view, MotionEvent event)
{
@ -1190,6 +1183,10 @@ public class MwmActivity extends BaseMwmFragmentActivity
Map.onCompassUpdated(north, true);
}
public void onMapBottomButtonsHeightChange(float height) {
updateBottomWidgetsOffset();
}
public void updateBottomWidgetsOffset()
{
updateBottomWidgetsOffset(-1);
@ -1201,8 +1198,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
return;
int offsetY = mNavBarHeight;
if (mMapButtonsController != null)
offsetY = Math.max(offsetY, (int) mMapButtonsController.getBottomButtonsHeight() + mNavBarHeight);
final Float bottomButtonHeight = mMapButtonsViewModel.getBottomButtonsHeight().getValue();
if (bottomButtonHeight != null)
offsetY = Math.max(offsetY, bottomButtonHeight.intValue() + mNavBarHeight);
if (mMainMenu != null)
offsetY = Math.max(offsetY, mMainMenu.getMenuHeight());
@ -1232,17 +1230,17 @@ public class MwmActivity extends BaseMwmFragmentActivity
{
mNavigationController.show(true);
closeSearchToolbar(false, false);
mMainMenu.setState(MainMenu.State.NAVIGATION, mIsFullscreen);
mMainMenu.setState(MainMenu.State.NAVIGATION, isFullscreen());
return;
}
if (RoutingController.get().isPlanning())
{
mMainMenu.setState(MainMenu.State.ROUTE_PREPARE, mIsFullscreen);
mMainMenu.setState(MainMenu.State.ROUTE_PREPARE, isFullscreen());
return;
}
mMainMenu.setState(MainMenu.State.MENU, mIsFullscreen);
mMainMenu.setState(MainMenu.State.MENU, isFullscreen());
}
private boolean adjustMenuLineFrameVisibility()
@ -1469,7 +1467,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
mRoutingPlanInplaceController.hideDrivingOptionsView();
mNavigationController.stop(this);
initNavigationButtons(MapButtonsController.LayoutMode.regular);
mMapButtonsViewModel.setSearchOption(null);
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.regular);
refreshLightStatusBar();
}
@ -1479,7 +1478,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
closeFloatingToolbarsAndPanels(true);
ThemeSwitcher.INSTANCE.restart(isMapRendererActive());
mNavigationController.start(this);
initNavigationButtons(MapButtonsController.LayoutMode.navigation);
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.navigation);
refreshLightStatusBar();
}
@ -1487,7 +1486,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onPlanningCancelled()
{
closeFloatingToolbarsAndPanels(true);
initNavigationButtons(MapButtonsController.LayoutMode.regular);
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.regular);
refreshLightStatusBar();
}
@ -1495,7 +1494,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onPlanningStarted()
{
closeFloatingToolbarsAndPanels(true);
initNavigationButtons(MapButtonsController.LayoutMode.planning);
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.planning);
refreshLightStatusBar();
}
@ -1505,7 +1504,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
closeFloatingToolbarsAndPanels(true);
ThemeSwitcher.INSTANCE.restart(isMapRendererActive());
mNavigationController.stop(this);
initNavigationButtons(MapButtonsController.LayoutMode.planning);
mMapButtonsViewModel.setSearchOption(null);
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.planning);
refreshLightStatusBar();
}
@ -1614,7 +1614,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onMyPositionModeChanged(int newMode)
{
Logger.d(TAG, "location newMode = " + newMode);
mMapButtonsController.updateNavMyPositionButton(newMode);
mMapButtonsViewModel.setMyPositionMode(newMode);
RoutingController controller = RoutingController.get();
if (controller.isPlanning())
showAddStartOrFinishFrame(controller, true);
@ -1790,12 +1790,11 @@ public class MwmActivity extends BaseMwmFragmentActivity
shareMyLocation();
}
@Override
public void onLayerItemClick(@NonNull Mode mode)
public void onLayerChange(Mode mode)
{
closeFloatingPanels();
if (mMapButtonsController != null)
mMapButtonsController.toggleMapLayer(mode);
if (mPreviousLayerMode != mode)
closeFloatingPanels();
mPreviousLayerMode = mode;
}
@Override

View file

@ -13,7 +13,10 @@ import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.MwmActivity;
import app.organicmaps.R;
import app.organicmaps.downloader.MapManager;
import app.organicmaps.downloader.UpdateInfo;
@ -49,20 +52,28 @@ public class MapButtonsController extends Fragment
private float mContentWidth;
private MapButtonClickListener mMapButtonClickListener;
private View.OnClickListener mOnSearchCanceledListener;
private OnBottomButtonsHeightChangedListener mOnBottomButtonsHeightChangedListener;
private PlacePageViewModel mPlacePageViewModel;
private MapButtonsViewModel mMapButtonsViewModel;
private final Observer<Integer> mPlacePageDistanceToTopObserver = this::move;
private final Observer<Boolean> mButtonHiddenObserver = this::setButtonsHidden;
private final Observer<Integer> mMyPositionModeObserver = this::updateNavMyPositionButton;
private final Observer<Mode> mMapLayerModeObserver = this::toggleMapLayer;
private final Observer<SearchWheel.SearchOption> mSearchOptionObserver = this::onSearchOptionChange;
private LayoutMode mLayoutMode;
private int mMyPositionMode;
private PlacePageViewModel mViewModel;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
if (mLayoutMode == LayoutMode.navigation)
final FragmentActivity activity = requireActivity();
mMapButtonClickListener = (MwmActivity) activity;
mPlacePageViewModel = new ViewModelProvider(activity).get(PlacePageViewModel.class);
mMapButtonsViewModel = new ViewModelProvider(activity).get(MapButtonsViewModel.class);
final LayoutMode layoutMode = mMapButtonsViewModel.getLayoutMode().getValue();
if (layoutMode == LayoutMode.navigation)
mFrame = inflater.inflate(R.layout.map_buttons_layout_navigation, container, false);
else if (mLayoutMode == LayoutMode.planning)
else if (layoutMode == LayoutMode.planning)
mFrame = inflater.inflate(R.layout.map_buttons_layout_planning, container, false);
else
mFrame = inflater.inflate(R.layout.map_buttons_layout_regular, container, false);
@ -76,44 +87,51 @@ public class MapButtonsController extends Fragment
{
helpButton.setImageResource(R.drawable.logo);
// Keep this button colorful in normal theme.
if (!ThemeUtils.isNightTheme(getContext()))
if (!ThemeUtils.isNightTheme(requireContext()))
helpButton.getDrawable().setTintList(null);
}
final View zoomFrame = mFrame.findViewById(R.id.zoom_buttons_container);
mFrame.findViewById(R.id.nav_zoom_in)
.setOnClickListener((v) -> mMapButtonClickListener.onClick(MapButtons.zoomIn));
.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomIn));
mFrame.findViewById(R.id.nav_zoom_out)
.setOnClickListener((v) -> mMapButtonClickListener.onClick(MapButtons.zoomOut));
.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomOut));
final View bookmarksButton = mFrame.findViewById(R.id.btn_bookmarks);
bookmarksButton.setOnClickListener((v) -> mMapButtonClickListener.onClick(MapButtons.bookmarks));
bookmarksButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.bookmarks));
final View myPosition = mFrame.findViewById(R.id.my_position);
mNavMyPosition = new MyPositionButton(myPosition, mMyPositionMode, (v) -> mMapButtonClickListener.onClick(MapButtons.myPosition));
mNavMyPosition = new MyPositionButton(myPosition, (v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.myPosition));
// Some buttons do not exist in navigation mode
final FloatingActionButton layersButton = mFrame.findViewById(R.id.layers_button);
if (layersButton != null)
{
mToggleMapLayerController = new MapLayersController(layersButton,
() -> mMapButtonClickListener.onClick(MapButtons.toggleMapLayer), requireActivity());
mToggleMapLayerController = new MapLayersController(
layersButton,
() -> mMapButtonClickListener.onMapButtonClick(MapButtons.toggleMapLayer),
requireActivity(),
mMapButtonsViewModel);
}
final View menuButton = mFrame.findViewById(R.id.menu_button);
if (menuButton != null)
{
menuButton.setOnClickListener((v) -> mMapButtonClickListener.onClick(MapButtons.menu));
menuButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.menu));
// This hack is needed to show the badge on the initial startup. For some reason, updateMenuBadge does not work from onResume() there.
menuButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
public void onGlobalLayout()
{
updateMenuBadge();
menuButton.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
if (helpButton != null)
helpButton.setOnClickListener((v) -> mMapButtonClickListener.onClick(MapButtons.help));
helpButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.help));
mSearchWheel = new SearchWheel(mFrame, (v) -> mMapButtonClickListener.onClick(MapButtons.search), mOnSearchCanceledListener);
mSearchWheel = new SearchWheel(mFrame,
(v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.search),
(v) -> mMapButtonClickListener.onSearchCanceled(),
mMapButtonsViewModel);
final View searchButton = mFrame.findViewById(R.id.btn_search);
// Used to get the maximum height the buttons will evolve in
@ -136,26 +154,9 @@ public class MapButtonsController extends Fragment
UiUtils.setViewInsetsPadding(view, windowInsets);
return windowInsets;
});
mViewModel = new ViewModelProvider(requireActivity()).get(PlacePageViewModel.class);
return mFrame;
}
public LayoutMode getLayoutMode()
{
return mLayoutMode;
}
public void init(LayoutMode layoutMode, int myPositionMode, MapButtonClickListener mapButtonClickListener, @NonNull View.OnClickListener onSearchCanceledListener, OnBottomButtonsHeightChangedListener onBottomButtonsHeightChangedListener)
{
mLayoutMode = layoutMode;
mMyPositionMode = myPositionMode;
mMapButtonClickListener = mapButtonClickListener;
mOnSearchCanceledListener = onSearchCanceledListener;
mOnBottomButtonsHeightChangedListener = onBottomButtonsHeightChangedListener;
}
public void showButton(boolean show, MapButtonsController.MapButtons button)
{
// TODO(AB): Why do we need this check? Isn't it better to crash and fix the wrong logic ASAP?
@ -211,10 +212,12 @@ public class MapButtonsController extends Fragment
private boolean isBehindPlacePage(View v)
{
if (mViewModel == null)
if (mPlacePageViewModel == null)
return false;
final int placePageWidth = mViewModel.getPlacePageWidth().getValue();
return !(mContentWidth / 2 > (placePageWidth / 2.0) + v.getWidth());
final Integer placePageWidth = mPlacePageViewModel.getPlacePageWidth().getValue();
if (placePageWidth != null)
return !(mContentWidth / 2 > (placePageWidth.floatValue() / 2.0) + v.getWidth());
return true;
}
private boolean isMoving(View v)
@ -264,7 +267,7 @@ public class MapButtonsController extends Fragment
}
}
public float getBottomButtonsHeight()
private float getBottomButtonsHeight()
{
if (mBottomButtonsFrame != null && mFrame != null && UiUtils.isVisible(mFrame))
return mBottomButtonsFrame.getMeasuredHeight();
@ -272,16 +275,12 @@ public class MapButtonsController extends Fragment
return 0;
}
public void showMapButtons(boolean show)
public void setButtonsHidden(boolean buttonHidden)
{
if (show)
{
UiUtils.show(mFrame);
UiUtils.showIf(!buttonHidden, mFrame);
if (!buttonHidden)
updateButtonsVisibility();
}
else
UiUtils.hide(mFrame);
mOnBottomButtonsHeightChangedListener.OnBottomButtonsHeightChanged();
mMapButtonsViewModel.setBottomButtonsHeight(getBottomButtonsHeight());
}
private boolean isInNavigationMode()
@ -289,10 +288,15 @@ public class MapButtonsController extends Fragment
return RoutingController.get().isPlanning() || RoutingController.get().isNavigating();
}
public void toggleMapLayer(@NonNull Mode mode)
public void toggleMapLayer(@Nullable Mode mode)
{
if (mToggleMapLayerController != null)
mToggleMapLayerController.toggleMode(mode);
{
if (mode == null)
mToggleMapLayerController.disableModes();
else
mToggleMapLayerController.enableMode(mode);
}
}
public void updateNavMyPositionButton(int newMode)
@ -307,32 +311,39 @@ public class MapButtonsController extends Fragment
}
@Override
public void onPause()
public void onStart()
{
super.onPause();
mViewModel.getPlacePageDistanceToTop().removeObserver(this::move);
super.onStart();
final FragmentActivity activity = requireActivity();
mPlacePageViewModel.getPlacePageDistanceToTop().observe(activity, mPlacePageDistanceToTopObserver);
mMapButtonsViewModel.getButtonsHidden().observe(activity, mButtonHiddenObserver);
mMapButtonsViewModel.getMyPositionMode().observe(activity, mMyPositionModeObserver);
mMapButtonsViewModel.getMapLayerMode().observe(activity, mMapLayerModeObserver);
mMapButtonsViewModel.getSearchOption().observe(activity, mSearchOptionObserver);
}
public void onResume()
{
super.onResume();
mViewModel.getPlacePageDistanceToTop().observe(requireActivity(), this::move);
mSearchWheel.onResume();
updateMenuBadge();
}
public void resetSearch()
@Override
public void onStop()
{
mSearchWheel.reset();
super.onStop();
mPlacePageViewModel.getPlacePageDistanceToTop().removeObserver(mPlacePageDistanceToTopObserver);
mMapButtonsViewModel.getButtonsHidden().removeObserver(mButtonHiddenObserver);
mMapButtonsViewModel.getMyPositionMode().removeObserver(mMyPositionModeObserver);
mMapButtonsViewModel.getMapLayerMode().removeObserver(mMapLayerModeObserver);
mMapButtonsViewModel.getSearchOption().removeObserver(mSearchOptionObserver);
}
public void saveNavSearchState(@NonNull Bundle outState)
public void onSearchOptionChange(@Nullable SearchWheel.SearchOption searchOption)
{
mSearchWheel.saveState(outState);
}
public void restoreNavSearchState(@NonNull Bundle savedInstanceState)
{
mSearchWheel.restoreState(savedInstanceState);
if (searchOption == null)
mSearchWheel.reset();
}
public enum LayoutMode
@ -357,12 +368,9 @@ public class MapButtonsController extends Fragment
public interface MapButtonClickListener
{
void onClick(MapButtons button);
}
void onMapButtonClick(MapButtons button);
public interface OnBottomButtonsHeightChangedListener
{
void OnBottomButtonsHeightChanged();
void onSearchCanceled();
}
private class ContentViewLayoutChangeListener implements View.OnLayoutChangeListener
@ -381,7 +389,7 @@ public class MapButtonsController extends Fragment
{
mContentHeight = bottom - top;
mContentWidth = right - left;
mOnBottomButtonsHeightChangedListener.OnBottomButtonsHeightChanged();
mMapButtonsViewModel.setBottomButtonsHeight(getBottomButtonsHeight());
mContentView.removeOnLayoutChangeListener(this);
}
}

View file

@ -0,0 +1,75 @@
package app.organicmaps.maplayer;
import androidx.annotation.Nullable;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MapButtonsViewModel extends ViewModel
{
private final MutableLiveData<Boolean> mButtonsHidden = new MutableLiveData<>(false);
private final MutableLiveData<Float> mBottomButtonsHeight = new MutableLiveData<>(0f);
private final MutableLiveData<MapButtonsController.LayoutMode> mLayoutMode = new MutableLiveData<>(MapButtonsController.LayoutMode.regular);
private final MutableLiveData<Integer> mMyPositionMode = new MutableLiveData<>();
private final MutableLiveData<Mode> mMapLayerMode = new MutableLiveData<>();
private final MutableLiveData<SearchWheel.SearchOption> mSearchOption = new MutableLiveData<>();
public MutableLiveData<Boolean> getButtonsHidden()
{
return mButtonsHidden;
}
public void setButtonsHidden(boolean buttonsHidden)
{
mButtonsHidden.setValue(buttonsHidden);
}
public MutableLiveData<Float> getBottomButtonsHeight()
{
return mBottomButtonsHeight;
}
public void setBottomButtonsHeight(float height)
{
mBottomButtonsHeight.setValue(height);
}
public MutableLiveData<MapButtonsController.LayoutMode> getLayoutMode()
{
return mLayoutMode;
}
public void setLayoutMode(MapButtonsController.LayoutMode layoutMode)
{
mLayoutMode.setValue(layoutMode);
}
public MutableLiveData<Integer> getMyPositionMode()
{
return mMyPositionMode;
}
public void setMyPositionMode(int mode)
{
mMyPositionMode.setValue(mode);
}
public MutableLiveData<Mode> getMapLayerMode()
{
return mMapLayerMode;
}
public void setMapLayerMode(Mode mode)
{
mMapLayerMode.setValue(mode);
}
public MutableLiveData<SearchWheel.SearchOption> getSearchOption()
{
return mSearchOption;
}
public void setSearchOption(@Nullable SearchWheel.SearchOption searchOption)
{
mSearchOption.setValue(searchOption);
}
}

View file

@ -23,21 +23,19 @@ public class MapLayersController
OnShowMenuListener mOnShowMenuListener;
@NonNull
private Mode mCurrentLayer;
private final MapButtonsViewModel mMapButtonsViewModel;
public MapLayersController(@NonNull ImageButton layersButton, @NonNull OnShowMenuListener onShowMenuListener, @NonNull Activity activity)
public MapLayersController(@NonNull ImageButton layersButton, @NonNull OnShowMenuListener onShowMenuListener, @NonNull Activity activity, MapButtonsViewModel mapButtonsViewModel)
{
mActivity = activity;
mMapButtonsViewModel = mapButtonsViewModel;
mLayersButton = layersButton;
mLayersButton.setOnClickListener(view -> onLayersButtonClick());
mOnShowMenuListener = onShowMenuListener;
mLayers = LayersUtils.getAvailableLayers();
mCurrentLayer = getCurrentLayer();
initMode();
}
private void initMode()
{
setEnabled(mCurrentLayer.isEnabled(mActivity));
// View model only expects a layer if it is active
mMapButtonsViewModel.setMapLayerMode(mCurrentLayer.isEnabled(activity) ? mCurrentLayer : null);
showButton(true);
}
@ -76,16 +74,21 @@ public class MapLayersController
private void onLayersButtonClick()
{
if (mCurrentLayer.isEnabled(mActivity))
setEnabled(false);
mMapButtonsViewModel.setMapLayerMode(null);
else
mOnShowMenuListener.onShow();
}
public void toggleMode(@NonNull Mode mode)
public void disableModes()
{
setEnabled(false);
}
public void enableMode(@NonNull Mode mode)
{
setCurrentLayer(mode);
showButton(true);
setEnabled(!mode.isEnabled(mActivity));
setEnabled(true);
}
public void showButton(boolean show)

View file

@ -26,7 +26,6 @@ import app.organicmaps.util.concurrency.UiThread;
public class SearchWheel implements View.OnClickListener
{
private static final String EXTRA_CURRENT_OPTION = "extra_current_option";
private final View mFrame;
private View mSearchLayout;
@ -35,12 +34,11 @@ public class SearchWheel implements View.OnClickListener
private final View mTouchInterceptor;
private boolean mIsExpanded;
@Nullable
private SearchOption mCurrentOption;
@NonNull
private final View.OnClickListener mOnSearchPressedListener;
@NonNull
private final View.OnClickListener mOnSearchCanceledListener;
private MapButtonsViewModel mMapButtonsViewModel;
private static final long CLOSE_DELAY_MILLIS = 5000L;
private final Runnable mCloseRunnable = new Runnable() {
@ -55,7 +53,7 @@ public class SearchWheel implements View.OnClickListener
}
};
private enum SearchOption
public enum SearchOption
{
FUEL(R.id.search_fuel, R.drawable.ic_routing_fuel_off, R.string.fuel),
PARKING(R.id.search_parking, R.drawable.ic_routing_parking_off, R.string.parking),
@ -103,9 +101,11 @@ public class SearchWheel implements View.OnClickListener
}
}
public SearchWheel(View frame, @NonNull View.OnClickListener onSearchPressedListener, @NonNull View.OnClickListener onSearchCanceledListener)
public SearchWheel(View frame, @NonNull View.OnClickListener onSearchPressedListener,
@NonNull View.OnClickListener onSearchCanceledListener, MapButtonsViewModel mapButtonsViewModel)
{
mFrame = frame;
mMapButtonsViewModel = mapButtonsViewModel;
mOnSearchPressedListener = onSearchPressedListener;
mOnSearchCanceledListener = onSearchCanceledListener;
mTouchInterceptor = mFrame.findViewById(R.id.touch_interceptor);
@ -151,26 +151,15 @@ public class SearchWheel implements View.OnClickListener
UiUtils.showIf(show && mIsExpanded, mSearchLayout);
}
public void saveState(@NonNull Bundle outState)
{
outState.putSerializable(EXTRA_CURRENT_OPTION, mCurrentOption);
}
public void restoreState(@NonNull Bundle savedState)
{
mCurrentOption = Utils.getSerializable(savedState, EXTRA_CURRENT_OPTION, SearchOption.class);
}
public void reset()
{
mIsExpanded = false;
mCurrentOption = null;
resetSearchButtonImage();
}
public void onResume()
{
if (mCurrentOption != null)
if (mMapButtonsViewModel.getSearchOption().getValue() != null)
{
refreshSearchButtonImage();
return;
@ -183,7 +172,6 @@ public class SearchWheel implements View.OnClickListener
return;
}
mCurrentOption = SearchOption.fromSearchQuery(query, mFrame.getContext());
refreshSearchButtonImage();
}
@ -244,10 +232,11 @@ public class SearchWheel implements View.OnClickListener
private void refreshSearchButtonImage()
{
final SearchOption searchOption = mMapButtonsViewModel.getSearchOption().getValue();
mSearchButton.setImageDrawable(Graphics.tint(mSearchButton.getContext(),
mCurrentOption == null ?
searchOption == null ?
R.drawable.ic_routing_search_off :
mCurrentOption.mDrawableOff,
searchOption.mDrawableOff,
R.attr.colorAccent));
}
@ -278,7 +267,7 @@ public class SearchWheel implements View.OnClickListener
return;
}
if (mCurrentOption != null || !TextUtils.isEmpty(SearchEngine.INSTANCE.getQuery()))
if (mMapButtonsViewModel.getSearchOption().getValue() != null || !TextUtils.isEmpty(SearchEngine.INSTANCE.getQuery()))
{
mOnSearchCanceledListener.onClick(v);
refreshSearchVisibility();
@ -303,7 +292,7 @@ public class SearchWheel implements View.OnClickListener
private void startSearch(SearchOption searchOption)
{
mCurrentOption = searchOption;
mMapButtonsViewModel.setSearchOption(searchOption);
final String query = mFrame.getContext().getString(searchOption.mQueryId);
// Category request from navigation search wheel.
SearchEngine.INSTANCE.searchInteractive(mFrame.getContext(), query, true, System.nanoTime(), false);

View file

@ -9,24 +9,23 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.R;
import app.organicmaps.maplayer.isolines.IsolinesManager;
import app.organicmaps.widget.recycler.SpanningLinearLayoutManager;
import app.organicmaps.util.SharedPropertiesUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.recycler.SpanningLinearLayoutManager;
import java.util.ArrayList;
import java.util.List;
public class ToggleMapLayerFragment extends Fragment
{
@Nullable
private LayerItemClickListener mLayerItemClickListener;
@Nullable
private LayersAdapter mAdapter;
private MapButtonsViewModel mMapButtonsViewModel;
@Nullable
@Override
@ -34,8 +33,7 @@ public class ToggleMapLayerFragment extends Fragment
{
View mRoot = inflater.inflate(R.layout.fragment_toggle_map_layer, container, false);
if (requireActivity() instanceof LayerItemClickListener)
mLayerItemClickListener = ((LayerItemClickListener) requireActivity());
mMapButtonsViewModel = new ViewModelProvider(requireActivity()).get(MapButtonsViewModel.class);
initRecycler(mRoot);
return mRoot;
@ -72,12 +70,6 @@ public class ToggleMapLayerFragment extends Fragment
mAdapter.notifyDataSetChanged();
if (IsolinesManager.from(context).shouldShowNotification())
Utils.showSnackbar(context, v.getRootView(), R.string.isolines_toast_zooms_1_10);
if (mLayerItemClickListener != null)
mLayerItemClickListener.onLayerItemClick(mode);
}
public interface LayerItemClickListener
{
void onLayerItemClick(@NonNull Mode mode);
mMapButtonsViewModel.setMapLayerMode(mode);
}
}

View file

@ -21,17 +21,16 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import app.organicmaps.Framework;
import app.organicmaps.MwmActivity;
import app.organicmaps.R;
import app.organicmaps.base.MediaPlayerWrapper;
import app.organicmaps.maplayer.MapButtonsController;
import app.organicmaps.maplayer.traffic.TrafficManager;
import app.organicmaps.sound.TtsPlayer;
import app.organicmaps.widget.menu.NavMenu;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.menu.NavMenu;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import java.util.Arrays;
@ -59,10 +58,7 @@ public class NavigationController implements Application.ActivityLifecycleCallba
private final RecyclerView mLanes;
@NonNull
private final LanesAdapter mLanesAdapter;
@NonNull
private final MapButtonsController mMapButtonsController;
@NonNull
private final MediaPlayer.OnCompletionListener mSpeedCamSignalCompletionListener;
@ -106,13 +102,12 @@ public class NavigationController implements Application.ActivityLifecycleCallba
mLanes.setNestedScrollingEnabled(false);
}
public NavigationController(AppCompatActivity activity, @NonNull MapButtonsController mapButtonsController,
View.OnClickListener onSettingsClickListener, NavMenu.OnMenuSizeChangedListener onMenuSizeChangedListener)
public NavigationController(AppCompatActivity activity, View.OnClickListener onSettingsClickListener,
NavMenu.OnMenuSizeChangedListener onMenuSizeChangedListener)
{
mFrame = activity.findViewById(R.id.navigation_frame);
mNavMenu = new NavMenu(activity, this, onMenuSizeChangedListener);
mOnSettingsClickListener = onSettingsClickListener;
mMapButtonsController = mapButtonsController;
// Top frame
View topFrame = mFrame.findViewById(R.id.nav_top_frame);
@ -154,8 +149,6 @@ public class NavigationController implements Application.ActivityLifecycleCallba
public void stop(MwmActivity parent)
{
mMapButtonsController.resetSearch();
if (mBound)
{
parent.unbindService(mServiceConnection);
@ -330,7 +323,6 @@ public class NavigationController implements Application.ActivityLifecycleCallba
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState)
{
outState.putBoolean(STATE_BOUND, mBound);
mMapButtonsController.saveNavSearchState(outState);
}
public void onRestoreState(@NonNull Bundle savedInstanceState, @NonNull MwmActivity parent)
@ -338,7 +330,6 @@ public class NavigationController implements Application.ActivityLifecycleCallba
mBound = savedInstanceState.getBoolean(STATE_BOUND);
if (mBound)
start(parent);
mMapButtonsController.restoreNavSearchState(savedInstanceState);
}
@Override

View file

@ -30,13 +30,13 @@ public class MyPositionButton
private final int mFollowPaddingShift;
public MyPositionButton(@NonNull View button, int myPositionMode, @NonNull View.OnClickListener listener)
public MyPositionButton(@NonNull View button, @NonNull View.OnClickListener listener)
{
mButton = (FloatingActionButton) button;
mButton.setOnClickListener(listener);
mIcons.clear();
mFollowPaddingShift = (int) (FOLLOW_SHIFT * button.getResources().getDisplayMetrics().density);
update(myPositionMode);
update(LocationState.nativeGetMode());
}
public void update(int mode)