[ios] Show "Opens in"/"Closes in" in PlacePagePreview

Signed-off-by: David Martinez <47610359+dvdmrtnz@users.noreply.github.com>
This commit is contained in:
David Martinez 2022-08-02 23:34:29 +02:00 committed by Viktor Govako
parent 383f3595fa
commit bec4e9d56b
4 changed files with 142 additions and 30 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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>