mirror of
https://github.com/Stef-00012/Zipline-Android-App.git
synced 2025-05-10 18:05:52 +02:00
optimize a bit code, re-order imports
This commit is contained in:
parent
7336de10f6
commit
044de8ce34
36 changed files with 1368 additions and 1040 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -35,7 +35,10 @@ yarn-error.*
|
|||
# typescript
|
||||
*.tsbuildinfo
|
||||
|
||||
# expo prebuild
|
||||
/android
|
||||
/ios
|
||||
|
||||
# misc
|
||||
biome.json
|
||||
package-lock.json
|
10
README.md
10
README.md
|
@ -36,12 +36,4 @@ This will create an apk but won't automatically install
|
|||
# TODO
|
||||
|
||||
- [x] Fix keyboard covering TOTP input on login screen
|
||||
- [ ] Optimize pages by re-rendering only the components that use certain variables and not other unrelated components (~~this is not Spotify~~)
|
||||
- app/(app)/admin/invites.ts: remove useless settings fetch, move header out of the condition
|
||||
- app/(app)/admin/settings.ts: re-render individual selects/inputs/switchs instead of the whole page, move header out of the condition
|
||||
- app/(app)/admin/users.ts: remove useless settings fetch, move header out of the condition
|
||||
- app/(app)/folders.ts: move header out of the condition
|
||||
- app/(app)/metrics.ts: move header out of the condition
|
||||
- app/(app)/settings.ts: re-render individual selects/inputs/switchs instead of the whole page, move header out of the condition
|
||||
- app/(app)/urls.ts: move header out of the condition
|
||||
- app/index.ts: move header out of the condition
|
||||
- [x] Optimize pages by re-rendering only the components that use certain variables and not other unrelated components (~~this is not Spotify~~)
|
|
@ -1,11 +1,10 @@
|
|||
import type { ExpoConfig, ConfigContext } from "expo/config";
|
||||
|
||||
const IS_DEV = process.env.APP_VARIANT === "development";
|
||||
const IS_RELEASE = process.env.APP_VARIANT === "devrelease";
|
||||
|
||||
export default ({ config }: ConfigContext): ExpoConfig => ({
|
||||
...config,
|
||||
name: `Zipline${IS_DEV ? " (Dev)" : IS_RELEASE ? " (Dev Release)" : ""}`,
|
||||
name: `Zipline${IS_DEV ? " (Dev)" : ""}`,
|
||||
slug: "zipline",
|
||||
version: "1.0.2",
|
||||
orientation: "portrait",
|
||||
|
@ -15,7 +14,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
|
|||
userInterfaceStyle: "automatic",
|
||||
platforms: ["android"],
|
||||
ios: {
|
||||
bundleIdentifier: `com.stefdp.zipline${IS_DEV ? ".dev" : IS_RELEASE ? ".devrelease" : ""}`
|
||||
bundleIdentifier: `com.stefdp.zipline${IS_DEV ? ".dev" : ""}`,
|
||||
},
|
||||
android: {
|
||||
adaptiveIcon: {
|
||||
|
@ -23,7 +22,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
|
|||
monochromeImage: "./assets/images/monochromatic-adaptive-icon.png",
|
||||
backgroundColor: "#121317",
|
||||
},
|
||||
package: `com.stefdp.zipline${IS_DEV ? ".dev" : IS_RELEASE ? ".devrelease" : ""}`
|
||||
package: `com.stefdp.zipline${IS_DEV ? ".dev" : ""}`,
|
||||
},
|
||||
androidStatusBar: {
|
||||
barStyle: "light-content",
|
||||
|
|
|
@ -468,7 +468,10 @@ export default function Files() {
|
|||
}}
|
||||
icon={favorites ? "star" : "star-border"}
|
||||
color="transparent"
|
||||
iconColor={favorites ? "#f1d01f" : "#2d3f70"}
|
||||
iconColor={favorites
|
||||
? files ? "#f1d01f" : "#f1d01f55"
|
||||
: files ? "#2d3f70" : "#2d3f7055"
|
||||
}
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
|
@ -489,7 +492,7 @@ export default function Files() {
|
|||
}}
|
||||
icon="sell"
|
||||
color="transparent"
|
||||
iconColor="#2d3f70"
|
||||
iconColor={files ? "#2d3f70" : "#2d3f7055"}
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
|
@ -508,7 +511,7 @@ export default function Files() {
|
|||
}}
|
||||
icon="upload-file"
|
||||
color="transparent"
|
||||
iconColor="#2d3f70"
|
||||
iconColor={files ? "#2d3f70" : "#2d3f7055"}
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { ScrollView, Text, View, ToastAndroid } from "react-native";
|
||||
import { getSettings } from "@/functions/zipline/settings";
|
||||
import { Row, Table } from "react-native-reanimated-table";
|
||||
import { useShareIntent } from "@/hooks/useShareIntent";
|
||||
import { timeDifference } from "@/functions/util";
|
||||
|
@ -20,7 +19,6 @@ import {
|
|||
} from "@/functions/zipline/invites";
|
||||
import type {
|
||||
APIInvites,
|
||||
APISettings,
|
||||
DashURL,
|
||||
} from "@/types/zipline";
|
||||
|
||||
|
@ -29,7 +27,6 @@ export default function Invites() {
|
|||
useShareIntent();
|
||||
|
||||
const [invites, setInvites] = useState<APIInvites | null>(null);
|
||||
const [settings, setSettings] = useState<APISettings | null>(null);
|
||||
|
||||
const [createNewInvite, setCreateNewInvite] = useState<boolean>(false);
|
||||
|
||||
|
@ -43,10 +40,8 @@ export default function Invites() {
|
|||
useEffect(() => {
|
||||
(async () => {
|
||||
const invites = await getInvites();
|
||||
const settings = await getSettings();
|
||||
|
||||
setInvites(typeof invites === "string" ? null : invites);
|
||||
setSettings(typeof settings === "string" ? null : settings);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
|
@ -136,28 +131,30 @@ export default function Invites() {
|
|||
</View>
|
||||
</Popup>
|
||||
|
||||
{invites && settings && dashUrl ? (
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Invites</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewInvite(true);
|
||||
}}
|
||||
icon="add"
|
||||
color="transparent"
|
||||
iconColor="#2d3f70"
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Invites</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewInvite(true);
|
||||
}}
|
||||
icon="add"
|
||||
color="transparent"
|
||||
// iconColor="#2d3f70"
|
||||
iconColor={(invites && dashUrl) ? "#2d3f70" : "#2d3f7055"}
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
disabled={!invites || !dashUrl}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ ...styles.invitesContainer, flex: 1 }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={{ ...styles.invitesContainer, flex: 1 }}>
|
||||
{invites && dashUrl ? (
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
|
@ -337,13 +334,13 @@ export default function Invites() {
|
|||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
|
|
@ -635,22 +635,22 @@ export default function ServerSettings() {
|
|||
return (
|
||||
<View style={styles.mainContainer}>
|
||||
<View style={styles.mainContainer}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Server Settings</Text>
|
||||
|
||||
{saveError && (
|
||||
<View>
|
||||
{saveError.map((error) => (
|
||||
<Text style={styles.errorText} key={error}>
|
||||
{error}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{settings ? (
|
||||
<View style={styles.settingsContainer}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Server Settings</Text>
|
||||
|
||||
{saveError && (
|
||||
<View>
|
||||
{saveError.map((error) => (
|
||||
<Text style={styles.errorText} key={error}>
|
||||
{error}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<KeyboardAwareScrollView style={styles.scrollView}>
|
||||
{/* Core */}
|
||||
<View style={styles.settingGroup}>
|
||||
|
|
|
@ -2,7 +2,6 @@ import { ScrollView, Text, View, ToastAndroid } from "react-native";
|
|||
import { getFileDataURI, timeDifference } from "@/functions/util";
|
||||
import { fileQuotaTypes, userRoles } from "@/constants/users";
|
||||
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
|
||||
import { getSettings } from "@/functions/zipline/settings";
|
||||
import { Row, Table } from "react-native-reanimated-table";
|
||||
import { useShareIntent } from "@/hooks/useShareIntent";
|
||||
import * as DocumentPicker from "expo-document-picker";
|
||||
|
@ -25,7 +24,6 @@ import {
|
|||
getUsers,
|
||||
} from "@/functions/zipline/users";
|
||||
import type {
|
||||
APISettings,
|
||||
APIUser,
|
||||
APIUserQuota,
|
||||
APIUsersNoIncl,
|
||||
|
@ -37,7 +35,6 @@ export default function Users() {
|
|||
useShareIntent();
|
||||
|
||||
const [users, setUsers] = useState<APIUsersNoIncl | null>(null);
|
||||
const [settings, setSettings] = useState<APISettings | null>(null);
|
||||
|
||||
const [userToEdit, setUserToEdit] = useState<APIUsersNoIncl[0] | null>(null);
|
||||
|
||||
|
@ -88,10 +85,8 @@ export default function Users() {
|
|||
useEffect(() => {
|
||||
(async () => {
|
||||
const users = await getUsers(true);
|
||||
const settings = await getSettings();
|
||||
|
||||
setUsers(typeof users === "string" ? null : users);
|
||||
setSettings(typeof settings === "string" ? null : settings);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
|
@ -651,190 +646,191 @@ export default function Users() {
|
|||
</View>
|
||||
</Popup>
|
||||
|
||||
{users && settings && dashUrl ? (
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Users</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewUser(true);
|
||||
}}
|
||||
icon="person-add"
|
||||
color="transparent"
|
||||
iconColor={(users && dashUrl) ? "#2d3f70" : "#2d3f7055"}
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
disabled={!users || !dashUrl}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Users</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewUser(true);
|
||||
}}
|
||||
icon="person-add"
|
||||
color="transparent"
|
||||
iconColor="#2d3f70"
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ ...styles.usersContainer, flex: 1 }}>
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
<Row
|
||||
data={[
|
||||
"Avatar",
|
||||
"Username",
|
||||
"Role",
|
||||
"Created",
|
||||
"Last Updated",
|
||||
"Actions",
|
||||
]}
|
||||
widthArr={[80, 100, 100, 130, 130, 130]}
|
||||
style={styles.tableHeader}
|
||||
textStyle={{
|
||||
...styles.rowText,
|
||||
...styles.headerRow,
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={styles.tableVerticalScroll}
|
||||
>
|
||||
{users && dashUrl ? (
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
{users.map((user, index) => {
|
||||
const avatar = user.avatar ? (
|
||||
<Image
|
||||
source={{ uri: user.avatar }}
|
||||
style={styles.userAvatar}
|
||||
alt={`${user.username}'s avatar`}
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.userAvatar}>
|
||||
<MaterialIcons
|
||||
name="person"
|
||||
size={30}
|
||||
color={"white"}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
const username = (
|
||||
<Text key={user.id} style={styles.rowText}>
|
||||
{user.username}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const role = (
|
||||
<Text key={user.id} style={styles.rowText}>
|
||||
{user.role.charAt(0).toUpperCase() +
|
||||
user.role.slice(1).toLowerCase()}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const created = (
|
||||
<Text style={styles.rowText}>
|
||||
{timeDifference(
|
||||
new Date(),
|
||||
new Date(user.createdAt),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const lastUpdated = (
|
||||
<Text style={styles.rowText}>
|
||||
{timeDifference(
|
||||
new Date(),
|
||||
new Date(user.updatedAt),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const actions = (
|
||||
<View style={styles.actionsContainer}>
|
||||
<Button
|
||||
icon="folder-open"
|
||||
color="#323ea8"
|
||||
onPress={async () => {
|
||||
const userId = user.id;
|
||||
|
||||
router.replace(`/files?id=${userId}`);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="edit"
|
||||
color="#323ea8"
|
||||
onPress={() => {
|
||||
const userId = user.id;
|
||||
|
||||
setUserToEdit(
|
||||
users.find((usr) => usr.id === userId) ||
|
||||
null,
|
||||
);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="delete"
|
||||
color="#CF4238"
|
||||
onPress={async () => {
|
||||
setUserToDelete(user);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
let rowStyle = styles.row;
|
||||
|
||||
if (index === 0)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.firstRow,
|
||||
};
|
||||
|
||||
if (index === users.length - 1)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.lastRow,
|
||||
};
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={user.id}
|
||||
data={[
|
||||
avatar,
|
||||
username,
|
||||
role,
|
||||
created,
|
||||
lastUpdated,
|
||||
actions,
|
||||
]}
|
||||
widthArr={[80, 100, 100, 130, 130, 130]}
|
||||
style={rowStyle}
|
||||
textStyle={styles.rowText}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<Row
|
||||
data={[
|
||||
"Avatar",
|
||||
"Username",
|
||||
"Role",
|
||||
"Created",
|
||||
"Last Updated",
|
||||
"Actions",
|
||||
]}
|
||||
widthArr={[80, 100, 100, 130, 130, 130]}
|
||||
style={styles.tableHeader}
|
||||
textStyle={{
|
||||
...styles.rowText,
|
||||
...styles.headerRow,
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
</ScrollView>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={styles.tableVerticalScroll}
|
||||
>
|
||||
<Table>
|
||||
{users.map((user, index) => {
|
||||
const avatar = user.avatar ? (
|
||||
<Image
|
||||
source={{ uri: user.avatar }}
|
||||
style={styles.userAvatar}
|
||||
alt={`${user.username}'s avatar`}
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.userAvatar}>
|
||||
<MaterialIcons
|
||||
name="person"
|
||||
size={30}
|
||||
color={"white"}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
const username = (
|
||||
<Text key={user.id} style={styles.rowText}>
|
||||
{user.username}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const role = (
|
||||
<Text key={user.id} style={styles.rowText}>
|
||||
{user.role.charAt(0).toUpperCase() +
|
||||
user.role.slice(1).toLowerCase()}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const created = (
|
||||
<Text style={styles.rowText}>
|
||||
{timeDifference(
|
||||
new Date(),
|
||||
new Date(user.createdAt),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const lastUpdated = (
|
||||
<Text style={styles.rowText}>
|
||||
{timeDifference(
|
||||
new Date(),
|
||||
new Date(user.updatedAt),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const actions = (
|
||||
<View style={styles.actionsContainer}>
|
||||
<Button
|
||||
icon="folder-open"
|
||||
color="#323ea8"
|
||||
onPress={async () => {
|
||||
const userId = user.id;
|
||||
|
||||
router.replace(`/files?id=${userId}`);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="edit"
|
||||
color="#323ea8"
|
||||
onPress={() => {
|
||||
const userId = user.id;
|
||||
|
||||
setUserToEdit(
|
||||
users.find((usr) => usr.id === userId) ||
|
||||
null,
|
||||
);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="delete"
|
||||
color="#CF4238"
|
||||
onPress={async () => {
|
||||
setUserToDelete(user);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
let rowStyle = styles.row;
|
||||
|
||||
if (index === 0)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.firstRow,
|
||||
};
|
||||
|
||||
if (index === users.length - 1)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.lastRow,
|
||||
};
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={user.id}
|
||||
data={[
|
||||
avatar,
|
||||
username,
|
||||
role,
|
||||
created,
|
||||
lastUpdated,
|
||||
actions,
|
||||
]}
|
||||
widthArr={[80, 100, 100, 130, 130, 130]}
|
||||
style={rowStyle}
|
||||
textStyle={styles.rowText}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
|
|
@ -107,230 +107,231 @@ export default function Folders() {
|
|||
</View>
|
||||
</Popup>
|
||||
|
||||
{folders && dashUrl ? (
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Folders</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewFolder(true);
|
||||
}}
|
||||
icon="create-new-folder"
|
||||
color="transparent"
|
||||
iconColor={(folders && dashUrl) ? "#2d3f70" : "#2d3f7055"}
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
disabled={!folders || !dashUrl}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Folders</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewFolder(true);
|
||||
}}
|
||||
icon="create-new-folder"
|
||||
color="transparent"
|
||||
iconColor="#2d3f70"
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ ...styles.foldersContainer, flex: 1 }}>
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
<Row
|
||||
data={["Name", "Public", "Created", "Actions"]}
|
||||
widthArr={[80, 50, 130, 150]}
|
||||
style={styles.tableHeader}
|
||||
textStyle={{
|
||||
...styles.rowText,
|
||||
...styles.headerRow,
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={styles.tableVerticalScroll}
|
||||
>
|
||||
{folders && dashUrl ? (
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
{folders.map((folder, index) => {
|
||||
const name = folder.public ? (
|
||||
<Link
|
||||
key={folder.id}
|
||||
href={
|
||||
`${dashUrl}/folder/${folder.id}` as ExternalPathString
|
||||
}
|
||||
style={{
|
||||
...styles.rowText,
|
||||
...styles.link,
|
||||
}}
|
||||
>
|
||||
{folder.name}
|
||||
</Link>
|
||||
) : (
|
||||
<Text key={folder.id} style={styles.rowText}>
|
||||
{folder.name}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const isPublic = (
|
||||
<Text key={folder.id} style={styles.rowText}>
|
||||
{folder.public ? "Yes" : "No"}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const created = (
|
||||
<Text style={styles.rowText}>
|
||||
{timeDifference(
|
||||
new Date(),
|
||||
new Date(folder.createdAt),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const actions = (
|
||||
<View style={styles.actionsContainer}>
|
||||
<Button
|
||||
icon="folder-open"
|
||||
color="#323ea8"
|
||||
onPress={() => {
|
||||
const folderId = folder.id;
|
||||
|
||||
router.replace(`/files?folderId=${folderId}`);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="content-copy"
|
||||
color={folder.public ? "#323ea8" : "#181c28"}
|
||||
iconColor={folder.public ? "white" : "#2a3952"}
|
||||
onPress={async () => {
|
||||
const urlDest = `${dashUrl}/folder/${folder.id}`;
|
||||
|
||||
const saved =
|
||||
await Clipboard.setStringAsync(urlDest);
|
||||
|
||||
if (saved)
|
||||
return ToastAndroid.show(
|
||||
"Folder URL copied to clipboard",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
return ToastAndroid.show(
|
||||
"Failed to paste to the clipboard",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
disabled={!folder.public}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onPress={async () => {
|
||||
const folderId = folder.id;
|
||||
|
||||
const success = await editFolder(
|
||||
folderId,
|
||||
!folder.public,
|
||||
);
|
||||
|
||||
if (typeof success === "string")
|
||||
return ToastAndroid.show(
|
||||
`Failed to update the folder "${folder.name}"`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
ToastAndroid.show(
|
||||
`Updated the folder "${folder.name}"'s visibility`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
const folderIndex = folders.findIndex(
|
||||
(fold) => folder.id === fold.id,
|
||||
);
|
||||
|
||||
const newFolders = [...folders];
|
||||
newFolders[folderIndex].public = !folder.public;
|
||||
|
||||
setFolders(newFolders);
|
||||
}}
|
||||
color={folder.public ? "#323ea8" : "#343a40"}
|
||||
icon={folder.public ? "lock-open" : "lock"}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onPress={async () => {
|
||||
const folderId = folder.id;
|
||||
|
||||
const success = await deleteFolder(folderId);
|
||||
|
||||
if (typeof success === "string")
|
||||
return ToastAndroid.show(
|
||||
`Failed to delete the folder "${folder.name}"`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
const newFolders = folders.filter(
|
||||
(fold) => fold.id !== folder.id,
|
||||
);
|
||||
|
||||
setFolders(newFolders);
|
||||
|
||||
ToastAndroid.show(
|
||||
`Deleted the folder "${folder.name}"`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
color="#CF4238"
|
||||
icon="delete"
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
let rowStyle = styles.row;
|
||||
|
||||
if (index === 0)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.firstRow,
|
||||
};
|
||||
|
||||
if (index === folders.length - 1)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.lastRow,
|
||||
};
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={folder.id}
|
||||
data={[name, isPublic, created, actions]}
|
||||
widthArr={[80, 50, 130, 150]}
|
||||
style={rowStyle}
|
||||
textStyle={styles.rowText}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<Row
|
||||
data={["Name", "Public", "Created", "Actions"]}
|
||||
widthArr={[80, 50, 130, 150]}
|
||||
style={styles.tableHeader}
|
||||
textStyle={{
|
||||
...styles.rowText,
|
||||
...styles.headerRow,
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
</ScrollView>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={styles.tableVerticalScroll}
|
||||
>
|
||||
<Table>
|
||||
{folders.map((folder, index) => {
|
||||
const name = folder.public ? (
|
||||
<Link
|
||||
key={folder.id}
|
||||
href={
|
||||
`${dashUrl}/folder/${folder.id}` as ExternalPathString
|
||||
}
|
||||
style={{
|
||||
...styles.rowText,
|
||||
...styles.link,
|
||||
}}
|
||||
>
|
||||
{folder.name}
|
||||
</Link>
|
||||
) : (
|
||||
<Text key={folder.id} style={styles.rowText}>
|
||||
{folder.name}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const isPublic = (
|
||||
<Text key={folder.id} style={styles.rowText}>
|
||||
{folder.public ? "Yes" : "No"}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const created = (
|
||||
<Text style={styles.rowText}>
|
||||
{timeDifference(
|
||||
new Date(),
|
||||
new Date(folder.createdAt),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const actions = (
|
||||
<View style={styles.actionsContainer}>
|
||||
<Button
|
||||
icon="folder-open"
|
||||
color="#323ea8"
|
||||
onPress={() => {
|
||||
const folderId = folder.id;
|
||||
|
||||
router.replace(`/files?folderId=${folderId}`);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="content-copy"
|
||||
color={folder.public ? "#323ea8" : "#181c28"}
|
||||
iconColor={folder.public ? "white" : "#2a3952"}
|
||||
onPress={async () => {
|
||||
const urlDest = `${dashUrl}/folder/${folder.id}`;
|
||||
|
||||
const saved =
|
||||
await Clipboard.setStringAsync(urlDest);
|
||||
|
||||
if (saved)
|
||||
return ToastAndroid.show(
|
||||
"Folder URL copied to clipboard",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
return ToastAndroid.show(
|
||||
"Failed to paste to the clipboard",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
disabled={!folder.public}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onPress={async () => {
|
||||
const folderId = folder.id;
|
||||
|
||||
const success = await editFolder(
|
||||
folderId,
|
||||
!folder.public,
|
||||
);
|
||||
|
||||
if (typeof success === "string")
|
||||
return ToastAndroid.show(
|
||||
`Failed to update the folder "${folder.name}"`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
ToastAndroid.show(
|
||||
`Updated the folder "${folder.name}"'s visibility`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
const folderIndex = folders.findIndex(
|
||||
(fold) => folder.id === fold.id,
|
||||
);
|
||||
|
||||
const newFolders = [...folders];
|
||||
newFolders[folderIndex].public = !folder.public;
|
||||
|
||||
setFolders(newFolders);
|
||||
}}
|
||||
color={folder.public ? "#323ea8" : "#343a40"}
|
||||
icon={folder.public ? "lock-open" : "lock"}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onPress={async () => {
|
||||
const folderId = folder.id;
|
||||
|
||||
const success = await deleteFolder(folderId);
|
||||
|
||||
if (typeof success === "string")
|
||||
return ToastAndroid.show(
|
||||
`Failed to delete the folder "${folder.name}"`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
const newFolders = folders.filter(
|
||||
(fold) => fold.id !== folder.id,
|
||||
);
|
||||
|
||||
setFolders(newFolders);
|
||||
|
||||
ToastAndroid.show(
|
||||
`Deleted the folder "${folder.name}"`,
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
color="#CF4238"
|
||||
icon="delete"
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
let rowStyle = styles.row;
|
||||
|
||||
if (index === 0)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.firstRow,
|
||||
};
|
||||
|
||||
if (index === folders.length - 1)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.lastRow,
|
||||
};
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={folder.id}
|
||||
data={[name, isPublic, created, actions]}
|
||||
widthArr={[80, 50, 130, 150]}
|
||||
style={rowStyle}
|
||||
textStyle={styles.rowText}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
|
|
@ -146,38 +146,42 @@ export default function Metrics() {
|
|||
/>
|
||||
</DatePicker>
|
||||
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Metrics</Text>
|
||||
|
||||
<Text style={styles.dateRangeText}>
|
||||
{allTime
|
||||
? "All Time"
|
||||
: `${new Date(
|
||||
range.startDate as string,
|
||||
).toLocaleDateString()}${
|
||||
range.endDate
|
||||
? ` to ${new Date(range.endDate as string).toLocaleDateString()}`
|
||||
: ""
|
||||
}`}
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
onPress={() => {
|
||||
setDatePickerOpen(true);
|
||||
}}
|
||||
color="transparent"
|
||||
text="Change Date Range"
|
||||
borderWidth={2}
|
||||
borderColor="#222c47"
|
||||
margin={{
|
||||
right: 10,
|
||||
top: 10,
|
||||
}}
|
||||
rippleColor="#283557"
|
||||
disabled={!filteredStats || !mainStat}
|
||||
textColor={(filteredStats && mainStat) ? "white" : "gray"}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{filteredStats && mainStat ? (
|
||||
<View>
|
||||
<ScrollView>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>Metrics</Text>
|
||||
<Text style={styles.dateRangeText}>
|
||||
{allTime
|
||||
? "All Time"
|
||||
: `${new Date(
|
||||
range.startDate as string,
|
||||
).toLocaleDateString()}${
|
||||
range.endDate
|
||||
? ` to ${new Date(range.endDate as string).toLocaleDateString()}`
|
||||
: ""
|
||||
}`}
|
||||
</Text>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setDatePickerOpen(true);
|
||||
}}
|
||||
color="transparent"
|
||||
text="Change Date Range"
|
||||
borderWidth={2}
|
||||
borderColor="#222c47"
|
||||
margin={{
|
||||
right: 10,
|
||||
top: 10,
|
||||
}}
|
||||
rippleColor="#283557"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<ScrollView
|
||||
horizontal
|
||||
style={{
|
||||
|
|
|
@ -470,67 +470,69 @@ export default function UserSettings() {
|
|||
</Text>
|
||||
</Popup>
|
||||
|
||||
{user && token && exports ? (
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>User Settings</Text>
|
||||
|
||||
{saveError && (
|
||||
<Text style={styles.errorText} key={saveError}>
|
||||
{saveError}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{user ? (
|
||||
<View style={styles.settingsContainer}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>User Settings</Text>
|
||||
|
||||
{saveError && (
|
||||
<Text style={styles.errorText} key={saveError}>
|
||||
{saveError}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<KeyboardAwareScrollView style={styles.scrollView}>
|
||||
{/* User Info */}
|
||||
<View style={styles.settingGroup}>
|
||||
<Text style={styles.headerText}>User Info</Text>
|
||||
<Text style={styles.subHeaderText}>{user.id}</Text>
|
||||
{token && (
|
||||
<View style={styles.settingGroup}>
|
||||
<Text style={styles.headerText}>User Info</Text>
|
||||
<Text style={styles.subHeaderText}>{user.id}</Text>
|
||||
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setTokenVisible(true);
|
||||
}}
|
||||
>
|
||||
<TextInput
|
||||
title="Token:"
|
||||
showDisabledStyle={false}
|
||||
disabled
|
||||
disableContext
|
||||
value={tokenVisible ? token : "[Click to Reveal]"}
|
||||
onSideButtonPress={() => {
|
||||
Clipboard.setStringAsync(token);
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setTokenVisible(true);
|
||||
}}
|
||||
sideButtonIcon="content-copy"
|
||||
>
|
||||
<TextInput
|
||||
title="Token:"
|
||||
showDisabledStyle={false}
|
||||
disabled
|
||||
disableContext
|
||||
value={tokenVisible ? token : "[Click to Reveal]"}
|
||||
onSideButtonPress={() => {
|
||||
Clipboard.setStringAsync(token);
|
||||
}}
|
||||
sideButtonIcon="content-copy"
|
||||
/>
|
||||
</Pressable>
|
||||
|
||||
<TextInput
|
||||
title="Username:"
|
||||
onValueChange={(content) => setUsername(content)}
|
||||
placeholder="My Cool Username"
|
||||
value={username || ""}
|
||||
/>
|
||||
</Pressable>
|
||||
|
||||
<TextInput
|
||||
title="Username:"
|
||||
onValueChange={(content) => setUsername(content)}
|
||||
placeholder="My Cool Username"
|
||||
value={username || ""}
|
||||
/>
|
||||
<TextInput
|
||||
title="Password:"
|
||||
onValueChange={(content) => setPassword(content)}
|
||||
placeholder="myPassword123"
|
||||
value={password || ""}
|
||||
password
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
title="Password:"
|
||||
onValueChange={(content) => setPassword(content)}
|
||||
placeholder="myPassword123"
|
||||
value={password || ""}
|
||||
password
|
||||
/>
|
||||
|
||||
<Button
|
||||
onPress={() => handleSave("userInfo")}
|
||||
color="#323ea8"
|
||||
text="Save"
|
||||
icon="save"
|
||||
margin={{
|
||||
top: 10,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<Button
|
||||
onPress={() => handleSave("userInfo")}
|
||||
color="#323ea8"
|
||||
text="Save"
|
||||
icon="save"
|
||||
margin={{
|
||||
top: 10,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* Avatar */}
|
||||
<View style={styles.settingGroup}>
|
||||
|
@ -781,247 +783,249 @@ export default function UserSettings() {
|
|||
</View>
|
||||
|
||||
{/* Export Files */}
|
||||
<View style={styles.settingGroup}>
|
||||
<Text style={styles.headerText}>Export Files</Text>
|
||||
{(exports && token) && (
|
||||
<View style={styles.settingGroup}>
|
||||
<Text style={styles.headerText}>Export Files</Text>
|
||||
|
||||
<Button
|
||||
onPress={async () => {
|
||||
const success = await createUserExport();
|
||||
<Button
|
||||
onPress={async () => {
|
||||
const success = await createUserExport();
|
||||
|
||||
if (typeof success === "string")
|
||||
return setSaveError(success);
|
||||
if (typeof success === "string")
|
||||
return setSaveError(success);
|
||||
|
||||
const newExports = await getUserExports();
|
||||
const newExports = await getUserExports();
|
||||
|
||||
setExports(
|
||||
typeof newExports === "string" ? null : newExports,
|
||||
);
|
||||
setExports(
|
||||
typeof newExports === "string" ? null : newExports,
|
||||
);
|
||||
|
||||
ToastAndroid.show(
|
||||
"Successfully started creating the export",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
color="#323ea8"
|
||||
text="New Export"
|
||||
margin={{
|
||||
top: 10,
|
||||
}}
|
||||
/>
|
||||
ToastAndroid.show(
|
||||
"Successfully started creating the export",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
color="#323ea8"
|
||||
text="New Export"
|
||||
margin={{
|
||||
top: 10,
|
||||
}}
|
||||
/>
|
||||
|
||||
<View style={styles.exportsContainer}>
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
<Row
|
||||
data={[
|
||||
"ID",
|
||||
"Started On",
|
||||
"Files",
|
||||
"Size",
|
||||
"Actions",
|
||||
]}
|
||||
widthArr={[150, 130, 50, 70, 90]}
|
||||
style={styles.tableHeader}
|
||||
textStyle={{
|
||||
...styles.rowText,
|
||||
...styles.headerRow,
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={styles.tableVerticalScroll}
|
||||
>
|
||||
<View style={styles.exportsContainer}>
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
{exports.map((zlExport, index) => {
|
||||
const id = (
|
||||
<Text style={styles.rowText}>{zlExport.id}</Text>
|
||||
);
|
||||
<Row
|
||||
data={[
|
||||
"ID",
|
||||
"Started On",
|
||||
"Files",
|
||||
"Size",
|
||||
"Actions",
|
||||
]}
|
||||
widthArr={[150, 130, 50, 70, 90]}
|
||||
style={styles.tableHeader}
|
||||
textStyle={{
|
||||
...styles.rowText,
|
||||
...styles.headerRow,
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={styles.tableVerticalScroll}
|
||||
>
|
||||
<Table>
|
||||
{exports.map((zlExport, index) => {
|
||||
const id = (
|
||||
<Text style={styles.rowText}>{zlExport.id}</Text>
|
||||
);
|
||||
|
||||
const startedOn = (
|
||||
<Text style={styles.rowText}>
|
||||
{new Date(zlExport.createdAt).toLocaleString()}
|
||||
</Text>
|
||||
);
|
||||
const startedOn = (
|
||||
<Text style={styles.rowText}>
|
||||
{new Date(zlExport.createdAt).toLocaleString()}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const files = (
|
||||
<Text style={styles.rowText}>
|
||||
{zlExport.files}
|
||||
</Text>
|
||||
);
|
||||
const files = (
|
||||
<Text style={styles.rowText}>
|
||||
{zlExport.files}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const size = (
|
||||
<Text style={styles.rowText}>
|
||||
{convertToBytes(
|
||||
Number.parseInt(zlExport.size),
|
||||
{
|
||||
unitSeparator: " ",
|
||||
},
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
const size = (
|
||||
<Text style={styles.rowText}>
|
||||
{convertToBytes(
|
||||
Number.parseInt(zlExport.size),
|
||||
{
|
||||
unitSeparator: " ",
|
||||
},
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const actions = (
|
||||
<View style={styles.actionsContainer}>
|
||||
<Button
|
||||
icon="delete"
|
||||
color="#CF4238"
|
||||
onPress={async () => {
|
||||
setSaveError(null);
|
||||
const actions = (
|
||||
<View style={styles.actionsContainer}>
|
||||
<Button
|
||||
icon="delete"
|
||||
color="#CF4238"
|
||||
onPress={async () => {
|
||||
setSaveError(null);
|
||||
|
||||
const exportId = zlExport.id;
|
||||
const exportId = zlExport.id;
|
||||
|
||||
const success =
|
||||
await deleteUserExport(exportId);
|
||||
const success =
|
||||
await deleteUserExport(exportId);
|
||||
|
||||
if (typeof success === "string")
|
||||
return setSaveError(success);
|
||||
if (typeof success === "string")
|
||||
return setSaveError(success);
|
||||
|
||||
const newExports = await getUserExports();
|
||||
const newExports = await getUserExports();
|
||||
|
||||
setExports(
|
||||
typeof newExports === "string"
|
||||
? null
|
||||
: newExports,
|
||||
);
|
||||
|
||||
return ToastAndroid.show(
|
||||
"Successfully deleted the export",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="download"
|
||||
color={
|
||||
zlExport.completed ? "#323ea8" : "#181c28"
|
||||
}
|
||||
iconColor={
|
||||
zlExport.completed ? "white" : "gray"
|
||||
}
|
||||
disabled={!zlExport.completed}
|
||||
onPress={async () => {
|
||||
const exportId = zlExport.id;
|
||||
|
||||
const downloadUrl = `${url}/api/user/export?id=${exportId}`;
|
||||
|
||||
let savedExportDownloadUri =
|
||||
db.get("exportDownloadPath");
|
||||
|
||||
if (!savedExportDownloadUri) {
|
||||
const permissions =
|
||||
await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
|
||||
|
||||
if (!permissions.granted)
|
||||
return ToastAndroid.show(
|
||||
"The permission to save the file was not granted",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
db.set(
|
||||
"exportDownloadPath",
|
||||
permissions.directoryUri,
|
||||
);
|
||||
savedExportDownloadUri =
|
||||
permissions.directoryUri;
|
||||
}
|
||||
|
||||
ToastAndroid.show(
|
||||
"Downloading...",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
const saveUri =
|
||||
await FileSystem.StorageAccessFramework.createFileAsync(
|
||||
savedExportDownloadUri,
|
||||
zlExport.path,
|
||||
"application/zip",
|
||||
setExports(
|
||||
typeof newExports === "string"
|
||||
? null
|
||||
: newExports,
|
||||
);
|
||||
|
||||
const downloadResult =
|
||||
await FileSystem.downloadAsync(
|
||||
downloadUrl,
|
||||
`${FileSystem.cacheDirectory}/${zlExport.path}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: token,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!downloadResult.uri)
|
||||
return ToastAndroid.show(
|
||||
"Something went wrong while downloading the file",
|
||||
"Successfully deleted the export",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon="download"
|
||||
color={
|
||||
zlExport.completed ? "#323ea8" : "#181c28"
|
||||
}
|
||||
iconColor={
|
||||
zlExport.completed ? "white" : "gray"
|
||||
}
|
||||
disabled={!zlExport.completed}
|
||||
onPress={async () => {
|
||||
const exportId = zlExport.id;
|
||||
|
||||
const downloadUrl = `${url}/api/user/export?id=${exportId}`;
|
||||
|
||||
let savedExportDownloadUri =
|
||||
db.get("exportDownloadPath");
|
||||
|
||||
if (!savedExportDownloadUri) {
|
||||
const permissions =
|
||||
await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
|
||||
|
||||
if (!permissions.granted)
|
||||
return ToastAndroid.show(
|
||||
"The permission to save the file was not granted",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
db.set(
|
||||
"exportDownloadPath",
|
||||
permissions.directoryUri,
|
||||
);
|
||||
savedExportDownloadUri =
|
||||
permissions.directoryUri;
|
||||
}
|
||||
|
||||
ToastAndroid.show(
|
||||
"Downloading...",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
const base64Export =
|
||||
await FileSystem.readAsStringAsync(
|
||||
downloadResult.uri,
|
||||
const saveUri =
|
||||
await FileSystem.StorageAccessFramework.createFileAsync(
|
||||
savedExportDownloadUri,
|
||||
zlExport.path,
|
||||
"application/zip",
|
||||
);
|
||||
|
||||
const downloadResult =
|
||||
await FileSystem.downloadAsync(
|
||||
downloadUrl,
|
||||
`${FileSystem.cacheDirectory}/${zlExport.path}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: token,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!downloadResult.uri)
|
||||
return ToastAndroid.show(
|
||||
"Something went wrong while downloading the file",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
|
||||
const base64Export =
|
||||
await FileSystem.readAsStringAsync(
|
||||
downloadResult.uri,
|
||||
{
|
||||
encoding:
|
||||
FileSystem.EncodingType.Base64,
|
||||
},
|
||||
);
|
||||
|
||||
await FileSystem.writeAsStringAsync(
|
||||
saveUri,
|
||||
base64Export,
|
||||
{
|
||||
encoding:
|
||||
FileSystem.EncodingType.Base64,
|
||||
},
|
||||
);
|
||||
|
||||
await FileSystem.writeAsStringAsync(
|
||||
saveUri,
|
||||
base64Export,
|
||||
{
|
||||
encoding:
|
||||
FileSystem.EncodingType.Base64,
|
||||
},
|
||||
);
|
||||
ToastAndroid.show(
|
||||
"Successfully downloaded the export",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
ToastAndroid.show(
|
||||
"Successfully downloaded the export",
|
||||
ToastAndroid.SHORT,
|
||||
);
|
||||
}}
|
||||
iconSize={20}
|
||||
width={32}
|
||||
height={32}
|
||||
padding={6}
|
||||
let rowStyle = styles.row;
|
||||
|
||||
if (index === 0)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.firstRow,
|
||||
};
|
||||
|
||||
if (index === exports.length - 1)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.lastRow,
|
||||
};
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={zlExport.id}
|
||||
data={[id, startedOn, files, size, actions]}
|
||||
widthArr={[150, 130, 50, 70, 90]}
|
||||
style={rowStyle}
|
||||
textStyle={styles.rowText}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
let rowStyle = styles.row;
|
||||
|
||||
if (index === 0)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.firstRow,
|
||||
};
|
||||
|
||||
if (index === exports.length - 1)
|
||||
rowStyle = {
|
||||
...styles.row,
|
||||
...styles.lastRow,
|
||||
};
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={zlExport.id}
|
||||
data={[id, startedOn, files, size, actions]}
|
||||
widthArr={[150, 130, 50, 70, 90]}
|
||||
style={rowStyle}
|
||||
textStyle={styles.rowText}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* Server Actions */}
|
||||
<View style={styles.settingGroup}>
|
||||
|
|
|
@ -328,28 +328,29 @@ export default function Urls() {
|
|||
</View>
|
||||
</Popup>
|
||||
|
||||
{urls && settings && dashUrl ? (
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>URLs</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewUrl(true);
|
||||
}}
|
||||
icon="add-link"
|
||||
color="transparent"
|
||||
iconColor="#2d3f70"
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerText}>URLs</Text>
|
||||
<View style={styles.headerButtons}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCreateNewUrl(true);
|
||||
}}
|
||||
icon="add-link"
|
||||
color="transparent"
|
||||
iconColor={(urls && settings && dashUrl) ? "#2d3f70" : "#2d3f7055"}
|
||||
borderColor="#222c47"
|
||||
borderWidth={2}
|
||||
iconSize={30}
|
||||
padding={4}
|
||||
rippleColor="#283557"
|
||||
disabled={!urls || !dashUrl || !settings}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ ...styles.urlsContainer, flex: 1 }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={{ ...styles.urlsContainer, flex: 1 }}>
|
||||
{urls && settings && dashUrl ? (
|
||||
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
|
||||
<View>
|
||||
<Table>
|
||||
|
@ -562,13 +563,13 @@ export default function Urls() {
|
|||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
|
215
app/index.tsx
215
app/index.tsx
|
@ -79,112 +79,121 @@ export default function Home() {
|
|||
/>
|
||||
)}
|
||||
|
||||
{user && stats && recentFiles ? (
|
||||
{user ? (
|
||||
<ScrollView>
|
||||
<View>
|
||||
<Text style={styles.headerText}>Recent Files</Text>
|
||||
<ScrollView horizontal style={styles.scrollView}>
|
||||
{recentFiles.map((file) => (
|
||||
<View key={file.id} style={styles.recentFileContainer}>
|
||||
<FileDisplay
|
||||
uri={`${url}/raw/${file.name}`}
|
||||
originalName={file.originalName}
|
||||
name={file.name}
|
||||
width={200}
|
||||
height={200}
|
||||
passwordProtected={file.password}
|
||||
onPress={() => setFocusedFile(file)}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
{recentFiles && (
|
||||
<View>
|
||||
<Text style={styles.headerText}>Recent Files</Text>
|
||||
|
||||
<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}>
|
||||
{convertToBytes(stats.storageUsed, {
|
||||
unitSeparator: " ",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>Average Storage Used:</Text>
|
||||
<Text style={styles.statText}>
|
||||
{convertToBytes(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={[260, 150]}
|
||||
textStyle={styles.tableHeadText}
|
||||
/>
|
||||
<Rows
|
||||
data={Object.entries(stats.sortTypeCount).sort(
|
||||
(a, b) => b[1] - a[1],
|
||||
)}
|
||||
widthArr={[260, 150]}
|
||||
textStyle={styles.tableText}
|
||||
/>
|
||||
</Table>
|
||||
<ScrollView horizontal style={styles.scrollView}>
|
||||
{recentFiles.map((file) => (
|
||||
<View key={file.id} style={styles.recentFileContainer}>
|
||||
<FileDisplay
|
||||
uri={`${url}/raw/${file.name}`}
|
||||
originalName={file.originalName}
|
||||
name={file.name}
|
||||
width={200}
|
||||
height={200}
|
||||
passwordProtected={file.password}
|
||||
onPress={() => setFocusedFile(file)}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{stats && (
|
||||
<>
|
||||
<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}>
|
||||
{convertToBytes(stats.storageUsed, {
|
||||
unitSeparator: " ",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statContainer}>
|
||||
<Text style={styles.subHeaderText}>Average Storage Used:</Text>
|
||||
<Text style={styles.statText}>
|
||||
{convertToBytes(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={[260, 150]}
|
||||
textStyle={styles.tableHeadText}
|
||||
/>
|
||||
<Rows
|
||||
data={Object.entries(stats.sortTypeCount).sort(
|
||||
(a, b) => b[1] - a[1],
|
||||
)}
|
||||
widthArr={[260, 150]}
|
||||
textStyle={styles.tableText}
|
||||
/>
|
||||
</Table>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</ScrollView>
|
||||
) : (
|
||||
<View style={styles.loadingContainer}>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
import type { SelectProps } from "@/components/Select";
|
||||
import type { APISettings, ShortenEmbed, UploadEmbed } from "@/types/zipline";
|
||||
import type { SelectProps } from "@/components/Select";
|
||||
|
||||
export const defaultUploadEmbed: UploadEmbed = {
|
||||
url: false,
|
||||
color: null,
|
||||
title: null,
|
||||
footer: null,
|
||||
thumbnail: false,
|
||||
timestamp: false,
|
||||
description: null,
|
||||
imageOrVideo: false,
|
||||
description: null,
|
||||
timestamp: false,
|
||||
thumbnail: false,
|
||||
footer: null,
|
||||
title: null,
|
||||
color: null,
|
||||
url: false,
|
||||
};
|
||||
|
||||
export const defaultShortenEmbed: ShortenEmbed = {
|
||||
url: false,
|
||||
color: null,
|
||||
title: null,
|
||||
footer: null,
|
||||
thumbnail: false,
|
||||
timestamp: false,
|
||||
description: null,
|
||||
imageOrVideo: false,
|
||||
description: null,
|
||||
timestamp: false,
|
||||
thumbnail: false,
|
||||
footer: null,
|
||||
title: null,
|
||||
color: null,
|
||||
url: false,
|
||||
};
|
||||
|
||||
export type SettingPath<T extends keyof APISettings = keyof APISettings> =
|
||||
|
@ -162,9 +162,24 @@ export const settingNames: Partial<Record<SettingPath, string>> = {
|
|||
};
|
||||
|
||||
export const formats: SelectProps["data"] = [
|
||||
{ label: "Random", value: "random" },
|
||||
{ label: "Date", value: "date" },
|
||||
{ label: "UUID", value: "uuid" },
|
||||
{ label: "Use File Name", value: "name" },
|
||||
{ label: "Gfycat-style Name", value: "gfycat" },
|
||||
{
|
||||
label: "Random",
|
||||
value: "random",
|
||||
},
|
||||
{
|
||||
label: "Date",
|
||||
value: "date",
|
||||
},
|
||||
{
|
||||
label: "UUID",
|
||||
value: "uuid",
|
||||
},
|
||||
{
|
||||
label: "Use File Name",
|
||||
value: "name",
|
||||
},
|
||||
{
|
||||
label: "Gfycat-style Name",
|
||||
value: "gfycat",
|
||||
},
|
||||
];
|
||||
|
|
|
@ -5,12 +5,44 @@ export const millisecondsHour = 60 * millisecondsMinute;
|
|||
export const millisecondsDay = 24 * millisecondsHour;
|
||||
|
||||
export const dates: SelectProps["data"] = [
|
||||
{ label: "Never", value: "never", milliseconds: null },
|
||||
{ label: "30 minutes", value: "30m", milliseconds: 30 * millisecondsMinute },
|
||||
{ label: "1 hour", value: "1h", milliseconds: millisecondsHour },
|
||||
{ label: "12 hours", value: "12h", milliseconds: 12 * millisecondsHour },
|
||||
{ label: "1 day", value: "1d", milliseconds: millisecondsDay },
|
||||
{ label: "3 days", value: "3d", milliseconds: 3 * millisecondsDay },
|
||||
{ label: "5 days", value: "5d", milliseconds: 5 * millisecondsDay },
|
||||
{ label: "7 days", value: "7d", milliseconds: 7 * millisecondsDay },
|
||||
{
|
||||
label: "Never",
|
||||
value: "never",
|
||||
milliseconds: null,
|
||||
},
|
||||
{
|
||||
label: "30 minutes",
|
||||
value: "30m",
|
||||
milliseconds: 30 * millisecondsMinute,
|
||||
},
|
||||
{
|
||||
label: "1 hour",
|
||||
value: "1h",
|
||||
milliseconds: millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "12 hours",
|
||||
value: "12h",
|
||||
milliseconds: 12 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "1 day",
|
||||
value: "1d",
|
||||
milliseconds: millisecondsDay,
|
||||
},
|
||||
{
|
||||
label: "3 days",
|
||||
value: "3d",
|
||||
milliseconds: 3 * millisecondsDay,
|
||||
},
|
||||
{
|
||||
label: "5 days",
|
||||
value: "5d",
|
||||
milliseconds: 5 * millisecondsDay,
|
||||
},
|
||||
{
|
||||
label: "7 days",
|
||||
value: "7d",
|
||||
milliseconds: 7 * millisecondsDay,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -2,23 +2,23 @@ import type { IconProps } from "@react-native-material/core";
|
|||
import type MaterialIcons from "@expo/vector-icons/MaterialIcons";
|
||||
|
||||
interface SidebarOptionButton {
|
||||
icon: keyof typeof MaterialIcons.glyphMap;
|
||||
invitesRoute: boolean;
|
||||
adminOnly: boolean;
|
||||
type: "button";
|
||||
route: string;
|
||||
name: string;
|
||||
icon: keyof typeof MaterialIcons.glyphMap;
|
||||
adminOnly: boolean;
|
||||
invitesRoute: boolean;
|
||||
type: "button";
|
||||
subMenus: [];
|
||||
}
|
||||
|
||||
interface SidebarOptionSelect {
|
||||
route: null;
|
||||
name: string;
|
||||
icon: keyof typeof MaterialIcons.glyphMap;
|
||||
adminOnly: boolean;
|
||||
invitesRoute: boolean;
|
||||
type: "select";
|
||||
subMenus: Array<SidebarOption>;
|
||||
invitesRoute: boolean;
|
||||
adminOnly: boolean;
|
||||
type: "select";
|
||||
name: string;
|
||||
route: null;
|
||||
}
|
||||
|
||||
export type SidebarOption = SidebarOptionButton | SidebarOptionSelect;
|
||||
|
|
|
@ -8,100 +8,375 @@ export const millisecondsMonth = 30 * millisecondsDay;
|
|||
export const millisecondsYear = 365 * millisecondsDay;
|
||||
|
||||
export const dates: SelectProps["data"] = [
|
||||
{ label: "Never", value: "never", milliseconds: null },
|
||||
{ label: "5 minutes", value: "5m", milliseconds: 5 * millisecondsMinute },
|
||||
{ label: "10 minutes", value: "10m", milliseconds: 10 * millisecondsMinute },
|
||||
{ label: "15 minutes", value: "15m", milliseconds: 15 * millisecondsMinute },
|
||||
{ label: "30 minutes", value: "30m", milliseconds: 30 * millisecondsMinute },
|
||||
{ label: "1 hour", value: "1h", milliseconds: millisecondsHour },
|
||||
{ label: "2 hours", value: "2h", milliseconds: 2 * millisecondsHour },
|
||||
{ label: "3 hours", value: "3h", milliseconds: 3 * millisecondsHour },
|
||||
{ label: "4 hours", value: "4h", milliseconds: 4 * millisecondsHour },
|
||||
{ label: "5 hours", value: "5h", milliseconds: 5 * millisecondsHour },
|
||||
{ label: "6 hours", value: "6h", milliseconds: 6 * millisecondsHour },
|
||||
{ label: "8 hours", value: "8h", milliseconds: 8 * millisecondsHour },
|
||||
{ label: "12 hours", value: "12h", milliseconds: 12 * millisecondsHour },
|
||||
{ label: "1 day", value: "1d", milliseconds: millisecondsDay },
|
||||
{ label: "3 days", value: "3d", milliseconds: 3 * millisecondsDay },
|
||||
{ label: "5 days", value: "5d", milliseconds: 5 * millisecondsDay },
|
||||
{ label: "1 week", value: "1w", milliseconds: millisecondsWeek },
|
||||
{ label: "1.5 weeks", value: "1.5w", milliseconds: 1.5 * millisecondsWeek },
|
||||
{ label: "2 weeks", value: "2w", milliseconds: 2 * millisecondsWeek },
|
||||
{ label: "3 weeks", value: "3w", milliseconds: 3 * millisecondsWeek },
|
||||
{ label: "1 month", value: "1M", milliseconds: millisecondsMonth },
|
||||
{ label: "1.5 months", value: "1.5M", milliseconds: 1.5 * millisecondsMonth },
|
||||
{ label: "2 months", value: "2M", milliseconds: 2 * millisecondsMonth },
|
||||
{ label: "3 months", value: "3M", milliseconds: 3 * millisecondsMonth },
|
||||
{ label: "4 months", value: "4M", milliseconds: 4 * millisecondsMonth },
|
||||
{ label: "6 months", value: "6M", milliseconds: 6 * millisecondsMonth },
|
||||
{ label: "1 year", value: "1y", milliseconds: millisecondsYear },
|
||||
{
|
||||
label: "Never",
|
||||
value: "never",
|
||||
milliseconds: null,
|
||||
},
|
||||
{
|
||||
label: "5 minutes",
|
||||
value: "5m",
|
||||
milliseconds: 5 * millisecondsMinute,
|
||||
},
|
||||
{
|
||||
label: "10 minutes",
|
||||
value: "10m",
|
||||
milliseconds: 10 * millisecondsMinute,
|
||||
},
|
||||
{
|
||||
label: "15 minutes",
|
||||
value: "15m",
|
||||
milliseconds: 15 * millisecondsMinute,
|
||||
},
|
||||
{
|
||||
label: "30 minutes",
|
||||
value: "30m",
|
||||
milliseconds: 30 * millisecondsMinute,
|
||||
},
|
||||
{
|
||||
label: "1 hour",
|
||||
value: "1h",
|
||||
milliseconds: millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "2 hours",
|
||||
value: "2h",
|
||||
milliseconds: 2 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "3 hours",
|
||||
value: "3h",
|
||||
milliseconds: 3 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "4 hours",
|
||||
value: "4h",
|
||||
milliseconds: 4 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "5 hours",
|
||||
value: "5h",
|
||||
milliseconds: 5 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "6 hours",
|
||||
value: "6h",
|
||||
milliseconds: 6 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "8 hours",
|
||||
value: "8h",
|
||||
milliseconds: 8 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "12 hours",
|
||||
value: "12h",
|
||||
milliseconds: 12 * millisecondsHour,
|
||||
},
|
||||
{
|
||||
label: "1 day",
|
||||
value: "1d",
|
||||
milliseconds: millisecondsDay,
|
||||
},
|
||||
{
|
||||
label: "3 days",
|
||||
value: "3d",
|
||||
milliseconds: 3 * millisecondsDay,
|
||||
},
|
||||
{
|
||||
label: "5 days",
|
||||
value: "5d",
|
||||
milliseconds: 5 * millisecondsDay,
|
||||
},
|
||||
{
|
||||
label: "1 week",
|
||||
value: "1w",
|
||||
milliseconds: millisecondsWeek,
|
||||
},
|
||||
{
|
||||
label: "1.5 weeks",
|
||||
value: "1.5w",
|
||||
milliseconds: 1.5 * millisecondsWeek,
|
||||
},
|
||||
{
|
||||
label: "2 weeks",
|
||||
value: "2w",
|
||||
milliseconds: 2 * millisecondsWeek,
|
||||
},
|
||||
{
|
||||
label: "3 weeks",
|
||||
value: "3w",
|
||||
milliseconds: 3 * millisecondsWeek,
|
||||
},
|
||||
{
|
||||
label: "1 month",
|
||||
value: "1M",
|
||||
milliseconds: millisecondsMonth,
|
||||
},
|
||||
{
|
||||
label: "1.5 months",
|
||||
value: "1.5M",
|
||||
milliseconds: 1.5 * millisecondsMonth,
|
||||
},
|
||||
{
|
||||
label: "2 months",
|
||||
value: "2M",
|
||||
milliseconds: 2 * millisecondsMonth,
|
||||
},
|
||||
{
|
||||
label: "3 months",
|
||||
value: "3M",
|
||||
milliseconds: 3 * millisecondsMonth,
|
||||
},
|
||||
{
|
||||
label: "4 months",
|
||||
value: "4M",
|
||||
milliseconds: 4 * millisecondsMonth,
|
||||
},
|
||||
{
|
||||
label: "6 months",
|
||||
value: "6M",
|
||||
milliseconds: 6 * millisecondsMonth,
|
||||
},
|
||||
{
|
||||
label: "1 year",
|
||||
value: "1y",
|
||||
milliseconds: millisecondsYear,
|
||||
},
|
||||
];
|
||||
|
||||
export const formats: SelectProps["data"] = [
|
||||
{ label: "Random", value: "random" },
|
||||
{ label: "Date", value: "date" },
|
||||
{ label: "UUID", value: "uuid" },
|
||||
{ label: "Use File Name", value: "name" },
|
||||
{ label: "Gfycat-style Name", value: "gfycat" },
|
||||
{
|
||||
label: "Random",
|
||||
value: "random",
|
||||
},
|
||||
{
|
||||
label: "Date",
|
||||
value: "date",
|
||||
},
|
||||
{
|
||||
label: "UUID",
|
||||
value: "uuid",
|
||||
},
|
||||
{
|
||||
label: "Use File Name",
|
||||
value: "name",
|
||||
},
|
||||
{
|
||||
label: "Gfycat-style Name",
|
||||
value: "gfycat",
|
||||
},
|
||||
];
|
||||
|
||||
export const avaibleTextMimetypes: SelectProps["data"] = [
|
||||
{ label: "HTML", value: "html", mimetype: "text/x-zipline-html" },
|
||||
{ label: "CSS", value: "css", mimetype: "text/x-zipline-css" },
|
||||
{ label: "C++", value: "cpp", mimetype: "text/x-zipline-c++src" },
|
||||
{ label: "JavaScript", value: "js", mimetype: "text/x-zipline-javascript" },
|
||||
{ label: "Python", value: "py", mimetype: "text/x-zipline-python" },
|
||||
{ label: "Ruby", value: "rb", mimetype: "text/x-zipline-ruby" },
|
||||
{ label: "Java", value: "java", mimetype: "text/x-zipline-java" },
|
||||
{ label: "Markdown", value: "md", mimetype: "text/x-zipline-markdown" },
|
||||
{ label: "C", value: "c", mimetype: "text/x-zipline-csrc" },
|
||||
{ label: "PHP", value: "php", mimetype: "text/x-zipline-httpd-php" },
|
||||
{ label: "Sass", value: "sass", mimetype: "text/x-zipline-sass" },
|
||||
{ label: "SCSS", value: "scss", mimetype: "text/x-zipline-scss" },
|
||||
{ label: "Swift", value: "swift", mimetype: "text/x-zipline-swift" },
|
||||
{ label: "TypeScript", value: "ts", mimetype: "text/x-zipline-typescript" },
|
||||
{ label: "Go", value: "go", mimetype: "text/x-zipline-go" },
|
||||
{ label: "Rust", value: "rs", mimetype: "text/x-zipline-rustsrc" },
|
||||
{ label: "Bash", value: "sh", mimetype: "text/x-zipline-sh" },
|
||||
{ label: "JSON", value: "json", mimetype: "text/x-zipline-json" },
|
||||
{ label: "PowerShell", value: "ps1", mimetype: "text/x-zipline-powershell" },
|
||||
{ label: "SQL", value: "sql", mimetype: "text/x-zipline-sql" },
|
||||
{ label: "YAML", value: "yaml", mimetype: "text/x-zipline-yaml" },
|
||||
{
|
||||
label: "HTML",
|
||||
value: "html",
|
||||
mimetype: "text/x-zipline-html",
|
||||
},
|
||||
{
|
||||
label: "CSS",
|
||||
value: "css",
|
||||
mimetype: "text/x-zipline-css",
|
||||
},
|
||||
{
|
||||
label: "C++",
|
||||
value: "cpp",
|
||||
mimetype: "text/x-zipline-c++src",
|
||||
},
|
||||
{
|
||||
label: "JavaScript",
|
||||
value: "js",
|
||||
mimetype: "text/x-zipline-javascript",
|
||||
},
|
||||
{
|
||||
label: "Python",
|
||||
value: "py",
|
||||
mimetype: "text/x-zipline-python",
|
||||
},
|
||||
{
|
||||
label: "Ruby",
|
||||
value: "rb",
|
||||
mimetype: "text/x-zipline-ruby",
|
||||
},
|
||||
{
|
||||
label: "Java",
|
||||
value: "java",
|
||||
mimetype: "text/x-zipline-java",
|
||||
},
|
||||
{
|
||||
label: "Markdown",
|
||||
value: "md",
|
||||
mimetype: "text/x-zipline-markdown",
|
||||
},
|
||||
{
|
||||
label: "C",
|
||||
value: "c",
|
||||
mimetype: "text/x-zipline-csrc",
|
||||
},
|
||||
{
|
||||
label: "PHP",
|
||||
value: "php",
|
||||
mimetype: "text/x-zipline-httpd-php",
|
||||
},
|
||||
{
|
||||
label: "Sass",
|
||||
value: "sass",
|
||||
mimetype: "text/x-zipline-sass",
|
||||
},
|
||||
{
|
||||
label: "SCSS",
|
||||
value: "scss",
|
||||
mimetype: "text/x-zipline-scss",
|
||||
},
|
||||
{
|
||||
label: "Swift",
|
||||
value: "swift",
|
||||
mimetype: "text/x-zipline-swift",
|
||||
},
|
||||
{
|
||||
label: "TypeScript",
|
||||
value: "ts",
|
||||
mimetype: "text/x-zipline-typescript",
|
||||
},
|
||||
{
|
||||
label: "Go",
|
||||
value: "go",
|
||||
mimetype: "text/x-zipline-go",
|
||||
},
|
||||
{
|
||||
label: "Rust",
|
||||
value: "rs",
|
||||
mimetype: "text/x-zipline-rustsrc",
|
||||
},
|
||||
{
|
||||
label: "Bash",
|
||||
value: "sh",
|
||||
mimetype: "text/x-zipline-sh",
|
||||
},
|
||||
{
|
||||
label: "JSON",
|
||||
value: "json",
|
||||
mimetype: "text/x-zipline-json",
|
||||
},
|
||||
{
|
||||
label: "PowerShell",
|
||||
value: "ps1",
|
||||
mimetype: "text/x-zipline-powershell",
|
||||
},
|
||||
{
|
||||
label: "SQL",
|
||||
value: "sql",
|
||||
mimetype: "text/x-zipline-sql",
|
||||
},
|
||||
{
|
||||
label: "YAML",
|
||||
value: "yaml",
|
||||
mimetype: "text/x-zipline-yaml",
|
||||
},
|
||||
{
|
||||
label: "Dockerfile",
|
||||
value: "dockerfile",
|
||||
mimetype: "text/x-zipline-dockerfile",
|
||||
},
|
||||
{ label: "Lua", value: "lua", mimetype: "text/x-zipline-lua" },
|
||||
{
|
||||
label: "Lua",
|
||||
value: "lua",
|
||||
mimetype: "text/x-zipline-lua",
|
||||
},
|
||||
{
|
||||
label: "NGINX Config File",
|
||||
value: "conf",
|
||||
mimetype: "text/x-zipline-nginx-conf",
|
||||
},
|
||||
{ label: "Perl", value: "pl", mimetype: "text/x-zipline-perl" },
|
||||
{ label: "R", value: "r", mimetype: "text/x-zipline-rsrc" },
|
||||
{ label: "Scala", value: "scala", mimetype: "text/x-zipline-scala" },
|
||||
{ label: "Groovy", value: "groovy", mimetype: "text/x-zipline-groovy" },
|
||||
{ label: "Kotlin", value: "kt", mimetype: "text/x-zipline-kotlin" },
|
||||
{ label: "Haskell", value: "hs", mimetype: "text/x-zipline-haskell" },
|
||||
{ label: "Elixir", value: "ex", mimetype: "text/x-zipline-elixir" },
|
||||
{ label: "Vim", value: "vim", mimetype: "text/x-zipline-vim" },
|
||||
{ label: "MATLAB", value: "m", mimetype: "text/x-zipline-matlab" },
|
||||
{ label: "Dart", value: "dart", mimetype: "text/x-zipline-dart" },
|
||||
{
|
||||
label: "Perl",
|
||||
value: "pl",
|
||||
mimetype: "text/x-zipline-perl",
|
||||
},
|
||||
{
|
||||
label: "R",
|
||||
value: "r",
|
||||
mimetype: "text/x-zipline-rsrc",
|
||||
},
|
||||
{
|
||||
label: "Scala",
|
||||
value: "scala",
|
||||
mimetype: "text/x-zipline-scala",
|
||||
},
|
||||
{
|
||||
label: "Groovy",
|
||||
value: "groovy",
|
||||
mimetype: "text/x-zipline-groovy",
|
||||
},
|
||||
{
|
||||
label: "Kotlin",
|
||||
value: "kt",
|
||||
mimetype: "text/x-zipline-kotlin",
|
||||
},
|
||||
{
|
||||
label: "Haskell",
|
||||
value: "hs",
|
||||
mimetype: "text/x-zipline-haskell",
|
||||
},
|
||||
{
|
||||
label: "Elixir",
|
||||
value: "ex",
|
||||
mimetype: "text/x-zipline-elixir",
|
||||
},
|
||||
{
|
||||
label: "Vim",
|
||||
value: "vim",
|
||||
mimetype: "text/x-zipline-vim",
|
||||
},
|
||||
{
|
||||
label: "MATLAB",
|
||||
value: "m",
|
||||
mimetype: "text/x-zipline-matlab",
|
||||
},
|
||||
{
|
||||
label: "Dart",
|
||||
value: "dart",
|
||||
mimetype: "text/x-zipline-dart",
|
||||
},
|
||||
{
|
||||
label: "Handlebars",
|
||||
value: "hbs",
|
||||
mimetype: "text/x-zipline-handlebars-template",
|
||||
},
|
||||
{ label: "HCL", value: "hcl", mimetype: "text/x-zipline-hcl" },
|
||||
{ label: "HTTP", value: "http", mimetype: "text/x-zipline-http" },
|
||||
{ label: "INI", value: "ini", mimetype: "text/x-zipline-ini" },
|
||||
{ label: "JSX", value: "jsx", mimetype: "text/x-zipline-jsx" },
|
||||
{
|
||||
label: "HCL",
|
||||
value: "hcl",
|
||||
mimetype: "text/x-zipline-hcl",
|
||||
},
|
||||
{
|
||||
label: "HTTP",
|
||||
value: "http",
|
||||
mimetype: "text/x-zipline-http",
|
||||
},
|
||||
{
|
||||
label: "INI",
|
||||
value: "ini",
|
||||
mimetype: "text/x-zipline-ini",
|
||||
},
|
||||
{
|
||||
label: "JSX",
|
||||
value: "jsx",
|
||||
mimetype: "text/x-zipline-jsx",
|
||||
},
|
||||
{
|
||||
label: "CoffeeScript",
|
||||
value: "coffee",
|
||||
mimetype: "text/x-zipline-coffeescript",
|
||||
},
|
||||
{ label: "LaTeX (KaTeX)", value: "tex", mimetype: "text/x-zipline-latex" },
|
||||
{ label: "Plain Text", value: "txt", mimetype: "text/x-zipline-plain" },
|
||||
{
|
||||
label: "LaTeX (KaTeX)",
|
||||
value: "tex",
|
||||
mimetype: "text/x-zipline-latex",
|
||||
},
|
||||
{
|
||||
label: "Plain Text",
|
||||
value: "txt",
|
||||
mimetype: "text/x-zipline-plain",
|
||||
},
|
||||
];
|
||||
|
|
|
@ -28,16 +28,16 @@ export const fileQuotaTypes: SelectProps["data"] = [
|
|||
];
|
||||
|
||||
export const templateUser: APIUser = {
|
||||
avatar: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
id: "1234567890",
|
||||
oauthProviders: [],
|
||||
passkeys: [],
|
||||
quota: null,
|
||||
role: "USER",
|
||||
sessions: [],
|
||||
totpSecret: null,
|
||||
updatedAt: new Date().toISOString(),
|
||||
username: "Placeholder",
|
||||
oauthProviders: [],
|
||||
totpSecret: null,
|
||||
id: "1234567890",
|
||||
passkeys: [],
|
||||
sessions: [],
|
||||
avatar: null,
|
||||
role: "USER",
|
||||
quota: null,
|
||||
view: {},
|
||||
};
|
||||
|
|
|
@ -142,11 +142,11 @@ export function toRgba(color: string): RGBA {
|
|||
};
|
||||
}
|
||||
|
||||
function gammaCorrect(c: number) {
|
||||
function gammaCorrect(c: number): number {
|
||||
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
||||
}
|
||||
|
||||
function getLightnessFromOklch(oklchColor: string) {
|
||||
function getLightnessFromOklch(oklchColor: string): number | null {
|
||||
const match = oklchColor.match(/oklch\((.*?)%\s/);
|
||||
return match ? Number.parseFloat(match[1]) : null;
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ export function luminance(color: string): number {
|
|||
return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
|
||||
}
|
||||
|
||||
export function isLightColor(color: string, luminanceThreshold = 0.179) {
|
||||
export function isLightColor(color: string, luminanceThreshold = 0.179): boolean {
|
||||
if (color.startsWith("var(")) {
|
||||
return false;
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ export function isLightColor(color: string, luminanceThreshold = 0.179) {
|
|||
return luminance(color) > luminanceThreshold;
|
||||
}
|
||||
|
||||
export function rgbaToHex(r: number, g: number, b: number, a = 1) {
|
||||
export function rgbaToHex(r: number, g: number, b: number, a = 1): string {
|
||||
r = Math.min(255, Math.max(0, r));
|
||||
g = Math.min(255, Math.max(0, g));
|
||||
b = Math.min(255, Math.max(0, b));
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { isLightColor, rgbaToHex, toRgba } from "@/functions/color";
|
||||
import mimetypesJSON from "@/assets/mimetypes.json";
|
||||
import type { Mimetypes } from "@/types/mimetypes";
|
||||
import bytes from "bytes";
|
||||
import ms, { type FormatOptions } from "enhanced-ms";
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import { isLightColor, rgbaToHex, toRgba } from "./color";
|
||||
import { namedColors } from "@/constants/colors";
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import ms from "enhanced-ms";
|
||||
import bytes from "bytes";
|
||||
|
||||
const mimetypes = mimetypesJSON as Mimetypes;
|
||||
|
||||
|
@ -117,7 +117,8 @@ export function convertToBytes(
|
|||
|
||||
export function convertToTime(
|
||||
value: string | number,
|
||||
options?: FormatOptions,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: enhanced-ms does not export the FormatOptions interface
|
||||
options?: any,
|
||||
): string | null {
|
||||
if (typeof value === "number") return ms(value);
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
import type {
|
||||
APILoginResponse,
|
||||
APISelfUser,
|
||||
APITokenResponse,
|
||||
} from "@/types/zipline";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
|
||||
export async function isAuthenticated(): Promise<APISelfUser["role"] | false> {
|
||||
const url = db.get("url");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { APIExports } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
// GET /api/user/export
|
||||
export async function getUserExports(): Promise<APIExports | string> {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import * as FileSystem from "expo-file-system";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
import type {
|
||||
APIFile,
|
||||
APIFiles,
|
||||
|
@ -5,9 +8,6 @@ import type {
|
|||
APITag,
|
||||
APIUploadFile,
|
||||
} from "@/types/zipline";
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
|
||||
export interface GetFilesOptions {
|
||||
id?: string;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { APIFoldersNoIncl, APIFolders, APIFolder } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
// GET /api/user/folders
|
||||
export async function getFolders<T extends boolean | undefined = undefined>(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { APIInvite, APIInvites } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
// GET /api/auth/invites
|
||||
export async function getInvites(): Promise<APIInvites | string> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as db from "@/functions/database";
|
||||
import type { APIFile, ServerActionResponse } from "@/types/zipline";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
export async function clearZeroByteFiles(): Promise<
|
||||
ServerActionResponse | string
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { APISettings } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import { settingNames } from "@/constants/adminSettings";
|
||||
import type { APISettings } from "@/types/zipline";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
// GET /api/server/settings
|
||||
export async function getSettings(): Promise<APISettings | string> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { APIUserStats, APIStats } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
export interface StatsProps {
|
||||
from?: string;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { APITag, APITags } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
// GET /api/user/tags
|
||||
export async function getTags(): Promise<APITags | string> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { APIURLs, APIURL } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
// GET /user/urls
|
||||
export async function getURLs(): Promise<APIURLs | string> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { APIRecentFiles, APISelfUser, APIUser } from "@/types/zipline";
|
||||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
|
||||
// GET /api/user
|
||||
export async function getCurrentUser(): Promise<APISelfUser | string> {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as db from "@/functions/database";
|
||||
import axios, { type AxiosError } from "axios";
|
||||
import * as db from "@/functions/database";
|
||||
import type {
|
||||
APIUsersNoIncl,
|
||||
APIUsers,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { isAuthenticated } from "@/functions/zipline/auth";
|
||||
import type { APIUser } from "@/types/zipline";
|
||||
import { useFocusEffect, useRouter } from "expo-router";
|
||||
import type { APIUser } from "@/types/zipline";
|
||||
import { roles } from "@/constants/auth";
|
||||
|
||||
export const useAuth = (minimumRole: APIUser["role"] = "USER") => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useRouter } from "expo-router";
|
||||
import { useShareIntentContext } from "expo-share-intent";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "expo-router";
|
||||
|
||||
export const useShareIntent = (skipRedirect = false) => {
|
||||
const router = useRouter();
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { type ExternalPathString, useRouter } from "expo-router";
|
||||
// import * as DocumentPicker from "expo-document-picker";
|
||||
import { repoName, username } from "@/constants/updates";
|
||||
import { version as appVersion } from "@/package.json";
|
||||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import semver from "semver";
|
||||
import * as db from "@/functions/database";
|
||||
// import * as DocumentPicker from "expo-document-picker";
|
||||
// import * as FileSystem from "expo-file-system";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ToastAndroid } from "react-native";
|
||||
import { type ExternalPathString, useRouter } from "expo-router";
|
||||
import * as db from "@/functions/database";
|
||||
import semver from "semver";
|
||||
import axios from "axios";
|
||||
|
||||
export function useAppUpdates() {
|
||||
const router = useRouter();
|
||||
|
|
11
package.json
11
package.json
|
@ -5,16 +5,11 @@
|
|||
"scripts": {
|
||||
"start": "expo start",
|
||||
"start:dev": "APP_VARIANT=development EDGE_PATH=/home/stef/.local/bin/google-chrome expo start --dev-client",
|
||||
"start:release": "APP_VARIANT=devrelease EDGE_PATH=/home/stef/.local/bin/google-chrome expo start --dev-client",
|
||||
"prebuild": "expo prebuild --no-install --clean",
|
||||
"prebuild:dev": "APP_VARIANT=development expo prebuild --no-install --clean",
|
||||
"prebuild:release": "APP_VARIANT=devrelease expo prebuild --no-install --clean",
|
||||
"prebuild": "EXPO_NO_GIT_STATUS=1 expo prebuild --no-install --clean --platform android",
|
||||
"prebuild:dev": "EXPO_NO_GIT_STATUS=1 APP_VARIANT=development expo prebuild --no-install --clean --platform android",
|
||||
"run:android": "expo run:android",
|
||||
"run:android:release": "expo run:android --variant release",
|
||||
"test": "jest --watchAll",
|
||||
"lint": "expo lint",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios"
|
||||
"lint": "expo lint"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-expo"
|
||||
|
|
|
@ -28,6 +28,7 @@ export const styles = StyleSheet.create({
|
|||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 10
|
||||
},
|
||||
dateRangeText: {
|
||||
color: "gray",
|
||||
|
@ -36,13 +37,13 @@ export const styles = StyleSheet.create({
|
|||
marginTop: 10,
|
||||
},
|
||||
scrollView: {
|
||||
marginTop: 15,
|
||||
borderStyle: "solid",
|
||||
borderWidth: 2,
|
||||
borderColor: "#222c47",
|
||||
marginHorizontal: 10,
|
||||
borderRadius: 15,
|
||||
padding: 15,
|
||||
marginBottom: 10
|
||||
},
|
||||
statsContainer: {
|
||||
paddingHorizontal: 7,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue