From d45134afd2bff65deb29492a95a36a8306447108 Mon Sep 17 00:00:00 2001 From: Robert Eggl Date: Fri, 16 Aug 2024 00:50:01 +0200 Subject: [PATCH] React Native 0.75 & new toast library --- android/app/build.gradle | 37 +- .../src/main/res/drawable/account_circle.xml | 5 + .../src/main/res/drawable/calendar_month.xml | 2 +- android/app/src/main/res/drawable/map.xml | 2 +- .../res/drawable/silverware_fork_knife.xml | 2 +- android/app/src/main/res/resources.properties | 1 - android/app/src/main/res/values/strings.xml | 2 +- android/app/src/main/res/values/styles.xml | 2 +- android/gradle.properties | 3 + android/gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43453 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle | 45 +- app.config.json | 7 +- bun.lockb | Bin 785837 -> 820472 bytes ios/NeulandNext.xcodeproj/project.pbxproj | 241 ++-- .../xcshareddata/swiftpm/Package.resolved | 15 - ios/NeulandNext/Images.xcassets/Contents.json | 4 +- ios/NeulandNext/Info.plist | 7 +- ios/NeulandNext/NeulandNext.entitlements | 2 - .../NeulandNextRelease.entitlements | 11 - ios/Podfile | 18 +- ios/Podfile.lock | 1069 ++++++++++++----- ios/TestFlight/WhatToTest.de-DE.txt | 5 +- ios/TestFlight/WhatToTest.en-US.txt | 5 +- package.json | 54 +- ...Freact-navigation-bottom-sheet@0.3.2.patch | 22 + patches/react-native-pager-view@6.3.4.patch | 13 + patches/react-native-paper@5.12.5.patch | 247 ++++ patches/react-native-shimmer@0.6.0.patch | 15 + patches/react-native-week-view@0.30.0.patch | 90 ++ react-native.config.js | 3 - src/app/(flow)/onboarding.tsx | 11 +- src/app/(screens)/clEvents.tsx | 4 +- src/app/(screens)/dashboard.tsx | 20 +- src/app/(screens)/lecture.tsx | 59 +- src/app/(screens)/lecturers.tsx | 4 +- src/app/(screens)/profile.tsx | 100 +- src/app/(screens)/webView.tsx | 59 +- src/app/(tabs)/(food)/index.tsx | 4 +- src/app/(tabs)/(index)/index.tsx | 19 +- src/app/(tabs)/(index)/links.tsx | 2 +- src/app/(tabs)/_layout.tsx | 27 +- src/components/Cards/BaseCard.tsx | 36 +- src/components/Cards/LibraryCard.tsx | 3 +- src/components/Cards/LinkCard.tsx | 36 +- .../Elements/Dashboard/HeaderRight.tsx | 2 + .../Elements/Layout/BottomSheet.tsx | 2 +- .../Elements/Layout/DefaultTabs.tsx | 2 - .../Elements/Layout/MaterialTabbar.tsx | 2 +- .../Elements/Layout/MaterialTabs.tsx | 1 + .../Elements/Map/BottomSheetBackground.tsx | 4 +- .../Elements/Map/BottomSheetMap.tsx | 1036 ++++++++-------- src/components/Elements/Map/MapScreen.tsx | 19 +- .../Elements/Map/SearchResultRow.tsx | 4 +- .../Universal/BottomSheetRootBackground.tsx | 1 + .../Elements/Universal/LoginForm.tsx | 16 +- src/components/provider.tsx | 42 +- src/contexts/dashboard.ts | 2 - src/data/constants.ts | 11 +- src/data/licenses.json | 40 +- src/localization/de/common.json | 18 +- src/localization/en/common.json | 18 +- src/utils/ui-utils.ts | 52 +- 63 files changed, 2235 insertions(+), 1352 deletions(-) create mode 100644 android/app/src/main/res/drawable/account_circle.xml delete mode 100644 android/app/src/main/res/resources.properties delete mode 100644 ios/NeulandNext.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 ios/NeulandNext/NeulandNextRelease.entitlements create mode 100644 patches/@th3rdwave%2Freact-navigation-bottom-sheet@0.3.2.patch create mode 100644 patches/react-native-pager-view@6.3.4.patch create mode 100644 patches/react-native-paper@5.12.5.patch create mode 100644 patches/react-native-shimmer@0.6.0.patch create mode 100644 patches/react-native-week-view@0.30.0.patch delete mode 100644 react-native.config.js diff --git a/android/app/build.gradle b/android/app/build.gradle index 8e193ebc..46d59991 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -4,6 +4,27 @@ apply plugin: "com.facebook.react" def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() +static def versionToNumber(major, minor, patch) { + return patch * 100 + minor * 10000 + major * 1000000 +} + +def getRNVersion() { + def version = providers.exec { + workingDir(projectDir) + commandLine("node", "-e", "console.log(require('react-native/package.json').version);") + }.standardOutput.asText.get().trim() + + def coreVersion = version.split("-")[0] + def (major, minor, patch) = coreVersion.tokenize('.').collect { it.toInteger() } + + return versionToNumber( + major, + minor, + patch + ) +} +def rnVersion = getRNVersion() + /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. @@ -57,6 +78,11 @@ react { // // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" // hermesFlags = ["-O", "-output-source-map"] + + if (rnVersion >= versionToNumber(0, 75, 0)) { + /* Autolinking */ + autolinkLibrariesWithApp() + } } /** @@ -88,8 +114,8 @@ android { applicationId 'app.neuland' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 145 - versionName "0.9.0" + versionCode 155 + versionName "0.9.1" } signingConfigs { debug { @@ -110,6 +136,7 @@ android { shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) } } packagingOptions { @@ -168,5 +195,7 @@ dependencies { } } -apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); -applyNativeModulesAppBuildGradle(project) +if (rnVersion < versionToNumber(0, 75, 0)) { + apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); + applyNativeModulesAppBuildGradle(project) +} diff --git a/android/app/src/main/res/drawable/account_circle.xml b/android/app/src/main/res/drawable/account_circle.xml new file mode 100644 index 00000000..51ea9d4e --- /dev/null +++ b/android/app/src/main/res/drawable/account_circle.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/app/src/main/res/drawable/calendar_month.xml b/android/app/src/main/res/drawable/calendar_month.xml index d5821a5c..8ae0a166 100644 --- a/android/app/src/main/res/drawable/calendar_month.xml +++ b/android/app/src/main/res/drawable/calendar_month.xml @@ -4,6 +4,6 @@ android:viewportWidth="960" android:viewportHeight="960"> diff --git a/android/app/src/main/res/drawable/map.xml b/android/app/src/main/res/drawable/map.xml index f5df6183..0ae7ce2d 100644 --- a/android/app/src/main/res/drawable/map.xml +++ b/android/app/src/main/res/drawable/map.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/android/app/src/main/res/drawable/silverware_fork_knife.xml b/android/app/src/main/res/drawable/silverware_fork_knife.xml index 0a035b19..782380a6 100644 --- a/android/app/src/main/res/drawable/silverware_fork_knife.xml +++ b/android/app/src/main/res/drawable/silverware_fork_knife.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/android/app/src/main/res/resources.properties b/android/app/src/main/res/resources.properties deleted file mode 100644 index d5a3ddc9..00000000 --- a/android/app/src/main/res/resources.properties +++ /dev/null @@ -1 +0,0 @@ -unqualifiedResLocale=en-US \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 0c0bd9e4..1982ea1f 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ Neuland Next contain - true + false automatic undefined \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index afcee0ec..8f9ff604 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -5,7 +5,7 @@ @drawable/rn_edit_text_material @color/colorPrimary @color/colorPrimaryDark - @android:color/transparent + #ffffff ${sanitizedHtml}` @@ -43,53 +40,25 @@ export default function NotesDetails(): JSX.Element { }) }, [navigation]) - async function setDelayedIsLoaded(): Promise { - const delay = Platform.OS === 'ios' ? 50 : 0 - - await new Promise((resolve) => setTimeout(resolve, delay)) - setIsLoaded(true) - } - return ( <> { - void setDelayedIsLoaded() - }} - style={{ - ...styles.webView, - width: windowWidth - PADDING * 2, - backgroundColor: colors.background, - color: colors.text, - }} - originWhitelist={['*']} source={{ html: styledHtml }} scalesPageToFit + onLoadEnd={(e) => { + if (!loaded) { + setLoaded(true) + } + }} /> - - {/* prevent flickering on load on iOS */} - {isLoaded ? null : ( + {!loaded && ( + > )} ) } - -const styles = StyleSheet.create({ - webView: { - height: '100%', - padding: PADDING, - alignSelf: 'center', - }, - iosContainer: { - height: '100%', - width: '100%', - position: 'absolute', - justifyContent: 'center', - }, -}) diff --git a/src/app/(tabs)/(food)/index.tsx b/src/app/(tabs)/(food)/index.tsx index 290b7861..037a48cb 100644 --- a/src/app/(tabs)/(food)/index.tsx +++ b/src/app/(tabs)/(food)/index.tsx @@ -9,7 +9,7 @@ import { type Food } from '@/types/neuland-api' import { networkError } from '@/utils/api-utils' import { loadFoodEntries } from '@/utils/food-utils' import { PAGE_BOTTOM_SAFE_AREA } from '@/utils/style-utils' -import { showToast } from '@/utils/ui-utils' +import { pausedToast } from '@/utils/ui-utils' import { useTheme } from '@react-navigation/native' import { useQuery } from '@tanstack/react-query' import * as Haptics from 'expo-haptics' @@ -81,7 +81,7 @@ export function FoodScreen(): JSX.Element { useEffect(() => { if (isPaused && data != null) { - void showToast(t('toast.paused')) + pausedToast() } }, [data, isPaused, t]) diff --git a/src/app/(tabs)/(index)/index.tsx b/src/app/(tabs)/(index)/index.tsx index 1a4343ca..78f8c983 100644 --- a/src/app/(tabs)/(index)/index.tsx +++ b/src/app/(tabs)/(index)/index.tsx @@ -20,10 +20,15 @@ import { StyleSheet, View, } from 'react-native' +import { useSafeAreaInsets } from 'react-native-safe-area-context' export default function HomeRootScreen(): JSX.Element { const [isPageOpen, setIsPageOpen] = useState(false) - + const colors = useTheme().colors as Colors + const safeArea = useSafeAreaInsets() + const topInset = safeArea.top + const hasDynamicIsland = Platform.OS === 'ios' && topInset > 50 + const paddingTop = hasDynamicIsland ? topInset : 0 useEffect(() => { setIsPageOpen(true) }, []) @@ -41,6 +46,8 @@ export default function HomeRootScreen(): JSX.Element { <>} largeTitle={true} - transparent={true} + transparent={!hasDynamicIsland} headerRightElement={IndexHeaderRight} androidFallback /> @@ -65,7 +72,7 @@ function HomeScreen(): JSX.Element { ) const colors = useTheme().colors as Colors const [columns, setColumns] = useState( - Math.floor(Dimensions.get('window').width < 800 ? 1 : 2) + Math.floor(Dimensions.get('window').width < 800 ? 1 : 1) ) const navigation = useNavigation() const { t } = useTranslation(['navigation', 'settings']) @@ -142,8 +149,8 @@ function HomeScreen(): JSX.Element { if (columns !== 1) { paddingStyle = index % 2 === 0 - ? { paddingRight: PAGE_PADDING / 2 } - : { paddingLeft: PAGE_PADDING / 2 } + ? { marginRight: PAGE_PADDING / 2 } + : { marginLeft: PAGE_PADDING / 2 } } return ( @@ -173,6 +180,8 @@ const styles = StyleSheet.create({ errorContainer: { paddingTop: 110, flex: 1 }, item: { marginVertical: 6, + gap: 0, + marginHorizontal: PAGE_PADDING, }, container: { paddingBottom: PAGE_BOTTOM_SAFE_AREA, diff --git a/src/app/(tabs)/(index)/links.tsx b/src/app/(tabs)/(index)/links.tsx index b68485bb..8fdc31d9 100644 --- a/src/app/(tabs)/(index)/links.tsx +++ b/src/app/(tabs)/(index)/links.tsx @@ -76,7 +76,7 @@ const LinkScreen = (): JSX.Element => { } const styles = StyleSheet.create({ - formlistRow: { marginVertical: 14.5 }, + formlistRow: { marginVertical: 13.5 }, headerContainer: { flexDirection: 'row', justifyContent: 'space-between', diff --git a/src/app/(tabs)/_layout.tsx b/src/app/(tabs)/_layout.tsx index 5b98911c..e7011024 100644 --- a/src/app/(tabs)/_layout.tsx +++ b/src/app/(tabs)/_layout.tsx @@ -70,7 +70,7 @@ export default function HomeLayout(): JSX.Element { useEffect(() => { // Android only: Sets the navigation bar color based on the current screen to match TabBar or Background color const prepare = async (): Promise => { - const tabsPaths = ['/', '/timetable', '/map', '/food', '/links'] + const tabsPaths = ['/', '/timetable', '/map', '/food'] const isTab = tabsPaths.includes(pathname) if (isOnboarded !== true) { await NavigationBar.setBackgroundColorAsync(colors.contrast) @@ -129,11 +129,32 @@ export default function HomeLayout(): JSX.Element { selectedRestaurants[0] as keyof typeof humanLocations ], data: { - path: '(tabs)/food', + path: '(tabs)/(food)', }, symbolName: 'fork.knife', iconName: 'silverware_fork_knife', }, + ...(userKind === USER_GUEST + ? [ + { + id: 'login', + type: 'login', + title: t('navigation.login'), + data: { path: 'login' }, + symbolName: 'person.circle', + iconName: 'account_circle', + }, + ] + : [ + { + id: 'profile', + type: 'profile', + title: t('navigation.profile'), + data: { path: 'profile' }, + symbolName: 'person.circle', + iconName: 'account_circle', + }, + ]), ] function processShortcut(item: ShortcutItem): void { router.navigate(item.data.path as string) @@ -147,7 +168,7 @@ export default function HomeLayout(): JSX.Element { return () => { if (shortcutSubscription != null) shortcutSubscription.remove() } - }, [selectedRestaurants, router, t]) + }, [selectedRestaurants, router, t, userKind]) useEffect(() => { console.log('Analytics allowed:', analyticsAllowed) diff --git a/src/components/Cards/BaseCard.tsx b/src/components/Cards/BaseCard.tsx index c4d6c0dc..ee2964f2 100644 --- a/src/components/Cards/BaseCard.tsx +++ b/src/components/Cards/BaseCard.tsx @@ -2,7 +2,7 @@ import { type Colors } from '@/components/colors' import { USER_GUEST } from '@/data/constants' import { type MaterialIcon } from '@/types/material-icons' -import { CARD_PADDING, PAGE_PADDING } from '@/utils/style-utils' +import { CARD_PADDING } from '@/utils/style-utils' import { useTheme } from '@react-navigation/native' import { router } from 'expo-router' import React, { useContext } from 'react' @@ -16,7 +16,7 @@ import { cardIcons } from '../icons' interface BaseCardProps { title: string - onPressRoute: string + onPressRoute?: string removable?: boolean children?: React.ReactNode } @@ -63,12 +63,13 @@ const BaseCard: React.FC = ({ return ( { - router.navigate(onPressRoute) + onPressRoute != null && router.navigate(onPressRoute) }} delayLongPress={300} onLongPress={() => {}} - style={{ marginHorizontal: PAGE_PADDING }} + // style={{ paddingHorizontal: PAGE_PADDING }} > = ({ resetOrder(userKind ?? 'guest') }} onPreviewPress={() => { - router.navigate(onPressRoute) + onPressRoute != null && router.navigate(onPressRoute) }} > = ({ {/* @ts-expect-error cannot verify that title is a valid key */} {t('cards.titles.' + title)} - - + {onPressRoute != null && ( + + )} {children != null && <>{children}} diff --git a/src/components/Cards/LibraryCard.tsx b/src/components/Cards/LibraryCard.tsx index 071fd497..30e960ae 100644 --- a/src/components/Cards/LibraryCard.tsx +++ b/src/components/Cards/LibraryCard.tsx @@ -9,7 +9,7 @@ import { LoadingState } from '@/utils/ui-utils' import { useTheme } from '@react-navigation/native' import { useRouter } from 'expo-router' import React, { useContext, useEffect, useState } from 'react' -import { StyleSheet, Text, View } from 'react-native' +import { LayoutAnimation, StyleSheet, Text, View } from 'react-native' import BaseCard from './BaseCard' @@ -37,6 +37,7 @@ const LibraryCard = (): JSX.Element => { }) setReservations(firstTwoReservations) + LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) setLoadingState(LoadingState.LOADED) } catch (e: any) { setLoadingState(LoadingState.ERROR) diff --git a/src/components/Cards/LinkCard.tsx b/src/components/Cards/LinkCard.tsx index 719efa64..fa932b01 100644 --- a/src/components/Cards/LinkCard.tsx +++ b/src/components/Cards/LinkCard.tsx @@ -6,7 +6,14 @@ import { trackEvent } from '@aptabase/react-native' import { useTheme } from '@react-navigation/native' import React, { useContext } from 'react' import { useTranslation } from 'react-i18next' -import { Linking, Pressable, StyleSheet, Text, View } from 'react-native' +import { + Linking, + Platform, + Pressable, + StyleSheet, + Text, + View, +} from 'react-native' import PlatformIcon from '../Elements/Universal/Icon' import BaseCard from './BaseCard' @@ -25,6 +32,7 @@ const LinkCard = (): JSX.Element => { trackEvent('Quicklink', { link: key }) await Linking.openURL(url) } + return ( @@ -44,11 +52,12 @@ const LinkCard = (): JSX.Element => { color={colors.primary} ios={{ name: link.icon.ios, - size: 18, + size: 17, + weight: 'semibold', }} android={{ name: link.icon.android as MaterialIcon, - size: 20, + size: 21, variant: 'outlined', }} /> @@ -57,7 +66,10 @@ const LinkCard = (): JSX.Element => { ...styles.eventTitle, color: colors.text, }} - numberOfLines={2} + numberOfLines={1} + adjustsFontSizeToFit={Platform.OS === 'ios'} + minimumFontScale={0.8} + ellipsizeMode="tail" > {t( // @ts-expect-error Type cannot be verified @@ -76,23 +88,23 @@ const styles = StyleSheet.create({ cardsFilled: { paddingTop: 14, flexDirection: 'row', - justifyContent: 'space-between', + flexWrap: 'wrap', gap: 10, }, eventTitle: { fontWeight: '500', - fontSize: 16, + fontSize: 14.5, + flexShrink: 1, }, linkBox: { - padding: 12, + paddingTop: 12, + paddingBottom: 7, + paddingHorizontal: 8, borderRadius: 8, - - flexDirection: 'row', - gap: 10, + gap: Platform.OS === 'android' ? 2 : 7, flex: 1, - overflow: 'hidden', alignItems: 'center', - justifyContent: 'space-evenly', + justifyContent: 'space-between', }, }) diff --git a/src/components/Elements/Dashboard/HeaderRight.tsx b/src/components/Elements/Dashboard/HeaderRight.tsx index 4fed395e..efe963bc 100644 --- a/src/components/Elements/Dashboard/HeaderRight.tsx +++ b/src/components/Elements/Dashboard/HeaderRight.tsx @@ -9,6 +9,7 @@ import { getPersonalData, getUsername, performLogout } from '@/utils/api-utils' import { getContrastColor, getInitials } from '@/utils/ui-utils' import { useTheme } from '@react-navigation/native' import { useQuery } from '@tanstack/react-query' +import * as Device from 'expo-device' import { useRouter } from 'expo-router' import { getItem } from 'expo-secure-store' import React, { useContext, useEffect, useState } from 'react' @@ -114,6 +115,7 @@ export const IndexHeaderRight = (): JSX.Element => { children: JSX.Element }): JSX.Element => ( { options={{ title: t('navigation.map'), headerShown: false, - - tabBarHideOnKeyboard: true, tabBarIcon: ({ color, size }) => ( { ? Color(colors.card).mix(Color(colors.primary), 0.04).hex() : Color(colors.card).mix(Color(colors.primary), 0.1).hex(), }} + keyboardHidesNavigationBar={false} > { const { colors, dark } = useTheme() const darkIos = 'rgba(0, 0, 0, 0.55)' - const lightIos = 'rgba(200, 200, 200, 0.2)' + const lightIos = 'rgba(200, 200, 200, 0.3)' return Platform.OS === 'ios' ? ( { ]} > diff --git a/src/components/Elements/Map/BottomSheetMap.tsx b/src/components/Elements/Map/BottomSheetMap.tsx index abc39a21..4b01b137 100644 --- a/src/components/Elements/Map/BottomSheetMap.tsx +++ b/src/components/Elements/Map/BottomSheetMap.tsx @@ -5,7 +5,7 @@ import { USER_GUEST } from '@/data/constants' import { SEARCH_TYPES, type SearchResult } from '@/types/map' import { formatFriendlyDate, formatFriendlyTime } from '@/utils/date-utils' import { PAGE_BOTTOM_SAFE_AREA, PAGE_PADDING } from '@/utils/style-utils' -import { getContrastColor, showToast } from '@/utils/ui-utils' +import { getContrastColor, roomNotFoundToast } from '@/utils/ui-utils' import { trackEvent } from '@aptabase/react-native' import BottomSheet, { BottomSheetTextInput, @@ -33,7 +33,7 @@ import { Text, View, } from 'react-native' -import { Swipeable, TextInput } from 'react-native-gesture-handler' +import Swipeable from 'react-native-gesture-handler/ReanimatedSwipeable' import { type SharedValue } from 'react-native-reanimated' import Divider from '../Universal/Divider' @@ -227,330 +227,493 @@ const MapBottomSheet: React.FC = ({ textInputRef.current?.blur() } }} - enableDynamicSizing={false} > - - - - {Platform.OS !== 'ios' ? ( - { - setLocalSearch(text) - }} - onFocus={() => { - setSearchFocused(true) - animate(width) - - bottomSheetRef.current?.expand() - }} - onBlur={() => { - setSearchFocused(false) - animate(0) - }} - /> - ) : ( - { - setLocalSearch(text) - }} - onFocus={() => { - setSearchFocused(true) - animate(width) - - bottomSheetRef.current?.expand() - }} - onBlur={() => { - setSearchFocused(false) - animate(0) - }} - /> - )} - - + + { + setLocalSearch(text) + }} + onFocus={() => { + setSearchFocused(true) + animate(width) + bottomSheetRef.current?.expand() + }} + onBlur={() => { + setSearchFocused(false) + animate(0) + }} + /> + + + { + setLocalSearch('') + textInputRef.current?.blur() + // bottomSheetRef.current?.snapToIndex(1) }} + style={styles.cancelButton} > - { - setLocalSearch('') - textInputRef.current?.blur() - // bottomSheetRef.current?.snapToIndex(1) + - - {t('misc.cancel')} - - - - + {t('misc.cancel')} + + + + - {searchFocused && - localSearch === '' && - searchHistory.length !== 0 && ( - <> - - + + + - - {t( - 'pages.map.details.room.history' - )} - - - - {searchHistory?.map( - (history, index) => ( - - ( - { - LayoutAnimation.configureNext( - LayoutAnimation - .Presets - .easeInEaseOut - ) - if ( - Platform.OS === - 'ios' - ) { - void selectionAsync() - } - deleteSearchHistoryItem( - history - ) - }} - > - - - )} + {t('pages.map.details.room.history')} + + + + {searchHistory?.map((history, index) => ( + + ( + { + LayoutAnimation.configureNext( + LayoutAnimation + .Presets + .easeInEaseOut + ) + if ( + Platform.OS === + 'ios' + ) { + void selectionAsync() + } + deleteSearchHistoryItem( + history + ) + }} > - - - - - {index !== - searchHistory.length - - 1 && ( - - )} - - ) - )} - + + )} + > + + + + + {index !== + searchHistory.length - 1 && ( + + )} + + ))} - - )} + + + )} - {searchFocused && localSearch === '' && ( + {searchFocused && localSearch === '' && ( + + {t('pages.map.search.placeholder')} + + )} + + {localSearch !== '' ? ( + searchResultsExact.length > 0 || + searchResultsFuzzy.length > 0 ? ( + 0 + ? [ + { + title: t( + 'pages.map.search.results' + ), + data: searchResultsExact, + }, + ] + : []), + ...(searchResultsFuzzy.length > 0 + ? [ + { + title: t( + 'pages.map.search.fuzzy' + ), + data: searchResultsFuzzy, + }, + ] + : []), + ]} + keyExtractor={(item, index) => item.title + index} + renderItem={({ item, index }) => ( + + )} + ItemSeparatorComponent={() => ( + + )} + stickySectionHeadersEnabled={false} + renderSectionHeader={({ section: { title } }) => ( + + {title} + + )} + /> + ) : ( - {t('pages.map.search.placeholder')} + {t('pages.map.search.noResults')} - )} - - {localSearch !== '' ? ( - searchResultsExact.length > 0 || - searchResultsFuzzy.length > 0 ? ( - 0 - ? [ - { - title: t( - 'pages.map.search.results' - ), - data: searchResultsExact, - }, - ] - : []), - ...(searchResultsFuzzy.length > 0 - ? [ - { - title: t( - 'pages.map.search.fuzzy' - ), - data: searchResultsFuzzy, - }, - ] - : []), - ]} - keyExtractor={(item, index) => - item.title + index - } - renderItem={({ item, index }) => ( - - )} - ItemSeparatorComponent={() => ( - - )} - stickySectionHeadersEnabled={false} - renderSectionHeader={({ - section: { title }, - }) => ( + ) + ) : searchFocused ? null : ( + <> + {nextLecture !== null && nextLecture.length > 0 && ( + + - {title} + {t( + 'pages.map.details.room.nextLecture' + )} - )} - /> - ) : ( - - {t('pages.map.search.noResults')} - - ) - ) : searchFocused ? null : ( - <> - {nextLecture !== null && nextLecture.length > 0 && ( - - - - {t( - 'pages.map.details.room.nextLecture' + {formatFriendlyDate( + nextLecture[0].date + )} + + + + {nextLecture.map((lecture, key) => ( + + { + const details = + allRooms.features.find( + (x) => + x.properties + ?.Raum === + lecture.rooms[0] + ) + if (details == null) { + roomNotFoundToast( + lecture.rooms[0], + colors.notification + ) + return + } + const etage = + details?.properties + ?.Ebene + bottomSheetRef.current?.close() + setCurrentFloor({ + floor: + (etage as string) ?? + 'EG', + manual: false, + }) + setClickedElement({ + data: lecture.rooms[0], + type: SEARCH_TYPES.ROOM, + center: details + ?.properties + ?.center, + manual: false, + }) + trackEvent('Room', { + room: lecture.rooms[0], + origin: 'NextLecture', + }) + + handlePresentModalPress() + }} + > + + + + + + + + {lecture.name} + + + {lecture.rooms.join( + ', ' + )} + + + + + + {formatFriendlyTime( + lecture.startDate + )} + + + {formatFriendlyTime( + lecture.endDate + )} + + + + {key !== nextLecture.length - 1 && ( + )} - + + ))} + + + )} + + + + + {t('pages.map.details.room.availableRooms')} + + {userKind !== USER_GUEST && ( + { + router.navigate('roomSearch') + }} + hitSlop={{ + top: 10, + right: 10, + bottom: 10, + left: 10, + }} + > - {formatFriendlyDate( - nextLecture[0].date - )} + {t('misc.more')} - - + )} + + + {userKind === USER_GUEST ? ( + - {nextLecture.map((lecture, key) => ( + {t('pages.map.details.room.signIn')} + + ) : availableRooms === null ? ( + + ) : availableRooms.length === 0 ? ( + + {t('pages.map.noAvailableRooms')} + + ) : ( + availableRooms + .slice(0, 3) + .map((room, key) => ( { const details = @@ -558,21 +721,21 @@ const MapBottomSheet: React.FC = ({ (x) => x.properties ?.Raum === - lecture - .rooms[0] + room.room ) + if (details == null) { - void showToast( - t( - 'toast.roomNotFound' - ) + roomNotFoundToast( + room.room, + colors.notification ) return } + const etage = details?.properties ?.Ebene - bottomSheetRef.current?.close() + setCurrentFloor({ floor: (etage as string) ?? @@ -580,18 +743,18 @@ const MapBottomSheet: React.FC = ({ manual: false, }) setClickedElement({ - data: lecture - .rooms[0], + data: room.room, type: SEARCH_TYPES.ROOM, - center: details - ?.properties - ?.center, + center: + details + ?.properties + ?.center ?? + undefined, manual: false, }) trackEvent('Room', { - room: lecture - .rooms[0], - origin: 'NextLecture', + room: room.room, + origin: 'AvailableRoomsSuggestion', }) handlePresentModalPress() @@ -614,7 +777,7 @@ const MapBottomSheet: React.FC = ({ colors.primary )} ios={{ - name: 'clock.fill', + name: 'studentdesk', size: 18, }} android={{ @@ -634,11 +797,8 @@ const MapBottomSheet: React.FC = ({ color: colors.text, ...styles.suggestionTitle, }} - numberOfLines={ - 2 - } > - {lecture.name} + {room.room} = ({ ...styles.suggestionSubtitle, }} > - {lecture.rooms.join( - ', ' + {room.type} ( + {room.capacity}{' '} + {t( + 'pages.rooms.options.seats' )} + ) @@ -666,7 +829,7 @@ const MapBottomSheet: React.FC = ({ }} > {formatFriendlyTime( - lecture.startDate + room.from )} = ({ }} > {formatFriendlyTime( - lecture.endDate + room.until )} - {key !== - nextLecture.length - 1 && ( - - )} + {key !== 2 && } - ))} - - - )} - - - - - {t( - 'pages.map.details.room.availableRooms' - )} - - {userKind !== USER_GUEST && ( - { - router.navigate('roomSearch') - }} - hitSlop={{ - top: 10, - right: 10, - bottom: 10, - left: 10, - }} - > - - {t('misc.more')} - - - )} - - - {userKind === USER_GUEST ? ( - - {t('pages.map.details.room.signIn')} - - ) : availableRooms === null ? ( - - ) : availableRooms.length === 0 ? ( - - {t('pages.map.noAvailableRooms')} - - ) : ( - availableRooms - .slice(0, 3) - .map((room, key) => ( - - { - const details = - allRooms.features.find( - (x) => - x - .properties - ?.Raum === - room.room - ) - - if ( - details == null - ) { - void showToast( - t( - 'toast.roomNotFound' - ) - ) - return - } - - const etage = - details - ?.properties - ?.Ebene - - setCurrentFloor({ - floor: - (etage as string) ?? - 'EG', - manual: false, - }) - setClickedElement({ - data: room.room, - type: SEARCH_TYPES.ROOM, - center: - details - ?.properties - ?.center ?? - undefined, - manual: false, - }) - trackEvent('Room', { - room: room.room, - origin: 'AvailableRoomsSuggestion', - }) - - handlePresentModalPress() - }} - > - - - - - - - - {room.room} - - - {room.type}{' '} - ( - { - room.capacity - }{' '} - {t( - 'pages.rooms.options.seats' - )} - ) - - - - - - {formatFriendlyTime( - room.from - )} - - - {formatFriendlyTime( - room.until - )} - - - - {key !== 2 && } - - )) - )} - + )) + )} - - - )} - + + + + )} ) diff --git a/src/components/Elements/Map/MapScreen.tsx b/src/components/Elements/Map/MapScreen.tsx index 42d55635..1ad1caf9 100644 --- a/src/components/Elements/Map/MapScreen.tsx +++ b/src/components/Elements/Map/MapScreen.tsx @@ -28,7 +28,7 @@ import { getCenterSingle, getIcon, } from '@/utils/map-utils' -import { LoadingState, showToast } from '@/utils/ui-utils' +import { LoadingState, roomNotFoundToast } from '@/utils/ui-utils' import { trackEvent } from '@aptabase/react-native' import type BottomSheet from '@gorhom/bottom-sheet' import { type BottomSheetModal } from '@gorhom/bottom-sheet' @@ -39,6 +39,7 @@ import MapLibreGL, { } from '@maplibre/maplibre-react-native' import { useTheme } from '@react-navigation/native' import { useQuery } from '@tanstack/react-query' +import { toast } from 'burnt' import { useNavigation } from 'expo-router' import { type Feature, @@ -72,7 +73,6 @@ import Animated, { useSharedValue, withTiming, } from 'react-native-reanimated' -import Toast from 'react-native-root-toast' import packageInfo from '../../../../package.json' import { modalSection } from './ModalSections' @@ -149,7 +149,6 @@ const MapScreen = (): JSX.Element => { const handlePresentModalPress = useCallback(() => { bottomSheetRef.current?.close() - bottomSheetModalRef.current?.present() }, []) @@ -164,13 +163,11 @@ const MapScreen = (): JSX.Element => { useEffect(() => { if (overlayError != null) { - Toast.show(t('toast.mapOverlay', { ns: 'common' }), { - duration: Toast.durations.SHORT, - position: 50, - shadow: false, - animation: true, - hideOnPress: true, - delay: 0, + toast({ + title: t('toast.mapOverlay', { ns: 'common' }), + preset: 'error', + duration: 3, + from: 'top', }) } }, [overlayError]) @@ -349,7 +346,7 @@ const MapScreen = (): JSX.Element => { )?.properties if (room == null) { - void showToast(t('toast.roomNotFound')) + roomNotFoundToast(routeParams, colors.notification) updateRouteParams('') return } diff --git a/src/components/Elements/Map/SearchResultRow.tsx b/src/components/Elements/Map/SearchResultRow.tsx index 33fce596..7ee9ada0 100644 --- a/src/components/Elements/Map/SearchResultRow.tsx +++ b/src/components/Elements/Map/SearchResultRow.tsx @@ -6,7 +6,7 @@ import { trackEvent } from '@aptabase/react-native' import { TouchableOpacity } from '@gorhom/bottom-sheet' import React, { useContext } from 'react' import { useTranslation } from 'react-i18next' -import { Keyboard, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' import PlatformIcon from '../Universal/Icon' @@ -35,8 +35,6 @@ const ResultRow: React.FC<{ style={styles.searchRowContainer} onPress={() => { const center = result.item.properties?.center - Keyboard.dismiss() - bottomSheetRef.current?.collapse() updateSearchHistory(result) setClickedElement({ data: result.title, diff --git a/src/components/Elements/Universal/BottomSheetRootBackground.tsx b/src/components/Elements/Universal/BottomSheetRootBackground.tsx index 949911d2..fb959a49 100644 --- a/src/components/Elements/Universal/BottomSheetRootBackground.tsx +++ b/src/components/Elements/Universal/BottomSheetRootBackground.tsx @@ -5,6 +5,7 @@ import { Platform, StyleSheet, View } from 'react-native' const BottomSheetRootBackground = (): JSX.Element => { const { colors, dark } = useTheme() + console.log(dark) const darkIos = 'rgba(0, 0, 0, 0.3)' const lightIos = 'rgba(255, 255, 255, 0.5)' return Platform.OS === 'ios' ? ( diff --git a/src/components/Elements/Universal/LoginForm.tsx b/src/components/Elements/Universal/LoginForm.tsx index 198049d1..c976b915 100644 --- a/src/components/Elements/Universal/LoginForm.tsx +++ b/src/components/Elements/Universal/LoginForm.tsx @@ -10,6 +10,7 @@ import { import { trimErrorMsg } from '@/utils/api-utils' import { getContrastColor } from '@/utils/ui-utils' import { useTheme } from '@react-navigation/native' +import { toast } from 'burnt' import Color from 'color' import * as Haptics from 'expo-haptics' import * as SecureStore from 'expo-secure-store' @@ -26,7 +27,6 @@ import { TouchableOpacity, View, } from 'react-native' -import Toast from 'react-native-root-toast' const LoginForm = ({ navigateHome, @@ -59,14 +59,12 @@ const LoginForm = ({ Haptics.NotificationFeedbackType.Success ) } - - Toast.show(t('login.toast'), { - duration: Toast.durations.LONG, - position: 50, - shadow: false, - animation: true, - hideOnPress: true, - delay: 0, + toast({ + title: t('login.toast'), + preset: 'done', + haptic: 'success', + duration: 2.5, + from: 'top', }) navigateHome() } catch (e) { diff --git a/src/components/provider.tsx b/src/components/provider.tsx index 3b6917e2..6313a6d9 100644 --- a/src/components/provider.tsx +++ b/src/components/provider.tsx @@ -2,6 +2,7 @@ import { useAppState, useOnlineManager } from '@/hooks' import i18n from '@/localization/i18n' import { syncStoragePersister } from '@/utils/storage' import { trackEvent } from '@aptabase/react-native' +import { BottomSheetModalProvider } from '@gorhom/bottom-sheet' import { DarkTheme, DefaultTheme, @@ -19,7 +20,6 @@ import { useColorScheme, } from 'react-native' import { GestureHandlerRootView } from 'react-native-gesture-handler' -import { RootSiblingParent } from 'react-native-root-siblings' import { SafeAreaProvider } from 'react-native-safe-area-context' import { @@ -262,31 +262,31 @@ export default function Provider({ - - - - - - + + + + + - - + {children} - - - - - - - - + + + + + + + + diff --git a/src/contexts/dashboard.ts b/src/contexts/dashboard.ts index eed7ac16..e0934496 100644 --- a/src/contexts/dashboard.ts +++ b/src/contexts/dashboard.ts @@ -72,7 +72,6 @@ export function useDashboard(): Dashboard { const changeDashboardOrder = useCallback( (entries: string[], hiddenEntries: string[]) => { - console.log('changeDashboardOrder', entries, hiddenEntries) setShownDashboardEntries(entries) setHiddenDashboardEntries(hiddenEntries) }, @@ -81,7 +80,6 @@ export function useDashboard(): Dashboard { const updateDashboardOrder = useCallback( (entries: string[]) => { - console.log('updateDashboardOrder', entries) setShownDashboardEntries(entries) }, [setShownDashboardEntries] diff --git a/src/data/constants.ts b/src/data/constants.ts index 16f19224..1feb82de 100644 --- a/src/data/constants.ts +++ b/src/data/constants.ts @@ -12,6 +12,7 @@ const studverLink = 'https://studverthi.de' const marketplaceLink = 'https://www.thi.de/service/marketplace/' const myThiLink = 'https://mythi.de' const libraryLink = 'https://opac.ku.de/index-hi.html' +const thiLink = 'https://www.thi.de' export const quicklinks = [ { @@ -43,7 +44,15 @@ export const quicklinks = [ url: studverLink, icon: { ios: 'person.bubble', - android: 'podium', + android: '3p', + }, + }, + { + key: 'THI', + url: thiLink, + icon: { + ios: 'globe', + android: 'captive_portal', }, }, { diff --git a/src/data/licenses.json b/src/data/licenses.json index 3eca82db..6830065a 100644 --- a/src/data/licenses.json +++ b/src/data/licenses.json @@ -35,12 +35,6 @@ "licenseUrl": "https://github.com/maplibre/maplibre-react-native/raw/master/LICENSE.md", "parents": "neuland" }, - "@material/material-color-utilities@0.3.0": { - "licenses": "Apache-2.0", - "repository": "https://github.com/material-foundation/material-color-utilities", - "licenseUrl": "https://github.com/material-foundation/material-color-utilities/raw/master/LICENSE", - "parents": "neuland" - }, "@react-native-community/datetimepicker@8.0.1": { "licenses": "MIT", "repository": "https://github.com/react-native-community/datetimepicker", @@ -89,6 +83,12 @@ "licenseUrl": "https://github.com/th3rdwave/react-navigation-bottom-sheet/raw/master/LICENSE", "parents": "neuland" }, + "burnt@0.12.2": { + "licenses": "MIT", + "repository": "https://github.com/nandorojo/burnt", + "licenseUrl": "https://github.com/nandorojo/burnt/raw/master/LICENSE", + "parents": "neuland" + }, "color@4.2.3": { "licenses": "MIT", "repository": "https://github.com/Qix-/color", @@ -167,7 +167,7 @@ "licenseUrl": "https://github.com/expo/expo", "parents": "neuland" }, - "expo-router@3.5.21": { + "expo-router@3.5.23": { "licenses": "MIT", "repository": "https://github.com/expo/expo", "licenseUrl": "https://github.com/expo/expo", @@ -185,7 +185,7 @@ "licenseUrl": "https://github.com/expo/expo", "parents": "neuland" }, - "expo@51.0.26": { + "expo@51.0.28": { "licenses": "MIT", "repository": "https://github.com/expo/expo", "licenseUrl": "https://github.com/expo/expo", @@ -209,7 +209,7 @@ "licenseUrl": "https://github.com/graphql/graphql-js/raw/master/LICENSE", "parents": "neuland" }, - "i18next@23.12.2": { + "i18next@23.12.7": { "licenses": "MIT", "repository": "https://github.com/i18next/i18next", "licenseUrl": "https://github.com/i18next/i18next/raw/master/LICENSE", @@ -227,7 +227,7 @@ "licenseUrl": "https://github.com/moment/moment/raw/master/LICENSE", "parents": "neuland" }, - "react-dom@18.2.0": { + "react-dom@18.3.1": { "licenses": "MIT", "repository": "https://github.com/facebook/react", "licenseUrl": "https://github.com/facebook/react/raw/master/LICENSE", @@ -269,7 +269,7 @@ "licenseUrl": "https://github.com/idearockers/react-native-dynamic-app-icon/raw/master/LICENSE", "parents": "neuland" }, - "react-native-gesture-handler@2.16.2": { + "react-native-gesture-handler@2.18.1": { "licenses": "MIT", "repository": "https://github.com/software-mansion/react-native-gesture-handler", "licenseUrl": "https://github.com/software-mansion/react-native-gesture-handler/raw/master/LICENSE", @@ -281,37 +281,31 @@ "licenseUrl": "https://github.com/mrousavy/react-native-mmkv/raw/master/LICENSE", "parents": "neuland" }, - "react-native-pager-view@6.3.0": { + "react-native-pager-view@6.3.4": { "licenses": "MIT", "repository": "https://github.com/callstack/react-native-pager-view", "licenseUrl": "https://github.com/callstack/react-native-pager-view/raw/master/LICENSE", "parents": "neuland" }, - "react-native-paper@5.12.3": { + "react-native-paper@5.12.5": { "licenses": "MIT", "repository": "https://github.com/callstack/react-native-paper", "licenseUrl": "https://github.com/callstack/react-native-paper/raw/master/LICENSE.md", "parents": "neuland" }, - "react-native-reanimated@3.10.1": { + "react-native-reanimated@3.15.0": { "licenses": "MIT", "repository": "https://github.com/software-mansion/react-native-reanimated", "licenseUrl": "https://github.com/software-mansion/react-native-reanimated/raw/master/LICENSE", "parents": "neuland" }, - "react-native-root-toast@3.6.0": { - "licenses": "MIT", - "repository": "https://github.com/magicismight/react-native-root-toast", - "licenseUrl": "https://github.com/magicismight/react-native-root-toast/raw/master/LICENSE.txt", - "parents": "neuland" - }, "react-native-safe-area-context@4.10.5": { "licenses": "MIT", "repository": "https://github.com/th3rdwave/react-native-safe-area-context", "licenseUrl": "https://github.com/th3rdwave/react-native-safe-area-context/raw/master/LICENSE", "parents": "neuland" }, - "react-native-screens@3.31.1": { + "react-native-screens@3.34.0": { "licenses": "MIT", "repository": "https://github.com/software-mansion/react-native-screens", "licenseUrl": "https://github.com/software-mansion/react-native-screens/raw/master/LICENSE", @@ -353,13 +347,13 @@ "licenseUrl": "https://github.com/hoangnm/react-native-week-view/raw/master/LICENSE", "parents": "neuland" }, - "react-native@0.74.5": { + "react-native@0.75.1": { "licenses": "MIT", "repository": "https://github.com/facebook/react-native", "licenseUrl": "https://github.com/facebook/react-native/raw/master/LICENSE", "parents": "neuland" }, - "react@18.2.0": { + "react@18.3.1": { "licenses": "MIT", "repository": "https://github.com/facebook/react", "licenseUrl": "https://github.com/facebook/react/raw/master/LICENSE", diff --git a/src/localization/de/common.json b/src/localization/de/common.json index c135e4b3..2ba8e0ce 100644 --- a/src/localization/de/common.json +++ b/src/localization/de/common.json @@ -1,7 +1,10 @@ { "toast": { "clipboard": "in Zwischenablage kopiert", - "paused": "Keine Internetverbindung", + "paused": { + "title": "Keine Internetverbindung", + "description": "Daten können veraltet sein" + }, "roomNotFound": "Raum nicht gefunden", "mapOverlay": "Fehler beim Laden des Overlays", "dashboard": "Drag & Drop zum Sortieren" @@ -63,9 +66,10 @@ "moodle": "Moodle", "webmail": "E-Mail", "studVer": "StudVer", - "marketplace": "Markt-platz", + "marketplace": "Marktplatz", "myTHI": "MyTHI", - "library": "Biblio-thek" + "library": "Bibliothek", + "thi": "THI" }, "pages": { "quicklinks": { @@ -76,10 +80,12 @@ "moodle": "Moodle", "webmail": "E-Mail", "studVer": "Studierendenvertretung", - "marketplace": "THI Marktplatz", + "marketplace": "Marktplatz", "myTHI": "MyTHI", - "library": "Bibliothekskatalog" - } + "library": "Bibliothekskatalog", + "thi": "THI Website" + }, + "more": "Mehr" }, "calendar": { "exams": { diff --git a/src/localization/en/common.json b/src/localization/en/common.json index 7c5d4c86..ba3b7054 100644 --- a/src/localization/en/common.json +++ b/src/localization/en/common.json @@ -1,7 +1,10 @@ { "toast": { "clipboard": "copied to clipboard", - "paused": "No internet connection", + "paused": { + "title": "No internet connection", + "description": "Data may be outdated" + }, "roomNotFound": "Room not found", "mapOverlay": "Error while loading overlay", "dashboard": "Drag & drop to reorder" @@ -63,9 +66,10 @@ "moodle": "Moodle", "webmail": "E-Mail", "studVer": "StudVer", - "marketplace": "Market-place", + "marketplace": "Marketplace", "myTHI": "MyTHI", - "library": "Library" + "library": "Library", + "thi": "THI" }, "pages": { "quicklinks": { @@ -76,10 +80,12 @@ "moodle": "Moodle", "webmail": "E-Mail", "studVer": "Student Representation", - "marketplace": "THI Marketplace", + "marketplace": "Marketplace", "myTHI": "MyTHI", - "library": "Library Catalog" - } + "library": "Library Catalog", + "thi": "THI Website" + }, + "more": "more links" }, "calendar": { "exams": { diff --git a/src/utils/ui-utils.ts b/src/utils/ui-utils.ts index 64aaaba5..fb9e8994 100644 --- a/src/utils/ui-utils.ts +++ b/src/utils/ui-utils.ts @@ -1,6 +1,8 @@ +import { trackEvent } from '@aptabase/react-native' +import { toast } from 'burnt' import Color from 'color' +import { t } from 'i18next' import { type ColorValue } from 'react-native' -import Toast, { type ToastOptions } from 'react-native-root-toast' export enum LoadingState { LOADING, @@ -110,26 +112,38 @@ export const lighten = (percentage: number, color: string): string => { return newColor } -let toast: any = null -export const showToast = async ( - message: string, - options?: ToastOptions -): Promise => { - if (toast !== null) { - Toast.hide(toast) - } - - toast = Toast.show(message, { - duration: Toast.durations.SHORT, - position: 50, - shadow: false, - animation: true, - hideOnPress: true, - delay: 0, - ...options, +export const roomNotFoundToast = (room: string, color: string): void => { + trackEvent('RoomNotFound', { room }) + toast({ + title: t('toast.roomNotFound', { ns: 'common' }), + message: room, + preset: 'custom', + haptic: 'error', + duration: 3, + from: 'top', + icon: { + ios: { + name: 'exclamationmark.magnifyingglass', + color, + }, + }, + }) +} +export const pausedToast = (): void => { + toast({ + title: t('toast.paused.title', { ns: 'common' }), + message: t('toast.paused.description', { ns: 'common' }), + preset: 'custom', + duration: 2, + from: 'top', + icon: { + ios: { + name: 'wifi.slash', + color: '#ed8422', + }, + }, }) } - export const getStatusBarStyle = ( theme: 'light' | 'dark' | 'auto', isAndroid: boolean,