diff --git a/app/components/calendar-icon/calendar-icon.tsx b/app/components/calendar-icon/calendar-icon.tsx
new file mode 100644
index 00000000..3753a734
--- /dev/null
+++ b/app/components/calendar-icon/calendar-icon.tsx
@@ -0,0 +1,25 @@
+import { Image, ImageStyle, TouchableOpacity, ViewStyle } from "react-native"
+import { translate } from "../../i18n"
+
+const CalenderImageIcon = require("../../../assets/calendar.png")
+
+const ICON_STYLE: ImageStyle = {
+ width: 27,
+ height: 25,
+ resizeMode: "contain",
+ tintColor: "lightgrey",
+ opacity: 0.9,
+}
+const CONTAINER: ViewStyle = {
+ justifyContent: "center",
+}
+
+export const CalendarIcon = function CalendarIcon(props: { style?: ViewStyle; onPress: () => void }) {
+ const { onPress, style } = props
+
+ return (
+
+
+
+ )
+}
diff --git a/app/components/calendar-icon/index.ts b/app/components/calendar-icon/index.ts
new file mode 100644
index 00000000..a2b5cc95
--- /dev/null
+++ b/app/components/calendar-icon/index.ts
@@ -0,0 +1 @@
+export * from "./calendar-icon"
diff --git a/app/components/icon/icon.props.ts b/app/components/icon/icon.props.ts
deleted file mode 100644
index 6928ede2..00000000
--- a/app/components/icon/icon.props.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { ImageStyle, ViewStyle } from "react-native"
-import { IconTypes } from "./icons"
-
-export interface IconProps {
- /**
- * Style overrides for the icon image
- */
- style?: ImageStyle
-
- /**
- * Style overrides for the icon container
- */
-
- containerStyle?: ViewStyle
-
- /**
- * The name of the icon
- */
-
- icon?: IconTypes
-}
diff --git a/app/components/icon/icon.story.tsx b/app/components/icon/icon.story.tsx
deleted file mode 100644
index d119ed40..00000000
--- a/app/components/icon/icon.story.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as React from "react"
-import { storiesOf } from "@storybook/react-native"
-import { StoryScreen, Story, UseCase } from "../../../storybook/views"
-import { Icon } from "./icon"
-
-declare let module
-
-storiesOf("Icon", module)
- .addDecorator((fn) => {fn()})
- .add("Names", () => (
-
-
-
-
-
-
-
-
- ))
diff --git a/app/components/icon/icon.tsx b/app/components/icon/icon.tsx
deleted file mode 100644
index c2d9723f..00000000
--- a/app/components/icon/icon.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as React from "react"
-import { View, Image, ImageStyle } from "react-native"
-import { IconProps } from "./icon.props"
-import { icons } from "./icons"
-
-const ROOT: ImageStyle = {
- resizeMode: "contain",
-}
-
-export function Icon(props: IconProps) {
- const { style: styleOverride, icon, containerStyle } = props
- const style: ImageStyle = { ...ROOT, ...styleOverride }
-
- return (
-
-
-
- )
-}
diff --git a/app/components/icon/icons/arrow-left.png b/app/components/icon/icons/arrow-left.png
deleted file mode 100644
index 9d607d76..00000000
Binary files a/app/components/icon/icons/arrow-left.png and /dev/null differ
diff --git a/app/components/icon/icons/arrow-left@2x.png b/app/components/icon/icons/arrow-left@2x.png
deleted file mode 100644
index 9d607d76..00000000
Binary files a/app/components/icon/icons/arrow-left@2x.png and /dev/null differ
diff --git a/app/components/icon/icons/bullet.png b/app/components/icon/icons/bullet.png
deleted file mode 100644
index 8fc256f6..00000000
Binary files a/app/components/icon/icons/bullet.png and /dev/null differ
diff --git a/app/components/icon/icons/bullet@2x.png b/app/components/icon/icons/bullet@2x.png
deleted file mode 100644
index 8fc256f6..00000000
Binary files a/app/components/icon/icons/bullet@2x.png and /dev/null differ
diff --git a/app/components/icon/icons/index.ts b/app/components/icon/icons/index.ts
deleted file mode 100644
index 00e8a591..00000000
--- a/app/components/icon/icons/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export const icons = {
- back: require("./arrow-left.png"),
- bullet: require("./bullet.png"),
-}
-
-export type IconTypes = keyof typeof icons
diff --git a/app/components/index.ts b/app/components/index.ts
index 84d5048e..4ec6667a 100644
--- a/app/components/index.ts
+++ b/app/components/index.ts
@@ -1,6 +1,5 @@
export * from "./button/button"
export * from "./close-button/close-button"
-export * from "./icon/icon"
export * from "./screen/screen"
export * from "./text/text"
export * from "./dummy-input/dummy-input"
diff --git a/app/components/route-details-header/route-details-header.tsx b/app/components/route-details-header/route-details-header.tsx
index 7097a9cf..9e0dcd78 100644
--- a/app/components/route-details-header/route-details-header.tsx
+++ b/app/components/route-details-header/route-details-header.tsx
@@ -12,6 +12,9 @@ import { stationsObject, stationLocale } from "../../data/stations"
import { isRTL, translate } from "../../i18n"
import { useStores } from "../../models"
import * as Burnt from "burnt"
+import * as AddCalendarEvent from "react-native-add-calendar-event"
+import { CalendarIcon } from "../calendar-icon/calendar-icon"
+import { RouteItem } from "../../services/api"
const arrowIcon = require("../../../assets/arrow-left.png")
@@ -84,48 +87,60 @@ const HEADER_RIGHT_WRAPPER: ViewStyle = {
export interface RouteDetailsHeaderProps {
originId: string
destinationId: string
+ routeItem: RouteItem
/**
* The screen name we're displaying the header inside
*/
screenName?: "routeDetails" | "activeRide"
style?: ViewStyle
+ eventConfig?: AddCalendarEvent.CreateOptions
}
export const RouteDetailsHeader = observer(function RouteDetailsHeader(props: RouteDetailsHeaderProps) {
- const { originId, destinationId, screenName, style } = props
+ const { routeItem, originId, destinationId, screenName, style, eventConfig } = props
const { favoriteRoutes } = useStores()
const navigation = useNavigation()
+ const addToCalendar = () => {
+ const eventConfig = createEventConfig(routeItem)
+ AddCalendarEvent.presentEventCreatingDialog(eventConfig)
+ }
+
const originName = stationsObject[originId][stationLocale]
const destinationName = stationsObject[destinationId][stationLocale]
const routeId = `${originId}${destinationId}`
- const isFavorite: boolean = useMemo(() => {
- return favoriteRoutes.routes.find((favorite) => favorite.id === routeId)
- }, [favoriteRoutes.routes.length])
+ const isFavorite: boolean = useMemo(
+ () => !!favoriteRoutes.routes.find((favorite) => favorite.id === routeId),
+ [favoriteRoutes.routes.length],
+ )
useLayoutEffect(() => {
screenName !== "activeRide" &&
navigation.setOptions({
headerRight: () => (
- {
- const favorite = { id: routeId, originId, destinationId }
- if (!isFavorite) {
- Burnt.alert({ title: translate("favorites.added"), duration: 1.5 })
- HapticFeedback.trigger("impactMedium")
- favoriteRoutes.add(favorite)
- analytics().logEvent("favorite_route_added")
- } else {
- HapticFeedback.trigger("impactLight")
- favoriteRoutes.remove(favorite.id)
- analytics().logEvent("favorite_route_removed")
- }
- }}
- />
+ {screenName === "routeDetails" ? (
+
+ ) : (
+ {
+ const favorite = { id: routeId, originId, destinationId }
+ if (!isFavorite) {
+ Burnt.alert({ title: translate("favorites.added"), duration: 1.5 })
+ HapticFeedback.trigger("impactMedium")
+ favoriteRoutes.add(favorite)
+ analytics().logEvent("favorite_route_added")
+ } else {
+ HapticFeedback.trigger("impactLight")
+ favoriteRoutes.remove(favorite.id)
+ analytics().logEvent("favorite_route_removed")
+ }
+ }}
+ />
+ )}
),
})
@@ -160,3 +175,20 @@ export const RouteDetailsHeader = observer(function RouteDetailsHeader(props: Ro
)
})
+
+function createEventConfig(routeItem: RouteItem) {
+ const { destinationStationName: destination, originStationName: origin, trainNumber } = routeItem.trains[0]
+
+ const title = translate("plan.eventTitle", { destination })
+ const notes = translate("plan.trainFromToStation", { trainNumber, origin, destination })
+
+ const eventConfig: AddCalendarEvent.CreateOptions = {
+ title,
+ startDate: new Date(routeItem.departureTime).toISOString(),
+ endDate: new Date(routeItem.arrivalTime).toISOString(),
+ location: translate("plan.trainStation", { stationName: origin }),
+ notes,
+ }
+
+ return eventConfig
+}
diff --git a/app/components/star-icon/star-icon.tsx b/app/components/star-icon/star-icon.tsx
index f55b3966..ba871216 100644
--- a/app/components/star-icon/star-icon.tsx
+++ b/app/components/star-icon/star-icon.tsx
@@ -1,7 +1,7 @@
import React, { useMemo } from "react"
import { Image, TouchableOpacity, ImageStyle, ViewStyle } from "react-native"
import { observer } from "mobx-react-lite"
-import { color, spacing } from "../../theme"
+import { color } from "../../theme"
const starImage = require("../../../assets/star.png")
@@ -46,3 +46,4 @@ export const StarIcon = observer(function StarIcon(props: StarIconProps) {
)
})
+
diff --git a/app/i18n/ar.json b/app/i18n/ar.json
index 36c84135..d640636c 100644
--- a/app/i18n/ar.json
+++ b/app/i18n/ar.json
@@ -20,7 +20,10 @@
"find": "حساب المسار",
"resetTime": "إعادة تعيين الوقت",
"switchStations": "تبديل المحطات",
- "switchStationsHint": "اختصار لتبديل محطة البداية بمحطة الوصول"
+ "switchStationsHint": "اختصار لتبديل محطة البداية بمحطة الوصول",
+ "trainFromToStation": "القطار رقم %{trainNumber} من %{origin} إلى %{destination}",
+ "eventTitle": "رحلة إلى %{destination}",
+ "trainStation": "محطة القطار %{stationName}"
},
"selectStation": {
"placeholder": "البحث عن محطة",
@@ -47,7 +50,8 @@
"waitingTime": "مدة الانتظار",
"lastStop": "المحطة الأخيرة",
"routeWarning": "تحذير الطريق الطويل",
- "routeWarningText": "هناك طرق قطار أقصر حول وقت المغادرة."
+ "routeWarningText": "هناك طرق قطار أقصر حول وقت المغادرة.",
+ "addToCalendar": "إضافة إلى التقويم"
},
"settings": {
"title": "اعدادت",
diff --git a/app/i18n/en.json b/app/i18n/en.json
index 4a1fbfb2..898479af 100644
--- a/app/i18n/en.json
+++ b/app/i18n/en.json
@@ -24,7 +24,10 @@
"find": "Find Routes",
"resetTime": "Reset Time",
"switchStations": "Flip stations",
- "switchStationsHint": "A shortcut to flip the origin station with the destination station"
+ "switchStationsHint": "A shortcut to flip the origin station with the destination station",
+ "trainFromToStation": "Train No. %{trainNumber} from %{origin} to %{destination}",
+ "eventTitle": "Ride to %{destination}",
+ "trainStation": "%{stationName} Train Station"
},
"selectStation": {
"placeholder": "Search Stations",
@@ -55,7 +58,8 @@
"minutes": "min",
"lastStop": "Last Stop",
"routeWarning": "Long Route Warning",
- "routeWarningText": "There are shorter train routes around the departure time."
+ "routeWarningText": "There are shorter train routes around the departure time.",
+ "addToCalendar": "Add to Calendar"
},
"settings": {
"title": "Settings",
diff --git a/app/i18n/he.json b/app/i18n/he.json
index 728b3a59..b6473e44 100644
--- a/app/i18n/he.json
+++ b/app/i18n/he.json
@@ -24,7 +24,10 @@
"find": "חישוב מסלול",
"resetTime": "איפוס זמן",
"switchStations": "החלפת תחנות",
- "switchStationsHint": "קיצור דרך להחלפת תחנת המוצא עם תחנת היעד"
+ "switchStationsHint": "קיצור דרך להחלפת תחנת המוצא עם תחנת היעד",
+ "trainFromToStation": "רכבת מס' %{trainNumber} מ%{origin} אל %{destination}",
+ "eventTitle": "נסיעה ל%{destination}",
+ "trainStation": "תחנת רכבת %{stationName}"
},
"selectStation": {
"placeholder": "חיפוש תחנה",
@@ -55,7 +58,8 @@
"minutes": "דק'",
"lastStop": "יעד סופי",
"routeWarning": "רכבת מאספת",
- "routeWarningText": "קיימים מסלולי נסיעה קצרים יותר סביב שעת היציאה הנבחרת"
+ "routeWarningText": "קיימים מסלולי נסיעה קצרים יותר סביב שעת היציאה הנבחרת",
+ "addToCalendar": "הוספה ליומן"
},
"settings": {
"title": "הגדרות",
diff --git a/app/i18n/ru.json b/app/i18n/ru.json
index b19b83f3..13bb3a29 100644
--- a/app/i18n/ru.json
+++ b/app/i18n/ru.json
@@ -24,7 +24,10 @@
"find": "Найти маршруты",
"resetTime": "сбросить время",
"switchStations": "Перевернуть станции",
- "switchStationsHint": "Ярлык для перестановки исходной станции со станцией назначения"
+ "switchStationsHint": "Ярлык для перестановки исходной станции со станцией назначения",
+ "trainFromToStation": "Поезд № %{trainNumber} из %{origin} в %{destination}",
+ "eventTitle": "Поездка в %{destination}",
+ "trainStation": "%{stationName} станция"
},
"selectStation": {
"placeholder": "Поиск остановки",
@@ -54,7 +57,8 @@
"minutes": "минут",
"lastStop": "Последняя остановка",
"routeWarning": "Предупреждение о длинном маршруте",
- "routeWarningText": "Во время отправления есть более короткие маршруты поездов."
+ "routeWarningText": "Во время отправления есть более короткие маршруты поездов.",
+ "addToCalendar": "Добавить в календарь"
},
"settings": {
"title": "Настройки",
diff --git a/app/screens/route-details/route-details-screen.tsx b/app/screens/route-details/route-details-screen.tsx
index f28cbf80..f7dbdb4a 100644
--- a/app/screens/route-details/route-details-screen.tsx
+++ b/app/screens/route-details/route-details-screen.tsx
@@ -1,6 +1,6 @@
/* eslint-disable react-native/no-inline-styles */
import React, { useEffect, useMemo, useRef, useState } from "react"
-import { Platform, View, ViewStyle } from "react-native"
+import { View, ViewStyle } from "react-native"
import { observer } from "mobx-react-lite"
import { useSafeAreaInsets } from "react-native-safe-area-context"
import { SharedElement } from "react-navigation-shared-element"
@@ -14,17 +14,25 @@ import { useRideProgress } from "../../hooks/use-ride-progress"
import { RouteDetailsScreenProps } from "../../navigators/main-navigator"
import { color, spacing } from "../../theme"
import { RouteDetailsHeader, Screen } from "../../components"
-import { RouteStationCard, RouteStopCard, RouteLine, RouteExchangeDetails } from "./components"
-import { LiveRideSheet, LongRouteWarning, StartRideButton } from "./components"
+import {
+ LiveRideSheet,
+ LongRouteWarning,
+ RouteExchangeDetails,
+ RouteLine,
+ RouteStationCard,
+ RouteStopCard,
+ StartRideButton,
+} from "./components"
import BottomSheet from "@gorhom/bottom-sheet"
import { FirstRideAlert } from "./components/first-ride-alert"
import { canRunLiveActivities } from "../../utils/ios-helpers"
+import { CreateOptions } from "react-native-add-calendar-event"
+import { translate } from "../../i18n"
const ROOT: ViewStyle = {
flex: 1,
backgroundColor: color.background,
}
-
export const RouteDetailsScreen = observer(function RouteDetailsScreen({ route }: RouteDetailsScreenProps) {
const { ride } = useStores()
const bottomSheetRef = useRef(null)
@@ -66,6 +74,7 @@ export const RouteDetailsScreen = observer(function RouteDetailsScreen({ route }
>