mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-11-03 19:17:16 -05:00 
			
		
		
		
	Add avatar upload setting
This commit is contained in:
		
							parent
							
								
									0bd497279d
								
							
						
					
					
						commit
						2ecda09ee4
					
				@ -34,6 +34,7 @@
 | 
				
			|||||||
		"expo-dev-client": "~3.3.7",
 | 
							"expo-dev-client": "~3.3.7",
 | 
				
			||||||
		"expo-file-system": "~16.0.5",
 | 
							"expo-file-system": "~16.0.5",
 | 
				
			||||||
		"expo-font": "~11.10.2",
 | 
							"expo-font": "~11.10.2",
 | 
				
			||||||
 | 
							"expo-image-picker": "~14.7.1",
 | 
				
			||||||
		"expo-linear-gradient": "~12.7.1",
 | 
							"expo-linear-gradient": "~12.7.1",
 | 
				
			||||||
		"expo-linking": "~6.2.2",
 | 
							"expo-linking": "~6.2.2",
 | 
				
			||||||
		"expo-localization": "~14.8.3",
 | 
							"expo-localization": "~14.8.3",
 | 
				
			||||||
 | 
				
			|||||||
@ -108,6 +108,7 @@ const nextConfig = {
 | 
				
			|||||||
		"expo-av",
 | 
							"expo-av",
 | 
				
			||||||
		"expo-modules-core",
 | 
							"expo-modules-core",
 | 
				
			||||||
		"expo-linear-gradient",
 | 
							"expo-linear-gradient",
 | 
				
			||||||
 | 
							"expo-image-picker",
 | 
				
			||||||
	],
 | 
						],
 | 
				
			||||||
	experimental: {
 | 
						experimental: {
 | 
				
			||||||
		outputFileTracingRoot: path.join(__dirname, "../../"),
 | 
							outputFileTracingRoot: path.join(__dirname, "../../"),
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,7 @@
 | 
				
			|||||||
		"@tanstack/react-query": "^5.17.19",
 | 
							"@tanstack/react-query": "^5.17.19",
 | 
				
			||||||
		"@tanstack/react-query-devtools": "^5.17.21",
 | 
							"@tanstack/react-query-devtools": "^5.17.21",
 | 
				
			||||||
		"array-shuffle": "^3.0.0",
 | 
							"array-shuffle": "^3.0.0",
 | 
				
			||||||
 | 
							"expo-image-picker": "~14.7.1",
 | 
				
			||||||
		"expo-linear-gradient": "^12.7.1",
 | 
							"expo-linear-gradient": "^12.7.1",
 | 
				
			||||||
		"expo-modules-core": "^1.11.8",
 | 
							"expo-modules-core": "^1.11.8",
 | 
				
			||||||
		"hls.js": "^1.5.2",
 | 
							"hls.js": "^1.5.2",
 | 
				
			||||||
 | 
				
			|||||||
@ -48,6 +48,7 @@ export const queryFn = async <Parser extends z.ZodTypeAny>(
 | 
				
			|||||||
		| ({
 | 
							| ({
 | 
				
			||||||
				path: (string | false | undefined | null)[];
 | 
									path: (string | false | undefined | null)[];
 | 
				
			||||||
				body?: object;
 | 
									body?: object;
 | 
				
			||||||
 | 
									formData?: FormData;
 | 
				
			||||||
				plainText?: boolean;
 | 
									plainText?: boolean;
 | 
				
			||||||
		  } & Partial<QueryFunctionContext>)
 | 
							  } & Partial<QueryFunctionContext>)
 | 
				
			||||||
	),
 | 
						),
 | 
				
			||||||
@ -72,7 +73,12 @@ export const queryFn = async <Parser extends z.ZodTypeAny>(
 | 
				
			|||||||
	try {
 | 
						try {
 | 
				
			||||||
		resp = await fetch(path, {
 | 
							resp = await fetch(path, {
 | 
				
			||||||
			method: context.method,
 | 
								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: {
 | 
								headers: {
 | 
				
			||||||
				...(token ? { Authorization: token } : {}),
 | 
									...(token ? { Authorization: token } : {}),
 | 
				
			||||||
				...("body" in context ? { "Content-Type": "application/json" } : {}),
 | 
									...("body" in context ? { "Content-Type": "application/json" } : {}),
 | 
				
			||||||
 | 
				
			|||||||
@ -23,8 +23,7 @@ import { useYoshiki, px, Stylable } from "yoshiki/native";
 | 
				
			|||||||
import { Icon } from "./icons";
 | 
					import { Icon } from "./icons";
 | 
				
			||||||
import { P } from "./text";
 | 
					import { P } from "./text";
 | 
				
			||||||
import AccountCircle from "@material-symbols/svg-400/rounded/account_circle-fill.svg";
 | 
					import AccountCircle from "@material-symbols/svg-400/rounded/account_circle-fill.svg";
 | 
				
			||||||
import { YoshikiStyle } from "yoshiki";
 | 
					import { ComponentType, forwardRef, RefAttributes } from "react";
 | 
				
			||||||
import { ComponentType, forwardRef, RefAttributes, useEffect, useState } from "react";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const stringToColor = (string: string) => {
 | 
					const stringToColor = (string: string) => {
 | 
				
			||||||
	let hash = 0;
 | 
						let hash = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@
 | 
				
			|||||||
		"@shopify/flash-list": "^1.3.1",
 | 
							"@shopify/flash-list": "^1.3.1",
 | 
				
			||||||
		"@tanstack/react-query": "*",
 | 
							"@tanstack/react-query": "*",
 | 
				
			||||||
		"expo-file-system": "*",
 | 
							"expo-file-system": "*",
 | 
				
			||||||
 | 
							"expo-image-picker": "~14.7.1",
 | 
				
			||||||
		"expo-linear-gradient": "*",
 | 
							"expo-linear-gradient": "*",
 | 
				
			||||||
		"expo-router": "*",
 | 
							"expo-router": "*",
 | 
				
			||||||
		"i18next": "*",
 | 
							"i18next": "*",
 | 
				
			||||||
 | 
				
			|||||||
@ -19,21 +19,33 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Account, KyooErrors, deleteAccount, logout, queryFn, useAccount } from "@kyoo/models";
 | 
					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 { useMutation, useQueryClient } from "@tanstack/react-query";
 | 
				
			||||||
import { ComponentProps, useState } from "react";
 | 
					import { ComponentProps, useState } from "react";
 | 
				
			||||||
import { useTranslation } from "react-i18next";
 | 
					import { useTranslation } from "react-i18next";
 | 
				
			||||||
import { View } from "react-native";
 | 
					import { View } from "react-native";
 | 
				
			||||||
import { rem, useYoshiki } from "yoshiki/native";
 | 
					import { rem, useYoshiki } from "yoshiki/native";
 | 
				
			||||||
 | 
					import * as ImagePicker from "expo-image-picker";
 | 
				
			||||||
import { PasswordInput } from "../login/password-input";
 | 
					import { PasswordInput } from "../login/password-input";
 | 
				
			||||||
import { Preference, SettingsContainer } from "./base";
 | 
					import { Preference, SettingsContainer } from "./base";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Username from "@material-symbols/svg-400/outlined/badge.svg";
 | 
					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 Mail from "@material-symbols/svg-400/outlined/mail.svg";
 | 
				
			||||||
import Password from "@material-symbols/svg-400/outlined/password.svg";
 | 
					import Password from "@material-symbols/svg-400/outlined/password.svg";
 | 
				
			||||||
import Delete from "@material-symbols/svg-400/rounded/delete.svg";
 | 
					import Delete from "@material-symbols/svg-400/rounded/delete.svg";
 | 
				
			||||||
import Logout from "@material-symbols/svg-400/rounded/logout.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 = () => {
 | 
					export const AccountSettings = () => {
 | 
				
			||||||
	const account = useAccount()!;
 | 
						const account = useAccount()!;
 | 
				
			||||||
	const { css, theme } = useYoshiki();
 | 
						const { css, theme } = useYoshiki();
 | 
				
			||||||
@ -118,6 +130,33 @@ export const AccountSettings = () => {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				/>
 | 
									/>
 | 
				
			||||||
			</Preference>
 | 
								</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}>
 | 
								<Preference icon={Mail} label={t("settings.account.email.label")} description={account.email}>
 | 
				
			||||||
				<Button
 | 
									<Button
 | 
				
			||||||
					text={t("misc.edit")}
 | 
										text={t("misc.edit")}
 | 
				
			||||||
 | 
				
			|||||||
@ -36,12 +36,14 @@ import { View } from "react-native";
 | 
				
			|||||||
import { px, rem, useYoshiki } from "yoshiki/native";
 | 
					import { px, rem, useYoshiki } from "yoshiki/native";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Preference = ({
 | 
					export const Preference = ({
 | 
				
			||||||
 | 
						customIcon,
 | 
				
			||||||
	icon,
 | 
						icon,
 | 
				
			||||||
	label,
 | 
						label,
 | 
				
			||||||
	description,
 | 
						description,
 | 
				
			||||||
	children,
 | 
						children,
 | 
				
			||||||
	...props
 | 
						...props
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
 | 
						customIcon?: ReactElement;
 | 
				
			||||||
	icon: Icon;
 | 
						icon: Icon;
 | 
				
			||||||
	label: string;
 | 
						label: string;
 | 
				
			||||||
	description: string;
 | 
						description: string;
 | 
				
			||||||
@ -62,8 +64,16 @@ export const Preference = ({
 | 
				
			|||||||
				props,
 | 
									props,
 | 
				
			||||||
			)}
 | 
								)}
 | 
				
			||||||
		>
 | 
							>
 | 
				
			||||||
			<View {...css({ flexDirection: "row", alignItems: "center", flexShrink: 1 })}>
 | 
								<View
 | 
				
			||||||
				<Icon icon={icon} {...css({ marginX: ts(2) })} />
 | 
									{...css({
 | 
				
			||||||
 | 
										flexDirection: "row",
 | 
				
			||||||
 | 
										alignItems: "center",
 | 
				
			||||||
 | 
										flexShrink: 1,
 | 
				
			||||||
 | 
										marginX: ts(2),
 | 
				
			||||||
 | 
										gap: ts(2),
 | 
				
			||||||
 | 
									})}
 | 
				
			||||||
 | 
								>
 | 
				
			||||||
 | 
									{customIcon ?? <Icon icon={icon} />}
 | 
				
			||||||
				<View {...css({ flexShrink: 1 })}>
 | 
									<View {...css({ flexShrink: 1 })}>
 | 
				
			||||||
					<P {...css({ marginBottom: 0 })}>{label}</P>
 | 
										<P {...css({ marginBottom: 0 })}>{label}</P>
 | 
				
			||||||
					<SubP>{description}</SubP>
 | 
										<SubP>{description}</SubP>
 | 
				
			||||||
 | 
				
			|||||||
@ -2619,6 +2619,7 @@ __metadata:
 | 
				
			|||||||
    "@shopify/flash-list": ^1.3.1
 | 
					    "@shopify/flash-list": ^1.3.1
 | 
				
			||||||
    "@tanstack/react-query": "*"
 | 
					    "@tanstack/react-query": "*"
 | 
				
			||||||
    expo-file-system: "*"
 | 
					    expo-file-system: "*"
 | 
				
			||||||
 | 
					    expo-image-picker: ~14.7.1
 | 
				
			||||||
    expo-linear-gradient: "*"
 | 
					    expo-linear-gradient: "*"
 | 
				
			||||||
    expo-router: "*"
 | 
					    expo-router: "*"
 | 
				
			||||||
    i18next: "*"
 | 
					    i18next: "*"
 | 
				
			||||||
@ -7420,6 +7421,26 @@ __metadata:
 | 
				
			|||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  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":
 | 
					"expo-json-utils@npm:~0.12.0":
 | 
				
			||||||
  version: 0.12.3
 | 
					  version: 0.12.3
 | 
				
			||||||
  resolution: "expo-json-utils@npm:0.12.3"
 | 
					  resolution: "expo-json-utils@npm:0.12.3"
 | 
				
			||||||
@ -10426,6 +10447,7 @@ __metadata:
 | 
				
			|||||||
    expo-dev-client: ~3.3.7
 | 
					    expo-dev-client: ~3.3.7
 | 
				
			||||||
    expo-file-system: ~16.0.5
 | 
					    expo-file-system: ~16.0.5
 | 
				
			||||||
    expo-font: ~11.10.2
 | 
					    expo-font: ~11.10.2
 | 
				
			||||||
 | 
					    expo-image-picker: ~14.7.1
 | 
				
			||||||
    expo-linear-gradient: ~12.7.1
 | 
					    expo-linear-gradient: ~12.7.1
 | 
				
			||||||
    expo-linking: ~6.2.2
 | 
					    expo-linking: ~6.2.2
 | 
				
			||||||
    expo-localization: ~14.8.3
 | 
					    expo-localization: ~14.8.3
 | 
				
			||||||
@ -13998,6 +14020,7 @@ __metadata:
 | 
				
			|||||||
    copy-webpack-plugin: ^12.0.2
 | 
					    copy-webpack-plugin: ^12.0.2
 | 
				
			||||||
    eslint: ^8.56.0
 | 
					    eslint: ^8.56.0
 | 
				
			||||||
    eslint-config-next: 14.1.0
 | 
					    eslint-config-next: 14.1.0
 | 
				
			||||||
 | 
					    expo-image-picker: ~14.7.1
 | 
				
			||||||
    expo-linear-gradient: ^12.7.1
 | 
					    expo-linear-gradient: ^12.7.1
 | 
				
			||||||
    expo-modules-core: ^1.11.8
 | 
					    expo-modules-core: ^1.11.8
 | 
				
			||||||
    hls.js: ^1.5.2
 | 
					    hls.js: ^1.5.2
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user