[nobuild] .

This commit is contained in:
Stef-00012 2025-02-07 08:01:03 +01:00
parent 3f586399de
commit aa36fbb91e
No known key found for this signature in database
GPG key ID: 28BE9A9E4EF0E6BF
9 changed files with 809 additions and 718 deletions

View file

@ -18,6 +18,7 @@ import { isLightColor } from "@/functions/color";
import { colorHash } from "@/functions/util";
import LargeFileDisplay from "@/components/LargeFileDisplay";
import TextInput from "@/components/TextInput";
import Button from "@/components/Button";
export default function Files() {
const router = useRouter();
@ -145,19 +146,20 @@ export default function Files() {
<Text style={styles.headerText}>Tags</Text>
<View style={styles.headerButtons}>
<Pressable
style={styles.headerButton}
<Button
onPress={() => {
setCreateNewTag(true)
setTagsMenuOpen(false)
}}
>
<MaterialIcons
name="add"
size={30}
color={styles.headerButton.color}
/>
</Pressable>
icon="add"
color="transparent"
iconColor="#2d3f70"
borderColor="#222c47"
borderWidth={2}
iconSize={30}
padding={4}
rippleColor="#283557"
/>
</View>
</View>
@ -174,47 +176,54 @@ export default function Files() {
</View>
<View style={styles.tagButtonContainer}>
<Pressable style={styles.tagButton}>
<MaterialIcons
name="edit"
size={20}
color={"white"}
onPress={() => {
setTagToEdit(tag)
setTagsMenuOpen(false)
}}
/>
</Pressable>
<Button
icon="edit"
color="#323ea8"
onPress={() => {
setTagToEdit(tag)
setTagsMenuOpen(false)
}}
iconSize={20}
width={32}
height={32}
padding={6}
margin={{
left: 5,
right: 5
}}
/>
<Pressable style={{
...styles.tagButton,
...styles.tagButtonDanger
}}>
<MaterialIcons
name="delete"
size={20}
color={"white"}
onPress={async () => {
const tagId = tag.id
<Button
icon="delete"
color="#CF4238"
onPress={async () => {
const tagId = tag.id
const success = await deleteTag(tagId)
const success = await deleteTag(tagId)
if (typeof success === "string") return ToastAndroid.show(
`Failed to delete the tag "${tag.name}"`,
ToastAndroid.SHORT
)
if (typeof success === "string") return ToastAndroid.show(
`Failed to delete the tag "${tag.name}"`,
ToastAndroid.SHORT
)
const newTags = tags.filter(tg => tag.id !== tg.id)
const newTags = tags.filter(tg => tag.id !== tg.id)
setTags(newTags)
setTags(newTags)
ToastAndroid.show(
`Deleted the tag "${tag.name}"`,
ToastAndroid.SHORT
)
}}
/>
</Pressable>
ToastAndroid.show(
`Deleted the tag "${tag.name}"`,
ToastAndroid.SHORT
)
}}
iconSize={20}
width={32}
height={32}
padding={6}
margin={{
left: 5,
right: 5
}}
/>
</View>
</View>
))}
@ -256,26 +265,25 @@ export default function Files() {
/>
<View style={styles.manageTagButtonsContainer}>
<Pressable
style={{
...styles.button,
...styles.manageTagButton,
...styles.guessButton
}}
<Button
color="#616060"
text="Guess Color"
onPress={async () => {
const guess = colorHash(newTagName || "")
setNewTagColor(guess)
}}
>
<Text style={styles.buttonText}>Guess Color</Text>
</Pressable>
<Pressable
style={{
...styles.button,
...styles.manageTagButton
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 15
}}
/>
<Button
color="#323ea8"
text="Create"
onPress={async () => {
setNewTagError(null);
@ -297,9 +305,13 @@ export default function Files() {
setCreateNewTag(false);
setTagsMenuOpen(true)
}}
>
<Text style={styles.buttonText}>Create</Text>
</Pressable>
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 15
}}
/>
</View>
<Text
@ -340,26 +352,25 @@ export default function Files() {
/>
<View style={styles.manageTagButtonsContainer}>
<Pressable
style={{
...styles.button,
...styles.manageTagButton,
...styles.guessButton
}}
<Button
color="#616060"
text="Guess Color"
onPress={async () => {
const guess = colorHash(editTagName || "")
setEditTagColor(guess)
}}
>
<Text style={styles.buttonText}>Guess Color</Text>
</Pressable>
<Pressable
style={{
...styles.button,
...styles.manageTagButton
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 15
}}
/>
<Button
color="#323ea8"
text="Create"
onPress={async () => {
setEditTagError(null);
@ -386,9 +397,13 @@ export default function Files() {
setTagToEdit(null);
setTagsMenuOpen(true)
}}
>
<Text style={styles.buttonText}>Edit</Text>
</Pressable>
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 15
}}
/>
</View>
<Text
@ -406,49 +421,64 @@ export default function Files() {
{!isFolder && (
<View style={styles.headerButtons}>
<Pressable
disabled={!files}
style={styles.headerButton}
<Button
onPress={() => {
setFavorites((prev) => !prev);
}}
>
<MaterialIcons
name={favorites ? "star" : "star-border"}
size={30}
color={favorites ? styles.headerStarButtonActive.color : styles.headerButton.color}
/>
</Pressable>
icon={favorites ? "star" : "star-border"}
color="transparent"
iconColor={favorites ? "#f1d01f" : "#2d3f70"}
borderColor="#222c47"
borderWidth={2}
iconSize={30}
padding={4}
rippleColor="#283557"
disabled={!files}
margin={{
left: 2,
right: 2
}}
/>
{!name && (
<>
<Pressable
disabled={!files}
style={styles.headerButton}
<Button
onPress={() => {
setTagsMenuOpen(true)
}}
>
<MaterialIcons
name="sell"
size={30}
color={styles.headerButton.color}
/>
</Pressable>
<Pressable
icon="sell"
color="transparent"
iconColor="#2d3f70"
borderColor="#222c47"
borderWidth={2}
iconSize={30}
disabled={!files}
style={styles.headerButton}
padding={4}
rippleColor="#283557"
margin={{
left: 2,
right: 2
}}
/>
<Button
onPress={() => {
router.replace("/upload/file")
}}
>
<MaterialIcons
name="upload-file"
size={30}
color={styles.headerButton.color}
/>
</Pressable>
icon="upload-file"
color="transparent"
iconColor="#2d3f70"
borderColor="#222c47"
borderWidth={2}
iconSize={30}
disabled={!files}
padding={4}
rippleColor="#283557"
margin={{
left: 2,
right: 2
}}
/>
</>
)}
</View>
@ -486,9 +516,7 @@ export default function Files() {
{!isFolder && (
<View style={styles.pagesContainer}>
<Pressable
style={styles.pageButton}
disabled={prevPageDisabled || allPageDisabled}
<Button
onPress={() => {
setNextPageDisabled(false);
@ -504,24 +532,21 @@ export default function Files() {
setPage(newPage);
setSelectedPage(newPage);
}}
>
<Text
style={
allPageDisabled || prevPageDisabled
? {
...styles.pageButtonText,
...styles.pageButtonTextDisabled,
}
: styles.pageButtonText
}
>
PREV
</Text>
</Pressable>
<Pressable
style={styles.pageButton}
text="PREV"
color="transparent"
textColor={(allPageDisabled || prevPageDisabled) ? "gray" : "white"}
borderColor="#222c47"
borderWidth={2}
rippleColor="#283557"
flex={1}
disabled={allPageDisabled || prevPageDisabled}
margin={{
left: 5,
right: 5
}}
/>
<Button
onPress={() => {
setPrevPageDisabled(true);
setNextPageDisabled(false);
@ -531,20 +556,19 @@ export default function Files() {
setPage(newPage);
setSelectedPage(newPage);
}}
>
<Text
style={
allPageDisabled || prevPageDisabled
? {
...styles.pageButtonText,
...styles.pageButtonTextDisabled,
}
: styles.pageButtonText
}
>
1
</Text>
</Pressable>
text="1"
color="transparent"
textColor={(allPageDisabled || prevPageDisabled) ? "gray" : "white"}
borderColor="#222c47"
borderWidth={2}
rippleColor="#283557"
flex={1}
disabled={allPageDisabled || prevPageDisabled}
margin={{
left: 5,
right: 5
}}
/>
<TextInput
inputStyle={styles.input}
@ -576,9 +600,7 @@ export default function Files() {
value={selectedPage}
/>
<Pressable
style={styles.pageButton}
disabled={allPageDisabled || nextPageDisabled}
<Button
onPress={() => {
setNextPageDisabled(true);
setPrevPageDisabled(false);
@ -588,24 +610,21 @@ export default function Files() {
setPage(newPage);
setSelectedPage(newPage);
}}
>
<Text
style={
allPageDisabled || nextPageDisabled
? {
...styles.pageButtonText,
...styles.pageButtonTextDisabled,
}
: styles.pageButtonText
}
>
{files?.pages || "..."}
</Text>
</Pressable>
<Pressable
style={styles.pageButton}
text={files?.pages ? String(files?.pages) : "..."}
color="transparent"
textColor={(nextPageDisabled || allPageDisabled) ? "gray" : "white"}
borderColor="#222c47"
borderWidth={2}
rippleColor="#283557"
flex={1}
disabled={nextPageDisabled || allPageDisabled}
margin={{
left: 5,
right: 5
}}
/>
<Button
onPress={() => {
setPrevPageDisabled(false);
@ -618,20 +637,19 @@ export default function Files() {
setPage(newPage);
setSelectedPage(newPage);
}}
>
<Text
style={
allPageDisabled || nextPageDisabled
? {
...styles.pageButtonText,
...styles.pageButtonTextDisabled,
}
: styles.pageButtonText
}
>
NEXT
</Text>
</Pressable>
text="NEXT"
color="transparent"
textColor={(nextPageDisabled || allPageDisabled) ? "gray" : "white"}
borderColor="#222c47"
borderWidth={2}
rippleColor="#283557"
flex={1}
disabled={nextPageDisabled || allPageDisabled}
margin={{
left: 5,
right: 5
}}
/>
</View>
)}
</View>

View file

@ -8,23 +8,25 @@ import { styles } from "@/styles/folders";
import { useEffect, useState } from "react";
import * as Clipboard from "expo-clipboard";
import * as db from "@/functions/database";
import { type ExternalPathString, Link, useRouter } from "expo-router";
import {
type ExternalPathString,
Link,
useRouter,
} from "expo-router";
import { createFolder, deleteFolder, editFolder, getFolders } from "@/functions/zipline/folders";
createFolder,
deleteFolder,
editFolder,
getFolders,
} from "@/functions/zipline/folders";
import Popup from "@/components/Popup";
import { useAuth } from "@/hooks/useAuth";
import { useShareIntent } from "@/hooks/useShareIntent";
import TextInput from "@/components/TextInput";
import Switch from "@/components/Switch"
import Switch from "@/components/Switch";
import Button from "@/components/Button";
export default function Folders() {
const router = useRouter();
useAuth()
useShareIntent()
useAuth();
useShareIntent();
const [folders, setFolders] = useState<APIFolders | null>(null);
@ -48,14 +50,19 @@ export default function Folders() {
return (
<View style={styles.mainContainer}>
<View style={styles.mainContainer}>
<Popup hidden={!createNewFolder} onClose={() => {
setCreateNewFolder(false)
setNewFolderName(null)
setNewFolderPublic(false)
}}>
<Popup
hidden={!createNewFolder}
onClose={() => {
setCreateNewFolder(false);
setNewFolderName(null);
setNewFolderPublic(false);
}}
>
<View style={styles.popupContent}>
<Text style={styles.mainHeaderText}>Create Folder</Text>
{newFolderError && <Text style={styles.errorText}>{newFolderError}</Text>}
{newFolderError && (
<Text style={styles.errorText}>{newFolderError}</Text>
)}
<TextInput
title="Name:"
@ -65,33 +72,40 @@ export default function Folders() {
value={newFolderName || ""}
placeholder="myFolder"
/>
<Switch onValueChange={() => setNewFolderPublic((prev) => !prev)} value={newFolderPublic} title="Public" />
<Pressable
style={styles.button}
<Switch
onValueChange={() => setNewFolderPublic((prev) => !prev)}
value={newFolderPublic}
title="Public"
/>
<Button
onPress={async () => {
setNewFolderError(null)
setNewFolderError(null);
if (!newFolderName || newFolderName.length <= 0) return setNewFolderError("Please insert a folder name");
if (!newFolderName || newFolderName.length <= 0)
return setNewFolderError("Please insert a folder name");
const createdFolder = await createFolder(
newFolderName,
newFolderPublic,
);
const createdFolder = await createFolder(newFolderName, newFolderPublic);
if (typeof createdFolder === "string")
return setNewFolderError(createdFolder);
setNewFolderName(null);
setNewFolderPublic(false);
const newFolders = await getFolders()
const newFolders = await getFolders();
setFolders(typeof newFolders === "string" ? null : newFolders)
setFolders(typeof newFolders === "string" ? null : newFolders);
setCreateNewFolder(false);
}}
>
<Text style={styles.buttonText}>Create</Text>
</Pressable>
text="Create"
color="#323ea8"
/>
</View>
</Popup>
@ -100,35 +114,28 @@ export default function Folders() {
<View style={styles.header}>
<Text style={styles.headerText}>Folders</Text>
<View style={styles.headerButtons}>
<Pressable
style={styles.headerButton}
<Button
onPress={() => {
setCreateNewFolder(true)
setCreateNewFolder(true);
}}
>
<MaterialIcons
name="create-new-folder"
size={30}
color={styles.headerButton.color}
/>
</Pressable>
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
>
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
<View>
<Table>
<Row
data={[
"Name",
"Public",
"Created",
"Actions",
]}
data={["Name", "Public", "Created", "Actions"]}
widthArr={[80, 50, 130, 150]}
style={styles.tableHeader}
textStyle={styles.rowText}
@ -154,19 +161,13 @@ export default function Folders() {
{folder.name}
</Link>
) : (
<Text
key={folder.id}
style={styles.rowText}
>
<Text key={folder.id} style={styles.rowText}>
{folder.name}
</Text>
)
);
const isPublic = (
<Text
key={folder.id}
style={styles.rowText}
>
<Text key={folder.id} style={styles.rowText}>
{folder.public ? "Yes" : "No"}
</Text>
);
@ -182,29 +183,26 @@ export default function Folders() {
const actions = (
<View style={styles.actionsContainer}>
<Pressable
style={styles.actionButton}
<Button
icon="folder-open"
color="#323ea8"
onPress={() => {
const folderId = folder.id;
router.replace(`/files?folderId=${folderId}`)
router.replace(`/files?folderId=${folderId}`);
}}
>
<MaterialIcons
name="folder-open"
size={20}
color={"white"}
/>
</Pressable>
iconSize={20}
width={32}
height={32}
padding={6}
/>
<Pressable
style={{
...styles.actionButton,
...(!folder.public && styles.actionButtonDisabled)
}}
disabled={!folder.public}
<Button
icon="content-copy"
color={folder.public ? "#323ea8" : "#181c28"}
iconColor={folder.public ? "white" : "#2a3952"}
onPress={async () => {
const urlDest = `${dashUrl}/folder/${folder.id}`
const urlDest = `${dashUrl}/folder/${folder.id}`;
const saved =
await Clipboard.setStringAsync(urlDest);
@ -220,80 +218,80 @@ export default function Folders() {
ToastAndroid.SHORT,
);
}}
>
<MaterialIcons
name="content-copy"
size={20}
color={folder.public ? "white" : "#2a3952"}
/>
</Pressable>
disabled={!folder.public}
iconSize={20}
width={32}
height={32}
padding={6}
/>
<Pressable
style={{
...styles.actionButton,
...(!folder.public && styles.actionButtonPrivate)
}}
<Button
onPress={async () => {
const folderId = folder.id;
const success = await editFolder(folderId, !folder.public);
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
)
if (typeof success === "string")
return ToastAndroid.show(
`Failed to update the folder "${folder.name}"`,
ToastAndroid.SHORT,
);
const folderIndex = folders.findIndex((fold) => folder.id === fold.id)
ToastAndroid.show(
`Updated the folder "${folder.name}"'s visibility`,
ToastAndroid.SHORT,
);
const newFolders = [...folders];
newFolders[folderIndex].public = !folder.public;
const folderIndex = folders.findIndex(
(fold) => folder.id === fold.id,
);
setFolders(newFolders);
const newFolders = [...folders];
newFolders[folderIndex].public = !folder.public;
setFolders(newFolders);
}}
>
<MaterialIcons
name={folder.public ? "lock-open" : "lock"}
size={20}
color={"white"}
/>
</Pressable>
color={folder.public ? "#323ea8": "#343a40"}
icon={folder.public ? "lock-open" : "lock"}
iconSize={20}
width={32}
height={32}
padding={6}
/>
<Pressable
style={{
...styles.actionButton,
...styles.actionButtonDanger,
}}
<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
)
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)
const newFolders = folders.filter(
(fold) => fold.id !== folder.id,
);
setFolders(newFolders)
setFolders(newFolders);
ToastAndroid.show(
`Deleted the folder "${folder.name}"`,
ToastAndroid.SHORT
)
ToastAndroid.show(
`Deleted the folder "${folder.name}"`,
ToastAndroid.SHORT,
);
}}
>
<MaterialIcons
name="delete"
size={20}
color={"white"}
/>
</Pressable>
color="#CF4238"
icon="delete"
iconSize={20}
width={32}
height={32}
padding={6}
/>
</View>
);
@ -314,12 +312,7 @@ export default function Folders() {
return (
<Row
key={folder.id}
data={[
name,
isPublic,
created,
actions,
]}
data={[name, isPublic, created, actions]}
widthArr={[80, 50, 130, 150]}
style={rowStyle}
textStyle={styles.rowText}

View file

@ -7,6 +7,7 @@ import { styles } from "@/styles/login";
import { useLoginAuth } from "@/hooks/useLoginAuth";
import React from "react";
import TextInput from "@/components/TextInput";
import Button from "@/components/Button";
export default function Login() {
const router = useRouter();
@ -83,18 +84,16 @@ export default function Login() {
</>
)}
<Pressable
style={{
...styles.button,
...styles.buttonSecondary,
}}
<Button
onPress={() => setTokenLogin((prev) => !prev)}
>
<Text style={styles.buttonText}>Use {tokenLogin ? "Password" : "Token"} Login</Text>
</Pressable>
color="#616060"
text={`Use ${tokenLogin ? "Password" : "Token"} Login`}
margin={{
top: 5
}}
/>
<Pressable
style={styles.button}
<Button
onPress={async () => {
setError(undefined)
@ -136,9 +135,12 @@ export default function Login() {
return router.replace("/");
}}
>
<Text style={styles.buttonText}>Login</Text>
</Pressable>
text="Login"
color="#323ea8"
margin={{
top: 5
}}
/>
</View>
</View>
);

View file

@ -23,6 +23,7 @@ import { clearTempFiles, clearZeroByteFiles, generateThumbnails, getZeroByteFile
import { useRouter } from "expo-router";
import TextInput from "@/components/TextInput"
import Switch from "@/components/Switch";
import Button from "@/components/Button";
export default function UserSettings() {
const router = useRouter()
@ -161,39 +162,43 @@ export default function UserSettings() {
<Text style={styles.serverActionWarningText}>This will delete {zeroByteFiles} files from the database and datasource.</Text>
<View style={styles.manageServerActionButtonsContainer}>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonCancel,
marginRight: 10
}} onPress={() => {
setClearZeroByteFilesPopupOpen(false)
}}>
<Text style={styles.buttonText}>Cancel</Text>
</Pressable>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonDanger,
marginRight: 10
}} onPress={async () => {
const success = await clearZeroByteFiles()
if (typeof success === "string") {
setSaveError(success)
<Button
onPress={() => {
setClearZeroByteFilesPopupOpen(false)
}}
text="Cancel"
color="#181c28"
margin={{
right: 10,
top: 10,
}}
/>
return;
}
setClearZeroByteFilesPopupOpen(false)
ToastAndroid.show(
success.status,
ToastAndroid.SHORT
)
}}>
<Text style={styles.buttonText}>Yes, Delete</Text>
</Pressable>
<Button
color="#CF4238"
margin={{
right: 10,
top: 10,
}}
text="Yes, Delete"
onPress={async () => {
const success = await clearZeroByteFiles()
if (typeof success === "string") {
setSaveError(success)
setClearZeroByteFilesPopupOpen(false)
return;
}
setClearZeroByteFilesPopupOpen(false)
ToastAndroid.show(
success.status,
ToastAndroid.SHORT
)
}}
/>
</View>
</View>
@ -213,39 +218,43 @@ export default function UserSettings() {
<Text style={styles.serverActionWarningText}>This will delete temporary files stored within the temporary directory (defined in the configuration). This should not cause harm unless there are files that are being processed still.</Text>
<View style={styles.manageServerActionButtonsContainer}>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonCancel,
marginRight: 10
}} onPress={() => {
setClearTempFilesPopupOpen(false)
}}>
<Text style={styles.buttonText}>Cancel</Text>
</Pressable>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonDanger,
marginRight: 10
}} onPress={async () => {
const success = await clearTempFiles()
if (typeof success === "string") {
setSaveError(success)
<Button
onPress={() => {
setClearTempFilesPopupOpen(false)
}}
text="Cancel"
color="#181c28"
margin={{
right: 10,
top: 10,
}}
/>
return;
}
setClearTempFilesPopupOpen(false)
ToastAndroid.show(
success.status,
ToastAndroid.SHORT
)
}}>
<Text style={styles.buttonText}>Yes, Delete</Text>
</Pressable>
<Button
color="#CF4238"
margin={{
right: 10,
top: 10,
}}
text="Yes, Delete"
onPress={async () => {
const success = await clearTempFiles()
if (typeof success === "string") {
setSaveError(success)
setClearTempFilesPopupOpen(false)
return;
}
setClearTempFilesPopupOpen(false)
ToastAndroid.show(
success.status,
ToastAndroid.SHORT
)
}}
/>
</View>
</View>
@ -281,48 +290,52 @@ export default function UserSettings() {
/>
<View style={styles.manageServerActionButtonsContainer}>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonCancel,
marginRight: 10
}} onPress={() => {
setRequerySizeOfFilesPopupOpen(false)
setRequerySizeForceDelete(false)
setRequerySizeForceUpdate(false)
}}>
<Text style={styles.buttonText}>Cancel</Text>
</Pressable>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonDanger,
marginRight: 10
}} onPress={async () => {
const success = await requeryFileSize({
forceDelete: requerySizeForceDelete,
forceUpdate: requerySizeForceUpdate
})
if (typeof success === "string") {
setSaveError(success)
<Button
onPress={() => {
setRequerySizeOfFilesPopupOpen(false)
setRequerySizeForceDelete(false)
setRequerySizeForceUpdate(false)
}}
text="Cancel"
color="#181c28"
margin={{
right: 10,
top: 10,
}}
/>
return;
}
setRequerySizeOfFilesPopupOpen(false)
setRequerySizeForceDelete(false)
setRequerySizeForceUpdate(false)
ToastAndroid.show(
success.status,
ToastAndroid.SHORT
)
}}>
<Text style={styles.buttonText}>Requery</Text>
</Pressable>
<Button
color="#CF4238"
margin={{
right: 10,
top: 10,
}}
text="Requery"
onPress={async () => {
const success = await requeryFileSize({
forceDelete: requerySizeForceDelete,
forceUpdate: requerySizeForceUpdate
})
if (typeof success === "string") {
setSaveError(success)
setRequerySizeOfFilesPopupOpen(false)
setRequerySizeForceDelete(false)
setRequerySizeForceUpdate(false)
return;
}
setRequerySizeOfFilesPopupOpen(false)
setRequerySizeForceDelete(false)
setRequerySizeForceUpdate(false)
ToastAndroid.show(
success.status,
ToastAndroid.SHORT
)
}}
/>
</View>
</View>
@ -351,42 +364,46 @@ export default function UserSettings() {
/>
<View style={styles.manageServerActionButtonsContainer}>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonCancel,
marginRight: 10
}} onPress={() => {
setGenerateThumbnailsPopupOpen(false)
setGenerateThumbnailsRerun(false)
}}>
<Text style={styles.buttonText}>Cancel</Text>
</Pressable>
<Button
onPress={() => {
setGenerateThumbnailsPopupOpen(false)
setGenerateThumbnailsRerun(false)
}}
text="Cancel"
color="#181c28"
margin={{
right: 10,
top: 10,
}}
/>
<Pressable style={{
...styles.button,
...styles.manageServerActionButtonDanger,
marginRight: 10
}} onPress={async () => {
const success = await generateThumbnails(generateThumbnailsRerun)
<Button
color="#CF4238"
margin={{
right: 10,
top: 10,
}}
text="Generate"
onPress={async () => {
const success = await generateThumbnails(generateThumbnailsRerun)
if (typeof success === "string") {
setSaveError(success)
setGenerateThumbnailsPopupOpen(false)
setGenerateThumbnailsRerun(false)
return;
}
if (typeof success === "string") {
setSaveError(success)
setGenerateThumbnailsPopupOpen(false)
setGenerateThumbnailsRerun(false)
return;
}
setGenerateThumbnailsPopupOpen(false)
setGenerateThumbnailsRerun(false)
ToastAndroid.show(
success.status,
ToastAndroid.LONG
)
}}>
<Text style={styles.buttonText}>Generate</Text>
</Pressable>
ToastAndroid.show(
success.status,
ToastAndroid.LONG
)
}}
/>
</View>
</View>
@ -442,49 +459,62 @@ export default function UserSettings() {
password
/>
<Pressable style={styles.button} onPress={() => handleSave("userInfo")}>
<Text style={styles.buttonText}>Save</Text>
</Pressable>
<Button
onPress={() => handleSave("userInfo")}
color="#323ea8"
text="Save"
icon="save"
margin={{
top: 10,
}}
/>
</View>
{/* Avatar */}
<View style={styles.settingGroup}>
<Text style={styles.headerText}>Avatar</Text>
<Text style={styles.headerText}>Avatar:</Text>
<Pressable style={styles.avatarButton} onPress={async () => {
const output = await DocumentPicker.getDocumentAsync({
type: [
"image/png",
"image/jpeg",
"image/jpg"
],
copyToCacheDirectory: true,
});
if (output.canceled || !output.assets) {
setAvatar(undefined)
setAvatarName(null)
return;
};
const fileURI = output.assets[0].uri
const fileInfo = await FileSystem.getInfoAsync(fileURI)
if (!fileInfo.exists) return;
const avatarDataURI = await getFileDataURI(fileURI)
setAvatar(avatarDataURI || undefined)
const filename = fileURI.split('/').pop() || "avatar.png"
setAvatarName(filename)
}}>
<Text style={styles.avatarButtonText}>{avatar ? avatarName : "Select an Avatar..."}</Text>
</Pressable>
<Button
color="transparent"
borderWidth={2}
borderColor="#222c47"
margin={{
top: 5
}}
rippleColor="gray"
text={avatar ? avatarName as string : "Select an Avatar..."}
onPress={async () => {
const output = await DocumentPicker.getDocumentAsync({
type: [
"image/png",
"image/jpeg",
"image/jpg"
],
copyToCacheDirectory: true,
});
if (output.canceled || !output.assets) {
setAvatar(undefined)
setAvatarName(null)
return;
};
const fileURI = output.assets[0].uri
const fileInfo = await FileSystem.getInfoAsync(fileURI)
if (!fileInfo.exists) return;
const avatarDataURI = await getFileDataURI(fileURI)
setAvatar(avatarDataURI || undefined)
const filename = fileURI.split('/').pop() || "avatar.png"
setAvatarName(filename)
}}
/>
<View style={styles.avatarPreviewContainer}>
<Text style={styles.avatarPreviewHeader}>Avatar Preview</Text>
@ -493,27 +523,38 @@ export default function UserSettings() {
<View style={styles.avatarButtonsContainer}>
{avatar && (
<Pressable
style={{
...styles.button,
...styles.manageAvatarButton,
...styles.cancelAvatarButton
<Button
text="Cancel"
color="transparent"
textColor="white"
height="auto"
width="28.33%"
margin={{
left: "2.5%",
right: "2.5%",
top: 10
}}
rippleColor="gray"
borderWidth={2}
borderColor="#ff8787"
onPress={() => {
setAvatar(undefined)
setAvatarName(null)
}}
>
<Text style={styles.buttonText}>Cancel</Text>
</Pressable>
/>
)}
{currentAvatar && (
<Pressable
style={{
...styles.button,
...styles.manageAvatarButton,
...styles.removeAvatarButton
<Button
text="Remove Avatar"
color="#e03131"
textColor="white"
height="auto"
width="28.33%"
margin={{
left: "2.5%",
right: "2.5%",
top: 10
}}
onPress={async () => {
const success = await editCurrentUser({
@ -533,17 +574,21 @@ export default function UserSettings() {
ToastAndroid.SHORT
)
}}
>
<Text style={styles.buttonText}>Remove Avatar</Text>
</Pressable>
/>
)}
<Pressable
style={{
...styles.button,
...styles.manageAvatarButton,
...(!avatar && styles.saveAvatarButtonDisabled)
<Button
text="Save"
color={avatar ? "#323ea8" : "#181c28"}
textColor={avatar ? "white" : "gray"}
height="auto"
width="28.33%"
margin={{
left: "2.5%",
right: "2.5%",
top: 10
}}
disabled={!avatar}
onPress={async () => {
const success = await editCurrentUser({
avatar: avatar
@ -562,12 +607,7 @@ export default function UserSettings() {
ToastAndroid.SHORT
)
}}
>
<Text style={{
...styles.buttonText,
...(!avatar && styles.saveAvatarButtonTextDisabled)
}}>Save</Text>
</Pressable>
/>
</View>
</View>
@ -665,31 +705,42 @@ export default function UserSettings() {
placeholder="My Cool Color"
/>
<Pressable style={styles.button} onPress={() => handleSave("viewingFiles")}>
<Text style={styles.buttonText}>Save</Text>
</Pressable>
<Button
onPress={() => handleSave("viewingFiles")}
color="#323ea8"
text="Save"
icon="save"
margin={{
top: 10,
}}
/>
</View>
{/* Export Files */}
<View style={styles.settingGroup}>
<Text style={styles.headerText}>Export Files</Text>
<Pressable style={styles.button} onPress={async () => {
const success = await createUserExport()
if (typeof success === "string") return setSaveError(success);
const newExports = await getUserExports()
setExports(typeof newExports === "string" ? null : newExports)
ToastAndroid.show(
"Successfully started creating the export",
ToastAndroid.SHORT
)
}}>
<Text style={styles.buttonText}>New Export</Text>
</Pressable>
<Button
onPress={async () => {
const success = await createUserExport()
if (typeof success === "string") return setSaveError(success);
const newExports = await getUserExports()
setExports(typeof newExports === "string" ? null : newExports)
ToastAndroid.show(
"Successfully started creating the export",
ToastAndroid.SHORT
)
}}
color="#323ea8"
text="New Export"
margin={{
top: 10,
}}
/>
<View style={styles.exportsContainer}>
<ScrollView
@ -745,11 +796,9 @@ export default function UserSettings() {
const actions = (
<View style={styles.actionsContainer}>
<Pressable
style={{
...styles.actionButton,
...styles.actionButtonDanger
}}
<Button
icon="delete"
color="#CF4238"
onPress={async () => {
setSaveError(null)
@ -768,19 +817,16 @@ export default function UserSettings() {
ToastAndroid.SHORT,
);
}}
>
<MaterialIcons
name="delete"
size={20}
color={"white"}
/>
</Pressable>
<Pressable
style={{
...styles.actionButton,
...(!zlExport.completed && styles.actionButtonDisabled)
}}
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;
@ -832,13 +878,11 @@ export default function UserSettings() {
ToastAndroid.SHORT
)
}}
>
<MaterialIcons
name="download"
size={20}
color={"white"}
/>
</Pressable>
iconSize={20}
width={32}
height={32}
padding={6}
/>
</View>
);
@ -884,40 +928,60 @@ export default function UserSettings() {
<Text style={styles.headerText}>Server Actions</Text>
<View style={styles.serverActionButtonRow}>
<Pressable style={{
...styles.button,
...styles.serverActionButton
}} onPress={async () => {
setClearZeroByteFilesPopupOpen(true)
<Button
onPress={async () => {
setClearZeroByteFilesPopupOpen(true)
const zeroByteFiles = await getZeroByteFiles()
setZeroByteFiles(typeof zeroByteFiles === "string" ? 0 : zeroByteFiles.files.length)
}}
color="#323ea8"
text="Clear Zero Byte Files"
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 10,
}}
/>
const zeroByteFiles = await getZeroByteFiles()
setZeroByteFiles(typeof zeroByteFiles === "string" ? 0 : zeroByteFiles.files.length)
}}>
<Text style={styles.buttonText}>Clear Zero Byte Files</Text>
</Pressable>
<Pressable style={{
...styles.button,
...styles.serverActionButton
}} onPress={() => setClearTempFilesPopupOpen(true)}>
<Text style={styles.buttonText}>Clear Temp Files</Text>
</Pressable>
<Button
onPress={() => setClearTempFilesPopupOpen(true)}
color="#323ea8"
text="Clear Temp Files"
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 10,
}}
/>
</View>
<View style={styles.serverActionButtonRow}>
<Pressable style={{
...styles.button,
...styles.serverActionButton
}} onPress={() => setRequerySizeOfFilesPopupOpen(true)}>
<Text style={styles.buttonText}>Requery Size of Files</Text>
</Pressable>
<Button
onPress={() => setRequerySizeOfFilesPopupOpen(true)}
color="#323ea8"
text="Requery Size of Files"
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 10,
}}
/>
<Pressable style={{
...styles.button,
...styles.serverActionButton
}} onPress={() => setGenerateThumbnailsPopupOpen(true)}>
<Text style={styles.buttonText}>Generate Thumbnails</Text>
</Pressable>
<Button
onPress={() => setGenerateThumbnailsPopupOpen(true)}
color="#323ea8"
text="Generate Thumbnails"
width="45%"
margin={{
left: "2.5%",
right: "2.5%",
top: 10,
}}
/>
</View>
</View>
@ -925,59 +989,65 @@ export default function UserSettings() {
<View style={styles.settingGroup}>
<Text style={styles.headerText}>App Settings</Text>
<Pressable style={{
...styles.button,
...styles.buttonSecondary
}} onPress={async () => {
const permissions = await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
<Button
onPress={async () => {
const permissions = await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
if (!permissions.granted) return ToastAndroid.show(
"The permission to the folder was not granted",
ToastAndroid.SHORT
);
db.set("exportDownloadPath", permissions.directoryUri)
ToastAndroid.show(
"Successfully changed the folder",
ToastAndroid.SHORT
)
}}
color="#323244"
text="Change Export Download Folder"
margin={{
top: 10,
}}
/>
if (!permissions.granted) return ToastAndroid.show(
"The permission to the folder was not granted",
ToastAndroid.SHORT
);
<Button
onPress={async () => {
const permissions = await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
if (!permissions.granted) return ToastAndroid.show(
"The permission to the folder was not granted",
ToastAndroid.SHORT
);
db.set("fileDownloadPath", permissions.directoryUri)
ToastAndroid.show(
"Successfully changed the folder",
ToastAndroid.SHORT
)
}}
color="#323244"
text="Change File Download Folder"
margin={{
top: 10,
}}
/>
db.set("exportDownloadPath", permissions.directoryUri)
ToastAndroid.show(
"Successfully changed the folder",
ToastAndroid.SHORT
)
}}>
<Text style={styles.buttonText}>Change Export Download Folder</Text>
</Pressable>
<Pressable style={{
...styles.button,
...styles.buttonSecondary
}} onPress={async () => {
const permissions = await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
if (!permissions.granted) return ToastAndroid.show(
"The permission to the folder was not granted",
ToastAndroid.SHORT
);
db.set("fileDownloadPath", permissions.directoryUri)
ToastAndroid.show(
"Successfully changed the folder",
ToastAndroid.SHORT
)
}}>
<Text style={styles.buttonText}>Change File Download Folder</Text>
</Pressable>
<Pressable style={{
...styles.button,
...styles.buttonDanger
}} onPress={async () => {
await db.del("url")
await db.del("token")
router.replace("/login")
}}>
<Text style={styles.buttonText}>Logout</Text>
</Pressable>
<Button
onPress={async () => {
await db.del("url")
await db.del("token")
router.replace("/login")
}}
color="#CF4238"
text="Logout"
margin={{
top: 10,
}}
/>
</View>
</KeyboardAwareScrollView>
</View>

View file

@ -18,6 +18,7 @@ import { useAuth } from "@/hooks/useAuth";
import { useShareIntent } from "@/hooks/useShareIntent";
import TextInput from "@/components/TextInput";
import Switch from "@/components/Switch";
import Button from "@/components/Button";
export default function Urls() {
useAuth()
@ -131,9 +132,13 @@ export default function Urls() {
value={newUrlEnabled}
onValueChange={() => setNewUrlEnabled((prev) => !prev)}
/>
<Pressable
style={styles.button}
<Button
color="#323ea8"
text="Shorten"
margin={{
top: 5
}}
onPress={async () => {
setNewUrlError(undefined);
@ -180,9 +185,7 @@ export default function Urls() {
ToastAndroid.SHORT,
);
}}
>
<Text style={styles.buttonText}>Shorten</Text>
</Pressable>
/>
<Text
style={styles.popupSubHeaderText}
@ -251,9 +254,13 @@ export default function Urls() {
value={editUrlEnabled}
onValueChange={() => setEditUrlEnabled((prev) => !prev)}
/>
<Pressable
style={styles.button}
<Button
color="#323ea8"
text="Edit"
margin={{
top: 5
}}
onPress={async () => {
setEditUrlError(undefined);
@ -287,9 +294,7 @@ export default function Urls() {
setUrlToEdit(null);
}}
>
<Text style={styles.buttonText}>Edit</Text>
</Pressable>
/>
<Text
style={styles.popupSubHeaderText}
@ -306,18 +311,19 @@ export default function Urls() {
<View style={styles.header}>
<Text style={styles.headerText}>URLs</Text>
<View style={styles.headerButtons}>
<Pressable
style={styles.headerButton}
<Button
onPress={() => {
setCreateNewUrl(true);
}}
>
<MaterialIcons
name="add-link"
size={30}
color={styles.headerButton.color}
/>
</Pressable>
icon="add-link"
color="transparent"
iconColor="#2d3f70"
borderColor="#222c47"
borderWidth={2}
iconSize={30}
padding={4}
rippleColor="#283557"
/>
</View>
</View>
@ -424,8 +430,9 @@ export default function Urls() {
const actions = (
<View style={styles.actionsContainer}>
<Pressable
style={styles.actionButton}
<Button
icon="content-copy"
color="#323ea8"
onPress={async () => {
const urlDest = url.vanity
? `${dashUrl}${settings.urlsRoute === "/" ? "" : settings.urlsRoute}/${url.vanity}`
@ -445,32 +452,27 @@ export default function Urls() {
ToastAndroid.SHORT,
);
}}
>
<MaterialIcons
name="content-copy"
size={20}
color={"white"}
/>
</Pressable>
iconSize={20}
width={32}
height={32}
padding={6}
/>
<Pressable
style={styles.actionButton}
<Button
icon="edit"
color="#323ea8"
onPress={() => {
setUrlToEdit(url)
}}
>
<MaterialIcons
name="edit"
size={20}
color={"white"}
/>
</Pressable>
iconSize={20}
width={32}
height={32}
padding={6}
/>
<Pressable
style={{
...styles.actionButton,
...styles.actionButtonDanger,
}}
<Button
icon="delete"
color="#CF4238"
onPress={async () => {
const urlId = url.id;
@ -490,13 +492,11 @@ export default function Urls() {
ToastAndroid.SHORT
)
}}
>
<MaterialIcons
name="delete"
size={20}
color={"white"}
/>
</Pressable>
iconSize={20}
width={32}
height={32}
padding={6}
/>
</View>
);

View file

@ -14,23 +14,16 @@ export default function NotFoundScreen() {
<Text style={styles.text}>This page does not exist.</Text>
<Button onPress={() => {
// router.replace({
// pathname: "/",
// });
}} text="Head to the Dashboard" color="#323ea8" />
{/* <Pressable
style={styles.button}
<Button
onPress={() => {
router.replace({
pathname: "/",
});
}}
>
<Text style={styles.buttonText}>Head to the Dashboard</Text>
</Pressable> */}
text="Head to the Dashboard"
color="#323ea8"
/>
</View>
</View>
);
}
}

View file

@ -42,7 +42,7 @@ export default function Home() {
// db.del("url")
// db.del("token")
router.replace("/test");
// router.replace("/login");
}
});

View file

@ -4,12 +4,10 @@ import { MaterialIcons } from "@expo/vector-icons";
import { type ColorValue, type DimensionValue, Pressable, Text } from "react-native";
interface Props {
onPress: () => void | Promise<void>;
onPress: () => unknown | Promise<unknown>;
disabled?: boolean;
color: ColorValue;
disabledColor?: ColorValue;
textColor?: ColorValue;
disabledTextColor?: ColorValue;
text?: string;
width?: DimensionValue;
height?: DimensionValue;
@ -17,15 +15,23 @@ interface Props {
iconColor?: ColorValue;
borderWidth?: number;
borderColor?: ColorValue;
iconSize?: number;
padding?: number;
rippleColor?: ColorValue;
margin?: {
top?: DimensionValue;
bottom?: DimensionValue;
left?: DimensionValue;
right?: DimensionValue;
},
flex?: number
}
export default function Button({
onPress = () => {},
disabled = false,
color,
disabledColor,
textColor = "white",
disabledTextColor = "gray",
text,
width,
height,
@ -33,37 +39,45 @@ export default function Button({
iconColor = "white",
borderWidth = 0,
borderColor,
iconSize = 20,
padding = 10,
margin = {},
rippleColor,
flex
}: Props) {
return (
<Pressable
onPress={onPress}
disabled={disabled}
android_ripple={{
color: disabled
? getRippleColor(disabledColor as string || "#323244")
: getRippleColor(color as string),
color: rippleColor || getRippleColor(color as string)
}}
style={{
...styles.button,
width: width,
...(height && { height: height }),
backgroundColor: disabled ? disabledColor : color,
backgroundColor: color,
borderWidth: borderWidth,
borderColor: borderColor,
padding: 10 - borderWidth
padding: padding - borderWidth,
...(margin.left && { marginLeft: margin.left }),
...(margin.right && { marginRight: margin.right }),
...(margin.top && { marginTop: margin.top }),
...(margin.bottom && { marginBottom: margin.bottom }),
...(flex && { flex })
}}
>
{icon && (
<MaterialIcons
name={icon}
size={20}
size={iconSize}
color={iconColor}
/>
)}
{text && (
<Text style={{
...styles.buttonText,
color: disabled ? disabledTextColor : textColor,
color: textColor,
...(icon && { marginLeft: 5 })
}}>{text}</Text>
)}

View file

@ -6,6 +6,7 @@ export const styles = StyleSheet.create({
borderRadius: 6,
height: 40,
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
},
buttonText: {