[android] Allow customization of the first (OM logo / About) button

This commit is contained in:
Mihail Mitrofanov
2025-06-03 13:10:38 +02:00
committed by Konstantin Pastbin
parent d38ffe2fa8
commit 5eff4f56ca
15 changed files with 522 additions and 63 deletions

View File

@@ -7,6 +7,7 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Color; import android.graphics.Color;
import android.location.Location; import android.location.Location;
@@ -35,6 +36,7 @@ import androidx.annotation.StyleRes;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
@@ -99,6 +101,9 @@ import app.organicmaps.settings.DrivingOptionsActivity;
import app.organicmaps.settings.RoadType; import app.organicmaps.settings.RoadType;
import app.organicmaps.settings.SettingsActivity; import app.organicmaps.settings.SettingsActivity;
import app.organicmaps.settings.UnitLocale; import app.organicmaps.settings.UnitLocale;
import app.organicmaps.leftbutton.LeftButton;
import app.organicmaps.leftbutton.LeftButtonsHolder;
import app.organicmaps.leftbutton.LeftToggleButton;
import app.organicmaps.util.Config; import app.organicmaps.util.Config;
import app.organicmaps.util.LocationUtils; import app.organicmaps.util.LocationUtils;
import app.organicmaps.util.PowerManagment; import app.organicmaps.util.PowerManagment;
@@ -116,6 +121,7 @@ import app.organicmaps.widget.placepage.PlacePageController;
import app.organicmaps.widget.placepage.PlacePageData; import app.organicmaps.widget.placepage.PlacePageData;
import app.organicmaps.widget.placepage.PlacePageViewModel; import app.organicmaps.widget.placepage.PlacePageViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
@@ -127,6 +133,10 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static app.organicmaps.location.LocationState.FOLLOW; import static app.organicmaps.location.LocationState.FOLLOW;
import static app.organicmaps.location.LocationState.FOLLOW_AND_ROTATE; import static app.organicmaps.location.LocationState.FOLLOW_AND_ROTATE;
import static app.organicmaps.location.LocationState.LOCATION_TAG; import static app.organicmaps.location.LocationState.LOCATION_TAG;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_ADD_PLACE_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_HELP_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_RECORD_TRACK_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_SETTINGS_CODE;
import static app.organicmaps.util.PowerManagment.POWER_MANAGEMENT_TAG; import static app.organicmaps.util.PowerManagment.POWER_MANAGEMENT_TAG;
public class MwmActivity extends BaseMwmFragmentActivity public class MwmActivity extends BaseMwmFragmentActivity
@@ -200,6 +210,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
private int mNavBarHeight; private int mNavBarHeight;
private LeftButtonsHolder buttonsHolder;
private PlacePageViewModel mPlacePageViewModel; private PlacePageViewModel mPlacePageViewModel;
private MapButtonsViewModel mMapButtonsViewModel; private MapButtonsViewModel mMapButtonsViewModel;
private MapButtonsController.LayoutMode mPreviousMapLayoutMode; private MapButtonsController.LayoutMode mPreviousMapLayoutMode;
@@ -232,6 +244,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
@NonNull @NonNull
private ActivityResultLauncher<Intent> mPowerSaveSettings; private ActivityResultLauncher<Intent> mPowerSaveSettings;
@NonNull @NonNull
private ActivityResultLauncher<Intent> mSettingsLauncher;
@NonNull
private boolean mPowerSaveDisclaimerShown = false; private boolean mPowerSaveDisclaimerShown = false;
@SuppressWarnings("NotNullFieldNotInitialized") @SuppressWarnings("NotNullFieldNotInitialized")
@@ -415,6 +429,11 @@ public class MwmActivity extends BaseMwmFragmentActivity
BookmarkCategoriesActivity.start(this); BookmarkCategoriesActivity.start(this);
} }
private void onAddPlace()
{
showPositionChooserForEditor(false, false);
}
private void showHelp() private void showHelp()
{ {
Intent intent = new Intent(this, HelpActivity.class); Intent intent = new Intent(this, HelpActivity.class);
@@ -555,6 +574,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
mPowerSaveSettings = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), mPowerSaveSettings = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
this::onPowerSaveResult); this::onPowerSaveResult);
mSettingsLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
this::onSettingsResult);
mShareLauncher = SharingUtils.RegisterLauncher(this); mShareLauncher = SharingUtils.RegisterLauncher(this);
mDisplayManager = DisplayManager.from(this); mDisplayManager = DisplayManager.from(this);
@@ -586,6 +608,22 @@ public class MwmActivity extends BaseMwmFragmentActivity
onRenderingInitializationFinished(); onRenderingInitializationFinished();
} }
private void onSettingsResult(ActivityResult activityResult)
{
if (activityResult.getResultCode() == Activity.RESULT_OK)
{
Intent data = activityResult.getData();
if (data != null && data.hasExtra(MwmActivity.this.getString(R.string.pref_left_button)))
{
MapButtonsController mMapButtonsController = (MapButtonsController) getSupportFragmentManager().findFragmentById(R.id.map_buttons);
if (mMapButtonsController != null)
{
mMapButtonsController.reloadLeftButton(buttonsHolder.getActiveButton());
}
}
}
}
private void refreshLightStatusBar() private void refreshLightStatusBar()
{ {
UiUtils.setLightStatusBar(this, !( UiUtils.setLightStatusBar(this, !(
@@ -781,16 +819,147 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void initNavigationButtons() private void initNavigationButtons()
{ {
prepareNavigationButtons();
initNavigationButtons(mMapButtonsViewModel.getLayoutMode().getValue()); initNavigationButtons(mMapButtonsViewModel.getLayoutMode().getValue());
} }
private void prepareNavigationButtons()
{
buttonsHolder = LeftButtonsHolder.getInstance(this);
buttonsHolder.registerButton(new LeftButton()
{
@Override
public String getCode()
{
return BUTTON_HELP_CODE;
}
@Override
public String getPrefsName()
{
return getString(R.string.help);
}
@Override
public void drawIcon(FloatingActionButton imageView)
{
imageView.setImageResource(R.drawable.ic_question_mark);
}
@Override
public void onClick(FloatingActionButton left)
{
Intent intent = new Intent(MwmActivity.this, HelpActivity.class);
MwmActivity.this.startActivity(intent);
}
});
buttonsHolder.registerButton(new LeftButton()
{
@Override
public String getCode()
{
return BUTTON_ADD_PLACE_CODE;
}
@Override
public String getPrefsName()
{
return getString(R.string.placepage_add_place_button);
}
@Override
public void drawIcon(FloatingActionButton imageView)
{
imageView.setImageResource(R.drawable.ic_plus);
}
@Override
public void onClick(FloatingActionButton left)
{
onAddPlace();
}
});
buttonsHolder.registerButton(new LeftButton()
{
@Override
public String getCode()
{
return BUTTON_SETTINGS_CODE;
}
@Override
public String getPrefsName()
{
return getString(R.string.settings);
}
@Override
public void drawIcon(FloatingActionButton imageView)
{
imageView.setImageResource(R.drawable.ic_settings);
}
@Override
public void onClick(FloatingActionButton left)
{
onOpenSettings();
}
});
buttonsHolder.registerButton(new LeftToggleButton()
{
private boolean isRecording = TrackRecorder.nativeIsTrackRecordingEnabled();
@Override
public void setChecked(boolean checked)
{
isRecording = checked;
}
@Override
public String getCode()
{
return BUTTON_RECORD_TRACK_CODE;
}
@Override
public String getPrefsName()
{
return getString(R.string.start_track_recording);
}
@Override
public void drawIcon(FloatingActionButton imageView)
{
imageView.setImageResource(R.drawable.ic_track_recording_off);
int color = isRecording
? ContextCompat.getColor(MwmActivity.this, R.color.active_track_recording)
: ThemeUtils.getColor(MwmActivity.this, R.attr.iconTint);
ColorStateList colorStateList = ColorStateList.valueOf(color);
imageView.setImageTintList(colorStateList);
}
@Override
public void onClick(FloatingActionButton left)
{
onTrackRecordingOptionSelected();
drawIcon(left);
}
});
}
private void initNavigationButtons(MapButtonsController.LayoutMode layoutMode) private void initNavigationButtons(MapButtonsController.LayoutMode layoutMode)
{ {
// Recreate the navigation buttons with the correct layout when it changes // Recreate the navigation buttons with the correct layout when it changes
if (mPreviousMapLayoutMode != layoutMode) if (mPreviousMapLayoutMode != layoutMode)
{ {
MapButtonsController mapButtonsController = new MapButtonsController();
mapButtonsController.setLeftButton(buttonsHolder.getActiveButton());
FragmentTransaction transaction = getSupportFragmentManager() FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction().replace(R.id.map_buttons, new MapButtonsController()); .beginTransaction().replace(R.id.map_buttons, mapButtonsController);
transaction.commit(); transaction.commit();
mPreviousMapLayoutMode = layoutMode; mPreviousMapLayoutMode = layoutMode;
} }
@@ -2287,7 +2456,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onAddPlaceOptionSelected() public void onAddPlaceOptionSelected()
{ {
closeFloatingPanels(); closeFloatingPanels();
showPositionChooserForEditor(false, false); onAddPlace();
} }
public void onDownloadMapsOptionSelected() public void onDownloadMapsOptionSelected()
@@ -2304,9 +2473,14 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onSettingsOptionSelected() public void onSettingsOptionSelected()
{ {
Intent intent = new Intent(this, SettingsActivity.class);
closeFloatingPanels(); closeFloatingPanels();
startActivity(intent); onOpenSettings();
}
private void onOpenSettings()
{
Intent intent = new Intent(this, SettingsActivity.class);
mSettingsLauncher.launch(intent);
} }
private boolean startTrackRecording() private boolean startTrackRecording()

View File

@@ -0,0 +1,14 @@
package app.organicmaps.leftbutton;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
public interface LeftButton
{
String getCode();
String getPrefsName();
default void drawIcon(FloatingActionButton imageView) {}
default void onClick(FloatingActionButton leftButtonView) {}
}

View File

@@ -0,0 +1,96 @@
package app.organicmaps.leftbutton;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceManager;
import app.organicmaps.R;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class LeftButtonsHolder
{
private static volatile LeftButtonsHolder instance;
public static final String DISABLE_BUTTON_CODE = "disable";
public static final String BUTTON_HELP_CODE = "help";
public static final String BUTTON_SETTINGS_CODE = "settings";
public static final String BUTTON_ADD_PLACE_CODE = "add-place";
public static final String BUTTON_RECORD_TRACK_CODE = "record-track";
private static final String DEFAULT_BUTTON_CODE = BUTTON_HELP_CODE;
private final String leftButtonPreferenceKey;
private final SharedPreferences prefs;
private final Map<String, LeftButton> availableButtons = new LinkedHashMap<>();
private LeftButtonsHolder(Context context)
{
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
this.leftButtonPreferenceKey = context.getString(R.string.pref_left_button);
initDisableButton(context);
}
public void registerButton(LeftButton button)
{
availableButtons.put(button.getCode(), button);
}
@Nullable
public LeftButton getActiveButton()
{
String activeButtonCode = prefs.getString(leftButtonPreferenceKey, DEFAULT_BUTTON_CODE);
if (!TextUtils.isEmpty(activeButtonCode))
return availableButtons.get(activeButtonCode);
else
return null;
}
public Collection<LeftButton> getAllButtons()
{
return availableButtons.values();
}
public static LeftButtonsHolder getInstance(Context context)
{
LeftButtonsHolder localInstance = instance;
if (localInstance == null)
{
synchronized (LeftButtonsHolder.class)
{
localInstance = instance;
if (localInstance == null)
{
instance = localInstance = new LeftButtonsHolder(context);
}
}
}
return localInstance;
}
private void initDisableButton(Context context)
{
availableButtons.put(DISABLE_BUTTON_CODE, new LeftButton()
{
@Override
public String getCode()
{
return DISABLE_BUTTON_CODE;
}
@Override
public String getPrefsName()
{
return context.getString(R.string.pref_left_button_disable);
}
}
);
}
}

View File

@@ -0,0 +1,6 @@
package app.organicmaps.leftbutton;
public interface LeftToggleButton extends LeftButton
{
void setChecked(boolean checked);
}

View File

@@ -1,8 +1,12 @@
package app.organicmaps.maplayer; package app.organicmaps.maplayer;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_HELP_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.DISABLE_BUTTON_CODE;
import android.animation.ArgbEvaluator; import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.content.Context; import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
@@ -21,6 +25,7 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import app.organicmaps.Framework; import app.organicmaps.Framework;
import app.organicmaps.MwmActivity; import app.organicmaps.MwmActivity;
import app.organicmaps.R; import app.organicmaps.R;
@@ -31,11 +36,15 @@ import app.organicmaps.maplayer.isolines.IsolinesManager;
import app.organicmaps.maplayer.subway.SubwayManager; import app.organicmaps.maplayer.subway.SubwayManager;
import app.organicmaps.maplayer.traffic.TrafficManager; import app.organicmaps.maplayer.traffic.TrafficManager;
import app.organicmaps.routing.RoutingController; import app.organicmaps.routing.RoutingController;
import app.organicmaps.leftbutton.LeftButton;
import app.organicmaps.leftbutton.LeftToggleButton;
import app.organicmaps.util.Config; import app.organicmaps.util.Config;
import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.UiUtils; import app.organicmaps.util.UiUtils;
import app.organicmaps.util.WindowInsetUtils; import app.organicmaps.util.WindowInsetUtils;
import app.organicmaps.widget.menu.MyPositionButton; import app.organicmaps.widget.menu.MyPositionButton;
import app.organicmaps.widget.placepage.PlacePageViewModel; import app.organicmaps.widget.placepage.PlacePageViewModel;
import com.google.android.material.badge.BadgeDrawable; import com.google.android.material.badge.BadgeDrawable;
import com.google.android.material.badge.BadgeUtils; import com.google.android.material.badge.BadgeUtils;
import com.google.android.material.badge.ExperimentalBadgeUtils; import com.google.android.material.badge.ExperimentalBadgeUtils;
@@ -75,9 +84,12 @@ public class MapButtonsController extends Fragment
private final Observer<Boolean> mTrackRecorderObserver = (enable) -> { private final Observer<Boolean> mTrackRecorderObserver = (enable) -> {
updateMenuBadge(enable); updateMenuBadge(enable);
showButton(enable, MapButtons.trackRecordingStatus); showButton(enable, MapButtons.trackRecordingStatus);
updateLeftButtonToggleState(enable);
}; };
private final Observer<Integer> mTopButtonMarginObserver = this::updateTopButtonsMargin; private final Observer<Integer> mTopButtonMarginObserver = this::updateTopButtonsMargin;
private LeftButton mLeftButton;
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
@@ -98,27 +110,15 @@ public class MapButtonsController extends Fragment
mInnerRightButtonsFrame = mFrame.findViewById(R.id.map_buttons_inner_right); mInnerRightButtonsFrame = mFrame.findViewById(R.id.map_buttons_inner_right);
mBottomButtonsFrame = mFrame.findViewById(R.id.map_buttons_bottom); mBottomButtonsFrame = mFrame.findViewById(R.id.map_buttons_bottom);
final FloatingActionButton helpButton = mFrame.findViewById(R.id.help_button); mButtonsMap = new HashMap<>();
if (helpButton != null)
{ initBottomButtons();
if (Config.isNY() && !TextUtils.isEmpty(Config.getDonateUrl(requireContext())))
helpButton.setImageResource(R.drawable.ic_christmas_tree);
// else
// {
// helpButton.setImageResource(R.drawable.ic_launcher);
// }
// // Keep this button colorful in normal theme.
// if (!ThemeUtils.isNightTheme(requireContext()))
// helpButton.getDrawable().setTintList(null);
}
final View zoomFrame = mFrame.findViewById(R.id.zoom_buttons_container); final View zoomFrame = mFrame.findViewById(R.id.zoom_buttons_container);
mFrame.findViewById(R.id.nav_zoom_in) mFrame.findViewById(R.id.nav_zoom_in)
.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomIn)); .setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomIn));
mFrame.findViewById(R.id.nav_zoom_out) mFrame.findViewById(R.id.nav_zoom_out)
.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomOut)); .setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomOut));
final View bookmarksButton = mFrame.findViewById(R.id.btn_bookmarks);
bookmarksButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.bookmarks));
final View myPosition = mFrame.findViewById(R.id.my_position); final View myPosition = mFrame.findViewById(R.id.my_position);
mNavMyPosition = new MyPositionButton(myPosition, (v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.myPosition)); mNavMyPosition = new MyPositionButton(myPosition, (v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.myPosition));
@@ -133,12 +133,55 @@ public class MapButtonsController extends Fragment
mTrackRecordingStatusButton = mFrame.findViewById(R.id.track_recording_status); mTrackRecordingStatusButton = mFrame.findViewById(R.id.track_recording_status);
if (mTrackRecordingStatusButton != null) if (mTrackRecordingStatusButton != null)
mTrackRecordingStatusButton.setOnClickListener(view -> mMapButtonClickListener.onMapButtonClick(MapButtons.trackRecordingStatus)); mTrackRecordingStatusButton.setOnClickListener(view -> mMapButtonClickListener.onMapButtonClick(MapButtons.trackRecordingStatus));
final View menuButton = mFrame.findViewById(R.id.menu_button);
mSearchWheel = new SearchWheel(mFrame,
(v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.search),
(v) -> mMapButtonClickListener.onSearchCanceled(),
mMapButtonsViewModel);
// Used to get the maximum height the buttons will evolve in
mFrame.addOnLayoutChangeListener(new MapButtonsController.ContentViewLayoutChangeListener(mFrame));
mButtonsMap.put(MapButtons.zoom, zoomFrame);
mButtonsMap.put(MapButtons.myPosition, myPosition);
if (mToggleMapLayerButton != null)
mButtonsMap.put(MapButtons.toggleMapLayer, mToggleMapLayerButton);
if (mTrackRecordingStatusButton != null)
mButtonsMap.put(MapButtons.trackRecordingStatus, mTrackRecordingStatusButton);
showButton(false, MapButtons.trackRecordingStatus);
return mFrame;
}
private void initBottomButtons()
{
// universal button
applyLeftButton();
// bookmarks button
View bookmarksButton = mFrame.findViewById(R.id.btn_bookmarks);
if (bookmarksButton != null)
{
bookmarksButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.bookmarks));
mButtonsMap.put(MapButtons.bookmarks, bookmarksButton);
}
// search button
View searchButton = mFrame.findViewById(R.id.btn_search);
if (searchButton != null)
{
searchButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.bookmarks));
mButtonsMap.put(MapButtons.search, searchButton);
}
// menu button
View menuButton = mFrame.findViewById(R.id.menu_button);
if (menuButton != null) if (menuButton != null)
{ {
menuButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(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. // 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() { menuButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override @Override
public void onGlobalLayout() public void onGlobalLayout()
{ {
@@ -146,35 +189,49 @@ public class MapButtonsController extends Fragment
menuButton.getViewTreeObserver().removeOnGlobalLayoutListener(this); menuButton.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} }
}); });
}
if (helpButton != null)
helpButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.help));
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
mFrame.addOnLayoutChangeListener(new MapButtonsController.ContentViewLayoutChangeListener(mFrame));
mButtonsMap = new HashMap<>();
mButtonsMap.put(MapButtons.zoom, zoomFrame);
mButtonsMap.put(MapButtons.myPosition, myPosition);
mButtonsMap.put(MapButtons.bookmarks, bookmarksButton);
mButtonsMap.put(MapButtons.search, searchButton);
if (mToggleMapLayerButton != null)
mButtonsMap.put(MapButtons.toggleMapLayer, mToggleMapLayerButton);
if (menuButton != null)
mButtonsMap.put(MapButtons.menu, menuButton); mButtonsMap.put(MapButtons.menu, menuButton);
if (helpButton != null) }
mButtonsMap.put(MapButtons.help, helpButton); }
if (mTrackRecordingStatusButton != null)
mButtonsMap.put(MapButtons.trackRecordingStatus, mTrackRecordingStatusButton); private void applyLeftButton()
showButton(false, MapButtons.trackRecordingStatus); {
return mFrame; FloatingActionButton leftButtonView = mFrame.findViewById(R.id.left_button);
if (leftButtonView != null && mLeftButton != null && !mLeftButton.getCode().equals(DISABLE_BUTTON_CODE))
{
UiUtils.show(leftButtonView);
Context context = getContext();
if (context == null)
return;
leftButtonView.setImageTintList(ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.iconTint)));
// Christmas tree with help button
if (Config.isNY() &&
mLeftButton.getCode().equals(BUTTON_HELP_CODE) &&
!TextUtils.isEmpty(Config.getDonateUrl(requireContext()))
)
{
leftButtonView.setImageResource(R.drawable.ic_christmas_tree);
leftButtonView.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.help));
}
else
{
mLeftButton.drawIcon(leftButtonView);
leftButtonView.setOnClickListener((v) -> mLeftButton.onClick(leftButtonView));
}
// else
// {
// helpButton.setImageResource(R.drawable.ic_launcher);
// }
// // Keep this button colorful in normal theme.
// if (!ThemeUtils.isNightTheme(requireContext()))
// helpButton.getDrawable().setTintList(null);
}
else if (leftButtonView != null)
{
UiUtils.hide(leftButtonView);
}
} }
public void showButton(boolean show, MapButtonsController.MapButtons button) public void showButton(boolean show, MapButtonsController.MapButtons button)
@@ -251,7 +308,7 @@ public class MapButtonsController extends Fragment
final UpdateInfo info = MapManager.nativeGetUpdateInfo(null); final UpdateInfo info = MapManager.nativeGetUpdateInfo(null);
final int count = (info == null ? 0 : info.filesCount); final int count = (info == null ? 0 : info.filesCount);
final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(0) final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(0)
.length() * 5, context); .length() * 5, context);
if (count == 0) if (count == 0)
{ {
@@ -450,6 +507,27 @@ public class MapButtonsController extends Fragment
mSearchWheel.reset(); mSearchWheel.reset();
} }
public void setLeftButton(LeftButton leftButton)
{
this.mLeftButton = leftButton;
}
public void reloadLeftButton(LeftButton leftButton)
{
setLeftButton(leftButton);
applyLeftButton();
}
private void updateLeftButtonToggleState(boolean isEnabled)
{
if (mLeftButton instanceof LeftToggleButton)
{
((LeftToggleButton) mLeftButton).setChecked(isEnabled);
reloadLeftButton(mLeftButton);
}
}
public enum LayoutMode public enum LayoutMode
{ {
regular, regular,

View File

@@ -1,5 +1,7 @@
package app.organicmaps.settings; package app.organicmaps.settings;
import static app.organicmaps.leftbutton.LeftButtonsHolder.DISABLE_BUTTON_CODE;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -25,6 +27,8 @@ import app.organicmaps.help.HelpActivity;
import app.organicmaps.location.LocationHelper; import app.organicmaps.location.LocationHelper;
import app.organicmaps.location.LocationProviderFactory; import app.organicmaps.location.LocationProviderFactory;
import app.organicmaps.sdk.routing.RoutingOptions; import app.organicmaps.sdk.routing.RoutingOptions;
import app.organicmaps.leftbutton.LeftButton;
import app.organicmaps.leftbutton.LeftButtonsHolder;
import app.organicmaps.util.Config; import app.organicmaps.util.Config;
import app.organicmaps.util.NetworkPolicy; import app.organicmaps.util.NetworkPolicy;
import app.organicmaps.util.PowerManagment; import app.organicmaps.util.PowerManagment;
@@ -35,6 +39,11 @@ import app.organicmaps.util.log.LogsManager;
import app.organicmaps.sdk.search.SearchRecents; import app.organicmaps.sdk.search.SearchRecents;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale; import java.util.Locale;
public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements LanguagesFragment.Listener public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements LanguagesFragment.Listener
@@ -68,6 +77,55 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements La
initSearchPrivacyPrefsCallbacks(); initSearchPrivacyPrefsCallbacks();
initScreenSleepEnabledPrefsCallbacks(); initScreenSleepEnabledPrefsCallbacks();
initShowOnLockScreenPrefsCallbacks(); initShowOnLockScreenPrefsCallbacks();
initLeftButtonPrefs();
}
private void initLeftButtonPrefs()
{
final String leftButtonPreferenceKey = getString(R.string.pref_left_button);
final ListPreference pref = getPreference(leftButtonPreferenceKey);
LeftButtonsHolder holder = LeftButtonsHolder.getInstance(requireContext());
LeftButton currentButton = holder.getActiveButton();
Collection<LeftButton> buttons = holder.getAllButtons();
List<String> entryList = new ArrayList<>(buttons.size());
List<String> valueList = new ArrayList<>(buttons.size());
for (LeftButton button : buttons)
{
entryList.add(button.getPrefsName());
valueList.add(button.getCode());
}
pref.setEntries(entryList.toArray(new CharSequence[0]));
pref.setEntryValues(valueList.toArray(new CharSequence[0]));
if (currentButton != null)
{
pref.setSummary(currentButton.getPrefsName());
pref.setValue(currentButton.getCode());
}
else
{
pref.setSummary(R.string.pref_left_button_disable);
pref.setValue(DISABLE_BUTTON_CODE);
}
pref.setOnPreferenceChangeListener((preference, newValue) -> {
int index = pref.findIndexOfValue(newValue.toString());
if (index >= 0)
{
pref.setSummary(pref.getEntries()[index]);
}
Intent intent = new Intent();
intent.putExtra(leftButtonPreferenceKey, newValue.toString());
requireActivity().setResult(-1, intent);
return true;
});
} }
private void updateVoiceInstructionsPrefsSummary() private void updateVoiceInstructionsPrefsSummary()

View File

@@ -6,7 +6,7 @@
android:viewportHeight="80"> android:viewportHeight="80">
<path <path
android:pathData="m4.858,10.076c0,-5.523 4.477,-10 10,-10h60c5.523,0 10,4.477 10,10v60c0,5.523 -4.477,10 -10,10h-60c-5.523,0 -10,-4.477 -10,-10z" android:pathData="m4.858,10.076c0,-5.523 4.477,-10 10,-10h60c5.523,0 10,4.477 10,10v60c0,5.523 -4.477,10 -10,10h-60c-5.523,0 -10,-4.477 -10,-10z"
android:fillColor="#0057ff" android:fillColor="@color/active_track_recording"
android:fillAlpha="0.78" /> android:fillAlpha="0.78" />
<path <path
android:pathData="m78.907,32.87 l-31.833,13.318 13.335,5.772 6.188,13.147z" android:pathData="m78.907,32.87 l-31.833,13.318 13.335,5.772 6.188,13.147z"

View File

@@ -3,5 +3,5 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> android:shape="rectangle">
<corners android:radius="12dp" /> <corners android:radius="12dp" />
<solid android:color="#0057ff" /> <solid android:color="@color/active_track_recording" />
</shape> </shape>

View File

@@ -9,29 +9,37 @@
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false"> android:clipToPadding="false">
<include <include
android:id="@+id/left_button"
layout="@layout/map_buttons_help" layout="@layout/map_buttons_help"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_half_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_search"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<include <include
android:id="@+id/btn_search"
layout="@layout/map_buttons_search_square" layout="@layout/map_buttons_search_square"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_base_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_bookmarks" app:layout_goneMarginStart="@dimen/margin_half_plus"
app:layout_constraintStart_toEndOf="@+id/help_button" /> app:layout_constraintStart_toEndOf="@+id/left_button" />
<include <include
android:id="@+id/btn_bookmarks"
layout="@layout/map_buttons_bookmarks_square" layout="@layout/map_buttons_bookmarks_square"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_base_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/menu_button"
app:layout_constraintStart_toEndOf="@+id/btn_search" /> app:layout_constraintStart_toEndOf="@+id/btn_search" />
<include <include
android:id="@+id/menu_button"
layout="@layout/map_buttons_menu" layout="@layout/map_buttons_menu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_base_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintStart_toEndOf="@+id/btn_bookmarks" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -7,38 +7,51 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
style="@style/MwmWidget.MapButton.Bottom" style="@style/MwmWidget.MapButton.Bottom"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false"> android:clipToPadding="false">
<include <include
android:id="@+id/left_button"
layout="@layout/map_buttons_help" layout="@layout/map_buttons_help"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_half" android:layout_marginHorizontal="@dimen/margin_half_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_search"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<include <include
android:id="@+id/btn_search"
layout="@layout/map_buttons_search_square" layout="@layout/map_buttons_search_square"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/margin_half_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_bookmarks" app:layout_constraintEnd_toStartOf="@+id/btn_bookmarks"
app:layout_constraintStart_toEndOf="@+id/help_button" /> app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/left_button" />
<include <include
android:id="@+id/btn_bookmarks"
layout="@layout/map_buttons_bookmarks_square" layout="@layout/map_buttons_bookmarks_square"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/margin_half_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/menu_button" app:layout_constraintEnd_toStartOf="@+id/menu_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/btn_search" /> app:layout_constraintStart_toEndOf="@+id/btn_search" />
<include <include
android:id="@+id/menu_button"
layout="@layout/map_buttons_menu" layout="@layout/map_buttons_menu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_half" android:layout_marginHorizontal="@dimen/margin_half_plus"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/btn_bookmarks" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout> </RelativeLayout>

