Skip to content

Commit f381254

Browse files
authored
✨ (expo): Basic mobile file browser (#758)
* small stylistic changes * try fix prisma dates * add glitchtip for crash reports, fix bad suspense in flashlist header * fix colors for progress in reading now * improve android dark search colors * wip: file browsing * fix route stack issues for files * icons and tweaks * OPDS tweaks * add root attribution * add click route for books in files * make home header big for iOS
1 parent e01ed33 commit f381254

File tree

64 files changed

+882
-301
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+882
-301
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Stump is a free and open source comics, manga and digital book server with OPDS
4141
- [Packages](#packages)
4242
- [Similar Projects 👯](#similar-projects-)
4343
- [License 📝](#license-)
44+
- [Attribution](#attribution)
4445
</details>
4546

4647
> **🚧 Disclaimer 🚧**: Stump is under active development and is an ongoing **WIP**. Anyone is welcome to try it out, but **DO NOT** expect a fully featured or bug-free experience. If you'd like to contribute and help expedite feature development, please review the [developer guide](#developer-guide-).
@@ -201,3 +202,8 @@ There are a number of other projects that are similar to Stump, it certainly isn
201202
## License 📝
202203

203204
Stump is broken up into a number of different packages and applications. Some of these have their own licenses. For example, the `expo` app is licensed under [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.html). If a package has its own license, it will be noted in the package's README or LICENSE file. In such cases, the license file(s) in the subfolder/package take precedence. If such a license or disclaimer is not present, it is safe to assume that the code is licensed under the [MIT License](https://www.tldrlegal.com/license/mit-license).
205+
206+
## Attribution
207+
208+
- Some of the icons used in the web and mobile applications are from the [Spacedrive](https://github.com/spacedriveapp/spacedrive/tree/main/packages/assets/icons) repository, and are licensed under the [AGPL-3.0](<https://www.tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)>) license.
209+
- The `job` crate could not be possible without the work of other open source projects which had a significant influence on the design and implementation. See the [corresponding section](core/README.md#license-) in the `core` crate for more information.

apps/expo/app.config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ export default ({ config }: ConfigContext): ExpoConfig => {
108108
// createDensityFolders: false,
109109
// },
110110
// ],
111+
[
112+
'@sentry/react-native/expo',
113+
{
114+
url: 'https://app.glitchtip.com/',
115+
project: 'stump-expo',
116+
organization: 'stumpapp',
117+
},
118+
],
111119
],
112120
owner: 'stumpapp',
113121
experiments: {

apps/expo/app/opds/[id]/index.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,7 @@ export default function Screen() {
9595
refreshControl={<RefreshControl refreshing={isRefetching} onRefresh={refetch} />}
9696
contentInsetAdjustmentBehavior="automatic"
9797
>
98-
<View className="flex-1 gap-6 tablet:gap-8">
99-
<Heading size="lg" className="mt-6">
100-
{activeServer?.name || 'OPDS Feed'}
101-
</Heading>
102-
98+
<View className="mt-6 flex-1 gap-6 tablet:gap-8">
10399
<OPDSNavigation navigation={feed.navigation} renderEmpty />
104100

105101
{navGroups.map((group) => (

apps/expo/app/server/[id]/(tabs)/_layout.tsx

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
import { useAuthQuery, useClientContext, useSDK } from '@stump/client'
22
import { isAxiosError } from 'axios'
3-
import { Tabs, useRouter } from 'expo-router'
3+
import { Tabs } from 'expo-router'
44
import { useEffect } from 'react'
5-
import { View } from 'react-native'
6-
import { Pressable } from 'react-native-gesture-handler'
75

86
import { icons } from '~/components/ui'
97
import { useColors } from '~/lib/constants'
108
import { cn } from '~/lib/utils'
119
import { usePreferencesStore, useUserStore } from '~/stores'
1210

13-
const { Unplug, Home, SquareLibrary, Search } = icons
11+
const { Home, SquareLibrary, Search } = icons
1412

1513
export default function TabLayout() {
1614
const { sdk } = useSDK()
1715

1816
const colors = useColors()
19-
const router = useRouter()
2017
const animationEnabled = usePreferencesStore((state) => !state.reduceAnimations)
2118
const setUser = useUserStore((state) => state.setUser)
2219

@@ -55,20 +52,7 @@ export default function TabLayout() {
5552
tabBarIcon: ({ focused }) => (
5653
<Home className={cn('h-6 w-6 text-foreground-muted', { 'text-foreground': focused })} />
5754
),
58-
headerLeft: () => (
59-
<Pressable onPress={() => router.dismissAll()}>
60-
{({ pressed }) => (
61-
<View
62-
className={cn(
63-
'aspect-square flex-1 items-start justify-center px-2',
64-
pressed && 'opacity-70',
65-
)}
66-
>
67-
<Unplug size={20} className="text-foreground-muted" />
68-
</View>
69-
)}
70-
</Pressable>
71-
),
55+
headerShown: false,
7256
}}
7357
/>
7458

apps/expo/app/server/[id]/(tabs)/browse/_layout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ export default function Layout() {
1212
headerTransparent: Platform.OS === 'ios',
1313
headerBlurEffect: 'regular',
1414
headerLargeTitle: true,
15+
headerLargeTitleStyle: {
16+
fontSize: 30,
17+
},
1518
}}
1619
/>
1720
</Stack>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Stack, useRouter } from 'expo-router'
2+
import { Unplug } from 'lucide-react-native'
3+
import { Platform, View } from 'react-native'
4+
import { Pressable } from 'react-native-gesture-handler'
5+
6+
import { Icon } from '~/components/ui/icon'
7+
import { cn } from '~/lib/utils'
8+
import { usePreferencesStore } from '~/stores'
9+
10+
export default function Layout() {
11+
const animationEnabled = usePreferencesStore((state) => !state.reduceAnimations)
12+
13+
const router = useRouter()
14+
15+
return (
16+
<Stack screenOptions={{ headerShown: false }}>
17+
<Stack.Screen
18+
name="index"
19+
options={{
20+
headerShown: true,
21+
headerTitle: 'Home',
22+
headerTransparent: Platform.OS === 'ios',
23+
headerLargeTitleStyle: {
24+
fontSize: 30,
25+
},
26+
headerLargeTitle: true,
27+
headerBlurEffect: 'regular',
28+
animation: animationEnabled ? 'default' : 'none',
29+
headerLeft: () => (
30+
<Pressable onPress={() => router.dismissAll()}>
31+
{({ pressed }) => (
32+
<View
33+
className={cn('aspect-square flex-1 items-start justify-center', {
34+
'mr-4': Platform.OS === 'android',
35+
})}
36+
style={{ opacity: pressed ? 0.6 : 1 }}
37+
>
38+
<Icon as={Unplug} size={20} className="text-foreground-muted" />
39+
</View>
40+
)}
41+
</Pressable>
42+
),
43+
}}
44+
/>
45+
</Stack>
46+
)
47+
}

apps/expo/app/server/[id]/(tabs)/index.tsx renamed to apps/expo/app/server/[id]/(tabs)/index/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ export default function Screen() {
1313
const client = useQueryClient()
1414
const onRefresh = useCallback(async () => {
1515
setRefreshing(true)
16-
await client.invalidateQueries({ queryKey: ['continueReading'], exact: false })
16+
await Promise.all([
17+
client.invalidateQueries({ queryKey: ['continueReading'], exact: false }),
18+
client.invalidateQueries({ queryKey: ['onDeck'], exact: false }),
19+
client.invalidateQueries({ queryKey: ['recentlyAddedBooks'], exact: false }),
20+
client.invalidateQueries({ queryKey: ['recentlyAddedSeries'], exact: false }),
21+
])
1722
setRefreshing(false)
18-
}, [])
23+
}, [client])
1924

2025
return (
2126
<ScrollView

apps/expo/app/server/[id]/(tabs)/search/index.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { NativeSyntheticEvent } from 'react-native'
99

1010
import { useActiveServer } from '~/components/activeServer'
1111
import { Text } from '~/components/ui'
12+
import { useColors } from '~/lib/constants'
1213

1314
import { prefetchBookSearch } from '../../books/search[q]'
1415

@@ -36,6 +37,7 @@ export default function Screen() {
3637
[sdk, client],
3738
)
3839
const setQuery = debounce(onSearchChange, 200)
40+
const colors = useColors()
3941

4042
const onSearch = useCallback(() => {
4143
if (!searchQuery) return
@@ -60,9 +62,13 @@ export default function Screen() {
6062
setQuery(e.nativeEvent.text),
6163
shouldShowHintSearchIcon: true,
6264
onSearchButtonPress: () => onSearch(),
65+
headerIconColor: colors.foreground.subtle,
66+
hintTextColor: colors.foreground.muted,
67+
tintColor: colors.fill.danger.DEFAULT,
68+
textColor: colors.foreground.DEFAULT,
6369
},
6470
})
65-
}, [navigation, setQuery])
71+
}, [navigation, setQuery, onSearch, colors])
6672

6773
return (
6874
<View className="flex-1 items-center justify-center gap-4 bg-background p-4 tablet:p-7">

apps/expo/app/server/[id]/books/_layout.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { Stack, useNavigation, useRouter } from 'expo-router'
1+
import { Stack, useNavigation } from 'expo-router'
22
import { Platform } from 'react-native'
3-
import { icons } from '~/lib'
43

4+
import { icons } from '~/lib'
55
import { usePreferencesStore } from '~/stores'
66

77
const { ChevronLeft } = icons
88

99
export default function Screen() {
1010
const animationEnabled = usePreferencesStore((state) => !state.reduceAnimations)
11-
const router = useRouter()
1211
const navigation = useNavigation()
1312

1413
return (

apps/expo/app/server/[id]/books/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FlashList } from '@shopify/flash-list'
22
import { useInfiniteSuspenseGraphQL } from '@stump/client'
33
import { graphql } from '@stump/graphql'
4-
import { useCallback, useRef } from 'react'
4+
import { Suspense, useCallback, useRef } from 'react'
55
import { Platform } from 'react-native'
66
import { SafeAreaView } from 'react-native-safe-area-context'
77
import { useStore } from 'zustand'
@@ -90,7 +90,11 @@ export default function Screen() {
9090
onEndReachedThreshold={0.75}
9191
onEndReached={onEndReached}
9292
contentInsetAdjustmentBehavior="automatic"
93-
ListHeaderComponent={<BookFilterHeader />}
93+
ListHeaderComponent={() => (
94+
<Suspense fallback={null}>
95+
<BookFilterHeader />
96+
</Suspense>
97+
)}
9498
ListHeaderComponentStyle={{ paddingBottom: 16 }}
9599
refreshControl={<RefreshControl refreshing={isRefetching} onRefresh={refetch} />}
96100
/>

0 commit comments

Comments
 (0)