forked from organicmaps/organicmaps
[ios] Show "Opens in"/"Closes in" in PlacePagePreview
Signed-off-by: David Martinez <47610359+dvdmrtnz@users.noreply.github.com>
This commit is contained in:
parent
383f3595fa
commit
bec4e9d56b
4 changed files with 142 additions and 30 deletions
|
@ -14,13 +14,19 @@ typedef NS_ENUM(NSInteger, PlacePageDataHotelType) {
|
|||
PlacePageDataHotelTypeNone
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, PlacePageDataSchedule) {
|
||||
typedef NS_ENUM(NSInteger, PlacePageDataOpeningHours) {
|
||||
PlacePageDataOpeningHoursAllDay,
|
||||
PlacePageDataOpeningHoursOpen,
|
||||
PlacePageDataOpeningHoursClosed,
|
||||
PlacePageDataOpeningHoursUnknown
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PlacePageDataOpeningHours state;
|
||||
time_t nextTimeOpen;
|
||||
time_t nextTimeClosed;
|
||||
} PlacePageDataSchedule;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface PlacePagePreviewData : NSObject
|
||||
|
|
|
@ -3,27 +3,45 @@
|
|||
#include "3party/opening_hours/opening_hours.hpp"
|
||||
|
||||
static PlacePageDataSchedule convertOpeningHours(std::string_view rawOH) {
|
||||
if (rawOH.empty())
|
||||
return PlacePageDataOpeningHoursUnknown;
|
||||
|
||||
PlacePageDataSchedule schedule;
|
||||
|
||||
if (rawOH.empty()) {
|
||||
schedule.state = PlacePageDataOpeningHoursUnknown;
|
||||
return schedule;
|
||||
}
|
||||
|
||||
/// @todo Avoid temporary string when OpeningHours (boost::spirit) will allow string_view.
|
||||
osmoh::OpeningHours oh((std::string(rawOH)));
|
||||
if (!oh.IsValid()) {
|
||||
return PlacePageDataOpeningHoursUnknown;
|
||||
schedule.state = PlacePageDataOpeningHoursUnknown;
|
||||
return schedule;
|
||||
}
|
||||
|
||||
if (oh.IsTwentyFourHours()) {
|
||||
return PlacePageDataOpeningHoursAllDay;
|
||||
schedule.state = PlacePageDataOpeningHoursAllDay;
|
||||
return schedule;
|
||||
}
|
||||
|
||||
auto const t = time(nullptr);
|
||||
if (oh.IsOpen(t)) {
|
||||
return PlacePageDataOpeningHoursOpen;
|
||||
osmoh::OpeningHours::InfoT info = oh.GetInfo(t);
|
||||
switch (info.state) {
|
||||
case osmoh::RuleState::Open:
|
||||
schedule.state = PlacePageDataOpeningHoursOpen;
|
||||
schedule.nextTimeClosed = info.nextTimeClosed;
|
||||
break;
|
||||
|
||||
case osmoh::RuleState::Closed:
|
||||
schedule.state = PlacePageDataOpeningHoursClosed;
|
||||
schedule.nextTimeOpen = info.nextTimeOpen;
|
||||
break;
|
||||
|
||||
case osmoh::RuleState::Unknown:
|
||||
schedule.state = PlacePageDataOpeningHoursUnknown;
|
||||
break;
|
||||
}
|
||||
if (oh.IsClosed(t)) {
|
||||
return PlacePageDataOpeningHoursClosed;
|
||||
}
|
||||
|
||||
return PlacePageDataOpeningHoursUnknown;
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
static PlacePageDataHotelType convertHotelType(std::optional<ftypes::IsHotelChecker::Type> hotelType) {
|
||||
|
|
|
@ -133,18 +133,109 @@ final class PlacePagePreviewViewController: UIViewController {
|
|||
// MARK: private
|
||||
|
||||
private func configSchedule() {
|
||||
switch placePagePreviewData.schedule {
|
||||
case .openingHoursAllDay:
|
||||
scheduleLabel.text = L("twentyfour_seven")
|
||||
case .openingHoursOpen:
|
||||
scheduleLabel.text = L("editor_time_open")
|
||||
case .openingHoursClosed:
|
||||
scheduleLabel.text = L("closed_now")
|
||||
scheduleLabel.textColor = UIColor.red
|
||||
case .openingHoursUnknown:
|
||||
let now = time_t(Date().timeIntervalSince1970);
|
||||
|
||||
let hourFormatter = DateFormatter();
|
||||
hourFormatter.dateFormat = "HH:mm";
|
||||
|
||||
switch placePagePreviewData.schedule.state {
|
||||
case .allDay:
|
||||
setScheduleLabel(state: L("twentyfour_seven"),
|
||||
stateColor: UIColor.systemGreen,
|
||||
details: nil);
|
||||
|
||||
case .open:
|
||||
let nextTimeClosed = placePagePreviewData.schedule.nextTimeClosed;
|
||||
let minutesUntilClosed = (nextTimeClosed - now) / 60;
|
||||
let stringTimeInterval = getTimeIntervalString(minutes: minutesUntilClosed);
|
||||
let stringTime = hourFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(nextTimeClosed)));
|
||||
|
||||
let details: String?;
|
||||
if (minutesUntilClosed < 3 * 60) // Less than 3 hours
|
||||
{
|
||||
details = String(format: L("closes_in"), stringTimeInterval) + " • " + stringTime;
|
||||
}
|
||||
else if (minutesUntilClosed < 24 * 60) // Less than 24 hours
|
||||
{
|
||||
details = String(format: L("closes_at"), stringTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
details = nil;
|
||||
}
|
||||
|
||||
setScheduleLabel(state: L("editor_time_open"),
|
||||
stateColor: UIColor.systemGreen,
|
||||
details: details);
|
||||
|
||||
case .closed:
|
||||
let nextTimeOpen = placePagePreviewData.schedule.nextTimeOpen;
|
||||
let nextTimeOpenDate = Date(timeIntervalSince1970: TimeInterval(nextTimeOpen));
|
||||
|
||||
let minutesUntilOpen = (nextTimeOpen - now) / 60;
|
||||
let stringTimeInterval = getTimeIntervalString(minutes: minutesUntilOpen);
|
||||
let stringTime = hourFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(nextTimeOpen)));
|
||||
|
||||
let details: String?;
|
||||
if (minutesUntilOpen < 3 * 60) // Less than 3 hours
|
||||
{
|
||||
details = String(format: L("opens_in"), stringTimeInterval) + " • " + stringTime;
|
||||
}
|
||||
else if (Calendar.current.isDateInToday(nextTimeOpenDate)) // Today
|
||||
{
|
||||
details = String(format: L("opens_at"), stringTime);
|
||||
}
|
||||
else if (minutesUntilOpen < 24 * 60) // Less than 24 hours
|
||||
{
|
||||
details = String(format: L("opens_tomorrow_at"), stringTime);
|
||||
}
|
||||
else if (minutesUntilOpen < 7 * 24 * 60) // Less than 1 week
|
||||
{
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "EEEE";
|
||||
let dayOfWeek = dateFormatter.string(from: nextTimeOpenDate);
|
||||
details = String(format: L("opens_dayoftheweek_at"), dayOfWeek, stringTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
details = nil;
|
||||
}
|
||||
|
||||
setScheduleLabel(state: L("closed_now"),
|
||||
stateColor: UIColor.systemRed,
|
||||
details: details);
|
||||
|
||||
case .unknown:
|
||||
scheduleContainerView.isHidden = true
|
||||
|
||||
@unknown default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
private func getTimeIntervalString(minutes: Int) -> String {
|
||||
var str = "";
|
||||
if (minutes > 60)
|
||||
{
|
||||
str = String(minutes / 60) + " " + L("hour") + " ";
|
||||
}
|
||||
str += String(minutes % 60) + " " + L("minute");
|
||||
return str;
|
||||
}
|
||||
|
||||
private func setScheduleLabel(state: String, stateColor: UIColor, details: String?) {
|
||||
let attributedString = NSMutableAttributedString();
|
||||
let stateString = NSAttributedString(string: state,
|
||||
attributes: [NSAttributedString.Key.font: UIFont.regular14(),
|
||||
NSAttributedString.Key.foregroundColor: stateColor]);
|
||||
attributedString.append(stateString);
|
||||
if (details != nil)
|
||||
{
|
||||
let detailsString = NSAttributedString(string: " • " + details!,
|
||||
attributes: [NSAttributedString.Key.font: UIFont.regular14(),
|
||||
NSAttributedString.Key.foregroundColor: UIColor.blackSecondaryText()]);
|
||||
attributedString.append(detailsString);
|
||||
}
|
||||
scheduleLabel.attributedText = attributedString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="bX8-ZQ-XDA">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="bX8-ZQ-XDA">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="Stack View standard spacing" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
|
@ -219,14 +219,11 @@
|
|||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fKt-f3-qqN">
|
||||
<rect key="frame" x="4" y="58" width="367" height="96"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" text="Open" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="caI-ec-meo">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" text="Open" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="caI-ec-meo">
|
||||
<rect key="frame" x="12" y="0.0" width="343" height="96"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="regular14:blackSecondaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
</subviews>
|
||||
<edgeInsets key="layoutMargins" top="0.0" left="12" bottom="0.0" right="12"/>
|
||||
|
@ -510,10 +507,10 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="021-FW-tZO">
|
||||
<rect key="frame" x="16" y="16" width="343" height="78"/>
|
||||
<rect key="frame" x="16" y="16" width="343" height="224"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RUc-Qr-8Sb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="164"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="OYY-L8-CtC"/>
|
||||
</constraints>
|
||||
|
@ -528,7 +525,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bAP-Be-X7d">
|
||||
<rect key="frame" x="0.0" y="60" width="343" height="18"/>
|
||||
<rect key="frame" x="0.0" y="180" width="343" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="fBI-zz-Fkk"/>
|
||||
</constraints>
|
||||
|
|
Loading…
Add table
Reference in a new issue