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 &&
}
+