From bc091393ecbc49c6f1b730da1c610d18243c8f4c Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:51:08 +0800 Subject: [PATCH 1/8] mobile: integrate expo-observe navigation metrics --- apps/mobile/src/app/(tabs)/index.tsx | 7 +++++++ apps/mobile/src/app/(tabs)/library/[tab].tsx | 8 +++++++- apps/mobile/src/app/(tabs)/settings/index.tsx | 13 ++++++++++--- apps/mobile/src/app/_layout.tsx | 13 ++++++++----- apps/mobile/src/app/player.tsx | 6 ++++++ apps/mobile/src/app/playlist/local/[id].tsx | 6 ++++++ 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/apps/mobile/src/app/(tabs)/index.tsx b/apps/mobile/src/app/(tabs)/index.tsx index 9a9c7e3c..7fbb7cd9 100644 --- a/apps/mobile/src/app/(tabs)/index.tsx +++ b/apps/mobile/src/app/(tabs)/index.tsx @@ -5,6 +5,7 @@ import dayjs from 'dayjs' import { eq } from 'drizzle-orm' import { useLiveQuery } from 'drizzle-orm/expo-sqlite' import { Image } from 'expo-image' +import { useObserve } from 'expo-observe' import { useRouter } from 'expo-router' import { useIncomingShare } from 'expo-sharing' import { @@ -102,6 +103,12 @@ function HomePage() { const { data: recentPlaylists } = useRecentPlaylists() + const { markInteractive } = useObserve() + + useEffect(() => { + markInteractive() + }, [markInteractive]) + const greeting = getGreetingMsg() const saveSearchHistory = useCallback( diff --git a/apps/mobile/src/app/(tabs)/library/[tab].tsx b/apps/mobile/src/app/(tabs)/library/[tab].tsx index f61ba02d..4db4e3bd 100644 --- a/apps/mobile/src/app/(tabs)/library/[tab].tsx +++ b/apps/mobile/src/app/(tabs)/library/[tab].tsx @@ -1,6 +1,7 @@ import Icon from '@react-native-vector-icons/material-design-icons' +import { useObserve } from 'expo-observe' import { useFocusEffect, useLocalSearchParams, useRouter } from 'expo-router' -import { useState, useTransition } from 'react' +import { useEffect, useState, useTransition } from 'react' import { StyleSheet, View } from 'react-native' import { Text, useTheme } from 'react-native-paper' import { useSafeAreaInsets } from 'react-native-safe-area-context' @@ -42,6 +43,11 @@ export default function Library() { const colors = useTheme().colors const router = useRouter() const { tab } = useLocalSearchParams<{ tab: string }>() + const { markInteractive } = useObserve() + + useEffect(() => { + markInteractive() + }, [markInteractive]) useFocusEffect(() => { if (tab === undefined) return diff --git a/apps/mobile/src/app/(tabs)/settings/index.tsx b/apps/mobile/src/app/(tabs)/settings/index.tsx index e98251b3..9513b25f 100644 --- a/apps/mobile/src/app/(tabs)/settings/index.tsx +++ b/apps/mobile/src/app/(tabs)/settings/index.tsx @@ -1,5 +1,7 @@ import { LinearGradient } from 'expo-linear-gradient' +import { useObserve } from 'expo-observe' import { useRouter } from 'expo-router' +import { useEffect } from 'react' import { ScrollView, StyleSheet, View } from 'react-native' import { Divider, List, Text, useTheme } from 'react-native-paper' import { useSafeAreaInsets } from 'react-native-safe-area-context' @@ -17,6 +19,11 @@ export default function SettingsPage() { const account = useAppStore((state) => state.bbplayerAccount) const hasBilibiliCookie = useAppStore((state) => state.hasBilibiliCookie()) const bilibiliUserInfo = useAppStore((state) => state.bilibiliUserInfo) + const { markInteractive } = useObserve() + + useEffect(() => { + markInteractive() + }, [markInteractive]) return ( @@ -155,7 +162,7 @@ export default function SettingsPage() { icon='chevron-right' /> )} - onPress={() => router.push('/settings/bilibili-account' as never)} + onPress={() => router.push('/settings/bilibili-account')} /> )} - onPress={() => router.push('/settings/account' as never)} + onPress={() => router.push('/settings/account')} /> )} - onPress={() => router.push('/settings/about' as never)} + onPress={() => router.push('/settings/about')} /> diff --git a/apps/mobile/src/app/_layout.tsx b/apps/mobile/src/app/_layout.tsx index af992223..1364c405 100644 --- a/apps/mobile/src/app/_layout.tsx +++ b/apps/mobile/src/app/_layout.tsx @@ -1,13 +1,13 @@ import { Orpheus } from '@bbplayer/orpheus' import { - fetch as fetchNetInfo, addEventListener as addNetInfoEventListener, + fetch as fetchNetInfo, } from '@react-native-community/netinfo' import * as Sentry from '@sentry/react-native' import { focusManager, onlineManager } from '@tanstack/react-query' import * as Application from 'expo-application' -import { ObserveRoot, useObserve } from 'expo-observe' -import { Stack, router } from 'expo-router' +import { Observe, ObserveRoot, useObserve } from 'expo-observe' +import { router, Stack } from 'expo-router' import * as Updates from 'expo-updates' import { useEffect, useState } from 'react' import type { AppStateStatus } from 'react-native' @@ -42,6 +42,10 @@ import migrations from '../../drizzle/migrations' const logger = log.extend('UI.RootLayout') +Observe.configure({ + integrations: { 'expo-router': true }, +}) + // 初始化 Sentry initializeSentry() @@ -66,10 +70,9 @@ function RootLayout() { setOnline(!isActuallyOffline(state)) }) - const unsubscribe = addNetInfoEventListener((state) => { + return addNetInfoEventListener((state) => { setOnline(!isActuallyOffline(state)) }) - return unsubscribe }) useEffect(() => { diff --git a/apps/mobile/src/app/player.tsx b/apps/mobile/src/app/player.tsx index e458416d..a6da53df 100644 --- a/apps/mobile/src/app/player.tsx +++ b/apps/mobile/src/app/player.tsx @@ -7,6 +7,7 @@ import { vec, } from '@shopify/react-native-skia' import { useImage } from 'expo-image' +import { useObserve } from 'expo-observe' import { router } from 'expo-router' import { useEffect, useMemo, useRef, useState } from 'react' import { @@ -78,6 +79,11 @@ export default function PlayerPage() { const insets = useSafeAreaInsets() const pagerRef = useRef(null) const currentTrack = useCurrentTrack() + const { markInteractive } = useObserve() + + useEffect(() => { + markInteractive() + }, [markInteractive]) const currentTrackCover = resolveBilibiliImageUrl( currentTrack ? resolveTrackCover(currentTrack.uniqueKey, currentTrack.coverUrl) diff --git a/apps/mobile/src/app/playlist/local/[id].tsx b/apps/mobile/src/app/playlist/local/[id].tsx index d47dc200..6342c41c 100644 --- a/apps/mobile/src/app/playlist/local/[id].tsx +++ b/apps/mobile/src/app/playlist/local/[id].tsx @@ -4,6 +4,7 @@ import type { TrueSheet } from '@lodev09/react-native-true-sheet' import { and, eq } from 'drizzle-orm' import { useLiveQuery } from 'drizzle-orm/expo-sqlite' import { useImage } from 'expo-image' +import { useObserve } from 'expo-observe' import { useLocalSearchParams, useRouter } from 'expo-router' import { useDeferredValue, useEffect, useMemo, useRef, useState } from 'react' import { StyleSheet, View } from 'react-native' @@ -153,6 +154,11 @@ export default function LocalPlaylistPage() { const theme = useTheme() const { colors } = theme const router = useRouter() + const { markInteractive } = useObserve() + + useEffect(() => { + markInteractive() + }, [markInteractive]) const bbplayerToken = useAppStore((state) => state.bbplayerToken) const [searchQuery, setSearchQuery] = useState('') const [startSearch, setStartSearch] = useState(false) From afd71a3b1e1d331d62c78f716f6ebfc727fe1776 Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:20:18 +0800 Subject: [PATCH 2/8] mobile: 1 --- apps/mobile/src/app/(tabs)/index.tsx | 2 +- apps/mobile/src/app/history/[date].tsx | 2 +- apps/mobile/src/app/onboarding.tsx | 4 ++-- .../src/app/playlist/remote/uploader/[mid].tsx | 2 +- apps/mobile/src/app/settings/about.tsx | 2 +- .../src/app/settings/bilibili-account/index.tsx | 12 ++++-------- .../app/settings/bilibili-account/qrcode-login.tsx | 2 +- .../modals/bilibili/AddVideoToBilibiliFavModal.tsx | 2 +- .../src/features/library/shared/TabDisabled.tsx | 4 +--- apps/mobile/src/hooks/stores/useSkinStore.ts | 2 +- apps/mobile/src/lib/api/bilibili/api.ts | 2 +- apps/mobile/src/lib/config/queryClient.ts | 2 +- apps/mobile/src/lib/facades/sharedPlaylist.ts | 6 ++---- apps/mobile/src/utils/error-handling.ts | 2 +- 14 files changed, 19 insertions(+), 27 deletions(-) diff --git a/apps/mobile/src/app/(tabs)/index.tsx b/apps/mobile/src/app/(tabs)/index.tsx index 7fbb7cd9..dba1b27f 100644 --- a/apps/mobile/src/app/(tabs)/index.tsx +++ b/apps/mobile/src/app/(tabs)/index.tsx @@ -310,7 +310,7 @@ function HomePage() { )} router.push('/settings/bilibili-account' as never)} + onPress={() => router.push('/settings/bilibili-account')} style={styles.avatarButton} > { storage.set('first_open', false) setIsClickFinalButton(true) - router.replace('/settings/bilibili-account/qrcode-login' as never) + router.replace('/settings/bilibili-account/qrcode-login') }, []) const handlePhone = useCallback(() => { storage.set('first_open', false) setIsClickFinalButton(true) - router.replace('/settings/bilibili-account/phone-login' as never) + router.replace('/settings/bilibili-account/phone-login') }, []) const animatedRowStyle = useAnimatedStyle(() => ({ diff --git a/apps/mobile/src/app/playlist/remote/uploader/[mid].tsx b/apps/mobile/src/app/playlist/remote/uploader/[mid].tsx index 9ff03416..3dc934c6 100644 --- a/apps/mobile/src/app/playlist/remote/uploader/[mid].tsx +++ b/apps/mobile/src/app/playlist/remote/uploader/[mid].tsx @@ -189,7 +189,7 @@ export default function UploaderPage() { diff --git a/apps/mobile/src/hooks/stores/useSkinStore.ts b/apps/mobile/src/hooks/stores/useSkinStore.ts index 375b160e..b4ef73f3 100644 --- a/apps/mobile/src/hooks/stores/useSkinStore.ts +++ b/apps/mobile/src/hooks/stores/useSkinStore.ts @@ -111,7 +111,7 @@ const useSkinStore = create()( ) } } - return persistedState as SkinStoreState + return persistedState }, partialize: (state) => ({ diff --git a/apps/mobile/src/lib/api/bilibili/api.ts b/apps/mobile/src/lib/api/bilibili/api.ts index 160359cc..eb95d0cb 100644 --- a/apps/mobile/src/lib/api/bilibili/api.ts +++ b/apps/mobile/src/lib/api/bilibili/api.ts @@ -1019,7 +1019,7 @@ export class BilibiliApi { type: 'ResponseFailed', }) } - const code = data.data.code as BilibiliQrCodeLoginStatus + const code = data.data.code if (code !== BilibiliQrCodeLoginStatus.QRCODE_LOGIN_STATUS_SUCCESS) { return { status: code, diff --git a/apps/mobile/src/lib/config/queryClient.ts b/apps/mobile/src/lib/config/queryClient.ts index 34c412a7..bb516d6e 100644 --- a/apps/mobile/src/lib/config/queryClient.ts +++ b/apps/mobile/src/lib/config/queryClient.ts @@ -26,7 +26,7 @@ export const queryClient = new QueryClient({ error.data.msgCode === -101 ) { toast.error('登录状态失效,请重新登录') - router.navigate('/settings/bilibili-account/qrcode-login' as never) + router.navigate('/settings/bilibili-account/qrcode-login') return } diff --git a/apps/mobile/src/lib/facades/sharedPlaylist.ts b/apps/mobile/src/lib/facades/sharedPlaylist.ts index 4a4ab21d..5bcb0fa1 100644 --- a/apps/mobile/src/lib/facades/sharedPlaylist.ts +++ b/apps/mobile/src/lib/facades/sharedPlaylist.ts @@ -470,7 +470,7 @@ export class SharedPlaylistFacade { await this._applyPullResponse( localId, remote.id, - changesData as Parameters[2], + changesData, tx, { playlistService: txPlaylist, @@ -695,9 +695,7 @@ export class SharedPlaylistFacade { `生成编辑者邀请码失败:${resp.status}`, ) } - const data = (await resp.json()) as { - editor_invite_code: string - } + const data = await resp.json() return { editorInviteCode: data.editor_invite_code } })(), (e) => diff --git a/apps/mobile/src/utils/error-handling.ts b/apps/mobile/src/utils/error-handling.ts index 8c9a47c3..c3a47860 100644 --- a/apps/mobile/src/utils/error-handling.ts +++ b/apps/mobile/src/utils/error-handling.ts @@ -34,7 +34,7 @@ export function toastAndLogError( }) } else { toast.error(message, { - description: String(error as unknown), + description: String(error), duration: Number.POSITIVE_INFINITY, }) log.extend(scope).error(message, error) From 9739d67b476ef44d3a7d748e4ff52cb54f4242d6 Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Wed, 12 Aug 2026 09:41:42 +0800 Subject: [PATCH 3/8] mobile: 1 --- .oxlintrc.json | 2 + apps/backend/src/routes/playlists.ts | 2 +- apps/mobile/src/app/_layout.tsx | 43 ++++++++++--------- apps/mobile/src/app/download.tsx | 15 ++++--- apps/mobile/src/app/playlist/local/[id].tsx | 4 +- .../bilibili-account/qrcode-login.tsx | 4 +- apps/mobile/src/app/share/playlist.tsx | 2 +- apps/mobile/src/components/NowPlayingBar.tsx | 20 ++++----- .../playlist/DuplicateLocalPlaylistModal.tsx | 2 +- .../playlist/SyncLocalToBilibiliModal.tsx | 2 +- .../src/features/home/SearchSuggestions.tsx | 2 +- .../components/lyrics/LyricLineItem.tsx | 9 ++-- .../local/components/SyncFailuresSheet.tsx | 2 +- .../src/hooks/queries/bilibili/search.ts | 2 +- apps/mobile/src/lib/api/bilibili/api.ts | 30 ++++++------- apps/mobile/src/lib/api/netease/request.ts | 2 + apps/mobile/src/lib/facades/sharedPlaylist.ts | 2 +- .../src/lib/player/PlayerSideEffects.ts | 2 +- .../src/lib/services/playlistService.ts | 8 ++-- apps/mobile/src/utils/error-handling.ts | 1 + apps/mobile/src/utils/sticky-mitt.ts | 1 + apps/update-publisher/src/index.ts | 2 +- packages/image-theme-colors/tsconfig.json | 3 +- packages/orpheus/src/hooks/useCurrentTrack.ts | 28 ++++++------ packages/orpheus/tsconfig.json | 3 +- .../react-native-bottom-tabs/src/SceneMap.tsx | 1 + packages/splash/tsconfig.json | 1 + 27 files changed, 104 insertions(+), 91 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index e3b36b46..13a58f48 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -56,6 +56,8 @@ "typescript/no-explicit-any": "error", "typescript/no-misused-promises": ["error", { "checksVoidReturn": false }], "typescript/no-unsafe-type-assertion": "allow", + "typescript/consistent-return": "off", + "no-underscore-dangle": ["error", { "allow": ["__csrf"] }], // tanstack query "@tanstack/query/exhaustive-deps": "error", diff --git a/apps/backend/src/routes/playlists.ts b/apps/backend/src/routes/playlists.ts index cd14cb33..97a9f9e3 100644 --- a/apps/backend/src/routes/playlists.ts +++ b/apps/backend/src/routes/playlists.ts @@ -140,7 +140,7 @@ const playlistsRoute = new Hono() cover_url: playlist.coverUrl, created_at: playlist.createdAt.getTime(), updated_at: playlist.updatedAt.getTime(), - track_count: Number(trackCount ?? 0), + track_count: trackCount ?? 0, }, owner: owner ? { diff --git a/apps/mobile/src/app/_layout.tsx b/apps/mobile/src/app/_layout.tsx index 1364c405..b18be570 100644 --- a/apps/mobile/src/app/_layout.tsx +++ b/apps/mobile/src/app/_layout.tsx @@ -57,6 +57,28 @@ function onAppStateChange(status: AppStateStatus) { } } +const checkOverlayPermissionOnStart = async () => { + if (Orpheus.isDesktopLyricsShown) { + const hasPermission = await Orpheus.checkOverlayPermission() + if (!hasPermission) { + // 延迟显示,确保 UI 已经加载 + setTimeout(() => { + alert( + '桌面歌词', + '检测到桌面歌词已开启,但缺少悬浮窗权限,请授权以恢复显示。', + [ + { text: '取消' }, + { + text: '去授权', + onPress: () => Orpheus.requestOverlayPermission(), + }, + ], + ) + }, 1000) + } + } +} + function RootLayout() { const [isReady, setIsReady] = useState(false) const { markInteractive } = useObserve() @@ -118,27 +140,6 @@ function RootLayout() { initPlayerQueueStore() // 桌面歌词权限启动检查 - const checkOverlayPermissionOnStart = async () => { - if (Orpheus.isDesktopLyricsShown) { - const hasPermission = await Orpheus.checkOverlayPermission() - if (!hasPermission) { - // 延迟显示,确保 UI 已经加载 - setTimeout(() => { - alert( - '桌面歌词', - '检测到桌面歌词已开启,但缺少悬浮窗权限,请授权以恢复显示。', - [ - { text: '取消' }, - { - text: '去授权', - onPress: () => Orpheus.requestOverlayPermission(), - }, - ], - ) - }, 1000) - } - } - } void checkOverlayPermissionOnStart() // 初始化播放器 Cookie diff --git a/apps/mobile/src/app/download.tsx b/apps/mobile/src/app/download.tsx index 7b0dbfa6..c0881d3c 100644 --- a/apps/mobile/src/app/download.tsx +++ b/apps/mobile/src/app/download.tsx @@ -75,14 +75,19 @@ export default function DownloadPage() { taskCount={tasks.length} retryableCount={tasks.filter(canRetryDownloadTask).length} onRetryAll={async () => { - await Promise.all( - tasks.filter(canRetryDownloadTask).map((task) => { + const promises = tasks + .filter(canRetryDownloadTask) + .map((task) => { if (task.state === DownloadState.STOPPED) { return Orpheus.resumeDownload(task.id) } - return task.track ? Orpheus.retryDownload(task.track) : undefined - }), - ) + if (task.track) { + return Orpheus.retryDownload(task.track) + } + return undefined + }) + .filter(Boolean) as Promise[] + await Promise.all(promises) await queryClient.invalidateQueries({ queryKey: orpheusQueryKeys.downloadTasks(), }) diff --git a/apps/mobile/src/app/playlist/local/[id].tsx b/apps/mobile/src/app/playlist/local/[id].tsx index 6342c41c..5a8b1135 100644 --- a/apps/mobile/src/app/playlist/local/[id].tsx +++ b/apps/mobile/src/app/playlist/local/[id].tsx @@ -348,14 +348,14 @@ export default function LocalPlaylistPage() { const { expandMultiPageOnSync } = useAppStore.getState().settings if (expandMultiPageOnSync === null) { openModal('SyncOptions', { - favoriteId: Number(playlistMetadata.remoteSyncId), + favoriteId: playlistMetadata.remoteSyncId, }) return } openModal( 'FavoriteSyncProgress', { - favoriteId: Number(playlistMetadata.remoteSyncId), + favoriteId: playlistMetadata.remoteSyncId, expandMultiPage: expandMultiPageOnSync, }, { dismissible: false }, diff --git a/apps/mobile/src/app/settings/bilibili-account/qrcode-login.tsx b/apps/mobile/src/app/settings/bilibili-account/qrcode-login.tsx index e780df59..6f975b76 100644 --- a/apps/mobile/src/app/settings/bilibili-account/qrcode-login.tsx +++ b/apps/mobile/src/app/settings/bilibili-account/qrcode-login.tsx @@ -34,7 +34,7 @@ type Action = payload: { qrcode_key: string; url: string } } | { type: 'GENERATE_FAILURE'; payload: string } - | { type: 'POLL_UPDATE'; payload: { code: number } } + | { type: 'POLL_UPDATE'; payload: { code: BilibiliQrCodeLoginStatus } } | { type: 'LOGIN_SUCCESS' } const initialState: State = { @@ -100,7 +100,7 @@ export default function QrCodeLoginPage() { if (response.isErr()) { dispatch({ type: 'GENERATE_FAILURE', - payload: String(response.error.message), + payload: response.error.message, }) toast.error('获取二维码失败', { id: 'bilibili-qrcode-login-error' }) } else { diff --git a/apps/mobile/src/app/share/playlist.tsx b/apps/mobile/src/app/share/playlist.tsx index 23610344..9f6f8099 100644 --- a/apps/mobile/src/app/share/playlist.tsx +++ b/apps/mobile/src/app/share/playlist.tsx @@ -36,7 +36,7 @@ const mapPreviewTrackToBilibiliTrack = ( index: number, now: Date, ): BilibiliTrack => { - const baseId = Number(bv2av(track.bilibili_bvid)) + const baseId = bv2av(track.bilibili_bvid) const cidNum = track.bilibili_cid ? Number(track.bilibili_cid) : undefined const id = Number.isFinite(baseId) ? baseId * 1000 + (cidNum ?? 0) + index diff --git a/apps/mobile/src/components/NowPlayingBar.tsx b/apps/mobile/src/components/NowPlayingBar.tsx index 2476fc9d..1ad3acf8 100644 --- a/apps/mobile/src/components/NowPlayingBar.tsx +++ b/apps/mobile/src/components/NowPlayingBar.tsx @@ -86,6 +86,16 @@ const ProgressBar = memo(function ProgressBar() { ) }) +const playPause = async () => { + void Haptics.performHaptics(Haptics.AndroidHaptics.Context_Click) + const isPlaying = await Orpheus.getIsPlaying() + if (isPlaying) { + void Orpheus.pause() + } else { + await Orpheus.play() + } +} + const NowPlayingBar = memo(function NowPlayingBar({ backgroundColor, }: { @@ -138,16 +148,6 @@ const NowPlayingBar = memo(function NowPlayingBar({ opacity: Math.min(Math.max(-dragOffset.value / 40, 0), 1), })) - const playPause = async () => { - void Haptics.performHaptics(Haptics.AndroidHaptics.Context_Click) - const isPlaying = await Orpheus.getIsPlaying() - if (isPlaying) { - void Orpheus.pause() - } else { - await Orpheus.play() - } - } - const navigateOnPlayerUpFling = useFlingGesture({ direction: Directions.UP, onActivate: () => { diff --git a/apps/mobile/src/components/modals/playlist/DuplicateLocalPlaylistModal.tsx b/apps/mobile/src/components/modals/playlist/DuplicateLocalPlaylistModal.tsx index 6fa22f28..bcf1a930 100644 --- a/apps/mobile/src/components/modals/playlist/DuplicateLocalPlaylistModal.tsx +++ b/apps/mobile/src/components/modals/playlist/DuplicateLocalPlaylistModal.tsx @@ -26,7 +26,7 @@ export default function DuplicateLocalPlaylistModal({ if (!duplicatePlaylistName) return duplicatePlaylist( { - playlistId: Number(sourcePlaylistId), + playlistId: sourcePlaylistId, name: duplicatePlaylistName, }, { diff --git a/apps/mobile/src/components/modals/playlist/SyncLocalToBilibiliModal.tsx b/apps/mobile/src/components/modals/playlist/SyncLocalToBilibiliModal.tsx index ea2e1cd5..ee92a6d3 100644 --- a/apps/mobile/src/components/modals/playlist/SyncLocalToBilibiliModal.tsx +++ b/apps/mobile/src/components/modals/playlist/SyncLocalToBilibiliModal.tsx @@ -118,7 +118,7 @@ export default function SyncLocalToBilibiliModal({ const check = async () => { const res = await syncLocalToBilibiliService.findRemotePlaylistByName( - Number(userInfo.mid), + userInfo.mid, playlist.title, ) if (res.isErr()) { diff --git a/apps/mobile/src/features/home/SearchSuggestions.tsx b/apps/mobile/src/features/home/SearchSuggestions.tsx index 724150b2..4391cdd6 100644 --- a/apps/mobile/src/features/home/SearchSuggestions.tsx +++ b/apps/mobile/src/features/home/SearchSuggestions.tsx @@ -48,7 +48,7 @@ export interface SearchHistoryItem { * - 强调段 { text, emphasized: true } */ function parseEmTags(text: string | undefined) { - const s = String(text ?? '') + const s = text ?? '' const regex = /]*>(.*?)<\/em>/gi const segments: { text: string; emphasized: boolean }[] = [] let lastIndex = 0 diff --git a/apps/mobile/src/features/player/components/lyrics/LyricLineItem.tsx b/apps/mobile/src/features/player/components/lyrics/LyricLineItem.tsx index 8f15f66f..406d7a49 100644 --- a/apps/mobile/src/features/player/components/lyrics/LyricLineItem.tsx +++ b/apps/mobile/src/features/player/components/lyrics/LyricLineItem.tsx @@ -48,12 +48,11 @@ export const OldSchoolLyricLineItem = memo(function OldSchoolLyricLineItem({ return isHighlighted.value ? currentTime.value : -1 }) - const isVerbatim = !!( + const isVerbatim = enableVerbatimLyrics && item.isDynamic && item.spans && item.spans.length > 0 - ) const animatedStyle = useAnimatedStyle(() => { const duration = isVerbatim ? 0 : 300 @@ -147,13 +146,11 @@ export const ModernLyricLineItem = memo(function ModernLyricLineItem({ (currentVal) => { scheduleOnRN( setIsVerbatim, - !!( - enableVerbatimLyrics && + enableVerbatimLyrics && item.isDynamic && item.spans && item.spans.length > 0 && - currentVal === index - ), + currentVal === index, ) scheduleOnRN(setIsHighlightedRState, currentVal === index) }, diff --git a/apps/mobile/src/features/playlist/local/components/SyncFailuresSheet.tsx b/apps/mobile/src/features/playlist/local/components/SyncFailuresSheet.tsx index 5d541bfd..75ce2373 100644 --- a/apps/mobile/src/features/playlist/local/components/SyncFailuresSheet.tsx +++ b/apps/mobile/src/features/playlist/local/components/SyncFailuresSheet.tsx @@ -64,7 +64,7 @@ export const SyncFailuresSheet = forwardRef( const insets = useSafeAreaInsets() const [loading, setLoading] = useState(false) - const { data: dbRows = [] } = useLiveQuery( + const { data: dbRows } = useLiveQuery( db .select() .from(schema.playlistSyncQueue) diff --git a/apps/mobile/src/hooks/queries/bilibili/search.ts b/apps/mobile/src/hooks/queries/bilibili/search.ts index 8a654559..14f40789 100644 --- a/apps/mobile/src/hooks/queries/bilibili/search.ts +++ b/apps/mobile/src/hooks/queries/bilibili/search.ts @@ -21,7 +21,7 @@ export const useSearchResults = (query: string) => { const enabled = query.trim().length > 0 return useInfiniteQuery({ queryKey: searchQueryKeys.results(query), - queryFn: ({ pageParam = 1, signal }) => + queryFn: ({ pageParam, signal }) => returnOrThrowAsync( bilibiliApi.searchVideos({ keyword: query, diff --git a/apps/mobile/src/lib/api/bilibili/api.ts b/apps/mobile/src/lib/api/bilibili/api.ts index eb95d0cb..c799e668 100644 --- a/apps/mobile/src/lib/api/bilibili/api.ts +++ b/apps/mobile/src/lib/api/bilibili/api.ts @@ -167,10 +167,10 @@ export class BilibiliApi { }) return params - .andThen((params) => { + .andThen((encodedParams) => { return bilibiliApiClient.getBuffer({ endpoint: '/x/v2/dm/wbi/web/seg.so', - params, + params: encodedParams, signal, }) }) @@ -239,13 +239,13 @@ export class BilibiliApi { }) return params - .andThen((params) => { + .andThen((encodedParams) => { return bilibiliApiClient.get<{ result: BilibiliSearchVideo[] numPages: number }>({ endpoint: '/x/web-interface/wbi/search/type', - params, + params: encodedParams, skipCookie, signal, }) @@ -282,13 +282,13 @@ export class BilibiliApi { }) return params - .andThen((params) => { + .andThen((encodedParams) => { return bilibiliApiClient.get<{ result: BilibiliSearchUser[] numPages: number }>({ endpoint: '/x/web-interface/wbi/search/type', - params, + params: encodedParams, skipCookie, signal, }) @@ -416,10 +416,10 @@ export class BilibiliApi { }) return wbiParams - .andThen((params) => { + .andThen((encodedParams) => { return bilibiliApiClient.get({ endpoint: '/x/player/wbi/playurl', - params, + params: encodedParams, }) }) .andThen((response) => { @@ -572,10 +572,10 @@ export class BilibiliApi { const params = getWbiEncodedParams({ mid: mid.toString(), }) - return params.andThen((params) => { + return params.andThen((encodedParams) => { return bilibiliApiClient.get({ endpoint: '/x/space/wbi/acc/info', - params, + params: encodedParams, signal, }) }) @@ -866,10 +866,10 @@ export class BilibiliApi { keyword: keyword ?? '', ps: '30', }) - return params.andThen((params) => { + return params.andThen((encodedParams) => { return bilibiliApiClient.get({ endpoint: '/x/space/wbi/arc/search', - params, + params: encodedParams, signal, }) }) @@ -1008,7 +1008,7 @@ export class BilibiliApi { }) } const data = (await response.json()) as { - data: { code: number } + data: { code: BilibiliQrCodeLoginStatus } code: number } if (data.code !== 0) { @@ -1190,10 +1190,10 @@ export class BilibiliApi { bvid, cid: String(cid), }) - return params.andThen((params) => { + return params.andThen((encodedParams) => { return bilibiliApiClient.get({ endpoint: '/x/player/wbi/v2', - params, + params: encodedParams, signal, }) }) diff --git a/apps/mobile/src/lib/api/netease/request.ts b/apps/mobile/src/lib/api/netease/request.ts index caf7e406..961618b6 100644 --- a/apps/mobile/src/lib/api/netease/request.ts +++ b/apps/mobile/src/lib/api/netease/request.ts @@ -50,6 +50,7 @@ interface RequestPayload { signal?: AbortSignal } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters const buildRequestPayload = ( uri: string, data: T, @@ -173,6 +174,7 @@ const executeFetch = ( ).andThen((res) => res as Result, NeteaseApiError>) } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters export const createRequest = ( uri: string, data: TData, diff --git a/apps/mobile/src/lib/facades/sharedPlaylist.ts b/apps/mobile/src/lib/facades/sharedPlaylist.ts index 5bcb0fa1..087ac5f6 100644 --- a/apps/mobile/src/lib/facades/sharedPlaylist.ts +++ b/apps/mobile/src/lib/facades/sharedPlaylist.ts @@ -358,7 +358,7 @@ export class SharedPlaylistFacade { coverUrl: data.playlist.cover_url ?? null, createdAt: new Date(data.playlist.created_at), updatedAt: new Date(data.playlist.updated_at), - trackCount: Number(data.playlist.track_count ?? 0), + trackCount: data.playlist.track_count ?? 0, }, owner: data.owner ? { diff --git a/apps/mobile/src/lib/player/PlayerSideEffects.ts b/apps/mobile/src/lib/player/PlayerSideEffects.ts index 246921b0..f8fb43d5 100644 --- a/apps/mobile/src/lib/player/PlayerSideEffects.ts +++ b/apps/mobile/src/lib/player/PlayerSideEffects.ts @@ -206,7 +206,7 @@ class PlayerSideEffects { 'Unknown playback error', ) } - return new Error(String(event.error || 'Unknown playback error')) + return new Error(event.error || 'Unknown playback error') } /** diff --git a/apps/mobile/src/lib/services/playlistService.ts b/apps/mobile/src/lib/services/playlistService.ts index 360cce64..a6043ba4 100644 --- a/apps/mobile/src/lib/services/playlistService.ts +++ b/apps/mobile/src/lib/services/playlistService.ts @@ -309,9 +309,9 @@ export class PlaylistService { `) return { - itemCount: Number(row?.itemCount ?? 0), - validTrackCount: Number(row?.validTrackCount ?? 0), - totalDuration: Number(row?.totalDuration ?? 0), + itemCount: row?.itemCount ?? 0, + validTrackCount: row?.validTrackCount ?? 0, + totalDuration: row?.totalDuration ?? 0, } } @@ -347,7 +347,7 @@ export class PlaylistService { return new Map( uniqueIds.map((id) => [ id, - Number(rows.find((row) => row.playlistId === id)?.itemCount ?? 0), + rows.find((row) => row.playlistId === id)?.itemCount ?? 0, ]), ) } diff --git a/apps/mobile/src/utils/error-handling.ts b/apps/mobile/src/utils/error-handling.ts index c3a47860..96023234 100644 --- a/apps/mobile/src/utils/error-handling.ts +++ b/apps/mobile/src/utils/error-handling.ts @@ -34,6 +34,7 @@ export function toastAndLogError( }) } else { toast.error(message, { + // oxlint-disable-next-line typescript/no-base-to-string description: String(error), duration: Number.POSITIVE_INFINITY, }) diff --git a/apps/mobile/src/utils/sticky-mitt.ts b/apps/mobile/src/utils/sticky-mitt.ts index 51042845..fb17ea7d 100644 --- a/apps/mobile/src/utils/sticky-mitt.ts +++ b/apps/mobile/src/utils/sticky-mitt.ts @@ -52,6 +52,7 @@ function createStickyEmitter>() { /** * 清除某个事件类型的粘性状态。 */ + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters clearSticky(type: Key): void { stickyEvents.delete(type) }, diff --git a/apps/update-publisher/src/index.ts b/apps/update-publisher/src/index.ts index c161c1f7..df2ada4d 100644 --- a/apps/update-publisher/src/index.ts +++ b/apps/update-publisher/src/index.ts @@ -358,7 +358,7 @@ async function run( } main().catch((error: unknown) => { - // oxlint-disable-next-line eslint(no-console) + // oxlint-disable-next-line no-console console.error(error instanceof Error ? error.message : String(error)) process.exitCode = 1 }) diff --git a/packages/image-theme-colors/tsconfig.json b/packages/image-theme-colors/tsconfig.json index 4805038e..c5813f08 100644 --- a/packages/image-theme-colors/tsconfig.json +++ b/packages/image-theme-colors/tsconfig.json @@ -4,7 +4,8 @@ "compilerOptions": { "skipLibCheck": true, "exactOptionalPropertyTypes": false, - "outDir": "./build" + "outDir": "./build", + "rootDir": "./src" }, "include": ["./src"], "exclude": ["**/__mocks__/*", "**/__tests__/*", "**/__rsc_tests__/*"] diff --git a/packages/orpheus/src/hooks/useCurrentTrack.ts b/packages/orpheus/src/hooks/useCurrentTrack.ts index a0ae5406..72c7ca25 100644 --- a/packages/orpheus/src/hooks/useCurrentTrack.ts +++ b/packages/orpheus/src/hooks/useCurrentTrack.ts @@ -2,6 +2,20 @@ import { useState, useEffect } from 'react' import { type Track, Orpheus } from '../ExpoOrpheusModule' +const fetchTrack = async () => { + try { + const [currentTrack, currentIndex] = await Promise.all([ + Orpheus.getCurrentTrack(), + Orpheus.getCurrentIndex(), + ]) + console.log(currentTrack) + return { currentTrack, currentIndex } + } catch (e) { + console.warn('Failed to fetch current track', e) + return { currentTrack: null, currentIndex: -1 } + } +} + /** * 订阅原生曲目开始事件,并暴露当前曲目和队列索引。 */ @@ -9,20 +23,6 @@ export function useCurrentTrack() { const [track, setTrack] = useState(null) const [index, setIndex] = useState(-1) - const fetchTrack = async () => { - try { - const [currentTrack, currentIndex] = await Promise.all([ - Orpheus.getCurrentTrack(), - Orpheus.getCurrentIndex(), - ]) - console.log(currentTrack) - return { currentTrack, currentIndex } - } catch (e) { - console.warn('Failed to fetch current track', e) - return { currentTrack: null, currentIndex: -1 } - } - } - useEffect(() => { let isMounted = true diff --git a/packages/orpheus/tsconfig.json b/packages/orpheus/tsconfig.json index 4805038e..c5813f08 100644 --- a/packages/orpheus/tsconfig.json +++ b/packages/orpheus/tsconfig.json @@ -4,7 +4,8 @@ "compilerOptions": { "skipLibCheck": true, "exactOptionalPropertyTypes": false, - "outDir": "./build" + "outDir": "./build", + "rootDir": "./src" }, "include": ["./src"], "exclude": ["**/__mocks__/*", "**/__tests__/*", "**/__rsc_tests__/*"] diff --git a/packages/react-native-bottom-tabs/src/SceneMap.tsx b/packages/react-native-bottom-tabs/src/SceneMap.tsx index 6b5be226..6830373c 100644 --- a/packages/react-native-bottom-tabs/src/SceneMap.tsx +++ b/packages/react-native-bottom-tabs/src/SceneMap.tsx @@ -6,6 +6,7 @@ type SceneProps = { } const SceneComponent = React.memo( + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters } & SceneProps>({ component, ...rest diff --git a/packages/splash/tsconfig.json b/packages/splash/tsconfig.json index 79ffc2c5..96f932ce 100644 --- a/packages/splash/tsconfig.json +++ b/packages/splash/tsconfig.json @@ -8,6 +8,7 @@ "exactOptionalPropertyTypes": false, "forceConsistentCasingInFileNames": true, "outDir": "./dist", + "rootDir": "./src", "types": ["jest", "node"] }, "include": ["src/**/*"] From 1be882c50b2be22b0b693a7214a41d7700263a96 Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Wed, 12 Aug 2026 09:55:50 +0800 Subject: [PATCH 4/8] mobile: 1 --- apps/backend/src/routes/playlists.ts | 32 +++++++++---------- .../src/app/playlist/recently/index.tsx | 4 +-- .../app/playlist/remote/collection/[id].tsx | 10 +++--- .../src/app/playlist/remote/favorite/[id].tsx | 4 +-- .../app/playlist/remote/multipage/[bvid].tsx | 6 ++-- apps/mobile/src/components/NowPlayingBar.tsx | 2 +- .../playlist/ManualMatchExternalSync.tsx | 8 ++--- .../features/downloads/DownloadTaskItem.tsx | 2 +- .../src/features/home/SearchSuggestions.tsx | 6 ++-- apps/mobile/src/hooks/queries/playHistory.ts | 4 +-- apps/mobile/src/lib/api/netease/crypto.ts | 8 ++--- apps/mobile/src/lib/facades/bilibili.ts | 4 +-- apps/mobile/src/lib/facades/playlist.ts | 22 ++++++------- apps/mobile/src/lib/facades/sharedPlaylist.ts | 30 ++++++++--------- .../src/lib/facades/syncBilibiliPlaylist.ts | 28 ++++++++-------- .../src/lib/facades/syncExternalPlaylist.ts | 16 +++++----- .../src/lib/player/PlayerSideEffects.ts | 16 +++++----- apps/mobile/src/lib/services/artistService.ts | 8 ++--- apps/mobile/src/lib/services/lyricService.ts | 8 ++--- .../src/lib/services/playlistService.ts | 12 +++---- apps/mobile/src/lib/services/trackService.ts | 10 +++--- .../react-native-bottom-tabs/src/TabView.tsx | 2 +- 22 files changed, 121 insertions(+), 121 deletions(-) diff --git a/apps/backend/src/routes/playlists.ts b/apps/backend/src/routes/playlists.ts index 97a9f9e3..0dfafe2d 100644 --- a/apps/backend/src/routes/playlists.ts +++ b/apps/backend/src/routes/playlists.ts @@ -251,9 +251,9 @@ const playlistsRoute = new Hono() (a, b) => a.operation_at - b.operation_at, ) - const upsertChanges = sorted.filter((c) => c.op === 'upsert') - const removeChanges = sorted.filter((c) => c.op === 'remove') - const reorderChanges = sorted.filter((c) => c.op === 'reorder') + const upsertChanges = sorted.filter((ch) => ch.op === 'upsert') + const removeChanges = sorted.filter((ch) => ch.op === 'remove') + const reorderChanges = sorted.filter((ch) => ch.op === 'reorder') await db.transaction(async (tx) => { // 1. 批量 upsert shared_tracks(资源池) @@ -261,15 +261,15 @@ const playlistsRoute = new Hono() await tx .insert(sharedTracks) .values( - upsertChanges.map((c) => ({ - uniqueKey: c.track.unique_key, - title: c.track.title, - artistName: c.track.artist_name, - artistId: c.track.artist_id, - coverUrl: c.track.cover_url, - duration: c.track.duration, - bilibiliBvid: c.track.bilibili_bvid, - bilibiliCid: c.track.bilibili_cid, + upsertChanges.map((ch) => ({ + uniqueKey: ch.track.unique_key, + title: ch.track.title, + artistName: ch.track.artist_name, + artistId: ch.track.artist_id, + coverUrl: ch.track.cover_url, + duration: ch.track.duration, + bilibiliBvid: ch.track.bilibili_bvid, + bilibiliCid: ch.track.bilibili_cid, })), ) .onConflictDoUpdate({ @@ -286,12 +286,12 @@ const playlistsRoute = new Hono() await tx .insert(sharedPlaylistTracks) .values( - upsertChanges.map((c) => ({ + upsertChanges.map((ch) => ({ playlistId, - trackUniqueKey: c.track.unique_key, - sortKey: c.sort_key, + trackUniqueKey: ch.track.unique_key, + sortKey: ch.sort_key, addedByUserId: userId, - updatedAt: new Date(c.operation_at), + updatedAt: new Date(ch.operation_at), deletedAt: null, })), ) diff --git a/apps/mobile/src/app/playlist/recently/index.tsx b/apps/mobile/src/app/playlist/recently/index.tsx index a9eae8ee..834453cf 100644 --- a/apps/mobile/src/app/playlist/recently/index.tsx +++ b/apps/mobile/src/app/playlist/recently/index.tsx @@ -75,9 +75,9 @@ export default function RecentlyPlayedPage() { toast.error('没有可播放的歌曲') return } - const tracks = tracksData.map((item) => item.track) + const playlistTracks = tracksData.map((item) => item.track) await addToQueue({ - tracks, + tracks: playlistTracks, playNow: true, clearQueue: true, playNext: false, diff --git a/apps/mobile/src/app/playlist/remote/collection/[id].tsx b/apps/mobile/src/app/playlist/remote/collection/[id].tsx index cd8a0041..982c562d 100644 --- a/apps/mobile/src/app/playlist/remote/collection/[id].tsx +++ b/apps/mobile/src/app/playlist/remote/collection/[id].tsx @@ -119,11 +119,11 @@ export default function CollectionPage() { toastId, }, { - onSuccess: (id) => { - if (!id) return + onSuccess: (localId) => { + if (!localId) return router.replace({ pathname: '/playlist/local/[id]', - params: { id: String(id) }, + params: { id: String(localId) }, }) }, }, @@ -188,8 +188,8 @@ export default function CollectionPage() { icon='playlist-plus' onPress={() => { const payloads = [] - for (const id of selected) { - const track = tracks.find((t) => t.id === id) + for (const selectedId of selected) { + const track = tracks.find((t) => t.id === selectedId) if (track) { payloads.push({ track: track as Track, diff --git a/apps/mobile/src/app/playlist/remote/favorite/[id].tsx b/apps/mobile/src/app/playlist/remote/favorite/[id].tsx index 7b24be46..3869a71b 100644 --- a/apps/mobile/src/app/playlist/remote/favorite/[id].tsx +++ b/apps/mobile/src/app/playlist/remote/favorite/[id].tsx @@ -204,8 +204,8 @@ export default function FavoritePage() { icon='playlist-plus' onPress={() => { const payloads = [] - for (const id of selected) { - const track = tracks.find((t) => t.id === id) + for (const selectedId of selected) { + const track = tracks.find((t) => t.id === selectedId) if (track) { payloads.push({ track: track as Track, diff --git a/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx b/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx index 74607a5b..ef7b54b0 100644 --- a/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx +++ b/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx @@ -178,8 +178,8 @@ export default function MultipagePage() { if (!extraData) throw new Error('Extradata 不存在') const { playTrack: play, - trackMenuItems, - selection, + trackMenuItems: _trackMenuItems, + selection: _selection, showItemCover, } = extraData @@ -190,7 +190,7 @@ export default function MultipagePage() { shouldFlash={shouldFlash} index={index} onTrackPress={() => play(item)} - menuItems={trackMenuItems(item)} + menuItems={_trackMenuItems(item)} showCoverImage={showItemCover ?? true} data={{ cover: item.coverUrl ?? undefined, diff --git a/apps/mobile/src/components/NowPlayingBar.tsx b/apps/mobile/src/components/NowPlayingBar.tsx index 1ad3acf8..d7fe9567 100644 --- a/apps/mobile/src/components/NowPlayingBar.tsx +++ b/apps/mobile/src/components/NowPlayingBar.tsx @@ -111,7 +111,7 @@ const NowPlayingBar = memo(function NowPlayingBar({ const bottomBarHeight = useBottomTabBarHeight() const nowPlayingBarStyle = useAppStore( - (state) => state.settings.nowPlayingBarStyle, + (s) => s.settings.nowPlayingBarStyle, ) const finalPlayingIndicator = isPlaying ? 'pause' : 'play' diff --git a/apps/mobile/src/components/modals/playlist/ManualMatchExternalSync.tsx b/apps/mobile/src/components/modals/playlist/ManualMatchExternalSync.tsx index 4c090252..f5aab648 100644 --- a/apps/mobile/src/components/modals/playlist/ManualMatchExternalSync.tsx +++ b/apps/mobile/src/components/modals/playlist/ManualMatchExternalSync.tsx @@ -104,11 +104,11 @@ export default function ManualMatchExternalSync({ const allTracks = data.pages.flatMap((page) => page.result) const uniqueMap = new Map( - allTracks.map((track) => [ - track.bvid, + allTracks.map((t) => [ + t.bvid, { - ...track, - title: decode(track.title), + ...t, + title: decode(t.title), }, ]), ) diff --git a/apps/mobile/src/features/downloads/DownloadTaskItem.tsx b/apps/mobile/src/features/downloads/DownloadTaskItem.tsx index e7eefb4d..e870c7c0 100644 --- a/apps/mobile/src/features/downloads/DownloadTaskItem.tsx +++ b/apps/mobile/src/features/downloads/DownloadTaskItem.tsx @@ -37,7 +37,7 @@ const DownloadTaskItem = memo(function DownloadTaskItem({ const handler = (e: ProgressEvent['progress:uniqueKey']) => { sharedProgress.value = e.percent if (e.state !== task.state) { - setTask((task) => ({ ...task, state: e.state })) + setTask((t) => ({ ...t, state: e.state })) } } eventListner.on(`progress:${task.id}`, handler) diff --git a/apps/mobile/src/features/home/SearchSuggestions.tsx b/apps/mobile/src/features/home/SearchSuggestions.tsx index 4391cdd6..5a344726 100644 --- a/apps/mobile/src/features/home/SearchSuggestions.tsx +++ b/apps/mobile/src/features/home/SearchSuggestions.tsx @@ -113,9 +113,9 @@ export default function SearchSuggestions({ useEffect(() => { scheduleOnUI( - (visible: boolean, tabBarHeight: number) => { - visibleShared.value = visible ? 1 : 0 - tabBarHeightShared.value = tabBarHeight + (vis: boolean, barHeight: number) => { + visibleShared.value = vis ? 1 : 0 + tabBarHeightShared.value = barHeight }, visible, tabBarHeight, diff --git a/apps/mobile/src/hooks/queries/playHistory.ts b/apps/mobile/src/hooks/queries/playHistory.ts index 601cf1ec..1819fc33 100644 --- a/apps/mobile/src/hooks/queries/playHistory.ts +++ b/apps/mobile/src/hooks/queries/playHistory.ts @@ -46,8 +46,8 @@ export const usePlayHistoryByDate = (dateStr: string) => { queryKey: playHistoryKeys.byDate(dateStr), queryFn: async () => { const historyRows = await drizzleDb.query.playHistory.findMany({ - where: (ph, { sql }) => { - return sql`date(${ph.startTime} / 1000, 'unixepoch', 'localtime') = ${dateStr}` + where: (ph, { sql: sqlFn }) => { + return sqlFn`date(${ph.startTime} / 1000, 'unixepoch', 'localtime') = ${dateStr}` }, with: { track: { diff --git a/apps/mobile/src/lib/api/netease/crypto.ts b/apps/mobile/src/lib/api/netease/crypto.ts index d85949b5..0409df30 100644 --- a/apps/mobile/src/lib/api/netease/crypto.ts +++ b/apps/mobile/src/lib/api/netease/crypto.ts @@ -16,7 +16,7 @@ const aesEncrypt = ( text: string, mode: 'cbc' | 'ecb', key: string, - iv: string, + aesIv: string, format = 'base64', ): string => { const encrypted = CryptoJS.AES.encrypt( @@ -82,13 +82,13 @@ export const eapi = ( const aesDecrypt = ( ciphertext: string, key: string, - iv: string, + aesIv: string, format = 'base64', ): string => { let bytes if (format === 'base64') { bytes = CryptoJS.AES.decrypt(ciphertext, CryptoJS.enc.Utf8.parse(key), { - iv: CryptoJS.enc.Utf8.parse(iv), + iv: CryptoJS.enc.Utf8.parse(aesIv), mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7, }) @@ -98,7 +98,7 @@ const aesDecrypt = ( { ciphertext: CryptoJS.enc.Hex.parse(ciphertext) }, CryptoJS.enc.Utf8.parse(key), { - iv: CryptoJS.enc.Utf8.parse(iv), + iv: CryptoJS.enc.Utf8.parse(aesIv), mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7, }, diff --git a/apps/mobile/src/lib/facades/bilibili.ts b/apps/mobile/src/lib/facades/bilibili.ts index 599ced38..331f00ec 100644 --- a/apps/mobile/src/lib/facades/bilibili.ts +++ b/apps/mobile/src/lib/facades/bilibili.ts @@ -1,7 +1,7 @@ import { err, ok } from 'neverthrow' import { - bilibiliApi, + bilibiliApi as bilibiliApiInstance, type bilibiliApi as BilibiliApiService, } from '@/lib/api/bilibili/api' import { av2bv } from '@/lib/api/bilibili/utils' @@ -96,4 +96,4 @@ export class BilibiliFacade { } } -export const bilibiliFacade = new BilibiliFacade(bilibiliApi) + export const bilibiliFacade = new BilibiliFacade(bilibiliApiInstance) diff --git a/apps/mobile/src/lib/facades/playlist.ts b/apps/mobile/src/lib/facades/playlist.ts index 854ea75a..064342bd 100644 --- a/apps/mobile/src/lib/facades/playlist.ts +++ b/apps/mobile/src/lib/facades/playlist.ts @@ -1,17 +1,17 @@ import type { ExpoSQLiteDatabase } from 'drizzle-orm/expo-sqlite' import { ResultAsync, errAsync } from 'neverthrow' -import { api as bbplayerApi } from '@/lib/api/bbplayer/client' -import db from '@/lib/db/db' +import { api as bbplayerApiInstance } from '@/lib/api/bbplayer/client' +import defaultDb from '@/lib/db/db' import * as schema from '@/lib/db/schema' import { createFacadeError } from '@/lib/errors/facade' import { createValidationError } from '@/lib/errors/service' -import { artistService, type ArtistService } from '@/lib/services/artistService' +import { artistService as artistServiceInstance, type ArtistService } from '@/lib/services/artistService' import { - playlistService, + playlistService as playlistServiceInstance, type PlaylistService, } from '@/lib/services/playlistService' -import { trackService, type TrackService } from '@/lib/services/trackService' +import { trackService as trackServiceInstance, type TrackService } from '@/lib/services/trackService' import { playlistSyncWorker } from '@/lib/workers/PlaylistSyncWorker' import type { CreateArtistPayload } from '@/types/services/artist' import type { @@ -21,7 +21,7 @@ import type { import type { CreateTrackPayload } from '@/types/services/track' import log from '@/utils/log' -type BbplayerApiClient = typeof bbplayerApi +type BbplayerApiClient = typeof bbplayerApiInstance const logger = log.extend('Facade') @@ -781,9 +781,9 @@ export class PlaylistFacade { } export const playlistFacade = new PlaylistFacade( - trackService, - playlistService, - artistService, - db, - bbplayerApi, + trackServiceInstance, + playlistServiceInstance, + artistServiceInstance, + defaultDb, + bbplayerApiInstance, ) diff --git a/apps/mobile/src/lib/facades/sharedPlaylist.ts b/apps/mobile/src/lib/facades/sharedPlaylist.ts index 087ac5f6..39f0b57d 100644 --- a/apps/mobile/src/lib/facades/sharedPlaylist.ts +++ b/apps/mobile/src/lib/facades/sharedPlaylist.ts @@ -17,19 +17,19 @@ import { clearSharedPlaylistMembers, } from '@/hooks/stores/useSharedPlaylistMembersStore' import { api as bbplayerApiClient } from '@/lib/api/bbplayer/client' -import db from '@/lib/db/db' +import defaultDb from '@/lib/db/db' import * as schema from '@/lib/db/schema' import { FacadeError, createFacadeError } from '@/lib/errors/facade' import { createValidationError } from '@/lib/errors/service' -import { artistService, type ArtistService } from '@/lib/services/artistService' +import { artistService as artistServiceInstance, type ArtistService } from '@/lib/services/artistService' import { - playlistService, + playlistService as playlistServiceInstance, type PlaylistService, } from '@/lib/services/playlistService' -import { trackService, type TrackService } from '@/lib/services/trackService' +import { trackService as trackServiceInstance, type TrackService } from '@/lib/services/trackService' import log from '@/utils/log' -type Tx = Parameters[0]>[0] +type Tx = Parameters[0]>[0] const logger = log.extend('SharedPlaylistFacade') @@ -781,13 +781,13 @@ export class SharedPlaylistFacade { artistService: ArtistService }, ): Promise { - const { playlistService, trackService, artistService } = services + const { playlistService: plSvc, trackService: trkSvc, artistService: artSvc } = services let applied = 0 // ---- 应用元数据更新 ---- if (data.metadata) { const metaUpdate: Parameters< - typeof playlistService.updatePlaylistMetadata + typeof plSvc.updatePlaylistMetadata >[1] = {} if (data.metadata.title != null) metaUpdate.title = data.metadata.title if (data.metadata.description !== undefined) @@ -795,7 +795,7 @@ export class SharedPlaylistFacade { if (data.metadata.cover_url !== undefined) metaUpdate.coverUrl = data.metadata.cover_url if (Object.keys(metaUpdate).length > 0) { - const metaResult = await playlistService.updatePlaylistMetadata( + const metaResult = await plSvc.updatePlaylistMetadata( localPlaylistId, metaUpdate, ) @@ -851,7 +851,7 @@ export class SharedPlaylistFacade { })) if (artistsToCreate.length > 0) { const artistResult = - await artistService.findOrCreateManyRemoteArtists(artistsToCreate) + await artSvc.findOrCreateManyRemoteArtists(artistsToCreate) if (artistResult.isOk()) { for (const [remoteId, artist] of artistResult.value.entries()) { artistMap.set(remoteId, artist.id) @@ -884,7 +884,7 @@ export class SharedPlaylistFacade { } }) - const trackIdsResult = await trackService.findOrCreateManyTracks( + const trackIdsResult = await trkSvc.findOrCreateManyTracks( trackPayloads, 'bilibili', ) @@ -925,7 +925,7 @@ export class SharedPlaylistFacade { if (deleteChanges.length > 0) { const uniqueKeys = deleteChanges.map((c) => c.track_unique_key) const trackIdsResult = - await trackService.findTrackIdsByUniqueKeys(uniqueKeys) + await trkSvc.findTrackIdsByUniqueKeys(uniqueKeys) if (trackIdsResult.isErr()) { throw trackIdsResult.error } @@ -960,9 +960,9 @@ export class SharedPlaylistFacade { } export const sharedPlaylistFacade = new SharedPlaylistFacade( - db, - playlistService, - trackService, - artistService, + defaultDb, + playlistServiceInstance, + trackServiceInstance, + artistServiceInstance, bbplayerApiClient, ) diff --git a/apps/mobile/src/lib/facades/syncBilibiliPlaylist.ts b/apps/mobile/src/lib/facades/syncBilibiliPlaylist.ts index 7a0d389a..8a7c1532 100644 --- a/apps/mobile/src/lib/facades/syncBilibiliPlaylist.ts +++ b/apps/mobile/src/lib/facades/syncBilibiliPlaylist.ts @@ -2,9 +2,9 @@ import type { ExpoSQLiteDatabase } from 'drizzle-orm/expo-sqlite' import { err, errAsync, ok, okAsync, Result, ResultAsync } from 'neverthrow' import type { bilibiliApi as BilibiliApiService } from '@/lib/api/bilibili/api' -import { bilibiliApi } from '@/lib/api/bilibili/api' +import { bilibiliApi as bilibiliApiInstance } from '@/lib/api/bilibili/api' import { av2bv, bv2av } from '@/lib/api/bilibili/utils' -import db from '@/lib/db/db' +import defaultDb from '@/lib/db/db' import type * as schema from '@/lib/db/schema' import type { DatabaseError, ServiceError } from '@/lib/errors' import type { FacadeError } from '@/lib/errors/facade' @@ -16,12 +16,12 @@ import { createValidationError } from '@/lib/errors/service' import type { BilibiliApiError } from '@/lib/errors/thirdparty/bilibili' import { analyticsService } from '@/lib/services/analyticsService' import type { ArtistService } from '@/lib/services/artistService' -import { artistService } from '@/lib/services/artistService' +import { artistService as artistServiceInstance } from '@/lib/services/artistService' import generateUniqueTrackKey from '@/lib/services/genKey' import type { PlaylistService } from '@/lib/services/playlistService' -import { playlistService } from '@/lib/services/playlistService' +import { playlistService as playlistServiceInstance } from '@/lib/services/playlistService' import type { TrackService } from '@/lib/services/trackService' -import { trackService } from '@/lib/services/trackService' +import { trackService as trackServiceInstance } from '@/lib/services/trackService' import type { BilibiliFavoriteListContent } from '@/types/apis/bilibili' import type { BilibiliMultipageVideo } from '@/types/apis/bilibili' import type { BilibiliTrack, Playlist, Track } from '@/types/core/media' @@ -844,7 +844,7 @@ export class SyncBilibiliPlaylistFacade { throw playlistAuthor.error } - const localPlaylist = await playlistSvc.findOrCreateRemotePlaylist({ + const playlistResult = await playlistSvc.findOrCreateRemotePlaylist({ title: bilibiliFavoriteListMetadata.info!.title, description: bilibiliFavoriteListMetadata.info!.intro, coverUrl: bilibiliFavoriteListMetadata.info!.cover, @@ -852,11 +852,11 @@ export class SyncBilibiliPlaylistFacade { remoteSyncId: favoriteId, authorId: playlistAuthor.value.id, }) - if (localPlaylist.isErr()) { - throw localPlaylist.error + if (playlistResult.isErr()) { + throw playlistResult.error } logger.debug('step 5: 创建 playlist 和其对应的 author 信息完成', { - localPlaylistId: localPlaylist.value.id, + localPlaylistId: playlistResult.value.id, artistId: playlistAuthor.value.id, }) @@ -1089,9 +1089,9 @@ export class SyncBilibiliPlaylistFacade { } export const syncFacade = new SyncBilibiliPlaylistFacade( - trackService, - bilibiliApi, - playlistService, - artistService, - db, + trackServiceInstance, + bilibiliApiInstance, + playlistServiceInstance, + artistServiceInstance, + defaultDb, ) diff --git a/apps/mobile/src/lib/facades/syncExternalPlaylist.ts b/apps/mobile/src/lib/facades/syncExternalPlaylist.ts index 5d8f37f7..5afb293b 100644 --- a/apps/mobile/src/lib/facades/syncExternalPlaylist.ts +++ b/apps/mobile/src/lib/facades/syncExternalPlaylist.ts @@ -1,20 +1,20 @@ import type { ExpoSQLiteDatabase } from 'drizzle-orm/expo-sqlite' import { ResultAsync } from 'neverthrow' -import db from '@/lib/db/db' +import defaultDb from '@/lib/db/db' import type * as schema from '@/lib/db/schema' import type { DatabaseError, ServiceError } from '@/lib/errors' import type { FacadeError } from '@/lib/errors/facade' import { createFacadeError } from '@/lib/errors/facade' import { analyticsService } from '@/lib/services/analyticsService' import type { ArtistService } from '@/lib/services/artistService' -import { artistService } from '@/lib/services/artistService' +import { artistService as artistServiceInstance } from '@/lib/services/artistService' import type { MatchResult } from '@/lib/services/externalPlaylistService' import generateUniqueTrackKey from '@/lib/services/genKey' import type { PlaylistService } from '@/lib/services/playlistService' -import { playlistService } from '@/lib/services/playlistService' +import { playlistService as playlistServiceInstance } from '@/lib/services/playlistService' import type { TrackService } from '@/lib/services/trackService' -import { trackService } from '@/lib/services/trackService' +import { trackService as trackServiceInstance } from '@/lib/services/trackService' import log from '@/utils/log' import { parseDurationString } from '@/utils/time' @@ -162,8 +162,8 @@ export class SyncExternalPlaylistFacade { } export const syncExternalPlaylistFacade = new SyncExternalPlaylistFacade( - trackService, - playlistService, - artistService, - db, + trackServiceInstance, + playlistServiceInstance, + artistServiceInstance, + defaultDb, ) diff --git a/apps/mobile/src/lib/player/PlayerSideEffects.ts b/apps/mobile/src/lib/player/PlayerSideEffects.ts index f8fb43d5..9d476b73 100644 --- a/apps/mobile/src/lib/player/PlayerSideEffects.ts +++ b/apps/mobile/src/lib/player/PlayerSideEffects.ts @@ -75,25 +75,25 @@ class PlayerSideEffects { ('rootCauseMessage' in event ? event.rootCauseMessage : null) || ('message' in event ? event.message : null) || '' - const code = 'errorCode' in event ? event.errorCode : null + const errorCode = 'errorCode' in event ? event.errorCode : null if (rawMessage.includes('Bilibili API Error')) { const codeMatch = rawMessage.match(/code=(-?\d+)/) const msgMatch = rawMessage.match(/msg=(.+)/) - const code = codeMatch ? codeMatch[1] : 'Unknown' + const biliCode = codeMatch ? codeMatch[1] : 'Unknown' const msg = msgMatch ? msgMatch[1] : 'Unknown Error' - if (code === '-412') { + if (biliCode === '-412') { return { message: 'Bilibili 触发验证码,请尝试重新登录或稍后再试', shouldReport: false, } } - if (code === '-101') { + if (biliCode === '-101') { return { message: 'Bilibili 账号未登录', shouldReport: false } } return { - message: `Bilibili API 错误: ${msg} (${code})`, + message: `Bilibili API 错误: ${msg} (${biliCode})`, shouldReport: false, } } @@ -137,9 +137,9 @@ class PlayerSideEffects { // 2000-2999 是关于 IO 或 NETWORK 的问题。 if ( isActuallyOffline(networkState) && - code && - code >= 2000 && - code < 3000 + errorCode && + errorCode >= 2000 && + errorCode < 3000 ) { return { message: '当前歌曲未缓存,离线状态下无法播放(或存在其他IO/网络问题)', diff --git a/apps/mobile/src/lib/services/artistService.ts b/apps/mobile/src/lib/services/artistService.ts index 0901dbf7..11f1fed3 100644 --- a/apps/mobile/src/lib/services/artistService.ts +++ b/apps/mobile/src/lib/services/artistService.ts @@ -3,7 +3,7 @@ import { and, eq, or } from 'drizzle-orm' import { type ExpoSQLiteDatabase } from 'drizzle-orm/expo-sqlite' import { ResultAsync, errAsync, okAsync } from 'neverthrow' -import db from '@/lib/db/db' +import defaultDb from '@/lib/db/db' import * as schema from '@/lib/db/schema' import { ServiceError } from '@/lib/errors' import { @@ -18,9 +18,9 @@ import type { } from '@/types/services/artist' import type { TrackService } from './trackService' -import { trackService } from './trackService' +import { trackService as trackServiceInstance } from './trackService' -type Tx = Parameters[0]>[0] +type Tx = Parameters[0]>[0] type DBLike = ExpoSQLiteDatabase | Tx export class ArtistService { @@ -400,4 +400,4 @@ export class ArtistService { } } -export const artistService = new ArtistService(db, trackService) +export const artistService = new ArtistService(defaultDb, trackServiceInstance) diff --git a/apps/mobile/src/lib/services/lyricService.ts b/apps/mobile/src/lib/services/lyricService.ts index ef688143..c110be1c 100644 --- a/apps/mobile/src/lib/services/lyricService.ts +++ b/apps/mobile/src/lib/services/lyricService.ts @@ -7,9 +7,9 @@ import { errAsync, okAsync, Result, ResultAsync } from 'neverthrow' import { useAppStore } from '@/hooks/stores/useAppStore' import { bilibiliApi } from '@/lib/api/bilibili/api' -import { kugouApi, type KugouApi } from '@/lib/api/kugou/api' -import { neteaseApi, type NeteaseApi } from '@/lib/api/netease/api' -import { qqMusicApi, type QQMusicApi } from '@/lib/api/qqmusic/api' +import { kugouApi as kugouApiInstance, type KugouApi } from '@/lib/api/kugou/api' +import { neteaseApi as neteaseApiInstance, type NeteaseApi } from '@/lib/api/netease/api' +import { qqMusicApi as qqMusicApiInstance, type QQMusicApi } from '@/lib/api/qqmusic/api' import type { CustomError } from '@/lib/errors' import { FileSystemError, LyricNotFoundError } from '@/lib/errors' import { trackService } from '@/lib/services/trackService' @@ -652,5 +652,5 @@ class LyricService { } } -const lyricService = new LyricService(neteaseApi, qqMusicApi, kugouApi) +const lyricService = new LyricService(neteaseApiInstance, qqMusicApiInstance, kugouApiInstance) export default lyricService diff --git a/apps/mobile/src/lib/services/playlistService.ts b/apps/mobile/src/lib/services/playlistService.ts index a6043ba4..bc011bb2 100644 --- a/apps/mobile/src/lib/services/playlistService.ts +++ b/apps/mobile/src/lib/services/playlistService.ts @@ -5,7 +5,7 @@ import { type ExpoSQLiteDatabase } from 'drizzle-orm/expo-sqlite' import { generateKeyBetween } from 'fractional-indexing' import { ResultAsync, errAsync, okAsync } from 'neverthrow' -import db from '@/lib/db/db' +import defaultDb from '@/lib/db/db' import * as schema from '@/lib/db/schema' import { ServiceError } from '@/lib/errors' import { @@ -22,9 +22,9 @@ import type { } from '@/types/services/playlist' import type { TrackService } from './trackService' -import { trackService } from './trackService' +import { trackService as trackServiceInstance } from './trackService' -type Tx = Parameters[0]>[0] +type Tx = Parameters[0]>[0] type DBLike = ExpoSQLiteDatabase | Tx type PlaylistTrackRow = typeof schema.playlistTracks.$inferSelect & { track: typeof schema.tracks.$inferSelect & { @@ -1272,7 +1272,7 @@ export class PlaylistService { return tracks } - const trackIdSubq = db + const trackIdSubq = defaultDb .select({ id: schema.tracks.id }) .from(schema.tracks) .leftJoin( @@ -1284,7 +1284,7 @@ export class PlaylistService { const rows = await Sentry.startSpan( { name: 'db:query:playlistTracks', op: 'db' }, () => - db.query.playlistTracks.findMany({ + defaultDb.query.playlistTracks.findMany({ where: and( eq(schema.playlistTracks.playlistId, playlistId), inArray(schema.playlistTracks.trackId, trackIdSubq), @@ -1515,4 +1515,4 @@ export class PlaylistService { } } -export const playlistService = new PlaylistService(db, trackService) +export const playlistService = new PlaylistService(defaultDb, trackServiceInstance) diff --git a/apps/mobile/src/lib/services/trackService.ts b/apps/mobile/src/lib/services/trackService.ts index 07a0ed3b..bda2cb90 100644 --- a/apps/mobile/src/lib/services/trackService.ts +++ b/apps/mobile/src/lib/services/trackService.ts @@ -4,7 +4,7 @@ import { and, count, desc, eq, inArray, lt, or, sql, sum } from 'drizzle-orm' import { type ExpoSQLiteDatabase } from 'drizzle-orm/expo-sqlite' import { Result, ResultAsync, err, errAsync, okAsync } from 'neverthrow' -import db from '@/lib/db/db' +import defaultDb from '@/lib/db/db' import * as schema from '@/lib/db/schema' import { ServiceError } from '@/lib/errors' import { @@ -32,7 +32,7 @@ import log from '@/utils/log' import generateUniqueTrackKey from './genKey' const logger = log.extend('Service.Track') -type Tx = Parameters[0]>[0] +type Tx = Parameters[0]>[0] type DBLike = ExpoSQLiteDatabase | Tx type SelectTrackBase = typeof schema.tracks.$inferSelect type SelectTrackWithMetadata = SelectTrackBase & { @@ -360,7 +360,7 @@ export class TrackService { return ResultAsync.fromPromise( Sentry.startSpan({ name: 'db:query:track', op: 'db' }, () => this.db.query.tracks.findFirst({ - where: (track, { eq }) => eq(track.uniqueKey, identifier.value), + where: (track, { eq: eqFn }) => eqFn(track.uniqueKey, identifier.value), with: { artist: true, bilibiliMetadata: true, @@ -410,7 +410,7 @@ export class TrackService { return ResultAsync.fromPromise( Sentry.startSpan({ name: 'db:query:track', op: 'db' }, () => this.db.query.tracks.findFirst({ - where: (track, { eq }) => eq(track.uniqueKey, uniqueKey), + where: (track, { eq: eqFn }) => eqFn(track.uniqueKey, uniqueKey), with: { artist: true, bilibiliMetadata: true, @@ -950,4 +950,4 @@ export class TrackService { } } -export const trackService = new TrackService(db) +export const trackService = new TrackService(defaultDb) diff --git a/packages/react-native-bottom-tabs/src/TabView.tsx b/packages/react-native-bottom-tabs/src/TabView.tsx index 249b2047..98fd834f 100644 --- a/packages/react-native-bottom-tabs/src/TabView.tsx +++ b/packages/react-native-bottom-tabs/src/TabView.tsx @@ -291,7 +291,7 @@ const TabView = ({ if (!loaded.includes(focusedKey)) { // Set the current tab to be loaded if it was not loaded before - setLoaded((loaded) => [...loaded, focusedKey]) + setLoaded((prev) => [...prev, focusedKey]) } const icons = React.useMemo( From f1a758a9fdb6c1a1ad0cd7213ab9cbdd3bb7d1d2 Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:35:06 +0800 Subject: [PATCH 5/8] mobile: 1 --- .oxlintrc.json | 2 ++ .../app/playlist/remote/multipage/[bvid].tsx | 2 +- .../components/modals/app/UpdateAppModal.tsx | 4 +-- .../bilibili/AddVideoToBilibiliFavModal.tsx | 6 ++-- .../editPlaylistMetadataModal.tsx | 7 +++-- .../edit-metadata/editTrackMetadataModal.tsx | 4 +-- .../modals/login/CookieLoginModal.tsx | 4 +-- .../BatchAddTracksToLocalPlaylist.tsx | 6 ++-- .../modals/playlist/CreatePlaylistModal.tsx | 4 +-- .../playlist/FavoriteSyncProgressModal.tsx | 6 ++-- .../UpdateTrackLocalPlaylistsModal.tsx | 6 ++-- .../src/features/home/SearchSuggestions.tsx | 6 ++-- .../player/components/PlayerSlider.tsx | 1 + apps/mobile/src/hooks/queries/lyrics/index.ts | 3 +- apps/mobile/src/lib/api/netease/crypto.ts | 4 +-- apps/mobile/src/lib/facades/sharedPlaylist.ts | 31 ++++++++++++------- apps/mobile/src/lib/services/trackService.ts | 7 +++-- apps/mobile/src/utils/log.ts | 14 ++++----- eslint.config.mjs | 8 ++++- .../src/hooks/useObservableStateAdapter.ts | 5 +-- .../expo-wavy-slider/src/utils/getStateId.ts | 7 +++-- packages/expo-wavy-slider/src/worklets.fx.ts | 1 + .../react-native-bottom-tabs/src/TabView.tsx | 24 +++++++------- 23 files changed, 94 insertions(+), 68 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index 13a58f48..bd23bf17 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -34,6 +34,7 @@ "**/*.config.mjs", "**/*.js", "packages/logs/**", + "**/worker-configuration.d.ts", "**/package-lock.json", "**/pnpm-lock.yaml" ], @@ -58,6 +59,7 @@ "typescript/no-unsafe-type-assertion": "allow", "typescript/consistent-return": "off", "no-underscore-dangle": ["error", { "allow": ["__csrf"] }], + "react/no-unstable-nested-components": "off", // tanstack query "@tanstack/query/exhaustive-deps": "error", diff --git a/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx b/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx index ef7b54b0..76c8086b 100644 --- a/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx +++ b/apps/mobile/src/app/playlist/remote/multipage/[bvid].tsx @@ -214,7 +214,7 @@ export default function MultipagePage() { /> ) }, - [cid], + [cid, selection], ) useEffect(() => { diff --git a/apps/mobile/src/components/modals/app/UpdateAppModal.tsx b/apps/mobile/src/components/modals/app/UpdateAppModal.tsx index 0f652be6..476f15aa 100644 --- a/apps/mobile/src/components/modals/app/UpdateAppModal.tsx +++ b/apps/mobile/src/components/modals/app/UpdateAppModal.tsx @@ -34,8 +34,8 @@ export default function UpdateAppModal({ forced = false, }: UpdateModalProps) { const colors = useTheme().colors - const _close = useModalStore((state) => state.close) - const close = useCallback(() => _close('UpdateApp'), [_close]) + const modalClose = useModalStore((state) => state.close) + const close = useCallback(() => modalClose('UpdateApp'), [modalClose]) const [isUpdating, setIsUpdating] = useState(false) const onUpdate = async () => { diff --git a/apps/mobile/src/components/modals/bilibili/AddVideoToBilibiliFavModal.tsx b/apps/mobile/src/components/modals/bilibili/AddVideoToBilibiliFavModal.tsx index 17252a5c..089e73e2 100644 --- a/apps/mobile/src/components/modals/bilibili/AddVideoToBilibiliFavModal.tsx +++ b/apps/mobile/src/components/modals/bilibili/AddVideoToBilibiliFavModal.tsx @@ -55,10 +55,10 @@ const AddToFavoriteListsModal = memo(function AddToFavoriteListsModal({ const queryClient = useQueryClient() const { data: personalInfo } = usePersonalInformation() const enable = useAppStore((state) => state.hasBilibiliCookie()) - const _close = useModalStore((state) => state.close) + const modalClose = useModalStore((state) => state.close) const close = useCallback( - () => _close('AddVideoToBilibiliFavorite'), - [_close], + () => modalClose('AddVideoToBilibiliFavorite'), + [modalClose], ) const { diff --git a/apps/mobile/src/components/modals/edit-metadata/editPlaylistMetadataModal.tsx b/apps/mobile/src/components/modals/edit-metadata/editPlaylistMetadataModal.tsx index be8837a0..ab1b319d 100644 --- a/apps/mobile/src/components/modals/edit-metadata/editPlaylistMetadataModal.tsx +++ b/apps/mobile/src/components/modals/edit-metadata/editPlaylistMetadataModal.tsx @@ -25,8 +25,11 @@ export default function EditPlaylistMetadataModal({ const [title, setTitle] = useState(playlist.title) const [description, setDescription] = useState(playlist.description) const [coverUrl, setCoverUrl] = useState(playlist.coverUrl) - const _close = useModalStore((state) => state.close) - const close = useCallback(() => _close('EditPlaylistMetadata'), [_close]) + const modalClose = useModalStore((state) => state.close) + const close = useCallback( + () => modalClose('EditPlaylistMetadata'), + [modalClose], + ) const fetchRemoteMetadata = useCallback(async () => { if (!playlist.remoteSyncId) { diff --git a/apps/mobile/src/components/modals/edit-metadata/editTrackMetadataModal.tsx b/apps/mobile/src/components/modals/edit-metadata/editTrackMetadataModal.tsx index 47f6df86..53da5dc3 100644 --- a/apps/mobile/src/components/modals/edit-metadata/editTrackMetadataModal.tsx +++ b/apps/mobile/src/components/modals/edit-metadata/editTrackMetadataModal.tsx @@ -17,8 +17,8 @@ const sanitizeFileName = (name: string) => export default function EditTrackMetadataModal({ track }: { track: Track }) { const [title, setTitle] = useState(track.title) const [coverUrl, setCoverUrl] = useState(track.coverUrl) - const _close = useModalStore((state) => state.close) - const close = useCallback(() => _close('EditTrackMetadata'), [_close]) + const modalClose = useModalStore((state) => state.close) + const close = useCallback(() => modalClose('EditTrackMetadata'), [modalClose]) const { mutate: editTrackMetadata } = useEditTrackMetadata() diff --git a/apps/mobile/src/components/modals/login/CookieLoginModal.tsx b/apps/mobile/src/components/modals/login/CookieLoginModal.tsx index fbb87d48..6361752d 100644 --- a/apps/mobile/src/components/modals/login/CookieLoginModal.tsx +++ b/apps/mobile/src/components/modals/login/CookieLoginModal.tsx @@ -16,8 +16,8 @@ export default function CookieLoginModal() { const cookieObjectFromStore = useAppStore((state) => state.bilibiliCookie) const setBilibiliCookie = useAppStore((state) => state.setBilibiliCookie) const clearBilibiliCookie = useAppStore((state) => state.clearBilibiliCookie) - const _close = useModalStore((state) => state.close) - const close = useCallback(() => _close('CookieLogin'), [_close]) + const modalClose = useModalStore((state) => state.close) + const close = useCallback(() => modalClose('CookieLogin'), [modalClose]) const displayCookieString = useMemo(() => { if (!cookieObjectFromStore) return '' diff --git a/apps/mobile/src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx b/apps/mobile/src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx index e1a04bec..0aced3d3 100644 --- a/apps/mobile/src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx +++ b/apps/mobile/src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx @@ -43,10 +43,10 @@ const BatchAddTracksToLocalPlaylistModal = memo( payloads: { track: CreateTrackPayload; artist: CreateArtistPayload }[] }) { const { colors } = useTheme() - const _close = useModalStore((state) => state.close) + const modalClose = useModalStore((state) => state.close) const close = useCallback( - () => _close('BatchAddTracksToLocalPlaylist'), - [_close], + () => modalClose('BatchAddTracksToLocalPlaylist'), + [modalClose], ) const openModal = useModalStore((state) => state.open) diff --git a/apps/mobile/src/components/modals/playlist/CreatePlaylistModal.tsx b/apps/mobile/src/components/modals/playlist/CreatePlaylistModal.tsx index 3874c6b2..b04f2414 100644 --- a/apps/mobile/src/components/modals/playlist/CreatePlaylistModal.tsx +++ b/apps/mobile/src/components/modals/playlist/CreatePlaylistModal.tsx @@ -20,9 +20,9 @@ export default function CreatePlaylistModal({ const [title, setTitle] = useState('') const [description, setDescription] = useState('') const [coverUrl, setCoverUrl] = useState('') - const _close = useModalStore((state) => state.close) + const modalClose = useModalStore((state) => state.close) const closeAll = useModalStore((state) => state.closeAll) - const close = useCallback(() => _close('CreatePlaylist'), [_close]) + const close = useCallback(() => modalClose('CreatePlaylist'), [modalClose]) const router = useRouter() const handleConfirm = useCallback(() => { diff --git a/apps/mobile/src/components/modals/playlist/FavoriteSyncProgressModal.tsx b/apps/mobile/src/components/modals/playlist/FavoriteSyncProgressModal.tsx index 953c7b66..cc93a7c6 100644 --- a/apps/mobile/src/components/modals/playlist/FavoriteSyncProgressModal.tsx +++ b/apps/mobile/src/components/modals/playlist/FavoriteSyncProgressModal.tsx @@ -18,19 +18,19 @@ const FavoriteSyncProgressModal = memo(function FavoriteSyncProgressModal({ shouldRedirectToLocalPlaylist?: boolean expandMultiPage?: boolean }) { - const _close = useModalStore((state) => state.close) + const modalClose = useModalStore((state) => state.close) const router = useRouter() const syncedPlaylistId = useRef(undefined) const close = useCallback(() => { - _close('FavoriteSyncProgress') + modalClose('FavoriteSyncProgress') if (shouldRedirectToLocalPlaylist && syncedPlaylistId.current) { const targetId = syncedPlaylistId.current useModalStore.getState().doAfterModalHostClosed(() => { router.push(`/playlist/local/${targetId}`) }) } - }, [_close, shouldRedirectToLocalPlaylist, router]) + }, [modalClose, shouldRedirectToLocalPlaylist, router]) const [progress, setProgress] = useState(null) const { mutate: syncFavorite, isPending } = usePlaylistSync() diff --git a/apps/mobile/src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx b/apps/mobile/src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx index 5fe579f8..3fee51b6 100644 --- a/apps/mobile/src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx +++ b/apps/mobile/src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx @@ -74,10 +74,10 @@ PlaylistListItem.displayName = 'PlaylistListItem' const UpdateTrackLocalPlaylistsModal = memo( function UpdateTrackLocalPlaylistsModal({ track }: { track: Track }) { const { colors } = useTheme() - const _close = useModalStore((state) => state.close) + const modalClose = useModalStore((state) => state.close) const close = useCallback( - () => _close('UpdateTrackLocalPlaylists'), - [_close], + () => modalClose('UpdateTrackLocalPlaylists'), + [modalClose], ) const open = useModalStore((state) => state.open) diff --git a/apps/mobile/src/features/home/SearchSuggestions.tsx b/apps/mobile/src/features/home/SearchSuggestions.tsx index 5a344726..f4c39979 100644 --- a/apps/mobile/src/features/home/SearchSuggestions.tsx +++ b/apps/mobile/src/features/home/SearchSuggestions.tsx @@ -94,7 +94,7 @@ export default function SearchSuggestions({ return ( items?.map((item) => ({ ...item, - _segments: parseEmTags(item.name), + segments: parseEmTags(item.name), })) ?? [] ) }, [items]) @@ -170,7 +170,7 @@ export default function SearchSuggestions({ index, }: { item: BilibiliSearchSuggestionItem & { - _segments?: { text: string; emphasized: boolean }[] + segments?: { text: string; emphasized: boolean }[] } index: number }) => { @@ -188,7 +188,7 @@ export default function SearchSuggestions({ numberOfLines={1} style={{ color: colors.onSurface }} > - {(item._segments ?? [{ text: item.value, emphasized: false }]).map( + {(item.segments ?? [{ text: item.value, emphasized: false }]).map( (seg, i) => ( { const dur = duration.value || 1 return Math.min(Math.max(buffered.value / dur, 0), 1) diff --git a/apps/mobile/src/hooks/queries/lyrics/index.ts b/apps/mobile/src/hooks/queries/lyrics/index.ts index fbe8b2eb..f75d0e6d 100644 --- a/apps/mobile/src/hooks/queries/lyrics/index.ts +++ b/apps/mobile/src/hooks/queries/lyrics/index.ts @@ -19,8 +19,7 @@ export const lyricsQueryKeys = { export const useSmartFetchLyrics = (enable: boolean, track?: Track) => { const enabled = !!track && enable return useQuery({ - // oxlint-disable-next-line @tanstack/query/exhaustive-deps - queryKey: lyricsQueryKeys.smartFetchLyrics(track?.uniqueKey), + queryKey: [...lyricsQueryKeys.smartFetchLyrics(track?.uniqueKey), track], queryFn: async () => { const result = await lyricService.smartFetchLyrics(track!) if (result.isErr()) { diff --git a/apps/mobile/src/lib/api/netease/crypto.ts b/apps/mobile/src/lib/api/netease/crypto.ts index 0409df30..843f056b 100644 --- a/apps/mobile/src/lib/api/netease/crypto.ts +++ b/apps/mobile/src/lib/api/netease/crypto.ts @@ -23,7 +23,7 @@ const aesEncrypt = ( CryptoJS.enc.Utf8.parse(text), CryptoJS.enc.Utf8.parse(key), { - iv: CryptoJS.enc.Utf8.parse(iv), + iv: CryptoJS.enc.Utf8.parse(aesIv), mode: CryptoJS.mode[mode.toUpperCase() as keyof typeof CryptoJS.mode], padding: CryptoJS.pad.Pkcs7, }, @@ -98,7 +98,7 @@ const aesDecrypt = ( { ciphertext: CryptoJS.enc.Hex.parse(ciphertext) }, CryptoJS.enc.Utf8.parse(key), { - iv: CryptoJS.enc.Utf8.parse(aesIv), + iv: CryptoJS.enc.Utf8.parse(aesIv), mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7, }, diff --git a/apps/mobile/src/lib/facades/sharedPlaylist.ts b/apps/mobile/src/lib/facades/sharedPlaylist.ts index 39f0b57d..bdc10120 100644 --- a/apps/mobile/src/lib/facades/sharedPlaylist.ts +++ b/apps/mobile/src/lib/facades/sharedPlaylist.ts @@ -21,12 +21,18 @@ import defaultDb from '@/lib/db/db' import * as schema from '@/lib/db/schema' import { FacadeError, createFacadeError } from '@/lib/errors/facade' import { createValidationError } from '@/lib/errors/service' -import { artistService as artistServiceInstance, type ArtistService } from '@/lib/services/artistService' +import { + artistService as artistServiceInstance, + type ArtistService, +} from '@/lib/services/artistService' import { playlistService as playlistServiceInstance, type PlaylistService, } from '@/lib/services/playlistService' -import { trackService as trackServiceInstance, type TrackService } from '@/lib/services/trackService' +import { + trackService as trackServiceInstance, + type TrackService, +} from '@/lib/services/trackService' import log from '@/utils/log' type Tx = Parameters[0]>[0] @@ -284,7 +290,7 @@ export class SharedPlaylistFacade { if (createResult.isErr()) throw createResult.error const id = createResult.value.id - await this._applyPullResponse(id, shareId, changesData, tx, { + await this.applyPullResponse(id, shareId, changesData, tx, { playlistService: txPlaylist, trackService: txTrack, artistService: txArtist, @@ -467,7 +473,7 @@ export class SharedPlaylistFacade { if (createResult.isErr()) throw createResult.error const localId = createResult.value.id - await this._applyPullResponse( + await this.applyPullResponse( localId, remote.id, changesData, @@ -565,7 +571,7 @@ export class SharedPlaylistFacade { const txTrack = this.trackService.withDB(tx) const txArtist = this.artistService.withDB(tx) - const n = await this._applyPullResponse( + const n = await this.applyPullResponse( localPlaylistId, playlist.shareId!, data, @@ -735,7 +741,7 @@ export class SharedPlaylistFacade { ) } - private async _applyPullResponse( + private async applyPullResponse( localPlaylistId: number, shareId: string, data: { @@ -781,14 +787,16 @@ export class SharedPlaylistFacade { artistService: ArtistService }, ): Promise { - const { playlistService: plSvc, trackService: trkSvc, artistService: artSvc } = services + const { + playlistService: plSvc, + trackService: trkSvc, + artistService: artSvc, + } = services let applied = 0 // ---- 应用元数据更新 ---- if (data.metadata) { - const metaUpdate: Parameters< - typeof plSvc.updatePlaylistMetadata - >[1] = {} + const metaUpdate: Parameters[1] = {} if (data.metadata.title != null) metaUpdate.title = data.metadata.title if (data.metadata.description !== undefined) metaUpdate.description = data.metadata.description @@ -924,8 +932,7 @@ export class SharedPlaylistFacade { // ---- 应用 delete 变更 ---- if (deleteChanges.length > 0) { const uniqueKeys = deleteChanges.map((c) => c.track_unique_key) - const trackIdsResult = - await trkSvc.findTrackIdsByUniqueKeys(uniqueKeys) + const trackIdsResult = await trkSvc.findTrackIdsByUniqueKeys(uniqueKeys) if (trackIdsResult.isErr()) { throw trackIdsResult.error } diff --git a/apps/mobile/src/lib/services/trackService.ts b/apps/mobile/src/lib/services/trackService.ts index bda2cb90..692d7948 100644 --- a/apps/mobile/src/lib/services/trackService.ts +++ b/apps/mobile/src/lib/services/trackService.ts @@ -100,7 +100,7 @@ export class TrackService { * @param payload - 创建 track 所需的数据。 * @returns ResultAsync 包含成功创建的 Track 或一个错误。 */ - private _createTrack( + private createTrack( payload: CreateTrackPayload, ): ResultAsync { // validate @@ -360,7 +360,8 @@ export class TrackService { return ResultAsync.fromPromise( Sentry.startSpan({ name: 'db:query:track', op: 'db' }, () => this.db.query.tracks.findFirst({ - where: (track, { eq: eqFn }) => eqFn(track.uniqueKey, identifier.value), + where: (track, { eq: eqFn }) => + eqFn(track.uniqueKey, identifier.value), with: { artist: true, bilibiliMetadata: true, @@ -441,7 +442,7 @@ export class TrackService { }) .orElse((error) => { if (error instanceof ServiceError && error.type === 'TrackNotFound') { - return this._createTrack(payload) + return this.createTrack(payload) } return errAsync(error) }) diff --git a/apps/mobile/src/utils/log.ts b/apps/mobile/src/utils/log.ts index 96510efd..d587785e 100644 --- a/apps/mobile/src/utils/log.ts +++ b/apps/mobile/src/utils/log.ts @@ -149,28 +149,28 @@ export function reportErrorToSentry( message?: string, scope?: ProjectScope | string, ) { - const _error = + const normalizedError = error instanceof Error ? error : new Error(`非 Error 类型错误:${stringifyError(error)}`, { cause: error, }) - const isCustom = _error instanceof CustomError + const isCustom = normalizedError instanceof CustomError const tags: Record = { appScope: scope, } - if (isCustom && typeof _error.type === 'string') { - tags.errorType = _error.type + if (isCustom && typeof normalizedError.type === 'string') { + tags.errorType = normalizedError.type } const extra: Record = { message } - if (isCustom && _error.data !== undefined) { - extra.errorData = _error.data + if (isCustom && normalizedError.data !== undefined) { + extra.errorData = normalizedError.data } - const id = Sentry.captureException(_error, { tags, extra }) + const id = Sentry.captureException(normalizedError, { tags, extra }) log.error(`已上报错误到 sentry,id: ${id}`) } diff --git a/eslint.config.mjs b/eslint.config.mjs index 95d3d75e..b6a24685 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -5,7 +5,13 @@ import tseslint from 'typescript-eslint' export default defineConfig([ { - ignores: ['dist/*', '**/dm.d.ts', '**/dm.js', '**/router.d.ts'], + ignores: [ + 'dist/*', + '**/dm.d.ts', + '**/dm.js', + '**/router.d.ts', + '**/worker-configuration.d.ts', + ], }, { files: ['**/*.{ts,tsx,mts,cts}'], diff --git a/packages/expo-wavy-slider/src/hooks/useObservableStateAdapter.ts b/packages/expo-wavy-slider/src/hooks/useObservableStateAdapter.ts index d0a56adb..a30c49ac 100644 --- a/packages/expo-wavy-slider/src/hooks/useObservableStateAdapter.ts +++ b/packages/expo-wavy-slider/src/hooks/useObservableStateAdapter.ts @@ -29,8 +29,8 @@ export default function useObservableStateAdapter( const isActive = useSharedValue(false) useEffect(() => { - if (!value || isObservableState(value)) return - if (sharedValueAdapterId == null) return + if (!value || isObservableState(value)) return undefined + if (sharedValueAdapterId == null) return undefined isActive.set(true) @@ -76,6 +76,7 @@ function resolveObservableStateInWorklet( const sharedObject = expo?.SharedObject try { + // oxlint-disable-next-line no-underscore-dangle return sharedObject?.__resolveInWorklet?.(stateId) } catch { return undefined diff --git a/packages/expo-wavy-slider/src/utils/getStateId.ts b/packages/expo-wavy-slider/src/utils/getStateId.ts index 9065ee23..1167215d 100644 --- a/packages/expo-wavy-slider/src/utils/getStateId.ts +++ b/packages/expo-wavy-slider/src/utils/getStateId.ts @@ -6,6 +6,9 @@ export default function getStateId(state?: object | null): number | undefined { if (!state) { return undefined } - return (state as { __expo_shared_object_id__?: number }) - .__expo_shared_object_id__ + return ( + (state as { __expo_shared_object_id__?: number }) + // oxlint-disable-next-line no-underscore-dangle + .__expo_shared_object_id__ + ) } diff --git a/packages/expo-wavy-slider/src/worklets.fx.ts b/packages/expo-wavy-slider/src/worklets.fx.ts index c8e33631..e865b1f5 100644 --- a/packages/expo-wavy-slider/src/worklets.fx.ts +++ b/packages/expo-wavy-slider/src/worklets.fx.ts @@ -46,6 +46,7 @@ function registerSharedObjectSerializer(): void { } } ).expo.SharedObject + // oxlint-disable-next-line no-underscore-dangle const obj = sharedObject.__resolveInWorklet(packed.objectId) if ( diff --git a/packages/react-native-bottom-tabs/src/TabView.tsx b/packages/react-native-bottom-tabs/src/TabView.tsx index 98fd834f..0b738bc0 100644 --- a/packages/react-native-bottom-tabs/src/TabView.tsx +++ b/packages/react-native-bottom-tabs/src/TabView.tsx @@ -234,28 +234,30 @@ const TabView = ({ rippleColor, tabBarActiveTintColor: activeTintColor, tabBarInactiveTintColor: inactiveTintColor, - getBadge = ({ route }: { route: Route }) => route.badge, + getBadge = ({ route }: { route: Route }) => route.badge, // oxlint-disable-line react/no-object-type-as-default-prop + // oxlint-disable-next-line react/no-object-type-as-default-prop getBadgeBackgroundColor = ({ route }: { route: Route }) => route.badgeBackgroundColor, - getBadgeTextColor = ({ route }: { route: Route }) => route.badgeTextColor, - getLazy = ({ route }: { route: Route }) => route.lazy, - getLabelText = ({ route }: { route: Route }) => route.title, + getBadgeTextColor = ({ route }: { route: Route }) => route.badgeTextColor, // oxlint-disable-line react/no-object-type-as-default-prop + getLazy = ({ route }: { route: Route }) => route.lazy, // oxlint-disable-line react/no-object-type-as-default-prop + getLabelText = ({ route }: { route: Route }) => route.title, // oxlint-disable-line react/no-object-type-as-default-prop + // oxlint-disable-next-line react/no-object-type-as-default-prop getIcon = ({ route, focused }: { route: Route; focused: boolean }) => route.unfocusedIcon ? focused ? route.focusedIcon : route.unfocusedIcon : route.focusedIcon, - getHidden = ({ route }: { route: Route }) => route.hidden, - getActiveTintColor = ({ route }: { route: Route }) => route.activeTintColor, - getTestID = ({ route }: { route: Route }) => route.testID, - getRole = ({ route }: { route: Route }) => route.role, - getSceneStyle = ({ route }: { route: Route }) => route.style, - getPreventsDefault = ({ route }: { route: Route }) => route.preventsDefault, + getHidden = ({ route }: { route: Route }) => route.hidden, // oxlint-disable-line react/no-object-type-as-default-prop + getActiveTintColor = ({ route }: { route: Route }) => route.activeTintColor, // oxlint-disable-line react/no-object-type-as-default-prop + getTestID = ({ route }: { route: Route }) => route.testID, // oxlint-disable-line react/no-object-type-as-default-prop + getRole = ({ route }: { route: Route }) => route.role, // oxlint-disable-line react/no-object-type-as-default-prop + getSceneStyle = ({ route }: { route: Route }) => route.style, // oxlint-disable-line react/no-object-type-as-default-prop + getPreventsDefault = ({ route }: { route: Route }) => route.preventsDefault, // oxlint-disable-line react/no-object-type-as-default-prop hapticFeedbackEnabled = false, // Android's native behavior is to show labels when there are less than 4 tabs. We leave it as undefined to use the platform default behavior. labeled = Platform.OS !== 'android' ? true : undefined, - getFreezeOnBlur = ({ route }: { route: Route }) => route.freezeOnBlur, + getFreezeOnBlur = ({ route }: { route: Route }) => route.freezeOnBlur, // oxlint-disable-line react/no-object-type-as-default-prop tabBar: renderCustomTabBar, tabBarStyle, tabLabelStyle, From 96103f9ceae9ff3aca2e661463883a3e012bb7be Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:38:14 +0800 Subject: [PATCH 6/8] mobile: 1 --- .oxlintrc.json => oxlint.config.mts | 102 +++++++++++++--------------- 1 file changed, 47 insertions(+), 55 deletions(-) rename .oxlintrc.json => oxlint.config.mts (67%) diff --git a/.oxlintrc.json b/oxlint.config.mts similarity index 67% rename from .oxlintrc.json rename to oxlint.config.mts index bd23bf17..8a95fcaf 100644 --- a/.oxlintrc.json +++ b/oxlint.config.mts @@ -1,29 +1,22 @@ -{ - "$schema": "./node_modules/oxlint/configuration_schema.json", - "plugins": [ - "react", - "typescript", - "unicorn", - "eslint", - "oxc", - "import", - "promise" - ], - "categories": { - "correctness": "error", - "suspicious": "error", - "pedantic": "allow", - "perf": "error", - "style": "allow", - "restriction": "allow" +import { defineConfig } from "oxlint"; + +export default defineConfig({ + plugins: ["react", "typescript", "unicorn", "eslint", "oxc", "import", "promise"], + categories: { + correctness: "error", + suspicious: "error", + pedantic: "allow", + perf: "error", + style: "allow", + restriction: "allow", }, - "env": { - "builtin": true, - "es2022": true, - "browser": true, - "node": true + env: { + builtin: true, + es2022: true, + browser: true, + node: true, }, - "ignorePatterns": [ + ignorePatterns: [ "dist/*", "**/dm.d.ts", "**/dm.js", @@ -34,31 +27,33 @@ "**/*.config.mjs", "**/*.js", "packages/logs/**", + "packages/bottom-tabs-react-navigation/**", + "packages/react-native-bottom-tabs/**", "**/worker-configuration.d.ts", "**/package-lock.json", - "**/pnpm-lock.yaml" + "**/pnpm-lock.yaml", ], - "rules": { + rules: { "react/react-in-jsx-scope": "off", "no-unused-vars": [ "error", { - "args": "all", - "argsIgnorePattern": "^_", - "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "ignoreRestSiblings": true - } + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, ], "no-console": "error", "react-hooks/exhaustive-deps": "error", "typescript/no-explicit-any": "error", - "typescript/no-misused-promises": ["error", { "checksVoidReturn": false }], + "typescript/no-misused-promises": ["error", { checksVoidReturn: false }], "typescript/no-unsafe-type-assertion": "allow", "typescript/consistent-return": "off", - "no-underscore-dangle": ["error", { "allow": ["__csrf"] }], + "no-underscore-dangle": ["error", { allow: ["__csrf"] }], "react/no-unstable-nested-components": "off", // tanstack query @@ -99,30 +94,27 @@ "no-new-array": "allow", "style-prop-object": "allow", "no-map-spread": "allow", - "no-await-in-loop": "allow" + "no-await-in-loop": "allow", }, - "settings": { - "react": { - "version": "19.2" - } + settings: { + react: { + version: "19.2", + }, }, - "jsPlugins": [ + jsPlugins: [ "@tanstack/eslint-plugin-query", "eslint-plugin-react-compiler", - { - "name": "bbplayer", - "specifier": "./packages/eslint-plugin/index.js" - }, + { name: "bbplayer", specifier: "./packages/eslint-plugin/index.js" }, "eslint-plugin-react-hooks-extra", "eslint-plugin-react-you-might-not-need-an-effect", - "eslint-plugin-drizzle" + "eslint-plugin-drizzle", ], - "overrides": [ + overrides: [ { - "files": ["packages/**/*.{ts,tsx,js,jsx}"], - "rules": { - "no-console": "allow" - } - } - ] -} + files: ["packages/**/*.{ts,tsx,js,jsx}"], + rules: { + "no-console": "allow", + }, + }, + ], +}); From 9c00b78484327fcac25fd5bdf0628449fe783e72 Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:55:08 +0800 Subject: [PATCH 7/8] mobile: 1 --- packages/expo-wavy-slider/package.json | 2 +- pnpm-lock.yaml | 216 +------------------------ 2 files changed, 3 insertions(+), 215 deletions(-) diff --git a/packages/expo-wavy-slider/package.json b/packages/expo-wavy-slider/package.json index 7facb8e5..cabc4b09 100644 --- a/packages/expo-wavy-slider/package.json +++ b/packages/expo-wavy-slider/package.json @@ -56,7 +56,7 @@ "expo-module-scripts": "^56.0.2", "expo-modules-core": "56.0.11", "oxfmt": "^0.27.0", - "oxlint": "^1.47.0", + "oxlint": "^1.78.0", "react": "19.2.3", "react-native": "0.86.2", "react-native-reanimated": "~4.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c84a0db3..a55fbb6a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -635,8 +635,8 @@ importers: specifier: ^0.27.0 version: 0.27.0 oxlint: - specifier: ^1.47.0 - version: 1.66.0(oxlint-tsgolint@7.0.2001) + specifier: ^1.78.0 + version: 1.78.0(oxlint-tsgolint@7.0.2001) react: specifier: 19.2.3 version: 19.2.3 @@ -3661,97 +3661,48 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.66.0': - resolution: {integrity: sha512-f7kq8N51T4phpzqfBpA2qaVTI/KrkCmNwaj3t/97I/WLTDI+UhlP5GL9eER+zVxBhtlx5rKXWByJU1/zDAvyaw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - '@oxlint/binding-android-arm-eabi@1.78.0': resolution: {integrity: sha512-Bu819lmAfZMUHErrpe0cEWj3iaefuUODHSU8+UbXy67V/r7/7f4K3FL0NmbD85E+wiFLDYuhP8Zlv0XnVeXshw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.66.0': - resolution: {integrity: sha512-xu6QO71tdDS9mjmLZ3AqhtaVHBvdmsOKkYnReNNDgh+XiwnsipeQOIxbiYOOO0iAXycJ+GK0wdMSZP/2j/AmSg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - '@oxlint/binding-android-arm64@1.78.0': resolution: {integrity: sha512-CDfxZgB61B7buRdY2FJoAYYPPXCZ1EoC1LKscnC5dg3kjobdxiconvAvvN1BmHyW4PyFT3jRLDag/BY/roSNBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.66.0': - resolution: {integrity: sha512-HZ24VimSOC7mxuEA99e0H2FS0C1yO3+iW13jPRAk+e2njsUs3QeAXsafCDyaIrV/MirdOVez+etQNQsJE43zNQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - '@oxlint/binding-darwin-arm64@1.78.0': resolution: {integrity: sha512-2Y2U9Ahrz+OO0Ej88f9SJYq51/jUBp1Mc7iZu0ukrbeeZ3gpRGfzIFnoqfHDY96xr0GEfNrPUBFEy0nN5aD7HA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.66.0': - resolution: {integrity: sha512-awhj8ZvJrrRSnXj7V++rpZvTmnl99L6mi0B7gg7Cp7BN6cKpzuI481bHNLvXGA9GB1/oEgA3ponuyoAc6Md12A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - '@oxlint/binding-darwin-x64@1.78.0': resolution: {integrity: sha512-rpych6eJq6m9jDRypTEaPD1xysaEW5h9+xuxhGK/QhOg+/xaqPZrCrTNoIl/f3nEjuJeCEmstNDlrE9rJi/3/g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.66.0': - resolution: {integrity: sha512-KQF0oVV21/FjIqkRuL8Q1vh8ECsE5+ocdH5tcqTQ4ZnYuDVoYibQUNfqBjQaUsP6UIIda5Y75Wpm5p4RgQWiWw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - '@oxlint/binding-freebsd-x64@1.78.0': resolution: {integrity: sha512-IcMGrQT3QizkOESUJd5et+rOhVqSkNDfNik1cvrKDqIbzqx9KMtRswpFgkCuNTSwylCFLKhGUu8KmqY1ZnC0Dg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.66.0': - resolution: {integrity: sha512-9u1rgwZSEXWb30vbFZzQ78HVXBo0WCKNwJ3a2InRUTNMRng+PUDIoSFmA+m4HdUfBaIqftShq8J8qHc+eE/Vig==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxlint/binding-linux-arm-gnueabihf@1.78.0': resolution: {integrity: sha512-/uLdoJ0IXE6vo/0f0LKjinQAp+re+VMaCWaNT8ENIv2EOCkSsc8SGaflXAuW0Jua2dq5+GLVWm1NQK7P3UFSNQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.66.0': - resolution: {integrity: sha512-Ynot2HR1bHxUaNWoC280MVTDfZuaWuP3XfSMRDhyuZrVjhzoaBCVFlw8h8qeZjWKVUBhPWFIxB7AQTlK8Z2WWg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.78.0': resolution: {integrity: sha512-7xi4Wb/O8NRJhLoUXmDJMUVpNYvB5kefdhFU1Jb8rtae4QoXlTiLwI14X4YvAXVZLNZChP8m5qO9SQAlWQTbkQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.66.0': - resolution: {integrity: sha512-xCbgzciGgo+A4aQZEknsNrNiIwY7sU5SfRuMmRjPIvZAgdF34cIHiKvwOsS5XRLjlTVSFwitmq6YclTtHTfU+g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-arm64-gnu@1.78.0': resolution: {integrity: sha512-4hFW0+fVXa3OIh1Y4A5SPkmvI4wuuBSrCVKzOyE7PTjhc7yEqZ1pmvEEeS5Lj/MaqvegFxXyF33N+6jkehxdyg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3759,13 +3710,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.66.0': - resolution: {integrity: sha512-hmo+ZB/lHkR1HdDmnziNpzSLmulnUSu10VEqX2Yex7OwvoBAbjJQLvy4gIBRV3AAwWnCvAxKp5Nv1GE6LU1QMg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - '@oxlint/binding-linux-arm64-musl@1.78.0': resolution: {integrity: sha512-oC0mvsgBJjlMijSDEhx9KuvR9zYeHXceA9MjbuXB1F8NSR78Yj2unOBrstEvTVaq+pko+kuue6DajC00eqvTdg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3773,13 +3717,6 @@ packages: os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.66.0': - resolution: {integrity: sha512-2Invd4Uyy81mVooQC5FBtfxSNrvcX1OxbMlVQ6M2erRrNI2awFYF26YNW2yFxdVFZ4ffNOWKghtMjhnUPsXsVA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-ppc64-gnu@1.78.0': resolution: {integrity: sha512-XAllT5SUZS+ohjuZ3/5S0cwe0r7eboiuigeStCZ5DXRYx/2KVM2UvQXvAfyzXEimtQjAB7cDQ2YxDe2Zl2WNQQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3787,13 +3724,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.66.0': - resolution: {integrity: sha512-s0iXPDQVdgayE3RGa/N2DZF7tjgg0TwEtD1sGoDxqPDGrIXgo45H0yHknT0f9A0yteASsweYZtDyTuVlM4aSag==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.78.0': resolution: {integrity: sha512-trucMER/0QtecoXvc1y/UVqE3kwJipDwrx4oHfj+nNm3dq2zjP44WT0CfHNDPM3G1DXIkx/gY6lAD21NSCZVhA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3801,13 +3731,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.66.0': - resolution: {integrity: sha512-OekL4XFiu7RPK0JIZi8VeHgtIXPREf42t8Cy/rKEsC+P3gcqDgNAAGiyuUOpdbG4wwbfue1q4CHcCO7spSve6w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - '@oxlint/binding-linux-riscv64-musl@1.78.0': resolution: {integrity: sha512-cm3O4F/HQbdzOUX5mKHqG5KDL6E5w0pnlZ+fbBy2rmLryPOowkuLagFHTopQsEIpjcaZoPOrL+BmmAytAG9HFg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3815,13 +3738,6 @@ packages: os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.66.0': - resolution: {integrity: sha512-Ga1D0kj1SFslm34ThA/BdkUlyAYEnTsXyRC4pF0C5agZSwtGdHYWMTQWemUfBGp4RCG4QWXgdO+HmmmKqOtlBg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-s390x-gnu@1.78.0': resolution: {integrity: sha512-33wRf6HqGNsybJ3qX4cGaQN2ODPxNmc1rMa0mrTmx3eFq1VzOnvQooi9bIGVYakW8a/wmqVx1mgsUm8R2xfTiw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3829,13 +3745,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.66.0': - resolution: {integrity: sha512-p5jfP1wUZe/IC3qpQO84n9DRnf9g3lKRtLBlQq23ykyrDglHcVx7sWmVTlPuU6SBw8mNnPzyOn022G3XZHnlww==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.78.0': resolution: {integrity: sha512-rRdISSYegj6VganMZ9tjRjijowfHJ09IZU01i0toBAqr6n5LEtwHq2IeS4FjW2RoskOHlb6efB26H5izYb3GEQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3843,13 +3752,6 @@ packages: os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.66.0': - resolution: {integrity: sha512-vUB/sYlYZorDL1ZD+o9mRv7zbsykrrFRtmgS6R8musZqLtrPRQn1gc1eGpuX+sfdccz42STl/AqldY6XRb2upQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - '@oxlint/binding-linux-x64-musl@1.78.0': resolution: {integrity: sha512-GmsP4rW0xTL6u5CVdcDsaN5Fbc7hBc382Wmar1kttbnwSEviM+rSINKOMQ+UQ6iH+AGwC+8gaAiwu134Tgh6Lg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3857,48 +3759,24 @@ packages: os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.66.0': - resolution: {integrity: sha512-yde+6p/F59xRkGR9H1HfngWRif1QRJjynZK349l+UI0H6w9hL3G8/AVaTHFyTtLVQ56qtNbX2/5Dc77n1ovnOg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - '@oxlint/binding-openharmony-arm64@1.78.0': resolution: {integrity: sha512-sy9yeYuADc8a+n4TLBayzMCZiHPW78DcIFVpOXTmdKHWQeM9xe5uzkqIIZmi326D5hY9XVwacipEB1p7tQjPAg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.66.0': - resolution: {integrity: sha512-O9GLucgoTdmOrbBX+EjzNe7o/Ze5TFOvXcib6bzUOtBOmj6cV+zw18NgB+cGKAkDw1Pdqs8vGkfHbbsLuDtXWg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - '@oxlint/binding-win32-arm64-msvc@1.78.0': resolution: {integrity: sha512-rjc2hF1KfMi8fZj1X/m3AmnHbdsF3rL0v6KQg0Uc880Yb2khjz+3U14sfdZ7jWTpRnN1m1NQa/TT7uU9lJWPrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.66.0': - resolution: {integrity: sha512-m3Pjwc2MfTcom4E4gOv7DyuGyt7OfGNCbmqDHd+N7EzXmP+ppHuudm2NjcA3AjV5TSeGxaguVF4SbTKHe1USYA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.78.0': resolution: {integrity: sha512-zcuXFVrEFHIafRfkCQT8w/Xe41o07ozl/vwHq7p94vB29xVzsB0sZGYORU1jhcYKv3Lr0J3HbJ2T4fHH5rWmvA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.66.0': - resolution: {integrity: sha512-/DbBvw8UFBhja6PqudUjV4UtfsJr0Oa7jUjWVKB0g86lj/VwnPrkngn0sFql3c9RDA0O16dh7ozsXb6GjNAzBQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@oxlint/binding-win32-x64-msvc@1.78.0': resolution: {integrity: sha512-Sb5ocmLSuYeOuXd+CFOToGKp/gjXUEWDnvIGwhnh8aq8wY4TMmEnKnvbogSW7RdMZv77JSARduS7/gv+khYEjA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -9939,16 +9817,6 @@ packages: resolution: {integrity: sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==} hasBin: true - oxlint@1.66.0: - resolution: {integrity: sha512-N4LLxYLd94KEBqXDMDM5f+2PUpItTjDLreXe2Gn5KhjhCK4Qp2YUXaBi8Yu325ryOgKwt22m45fpD7nPOn69Yw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - oxlint-tsgolint: '>=0.22.1' - peerDependenciesMeta: - oxlint-tsgolint: - optional: true - oxlint@1.78.0: resolution: {integrity: sha512-QgQePuxIqKOzo1KSjG2EnITEeWvWnKAm77eq8nrMtf6AGoA+zyGc4PFYtDNJSD25g/ibOwfQ851hZ4/SPkMVoA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -16427,117 +16295,60 @@ snapshots: '@oxlint-tsgolint/win32-x64@7.0.2001': optional: true - '@oxlint/binding-android-arm-eabi@1.66.0': - optional: true - '@oxlint/binding-android-arm-eabi@1.78.0': optional: true - '@oxlint/binding-android-arm64@1.66.0': - optional: true - '@oxlint/binding-android-arm64@1.78.0': optional: true - '@oxlint/binding-darwin-arm64@1.66.0': - optional: true - '@oxlint/binding-darwin-arm64@1.78.0': optional: true - '@oxlint/binding-darwin-x64@1.66.0': - optional: true - '@oxlint/binding-darwin-x64@1.78.0': optional: true - '@oxlint/binding-freebsd-x64@1.66.0': - optional: true - '@oxlint/binding-freebsd-x64@1.78.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.66.0': - optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.78.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.66.0': - optional: true - '@oxlint/binding-linux-arm-musleabihf@1.78.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.66.0': - optional: true - '@oxlint/binding-linux-arm64-gnu@1.78.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.66.0': - optional: true - '@oxlint/binding-linux-arm64-musl@1.78.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.66.0': - optional: true - '@oxlint/binding-linux-ppc64-gnu@1.78.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.66.0': - optional: true - '@oxlint/binding-linux-riscv64-gnu@1.78.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.66.0': - optional: true - '@oxlint/binding-linux-riscv64-musl@1.78.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.66.0': - optional: true - '@oxlint/binding-linux-s390x-gnu@1.78.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.66.0': - optional: true - '@oxlint/binding-linux-x64-gnu@1.78.0': optional: true - '@oxlint/binding-linux-x64-musl@1.66.0': - optional: true - '@oxlint/binding-linux-x64-musl@1.78.0': optional: true - '@oxlint/binding-openharmony-arm64@1.66.0': - optional: true - '@oxlint/binding-openharmony-arm64@1.78.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.66.0': - optional: true - '@oxlint/binding-win32-arm64-msvc@1.78.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.66.0': - optional: true - '@oxlint/binding-win32-ia32-msvc@1.78.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.66.0': - optional: true - '@oxlint/binding-win32-x64-msvc@1.78.0': optional: true @@ -24895,29 +24706,6 @@ snapshots: '@oxlint-tsgolint/win32-arm64': 7.0.2001 '@oxlint-tsgolint/win32-x64': 7.0.2001 - oxlint@1.66.0(oxlint-tsgolint@7.0.2001): - optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.66.0 - '@oxlint/binding-android-arm64': 1.66.0 - '@oxlint/binding-darwin-arm64': 1.66.0 - '@oxlint/binding-darwin-x64': 1.66.0 - '@oxlint/binding-freebsd-x64': 1.66.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.66.0 - '@oxlint/binding-linux-arm-musleabihf': 1.66.0 - '@oxlint/binding-linux-arm64-gnu': 1.66.0 - '@oxlint/binding-linux-arm64-musl': 1.66.0 - '@oxlint/binding-linux-ppc64-gnu': 1.66.0 - '@oxlint/binding-linux-riscv64-gnu': 1.66.0 - '@oxlint/binding-linux-riscv64-musl': 1.66.0 - '@oxlint/binding-linux-s390x-gnu': 1.66.0 - '@oxlint/binding-linux-x64-gnu': 1.66.0 - '@oxlint/binding-linux-x64-musl': 1.66.0 - '@oxlint/binding-openharmony-arm64': 1.66.0 - '@oxlint/binding-win32-arm64-msvc': 1.66.0 - '@oxlint/binding-win32-ia32-msvc': 1.66.0 - '@oxlint/binding-win32-x64-msvc': 1.66.0 - oxlint-tsgolint: 7.0.2001 - oxlint@1.78.0(oxlint-tsgolint@7.0.2001): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.78.0 From 2edd4c6be7c0c57803ec41e72f0a9e48d265381c Mon Sep 17 00:00:00 2001 From: roitium <65794453+roitium@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:58:47 +0800 Subject: [PATCH 8/8] mobile: 1 --- apps/mobile/src/app/settings/account.tsx | 2 +- .../src/components/modals/playlist/EnableSharingModal.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/mobile/src/app/settings/account.tsx b/apps/mobile/src/app/settings/account.tsx index 046b43a5..3658717f 100644 --- a/apps/mobile/src/app/settings/account.tsx +++ b/apps/mobile/src/app/settings/account.tsx @@ -71,7 +71,7 @@ export default function AccountSettingsPage() { } playlistSyncWorker.triggerSync() if (returnTo) { - router.replace(returnTo as never) + router.replace(returnTo) } } diff --git a/apps/mobile/src/components/modals/playlist/EnableSharingModal.tsx b/apps/mobile/src/components/modals/playlist/EnableSharingModal.tsx index 0a8af6c7..607eba73 100644 --- a/apps/mobile/src/components/modals/playlist/EnableSharingModal.tsx +++ b/apps/mobile/src/components/modals/playlist/EnableSharingModal.tsx @@ -58,7 +58,7 @@ export default function EnableSharingModal({ router.push({ pathname: '/settings/account', params: { returnTo: `/playlist/local/${playlistId}` }, - } as never) + }) }) close('EnableSharing') return @@ -89,7 +89,7 @@ export default function EnableSharingModal({ router.push({ pathname: '/settings/account', params: { returnTo: `/playlist/local/${playlistId}` }, - } as never) + }) }) close('EnableSharing') return