diff --git a/THIRD_PARTY.md b/THIRD_PARTY.md index 6da4cc04..fd72ee9e 100644 --- a/THIRD_PARTY.md +++ b/THIRD_PARTY.md @@ -1,5 +1,6 @@ | Name | License | Source | | ---- | ------- | ------ | +| @backpackapp-io/react-native-toast | MIT | https://github.com/backpackapp-io/react-native-toast | | @expo/vector-icons | MIT | https://github.com/expo/vector-icons | | @gorhom/bottom-sheet | MIT | https://github.com/gorhom/react-native-bottom-sheet | | @miblanchard/react-native-slider | MIT | https://github.com/miblanchard/react-native-slider | @@ -48,7 +49,6 @@ | react-native-safe-area-context | MIT | https://github.com/th3rdwave/react-native-safe-area-context | | react-native-screens | MIT | https://github.com/software-mansion/react-native-screens | | react-native-svg | MIT | https://github.com/software-mansion/react-native-svg | -| react-native-toast-notifications | MIT | https://github.com/arnnis/react-native-toast-notifications | | react-native-track-player | Apache-2.0 | https://github.com/doublesymmetry/react-native-track-player | | Roboto Font | Apache-2.0 | https://github.com/googlefonts/roboto | | tailwind-merge | MIT | https://github.com/dcastil/tailwind-merge | diff --git a/mobile/package.json b/mobile/package.json index d7bfa65f..5e98e0e5 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -23,6 +23,7 @@ "release": "git checkout main -q && git pull && python ./scripts/release/release_bump.py" }, "dependencies": { + "@backpackapp-io/react-native-toast": "^0.11.0", "@expo/vector-icons": "^14.0.4", "@gorhom/bottom-sheet": "5.0.2", "@miblanchard/react-native-slider": "^2.6.0", @@ -67,7 +68,6 @@ "react-native-safe-area-context": "4.11.1", "react-native-screens": "~3.34.0", "react-native-svg": "^15.8.0", - "react-native-toast-notifications": "^3.4.0", "react-native-track-player": "^4.1.1", "tailwind-merge": "^2.5.4", "zod": "^3.23.8", @@ -113,7 +113,8 @@ }, "pnpm": { "patchedDependencies": { - "react-native-actions-sheet@0.9.7": "patches/react-native-actions-sheet@0.9.7.patch" + "react-native-actions-sheet@0.9.7": "patches/react-native-actions-sheet@0.9.7.patch", + "@backpackapp-io/react-native-toast@0.11.0": "patches/@backpackapp-io__react-native-toast@0.11.0.patch" } } } diff --git a/mobile/patches/@backpackapp-io__react-native-toast@0.11.0.patch b/mobile/patches/@backpackapp-io__react-native-toast@0.11.0.patch new file mode 100644 index 00000000..64d8bac4 --- /dev/null +++ b/mobile/patches/@backpackapp-io__react-native-toast@0.11.0.patch @@ -0,0 +1,29 @@ +diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx +index c598db60ff3d374db094493fb3a90ae5c4d59077..463219603128d5af80fa842c32b33423efdbbc50 100644 +--- a/src/components/Toast.tsx ++++ b/src/components/Toast.tsx +@@ -130,7 +130,7 @@ export const Toast: FC = ({ + kbHeight - + insets.bottom - + (extraInsets?.bottom ?? 0) - +- 24 ++ 0 + : startingY; + + offsetY.value = withSpring(val, { +@@ -241,6 +241,7 @@ export const Toast: FC = ({ + endPause(); + }} + onPress={onPress} ++ pointerEvents="box-none" + style={[ + { + backgroundColor: !toast.customToast +@@ -267,6 +268,7 @@ export const Toast: FC = ({ + updateHeight(toast.id, event.nativeEvent.layout.height) + } + key={toast.id} ++ pointerEvents="box-none" + > + {toast.customToast({ + ...toast, diff --git a/mobile/pnpm-lock.yaml b/mobile/pnpm-lock.yaml index aeda2f77..1a93c023 100644 --- a/mobile/pnpm-lock.yaml +++ b/mobile/pnpm-lock.yaml @@ -8,11 +8,17 @@ overrides: markdown-it: 14.1.0 patchedDependencies: + '@backpackapp-io/react-native-toast@0.11.0': + hash: od77t6fgaovtgbzmvgntqyne5e + path: patches/@backpackapp-io__react-native-toast@0.11.0.patch react-native-actions-sheet@0.9.7: hash: rilo6dygbis6iqezxxrswoam2q path: patches/react-native-actions-sheet@0.9.7.patch dependencies: + '@backpackapp-io/react-native-toast': + specifier: ^0.11.0 + version: 0.11.0(patch_hash=od77t6fgaovtgbzmvgntqyne5e)(react-native-gesture-handler@2.20.0)(react-native-reanimated@3.15.5)(react-native-safe-area-context@4.11.1)(react-native@0.75.4)(react@18.3.1) '@expo/vector-icons': specifier: ^14.0.4 version: 14.0.4 @@ -145,9 +151,6 @@ dependencies: react-native-svg: specifier: ^15.8.0 version: 15.8.0(react-native@0.75.4)(react@18.3.1) - react-native-toast-notifications: - specifier: ^3.4.0 - version: 3.4.0(react-native@0.75.4)(react@18.3.1) react-native-track-player: specifier: ^4.1.1 version: 4.1.1(react-native@0.75.4)(react@18.3.1) @@ -1789,6 +1792,23 @@ packages: '@babel/helper-validator-identifier': 7.25.7 to-fast-properties: 2.0.0 + /@backpackapp-io/react-native-toast@0.11.0(patch_hash=od77t6fgaovtgbzmvgntqyne5e)(react-native-gesture-handler@2.20.0)(react-native-reanimated@3.15.5)(react-native-safe-area-context@4.11.1)(react-native@0.75.4)(react@18.3.1): + resolution: {integrity: sha512-ZRVYQPK6QOvt6vP1bF0I5oBpN5pnssdrX1JLV+KHPyxXWSNNvl1oo0qdJ5uzM7zj2TxMMUBPIsMofFeLA8E/dw==} + peerDependencies: + react: '*' + react-native: '*' + react-native-gesture-handler: '>=2.2.1' + react-native-reanimated: '>=2.8.0' + react-native-safe-area-context: '>=4.2.4' + dependencies: + react: 18.3.1 + react-native: 0.75.4(@babel/core@7.25.8)(@babel/preset-env@7.25.8)(@types/react@18.3.11)(react@18.3.1)(typescript@5.6.3) + react-native-gesture-handler: 2.20.0(react-native@0.75.4)(react@18.3.1) + react-native-reanimated: 3.15.5(@babel/core@7.25.8)(react-native@0.75.4)(react@18.3.1) + react-native-safe-area-context: 4.11.1(react-native@0.75.4)(react@18.3.1) + dev: false + patched: true + /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true @@ -10744,16 +10764,6 @@ packages: warn-once: 0.1.1 dev: false - /react-native-toast-notifications@3.4.0(react-native@0.75.4)(react@18.3.1): - resolution: {integrity: sha512-ZvB//jLhRiBRemtcH7vGP1maiKCikqtW4aDqo+QYvEIOcX0y3GrjxRayVAqI4oh0qJgd/26DkbM8COobj+0MEQ==} - peerDependencies: - react: '*' - react-native: '*' - dependencies: - react: 18.3.1 - react-native: 0.75.4(@babel/core@7.25.8)(@babel/preset-env@7.25.8)(@types/react@18.3.11)(react@18.3.1)(typescript@5.6.3) - dev: false - /react-native-track-player@4.1.1(react-native@0.75.4)(react@18.3.1): resolution: {integrity: sha512-E5N/eK/+HtAVJUAzXpm1cWz8ROheV9jb0TI6h2bM+333U+DWibTTnT2T1122FkCoXLXIYavtm2FR2if+5jH8cA==} peerDependencies: diff --git a/mobile/scripts/licenses/licenseClarification.json b/mobile/scripts/licenses/licenseClarification.json index 782c4188..28ce9118 100644 --- a/mobile/scripts/licenses/licenseClarification.json +++ b/mobile/scripts/licenses/licenseClarification.json @@ -1,4 +1,7 @@ { + "@backpackapp-io/react-native-toast@0.11.0": { + "copyright": "Copyright (c) 2022 Nick DeBaise" + }, "@paralleldrive/cuid2@2.2.2": { "repository": "https://github.com/paralleldrive/cuid2" }, @@ -87,9 +90,6 @@ "repository": "https://github.com/expo/expo/tree/main/packages/expo-web-browser", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015-present 650 Industries, Inc. (aka Expo)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE." }, - "react-native-toast-notifications@3.4.0": { - "repository": "https://github.com/arnnis/react-native-toast-notifications" - }, "react-native-track-player@4.1.1": { "copyright": "Copyright (c) 2017 Double Symmetry" }, diff --git a/mobile/src/api/tracks/[id]/playlist.ts b/mobile/src/api/tracks/[id]/playlist.ts index d732116a..653dbddc 100644 --- a/mobile/src/api/tracks/[id]/playlist.ts +++ b/mobile/src/api/tracks/[id]/playlist.ts @@ -6,7 +6,6 @@ import { } from "@tanstack/react-query"; import { and, eq } from "drizzle-orm"; import { useCallback } from "react"; -import { Toast } from "react-native-toast-notifications"; import { db } from "@/db"; import { playlists, tracksToPlaylists } from "@/db/schema"; @@ -138,7 +137,6 @@ export function useDeleteTrackFromPlaylist( if (wasFavorited) { queryClient.invalidateQueries({ queryKey: favoriteKeys.lists() }); } - Toast.show("Removed track from playlist."); }, }); } diff --git a/mobile/src/components/new/Sheet/Sheet.tsx b/mobile/src/components/new/Sheet/Sheet.tsx index 89d8f6bc..76203834 100644 --- a/mobile/src/components/new/Sheet/Sheet.tsx +++ b/mobile/src/components/new/Sheet/Sheet.tsx @@ -1,3 +1,4 @@ +import { Toasts } from "@backpackapp-io/react-native-toast"; import { cssInterop } from "nativewind"; import type { StyleProp, ViewStyle } from "react-native"; import { View } from "react-native"; @@ -33,6 +34,7 @@ export function Sheet({ } + ExtraOverlayComponent={} containerClassName={cn("rounded-t-lg bg-canvas dark:bg-neutral5", { "h-full": snapTop, })} diff --git a/mobile/src/lib/toast.tsx b/mobile/src/lib/toast.tsx new file mode 100644 index 00000000..27824828 --- /dev/null +++ b/mobile/src/lib/toast.tsx @@ -0,0 +1,43 @@ +import type { + Toast, + ToastOptions as TOptions, +} from "@backpackapp-io/react-native-toast"; +import { ToastPosition } from "@backpackapp-io/react-native-toast"; +import { Text, View } from "react-native"; + +import { cn } from "./style"; + +/** Sensible defaults for toast. */ +export const ToastOptions = { + customToast: CustomToast, + disableShadow: true, + position: ToastPosition.BOTTOM, + height: 36, + providerKey: "PERSISTS", +} satisfies TOptions; + +/** Render a custom toast (makes styling for light/dark mode easier). */ +function CustomToast({ type, message, height, width }: Toast) { + return ( + + + + {message as string} + + + + ); +} diff --git a/mobile/src/modules/media/services/Music.ts b/mobile/src/modules/media/services/Music.ts index 51c7b5e2..66876d8a 100644 --- a/mobile/src/modules/media/services/Music.ts +++ b/mobile/src/modules/media/services/Music.ts @@ -4,9 +4,9 @@ * This file contains classes containing helpers to manipulate the store. */ +import { toast } from "@backpackapp-io/react-native-toast"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { eq } from "drizzle-orm"; -import { Toast } from "react-native-toast-notifications"; import TrackPlayer, { State } from "react-native-track-player"; import { useStore } from "zustand"; import { @@ -27,6 +27,9 @@ import { } from "@/db/queries"; import { formatForMediaCard } from "@/db/utils/formatters"; +import i18next from "@/modules/i18n"; + +import { ToastOptions } from "@/lib/toast"; import { shuffleArray } from "@/utils/object"; import { ReservedPlaylists } from "../constants"; import { @@ -367,11 +370,11 @@ musicStore.subscribe( /** Helpers to manipulate the current queue. */ export class Queue { /** Add a track id at the end of the current queue. */ - static async add(trackId: string) { + static async add(trackId: string, trackName?: string) { musicStore.setState((prev) => ({ queueList: [...prev.queueList, trackId], })); - Toast.show("Added track to queue."); + toast(i18next.t("response.queueAdd", { name: trackName }), ToastOptions); await RNTPManager.reloadNextTrack(); } diff --git a/mobile/src/modules/scanning/helpers/rescan.ts b/mobile/src/modules/scanning/helpers/rescan.ts index d5b4ddeb..76b40bf8 100644 --- a/mobile/src/modules/scanning/helpers/rescan.ts +++ b/mobile/src/modules/scanning/helpers/rescan.ts @@ -1,6 +1,6 @@ +import { toast } from "@backpackapp-io/react-native-toast"; import { useMutation } from "@tanstack/react-query"; import { eq } from "drizzle-orm"; -import { Toast } from "react-native-toast-notifications"; import { db } from "@/db"; import { fileNodes, invalidTracks, tracks } from "@/db/schema"; @@ -9,6 +9,7 @@ import { getTracks } from "@/db/queries"; import i18next from "@/modules/i18n"; import { RecentList, Resynchronize } from "@/modules/media/services/Music"; +import { ToastOptions } from "@/lib/toast"; import { batch } from "@/utils/promise"; import { findAndSaveArtwork, cleanupImages } from "../helpers/artwork"; import { cleanupDatabase, findAndSaveAudio } from "./audio"; @@ -16,7 +17,10 @@ import { savePathComponents } from "./folder"; /** Look through our library for any new or updated tracks. */ export async function rescanForTracks() { - const toastId = Toast.show(i18next.t("response.scanStart"), { duration: 0 }); + const toastId = toast(i18next.t("response.scanStart"), { + ...ToastOptions, + duration: Infinity, + }); try { // Slight buffer before we run our code due to the code blocking the @@ -58,14 +62,17 @@ export async function rescanForTracks() { // Make sure the "recents" list is correct. RecentList.refresh(); - Toast.update(toastId, i18next.t("response.scanSuccess"), { - duration: 3000, + toast(i18next.t("response.scanSuccess"), { + ...ToastOptions, + id: toastId, + duration: 4000, }); } catch (err) { console.log(err); - Toast.update(toastId, i18next.t("response.scanFail"), { - type: "danger", - duration: 3000, + toast.error(i18next.t("response.scanFail"), { + ...ToastOptions, + id: toastId, + duration: 4000, }); } } diff --git a/mobile/src/providers/ToastProvider.tsx b/mobile/src/providers/ToastProvider.tsx deleted file mode 100644 index 5a0a6a3f..00000000 --- a/mobile/src/providers/ToastProvider.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { View } from "react-native"; -import { ToastProvider as RNTNProvider } from "react-native-toast-notifications"; - -import { cn } from "@/lib/style"; -import { StyledText } from "@/components/new/Typography"; - -/** Customize the style of the toasts displayed by `react-native-toast-notifications`. */ -export function ToastProvider({ children }: { children: React.ReactNode }) { - return ( - ( - - - {message} - - - )} - > - {children} - - ); -} diff --git a/mobile/src/providers/index.tsx b/mobile/src/providers/index.tsx index dee19fa8..5e6ba7aa 100644 --- a/mobile/src/providers/index.tsx +++ b/mobile/src/providers/index.tsx @@ -1,12 +1,13 @@ +import { Toasts } from "@backpackapp-io/react-native-toast"; import { BottomSheetModalProvider } from "@gorhom/bottom-sheet"; import { QueryClientProvider } from "@tanstack/react-query"; import { SheetProvider } from "react-native-actions-sheet"; import { GestureHandlerRootView } from "react-native-gesture-handler"; +import { SafeAreaProvider } from "react-native-safe-area-context"; import "@/screens/Sheets"; import { RouteHandlers } from "./RouteHandlers"; import { ThemeProvider } from "./ThemeProvider"; -import { ToastProvider } from "./ToastProvider"; import { queryClient } from "@/lib/react-query"; @@ -14,16 +15,19 @@ import { queryClient } from "@/lib/react-query"; export function AppProvider({ children }: { children: React.ReactNode }) { return ( - - + + - {children} + + {children} + + - - + + ); } diff --git a/mobile/src/resources/licenses.json b/mobile/src/resources/licenses.json index 7ae33169..854cf978 100644 --- a/mobile/src/resources/licenses.json +++ b/mobile/src/resources/licenses.json @@ -1,4 +1,12 @@ { + "@backpackapp-io/react-native-toast": { + "name": "@backpackapp-io/react-native-toast", + "version": "0.11.0", + "copyright": "Copyright (c) 2022 Nick DeBaise", + "source": "https://github.com/backpackapp-io/react-native-toast", + "license": "MIT", + "licenseText": "MIT License\n\nCopyright (c) 2022 Nick DeBaise\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE." + }, "@expo/vector-icons": { "name": "@expo/vector-icons", "version": "14.0.4", @@ -383,14 +391,6 @@ "license": "MIT", "licenseText": "The MIT License (MIT)\n\nCopyright (c) [2015-2016] [Horcrux]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE." }, - "react-native-toast-notifications": { - "name": "react-native-toast-notifications", - "version": "3.4.0", - "copyright": "Copyright (c) 2020 Alireza Rezania", - "source": "https://github.com/arnnis/react-native-toast-notifications", - "license": "MIT", - "licenseText": "MIT License\r\n\r\nCopyright (c) 2020 Alireza Rezania\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE." - }, "react-native-track-player": { "name": "react-native-track-player", "version": "4.1.1", diff --git a/mobile/src/screens/Sheets/Backup/data.ts b/mobile/src/screens/Sheets/Backup/data.ts index 5ea0307b..7e567087 100644 --- a/mobile/src/screens/Sheets/Backup/data.ts +++ b/mobile/src/screens/Sheets/Backup/data.ts @@ -1,3 +1,4 @@ +import { toast } from "@backpackapp-io/react-native-toast"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import * as DocumentPicker from "expo-document-picker"; import * as FileSystem from "expo-file-system"; @@ -5,7 +6,6 @@ import * as Sharing from "expo-sharing"; import { and, eq, isNull } from "drizzle-orm"; import { useTranslation } from "react-i18next"; import { Platform } from "react-native"; -import { Toast } from "react-native-toast-notifications"; import { z } from "zod"; import { db } from "@/db"; @@ -24,6 +24,7 @@ import i18next from "@/modules/i18n"; import { Resynchronize, musicStore } from "@/modules/media/services/Music"; import { clearAllQueries } from "@/lib/react-query"; +import { ToastOptions } from "@/lib/toast"; import { pickKeys } from "@/utils/object"; import { isFulfilled } from "@/utils/promise"; import type { Maybe } from "@/utils/types"; @@ -235,10 +236,10 @@ export const useExportBackup = () => { return useMutation({ mutationFn: exportBackup, onSuccess: () => { - Toast.show(t("response.exportSuccess")); + toast(t("response.exportSuccess"), ToastOptions); }, onError: (err) => { - Toast.show(err.message, { type: "danger" }); + toast.error(err.message, ToastOptions); }, }); }; @@ -251,10 +252,10 @@ export const useImportBackup = () => { mutationFn: importBackup, onSuccess: () => { clearAllQueries({ client: queryClient }); - Toast.show(t("response.importSuccess")); + toast(t("response.importSuccess"), ToastOptions); }, onError: (err) => { - Toast.show(err.message, { type: "danger" }); + toast.error(err.message, ToastOptions); }, }); }; diff --git a/mobile/src/screens/Sheets/Backup/index.tsx b/mobile/src/screens/Sheets/Backup/index.tsx index 137cf715..ba59ed63 100644 --- a/mobile/src/screens/Sheets/Backup/index.tsx +++ b/mobile/src/screens/Sheets/Backup/index.tsx @@ -22,10 +22,6 @@ export default function BackupSheet(props: SheetProps<"backup-sheet">) { id={props.sheetId} title={t("title.backup")} contentContainerClassName="gap-4" - // Work around for toast notification being underneath the modal. - // - Using `isModal` makes the sheet appear slower compared to - // the default behavior or not having it. - isModal={false} > {t("settings.description.backup")} diff --git a/mobile/src/screens/Sheets/ScanFilterList/data.ts b/mobile/src/screens/Sheets/ScanFilterList/data.ts index 9e8d9831..3ab261d6 100644 --- a/mobile/src/screens/Sheets/ScanFilterList/data.ts +++ b/mobile/src/screens/Sheets/ScanFilterList/data.ts @@ -1,14 +1,15 @@ +import { toast } from "@backpackapp-io/react-native-toast"; import { PrimaryDirectoryPath, StorageVolumesDirectoryPaths, } from "@missingcore/react-native-metadata-retriever"; import { useMutation } from "@tanstack/react-query"; import * as FileSystem from "expo-file-system"; -import { Toast } from "react-native-toast-notifications"; import i18next from "@/modules/i18n"; import { userPreferencesStore } from "@/services/UserPreferences"; +import { ToastOptions } from "@/lib/toast"; import { addTrailingSlash } from "@/utils/string"; const SAF = FileSystem.StorageAccessFramework; @@ -41,7 +42,7 @@ export function validatePath(path: string) { export async function pickPath() { const permissions = await SAF.requestDirectoryPermissionsAsync(); if (!permissions.granted) { - Toast.show(i18next.t("response.actionCancel"), { type: "danger" }); + toast.error(i18next.t("response.actionCancel"), ToastOptions); return; } @@ -83,9 +84,10 @@ async function addPathToList(props: { ); if (!exists || !isDirectory) throw Error(); } catch { - Toast.show(i18next.t("template.notFound", { name: trimmed }), { - type: "danger", - }); + toast.error( + i18next.t("template.notFound", { name: trimmed }), + ToastOptions, + ); return; } userPreferencesStore.setState((prev) => ({ diff --git a/mobile/src/screens/Sheets/ScanFilterList/index.tsx b/mobile/src/screens/Sheets/ScanFilterList/index.tsx index 749e1e75..0b1dcf22 100644 --- a/mobile/src/screens/Sheets/ScanFilterList/index.tsx +++ b/mobile/src/screens/Sheets/ScanFilterList/index.tsx @@ -4,7 +4,7 @@ import { } from "@missingcore/react-native-metadata-retriever"; import { useCallback, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; -import { View } from "react-native"; +import { Keyboard, View } from "react-native"; import type { SheetProps } from "react-native-actions-sheet"; import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList"; @@ -138,13 +138,14 @@ function FilterForm(props: { + onPress={() => { + Keyboard.dismiss(); mutateGuard(onSubmit, { list: props.listType, path: newPath, onSuccess: () => setNewPath(""), - }) - } + }); + }} disabled={!isValidPath || onSubmit.isPending} className="bg-red" > diff --git a/mobile/src/screens/Sheets/Track.tsx b/mobile/src/screens/Sheets/Track.tsx index bfa41df4..85bc2248 100644 --- a/mobile/src/screens/Sheets/Track.tsx +++ b/mobile/src/screens/Sheets/Track.tsx @@ -121,7 +121,7 @@ function AddActions({ data }: { data: TrackData }) { preventClose /> Queue.add(data.id)} + onPress={() => Queue.add(data.id, data.name)} Icon={} text={t("trackModal.queueAdd")} /> diff --git a/mobile/src/services/PlaybackService.ts b/mobile/src/services/PlaybackService.ts index 3d60d65b..d6b58417 100644 --- a/mobile/src/services/PlaybackService.ts +++ b/mobile/src/services/PlaybackService.ts @@ -1,5 +1,5 @@ +import { toast } from "@backpackapp-io/react-native-toast"; import { router } from "expo-router"; -import { Toast } from "react-native-toast-notifications"; import TrackPlayer, { AppKilledPlaybackBehavior, Capability, @@ -9,6 +9,7 @@ import TrackPlayer, { import { deleteTrack } from "@/db/queries"; +import i18next from "@/modules/i18n"; import type { TrackStatus } from "@/modules/media/services/Music"; import { Queue, @@ -20,6 +21,7 @@ import { MusicControls } from "@/modules/media/services/Playback"; import { removeUnusedCategories } from "@/modules/scanning/helpers/audio"; import { clearAllQueries } from "@/lib/react-query"; +import { ToastOptions } from "@/lib/toast"; /** How we handle the actions in the media control notification. */ export async function PlaybackService() { @@ -120,7 +122,10 @@ export async function PlaybackService() { router.navigate("/"); } - Toast.show("Track no longer exists.", { type: "danger", duration: 3000 }); + toast.error( + i18next.t("template.notFound", { name: erroredTrack?.title }), + ToastOptions, + ); // Clear all reference of the current playing track. await resetState(); });