diff --git a/android/app/src/main/java/app/organicmaps/editor/FromToTimePicker.java b/android/app/src/main/java/app/organicmaps/editor/FromToTimePicker.java new file mode 100644 index 000000000..f2edeb276 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/editor/FromToTimePicker.java @@ -0,0 +1,194 @@ +package app.organicmaps.editor; + +import android.content.res.Configuration; +import android.content.res.Resources; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + +import com.google.android.material.timepicker.MaterialTimePicker; +import com.google.android.material.timepicker.TimeFormat; + +import app.organicmaps.R; +import app.organicmaps.sdk.editor.data.HoursMinutes; +import app.organicmaps.sdk.util.DateUtils; + +public class FromToTimePicker +{ + private final FragmentActivity mActivity; + private final FragmentManager mFragmentManager; + private final OnPickListener mListener; + private final int mId; + private final boolean mIs24HourFormat; + private final Resources mResources; + + private HoursMinutes mFromTime; + private HoursMinutes mToTime; + private MaterialTimePicker mToTimePicker; + private MaterialTimePicker mFromTimePicker; + private boolean mIsFromTimePicked; + + public static void pickTime(@NonNull Fragment fragment, + @NonNull FromToTimePicker.OnPickListener listener, + @NonNull HoursMinutes fromTime, + @NonNull HoursMinutes toTime, + int id, + boolean startWithToTime) + { + FromToTimePicker timePicker = new FromToTimePicker(fragment, + listener, + fromTime, + toTime, + id); + + if (startWithToTime) + timePicker.showToTimePicker(); + else + timePicker.showFromTimePicker(); + } + + private FromToTimePicker(@NonNull Fragment fragment, + @NonNull FromToTimePicker.OnPickListener listener, + @NonNull HoursMinutes fromTime, + @NonNull HoursMinutes toTime, + int id) + { + mActivity = fragment.requireActivity(); + mFragmentManager = fragment.getChildFragmentManager(); + mListener = listener; + mFromTime = fromTime; + mToTime = toTime; + mId = id; + + mIsFromTimePicked = false; + + mIs24HourFormat = DateUtils.is24HourFormat(mActivity); + mResources = mActivity.getResources(); + + mActivity.addOnConfigurationChangedListener(this::handleConfigurationChanged); + } + + public void showFromTimePicker() + { + if (mFromTimePicker != null) + { + mFromTime = getHoursMinutes(mFromTimePicker); + mFromTimePicker.dismiss(); + } + + mFromTimePicker = buildFromTimePicker(); + mFromTimePicker.show(mFragmentManager, null); + } + + public void showToTimePicker() + { + if (mToTimePicker != null) + { + mToTime = getHoursMinutes(mToTimePicker); + mToTimePicker.dismiss(); + } + + mToTimePicker = buildToTimePicker(); + + mToTimePicker.show(mFragmentManager, null); + } + + private MaterialTimePicker buildFromTimePicker() + { + MaterialTimePicker timePicker = buildTimePicker(mFromTime, + mResources.getString(R.string.editor_time_from), + mResources.getString(R.string.next_button), + null); + + timePicker.addOnNegativeButtonClickListener(view -> finishTimePicking(false)); + + timePicker.addOnPositiveButtonClickListener(view -> + { + mIsFromTimePicked = true; + mFromTime = getHoursMinutes(timePicker); + showToTimePicker(); + }); + + timePicker.addOnCancelListener(view -> finishTimePicking(false)); + + return timePicker; + } + + private MaterialTimePicker buildToTimePicker() + { + MaterialTimePicker timePicker = buildTimePicker(mToTime, + mResources.getString(R.string.editor_time_to), + null, + mResources.getString(R.string.back)); + + timePicker.addOnNegativeButtonClickListener(view -> + { + if (mIsFromTimePicked) + showFromTimePicker(); + else + finishTimePicking(false); + }); + + timePicker.addOnPositiveButtonClickListener(view -> + { + mToTime = getHoursMinutes(timePicker); + finishTimePicking(true); + }); + + timePicker.addOnCancelListener(view -> finishTimePicking(false)); + + return timePicker; + } + + @NonNull + private MaterialTimePicker buildTimePicker(@NonNull HoursMinutes time, + @NonNull String title, + @Nullable String positiveButtonTextOverride, + @Nullable String negativeButtonTextOverride) + { + MaterialTimePicker.Builder builder = new MaterialTimePicker.Builder() + .setTitleText(title) + .setTimeFormat(mIs24HourFormat ? TimeFormat.CLOCK_24H : TimeFormat.CLOCK_12H) + .setInputMode(MaterialTimePicker.INPUT_MODE_CLOCK) + .setTheme(R.style.MwmMain_MaterialTimePicker) + .setHour((int) time.hours) + .setMinute((int) time.minutes); + + if (positiveButtonTextOverride != null) + builder.setPositiveButtonText(positiveButtonTextOverride); + + if (negativeButtonTextOverride != null) + builder.setNegativeButtonText(negativeButtonTextOverride); + + return builder.build(); + } + + private HoursMinutes getHoursMinutes(@NonNull MaterialTimePicker picker) + { + return new HoursMinutes(picker.getHour(), picker.getMinute(), mIs24HourFormat); + } + + private void finishTimePicking(boolean isConfirmed) + { + mActivity.removeOnConfigurationChangedListener(this::handleConfigurationChanged); + + if (isConfirmed) + mListener.onHoursMinutesPicked(mFromTime, mToTime, mId); + } + + private void handleConfigurationChanged(Configuration configuration) + { + if (mFromTimePicker != null && mFromTimePicker.isVisible()) + showFromTimePicker(); + else if (mToTimePicker != null && mToTimePicker.isVisible()) + showToTimePicker(); + } + + public interface OnPickListener + { + void onHoursMinutesPicked(HoursMinutes from, HoursMinutes to, int id); + } +} diff --git a/android/app/src/main/java/app/organicmaps/editor/HoursMinutesPickerFragment.java b/android/app/src/main/java/app/organicmaps/editor/HoursMinutesPickerFragment.java deleted file mode 100644 index c09ad53c5..000000000 --- a/android/app/src/main/java/app/organicmaps/editor/HoursMinutesPickerFragment.java +++ /dev/null @@ -1,211 +0,0 @@ -package app.organicmaps.editor; - -import android.annotation.SuppressLint; -import android.app.Dialog; -import android.content.Context; -import android.content.res.ColorStateList; -import android.os.Bundle; -import android.text.format.DateFormat; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; -import android.widget.TimePicker; -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.content.res.AppCompatResources; -import androidx.fragment.app.FragmentManager; -import app.organicmaps.R; -import app.organicmaps.base.BaseMwmDialogFragment; -import app.organicmaps.sdk.editor.data.HoursMinutes; -import app.organicmaps.sdk.util.DateUtils; -import app.organicmaps.util.Utils; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.material.tabs.TabLayout; -import com.google.android.material.textview.MaterialTextView; - -public class HoursMinutesPickerFragment extends BaseMwmDialogFragment -{ - private static final String EXTRA_FROM = "HoursMinutesFrom"; - private static final String EXTRA_TO = "HoursMinutesTo"; - private static final String EXTRA_SELECT_FIRST = "SelectedTab"; - private static final String EXTRA_ID = "Id"; - - public static final int TAB_FROM = 0; - public static final int TAB_TO = 1; - - private HoursMinutes mFrom; - private HoursMinutes mTo; - - private TimePicker mPicker; - private View mPickerHoursLabel; - - @IntRange(from = 0, to = 1) - private int mSelectedTab; - private TabLayout mTabs; - - private int mId; - private Button mOkButton; - - public interface OnPickListener - { - void onHoursMinutesPicked(HoursMinutes from, HoursMinutes to, int id); - } - - public static void pick(Context context, FragmentManager manager, @NonNull HoursMinutes from, - @NonNull HoursMinutes to, @IntRange(from = 0, to = 1) int selectedPosition, int id) - { - final Bundle args = new Bundle(); - args.putParcelable(EXTRA_FROM, from); - args.putParcelable(EXTRA_TO, to); - args.putInt(EXTRA_SELECT_FIRST, selectedPosition); - args.putInt(EXTRA_ID, id); - - final HoursMinutesPickerFragment fragment = (HoursMinutesPickerFragment) manager.getFragmentFactory().instantiate( - context.getClassLoader(), HoursMinutesPickerFragment.class.getName()); - fragment.setArguments(args); - fragment.show(manager, null); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) - { - readArgs(); - final View root = createView(); - // noinspection ConstantConditions - mTabs.getTabAt(mSelectedTab).select(); - - final AlertDialog dialog = - new MaterialAlertDialogBuilder(requireActivity(), R.style.MwmMain_DialogFragment_TimePicker) - .setView(root) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, null) - .setCancelable(true) - .create(); - - dialog.setOnShowListener(dialogInterface -> { - mOkButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE); - mOkButton.setOnClickListener(v -> { - if (mSelectedTab == TAB_FROM) - { - // noinspection ConstantConditions - mTabs.getTabAt(TAB_TO).select(); - return; - } - - saveHoursMinutes(); - dismiss(); - if (getParentFragment() instanceof OnPickListener) - ((OnPickListener) getParentFragment()).onHoursMinutesPicked(mFrom, mTo, mId); - }); - refreshPicker(); - }); - - return dialog; - } - - private void readArgs() - { - final Bundle args = getArguments(); - if (args == null) - throw new IllegalArgumentException("Args must not be null"); - mFrom = Utils.getParcelable(args, EXTRA_FROM, HoursMinutes.class); - mTo = Utils.getParcelable(args, EXTRA_TO, HoursMinutes.class); - mSelectedTab = args.getInt(EXTRA_SELECT_FIRST); - mId = args.getInt(EXTRA_ID); - } - - private View createView() - { - final LayoutInflater inflater = LayoutInflater.from(requireActivity()); - @SuppressLint("InflateParams") - final View root = inflater.inflate(R.layout.fragment_timetable_picker, null); - - mPicker = root.findViewById(R.id.picker); - mPicker.setIs24HourView(DateFormat.is24HourFormat(requireActivity())); - @SuppressLint("DiscouragedApi") - int id = getResources().getIdentifier("hours", "id", "android"); - if (id != 0) - { - mPickerHoursLabel = mPicker.findViewById(id); - if (!(mPickerHoursLabel instanceof TextView)) - mPickerHoursLabel = null; - } - - mTabs = root.findViewById(R.id.tabs); - MaterialTextView tabView = (MaterialTextView) inflater.inflate(R.layout.tab_timepicker, mTabs, false); - tabView.setText(getResources().getString(R.string.editor_time_from)); - final ColorStateList textColor = - AppCompatResources.getColorStateList(requireContext(), R.color.accent_color_selector); - tabView.setTextColor(textColor); - mTabs.addTab(mTabs.newTab().setCustomView(tabView), true); - tabView = (MaterialTextView) inflater.inflate(R.layout.tab_timepicker, mTabs, false); - tabView.setText(getResources().getString(R.string.editor_time_to)); - tabView.setTextColor(textColor); - mTabs.addTab(mTabs.newTab().setCustomView(tabView), true); - mTabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { - @Override - public void onTabSelected(TabLayout.Tab tab) - { - if (!isInit()) - return; - - saveHoursMinutes(); - mSelectedTab = tab.getPosition(); - refreshPicker(); - if (mPickerHoursLabel != null) - mPickerHoursLabel.performClick(); - } - - @Override - public void onTabUnselected(TabLayout.Tab tab) - {} - - @Override - public void onTabReselected(TabLayout.Tab tab) - {} - }); - - return root; - } - - private void saveHoursMinutes() - { - boolean is24HourFormat = DateUtils.is24HourFormat(requireContext()); - final HoursMinutes hoursMinutes = - new HoursMinutes(mPicker.getCurrentHour(), mPicker.getCurrentMinute(), is24HourFormat); - if (mSelectedTab == TAB_FROM) - mFrom = hoursMinutes; - else - mTo = hoursMinutes; - } - - private boolean isInit() - { - return mOkButton != null && mPicker != null; - } - - private void refreshPicker() - { - if (!isInit()) - return; - - HoursMinutes hoursMinutes; - int okBtnRes; - if (mSelectedTab == TAB_FROM) - { - hoursMinutes = mFrom; - okBtnRes = R.string.next_button; - } - else - { - hoursMinutes = mTo; - okBtnRes = R.string.ok; - } - mPicker.setCurrentMinute((int) hoursMinutes.minutes); - mPicker.setCurrentHour((int) hoursMinutes.hours); - mOkButton.setText(okBtnRes); - } -} diff --git a/android/app/src/main/java/app/organicmaps/editor/SimpleTimetableAdapter.java b/android/app/src/main/java/app/organicmaps/editor/SimpleTimetableAdapter.java index 1b3497073..5d972a7fb 100644 --- a/android/app/src/main/java/app/organicmaps/editor/SimpleTimetableAdapter.java +++ b/android/app/src/main/java/app/organicmaps/editor/SimpleTimetableAdapter.java @@ -6,6 +6,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.LinearLayout; + import androidx.annotation.IdRes; import androidx.annotation.IntRange; import androidx.annotation.Nullable; @@ -29,13 +30,13 @@ import java.util.Calendar; import java.util.List; class SimpleTimetableAdapter extends RecyclerView.Adapter - implements HoursMinutesPickerFragment.OnPickListener, TimetableProvider + implements FromToTimePicker.OnPickListener, TimetableProvider { private static final int TYPE_TIMETABLE = 0; private static final int TYPE_ADD_TIMETABLE = 1; - private static final int ID_OPENING = 0; - private static final int ID_CLOSING = 1; + private static final int ID_OPENING_TIME = 0; + private static final int ID_CLOSED_SPAN = 1; private static final int[] DAYS = {R.id.day1, R.id.day2, R.id.day3, R.id.day4, R.id.day5, R.id.day6, R.id.day7}; @@ -69,7 +70,7 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter(Arrays.asList(OpeningHours.nativeAddWorkingDay(tts, position, day))); refreshComplement(); notifyDataSetChanged(); @@ -156,7 +163,7 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter(Arrays.asList(OpeningHours.nativeRemoveWorkingDay(tts, position, day))); refreshComplement(); notifyDataSetChanged(); @@ -262,13 +269,13 @@ class SimpleTimetableAdapter extends RecyclerView.Adapter - implements TimetableProvider, HoursMinutesPickerFragment.OnPickListener + implements TimetableProvider { private SimpleTimetableAdapter mAdapter; @Nullable @@ -57,10 +56,4 @@ public class SimpleTimetableFragment extends BaseMwmRecyclerFragment - - - - - - diff --git a/android/app/src/main/res/values/themes.xml b/android/app/src/main/res/values/themes.xml index 18d7eb3fa..c2b18be90 100644 --- a/android/app/src/main/res/values/themes.xml +++ b/android/app/src/main/res/values/themes.xml @@ -210,13 +210,11 @@ @android:color/transparent -