diff --git a/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs b/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs index 866e3b18..6e9a6b29 100644 --- a/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs +++ b/back/src/Kyoo.Authentication/Models/DTO/ServerInfo.cs @@ -22,11 +22,21 @@ namespace Kyoo.Authentication.Models; public class ServerInfo { + /// + /// The list of oidc providers configured for this instance of kyoo. + /// public Dictionary Oidc { get; set; } } public class OidcInfo { + /// + /// The name of this oidc service. Human readable. + /// public string DisplayName { get; set; } + + /// + /// A url returing a square logo for this provider. + /// public string? LogoUrl { get; set; } } diff --git a/front/packages/models/src/resources/index.ts b/front/packages/models/src/resources/index.ts index 3d934384..2070550d 100644 --- a/front/packages/models/src/resources/index.ts +++ b/front/packages/models/src/resources/index.ts @@ -32,3 +32,4 @@ export * from "./watch-info"; export * from "./watch-status"; export * from "./watchlist"; export * from "./user"; +export * from "./server-info"; diff --git a/front/packages/models/src/resources/server-info.ts b/front/packages/models/src/resources/server-info.ts new file mode 100644 index 00000000..598f21c0 --- /dev/null +++ b/front/packages/models/src/resources/server-info.ts @@ -0,0 +1,54 @@ +/* + * Kyoo - A portable and vast media library solution. + * Copyright (c) Kyoo. + * + * See AUTHORS.md and LICENSE file in the project root for full license information. + * + * Kyoo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Kyoo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kyoo. If not, see . + */ + +import { z } from "zod"; +import { imageFn } from ".."; + +export const OidcInfoP = z.object({ + /* + * The name of this oidc service. Human readable. + */ + displayName: z.string(), + /* + * A url returing a square logo for this provider. + */ + logoUrl: z.string().nullable(), +}); + +export const ServerInfoP = z.object({ + /* + * The list of oidc providers configured for this instance of kyoo. + */ + oidc: z + .record(z.string(), OidcInfoP) + .transform((x) => + Object.fromEntries( + Object.entries(x).map(([provider, info]) => [ + provider, + { ...info, link: imageFn(`/auth/login/${provider}`) }, + ]), + ), + ), +}); + +/** + * A season of a Show. + */ +export type ServerInfo = z.infer; diff --git a/front/packages/primitives/src/button.tsx b/front/packages/primitives/src/button.tsx index 5e095475..c061564e 100644 --- a/front/packages/primitives/src/button.tsx +++ b/front/packages/primitives/src/button.tsx @@ -23,14 +23,17 @@ import { Theme, useYoshiki } from "yoshiki/native"; import { PressableFeedback } from "./links"; import { P } from "./text"; import { ts } from "./utils"; -import { View } from "react-native"; +import { Falsy, View } from "react-native"; export const Button = forwardRef< View, - { text: string; licon?: ReactElement; icon?: ReactElement } & ComponentProps< - typeof PressableFeedback - > ->(function Button({ text, icon, licon, ...props }, ref) { + { + children?: ReactElement | Falsy; + text?: string; + licon?: ReactElement | Falsy; + icon?: ReactElement | Falsy; + } & ComponentProps +>(function Button({ children, text, icon, licon, ...props }, ref) { const { css } = useYoshiki("button"); return ( @@ -55,17 +58,20 @@ export const Button = forwardRef< props as any, )} > - - {licon} -

{text}

- {icon} -
+ {(licon || text || icon) != null && ( + + {licon} + {text &&

{text}

} + {icon} +
+ )} + {children} ); }); diff --git a/front/packages/primitives/src/divider.tsx b/front/packages/primitives/src/divider.tsx index 8b37cdac..6ee3e246 100644 --- a/front/packages/primitives/src/divider.tsx +++ b/front/packages/primitives/src/divider.tsx @@ -19,7 +19,7 @@ */ import { HR as EHR } from "@expo/html-elements"; -import { px, Stylable, useYoshiki } from "yoshiki/native"; +import { percent, px, Stylable, useYoshiki } from "yoshiki/native"; import { ts } from "./utils"; export const HR = ({ @@ -39,13 +39,13 @@ export const HR = ({ }, orientation === "vertical" && { width: px(1), - height: "auto", + height: percent(100), marginY: ts(1), marginX: ts(2), }, orientation === "horizontal" && { height: px(1), - width: "auto", + width: percent(100), marginX: ts(1), marginY: ts(2), }, diff --git a/front/packages/ui/src/login/login.tsx b/front/packages/ui/src/login/login.tsx index 640538d7..3d276251 100644 --- a/front/packages/ui/src/login/login.tsx +++ b/front/packages/ui/src/login/login.tsx @@ -29,7 +29,7 @@ import { percent, px, useYoshiki } from "yoshiki/native"; import { DefaultLayout } from "../layout"; import { FormPage } from "./form"; import { PasswordInput } from "./password-input"; -import { useQueryClient } from "@tanstack/react-query"; +import { OidcLogin } from "./oidc"; export const cleanApiUrl = (apiUrl: string) => { if (Platform.OS === "web") return undefined; @@ -45,7 +45,6 @@ export const LoginPage: QueryPage = () => { const [error, setError] = useState(undefined); const router = useRouter(); - const queryClient = useQueryClient(); const { t } = useTranslation(); const { css } = useYoshiki(); @@ -56,6 +55,7 @@ export const LoginPage: QueryPage = () => { })} >

{t("login.login")}

+ {Platform.OS !== "web" && ( <>

{t("login.server")}

@@ -102,4 +102,6 @@ export const LoginPage: QueryPage = () => { ); }; +LoginPage.getFetchUrls = () => [OidcLogin.query()]; + LoginPage.getLayout = DefaultLayout; diff --git a/front/packages/ui/src/login/oidc.tsx b/front/packages/ui/src/login/oidc.tsx new file mode 100644 index 00000000..e165f938 --- /dev/null +++ b/front/packages/ui/src/login/oidc.tsx @@ -0,0 +1,83 @@ +/* + * Kyoo - A portable and vast media library solution. + * Copyright (c) Kyoo. + * + * See AUTHORS.md and LICENSE file in the project root for full license information. + * + * Kyoo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Kyoo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kyoo. If not, see . + */ + +import { QueryIdentifier, ServerInfo, ServerInfoP, useFetch } from "@kyoo/models"; +import { Button, HR, P, Skeleton, tooltip, ts } from "@kyoo/primitives"; +import { View, ImageBackground } from "react-native"; +import { percent, rem, useYoshiki } from "yoshiki/native"; +import { useTranslation } from "react-i18next"; +import { ErrorView } from "../errors"; + +export const OidcLogin = () => { + const { css } = useYoshiki(); + const { t } = useTranslation(); + const { data, error } = useFetch(OidcLogin.query()); + + const btn = css({ width: { xs: percent(100), sm: percent(75) }, marginY: ts(1) }); + + return ( + + {error ? ( + + ) : data ? ( + Object.values(data.oidc).map((x) => ( + + )) + )} + +
+

{t("misc.or")}

+
+
+
+ ); +}; + +OidcLogin.query = (): QueryIdentifier => ({ + path: ["info"], + parser: ServerInfoP, +}); diff --git a/front/packages/ui/src/login/register.tsx b/front/packages/ui/src/login/register.tsx index 55394a8e..4fe3f27c 100644 --- a/front/packages/ui/src/login/register.tsx +++ b/front/packages/ui/src/login/register.tsx @@ -30,6 +30,7 @@ import { DefaultLayout } from "../layout"; import { FormPage } from "./form"; import { PasswordInput } from "./password-input"; import { cleanApiUrl } from "./login"; +import { OidcLogin } from "./oidc"; export const RegisterPage: QueryPage = () => { const [apiUrl, setApiUrl] = useState(""); @@ -46,6 +47,7 @@ export const RegisterPage: QueryPage = () => { return (

{t("login.register")}

+ {Platform.OS !== "web" && ( <>

{t("login.server")}

@@ -109,4 +111,6 @@ export const RegisterPage: QueryPage = () => { ); }; +RegisterPage.getFetchUrls = () => [OidcLogin.query()]; + RegisterPage.getLayout = DefaultLayout; diff --git a/front/translations/en.json b/front/translations/en.json index dcbe3b84..4aaa56c4 100644 --- a/front/translations/en.json +++ b/front/translations/en.json @@ -68,7 +68,8 @@ "more": "More", "expand": "Expand", "collapse": "Collapse", - "edit": "Edit" + "edit": "Edit", + "or": "OR" }, "navbar": { "home": "Home", @@ -165,6 +166,7 @@ "login": { "login": "Login", "register": "Register", + "via": "Continue via {{provider}}", "add-account": "Add account", "logout": "Logout", "server": "Server Address",