diff --git a/src/core/launch/index.ts b/src/core/launch/index.ts index 329f09d3..bdc27e49 100644 --- a/src/core/launch/index.ts +++ b/src/core/launch/index.ts @@ -109,12 +109,10 @@ export async function launchMinecraft( if (!validateMicrosoft(account.token)) { const refreshed = await refreshMicrosoft(account); if (!refreshed) { - coreLogger.warn( - "Unable to refresh microsoft account, please login again" - ); + coreLogger.warn("Unable to refresh microsoft account token"); showOverlay({ - title: "Warning", - message: "Unable to refresh microsoft account, please login again", + title: t("warning"), + message: t("unableToRefreshMsToken"), }); } } diff --git a/src/eph/components/layouts.tsx b/src/eph/components/layouts.tsx index c6b112ea..13131ea1 100644 --- a/src/eph/components/layouts.tsx +++ b/src/eph/components/layouts.tsx @@ -1,28 +1,41 @@ +import { DefaultFn } from "common/utils"; import { ReactNode } from "react"; -import { MdError, MdInfo, MdWarning } from "react-icons/md"; +import { MdCheck, MdClose, MdError, MdInfo, MdWarning } from "react-icons/md"; export function Alert(props: { children: ReactNode; - severity: "info" | "warn" | "error"; + className?: string; + severity: "info" | "warn" | "error" | "successful"; + onClose?: DefaultFn; }): JSX.Element { return (
- {props.severity === "warn" ? ( + {props.severity === "successful" ? ( + + ) : props.severity === "warn" ? ( ) : props.severity === "error" ? ( ) : ( )} -

{props.children}

+

{props.children}

+ {props.onClose && ( + + )}
); } diff --git a/src/eph/intl/definition.ts b/src/eph/intl/definition.ts index f5276a90..b7d8c54e 100644 --- a/src/eph/intl/definition.ts +++ b/src/eph/intl/definition.ts @@ -190,4 +190,6 @@ export interface LanguageDefinition { quit: string; confirmQuitting: string; removeFilesAsWell: string; + unableToRefreshMsToken: string; + msLoginAgain: string; } diff --git a/src/eph/intl/en-us.ts b/src/eph/intl/en-us.ts index 703552cf..84b61b94 100644 --- a/src/eph/intl/en-us.ts +++ b/src/eph/intl/en-us.ts @@ -215,6 +215,9 @@ const enUs: Language = { quit: "Quit", confirmQuitting: "Are you sure you want to quit Epherome?", removeFilesAsWell: "Remove files as well", + unableToRefreshMsToken: + "Unable to refresh Microsoft account token, please login again.", + msLoginAgain: "Login Again", }, }; diff --git a/src/eph/intl/ja-jp.ts b/src/eph/intl/ja-jp.ts index cef73b34..ea419de4 100644 --- a/src/eph/intl/ja-jp.ts +++ b/src/eph/intl/ja-jp.ts @@ -217,6 +217,9 @@ const jaJp: Language = { quit: "終了", confirmQuitting: "Epherome を終了してもよろしいですか?", removeFilesAsWell: "ファイルを削除", + unableToRefreshMsToken: + "Microsoft アカウントのトークンを更新できません。もう一度ログインしてください。", + msLoginAgain: "再度ログイン", }, }; diff --git a/src/eph/intl/zh-cn.ts b/src/eph/intl/zh-cn.ts index 79858739..aa51410f 100644 --- a/src/eph/intl/zh-cn.ts +++ b/src/eph/intl/zh-cn.ts @@ -203,6 +203,8 @@ const zhCn: Language = { quit: "退出", confirmQuitting: "你确定要退出 Epherome 吗?", removeFilesAsWell: "删除文件", + unableToRefreshMsToken: "无法刷新微软账户令牌,请重新登录。", + msLoginAgain: "重新登录", }, }; diff --git a/src/eph/views/AccountsPage.tsx b/src/eph/views/AccountsPage.tsx index 2c3ff83a..0147ea32 100644 --- a/src/eph/views/AccountsPage.tsx +++ b/src/eph/views/AccountsPage.tsx @@ -19,6 +19,7 @@ import { CreateAccountImplResult, MinecraftAccount, removeAccount, + updateAccountToken, } from "common/struct/accounts"; import { configStore, setConfig } from "common/struct/config"; import { MdCreate, MdDelete, MdEdit } from "react-icons/md"; @@ -33,6 +34,11 @@ import { downloadSkin } from "core/model/skin"; import { BiExport } from "react-icons/bi"; import { commonLogger } from "common/loggers"; import { Avatar, Body } from "eph/components/skin"; +import { ipcRenderer } from "electron"; +import { + authCode2AuthToken, + authToken2MinecraftTokenDirectly, +} from "core/auth"; export function ChangeAccountFragment(props: { onDone: DefaultFn; @@ -134,6 +140,8 @@ export function ChangeAccountFragment(props: { export function AccountGeneralFragment(props: { current: MinecraftAccount; }): JSX.Element { + const [stat, setStat] = useState(false); + const onClose = () => setStat(false); const handleRemove = (selected: MinecraftAccount) => showOverlay({ title: t("account.removing"), @@ -144,15 +152,72 @@ export function AccountGeneralFragment(props: { positiveText: t("remove"), }); + const handleLoginAgain = () => { + if (props.current.mode === "microsoft") { + setStat(true); + ipcRenderer.invoke("ms-auth").then(async (result) => { + let code = ""; + const split = result.split("&"); + for (const i of split) { + const j = i.split("="); + if (j[0] === "code") { + code = j[1]; + } + } + if (code) { + const authTokenResult = await authCode2AuthToken(code); + const accessToken = authTokenResult.access_token; + const refreshToken = authTokenResult.refresh_token; + if (accessToken && refreshToken) { + const mcTokenResult = await authToken2MinecraftTokenDirectly( + accessToken + ); + if (mcTokenResult.token) { + updateAccountToken( + props.current, + mcTokenResult.token, + authTokenResult.refresh_token + ); + setStat("succ"); + return; + } + } + setStat("err"); + } + }); + } + }; + return (
+ {stat === "succ" && ( + + {t("doneMessage")} + + )} + {stat === "err" && ( + + {t("errorOccurred")} + + )}
- {props.current?.name} + {props.current.name}

{props.current && t(`account.${props.current.mode}`)}

-
+
+ {props.current.mode === "microsoft" && ( + + )} + {stat === true && } +