diff --git a/front/apps/mobile/package.json b/front/apps/mobile/package.json index 0ac8ad7d..f15d2376 100644 --- a/front/apps/mobile/package.json +++ b/front/apps/mobile/package.json @@ -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", diff --git a/front/apps/web/next.config.js b/front/apps/web/next.config.js index 94a3ddec..366daaeb 100755 --- a/front/apps/web/next.config.js +++ b/front/apps/web/next.config.js @@ -108,6 +108,7 @@ const nextConfig = { "expo-av", "expo-modules-core", "expo-linear-gradient", + "expo-image-picker", ], experimental: { outputFileTracingRoot: path.join(__dirname, "../../"), diff --git a/front/apps/web/package.json b/front/apps/web/package.json index 6416cb62..a4c636cd 100644 --- a/front/apps/web/package.json +++ b/front/apps/web/package.json @@ -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", diff --git a/front/packages/models/src/query.tsx b/front/packages/models/src/query.tsx index 31afb51f..a57eef59 100644 --- a/front/packages/models/src/query.tsx +++ b/front/packages/models/src/query.tsx @@ -48,6 +48,7 @@ export const queryFn = async ( | ({ path: (string | false | undefined | null)[]; body?: object; + formData?: FormData; plainText?: boolean; } & Partial) ), @@ -72,7 +73,12 @@ export const queryFn = async ( 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" } : {}), diff --git a/front/packages/primitives/src/avatar.tsx b/front/packages/primitives/src/avatar.tsx index c247a3e7..c0f834c5 100644 --- a/front/packages/primitives/src/avatar.tsx +++ b/front/packages/primitives/src/avatar.tsx @@ -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; diff --git a/front/packages/ui/package.json b/front/packages/ui/package.json index fa09a752..aa9a0bc8 100644 --- a/front/packages/ui/package.json +++ b/front/packages/ui/package.json @@ -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": "*", diff --git a/front/packages/ui/src/settings/account.tsx b/front/packages/ui/src/settings/account.tsx index da33ea8d..d17a31f5 100644 --- a/front/packages/ui/src/settings/account.tsx +++ b/front/packages/ui/src/settings/account.tsx @@ -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 = () => { } /> + } + label={t("settings.account.avatar.label")} + description={t("settings.account.avatar.description")} + > +