From 029b5556673172d29cb9b788cf0b2fd62cda6d8e Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Thu, 10 Sep 2020 13:23:20 +0300 Subject: [PATCH] Add bottom sheet behaviour dialog --- .../drawable/bottom_sheet_buttons_bg_dark.xml | 11 + .../bottom_sheet_buttons_bg_light.xml | 11 + .../layout/bottom_sheet_behaviour_base.xml | 50 ++++ .../layout/bottom_sheet_plan_route_start.xml | 59 ++-- .../BottomSheetBehaviourDialogFragment.java | 282 ++++++++++++++++++ .../StartPlanRouteBottomSheet.java | 8 +- 6 files changed, 384 insertions(+), 37 deletions(-) create mode 100644 OsmAnd/res/drawable/bottom_sheet_buttons_bg_dark.xml create mode 100644 OsmAnd/res/drawable/bottom_sheet_buttons_bg_light.xml create mode 100644 OsmAnd/res/layout/bottom_sheet_behaviour_base.xml create mode 100644 OsmAnd/src/net/osmand/plus/base/BottomSheetBehaviourDialogFragment.java diff --git a/OsmAnd/res/drawable/bottom_sheet_buttons_bg_dark.xml b/OsmAnd/res/drawable/bottom_sheet_buttons_bg_dark.xml new file mode 100644 index 0000000000..1322edb6cb --- /dev/null +++ b/OsmAnd/res/drawable/bottom_sheet_buttons_bg_dark.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable/bottom_sheet_buttons_bg_light.xml b/OsmAnd/res/drawable/bottom_sheet_buttons_bg_light.xml new file mode 100644 index 0000000000..cfc0b32c50 --- /dev/null +++ b/OsmAnd/res/drawable/bottom_sheet_buttons_bg_light.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/bottom_sheet_behaviour_base.xml b/OsmAnd/res/layout/bottom_sheet_behaviour_base.xml new file mode 100644 index 0000000000..1f54a2b8d1 --- /dev/null +++ b/OsmAnd/res/layout/bottom_sheet_behaviour_base.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/bottom_sheet_plan_route_start.xml b/OsmAnd/res/layout/bottom_sheet_plan_route_start.xml index a4aa9f312e..d43c589a9d 100644 --- a/OsmAnd/res/layout/bottom_sheet_plan_route_start.xml +++ b/OsmAnd/res/layout/bottom_sheet_plan_route_start.xml @@ -1,47 +1,40 @@ - + android:orientation="horizontal" + android:paddingStart="@dimen/content_padding" + android:paddingLeft="@dimen/content_padding" + android:paddingTop="@dimen/bottom_sheet_title_padding_top" + android:paddingEnd="@dimen/content_padding" + android:paddingRight="@dimen/content_padding" + android:paddingBottom="@dimen/bottom_sheet_title_padding_bottom"> - - - - - - - + android:letterSpacing="@dimen/description_letter_spacing" + android:text="@string/plan_route_last_edited" + android:textColor="?attr/active_color_basic" + android:textSize="@dimen/default_desc_text_size" + osmand:typeface="@string/font_roboto_medium" /> - \ No newline at end of file + + + \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/base/BottomSheetBehaviourDialogFragment.java b/OsmAnd/src/net/osmand/plus/base/BottomSheetBehaviourDialogFragment.java new file mode 100644 index 0000000000..332fb5be0e --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/base/BottomSheetBehaviourDialogFragment.java @@ -0,0 +1,282 @@ +package net.osmand.plus.base; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.LinearLayout; + +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.FragmentActivity; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.UiUtilities.DialogButtonType; +import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; +import net.osmand.plus.helpers.AndroidUiHelper; + +import java.util.ArrayList; +import java.util.List; + +public abstract class BottomSheetBehaviourDialogFragment extends BottomSheetDialogFragment { + + private static final String USED_ON_MAP_KEY = "used_on_map"; + private static final int DEFAULT_VALUE = -1; + + protected List items = new ArrayList<>(); + + protected boolean usedOnMap = true; + protected boolean nightMode; + protected boolean portrait; + + protected View dismissButton; + protected View rightButton; + + private LinearLayout itemsContainer; + + public void setUsedOnMap(boolean usedOnMap) { + this.usedOnMap = usedOnMap; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + usedOnMap = savedInstanceState.getBoolean(USED_ON_MAP_KEY); + } + nightMode = isNightMode(requiredMyApplication()); + portrait = AndroidUiHelper.isOrientationPortrait(requireActivity()); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { + LayoutInflater themedInflater = UiUtilities.getInflater(requireContext(), nightMode); + View mainView = themedInflater.inflate(R.layout.bottom_sheet_behaviour_base, parent, false); + itemsContainer = (LinearLayout) mainView.findViewById(R.id.items_container); + + View scrollView = mainView.findViewById(R.id.bottom_sheet_scroll_view); + final BottomSheetBehavior behavior = BottomSheetBehavior.from(scrollView); + behavior.setPeekHeight(getPeekHeight()); + + LinearLayout buttonsContainer = (LinearLayout) mainView.findViewById(R.id.buttons_container); + buttonsContainer.setBackgroundResource(getButtonsContainerBg()); + + if (!portrait) { + Dialog dialog = getDialog(); + if (dialog != null) { + dialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + } + }); + } + } + + createMenuItems(savedInstanceState); + inflateMenuItems(); + + dismissButton = mainView.findViewById(R.id.dismiss_button); + UiUtilities.setupDialogButton(nightMode, dismissButton, getDismissButtonType(), getDismissButtonTextId()); + dismissButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onDismissButtonClickAction(); + dismiss(); + } + }); + if (hideButtonsContainer()) { + mainView.findViewById(R.id.buttons_container).setVisibility(View.GONE); + } else { + int rightBottomButtonTextId = getRightBottomButtonTextId(); + if (rightBottomButtonTextId != DEFAULT_VALUE) { + mainView.findViewById(R.id.buttons_divider).setVisibility(View.VISIBLE); + rightButton = mainView.findViewById(R.id.right_bottom_button); + UiUtilities.setupDialogButton(nightMode, rightButton, getRightBottomButtonType(), rightBottomButtonTextId); + rightButton.setVisibility(View.VISIBLE); + rightButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onRightBottomButtonClick(); + } + }); + } + } + updateBackground(); + updateBottomButtons(); + return mainView; + } + + @Override + public void onStart() { + super.onStart(); + FragmentActivity activity = requireActivity(); + if (!AndroidUiHelper.isOrientationPortrait(activity)) { + Dialog dialog = getDialog(); + Window window = dialog != null ? dialog.getWindow() : null; + if (window != null) { + WindowManager.LayoutParams params = window.getAttributes(); + params.width = activity.getResources().getDimensionPixelSize(R.dimen.landscape_bottom_sheet_dialog_fragment_width); + window.setAttributes(params); + } + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(USED_ON_MAP_KEY, usedOnMap); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + items.clear(); + if (itemsContainer != null) { + itemsContainer.removeAllViews(); + } + } + + public abstract void createMenuItems(Bundle savedInstanceState); + + protected void inflateMenuItems() { + Activity activity = requireActivity(); + for (BaseBottomSheetItem item : items) { + item.inflate(activity, itemsContainer, nightMode); + } + } + + @Override + protected Drawable getContentIcon(@DrawableRes int id) { + return getIcon(id, nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light); + } + + protected Drawable getActiveIcon(@DrawableRes int id) { + return getIcon(id, getActiveColorId()); + } + + @ColorRes + protected int getActiveColorId() { + return nightMode ? R.color.osmand_orange : R.color.color_myloc_distance; + } + + @ColorInt + protected int getResolvedColor(@ColorRes int colorId) { + Context ctx = getContext(); + return ctx != null ? ContextCompat.getColor(ctx, colorId) : 0; + } + + private void updateBackground() { + if (portrait) { + itemsContainer.setBackgroundResource(getPortraitBgResId()); + } else { + itemsContainer.setBackgroundResource(getLandscapeTopsidesBgResId()); + } + } + + protected int getPeekHeight() { + return DEFAULT_VALUE; + } + + protected boolean hideButtonsContainer() { + return false; + } + + @StringRes + protected int getDismissButtonTextId() { + return R.string.shared_string_cancel; + } + + protected DialogButtonType getDismissButtonType() { + return DialogButtonType.SECONDARY; + } + + protected void onDismissButtonClickAction() { + + } + + @StringRes + protected int getRightBottomButtonTextId() { + return DEFAULT_VALUE; + } + + protected DialogButtonType getRightBottomButtonType() { + return DialogButtonType.PRIMARY; + } + + protected void onRightBottomButtonClick() { + + } + + protected boolean isDismissButtonEnabled() { + return true; + } + + protected boolean isRightBottomButtonEnabled() { + return true; + } + + protected void updateBottomButtons() { + if (dismissButton != null) { + boolean enabled = isDismissButtonEnabled(); + dismissButton.setEnabled(enabled); + dismissButton.findViewById(R.id.button_text).setEnabled(enabled); + } + if (rightButton != null) { + boolean enabled = isRightBottomButtonEnabled(); + rightButton.setEnabled(enabled); + rightButton.findViewById(R.id.button_text).setEnabled(enabled); + } + } + + @ColorRes + protected int getBgColorId() { + return nightMode ? R.color.list_background_color_dark : R.color.list_background_color_light; + } + + @DrawableRes + protected int getPortraitBgResId() { + return nightMode ? R.drawable.bg_bottom_menu_dark : R.drawable.bg_bottom_menu_light; + } + + @DrawableRes + protected int getLandscapeTopsidesBgResId() { + return nightMode ? R.drawable.bg_bottom_sheet_topsides_landscape_dark : R.drawable.bg_bottom_sheet_topsides_landscape_light; + } + + @DrawableRes + protected int getLandscapeSidesBgResId() { + return nightMode ? R.drawable.bg_bottom_sheet_sides_landscape_dark : R.drawable.bg_bottom_sheet_sides_landscape_light; + } + + private int getButtonsContainerBg() { + if (portrait) { + return getBgColorId(); + } + return nightMode ? R.drawable.bottom_sheet_buttons_bg_dark : R.drawable.bottom_sheet_buttons_bg_light; + } + + protected boolean isNightMode(@NonNull OsmandApplication app) { + if (usedOnMap) { + return app.getDaynightHelper().isNightModeForMapControls(); + } + return !app.getSettings().isLightContent(); + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/StartPlanRouteBottomSheet.java b/OsmAnd/src/net/osmand/plus/measurementtool/StartPlanRouteBottomSheet.java index de235b0dc5..aedb65ee72 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/StartPlanRouteBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/StartPlanRouteBottomSheet.java @@ -19,7 +19,7 @@ import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.base.MenuBottomSheetDialogFragment; +import net.osmand.plus.base.BottomSheetBehaviourDialogFragment; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerItem; @@ -38,7 +38,7 @@ import java.util.List; import static net.osmand.plus.helpers.GpxUiHelper.getSortedGPXFilesInfo; -public class StartPlanRouteBottomSheet extends MenuBottomSheetDialogFragment { +public class StartPlanRouteBottomSheet extends BottomSheetBehaviourDialogFragment { public static final String TAG = StartPlanRouteBottomSheet.class.getSimpleName(); private static final Log LOG = PlatformUtil.getLog(StartPlanRouteBottomSheet.class); @@ -136,8 +136,8 @@ public class StartPlanRouteBottomSheet extends MenuBottomSheetDialogFragment { } @Override - protected int getCustomHeight() { - return AndroidUtils.dpToPx(mainView.getContext(), BOTTOM_SHEET_HEIGHT_DP); + protected int getPeekHeight() { + return AndroidUtils.dpToPx(getContext(), BOTTOM_SHEET_HEIGHT_DP); } private void onItemClick(int position, List gpxInfoList) {