View File

@@ -5,5 +5,6 @@
android:id="@+id/help_button" android:id="@+id/help_button"
style="@style/MwmWidget.MapButton.Square" style="@style/MwmWidget.MapButton.Square"
android:contentDescription="@string/help" android:contentDescription="@string/help"
android:tint="@null"
app:shapeAppearanceOverlay="@style/MwmWidget.MapButton.Square" app:shapeAppearanceOverlay="@style/MwmWidget.MapButton.Square"
app:srcCompat="@drawable/ic_question_mark" /> app:srcCompat="@drawable/ic_question_mark" />

View File

@@ -138,6 +138,8 @@
<color name="elevation_profile">#1E96F0</color> <color name="elevation_profile">#1E96F0</color>
<color name="elevation_profile_dark">#4BB9E6</color> <color name="elevation_profile_dark">#4BB9E6</color>
<color name="active_track_recording">#0057ff</color>
<color name="material_calendar_surface_dark">#929292</color> <color name="material_calendar_surface_dark">#929292</color>
<color name="notification_warning">#FFC22219</color> <color name="notification_warning">#FFC22219</color>
</resources> </resources>

View File

@@ -41,6 +41,7 @@
<string name="pref_keep_screen_on" translatable="false">KeepScreenOn</string> <string name="pref_keep_screen_on" translatable="false">KeepScreenOn</string>
<string name="pref_show_on_lock_screen" translatable="false">ShowOnLockScreen</string> <string name="pref_show_on_lock_screen" translatable="false">ShowOnLockScreen</string>
<string name="pref_map_locale" translatable="false">MapLanguage</string> <string name="pref_map_locale" translatable="false">MapLanguage</string>
<string name="pref_left_button" translatable="false">LeftButton</string>
<string name="notification_ticker_ltr" translatable="false">%1$s: %2$s</string> <string name="notification_ticker_ltr" translatable="false">%1$s: %2$s</string>
<string name="notification_ticker_rtl" translatable="false">%2$s :%1$s</string> <string name="notification_ticker_rtl" translatable="false">%2$s :%1$s</string>

