diff --git a/android/res/layout/place_page_details.xml b/android/res/layout/place_page_details.xml
index 1bf81f6941..d50113d60e 100644
--- a/android/res/layout/place_page_details.xml
+++ b/android/res/layout/place_page_details.xml
@@ -29,7 +29,11 @@
-
+
diff --git a/android/res/layout/place_page_opening_hours.xml b/android/res/layout/place_page_opening_hours_fragment.xml
similarity index 98%
rename from android/res/layout/place_page_opening_hours.xml
rename to android/res/layout/place_page_opening_hours_fragment.xml
index 6410318397..a744f94979 100644
--- a/android/res/layout/place_page_opening_hours.xml
+++ b/android/res/layout/place_page_opening_hours_fragment.xml
@@ -3,7 +3,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/ll__place_schedule"
style="@style/PlacePageItemFrame"
android:tag="schedule">
diff --git a/android/src/app/organicmaps/widget/placepage/PlacePageOpeningHoursFragment.java b/android/src/app/organicmaps/widget/placepage/PlacePageOpeningHoursFragment.java
new file mode 100644
index 0000000000..dfd0891b38
--- /dev/null
+++ b/android/src/app/organicmaps/widget/placepage/PlacePageOpeningHoursFragment.java
@@ -0,0 +1,193 @@
+package app.organicmaps.widget.placepage;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.Observer;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.RecyclerView;
+import app.organicmaps.R;
+import app.organicmaps.bookmarks.data.MapObject;
+import app.organicmaps.bookmarks.data.Metadata;
+import app.organicmaps.editor.OpeningHours;
+import app.organicmaps.editor.data.TimeFormatUtils;
+import app.organicmaps.editor.data.Timespan;
+import app.organicmaps.editor.data.Timetable;
+import app.organicmaps.util.ThemeUtils;
+import app.organicmaps.util.UiUtils;
+import app.organicmaps.util.Utils;
+
+import java.util.Calendar;
+import java.util.Locale;
+
+public class PlacePageOpeningHoursFragment extends Fragment implements Observer
+{
+ private View mFrame;
+ private TextView mTodayLabel;
+ private TextView mTodayOpenTime;
+ private TextView mTodayNonBusinessTime;
+ private RecyclerView mFullWeekOpeningHours;
+ private PlaceOpeningHoursAdapter mOpeningHoursAdapter;
+
+ private PlacePageViewModel viewModel;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
+ {
+ return inflater.inflate(R.layout.place_page_opening_hours_fragment, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
+ {
+ super.onViewCreated(view, savedInstanceState);
+ mFrame = view;
+ mTodayLabel = view.findViewById(R.id.oh_today_label);
+ mTodayOpenTime = view.findViewById(R.id.oh_today_open_time);
+ mTodayNonBusinessTime = view.findViewById(R.id.oh_nonbusiness_time);
+ mFullWeekOpeningHours = view.findViewById(R.id.rw__full_opening_hours);
+ mOpeningHoursAdapter = new PlaceOpeningHoursAdapter();
+ mFullWeekOpeningHours.setAdapter(mOpeningHoursAdapter);
+
+ viewModel = new ViewModelProvider(requireActivity()).get(PlacePageViewModel.class);
+ viewModel.getMapObject().observe(requireActivity(), this);
+ }
+
+ private void refreshTodayNonBusinessTime(Timespan[] closedTimespans)
+ {
+ final String hoursClosedLabel = getResources().getString(R.string.editor_hours_closed);
+ if (closedTimespans == null || closedTimespans.length == 0)
+ UiUtils.clearTextAndHide(mTodayNonBusinessTime);
+ else
+ UiUtils.setTextAndShow(mTodayNonBusinessTime, TimeFormatUtils.formatNonBusinessTime(closedTimespans, hoursClosedLabel));
+ }
+
+ private void refreshTodayOpeningHours(String label, String openTime, @ColorInt int color)
+ {
+ UiUtils.setTextAndShow(mTodayLabel, label);
+ UiUtils.setTextAndShow(mTodayOpenTime, openTime);
+
+ mTodayLabel.setTextColor(color);
+ mTodayOpenTime.setTextColor(color);
+ }
+
+ private void refreshTodayOpeningHours(String label, @ColorInt int color)
+ {
+ UiUtils.setTextAndShow(mTodayLabel, label);
+ UiUtils.hide(mTodayOpenTime);
+
+ mTodayLabel.setTextColor(color);
+ mTodayOpenTime.setTextColor(color);
+ }
+
+ private void refreshOpeningHours()
+ {
+ final String ohStr = viewModel.getMapObject()
+ .getValue()
+ .getMetadata(Metadata.MetadataType.FMD_OPEN_HOURS);
+ final Timetable[] timetables = OpeningHours.nativeTimetablesFromString(ohStr);
+ mFrame.setOnLongClickListener((v) -> {
+ PlacePageUtils.copyToClipboard(requireContext(), mFrame, TimeFormatUtils.formatTimetables(getResources(), ohStr, timetables));
+ return true;
+ });
+
+ final boolean isEmptyTT = (timetables == null || timetables.length == 0);
+ final int color = ThemeUtils.getColor(requireContext(), android.R.attr.textColorPrimary);
+
+ if (isEmptyTT)
+ {
+ // 'opening_hours' tag wasn't parsed either because it's empty or wrong format.
+ if (!ohStr.isEmpty())
+ {
+ UiUtils.show(mFrame);
+ refreshTodayOpeningHours(ohStr, color);
+ UiUtils.hide(mTodayNonBusinessTime);
+ UiUtils.hide(mFullWeekOpeningHours);
+ }
+ else
+ UiUtils.hide(mFrame);
+ }
+ else
+ {
+ UiUtils.show(mFrame);
+ final Resources resources = getResources();
+ if (timetables[0].isFullWeek())
+ {
+ final Timetable tt = timetables[0];
+ if (tt.isFullday)
+ {
+ refreshTodayOpeningHours(resources.getString(R.string.twentyfour_seven), color);
+ UiUtils.clearTextAndHide(mTodayNonBusinessTime);
+ UiUtils.hide(mTodayNonBusinessTime);
+ }
+ else
+ {
+ refreshTodayOpeningHours(resources.getString(R.string.daily), tt.workingTimespan.toWideString(), color);
+ refreshTodayNonBusinessTime(tt.closedTimespans);
+ }
+ UiUtils.hide(mFullWeekOpeningHours);
+ }
+ else
+ {
+ // Show whole week time table.
+ int firstDayOfWeek = Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek();
+ mOpeningHoursAdapter.setTimetables(timetables, firstDayOfWeek);
+ UiUtils.show(mFullWeekOpeningHours);
+
+ // Show today's open time + non-business time.
+ boolean containsCurrentWeekday = false;
+ final int currentDay = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
+ for (Timetable tt : timetables)
+ {
+ if (tt.containsWeekday(currentDay))
+ {
+ containsCurrentWeekday = true;
+ String openTime;
+
+ if (tt.isFullday)
+ {
+ String allDay = resources.getString(R.string.editor_time_allday);
+ openTime = Utils.unCapitalize(allDay);
+ }
+ else
+ openTime = tt.workingTimespan.toWideString();
+
+ refreshTodayOpeningHours(resources.getString(R.string.today), openTime, color);
+ refreshTodayNonBusinessTime(tt.closedTimespans);
+
+ break;
+ }
+ }
+
+ // Show that place is closed today.
+ if (!containsCurrentWeekday)
+ {
+ refreshTodayOpeningHours(resources.getString(R.string.day_off_today), resources.getColor(R.color.base_red));
+ UiUtils.hide(mTodayNonBusinessTime);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+ viewModel.getMapObject().removeObserver(this);
+ }
+
+ @Override
+ public void onChanged(MapObject mapObject)
+ {
+ refreshOpeningHours();
+ }
+}
diff --git a/android/src/app/organicmaps/widget/placepage/PlacePageView.java b/android/src/app/organicmaps/widget/placepage/PlacePageView.java
index 3839722c74..3158e25085 100644
--- a/android/src/app/organicmaps/widget/placepage/PlacePageView.java
+++ b/android/src/app/organicmaps/widget/placepage/PlacePageView.java
@@ -80,6 +80,7 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
private static final String BOOKMARK_FRAGMENT_TAG = "BOOKMARK_FRAGMENT_TAG";
private static final String WIKIPEDIA_FRAGMENT_TAG = "WIKIPEDIA_FRAGMENT_TAG";
private static final String PHONE_FRAGMENT_TAG = "PHONE_FRAGMENT_TAG";
+ private static final String OPENING_HOURS_FRAGMENT_TAG = "OPENING_HOURS_FRAGMENT_TAG";
private static final List visibleCoordsFormat =
Arrays.asList(CoordinatesFormat.LatLonDMS,
@@ -112,12 +113,6 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
private TextView mTvVkPage;
private View mLinePage;
private TextView mTvLinePage;
- private View mOpeningHours;
- private TextView mTodayLabel;
- private TextView mTodayOpenTime;
- private TextView mTodayNonBusinessTime;
- private RecyclerView mFullWeekOpeningHours;
- private PlaceOpeningHoursAdapter mOpeningHoursAdapter;
private View mWifi;
private TextView mTvWiFi;
private View mEmail;
@@ -324,13 +319,6 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
LinearLayout latlon = mFrame.findViewById(R.id.ll__place_latlon);
latlon.setOnClickListener(this);
mTvLatlon = mFrame.findViewById(R.id.tv__place_latlon);
- mOpeningHours = mFrame.findViewById(R.id.ll__place_schedule);
- mTodayLabel = mFrame.findViewById(R.id.oh_today_label);
- mTodayOpenTime = mFrame.findViewById(R.id.oh_today_open_time);
- mTodayNonBusinessTime = mFrame.findViewById(R.id.oh_nonbusiness_time);
- mFullWeekOpeningHours = mFrame.findViewById(R.id.rw__full_opening_hours);
- mOpeningHoursAdapter = new PlaceOpeningHoursAdapter();
- mFullWeekOpeningHours.setAdapter(mOpeningHoursAdapter);
mWifi = mFrame.findViewById(R.id.ll__place_wifi);
mTvWiFi = mFrame.findViewById(R.id.tv__place_wifi);
mEmail = mFrame.findViewById(R.id.ll__place_email);
@@ -356,7 +344,6 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
address.setOnLongClickListener(this);
mWebsite.setOnLongClickListener(this);
mWikimedia.setOnLongClickListener(this);
- mOpeningHours.setOnLongClickListener(this);
mEmail.setOnLongClickListener(this);
mOperator.setOnLongClickListener(this);
mLevel.setOnLongClickListener(this);
@@ -565,6 +552,30 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
updateButtons(showBackButton, showRoutingButton);
}
+ private void updateOpeningHoursView()
+ {
+ final FragmentManager fManager = getChildFragmentManager();
+ final PlacePageOpeningHoursFragment fragment = (PlacePageOpeningHoursFragment) fManager.findFragmentByTag(OPENING_HOURS_FRAGMENT_TAG);
+ final String ohStr = viewModel.getMapObject()
+ .getValue()
+ .getMetadata(Metadata.MetadataType.FMD_OPEN_HOURS);
+ final Timetable[] timetables = OpeningHours.nativeTimetablesFromString(ohStr);
+ final boolean isEmptyTT = (timetables == null || timetables.length == 0);
+
+ if (!isEmptyTT && fragment == null)
+ {
+ fManager.beginTransaction()
+ .add(R.id.place_page_opening_hours_fragment, PlacePageOpeningHoursFragment.class, null, OPENING_HOURS_FRAGMENT_TAG)
+ .commit();
+ }
+ else if (isEmptyTT && fragment != null)
+ {
+ fManager.beginTransaction()
+ .remove(fragment)
+ .commit();
+ }
+ }
+
private void updatePhoneView()
{
final FragmentManager fManager = getChildFragmentManager();
@@ -667,7 +678,6 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
refreshMetadataOrHide(Framework.nativeGetActiveObjectFormattedCuisine(), mCuisine, mTvCuisine);
refreshWiFi();
refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_FLATS), mEntrance, mTvEntrance);
- refreshOpeningHours();
refreshSocialLinks();
refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_LEVEL), mLevel, mTvLevel);
@@ -686,105 +696,10 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
|| UiUtils.isVisible(mAddOrganisation)
|| UiUtils.isVisible(mAddPlace), mEditTopSpace);
}
+ updateOpeningHoursView();
updateWikipediaView();
}
- private void refreshOpeningHours()
- {
- final String ohStr = mMapObject.getMetadata(Metadata.MetadataType.FMD_OPEN_HOURS);
- final Timetable[] timetables = OpeningHours.nativeTimetablesFromString(ohStr);
- final boolean isEmptyTT = (timetables == null || timetables.length == 0);
- final int color = ThemeUtils.getColor(requireContext(), android.R.attr.textColorPrimary);
-
- if (isEmptyTT)
- {
- // 'opening_hours' tag wasn't parsed either because it's empty or wrong format.
- if (!ohStr.isEmpty())
- {
- UiUtils.show(mOpeningHours);
- refreshTodayOpeningHours(ohStr, color);
- UiUtils.hide(mTodayNonBusinessTime);
- UiUtils.hide(mFullWeekOpeningHours);
- }
- else
- {
- UiUtils.hide(mOpeningHours);
- }
- return;
- }
-
- UiUtils.show(mOpeningHours);
-
- final Resources resources = getResources();
-
- if (timetables[0].isFullWeek())
- {
- final Timetable tt = timetables[0];
- if (tt.isFullday)
- {
- refreshTodayOpeningHours(resources.getString(R.string.twentyfour_seven), color);
- UiUtils.clearTextAndHide(mTodayNonBusinessTime);
- UiUtils.hide(mTodayNonBusinessTime);
- }
- else
- {
- refreshTodayOpeningHours(resources.getString(R.string.daily), tt.workingTimespan.toWideString(), color);
- refreshTodayNonBusinessTime(tt.closedTimespans);
- }
-
- UiUtils.hide(mFullWeekOpeningHours);
- return;
- }
-
- // Show whole week time table.
- int firstDayOfWeek = Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek();
- mOpeningHoursAdapter.setTimetables(timetables, firstDayOfWeek);
- UiUtils.show(mFullWeekOpeningHours);
-
- // Show today's open time + non-business time.
- boolean containsCurrentWeekday = false;
- final int currentDay = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
- for (Timetable tt : timetables)
- {
- if (tt.containsWeekday(currentDay))
- {
- containsCurrentWeekday = true;
- String openTime;
-
- if (tt.isFullday)
- {
- String allDay = resources.getString(R.string.editor_time_allday);
- openTime = Utils.unCapitalize(allDay);
- }
- else
- {
- openTime = tt.workingTimespan.toWideString();
- }
-
- refreshTodayOpeningHours(resources.getString(R.string.today), openTime, color);
- refreshTodayNonBusinessTime(tt.closedTimespans);
-
- break;
- }
- }
-
- // Show that place is closed today.
- if (!containsCurrentWeekday)
- {
- refreshTodayOpeningHours(resources.getString(R.string.day_off_today), resources.getColor(R.color.base_red));
- UiUtils.hide(mTodayNonBusinessTime);
- }
- }
-
- private void refreshTodayNonBusinessTime(Timespan[] closedTimespans)
- {
- final String hoursClosedLabel = getResources().getString(R.string.editor_hours_closed);
- if (closedTimespans == null || closedTimespans.length == 0)
- UiUtils.clearTextAndHide(mTodayNonBusinessTime);
- else
- UiUtils.setTextAndShow(mTodayNonBusinessTime, TimeFormatUtils.formatNonBusinessTime(closedTimespans, hoursClosedLabel));
- }
-
private void refreshWiFi()
{
final String inet = mMapObject.getMetadata(Metadata.MetadataType.FMD_INTERNET);
@@ -846,24 +761,6 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
}
}
- private void refreshTodayOpeningHours(String label, String openTime, @ColorInt int color)
- {
- UiUtils.setTextAndShow(mTodayLabel, label);
- UiUtils.setTextAndShow(mTodayOpenTime, openTime);
-
- mTodayLabel.setTextColor(color);
- mTodayOpenTime.setTextColor(color);
- }
-
- private void refreshTodayOpeningHours(String label, @ColorInt int color)
- {
- UiUtils.setTextAndShow(mTodayLabel, label);
- UiUtils.hide(mTodayOpenTime);
-
- mTodayLabel.setTextColor(color);
- mTodayOpenTime.setTextColor(color);
- }
-
private void updateBookmarkButton()
{
final List currentButtons = viewModel.getCurrentButtons()
@@ -1133,12 +1030,6 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
}
else if (id == R.id.ll__place_email)
items.add(mTvEmail.getText().toString());
- else if (id == R.id.ll__place_schedule)
- {
- final String ohStr = mMapObject.getMetadata(Metadata.MetadataType.FMD_OPEN_HOURS);
- final Timetable[] timetables = OpeningHours.nativeTimetablesFromString(ohStr);
- items.add(TimeFormatUtils.formatTimetables(getResources(), ohStr, timetables));
- }
else if (id == R.id.ll__place_operator)
items.add(mTvOperator.getText().toString());
else if (id == R.id.ll__place_level)