reorg again, absolute (module) imports

This commit is contained in:
austinried 2021-07-08 12:21:44 +09:00
parent a94a011a18
commit ea4421b7af
54 changed files with 186 additions and 251 deletions

View File

@ -1,11 +1,11 @@
import React from 'react' import React from 'react'
import { DarkTheme, NavigationContainer } from '@react-navigation/native' import { DarkTheme, NavigationContainer } from '@react-navigation/native'
import SplashPage from './src/components/SplashPage' import SplashPage from '@app/screens/SplashPage'
import RootNavigator from './src/components/navigation/RootNavigator' import RootNavigator from '@app/navigation/RootNavigator'
import { Provider } from 'jotai' import { Provider } from 'jotai'
import { StatusBar, View } from 'react-native' import { StatusBar, View } from 'react-native'
import colors from './src/styles/colors' import colors from '@app/styles/colors'
import TrackPlayerState from './src/components/TrackPlayerState' import TrackPlayerState from '@app/components/TrackPlayerState'
const theme = { ...DarkTheme } const theme = { ...DarkTheme }
theme.colors.background = colors.gradient.high theme.colors.background = colors.gradient.high

View File

@ -3,9 +3,9 @@ import React from 'react'
import { ActivityIndicator, View } from 'react-native' import { ActivityIndicator, View } from 'react-native'
import FastImage from 'react-native-fast-image' import FastImage from 'react-native-fast-image'
import LinearGradient from 'react-native-linear-gradient' import LinearGradient from 'react-native-linear-gradient'
import { albumArtAtomFamily } from '../../state/music' import { albumArtAtomFamily } from '@app/state/music'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import CoverArt from './CoverArt' import CoverArt from '@app/components/CoverArt'
interface AlbumArtProps { interface AlbumArtProps {
id: string id: string
@ -19,7 +19,7 @@ const AlbumArt: React.FC<AlbumArtProps> = ({ id, height, width }) => {
const Placeholder = () => ( const Placeholder = () => (
<LinearGradient colors={[colors.accent, colors.accentLow]}> <LinearGradient colors={[colors.accent, colors.accentLow]}>
<FastImage <FastImage
source={require('../../../res/record.png')} source={require('../../res/record.png')}
style={{ height, width }} style={{ height, width }}
resizeMode={FastImage.resizeMode.contain} resizeMode={FastImage.resizeMode.contain}
/> />

View File

@ -3,9 +3,9 @@ import React from 'react'
import { ActivityIndicator, View } from 'react-native' import { ActivityIndicator, View } from 'react-native'
import FastImage from 'react-native-fast-image' import FastImage from 'react-native-fast-image'
import LinearGradient from 'react-native-linear-gradient' import LinearGradient from 'react-native-linear-gradient'
import { artistArtAtomFamily } from '../../state/music' import { artistArtAtomFamily } from '@app/state/music'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import CoverArt from './CoverArt' import CoverArt from '@app/components/CoverArt'
interface ArtistArtSizeProps { interface ArtistArtSizeProps {
height: number height: number
@ -131,7 +131,7 @@ const NoneUp: React.FC<ArtistArtSizeProps> = ({ height, width }) => {
return ( return (
<PlaceholderContainer height={height} width={width}> <PlaceholderContainer height={height} width={width}>
<FastImage <FastImage
source={require('../../../res/mic_on-fill.png')} source={require('../../res/mic_on-fill.png')}
style={{ style={{
height: height - height / 4, height: height - height / 4,
width: width - width / 4, width: width - width / 4,

View File

@ -1,7 +1,7 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { GestureResponderEvent, Pressable, Text } from 'react-native' import { GestureResponderEvent, Pressable, Text } from 'react-native'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import text from '../../styles/text' import text from '@app/styles/text'
const Button: React.FC<{ const Button: React.FC<{
title: string title: string

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { ActivityIndicator, StyleSheet, View } from 'react-native' import { ActivityIndicator, StyleSheet, View } from 'react-native'
import FastImage from 'react-native-fast-image' import FastImage from 'react-native-fast-image'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
const CoverArt: React.FC<{ const CoverArt: React.FC<{
PlaceholderComponent: () => JSX.Element PlaceholderComponent: () => JSX.Element

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import { useWindowDimensions, ViewStyle } from 'react-native' import { useWindowDimensions, ViewStyle } from 'react-native'
import LinearGradient from 'react-native-linear-gradient' import LinearGradient from 'react-native-linear-gradient'
import colorStyles from '../../styles/colors' import colorStyles from '@app/styles/colors'
const GradientBackground: React.FC<{ const GradientBackground: React.FC<{
height?: number | string height?: number | string

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import { FlatList, FlatListProps, useWindowDimensions } from 'react-native' import { FlatList, FlatListProps, useWindowDimensions } from 'react-native'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import GradientBackground from './GradientBackground' import GradientBackground from '@app/components/GradientBackground'
function GradientFlatList<ItemT>(props: FlatListProps<ItemT>) { function GradientFlatList<ItemT>(props: FlatListProps<ItemT>) {
const layout = useWindowDimensions() const layout = useWindowDimensions()

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import { ScrollView, ScrollViewProps, ViewStyle } from 'react-native' import { ScrollView, ScrollViewProps, ViewStyle } from 'react-native'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import GradientBackground from './GradientBackground' import GradientBackground from '@app/components/GradientBackground'
const GradientScrollView: React.FC<ScrollViewProps> = props => { const GradientScrollView: React.FC<ScrollViewProps> = props => {
props.style = props.style || {} props.style = props.style || {}

View File

@ -4,8 +4,8 @@ import { ViewStyle } from 'react-native'
import FastImage from 'react-native-fast-image' import FastImage from 'react-native-fast-image'
import ImageColors from 'react-native-image-colors' import ImageColors from 'react-native-image-colors'
import { AndroidImageColors } from 'react-native-image-colors/lib/typescript/types' import { AndroidImageColors } from 'react-native-image-colors/lib/typescript/types'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import GradientBackground from './GradientBackground' import GradientBackground from '@app/components/GradientBackground'
const ImageGradientBackground: React.FC<{ const ImageGradientBackground: React.FC<{
height?: number | string height?: number | string

View File

@ -1,7 +1,7 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { LayoutRectangle, ScrollView, ScrollViewProps } from 'react-native' import { LayoutRectangle, ScrollView, ScrollViewProps } from 'react-native'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import ImageGradientBackground from './ImageGradientBackground' import ImageGradientBackground from '@app/components/ImageGradientBackground'
const ImageGradientScrollView: React.FC<ScrollViewProps & { imageUri?: string; imageKey?: string }> = props => { const ImageGradientScrollView: React.FC<ScrollViewProps & { imageUri?: string; imageKey?: string }> = props => {
const [layout, setLayout] = useState<LayoutRectangle | undefined>(undefined) const [layout, setLayout] = useState<LayoutRectangle | undefined>(undefined)

View File

@ -2,12 +2,12 @@ import React from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native' import { Pressable, StyleSheet, Text, View } from 'react-native'
import { useNavigation } from '@react-navigation/native' import { useNavigation } from '@react-navigation/native'
import { useAtomValue } from 'jotai/utils' import { useAtomValue } from 'jotai/utils'
import { currentTrackAtom, playerStateAtom, usePause, usePlay, useProgress } from '../state/trackplayer' import { currentTrackAtom, playerStateAtom, usePause, usePlay, useProgress } from '@app/state/trackplayer'
import CoverArt from './common/CoverArt' import CoverArt from '@app/components/CoverArt'
import colors from '../styles/colors' import colors from '@app/styles/colors'
import { Font } from '../styles/text' import { Font } from '@app/styles/text'
import { State } from 'react-native-track-player' import { State } from 'react-native-track-player'
import PressableOpacity from './common/PressableOpacity' import PressableOpacity from '@app/components/PressableOpacity'
import IconFA5 from 'react-native-vector-icons/FontAwesome5' import IconFA5 from 'react-native-vector-icons/FontAwesome5'
const ProgressBar = () => { const ProgressBar = () => {

View File

@ -41,4 +41,4 @@ const PressableOpacity: React.FC<PressableOpacityProps> = props => {
) )
} }
export default PressableOpacity export default React.memo(PressableOpacity)

View File

@ -13,7 +13,7 @@ import {
useRefreshPlayerState, useRefreshPlayerState,
useRefreshProgress, useRefreshProgress,
useRefreshQueue, useRefreshQueue,
} from '../state/trackplayer' } from '@app/state/trackplayer'
const AppActiveResponder: React.FC<{ const AppActiveResponder: React.FC<{
update: () => void update: () => void

View File

@ -1,27 +1,27 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { Text, View, Pressable } from 'react-native' import { Text, View, Pressable } from 'react-native'
import { BottomTabBarProps } from '@react-navigation/bottom-tabs' import { BottomTabBarProps } from '@react-navigation/bottom-tabs'
import textStyles from '../../styles/text' import textStyles from '@app/styles/text'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import FastImage from 'react-native-fast-image' import FastImage from 'react-native-fast-image'
import NowPlayingBar from '../NowPlayingBar' import NowPlayingBar from '@app/components/NowPlayingBar'
const icons: { [key: string]: any } = { const icons: { [key: string]: any } = {
home: { home: {
regular: require('../../../res/home.png'), regular: require('../../res/home.png'),
fill: require('../../../res/home-fill.png'), fill: require('../../res/home-fill.png'),
}, },
library: { library: {
regular: require('../../../res/library.png'), regular: require('../../res/library.png'),
fill: require('../../../res/library-fill.png'), fill: require('../../res/library-fill.png'),
}, },
search: { search: {
regular: require('../../../res/search.png'), regular: require('../../res/search.png'),
fill: require('../../../res/search-fill.png'), fill: require('../../res/search-fill.png'),
}, },
settings: { settings: {
regular: require('../../../res/settings.png'), regular: require('../../res/settings.png'),
fill: require('../../../res/settings-fill.png'), fill: require('../../res/settings-fill.png'),
}, },
} }

View File

@ -1,10 +1,10 @@
import React from 'react' import React from 'react'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import SettingsView from '../Settings' import SettingsView from '@app/screens/Settings'
import NowPlayingLayout from '../NowPlayingLayout' import NowPlayingLayout from '@app/screens/NowPlayingLayout'
import ArtistsList from '../ArtistsList' import ArtistsList from '@app/screens/ArtistsList'
import LibraryTopTabNavigator from './LibraryTopTabNavigator' import LibraryTopTabNavigator from '@app/navigation/LibraryTopTabNavigator'
import BottomTabBar from '../common/BottomTabBar' import BottomTabBar from '@app/navigation/BottomTabBar'
const Tab = createBottomTabNavigator() const Tab = createBottomTabNavigator()

View File

@ -1,15 +1,15 @@
import React from 'react' import React from 'react'
import { StatusBar, View } from 'react-native' import { StatusBar, View } from 'react-native'
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs' import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs'
import AlbumsTab from '../library/AlbumsTab' import AlbumsTab from '@app/screens/LibraryAlbums'
import ArtistsTab from '../library/ArtistsTab' import ArtistsTab from '@app/screens/LibraryArtists'
import PlaylistsTab from '../library/PlaylistsTab' import PlaylistsTab from '@app/screens/LibraryPlaylists'
import { createNativeStackNavigator, NativeStackNavigationProp } from 'react-native-screens/native-stack' import { createNativeStackNavigator, NativeStackNavigationProp } from 'react-native-screens/native-stack'
import AlbumView from '../common/AlbumView' import AlbumView from '@app/screens/AlbumView'
import { RouteProp } from '@react-navigation/native' import { RouteProp } from '@react-navigation/native'
import text from '../../styles/text' import text from '@app/styles/text'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import ArtistView from '../common/ArtistView' import ArtistView from '@app/screens/ArtistView'
const Tab = createMaterialTopTabNavigator() const Tab = createMaterialTopTabNavigator()

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import { createNativeStackNavigator } from 'react-native-screens/native-stack' import { createNativeStackNavigator } from 'react-native-screens/native-stack'
import NowPlayingLayout from '../NowPlayingLayout' import NowPlayingLayout from '@app/screens/NowPlayingLayout'
import BottomTabNavigator from './BottomTabNavigator' import BottomTabNavigator from '@app/navigation/BottomTabNavigator'
const RootStack = createNativeStackNavigator() const RootStack = createNativeStackNavigator()

View File

@ -4,15 +4,15 @@ import React, { useEffect } from 'react'
import { ActivityIndicator, GestureResponderEvent, StyleSheet, Text, useWindowDimensions, View } from 'react-native' import { ActivityIndicator, GestureResponderEvent, StyleSheet, Text, useWindowDimensions, View } from 'react-native'
import IconFA from 'react-native-vector-icons/FontAwesome' import IconFA from 'react-native-vector-icons/FontAwesome'
import IconMat from 'react-native-vector-icons/MaterialIcons' import IconMat from 'react-native-vector-icons/MaterialIcons'
import { albumAtomFamily } from '../../state/music' import { albumAtomFamily } from '@app/state/music'
import { currentTrackAtom, useSetQueue } from '../../state/trackplayer' import { currentTrackAtom, useSetQueue } from '@app/state/trackplayer'
import colors from '../../styles/colors' import colors from '@app/styles/colors'
import text, { Font } from '../../styles/text' import text, { Font } from '@app/styles/text'
import AlbumArt from './AlbumArt' import AlbumArt from '@app/components/AlbumArt'
import Button from './Button' import Button from '@app/components/Button'
import GradientBackground from './GradientBackground' import GradientBackground from '@app/components/GradientBackground'
import ImageGradientScrollView from './ImageGradientScrollView' import ImageGradientScrollView from '@app/components/ImageGradientScrollView'
import PressableOpacity from './PressableOpacity' import PressableOpacity from '@app/components/PressableOpacity'
const SongItem: React.FC<{ const SongItem: React.FC<{
id: string id: string

View File

@ -2,10 +2,10 @@ import { useNavigation } from '@react-navigation/native'
import { useAtomValue } from 'jotai/utils' import { useAtomValue } from 'jotai/utils'
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { Text } from 'react-native' import { Text } from 'react-native'
import { artistInfoAtomFamily } from '../../state/music' import { artistInfoAtomFamily } from '@app/state/music'
import text from '../../styles/text' import text from '@app/styles/text'
import ArtistArt from './ArtistArt' import ArtistArt from '@app/components/ArtistArt'
import GradientScrollView from './GradientScrollView' import GradientScrollView from '@app/components/GradientScrollView'
const ArtistDetails: React.FC<{ id: string }> = ({ id }) => { const ArtistDetails: React.FC<{ id: string }> = ({ id }) => {
const artist = useAtomValue(artistInfoAtomFamily(id)) const artist = useAtomValue(artistInfoAtomFamily(id))

View File

@ -1,8 +1,8 @@
import React from 'react' import React from 'react'
import { FlatList, Text, View } from 'react-native' import { FlatList, Text, View } from 'react-native'
import { useAtomValue } from 'jotai/utils' import { useAtomValue } from 'jotai/utils'
import { Artist } from '../models/music' import { Artist } from '@app/models/music'
import { artistsAtom } from '../state/music' import { artistsAtom } from '@app/state/music'
const ArtistItem: React.FC<{ item: Artist }> = ({ item }) => ( const ArtistItem: React.FC<{ item: Artist }> = ({ item }) => (
<View> <View>

View File

@ -2,11 +2,11 @@ import { useNavigation } from '@react-navigation/native'
import { useAtomValue } from 'jotai/utils' import { useAtomValue } from 'jotai/utils'
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { Pressable, Text, View } from 'react-native' import { Pressable, Text, View } from 'react-native'
import { Album } from '../../models/music' import { Album } from '@app/models/music'
import { albumsAtom, albumsUpdatingAtom, useUpdateAlbums } from '../../state/music' import { albumsAtom, albumsUpdatingAtom, useUpdateAlbums } from '@app/state/music'
import textStyles from '../../styles/text' import textStyles from '@app/styles/text'
import AlbumArt from '../common/AlbumArt' import AlbumArt from '@app/components/AlbumArt'
import GradientFlatList from '../common/GradientFlatList' import GradientFlatList from '@app/components/GradientFlatList'
const AlbumItem: React.FC<{ const AlbumItem: React.FC<{
id: string id: string

View File

@ -3,11 +3,11 @@ import { useAtomValue } from 'jotai/utils'
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { Pressable } from 'react-native' import { Pressable } from 'react-native'
import { Text } from 'react-native' import { Text } from 'react-native'
import { Artist } from '../../models/music' import { Artist } from '@app/models/music'
import { artistsAtom, artistsUpdatingAtom, useUpdateArtists } from '../../state/music' import { artistsAtom, artistsUpdatingAtom, useUpdateArtists } from '@app/state/music'
import textStyles from '../../styles/text' import textStyles from '@app/styles/text'
import ArtistArt from '../common/ArtistArt' import ArtistArt from '@app/components/ArtistArt'
import GradientFlatList from '../common/GradientFlatList' import GradientFlatList from '@app/components/GradientFlatList'
const ArtistItem: React.FC<{ item: Artist }> = ({ item }) => { const ArtistItem: React.FC<{ item: Artist }> = ({ item }) => {
const navigation = useNavigation() const navigation = useNavigation()

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import GradientBackground from '../common/GradientBackground' import GradientBackground from '@app/components/GradientBackground'
const PlaylistsTab = () => <GradientBackground /> const PlaylistsTab = () => <GradientBackground />

View File

@ -18,13 +18,13 @@ import {
usePlay, usePlay,
usePrevious, usePrevious,
useProgress, useProgress,
} from '../state/trackplayer' } from '@app/state/trackplayer'
import colors from '../styles/colors' import colors from '@app/styles/colors'
import { Font } from '../styles/text' import { Font } from '@app/styles/text'
import { formatDuration } from '../util' import formatDuration from '@app/util/formatDuration'
import CoverArt from './common/CoverArt' import CoverArt from '@app/components/CoverArt'
import ImageGradientBackground from './common/ImageGradientBackground' import ImageGradientBackground from '@app/components/ImageGradientBackground'
import PressableOpacity from './common/PressableOpacity' import PressableOpacity from '@app/components/PressableOpacity'
const NowPlayingHeader = () => { const NowPlayingHeader = () => {
const queueName = useAtomValue(queueNameAtom) const queueName = useAtomValue(queueNameAtom)

View File

@ -4,9 +4,9 @@ import md5 from 'md5'
import React from 'react' import React from 'react'
import { Button, Text, View } from 'react-native' import { Button, Text, View } from 'react-native'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { appSettingsAtom } from '../state/settings' import { appSettingsAtom } from '@app/state/settings'
import { getAllKeys, multiRemove } from '../storage/asyncstorage' import { getAllKeys, multiRemove } from '@app/storage/asyncstorage'
import text from '../styles/text' import text from '@app/styles/text'
const TestControls = () => { const TestControls = () => {
const navigation = useNavigation() const navigation = useNavigation()

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { Text, View } from 'react-native' import { Text, View } from 'react-native'
import RNFS from 'react-native-fs' import RNFS from 'react-native-fs'
import paths from '../paths' import paths from '@app/util/paths'
async function mkdir(path: string): Promise<void> { async function mkdir(path: string): Promise<void> {
const exists = await RNFS.exists(path) const exists = await RNFS.exists(path)

View File

@ -1,5 +1,5 @@
import TrackPlayer, { Event } from 'react-native-track-player' import TrackPlayer, { Event } from 'react-native-track-player'
import { trackPlayerCommands } from '../state/trackplayer' import { trackPlayerCommands } from '@app/state/trackplayer'
module.exports = async function () { module.exports = async function () {
TrackPlayer.addEventListener(Event.RemotePlay, () => trackPlayerCommands.enqueue(TrackPlayer.play)) TrackPlayer.addEventListener(Event.RemotePlay, () => trackPlayerCommands.enqueue(TrackPlayer.play))

View File

@ -1,10 +1,10 @@
import { atom, useAtom } from 'jotai' import { atom, useAtom } from 'jotai'
import { atomFamily, useAtomValue, useUpdateAtom } from 'jotai/utils' import { atomFamily, useAtomValue, useUpdateAtom } from 'jotai/utils'
import { Album, AlbumArt, AlbumWithSongs, Artist, ArtistArt, ArtistInfo, Song } from '../models/music' import { Album, AlbumArt, AlbumWithSongs, Artist, ArtistArt, ArtistInfo, Song } from '@app/models/music'
import { SubsonicApiClient } from '../subsonic/api' import { SubsonicApiClient } from '@app/subsonic/api'
import { AlbumID3Element, ArtistInfo2Element, ChildElement } from '../subsonic/elements' import { AlbumID3Element, ArtistInfo2Element, ChildElement } from '@app/subsonic/elements'
import { GetArtistResponse } from '../subsonic/responses' import { GetArtistResponse } from '@app/subsonic/responses'
import { activeServerAtom } from './settings' import { activeServerAtom } from '@app/state/settings'
export const artistsAtom = atom<Artist[]>([]) export const artistsAtom = atom<Artist[]>([])
export const artistsUpdatingAtom = atom(false) export const artistsUpdatingAtom = atom(false)

View File

@ -1,6 +1,6 @@
import { atom } from 'jotai' import { atom } from 'jotai'
import { AppSettings } from '../models/settings' import { AppSettings } from '@app/models/settings'
import atomWithAsyncStorage from '../storage/atomWithAsyncStorage' import atomWithAsyncStorage from '@app/storage/atomWithAsyncStorage'
export const appSettingsAtom = atomWithAsyncStorage<AppSettings>('@appSettings', { export const appSettingsAtom = atomWithAsyncStorage<AppSettings>('@appSettings', {
servers: [], servers: [],

View File

@ -3,8 +3,8 @@ import { atom } from 'jotai'
import { useAtomValue, useUpdateAtom } from 'jotai/utils' import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import { useEffect } from 'react' import { useEffect } from 'react'
import TrackPlayer, { State, Track } from 'react-native-track-player' import TrackPlayer, { State, Track } from 'react-native-track-player'
import { Song } from '../models/music' import { Song } from '@app/models/music'
import { PromiseQueue } from '../util' import PromiseQueue from '@app/util/PromiseQueue'
type TrackExt = Track & { type TrackExt = Track & {
id: string id: string

View File

@ -1,5 +1,5 @@
import { atomWithStorage } from 'jotai/utils' import { atomWithStorage } from 'jotai/utils'
import { getItem, setItem } from './asyncstorage' import { getItem, setItem } from '@app/storage/asyncstorage'
export default <T>(key: string, defaultValue: T) => { export default <T>(key: string, defaultValue: T) => {
return atomWithStorage<T>(key, defaultValue, { return atomWithStorage<T>(key, defaultValue, {

View File

@ -1,5 +1,5 @@
import { DownloadedSong } from '../models/music' import { DownloadedSong } from '@app/models/music'
import { getItem, multiGet, multiSet } from './asyncstorage' import { getItem, multiGet, multiSet } from '@app/storage/asyncstorage'
const key = { const key = {
downloadedSongKeys: '@downloadedSongKeys', downloadedSongKeys: '@downloadedSongKeys',

View File

@ -1,5 +1,5 @@
import { TextStyle } from 'react-native' import { TextStyle } from 'react-native'
import colors from './colors' import colors from '@app/styles/colors'
export enum Font { export enum Font {
regular = 'Metropolis-Regular', regular = 'Metropolis-Regular',

View File

@ -11,7 +11,7 @@ import {
GetIndexesParams, GetIndexesParams,
GetMusicDirectoryParams, GetMusicDirectoryParams,
StreamParams, StreamParams,
} from './params' } from '@app/subsonic/params'
import { import {
GetAlbumList2Response, GetAlbumList2Response,
GetAlbumListResponse, GetAlbumListResponse,
@ -23,10 +23,10 @@ import {
GetIndexesResponse, GetIndexesResponse,
GetMusicDirectoryResponse, GetMusicDirectoryResponse,
SubsonicResponse, SubsonicResponse,
} from './responses' } from '@app/subsonic/responses'
import { Server } from '../models/settings' import { Server } from '@app/models/settings'
import paths from '../paths' import paths from '@app/util/paths'
import { PromiseQueue } from '../util' import PromiseQueue from '@app/util/PromiseQueue'
export class SubsonicApiError extends Error { export class SubsonicApiError extends Error {
method: string method: string

View File

@ -1,6 +1,6 @@
import { useAtomValue } from 'jotai/utils' import { useAtomValue } from 'jotai/utils'
import { activeServerAtom } from '../state/settings' import { activeServerAtom } from '@app/state/settings'
import { SubsonicApiClient } from '../subsonic/api' import { SubsonicApiClient } from '@app/subsonic/api'
export const useSubsonicApi = () => { export const useSubsonicApi = () => {
const activeServer = useAtomValue(activeServerAtom) const activeServer = useAtomValue(activeServerAtom)

View File

@ -6,7 +6,7 @@ import {
ArtistInfoElement, ArtistInfoElement,
ChildElement, ChildElement,
DirectoryElement, DirectoryElement,
} from './elements' } from '@app/subsonic/elements'
export type ResponseStatus = 'ok' | 'failed' export type ResponseStatus = 'ok' | 'failed'

View File

@ -1,18 +1,6 @@
export function formatDuration(seconds: number): string {
const s = Math.floor(seconds) % 60
const m = Math.floor(seconds / 60) % 60
const h = Math.floor(seconds / 60 / 60)
let time = `${m.toString().padStart(1, '0')}:${s.toString().padStart(2, '0')}`
if (h > 0) {
time = `${h}:${time}`
}
return time
}
type QueuedPromise = () => Promise<any> type QueuedPromise = () => Promise<any>
export class PromiseQueue { class PromiseQueue {
maxSimultaneously: number maxSimultaneously: number
private active = 0 private active = 0
@ -39,3 +27,5 @@ export class PromiseQueue {
} }
} }
} }
export default PromiseQueue

View File

@ -0,0 +1,13 @@
function formatDuration(seconds: number): string {
const s = Math.floor(seconds) % 60
const m = Math.floor(seconds / 60) % 60
const h = Math.floor(seconds / 60 / 60)
let time = `${m.toString().padStart(1, '0')}:${s.toString().padStart(2, '0')}`
if (h > 0) {
time = `${h}:${time}`
}
return time
}
export default formatDuration

View File

@ -1,6 +1,16 @@
module.exports = { module.exports = {
presets: ['module:metro-react-native-babel-preset'], presets: ['module:metro-react-native-babel-preset'],
plugins: [ plugins: [
[
require.resolve('babel-plugin-module-resolver'),
{
cwd: 'babelrc',
extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js'],
alias: {
'@app': './app',
},
},
],
// reanimated has to be listed last in plugins // reanimated has to be listed last in plugins
'react-native-reanimated/plugin', 'react-native-reanimated/plugin',
], ],

View File

@ -5,12 +5,12 @@ import { enableScreens } from 'react-native-screens'
enableScreens() enableScreens()
import { AppRegistry } from 'react-native' import { AppRegistry } from 'react-native'
import App from './App' import App from '@app/App'
import { name as appName } from './app.json' import { name as appName } from '@app/app.json'
import TrackPlayer, { Capability } from 'react-native-track-player' import TrackPlayer, { Capability } from 'react-native-track-player'
AppRegistry.registerComponent(appName, () => App) AppRegistry.registerComponent(appName, () => App)
TrackPlayer.registerPlaybackService(() => require('./src/playback/service')) TrackPlayer.registerPlaybackService(() => require('./app/service'))
async function start() { async function start() {
await TrackPlayer.setupPlayer() await TrackPlayer.setupPlayer()

View File

@ -48,6 +48,7 @@
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"@types/xmldom": "^0.1.30", "@types/xmldom": "^0.1.30",
"babel-jest": "^26.6.3", "babel-jest": "^26.6.3",
"babel-plugin-module-resolver": "^4.1.0",
"eslint": "^7.14.0", "eslint": "^7.14.0",
"jest": "^26.6.3", "jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.64.0", "metro-react-native-babel-preset": "^0.64.0",

View File

@ -1,30 +0,0 @@
import React from 'react'
import { Image, ImageSourcePropType } from 'react-native'
import colors from '../styles/colors'
export type FocusableIconProps = {
focused: boolean
source: ImageSourcePropType
focusedSource?: ImageSourcePropType
width?: number
height?: number
}
const FocusableIcon: React.FC<FocusableIconProps> = props => {
props.focusedSource = props.focusedSource || props.source
props.width = props.width || 26
props.height = props.height || 26
return (
<Image
style={{
height: props.height,
width: props.width,
tintColor: props.focused ? colors.text.primary : colors.text.secondary,
}}
source={props.focused ? props.focusedSource : props.source}
/>
)
}
export default FocusableIcon

View File

@ -1,71 +0,0 @@
import React, { useEffect, useState } from 'react'
import { GestureResponderEvent, LayoutRectangle, Pressable, ViewStyle } from 'react-native'
import FastImage, { Source } from 'react-native-fast-image'
const PressableImage: React.FC<{
source: Source | number
onPress?: (event: GestureResponderEvent) => void
style?: ViewStyle
tintColor?: string
disabled?: boolean
hitSlop?: number
padding?: number
ripple?: boolean
}> = ({ source, onPress, style, tintColor, disabled, hitSlop, padding, ripple }) => {
const [opacity, setOpacity] = useState(1)
const [dimensions, setDimensions] = useState<LayoutRectangle | undefined>(undefined)
disabled = disabled === undefined ? false : disabled
padding = padding || 0
ripple = ripple === undefined ? false : ripple
style = {
...(style || {}),
opacity,
justifyContent: 'center',
alignItems: 'center',
}
useEffect(() => {
disabled ? setOpacity(0.3) : setOpacity(1)
}, [disabled])
return (
<Pressable
style={style}
onPress={onPress}
disabled={disabled}
hitSlop={hitSlop}
android_ripple={
ripple
? {
color: 'rgba(255,255,255,0.26)',
radius: dimensions ? dimensions.width / 2 : undefined,
}
: undefined
}
onPressIn={() => {
if (!disabled) {
setOpacity(0.4)
}
}}
onPressOut={() => {
if (!disabled) {
setOpacity(1)
}
}}
onLayout={event => setDimensions(event.nativeEvent.layout)}>
<FastImage
style={{
display: dimensions ? 'flex' : 'none',
height: dimensions ? dimensions.height - padding : 0,
width: dimensions ? dimensions.width - padding : 0,
}}
source={source}
tintColor={tintColor || 'white'}
resizeMode={FastImage.resizeMode.contain}
/>
</Pressable>
)
}
export default PressableImage

View File

@ -1,16 +0,0 @@
import React from 'react'
import LinearGradient from 'react-native-linear-gradient'
import colors from '../../styles/colors'
const TopTabContainer: React.FC<{}> = ({ children }) => (
<LinearGradient
colors={[colors.gradient.high, colors.gradient.mid, colors.gradient.low]}
locations={[0.03, 0.3, 0.7]}
style={{
flex: 1,
}}>
{children}
</LinearGradient>
)
export default TopTabContainer

View File

@ -36,8 +36,10 @@
/* Module Resolution Options */ /* Module Resolution Options */
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ "paths": {
"@app/*": ["app/*/index", "app/*"]
}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */ // "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */ // "types": [], /* Type declaration files to be included in compilation. */

View File

@ -1765,6 +1765,17 @@ babel-plugin-jest-hoist@^26.6.2:
"@types/babel__core" "^7.0.0" "@types/babel__core" "^7.0.0"
"@types/babel__traverse" "^7.0.6" "@types/babel__traverse" "^7.0.6"
babel-plugin-module-resolver@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2"
integrity sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==
dependencies:
find-babel-config "^1.2.0"
glob "^7.1.6"
pkg-up "^3.1.0"
reselect "^4.0.0"
resolve "^1.13.1"
babel-plugin-polyfill-corejs2@^0.2.2: babel-plugin-polyfill-corejs2@^0.2.2:
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327"
@ -3019,6 +3030,14 @@ finalhandler@1.1.2:
statuses "~1.5.0" statuses "~1.5.0"
unpipe "~1.0.0" unpipe "~1.0.0"
find-babel-config@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2"
integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==
dependencies:
json5 "^0.5.1"
path-exists "^3.0.0"
find-cache-dir@^2.0.0: find-cache-dir@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
@ -4241,6 +4260,11 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
json5@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
json5@^2.1.2: json5@^2.1.2:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
@ -5314,6 +5338,13 @@ pkg-dir@^4.2.0:
dependencies: dependencies:
find-up "^4.0.0" find-up "^4.0.0"
pkg-up@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==
dependencies:
find-up "^3.0.0"
plist@^3.0.1: plist@^3.0.1:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.2.tgz#74bbf011124b90421c22d15779cee60060ba95bc" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.2.tgz#74bbf011124b90421c22d15779cee60060ba95bc"
@ -5768,6 +5799,11 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
reselect@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
resolve-cwd@^3.0.0: resolve-cwd@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
@ -5795,7 +5831,7 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.18.1: resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.18.1:
version "1.20.0" version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==