View File

@@ -930,4 +930,6 @@
<!-- preference string for using auto theme only in navigation mode --> <!-- preference string for using auto theme only in navigation mode -->
<string name="nav_auto">Auto in navigation</string> <string name="nav_auto">Auto in navigation</string>
<string name="codeberg">Codeberg</string> <string name="codeberg">Codeberg</string>
<string name="pref_left_button_title">Left button setup</string>
<string name="pref_left_button_disable">Disable</string>
</resources> </resources>

View File

@@ -28,16 +28,22 @@
app:singleLineTitle="false" app:singleLineTitle="false"
android:summary="@string/pref_zoom_summary" android:summary="@string/pref_zoom_summary"
android:order="2"/> android:order="2"/>
<ListPreference
android:key="@string/pref_left_button"
android:title="@string/pref_left_button_title"
app:singleLineTitle="false"
android:persistent="true"
android:order="3"/>
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:key="@string/pref_3d_buildings" android:key="@string/pref_3d_buildings"
android:title="@string/pref_map_3d_buildings_title" android:title="@string/pref_map_3d_buildings_title"
app:singleLineTitle="false" app:singleLineTitle="false"
android:order="3"/> android:order="4"/>
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:key="@string/pref_autodownload" android:key="@string/pref_autodownload"
android:title="@string/autodownload" android:title="@string/autodownload"
app:singleLineTitle="false" app:singleLineTitle="false"
android:order="4"/> android:order="5"/>
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:key="@string/pref_large_fonts_size" android:key="@string/pref_large_fonts_size"
android:title="@string/big_font" android:title="@string/big_font"