From ad6fb66e87299b7c617da7f36ea44893ddbed9be Mon Sep 17 00:00:00 2001
From: Micah Lee
Date: Fri, 5 Jun 2026 11:15:33 -0700
Subject: [PATCH 1/2] When adding a new X account, show a modal asking about
archive-only mode
---
src/renderer/src/i18n/locales/en.json | 11 +-
src/renderer/src/modals/XAccountModeModal.vue | 100 ++++++++++++++++++
src/renderer/src/views/PlatformView.vue | 17 ---
src/renderer/src/views/x/XView.vue | 44 ++++++--
4 files changed, 145 insertions(+), 27 deletions(-)
create mode 100644 src/renderer/src/modals/XAccountModeModal.vue
diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json
index d7ee5136..c1325058 100644
--- a/src/renderer/src/i18n/locales/en.json
+++ b/src/renderer/src/i18n/locales/en.json
@@ -123,6 +123,14 @@
"failedToRegisterNewDevice": "Failed to register new device. Please try again later."
}
},
+ "modals": {
+ "xAccountMode": {
+ "title": "Do you still have access to your X account?",
+ "description": "If you can't login to your X account (you deleted it, or you were permanently suspended), but you have an X archive, add this account in Archive Only mode. You won't be able to delete data in this mode, but you can migrate your data to Bluesky.",
+ "loginButton": "I Can Login to X",
+ "archiveOnlyButton": "I Can't Login, Use Archive Only Mode"
+ }
+ },
"errorReport": {
"title": "Submit an error report",
"errorsOccurred": "{count} errors occured",
@@ -346,8 +354,7 @@
"platform": {
"u2fNotice": "If you use a U2F security key (like a Yubikey) for 2FA, press it when you see a white screen.",
"u2fNoticeFacebook": "If you use a U2F security key (like a Yubikey) for 2FA, press it when prompted.",
- "readMore": "Read more",
- "importArchiveOnly": "Import Archive Only (for deleted accounts with an archive)"
+ "readMore": "Read more"
},
"finished": {
"viewBlueskyProfile": "View Bluesky Profile",
diff --git a/src/renderer/src/modals/XAccountModeModal.vue b/src/renderer/src/modals/XAccountModeModal.vue
new file mode 100644
index 00000000..d0d864cd
--- /dev/null
+++ b/src/renderer/src/modals/XAccountModeModal.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
{{ $t("modals.xAccountMode.description") }}
+
+
+
+ {{ $t("modals.xAccountMode.loginButton") }}
+
+
+ {{ $t("modals.xAccountMode.archiveOnlyButton") }}
+
+
+
+
+
+
+
+
+
diff --git a/src/renderer/src/views/PlatformView.vue b/src/renderer/src/views/PlatformView.vue
index c9c4ef7d..bd884614 100644
--- a/src/renderer/src/views/PlatformView.vue
+++ b/src/renderer/src/views/PlatformView.vue
@@ -76,9 +76,6 @@ const emit = defineEmits<{
finishedRunAgainClicked: [];
updateUserPremium: [];
- // Archive only (conditional on feature flag)
- archiveOnlyClicked: [];
-
// Job control events
onPause: [];
onResume: [];
@@ -181,20 +178,6 @@ const currentJobsLength = computed(() => props.currentJobs.length);
>.
-
-
-
-
- {{ t("platform.importArchiveOnly") }}
-
-
-
-
diff --git a/src/renderer/src/views/x/XView.vue b/src/renderer/src/views/x/XView.vue
index 3b09d765..381edbb3 100644
--- a/src/renderer/src/views/x/XView.vue
+++ b/src/renderer/src/views/x/XView.vue
@@ -5,7 +5,7 @@
* Thin wrapper around PlatformView that handles X-specific logic:
* - XViewModel instantiation
* - X-specific state (rateLimitInfo, failure states, mediaPath)
- * - X-specific methods (archiveOnlyClicked, startJobs, etc.)
+ * - X-specific methods (startJobs, etc.)
* - X-specific event handlers
*/
@@ -49,6 +49,7 @@ import { usePlatformView } from "../../composables/usePlatformView";
import { getPlatformConfig } from "../../config/platforms";
import PlatformView from "../PlatformView.vue";
import XProgressComponent from "./components/XProgressComponent.vue";
+import XAccountModeModal from "../../modals/XAccountModeModal.vue";
// Get the global emitter
const vueInstance = getCurrentInstance();
@@ -68,6 +69,7 @@ const failureStateIndexTweets_FailedToRetryAfterRateLimit = ref(false);
const failureStateIndexLikes_FailedToRetryAfterRateLimit = ref(false);
const rateLimitInfo = ref(null);
const mediaPath = ref("");
+const showAccountModeModal = ref(false);
// The X view model
const model = ref(new XViewModel(props.account, emitter));
@@ -141,11 +143,6 @@ watch(
);
// X-specific methods
-const archiveOnlyClicked = async () => {
- model.value.cancelWaitForURL = true;
- await setState(State.WizardArchiveOnly.toString());
-};
-
const onAutomationErrorRetry = async () => {
console.log("Retrying automation after error");
@@ -322,6 +319,25 @@ const debugModeDisable = async () => {
model.value.state = State.WizardPrestart;
};
+// Account mode modal handlers
+const handleAccountModeModalLogin = async () => {
+ showAccountModeModal.value = false;
+ model.value.state = State.Login;
+ await startStateLoop();
+};
+
+const handleAccountModeModalArchiveOnly = async () => {
+ showAccountModeModal.value = false;
+ await window.electron.X.initArchiveOnlyMode(props.account.id);
+ await updateAccount();
+ model.value.state = State.WizardArchiveOnly;
+ await startStateLoop();
+};
+
+const handleAccountModeModalHide = () => {
+ showAccountModeModal.value = false;
+};
+
// Lifecycle
onMounted(async () => {
setupAuthListeners();
@@ -356,7 +372,12 @@ onMounted(async () => {
localStorage.removeItem(`account-${props.account.id}-state`);
}
- await startStateLoop();
+ // Check if we need to show the account mode modal (new account with no username)
+ if (!props.account.xAccount.username && !savedState) {
+ showAccountModeModal.value = true;
+ } else {
+ await startStateLoop();
+ }
}
} else {
console.error("Webview component not found");
@@ -415,7 +436,6 @@ onUnmounted(async () => {
@start-jobs-just-save="startJobsJustSave"
@finished-run-again-clicked="finishedRunAgainClicked"
@update-user-premium="updateUserPremium"
- @archive-only-clicked="archiveOnlyClicked"
@on-pause="model.pause()"
@on-resume="model.resume()"
@on-cancel="emit('onRefreshClicked')"
@@ -456,4 +476,12 @@ onUnmounted(async () => {
+
+
+
From 52cd327bdfd97f41d99fc26e594f5174c91da42d Mon Sep 17 00:00:00 2001
From: Micah Lee
Date: Fri, 5 Jun 2026 11:20:09 -0700
Subject: [PATCH 2/2] While showing the X account mode modal, hide the
background
---
src/renderer/src/views/x/XView.vue | 41 +++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 7 deletions(-)
diff --git a/src/renderer/src/views/x/XView.vue b/src/renderer/src/views/x/XView.vue
index 381edbb3..0f5080fb 100644
--- a/src/renderer/src/views/x/XView.vue
+++ b/src/renderer/src/views/x/XView.vue
@@ -322,12 +322,34 @@ const debugModeDisable = async () => {
// Account mode modal handlers
const handleAccountModeModalLogin = async () => {
showAccountModeModal.value = false;
+ await nextTick(); // Wait for PlatformView to render
+
+ // Initialize the platform view now that it's rendered
+ if (
+ platformViewRef.value?.webviewComponent !== null &&
+ platformViewRef.value?.webviewComponent !== undefined
+ ) {
+ const webview = platformViewRef.value.webviewComponent as WebviewTag;
+ await initializePlatformView(webview);
+ }
+
model.value.state = State.Login;
await startStateLoop();
};
const handleAccountModeModalArchiveOnly = async () => {
showAccountModeModal.value = false;
+ await nextTick(); // Wait for PlatformView to render
+
+ // Initialize the platform view now that it's rendered
+ if (
+ platformViewRef.value?.webviewComponent !== null &&
+ platformViewRef.value?.webviewComponent !== undefined
+ ) {
+ const webview = platformViewRef.value.webviewComponent as WebviewTag;
+ await initializePlatformView(webview);
+ }
+
await window.electron.X.initArchiveOnlyMode(props.account.id);
await updateAccount();
model.value.state = State.WizardArchiveOnly;
@@ -348,7 +370,16 @@ onMounted(async () => {
// Wait for child components to mount
await nextTick();
- if (
+ // Check if we need to show the account mode modal (new account with no username)
+ const shouldShowModal =
+ props.account.xAccount !== null &&
+ !props.account.xAccount.username &&
+ !localStorage.getItem(`account-${props.account.id}-state`);
+
+ if (shouldShowModal) {
+ showAccountModeModal.value = true;
+ // Don't initialize platform view yet - it will be done in the modal handlers
+ } else if (
platformViewRef.value?.webviewComponent !== null &&
platformViewRef.value?.webviewComponent !== undefined
) {
@@ -372,12 +403,7 @@ onMounted(async () => {
localStorage.removeItem(`account-${props.account.id}-state`);
}
- // Check if we need to show the account mode modal (new account with no username)
- if (!props.account.xAccount.username && !savedState) {
- showAccountModeModal.value = true;
- } else {
- await startStateLoop();
- }
+ await startStateLoop();
}
} else {
console.error("Webview component not found");
@@ -406,6 +432,7 @@ onUnmounted(async () => {