mirror of
https://github.com/Stef-00012/Zipline-Android-App.git
synced 2025-05-11 18:35:58 +02:00
home
This commit is contained in:
parent
3b187b4ce4
commit
990f8ae017
8 changed files with 225 additions and 45 deletions
|
@ -25,8 +25,9 @@ export default function Layout() {
|
|||
/>
|
||||
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
<Header/>
|
||||
<Slot />
|
||||
<Header>
|
||||
<Slot />
|
||||
</Header>
|
||||
</SafeAreaView>
|
||||
</ShareIntentProvider>
|
||||
);
|
||||
|
|
159
app/index.tsx
159
app/index.tsx
|
@ -1,12 +1,25 @@
|
|||
import type { APIRecentFiles, APISelfUser, APIUserStats } from "@/types/zipline";
|
||||
import { getRecentFiles, getCurrentUser } from "@/functions/zipline/user";
|
||||
import { Text, View, TextInput, Pressable } from "react-native";
|
||||
import { Table, Row, Rows } from "react-native-table-component";
|
||||
import { useShareIntentContext } from "expo-share-intent";
|
||||
import { getUserStats } from "@/functions/zipline/stats";
|
||||
import { useEffect, useState } from "react";
|
||||
import * as db from "@/functions/database";
|
||||
import { useRouter } from "expo-router";
|
||||
import { styles } from "@/styles/home";
|
||||
import bytes from "bytes";
|
||||
import type {
|
||||
APIRecentFiles,
|
||||
APISelfUser,
|
||||
APIUserStats,
|
||||
} from "@/types/zipline";
|
||||
import {
|
||||
Text,
|
||||
View,
|
||||
TextInput,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
Image,
|
||||
} from "react-native";
|
||||
|
||||
export default function Home() {
|
||||
const router = useRouter();
|
||||
|
@ -31,23 +44,8 @@ export default function Home() {
|
|||
const [stats, setStats] = useState<APIUserStats | null>();
|
||||
const [recentFiles, setRecentFiles] = useState<APIRecentFiles | null>();
|
||||
|
||||
const mainContainerStyles = user ? {
|
||||
...styles.mainContainer
|
||||
} : {
|
||||
...styles.mainContainer,
|
||||
marginTop: 0
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const user = await getCurrentUser();
|
||||
const stats = await getUserStats();
|
||||
const recentFiles = await getRecentFiles();
|
||||
|
||||
setUser(user);
|
||||
setStats(stats);
|
||||
setRecentFiles(recentFiles);
|
||||
})();
|
||||
handleLogin();
|
||||
}, []);
|
||||
|
||||
async function handleLogin() {
|
||||
|
@ -61,13 +59,126 @@ export default function Home() {
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={mainContainerStyles}>
|
||||
<View style={styles.mainContainer}>
|
||||
{url && token ? (
|
||||
<View style={{flex:1}}>
|
||||
{user ? (
|
||||
<View>
|
||||
<Text style={{color: "#fff"}}>{user.username}</Text>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{user && stats && recentFiles ? (
|
||||
<ScrollView>
|
||||
<View>
|
||||
<Text style={styles.headerText}>Recent Files</Text>
|
||||
<ScrollView horizontal style={styles.scrollView}>
|
||||
{recentFiles.map((file) => (
|
||||
<View key={file.id} style={styles.recentFileContainer}>
|
||||
<Image
|
||||
key={file.id}
|
||||
// src={`${url}/raw${file.url}`}
|
||||
source={{
|
||||
uri: `${url}/raw${file.url}`,
|
||||
}}
|
||||
alt={file.originalName || file.name}
|
||||
width={200}
|
||||
height={200}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<Text style={styles.headerText}>Stats</Text>
|
||||
<ScrollView
|
||||
horizontal
|
||||
style={{
|
||||
...styles.scrollView,
|
||||
...styles.statsContainer,
|
||||
}}
|
||||
>
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>Files Uploaded:</Text>
|
||||
<Text style={styles.statText}>{stats.filesUploaded}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>Favorite Files:</Text>
|
||||
<Text style={styles.statText}>{stats.favoriteFiles}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>Storage Used:</Text>
|
||||
<Text style={styles.statText}>
|
||||
{bytes(stats.storageUsed, {
|
||||
unitSeparator: " ",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>
|
||||
Average Storage Used:
|
||||
</Text>
|
||||
<Text style={styles.statText}>
|
||||
{bytes(stats.avgStorageUsed, {
|
||||
unitSeparator: " ",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>File Views:</Text>
|
||||
<Text style={styles.statText}>{stats.views}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>
|
||||
File Average Views:
|
||||
</Text>
|
||||
<Text style={styles.statText}>
|
||||
{Math.round(stats.avgViews)}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>Links Created:</Text>
|
||||
<Text style={styles.statText}>{stats.urlsCreated}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>Total Link View:</Text>
|
||||
<Text style={styles.statText}>{stats.urlViews}</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<Text style={styles.headerText}>File Types</Text>
|
||||
<View
|
||||
style={{
|
||||
...styles.scrollView,
|
||||
...styles.fileTypesContainer,
|
||||
}}
|
||||
>
|
||||
<Table>
|
||||
<Row
|
||||
data={["File Type", "Count"]}
|
||||
widthArr={[250, 150]}
|
||||
textStyle={styles.tableHeadText}
|
||||
/>
|
||||
<Rows
|
||||
data={Object.entries(stats.sortTypeCount).sort(
|
||||
(a, b) => b[1] - a[1],
|
||||
)}
|
||||
widthArr={[250, 150]}
|
||||
textStyle={styles.tableText}
|
||||
/>
|
||||
</Table>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
|
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
@ -1,30 +1,36 @@
|
|||
import { getCurrentUser, getCurrentUserAvatar } from "@/functions/zipline/user";
|
||||
import { type PropsWithChildren, useEffect, useRef, useState } from "react";
|
||||
import { Stack, IconButton } from "@react-native-material/core";
|
||||
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
|
||||
import { View, Text, Pressable, Image } from "react-native";
|
||||
import type { APISelfUser } from "@/types/zipline";
|
||||
import { useEffect, useState } from "react";
|
||||
import { styles } from "@/styles/header";
|
||||
import type React from "react";
|
||||
|
||||
export default function Header() {
|
||||
export default function Header({ children }: PropsWithChildren) {
|
||||
const [avatar, setAvatar] = useState<string | null>(null);
|
||||
const [user, setUser] = useState<APISelfUser | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const avatar = await getCurrentUserAvatar();
|
||||
const user = await getCurrentUser();
|
||||
|
||||
setAvatar(avatar);
|
||||
setUser(user);
|
||||
})();
|
||||
});
|
||||
if (!avatar || !user) {
|
||||
(async () => {
|
||||
const avatar = await getCurrentUserAvatar();
|
||||
const user = await getCurrentUser();
|
||||
|
||||
setAvatar(avatar);
|
||||
setUser(user);
|
||||
})();
|
||||
}
|
||||
}, [avatar, user]);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.headerContainer}>
|
||||
{avatar && user ? (
|
||||
<View>
|
||||
<View
|
||||
style={{
|
||||
marginBottom: 70
|
||||
}}
|
||||
>
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerLeft}>
|
||||
<IconButton
|
||||
|
@ -61,6 +67,7 @@ export default function Header() {
|
|||
) : (
|
||||
<View />
|
||||
)}
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { APIFile, APIFiles, APISettings } from "@/types/zipline";
|
|||
import { getSettings } from "@/functions/zipline/settings";
|
||||
import type { Mimetypes } from "@/types/mimetypes";
|
||||
import * as db from "@/functions/database";
|
||||
import bytesFn from "bytes";
|
||||
import bytes from "bytes";
|
||||
import axios from "axios";
|
||||
|
||||
// GET /api/user/files
|
||||
|
@ -167,9 +167,9 @@ export async function uploadFile(
|
|||
|
||||
const settings = await getSettings();
|
||||
|
||||
const chunksMax = bytesFn(settings?.chunksMax || "95mb") || 95 * 1024 * 1024;
|
||||
const chunksMax = bytes(settings?.chunksMax || "95mb") || 95 * 1024 * 1024;
|
||||
const chunksSize =
|
||||
bytesFn(settings?.chunksSize || "25mb") || 25 * 1024 * 1024;
|
||||
bytes(settings?.chunksSize || "25mb") || 25 * 1024 * 1024;
|
||||
|
||||
const headers: {
|
||||
[key: string]: string;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"start:dev": "expo start --dev-client",
|
||||
"prebuild": "expo prebuild --no-install --clean",
|
||||
"run:android": "expo run:android",
|
||||
"run:ios": "expo run:ios",
|
||||
|
@ -45,6 +46,7 @@
|
|||
"react-native-reanimated": "~3.16.1",
|
||||
"react-native-safe-area-context": "4.12.0",
|
||||
"react-native-screens": "~4.4.0",
|
||||
"react-native-table-component": "^1.2.2",
|
||||
"react-native-web": "~0.19.13",
|
||||
"react-native-webview": "13.12.5"
|
||||
},
|
||||
|
@ -53,6 +55,7 @@
|
|||
"@types/bytes": "^3.1.5",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/react": "~18.3.12",
|
||||
"@types/react-native-table-component": "^1.2.8",
|
||||
"@types/react-test-renderer": "^18.3.0",
|
||||
"jest": "^29.2.1",
|
||||
"jest-expo": "~52.0.3",
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { StyleSheet } from "react-native";
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
headerContainer: {
|
||||
flex: 1
|
||||
},
|
||||
header: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
|
@ -39,6 +42,7 @@ export const styles = StyleSheet.create({
|
|||
userMenuContainer: {
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "row",
|
||||
marginRight: 5
|
||||
},
|
||||
userMenuAvatar: {
|
||||
borderRadius: 8
|
||||
|
|
|
@ -4,19 +4,18 @@ export const styles = StyleSheet.create({
|
|||
mainContainer: {
|
||||
backgroundColor: "#0c101c",
|
||||
flex: 1,
|
||||
marginTop: 50
|
||||
},
|
||||
loadingContainer: {
|
||||
flex: 1,
|
||||
display: "flex"
|
||||
display: "flex",
|
||||
flex: 1
|
||||
},
|
||||
loadingText: {
|
||||
fontSize: 40,
|
||||
fontWeight: "bold",
|
||||
margin: "auto",
|
||||
color: "#304270",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
color: "#304270",
|
||||
},
|
||||
loginContainer: {
|
||||
display: "flex",
|
||||
|
@ -55,5 +54,60 @@ export const styles = StyleSheet.create({
|
|||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
color: "white"
|
||||
},
|
||||
scrollView: {
|
||||
marginTop: 15,
|
||||
borderStyle: "solid",
|
||||
borderWidth: 2,
|
||||
borderColor: "#222c47",
|
||||
marginHorizontal: 10,
|
||||
borderRadius: 15,
|
||||
padding: 15
|
||||
},
|
||||
recentFileContainer: {
|
||||
marginHorizontal: 10,
|
||||
},
|
||||
statsContainer: {
|
||||
paddingHorizontal: 7
|
||||
},
|
||||
headerText: {
|
||||
marginTop: 5,
|
||||
marginLeft: 10,
|
||||
fontSize: 23,
|
||||
fontWeight: "bold",
|
||||
color: "white"
|
||||
},
|
||||
subHeaderText: {
|
||||
fontSize: 18,
|
||||
fontWeight: "bold",
|
||||
color: "gray"
|
||||
},
|
||||
statText: {
|
||||
marginTop: 5,
|
||||
fontSize: 32,
|
||||
fontWeight: "bold",
|
||||
color: "white"
|
||||
},
|
||||
statContainer: {
|
||||
borderWidth: 2,
|
||||
borderColor: "#222c47",
|
||||
borderStyle: "solid",
|
||||
borderRadius: 10,
|
||||
padding: 10,
|
||||
marginHorizontal: 4
|
||||
},
|
||||
tableText: {
|
||||
color: "white",
|
||||
fontSize: 16,
|
||||
marginHorizontal: 10
|
||||
},
|
||||
fileTypesContainer: {
|
||||
marginBottom: 10,
|
||||
},
|
||||
tableHeadText: {
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
fontSize: 16,
|
||||
marginHorizontal: 10
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue