From ea4421b7aff29c50a80308ce07d9fde19edc98e8 Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:21:44 +0900 Subject: [PATCH] reorg again, absolute (module) imports --- App.tsx => app/App.tsx | 8 +-- app.json => app/app.json | 0 .../common => app/components}/AlbumArt.tsx | 8 +-- .../common => app/components}/ArtistArt.tsx | 8 +-- .../common => app/components}/Button.tsx | 4 +- .../common => app/components}/CoverArt.tsx | 2 +- .../components}/GradientBackground.tsx | 2 +- .../components}/GradientFlatList.tsx | 4 +- .../components}/GradientScrollView.tsx | 4 +- .../components}/ImageGradientBackground.tsx | 4 +- .../components}/ImageGradientScrollView.tsx | 4 +- {src => app}/components/NowPlayingBar.tsx | 10 +-- .../components}/PressableOpacity.tsx | 2 +- {src => app}/components/TrackPlayerState.tsx | 2 +- {src => app}/models/music.ts | 0 {src => app}/models/settings.ts | 0 .../navigation}/BottomTabBar.tsx | 22 +++--- .../navigation/BottomTabNavigator.tsx | 10 +-- .../navigation/LibraryTopTabNavigator.tsx | 14 ++-- .../navigation/RootNavigator.tsx | 4 +- .../common => app/screens}/AlbumView.tsx | 18 ++--- .../common => app/screens}/ArtistView.tsx | 8 +-- .../screens}/ArtistsList.tsx | 4 +- .../screens/LibraryAlbums.tsx | 10 +-- .../screens/LibraryArtists.tsx | 10 +-- .../screens/LibraryPlaylists.tsx | 2 +- .../screens}/NowPlayingLayout.tsx | 14 ++-- {src/components => app/screens}/Settings.tsx | 6 +- .../components => app/screens}/SplashPage.tsx | 2 +- {src/playback => app}/service.ts | 2 +- {src => app}/state/music.ts | 10 +-- {src => app}/state/settings.ts | 4 +- {src => app}/state/trackplayer.ts | 4 +- {src => app}/storage/asyncstorage.ts | 0 {src => app}/storage/atomWithAsyncStorage.ts | 2 +- {src => app}/storage/music.ts | 4 +- {src => app}/styles/colors.ts | 0 {src => app}/styles/text.ts | 2 +- {src => app}/subsonic/api.ts | 10 +-- {src => app}/subsonic/elements.ts | 0 .../subsonic.ts => app/subsonic/hooks.ts | 4 +- {src => app}/subsonic/params.ts | 0 {src => app}/subsonic/responses.ts | 2 +- src/util.ts => app/util/PromiseQueue.ts | 16 +---- app/util/formatDuration.ts | 13 ++++ {src => app/util}/paths.ts | 0 babel.config.js | 10 +++ index.js | 6 +- package.json | 1 + src/components/FocusableIcon.tsx | 30 -------- src/components/common/PressableImage.tsx | 71 ------------------- src/components/common/TopTabContainer.tsx | 16 ----- tsconfig.json | 6 +- yarn.lock | 38 +++++++++- 54 files changed, 186 insertions(+), 251 deletions(-) rename App.tsx => app/App.tsx (75%) rename app.json => app/app.json (100%) rename {src/components/common => app/components}/AlbumArt.tsx (87%) rename {src/components/common => app/components}/ArtistArt.tsx (96%) rename {src/components/common => app/components}/Button.tsx (90%) rename {src/components/common => app/components}/CoverArt.tsx (97%) rename {src/components/common => app/components}/GradientBackground.tsx (94%) rename {src/components/common => app/components}/GradientFlatList.tsx (83%) rename {src/components/common => app/components}/GradientScrollView.tsx (80%) rename {src/components/common => app/components}/ImageGradientBackground.tsx (94%) rename {src/components/common => app/components}/ImageGradientScrollView.tsx (87%) rename {src => app}/components/NowPlayingBar.tsx (93%) rename {src/components/common => app/components}/PressableOpacity.tsx (96%) rename {src => app}/components/TrackPlayerState.tsx (99%) rename {src => app}/models/music.ts (100%) rename {src => app}/models/settings.ts (100%) rename {src/components/common => app/navigation}/BottomTabBar.tsx (83%) rename {src/components => app}/navigation/BottomTabNavigator.tsx (70%) rename {src/components => app}/navigation/LibraryTopTabNavigator.tsx (89%) rename {src/components => app}/navigation/RootNavigator.tsx (78%) rename {src/components/common => app/screens}/AlbumView.tsx (90%) rename {src/components/common => app/screens}/ArtistView.tsx (82%) rename {src/components => app/screens}/ArtistsList.tsx (89%) rename src/components/library/AlbumsTab.tsx => app/screens/LibraryAlbums.tsx (90%) rename src/components/library/ArtistsTab.tsx => app/screens/LibraryArtists.tsx (88%) rename src/components/library/PlaylistsTab.tsx => app/screens/LibraryPlaylists.tsx (60%) rename {src/components => app/screens}/NowPlayingLayout.tsx (95%) rename {src/components => app/screens}/Settings.tsx (91%) rename {src/components => app/screens}/SplashPage.tsx (96%) rename {src/playback => app}/service.ts (94%) rename {src => app}/state/music.ts (95%) rename {src => app}/state/settings.ts (71%) rename {src => app}/state/trackplayer.ts (98%) rename {src => app}/storage/asyncstorage.ts (100%) rename {src => app}/storage/atomWithAsyncStorage.ts (81%) rename {src => app}/storage/music.ts (88%) rename {src => app}/styles/colors.ts (100%) rename {src => app}/styles/text.ts (96%) rename {src => app}/subsonic/api.ts (96%) rename {src => app}/subsonic/elements.ts (100%) rename src/hooks/subsonic.ts => app/subsonic/hooks.ts (70%) rename {src => app}/subsonic/params.ts (100%) rename {src => app}/subsonic/responses.ts (99%) rename src/util.ts => app/util/PromiseQueue.ts (62%) create mode 100644 app/util/formatDuration.ts rename {src => app/util}/paths.ts (100%) delete mode 100644 src/components/FocusableIcon.tsx delete mode 100644 src/components/common/PressableImage.tsx delete mode 100644 src/components/common/TopTabContainer.tsx diff --git a/App.tsx b/app/App.tsx similarity index 75% rename from App.tsx rename to app/App.tsx index caba2ea..3018d9b 100644 --- a/App.tsx +++ b/app/App.tsx @@ -1,11 +1,11 @@ import React from 'react' import { DarkTheme, NavigationContainer } from '@react-navigation/native' -import SplashPage from './src/components/SplashPage' -import RootNavigator from './src/components/navigation/RootNavigator' +import SplashPage from '@app/screens/SplashPage' +import RootNavigator from '@app/navigation/RootNavigator' import { Provider } from 'jotai' import { StatusBar, View } from 'react-native' -import colors from './src/styles/colors' -import TrackPlayerState from './src/components/TrackPlayerState' +import colors from '@app/styles/colors' +import TrackPlayerState from '@app/components/TrackPlayerState' const theme = { ...DarkTheme } theme.colors.background = colors.gradient.high diff --git a/app.json b/app/app.json similarity index 100% rename from app.json rename to app/app.json diff --git a/src/components/common/AlbumArt.tsx b/app/components/AlbumArt.tsx similarity index 87% rename from src/components/common/AlbumArt.tsx rename to app/components/AlbumArt.tsx index d5f7bdf..f4ee673 100644 --- a/src/components/common/AlbumArt.tsx +++ b/app/components/AlbumArt.tsx @@ -3,9 +3,9 @@ import React from 'react' import { ActivityIndicator, View } from 'react-native' import FastImage from 'react-native-fast-image' import LinearGradient from 'react-native-linear-gradient' -import { albumArtAtomFamily } from '../../state/music' -import colors from '../../styles/colors' -import CoverArt from './CoverArt' +import { albumArtAtomFamily } from '@app/state/music' +import colors from '@app/styles/colors' +import CoverArt from '@app/components/CoverArt' interface AlbumArtProps { id: string @@ -19,7 +19,7 @@ const AlbumArt: React.FC = ({ id, height, width }) => { const Placeholder = () => ( diff --git a/src/components/common/ArtistArt.tsx b/app/components/ArtistArt.tsx similarity index 96% rename from src/components/common/ArtistArt.tsx rename to app/components/ArtistArt.tsx index 5605993..942b01b 100644 --- a/src/components/common/ArtistArt.tsx +++ b/app/components/ArtistArt.tsx @@ -3,9 +3,9 @@ import React from 'react' import { ActivityIndicator, View } from 'react-native' import FastImage from 'react-native-fast-image' import LinearGradient from 'react-native-linear-gradient' -import { artistArtAtomFamily } from '../../state/music' -import colors from '../../styles/colors' -import CoverArt from './CoverArt' +import { artistArtAtomFamily } from '@app/state/music' +import colors from '@app/styles/colors' +import CoverArt from '@app/components/CoverArt' interface ArtistArtSizeProps { height: number @@ -131,7 +131,7 @@ const NoneUp: React.FC = ({ height, width }) => { return ( JSX.Element diff --git a/src/components/common/GradientBackground.tsx b/app/components/GradientBackground.tsx similarity index 94% rename from src/components/common/GradientBackground.tsx rename to app/components/GradientBackground.tsx index 3a72f08..c4ef9ce 100644 --- a/src/components/common/GradientBackground.tsx +++ b/app/components/GradientBackground.tsx @@ -1,7 +1,7 @@ import React from 'react' import { useWindowDimensions, ViewStyle } from 'react-native' import LinearGradient from 'react-native-linear-gradient' -import colorStyles from '../../styles/colors' +import colorStyles from '@app/styles/colors' const GradientBackground: React.FC<{ height?: number | string diff --git a/src/components/common/GradientFlatList.tsx b/app/components/GradientFlatList.tsx similarity index 83% rename from src/components/common/GradientFlatList.tsx rename to app/components/GradientFlatList.tsx index 77b035c..25a6cbc 100644 --- a/src/components/common/GradientFlatList.tsx +++ b/app/components/GradientFlatList.tsx @@ -1,7 +1,7 @@ import React from 'react' import { FlatList, FlatListProps, useWindowDimensions } from 'react-native' -import colors from '../../styles/colors' -import GradientBackground from './GradientBackground' +import colors from '@app/styles/colors' +import GradientBackground from '@app/components/GradientBackground' function GradientFlatList(props: FlatListProps) { const layout = useWindowDimensions() diff --git a/src/components/common/GradientScrollView.tsx b/app/components/GradientScrollView.tsx similarity index 80% rename from src/components/common/GradientScrollView.tsx rename to app/components/GradientScrollView.tsx index dc90bfd..b564697 100644 --- a/src/components/common/GradientScrollView.tsx +++ b/app/components/GradientScrollView.tsx @@ -1,7 +1,7 @@ import React from 'react' import { ScrollView, ScrollViewProps, ViewStyle } from 'react-native' -import colors from '../../styles/colors' -import GradientBackground from './GradientBackground' +import colors from '@app/styles/colors' +import GradientBackground from '@app/components/GradientBackground' const GradientScrollView: React.FC = props => { props.style = props.style || {} diff --git a/src/components/common/ImageGradientBackground.tsx b/app/components/ImageGradientBackground.tsx similarity index 94% rename from src/components/common/ImageGradientBackground.tsx rename to app/components/ImageGradientBackground.tsx index 8537531..ae694e0 100644 --- a/src/components/common/ImageGradientBackground.tsx +++ b/app/components/ImageGradientBackground.tsx @@ -4,8 +4,8 @@ import { ViewStyle } from 'react-native' import FastImage from 'react-native-fast-image' import ImageColors from 'react-native-image-colors' import { AndroidImageColors } from 'react-native-image-colors/lib/typescript/types' -import colors from '../../styles/colors' -import GradientBackground from './GradientBackground' +import colors from '@app/styles/colors' +import GradientBackground from '@app/components/GradientBackground' const ImageGradientBackground: React.FC<{ height?: number | string diff --git a/src/components/common/ImageGradientScrollView.tsx b/app/components/ImageGradientScrollView.tsx similarity index 87% rename from src/components/common/ImageGradientScrollView.tsx rename to app/components/ImageGradientScrollView.tsx index d34dbf6..041720a 100644 --- a/src/components/common/ImageGradientScrollView.tsx +++ b/app/components/ImageGradientScrollView.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react' import { LayoutRectangle, ScrollView, ScrollViewProps } from 'react-native' -import colors from '../../styles/colors' -import ImageGradientBackground from './ImageGradientBackground' +import colors from '@app/styles/colors' +import ImageGradientBackground from '@app/components/ImageGradientBackground' const ImageGradientScrollView: React.FC = props => { const [layout, setLayout] = useState(undefined) diff --git a/src/components/NowPlayingBar.tsx b/app/components/NowPlayingBar.tsx similarity index 93% rename from src/components/NowPlayingBar.tsx rename to app/components/NowPlayingBar.tsx index a792e8c..a3fa1ac 100644 --- a/src/components/NowPlayingBar.tsx +++ b/app/components/NowPlayingBar.tsx @@ -2,12 +2,12 @@ import React from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' import { useNavigation } from '@react-navigation/native' import { useAtomValue } from 'jotai/utils' -import { currentTrackAtom, playerStateAtom, usePause, usePlay, useProgress } from '../state/trackplayer' -import CoverArt from './common/CoverArt' -import colors from '../styles/colors' -import { Font } from '../styles/text' +import { currentTrackAtom, playerStateAtom, usePause, usePlay, useProgress } from '@app/state/trackplayer' +import CoverArt from '@app/components/CoverArt' +import colors from '@app/styles/colors' +import { Font } from '@app/styles/text' 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' const ProgressBar = () => { diff --git a/src/components/common/PressableOpacity.tsx b/app/components/PressableOpacity.tsx similarity index 96% rename from src/components/common/PressableOpacity.tsx rename to app/components/PressableOpacity.tsx index 9977c11..9a8b1ec 100644 --- a/src/components/common/PressableOpacity.tsx +++ b/app/components/PressableOpacity.tsx @@ -41,4 +41,4 @@ const PressableOpacity: React.FC = props => { ) } -export default PressableOpacity +export default React.memo(PressableOpacity) diff --git a/src/components/TrackPlayerState.tsx b/app/components/TrackPlayerState.tsx similarity index 99% rename from src/components/TrackPlayerState.tsx rename to app/components/TrackPlayerState.tsx index fc5b725..10527ad 100644 --- a/src/components/TrackPlayerState.tsx +++ b/app/components/TrackPlayerState.tsx @@ -13,7 +13,7 @@ import { useRefreshPlayerState, useRefreshProgress, useRefreshQueue, -} from '../state/trackplayer' +} from '@app/state/trackplayer' const AppActiveResponder: React.FC<{ update: () => void diff --git a/src/models/music.ts b/app/models/music.ts similarity index 100% rename from src/models/music.ts rename to app/models/music.ts diff --git a/src/models/settings.ts b/app/models/settings.ts similarity index 100% rename from src/models/settings.ts rename to app/models/settings.ts diff --git a/src/components/common/BottomTabBar.tsx b/app/navigation/BottomTabBar.tsx similarity index 83% rename from src/components/common/BottomTabBar.tsx rename to app/navigation/BottomTabBar.tsx index edf89b8..76abb86 100644 --- a/src/components/common/BottomTabBar.tsx +++ b/app/navigation/BottomTabBar.tsx @@ -1,27 +1,27 @@ import React, { useState } from 'react' import { Text, View, Pressable } from 'react-native' import { BottomTabBarProps } from '@react-navigation/bottom-tabs' -import textStyles from '../../styles/text' -import colors from '../../styles/colors' +import textStyles from '@app/styles/text' +import colors from '@app/styles/colors' import FastImage from 'react-native-fast-image' -import NowPlayingBar from '../NowPlayingBar' +import NowPlayingBar from '@app/components/NowPlayingBar' const icons: { [key: string]: any } = { home: { - regular: require('../../../res/home.png'), - fill: require('../../../res/home-fill.png'), + regular: require('../../res/home.png'), + fill: require('../../res/home-fill.png'), }, library: { - regular: require('../../../res/library.png'), - fill: require('../../../res/library-fill.png'), + regular: require('../../res/library.png'), + fill: require('../../res/library-fill.png'), }, search: { - regular: require('../../../res/search.png'), - fill: require('../../../res/search-fill.png'), + regular: require('../../res/search.png'), + fill: require('../../res/search-fill.png'), }, settings: { - regular: require('../../../res/settings.png'), - fill: require('../../../res/settings-fill.png'), + regular: require('../../res/settings.png'), + fill: require('../../res/settings-fill.png'), }, } diff --git a/src/components/navigation/BottomTabNavigator.tsx b/app/navigation/BottomTabNavigator.tsx similarity index 70% rename from src/components/navigation/BottomTabNavigator.tsx rename to app/navigation/BottomTabNavigator.tsx index 9326990..495dfbc 100644 --- a/src/components/navigation/BottomTabNavigator.tsx +++ b/app/navigation/BottomTabNavigator.tsx @@ -1,10 +1,10 @@ import React from 'react' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' -import SettingsView from '../Settings' -import NowPlayingLayout from '../NowPlayingLayout' -import ArtistsList from '../ArtistsList' -import LibraryTopTabNavigator from './LibraryTopTabNavigator' -import BottomTabBar from '../common/BottomTabBar' +import SettingsView from '@app/screens/Settings' +import NowPlayingLayout from '@app/screens/NowPlayingLayout' +import ArtistsList from '@app/screens/ArtistsList' +import LibraryTopTabNavigator from '@app/navigation/LibraryTopTabNavigator' +import BottomTabBar from '@app/navigation/BottomTabBar' const Tab = createBottomTabNavigator() diff --git a/src/components/navigation/LibraryTopTabNavigator.tsx b/app/navigation/LibraryTopTabNavigator.tsx similarity index 89% rename from src/components/navigation/LibraryTopTabNavigator.tsx rename to app/navigation/LibraryTopTabNavigator.tsx index a0ea841..030f7cb 100644 --- a/src/components/navigation/LibraryTopTabNavigator.tsx +++ b/app/navigation/LibraryTopTabNavigator.tsx @@ -1,15 +1,15 @@ import React from 'react' import { StatusBar, View } from 'react-native' import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs' -import AlbumsTab from '../library/AlbumsTab' -import ArtistsTab from '../library/ArtistsTab' -import PlaylistsTab from '../library/PlaylistsTab' +import AlbumsTab from '@app/screens/LibraryAlbums' +import ArtistsTab from '@app/screens/LibraryArtists' +import PlaylistsTab from '@app/screens/LibraryPlaylists' 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 text from '../../styles/text' -import colors from '../../styles/colors' -import ArtistView from '../common/ArtistView' +import text from '@app/styles/text' +import colors from '@app/styles/colors' +import ArtistView from '@app/screens/ArtistView' const Tab = createMaterialTopTabNavigator() diff --git a/src/components/navigation/RootNavigator.tsx b/app/navigation/RootNavigator.tsx similarity index 78% rename from src/components/navigation/RootNavigator.tsx rename to app/navigation/RootNavigator.tsx index adde2bd..08812f3 100644 --- a/src/components/navigation/RootNavigator.tsx +++ b/app/navigation/RootNavigator.tsx @@ -1,7 +1,7 @@ import React from 'react' import { createNativeStackNavigator } from 'react-native-screens/native-stack' -import NowPlayingLayout from '../NowPlayingLayout' -import BottomTabNavigator from './BottomTabNavigator' +import NowPlayingLayout from '@app/screens/NowPlayingLayout' +import BottomTabNavigator from '@app/navigation/BottomTabNavigator' const RootStack = createNativeStackNavigator() diff --git a/src/components/common/AlbumView.tsx b/app/screens/AlbumView.tsx similarity index 90% rename from src/components/common/AlbumView.tsx rename to app/screens/AlbumView.tsx index 51a8b73..cc32c29 100644 --- a/src/components/common/AlbumView.tsx +++ b/app/screens/AlbumView.tsx @@ -4,15 +4,15 @@ import React, { useEffect } from 'react' import { ActivityIndicator, GestureResponderEvent, StyleSheet, Text, useWindowDimensions, View } from 'react-native' import IconFA from 'react-native-vector-icons/FontAwesome' import IconMat from 'react-native-vector-icons/MaterialIcons' -import { albumAtomFamily } from '../../state/music' -import { currentTrackAtom, useSetQueue } from '../../state/trackplayer' -import colors from '../../styles/colors' -import text, { Font } from '../../styles/text' -import AlbumArt from './AlbumArt' -import Button from './Button' -import GradientBackground from './GradientBackground' -import ImageGradientScrollView from './ImageGradientScrollView' -import PressableOpacity from './PressableOpacity' +import { albumAtomFamily } from '@app/state/music' +import { currentTrackAtom, useSetQueue } from '@app/state/trackplayer' +import colors from '@app/styles/colors' +import text, { Font } from '@app/styles/text' +import AlbumArt from '@app/components/AlbumArt' +import Button from '@app/components/Button' +import GradientBackground from '@app/components/GradientBackground' +import ImageGradientScrollView from '@app/components/ImageGradientScrollView' +import PressableOpacity from '@app/components/PressableOpacity' const SongItem: React.FC<{ id: string diff --git a/src/components/common/ArtistView.tsx b/app/screens/ArtistView.tsx similarity index 82% rename from src/components/common/ArtistView.tsx rename to app/screens/ArtistView.tsx index f7d33cd..9a2ff7b 100644 --- a/src/components/common/ArtistView.tsx +++ b/app/screens/ArtistView.tsx @@ -2,10 +2,10 @@ import { useNavigation } from '@react-navigation/native' import { useAtomValue } from 'jotai/utils' import React, { useEffect } from 'react' import { Text } from 'react-native' -import { artistInfoAtomFamily } from '../../state/music' -import text from '../../styles/text' -import ArtistArt from './ArtistArt' -import GradientScrollView from './GradientScrollView' +import { artistInfoAtomFamily } from '@app/state/music' +import text from '@app/styles/text' +import ArtistArt from '@app/components/ArtistArt' +import GradientScrollView from '@app/components/GradientScrollView' const ArtistDetails: React.FC<{ id: string }> = ({ id }) => { const artist = useAtomValue(artistInfoAtomFamily(id)) diff --git a/src/components/ArtistsList.tsx b/app/screens/ArtistsList.tsx similarity index 89% rename from src/components/ArtistsList.tsx rename to app/screens/ArtistsList.tsx index 7b43c45..1e3e874 100644 --- a/src/components/ArtistsList.tsx +++ b/app/screens/ArtistsList.tsx @@ -1,8 +1,8 @@ import React from 'react' import { FlatList, Text, View } from 'react-native' import { useAtomValue } from 'jotai/utils' -import { Artist } from '../models/music' -import { artistsAtom } from '../state/music' +import { Artist } from '@app/models/music' +import { artistsAtom } from '@app/state/music' const ArtistItem: React.FC<{ item: Artist }> = ({ item }) => ( diff --git a/src/components/library/AlbumsTab.tsx b/app/screens/LibraryAlbums.tsx similarity index 90% rename from src/components/library/AlbumsTab.tsx rename to app/screens/LibraryAlbums.tsx index e168d4c..d3f5d8d 100644 --- a/src/components/library/AlbumsTab.tsx +++ b/app/screens/LibraryAlbums.tsx @@ -2,11 +2,11 @@ import { useNavigation } from '@react-navigation/native' import { useAtomValue } from 'jotai/utils' import React, { useEffect } from 'react' import { Pressable, Text, View } from 'react-native' -import { Album } from '../../models/music' -import { albumsAtom, albumsUpdatingAtom, useUpdateAlbums } from '../../state/music' -import textStyles from '../../styles/text' -import AlbumArt from '../common/AlbumArt' -import GradientFlatList from '../common/GradientFlatList' +import { Album } from '@app/models/music' +import { albumsAtom, albumsUpdatingAtom, useUpdateAlbums } from '@app/state/music' +import textStyles from '@app/styles/text' +import AlbumArt from '@app/components/AlbumArt' +import GradientFlatList from '@app/components/GradientFlatList' const AlbumItem: React.FC<{ id: string diff --git a/src/components/library/ArtistsTab.tsx b/app/screens/LibraryArtists.tsx similarity index 88% rename from src/components/library/ArtistsTab.tsx rename to app/screens/LibraryArtists.tsx index 322e1fc..cb92fbe 100644 --- a/src/components/library/ArtistsTab.tsx +++ b/app/screens/LibraryArtists.tsx @@ -3,11 +3,11 @@ import { useAtomValue } from 'jotai/utils' import React, { useEffect } from 'react' import { Pressable } from 'react-native' import { Text } from 'react-native' -import { Artist } from '../../models/music' -import { artistsAtom, artistsUpdatingAtom, useUpdateArtists } from '../../state/music' -import textStyles from '../../styles/text' -import ArtistArt from '../common/ArtistArt' -import GradientFlatList from '../common/GradientFlatList' +import { Artist } from '@app/models/music' +import { artistsAtom, artistsUpdatingAtom, useUpdateArtists } from '@app/state/music' +import textStyles from '@app/styles/text' +import ArtistArt from '@app/components/ArtistArt' +import GradientFlatList from '@app/components/GradientFlatList' const ArtistItem: React.FC<{ item: Artist }> = ({ item }) => { const navigation = useNavigation() diff --git a/src/components/library/PlaylistsTab.tsx b/app/screens/LibraryPlaylists.tsx similarity index 60% rename from src/components/library/PlaylistsTab.tsx rename to app/screens/LibraryPlaylists.tsx index 6d668c7..a90ef90 100644 --- a/src/components/library/PlaylistsTab.tsx +++ b/app/screens/LibraryPlaylists.tsx @@ -1,5 +1,5 @@ import React from 'react' -import GradientBackground from '../common/GradientBackground' +import GradientBackground from '@app/components/GradientBackground' const PlaylistsTab = () => diff --git a/src/components/NowPlayingLayout.tsx b/app/screens/NowPlayingLayout.tsx similarity index 95% rename from src/components/NowPlayingLayout.tsx rename to app/screens/NowPlayingLayout.tsx index dfcd03a..1bea8e2 100644 --- a/src/components/NowPlayingLayout.tsx +++ b/app/screens/NowPlayingLayout.tsx @@ -18,13 +18,13 @@ import { usePlay, usePrevious, useProgress, -} from '../state/trackplayer' -import colors from '../styles/colors' -import { Font } from '../styles/text' -import { formatDuration } from '../util' -import CoverArt from './common/CoverArt' -import ImageGradientBackground from './common/ImageGradientBackground' -import PressableOpacity from './common/PressableOpacity' +} from '@app/state/trackplayer' +import colors from '@app/styles/colors' +import { Font } from '@app/styles/text' +import formatDuration from '@app/util/formatDuration' +import CoverArt from '@app/components/CoverArt' +import ImageGradientBackground from '@app/components/ImageGradientBackground' +import PressableOpacity from '@app/components/PressableOpacity' const NowPlayingHeader = () => { const queueName = useAtomValue(queueNameAtom) diff --git a/src/components/Settings.tsx b/app/screens/Settings.tsx similarity index 91% rename from src/components/Settings.tsx rename to app/screens/Settings.tsx index acac4a9..a63d8e3 100644 --- a/src/components/Settings.tsx +++ b/app/screens/Settings.tsx @@ -4,9 +4,9 @@ import md5 from 'md5' import React from 'react' import { Button, Text, View } from 'react-native' import { v4 as uuidv4 } from 'uuid' -import { appSettingsAtom } from '../state/settings' -import { getAllKeys, multiRemove } from '../storage/asyncstorage' -import text from '../styles/text' +import { appSettingsAtom } from '@app/state/settings' +import { getAllKeys, multiRemove } from '@app/storage/asyncstorage' +import text from '@app/styles/text' const TestControls = () => { const navigation = useNavigation() diff --git a/src/components/SplashPage.tsx b/app/screens/SplashPage.tsx similarity index 96% rename from src/components/SplashPage.tsx rename to app/screens/SplashPage.tsx index afcb2cd..63052d9 100644 --- a/src/components/SplashPage.tsx +++ b/app/screens/SplashPage.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react' import { Text, View } from 'react-native' import RNFS from 'react-native-fs' -import paths from '../paths' +import paths from '@app/util/paths' async function mkdir(path: string): Promise { const exists = await RNFS.exists(path) diff --git a/src/playback/service.ts b/app/service.ts similarity index 94% rename from src/playback/service.ts rename to app/service.ts index c281aa3..4de807f 100644 --- a/src/playback/service.ts +++ b/app/service.ts @@ -1,5 +1,5 @@ import TrackPlayer, { Event } from 'react-native-track-player' -import { trackPlayerCommands } from '../state/trackplayer' +import { trackPlayerCommands } from '@app/state/trackplayer' module.exports = async function () { TrackPlayer.addEventListener(Event.RemotePlay, () => trackPlayerCommands.enqueue(TrackPlayer.play)) diff --git a/src/state/music.ts b/app/state/music.ts similarity index 95% rename from src/state/music.ts rename to app/state/music.ts index 864ea3e..56e3f2e 100644 --- a/src/state/music.ts +++ b/app/state/music.ts @@ -1,10 +1,10 @@ import { atom, useAtom } from 'jotai' import { atomFamily, useAtomValue, useUpdateAtom } from 'jotai/utils' -import { Album, AlbumArt, AlbumWithSongs, Artist, ArtistArt, ArtistInfo, Song } from '../models/music' -import { SubsonicApiClient } from '../subsonic/api' -import { AlbumID3Element, ArtistInfo2Element, ChildElement } from '../subsonic/elements' -import { GetArtistResponse } from '../subsonic/responses' -import { activeServerAtom } from './settings' +import { Album, AlbumArt, AlbumWithSongs, Artist, ArtistArt, ArtistInfo, Song } from '@app/models/music' +import { SubsonicApiClient } from '@app/subsonic/api' +import { AlbumID3Element, ArtistInfo2Element, ChildElement } from '@app/subsonic/elements' +import { GetArtistResponse } from '@app/subsonic/responses' +import { activeServerAtom } from '@app/state/settings' export const artistsAtom = atom([]) export const artistsUpdatingAtom = atom(false) diff --git a/src/state/settings.ts b/app/state/settings.ts similarity index 71% rename from src/state/settings.ts rename to app/state/settings.ts index 2f0c474..8769659 100644 --- a/src/state/settings.ts +++ b/app/state/settings.ts @@ -1,6 +1,6 @@ import { atom } from 'jotai' -import { AppSettings } from '../models/settings' -import atomWithAsyncStorage from '../storage/atomWithAsyncStorage' +import { AppSettings } from '@app/models/settings' +import atomWithAsyncStorage from '@app/storage/atomWithAsyncStorage' export const appSettingsAtom = atomWithAsyncStorage('@appSettings', { servers: [], diff --git a/src/state/trackplayer.ts b/app/state/trackplayer.ts similarity index 98% rename from src/state/trackplayer.ts rename to app/state/trackplayer.ts index a9ca230..3e86f16 100644 --- a/src/state/trackplayer.ts +++ b/app/state/trackplayer.ts @@ -3,8 +3,8 @@ import { atom } from 'jotai' import { useAtomValue, useUpdateAtom } from 'jotai/utils' import { useEffect } from 'react' import TrackPlayer, { State, Track } from 'react-native-track-player' -import { Song } from '../models/music' -import { PromiseQueue } from '../util' +import { Song } from '@app/models/music' +import PromiseQueue from '@app/util/PromiseQueue' type TrackExt = Track & { id: string diff --git a/src/storage/asyncstorage.ts b/app/storage/asyncstorage.ts similarity index 100% rename from src/storage/asyncstorage.ts rename to app/storage/asyncstorage.ts diff --git a/src/storage/atomWithAsyncStorage.ts b/app/storage/atomWithAsyncStorage.ts similarity index 81% rename from src/storage/atomWithAsyncStorage.ts rename to app/storage/atomWithAsyncStorage.ts index dc1d496..7c9c547 100644 --- a/src/storage/atomWithAsyncStorage.ts +++ b/app/storage/atomWithAsyncStorage.ts @@ -1,5 +1,5 @@ import { atomWithStorage } from 'jotai/utils' -import { getItem, setItem } from './asyncstorage' +import { getItem, setItem } from '@app/storage/asyncstorage' export default (key: string, defaultValue: T) => { return atomWithStorage(key, defaultValue, { diff --git a/src/storage/music.ts b/app/storage/music.ts similarity index 88% rename from src/storage/music.ts rename to app/storage/music.ts index 9b8ebd6..c4b9924 100644 --- a/src/storage/music.ts +++ b/app/storage/music.ts @@ -1,5 +1,5 @@ -import { DownloadedSong } from '../models/music' -import { getItem, multiGet, multiSet } from './asyncstorage' +import { DownloadedSong } from '@app/models/music' +import { getItem, multiGet, multiSet } from '@app/storage/asyncstorage' const key = { downloadedSongKeys: '@downloadedSongKeys', diff --git a/src/styles/colors.ts b/app/styles/colors.ts similarity index 100% rename from src/styles/colors.ts rename to app/styles/colors.ts diff --git a/src/styles/text.ts b/app/styles/text.ts similarity index 96% rename from src/styles/text.ts rename to app/styles/text.ts index 23ef68e..d82175b 100644 --- a/src/styles/text.ts +++ b/app/styles/text.ts @@ -1,5 +1,5 @@ import { TextStyle } from 'react-native' -import colors from './colors' +import colors from '@app/styles/colors' export enum Font { regular = 'Metropolis-Regular', diff --git a/src/subsonic/api.ts b/app/subsonic/api.ts similarity index 96% rename from src/subsonic/api.ts rename to app/subsonic/api.ts index 5837058..60e70e8 100644 --- a/src/subsonic/api.ts +++ b/app/subsonic/api.ts @@ -11,7 +11,7 @@ import { GetIndexesParams, GetMusicDirectoryParams, StreamParams, -} from './params' +} from '@app/subsonic/params' import { GetAlbumList2Response, GetAlbumListResponse, @@ -23,10 +23,10 @@ import { GetIndexesResponse, GetMusicDirectoryResponse, SubsonicResponse, -} from './responses' -import { Server } from '../models/settings' -import paths from '../paths' -import { PromiseQueue } from '../util' +} from '@app/subsonic/responses' +import { Server } from '@app/models/settings' +import paths from '@app/util/paths' +import PromiseQueue from '@app/util/PromiseQueue' export class SubsonicApiError extends Error { method: string diff --git a/src/subsonic/elements.ts b/app/subsonic/elements.ts similarity index 100% rename from src/subsonic/elements.ts rename to app/subsonic/elements.ts diff --git a/src/hooks/subsonic.ts b/app/subsonic/hooks.ts similarity index 70% rename from src/hooks/subsonic.ts rename to app/subsonic/hooks.ts index 296354b..bffde41 100644 --- a/src/hooks/subsonic.ts +++ b/app/subsonic/hooks.ts @@ -1,6 +1,6 @@ import { useAtomValue } from 'jotai/utils' -import { activeServerAtom } from '../state/settings' -import { SubsonicApiClient } from '../subsonic/api' +import { activeServerAtom } from '@app/state/settings' +import { SubsonicApiClient } from '@app/subsonic/api' export const useSubsonicApi = () => { const activeServer = useAtomValue(activeServerAtom) diff --git a/src/subsonic/params.ts b/app/subsonic/params.ts similarity index 100% rename from src/subsonic/params.ts rename to app/subsonic/params.ts diff --git a/src/subsonic/responses.ts b/app/subsonic/responses.ts similarity index 99% rename from src/subsonic/responses.ts rename to app/subsonic/responses.ts index 32cd795..9d88e19 100644 --- a/src/subsonic/responses.ts +++ b/app/subsonic/responses.ts @@ -6,7 +6,7 @@ import { ArtistInfoElement, ChildElement, DirectoryElement, -} from './elements' +} from '@app/subsonic/elements' export type ResponseStatus = 'ok' | 'failed' diff --git a/src/util.ts b/app/util/PromiseQueue.ts similarity index 62% rename from src/util.ts rename to app/util/PromiseQueue.ts index 4ed7106..803bc8d 100644 --- a/src/util.ts +++ b/app/util/PromiseQueue.ts @@ -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 -export class PromiseQueue { +class PromiseQueue { maxSimultaneously: number private active = 0 @@ -39,3 +27,5 @@ export class PromiseQueue { } } } + +export default PromiseQueue diff --git a/app/util/formatDuration.ts b/app/util/formatDuration.ts new file mode 100644 index 0000000..fbbe987 --- /dev/null +++ b/app/util/formatDuration.ts @@ -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 diff --git a/src/paths.ts b/app/util/paths.ts similarity index 100% rename from src/paths.ts rename to app/util/paths.ts diff --git a/babel.config.js b/babel.config.js index 5d45acd..8de22c4 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,6 +1,16 @@ module.exports = { presets: ['module:metro-react-native-babel-preset'], 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 'react-native-reanimated/plugin', ], diff --git a/index.js b/index.js index 94c91f3..d553f10 100644 --- a/index.js +++ b/index.js @@ -5,12 +5,12 @@ import { enableScreens } from 'react-native-screens' enableScreens() import { AppRegistry } from 'react-native' -import App from './App' -import { name as appName } from './app.json' +import App from '@app/App' +import { name as appName } from '@app/app.json' import TrackPlayer, { Capability } from 'react-native-track-player' AppRegistry.registerComponent(appName, () => App) -TrackPlayer.registerPlaybackService(() => require('./src/playback/service')) +TrackPlayer.registerPlaybackService(() => require('./app/service')) async function start() { await TrackPlayer.setupPlayer() diff --git a/package.json b/package.json index aebebdd..747c2d8 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "@types/uuid": "^8.3.0", "@types/xmldom": "^0.1.30", "babel-jest": "^26.6.3", + "babel-plugin-module-resolver": "^4.1.0", "eslint": "^7.14.0", "jest": "^26.6.3", "metro-react-native-babel-preset": "^0.64.0", diff --git a/src/components/FocusableIcon.tsx b/src/components/FocusableIcon.tsx deleted file mode 100644 index f65b61a..0000000 --- a/src/components/FocusableIcon.tsx +++ /dev/null @@ -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 = props => { - props.focusedSource = props.focusedSource || props.source - props.width = props.width || 26 - props.height = props.height || 26 - - return ( - - ) -} - -export default FocusableIcon diff --git a/src/components/common/PressableImage.tsx b/src/components/common/PressableImage.tsx deleted file mode 100644 index 714d679..0000000 --- a/src/components/common/PressableImage.tsx +++ /dev/null @@ -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(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 ( - { - if (!disabled) { - setOpacity(0.4) - } - }} - onPressOut={() => { - if (!disabled) { - setOpacity(1) - } - }} - onLayout={event => setDimensions(event.nativeEvent.layout)}> - - - ) -} - -export default PressableImage diff --git a/src/components/common/TopTabContainer.tsx b/src/components/common/TopTabContainer.tsx deleted file mode 100644 index 45d7c26..0000000 --- a/src/components/common/TopTabContainer.tsx +++ /dev/null @@ -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 }) => ( - - {children} - -) - -export default TopTabContainer diff --git a/tsconfig.json b/tsconfig.json index b3c9eaa..5980290 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -36,8 +36,10 @@ /* Module Resolution Options */ "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, - // "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'. */ + "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + "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. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ diff --git a/yarn.lock b/yarn.lock index d50fa1c..541e606 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1765,6 +1765,17 @@ babel-plugin-jest-hoist@^26.6.2: "@types/babel__core" "^7.0.0" "@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: version "0.2.2" 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" 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: version "2.1.0" 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" 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: version "2.2.0" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" @@ -5314,6 +5338,13 @@ pkg-dir@^4.2.0: dependencies: 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: version "3.0.2" 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" 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: version "3.0.0" 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" 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" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==