Add avatar upload setting

This commit is contained in:
Zoe Roux 2024-02-04 23:14:10 +01:00
parent 0bd497279d
commit 2ecda09ee4
9 changed files with 87 additions and 6 deletions

View File

@ -34,6 +34,7 @@
"expo-dev-client": "~3.3.7",
"expo-file-system": "~16.0.5",
"expo-font": "~11.10.2",
"expo-image-picker": "~14.7.1",
"expo-linear-gradient": "~12.7.1",
"expo-linking": "~6.2.2",
"expo-localization": "~14.8.3",

View File

@ -108,6 +108,7 @@ const nextConfig = {
"expo-av",
"expo-modules-core",
"expo-linear-gradient",
"expo-image-picker",
],
experimental: {
outputFileTracingRoot: path.join(__dirname, "../../"),

View File

@ -24,6 +24,7 @@
"@tanstack/react-query": "^5.17.19",
"@tanstack/react-query-devtools": "^5.17.21",
"array-shuffle": "^3.0.0",
"expo-image-picker": "~14.7.1",
"expo-linear-gradient": "^12.7.1",
"expo-modules-core": "^1.11.8",
"hls.js": "^1.5.2",

View File

@ -48,6 +48,7 @@ export const queryFn = async <Parser extends z.ZodTypeAny>(
| ({
path: (string | false | undefined | null)[];
body?: object;
formData?: FormData;
plainText?: boolean;
} & Partial<QueryFunctionContext>)
),
@ -72,7 +73,12 @@ export const queryFn = async <Parser extends z.ZodTypeAny>(
try {
resp = await fetch(path, {
method: context.method,
body: "body" in context && context.body ? JSON.stringify(context.body) : undefined,
body:
"body" in context && context.body
? JSON.stringify(context.body)
: "formData" in context && context.formData
? context.formData
: undefined,
headers: {
...(token ? { Authorization: token } : {}),
...("body" in context ? { "Content-Type": "application/json" } : {}),

View File

@ -23,8 +23,7 @@ import { useYoshiki, px, Stylable } from "yoshiki/native";
import { Icon } from "./icons";
import { P } from "./text";
import AccountCircle from "@material-symbols/svg-400/rounded/account_circle-fill.svg";
import { YoshikiStyle } from "yoshiki";
import { ComponentType, forwardRef, RefAttributes, useEffect, useState } from "react";
import { ComponentType, forwardRef, RefAttributes } from "react";
const stringToColor = (string: string) => {
let hash = 0;

View File

@ -21,6 +21,7 @@
"@shopify/flash-list": "^1.3.1",
"@tanstack/react-query": "*",
"expo-file-system": "*",
"expo-image-picker": "~14.7.1",
"expo-linear-gradient": "*",
"expo-router": "*",
"i18next": "*",

View File

@ -19,21 +19,33 @@
*/
import { Account, KyooErrors, deleteAccount, logout, queryFn, useAccount } from "@kyoo/models";
import { Alert, Button, H1, Icon, Input, P, Popup, ts, usePopup } from "@kyoo/primitives";
import { Alert, Avatar, Button, H1, Icon, Input, P, Popup, ts, usePopup } from "@kyoo/primitives";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { ComponentProps, useState } from "react";
import { useTranslation } from "react-i18next";
import { View } from "react-native";
import { rem, useYoshiki } from "yoshiki/native";
import * as ImagePicker from "expo-image-picker";
import { PasswordInput } from "../login/password-input";
import { Preference, SettingsContainer } from "./base";
import Username from "@material-symbols/svg-400/outlined/badge.svg";
import AccountCircle from "@material-symbols/svg-400/rounded/account_circle-fill.svg";
import Mail from "@material-symbols/svg-400/outlined/mail.svg";
import Password from "@material-symbols/svg-400/outlined/password.svg";
import Delete from "@material-symbols/svg-400/rounded/delete.svg";
import Logout from "@material-symbols/svg-400/rounded/logout.svg";
function dataURItoBlob(dataURI: string) {
const byteString = atob(dataURI.split(",")[1]);
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: "image/jpeg" });
}
export const AccountSettings = () => {
const account = useAccount()!;
const { css, theme } = useYoshiki();
@ -118,6 +130,33 @@ export const AccountSettings = () => {
}
/>
</Preference>
<Preference
icon={AccountCircle}
customIcon={<Avatar src={account.logo} />}
label={t("settings.account.avatar.label")}
description={t("settings.account.avatar.description")}
>
<Button
text={t("misc.edit")}
onPress={async () => {
const img = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
aspect: [1, 1],
quality: 1,
base64: true,
});
if (img.canceled || img.assets.length !== 1) return;
const data = dataURItoBlob(img.assets[0].uri);
const formData = new FormData();
formData.append("picture", data);
await queryFn({
method: "POST",
path: ["auth", "me", "logo"],
formData,
});
}}
/>
</Preference>
<Preference icon={Mail} label={t("settings.account.email.label")} description={account.email}>
<Button
text={t("misc.edit")}

View File

@ -36,12 +36,14 @@ import { View } from "react-native";
import { px, rem, useYoshiki } from "yoshiki/native";
export const Preference = ({
customIcon,
icon,
label,
description,
children,
...props
}: {
customIcon?: ReactElement;
icon: Icon;
label: string;
description: string;
@ -62,8 +64,16 @@ export const Preference = ({
props,
)}
>
<View {...css({ flexDirection: "row", alignItems: "center", flexShrink: 1 })}>
<Icon icon={icon} {...css({ marginX: ts(2) })} />
<View
{...css({
flexDirection: "row",
alignItems: "center",
flexShrink: 1,
marginX: ts(2),
gap: ts(2),
})}
>
{customIcon ?? <Icon icon={icon} />}
<View {...css({ flexShrink: 1 })}>
<P {...css({ marginBottom: 0 })}>{label}</P>
<SubP>{description}</SubP>

View File

@ -2619,6 +2619,7 @@ __metadata:
"@shopify/flash-list": ^1.3.1
"@tanstack/react-query": "*"
expo-file-system: "*"
expo-image-picker: ~14.7.1
expo-linear-gradient: "*"
expo-router: "*"
i18next: "*"
@ -7420,6 +7421,26 @@ __metadata:
languageName: node
linkType: hard
"expo-image-loader@npm:~4.6.0":
version: 4.6.0
resolution: "expo-image-loader@npm:4.6.0"
peerDependencies:
expo: "*"
checksum: 02981667f03dc429cd9db37e0acc302e4a0c4bb5875dc087b1c26388ef64563481e52dddc1d42dd32794eb7051d1acf5bc0c078413469c29025a02d4d4af1154
languageName: node
linkType: hard
"expo-image-picker@npm:~14.7.1":
version: 14.7.1
resolution: "expo-image-picker@npm:14.7.1"
dependencies:
expo-image-loader: ~4.6.0
peerDependencies:
expo: "*"
checksum: f9022cc9162365471b8e979df2c7a2156f43819b4717fb6ba376aedb6b55352a7b60b3a50a279dd58cf2551fbdd8a0719c5c903dcde4703436029e0fdca9c035
languageName: node
linkType: hard
"expo-json-utils@npm:~0.12.0":
version: 0.12.3
resolution: "expo-json-utils@npm:0.12.3"
@ -10426,6 +10447,7 @@ __metadata:
expo-dev-client: ~3.3.7
expo-file-system: ~16.0.5
expo-font: ~11.10.2
expo-image-picker: ~14.7.1
expo-linear-gradient: ~12.7.1
expo-linking: ~6.2.2
expo-localization: ~14.8.3
@ -13998,6 +14020,7 @@ __metadata:
copy-webpack-plugin: ^12.0.2
eslint: ^8.56.0
eslint-config-next: 14.1.0
expo-image-picker: ~14.7.1
expo-linear-gradient: ^12.7.1
expo-modules-core: ^1.11.8
hls.js: ^1.5.2