diff --git a/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/ConfigManager.java b/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/ConfigManager.java index 7eea190b..1b0de3d7 100644 --- a/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/ConfigManager.java +++ b/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/ConfigManager.java @@ -14,7 +14,9 @@ import java.nio.charset.StandardCharsets; import de.robv.android.xposed.XposedBridge; +import ps.reso.instaeclipse.R; import ps.reso.instaeclipse.utils.feature.FeatureFlags; +import ps.reso.instaeclipse.utils.i18n.I18n; public class ConfigManager { @@ -22,7 +24,7 @@ public class ConfigManager { public static void importConfigFromClipboard(Context context) { android.app.ProgressDialog progress = new android.app.ProgressDialog(context); - progress.setMessage("Importing config..."); + progress.setMessage(I18n.t(context, R.string.ig_config_importing)); progress.setCancelable(false); progress.show(); @@ -54,14 +56,14 @@ public static void importConfigFromClipboard(Context context) { new Handler(Looper.getMainLooper()).post(() -> { progress.dismiss(); - Toast.makeText(context, "✅ Imported into mc_overrides.json", Toast.LENGTH_LONG).show(); + Toast.makeText(context, I18n.t(context, R.string.ig_config_import_success), Toast.LENGTH_LONG).show(); XposedBridge.log("InstaEclipse | ✅ JSON imported from clipboard into mc_overrides.json"); }); } catch (Exception e) { XposedBridge.log("InstaEclipse | ❌ Clipboard import failed: " + e.getMessage()); new Handler(Looper.getMainLooper()).post(() -> { progress.dismiss(); - Toast.makeText(context, "❌ Failed to import config", Toast.LENGTH_LONG).show(); + Toast.makeText(context, I18n.t(context, R.string.ig_config_import_failed), Toast.LENGTH_LONG).show(); }); } finally { // 100% guarantee the flag is OFF after an attempt diff --git a/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonExportActivity.java b/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonExportActivity.java index 510f9eae..5db92659 100644 --- a/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonExportActivity.java +++ b/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonExportActivity.java @@ -13,6 +13,8 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import ps.reso.instaeclipse.R; + public class JsonExportActivity extends Activity { private static final int SAVE_JSON_FILE = 5678; @@ -27,7 +29,7 @@ private void openJsonSaver() { Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("application/json"); - intent.putExtra(Intent.EXTRA_TITLE, "mc_overrides_exported.json"); + intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.ig_config_export_file_name)); startActivityForResult(intent, SAVE_JSON_FILE); } @@ -36,7 +38,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SAVE_JSON_FILE && resultCode == RESULT_OK && data != null) { Uri uri = data.getData(); if (uri == null) { - Toast.makeText(this, "❌ Invalid URI", Toast.LENGTH_SHORT).show(); + Toast.makeText(this, getString(R.string.ig_config_invalid_uri), Toast.LENGTH_SHORT).show(); finish(); return; } @@ -44,28 +46,28 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { new Handler(Looper.getMainLooper()).postDelayed(() -> { ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); if (clipboard == null || !clipboard.hasPrimaryClip()) { - Toast.makeText(this, "❌ Clipboard is empty.", Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_clipboard_empty), Toast.LENGTH_LONG).show(); finish(); return; } ClipData clipData = clipboard.getPrimaryClip(); if (clipData == null || clipData.getItemCount() == 0) { - Toast.makeText(this, "❌ Clipboard has no data.", Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_clipboard_no_data), Toast.LENGTH_LONG).show(); finish(); return; } CharSequence text = clipData.getItemAt(0).getText(); if (text == null || text.length() == 0) { - Toast.makeText(this, "❌ Clipboard text is empty.", Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_clipboard_text_empty), Toast.LENGTH_LONG).show(); finish(); return; } String json = text.toString().trim(); if (!json.startsWith("{") || !json.endsWith("}")) { - Toast.makeText(this, "❌ Clipboard does not contain valid JSON.", Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_clipboard_invalid_json), Toast.LENGTH_LONG).show(); finish(); return; } @@ -74,10 +76,10 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { assert outputStream != null; outputStream.write(json.getBytes(StandardCharsets.UTF_8)); outputStream.flush(); - Toast.makeText(this, "✅ JSON exported successfully.", Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_export_success), Toast.LENGTH_LONG).show(); } catch (Exception e) { - Toast.makeText(this, "❌ Failed to save file: " + e.getMessage(), Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_failed_save_file, e.getMessage()), Toast.LENGTH_LONG).show(); } finish(); diff --git a/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonImportActivity.java b/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonImportActivity.java index 915fc74a..56f9d882 100644 --- a/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonImportActivity.java +++ b/app/src/main/java/ps/reso/instaeclipse/mods/devops/config/JsonImportActivity.java @@ -13,6 +13,7 @@ import java.nio.charset.StandardCharsets; import java.util.Scanner; +import ps.reso.instaeclipse.R; import ps.reso.instaeclipse.utils.feature.FeatureFlags; public class JsonImportActivity extends Activity { @@ -30,7 +31,7 @@ private void openJsonPicker() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("application/json"); intent.addCategory(Intent.CATEGORY_OPENABLE); - startActivityForResult(Intent.createChooser(intent, "Select JSON Config"), PICK_JSON_FILE); + startActivityForResult(Intent.createChooser(intent, getString(R.string.ig_config_select_json)), PICK_JSON_FILE); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -50,16 +51,16 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { //Toast.makeText(this, "Config copied, returning to import…", Toast.LENGTH_SHORT).show(); } else { FeatureFlags.isImportingConfig = false; - Toast.makeText(this, "❌ Not a valid JSON file", Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_not_valid_json), Toast.LENGTH_LONG).show(); } } catch (Exception e) { FeatureFlags.isImportingConfig = false; // <- make sure we reset on error - Toast.makeText(this, "❌ Failed to read file: " + e.getMessage(), Toast.LENGTH_LONG).show(); + Toast.makeText(this, getString(R.string.ig_config_failed_read_file, e.getMessage()), Toast.LENGTH_LONG).show(); } } else { // User pressed back / cancelled FeatureFlags.isImportingConfig = false; // <- ensure OFF on cancel - Toast.makeText(this, "Cancelled or no file selected", Toast.LENGTH_SHORT).show(); + Toast.makeText(this, getString(R.string.ig_config_cancelled_no_file), Toast.LENGTH_SHORT).show(); } } finish(); // Done, return to Instagram diff --git a/app/src/main/java/ps/reso/instaeclipse/mods/ui/UIHookManager.java b/app/src/main/java/ps/reso/instaeclipse/mods/ui/UIHookManager.java index ece7eab7..2ff9cee1 100644 --- a/app/src/main/java/ps/reso/instaeclipse/mods/ui/UIHookManager.java +++ b/app/src/main/java/ps/reso/instaeclipse/mods/ui/UIHookManager.java @@ -16,6 +16,7 @@ import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; +import ps.reso.instaeclipse.R; import ps.reso.instaeclipse.Xposed.Module; import ps.reso.instaeclipse.mods.devops.config.ConfigManager; import ps.reso.instaeclipse.mods.ui.utils.BottomSheetHookUtil; @@ -24,6 +25,7 @@ import ps.reso.instaeclipse.utils.feature.FeatureFlags; import ps.reso.instaeclipse.utils.feature.FeatureStatusTracker; import ps.reso.instaeclipse.utils.ghost.GhostModeUtils; +import ps.reso.instaeclipse.utils.i18n.I18n; import ps.reso.instaeclipse.utils.toast.CustomToast; public class UIHookManager { @@ -110,7 +112,7 @@ public void onGlobalLayout() { messageList.scrollBy(0, 100); // scroll back down FeatureFlags.isGhostSeen = true; - Toast.makeText(activity, "✅ Message was marked as read", Toast.LENGTH_SHORT).show(); + Toast.makeText(activity, I18n.t(activity, R.string.ig_toast_message_marked_read), Toast.LENGTH_SHORT).show(); }, 300); @@ -158,7 +160,7 @@ protected void afterHookedMethod(MethodHookParam param) { CustomToast.toastShown = true; new Handler(Looper.getMainLooper()).postDelayed(() -> { - StringBuilder sb = new StringBuilder("InstaEclipse Loaded 🎯\n"); + StringBuilder sb = new StringBuilder(I18n.t(activity, R.string.ig_toast_instaeclipse_loaded) + "\n"); for (Map.Entry entry : FeatureStatusTracker.getStatus().entrySet()) { sb.append(entry.getValue() ? "✅ " : "❌ ").append(entry.getKey()).append("\n"); } diff --git a/app/src/main/java/ps/reso/instaeclipse/utils/dialog/DialogUtils.java b/app/src/main/java/ps/reso/instaeclipse/utils/dialog/DialogUtils.java index d515965f..fa6c7a8c 100644 --- a/app/src/main/java/ps/reso/instaeclipse/utils/dialog/DialogUtils.java +++ b/app/src/main/java/ps/reso/instaeclipse/utils/dialog/DialogUtils.java @@ -26,12 +26,14 @@ import java.util.Objects; import de.robv.android.xposed.XposedBridge; +import ps.reso.instaeclipse.R; import ps.reso.instaeclipse.mods.devops.config.ConfigManager; import ps.reso.instaeclipse.mods.ghost.ui.GhostEmojiManager; import ps.reso.instaeclipse.mods.ui.UIHookManager; import ps.reso.instaeclipse.utils.core.SettingsManager; import ps.reso.instaeclipse.utils.feature.FeatureFlags; import ps.reso.instaeclipse.utils.ghost.GhostModeUtils; +import ps.reso.instaeclipse.utils.i18n.I18n; public class DialogUtils { @@ -59,7 +61,11 @@ public static void showEclipseOptionsDialog(Context context) { public static void showSimpleDialog(Context context, String title, String message) { try { - new AlertDialog.Builder(context).setTitle(title).setMessage(message).setPositiveButton("OK", null).show(); + new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton(android.R.string.ok, null) + .show(); } catch (Exception e) { // handle UI crash fallback } @@ -78,7 +84,7 @@ private static LinearLayout buildMainMenuLayout(Context context) { // Title TextView title = new TextView(context); - title.setText("InstaEclipse 🌘"); + title.setText(I18n.t(context, R.string.ig_dialog_title)); title.setTextColor(Color.WHITE); title.setTextSize(22); title.setGravity(Gravity.CENTER); @@ -90,25 +96,25 @@ private static LinearLayout buildMainMenuLayout(Context context) { // Now building menu manually // 0 - Developer Options => OPEN PAGE - mainLayout.addView(createClickableSection(context, "🎛 Developer Options", () -> showDevOptions(context))); + mainLayout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_menu_dev_options), () -> showDevOptions(context))); // 1 - Ghost Mode Settings => OPEN PAGE - mainLayout.addView(createClickableSection(context, "👻 Ghost Mode Settings", () -> showGhostOptions(context))); + mainLayout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_menu_ghost_settings), () -> showGhostOptions(context))); // 2 - Ad/Analytics Block => OPEN PAGE - mainLayout.addView(createClickableSection(context, "🛡 Ad/Analytics Block", () -> showAdOptions(context))); + mainLayout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_menu_ad_analytics_block), () -> showAdOptions(context))); // 3 - Distraction-Free Instagram => OPEN PAGE - mainLayout.addView(createClickableSection(context, "🧘 Distraction-Free Instagram", () -> showDistractionOptions(context))); + mainLayout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_menu_distraction_free), () -> showDistractionOptions(context))); // 4 - Misc Features => OPEN PAGE - mainLayout.addView(createClickableSection(context, "⚙ Misc Features", () -> showMiscOptions(context))); + mainLayout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_menu_misc_features), () -> showMiscOptions(context))); // 5 - About => OPEN PAGE - mainLayout.addView(createClickableSection(context, "ℹ️ About", () -> showAboutDialog(context))); + mainLayout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_menu_about), () -> showAboutDialog(context))); // 6 - Restart Instagram => OPEN PAGE - mainLayout.addView(createClickableSection(context, "🔁 Restart App", () -> showRestartSection(context))); + mainLayout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_menu_restart_app), () -> showRestartSection(context))); mainLayout.addView(createDivider(context)); @@ -123,7 +129,7 @@ private static LinearLayout buildMainMenuLayout(Context context) { // Embedded Close Button TextView closeButton = new TextView(context); - closeButton.setText("❌ Close"); + closeButton.setText(I18n.t(context, R.string.ig_dialog_close)); closeButton.setTextColor(Color.WHITE); closeButton.setTextSize(16); closeButton.setPadding(20, 30, 20, 30); @@ -156,10 +162,17 @@ private static void showGhostQuickToggleOptions(Context context) { LinearLayout layout = createSwitchLayout(context); // Create switches for customizing what gets toggled - Switch[] toggleSwitches = new Switch[]{createSwitch(context, "Include Hide Seen", FeatureFlags.quickToggleSeen), createSwitch(context, "Include Hide Typing", FeatureFlags.quickToggleTyping), createSwitch(context, "Include Disable Screenshot Detection", FeatureFlags.quickToggleScreenshot), createSwitch(context, "Include Hide View Once", FeatureFlags.quickToggleViewOnce), createSwitch(context, "Include Hide Story Seen", FeatureFlags.quickToggleStory), createSwitch(context, "Include Hide Live Seen", FeatureFlags.quickToggleLive)}; + Switch[] toggleSwitches = new Switch[]{ + createSwitch(context, I18n.t(context, R.string.ig_dialog_quick_include_hide_seen), FeatureFlags.quickToggleSeen), + createSwitch(context, I18n.t(context, R.string.ig_dialog_quick_include_hide_typing), FeatureFlags.quickToggleTyping), + createSwitch(context, I18n.t(context, R.string.ig_dialog_quick_include_disable_screenshot), FeatureFlags.quickToggleScreenshot), + createSwitch(context, I18n.t(context, R.string.ig_dialog_quick_include_hide_view_once), FeatureFlags.quickToggleViewOnce), + createSwitch(context, I18n.t(context, R.string.ig_dialog_quick_include_hide_story_seen), FeatureFlags.quickToggleStory), + createSwitch(context, I18n.t(context, R.string.ig_dialog_quick_include_hide_live_seen), FeatureFlags.quickToggleLive) + }; // Create Enable/Disable All switch - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, "Enable/Disable All", areAllEnabled(toggleSwitches)); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_enable_disable_all), areAllEnabled(toggleSwitches)); // Master listener enableAllSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { @@ -224,7 +237,7 @@ private static void showGhostQuickToggleOptions(Context context) { } // Show dialog - showSectionDialog(context, "Customize Quick Toggle 🛠️", layout, () -> { + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_quick_toggle), layout, () -> { }); } @@ -257,12 +270,12 @@ private static void restartApp(Context context) { // Forcibly kill the current process to ensure a clean restart Runtime.getRuntime().exit(0); } else { - Toast.makeText(context, "Could not find the app to restart.", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, I18n.t(context, R.string.ig_dialog_restart_not_found), Toast.LENGTH_SHORT).show(); } } catch (Exception e) { String packageName = context.getPackageName(); XposedBridge.log("InstaEclipse: Restart failed for " + packageName + " - " + e.getMessage()); - Toast.makeText(context, "Restart failed: " + e.getMessage(), Toast.LENGTH_LONG).show(); + Toast.makeText(context, I18n.t(context, R.string.ig_dialog_restart_failed, e.getMessage()), Toast.LENGTH_LONG).show(); } } @@ -311,7 +324,7 @@ private static void showDevOptions(Context context) { LinearLayout layout = createSwitchLayout(context); // Developer Mode Switch - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch devModeSwitch = createSwitch(context, "Enable Developer Mode", FeatureFlags.isDevEnabled); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch devModeSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_dev_enable), FeatureFlags.isDevEnabled); devModeSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { FeatureFlags.isDevEnabled = isChecked; SettingsManager.saveAllFlags(); @@ -322,7 +335,7 @@ private static void showDevOptions(Context context) { // 📥 Import Dev Config Button Button importButton = new Button(context); - importButton.setText("📥 Import Dev Config"); + importButton.setText(I18n.t(context, R.string.ig_dialog_dev_import)); importButton.setOnClickListener(v -> { Activity instagramActivity = UIHookManager.getCurrentActivity(); if (instagramActivity != null && !instagramActivity.isFinishing()) { @@ -336,11 +349,11 @@ private static void showDevOptions(Context context) { instagramActivity.startActivity(importIntent); } catch (Exception e) { XposedBridge.log("InstaEclipse | ❌ Failed to start JsonImportActivity: " + e.getMessage()); - showSimpleDialog(context, "Error", "Unable to open InstaEclipse UI."); + showSimpleDialog(context, I18n.t(context, R.string.ig_dialog_error), I18n.t(context, R.string.ig_dialog_unable_open_ui)); } } else { - showSimpleDialog(context, "Error", "Instagram is not open or ready."); + showSimpleDialog(context, I18n.t(context, R.string.ig_dialog_error), I18n.t(context, R.string.ig_dialog_instagram_not_ready)); } }); @@ -349,7 +362,7 @@ private static void showDevOptions(Context context) { // 📤 Export Dev Config Button Button exportButton = new Button(context); - exportButton.setText("📤 Export Dev Config"); + exportButton.setText(I18n.t(context, R.string.ig_dialog_dev_export)); exportButton.setOnClickListener(v -> { FeatureFlags.isExportingConfig = true; Activity instagramActivity = UIHookManager.getCurrentActivity(); @@ -364,28 +377,35 @@ private static void showDevOptions(Context context) { try { instagramActivity.startActivity(exportIntent); } catch (Exception e) { - showSimpleDialog(context, "Error", "Unable to open InstaEclipse UI."); + showSimpleDialog(context, I18n.t(context, R.string.ig_dialog_error), I18n.t(context, R.string.ig_dialog_unable_open_ui)); } } else { - showSimpleDialog(context, "Error", "Instagram is not open or ready."); + showSimpleDialog(context, I18n.t(context, R.string.ig_dialog_error), I18n.t(context, R.string.ig_dialog_instagram_not_ready)); } }); layout.addView(exportButton); // Save current dev mode flag when dialog is closed - showSectionDialog(context, "Developer Options 🎛", layout, SettingsManager::saveAllFlags); + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_dev_options), layout, SettingsManager::saveAllFlags); } private static void showGhostOptions(Context context) { LinearLayout layout = createSwitchLayout(context); - Switch[] switches = new Switch[]{createSwitch(context, "Hide Seen", FeatureFlags.isGhostSeen), createSwitch(context, "Hide Typing", FeatureFlags.isGhostTyping), createSwitch(context, "Disable Screenshot Detection", FeatureFlags.isGhostScreenshot), createSwitch(context, "Hide View Once", FeatureFlags.isGhostViewOnce), createSwitch(context, "Hide Story Seen", FeatureFlags.isGhostStory), createSwitch(context, "Hide Live Seen", FeatureFlags.isGhostLive)}; + Switch[] switches = new Switch[]{ + createSwitch(context, I18n.t(context, R.string.ig_dialog_ghost_hide_seen), FeatureFlags.isGhostSeen), + createSwitch(context, I18n.t(context, R.string.ig_dialog_ghost_hide_typing), FeatureFlags.isGhostTyping), + createSwitch(context, I18n.t(context, R.string.ig_dialog_ghost_disable_screenshot), FeatureFlags.isGhostScreenshot), + createSwitch(context, I18n.t(context, R.string.ig_dialog_ghost_hide_view_once), FeatureFlags.isGhostViewOnce), + createSwitch(context, I18n.t(context, R.string.ig_dialog_ghost_hide_story_seen), FeatureFlags.isGhostStory), + createSwitch(context, I18n.t(context, R.string.ig_dialog_ghost_hide_live_seen), FeatureFlags.isGhostLive) + }; - layout.addView(createClickableSection(context, "🛠 Customize Quick Toggle", () -> showGhostQuickToggleOptions(context))); + layout.addView(createClickableSection(context, I18n.t(context, R.string.ig_dialog_customize_quick_toggle), () -> showGhostQuickToggleOptions(context))); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, "Enable/Disable All", areAllEnabled(switches)); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_enable_disable_all), areAllEnabled(switches)); enableAllSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { for (Switch s : switches) { @@ -445,7 +465,7 @@ private static void showGhostOptions(Context context) { layout.addView(s); } - showSectionDialog(context, "Ghost Mode 👻", layout, () -> { + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_ghost_mode), layout, () -> { // No need to set FeatureFlags here anymore because handled instantly }); } @@ -455,16 +475,16 @@ private static void showAdOptions(Context context) { LinearLayout layout = createSwitchLayout(context); // Create switches - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch adBlock = createSwitch(context, "Block Ads", FeatureFlags.isAdBlockEnabled); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch adBlock = createSwitch(context, I18n.t(context, R.string.ig_dialog_ad_block_ads), FeatureFlags.isAdBlockEnabled); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch analytics = createSwitch(context, "Block Analytics", FeatureFlags.isAnalyticsBlocked); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch analytics = createSwitch(context, I18n.t(context, R.string.ig_dialog_ad_block_analytics), FeatureFlags.isAnalyticsBlocked); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch trackingLinks = createSwitch(context, "Disable Tracking Links", FeatureFlags.disableTrackingLinks); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch trackingLinks = createSwitch(context, I18n.t(context, R.string.ig_dialog_ad_disable_tracking_links), FeatureFlags.disableTrackingLinks); Switch[] switches = new Switch[]{adBlock, analytics, trackingLinks}; // Create Enable/Disable All switch - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, "Enable/Disable All", areAllEnabled(switches)); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_enable_disable_all), areAllEnabled(switches)); // Master listener enableAllSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { @@ -506,7 +526,7 @@ private static void showAdOptions(Context context) { } // Show the dialog - showSectionDialog(context, "Ad/Analytics Block 🛡️", layout, () -> { + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_ad_analytics), layout, () -> { }); } @@ -515,19 +535,19 @@ private static void showDistractionOptions(Context context) { LinearLayout layout = createSwitchLayout(context); // Child switches - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch extremeModeSwitch = createSwitch(context, "Extreme Mode 🔒 (Irreversible until reinstall)", FeatureFlags.isExtremeMode); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableStoriesSwitch = createSwitch(context, "Disable Stories", FeatureFlags.disableStories); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableFeedSwitch = createSwitch(context, "Disable Feed", FeatureFlags.disableFeed); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableReelsSwitch = createSwitch(context, "Disable Reels", FeatureFlags.disableReels); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch onlyInDMSwitch = createSwitch(context, "Disable Reels Except in DMs", FeatureFlags.disableReelsExceptDM); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableExploreSwitch = createSwitch(context, "Disable Explore", FeatureFlags.disableExplore); - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableCommentsSwitch = createSwitch(context, "Disable Comments", FeatureFlags.disableComments); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch extremeModeSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_extreme_mode), FeatureFlags.isExtremeMode); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableStoriesSwitch = createSwitch(context, I18n.t(context, R.string.disable_stories), FeatureFlags.disableStories); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableFeedSwitch = createSwitch(context, I18n.t(context, R.string.disable_feed), FeatureFlags.disableFeed); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableReelsSwitch = createSwitch(context, I18n.t(context, R.string.disable_reels), FeatureFlags.disableReels); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch onlyInDMSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_disable_reels_except_dm), FeatureFlags.disableReelsExceptDM); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableExploreSwitch = createSwitch(context, I18n.t(context, R.string.disable_explore), FeatureFlags.disableExplore); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch disableCommentsSwitch = createSwitch(context, I18n.t(context, R.string.disable_comments), FeatureFlags.disableComments); Switch[] switches = new Switch[]{disableStoriesSwitch, disableFeedSwitch, disableReelsSwitch, onlyInDMSwitch, disableExploreSwitch, disableCommentsSwitch}; // Enable/Disable All - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, "Enable/Disable All", areAllEnabled(switches)); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_enable_disable_all), areAllEnabled(switches)); if (FeatureFlags.isExtremeMode) { disableAllSwitches(switches, enableAllSwitch, onlyInDMSwitch); @@ -538,9 +558,9 @@ private static void showDistractionOptions(Context context) { extremeModeSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Activate Extreme Mode?"); - builder.setMessage("Once activated, you cannot disable Distraction-Free Mode until you reinstall the app. Continue?"); - builder.setPositiveButton("Yes", (dialog, which) -> { + builder.setTitle(I18n.t(context, R.string.ig_dialog_extreme_confirm_title)); + builder.setMessage(I18n.t(context, R.string.ig_dialog_extreme_confirm_message)); + builder.setPositiveButton(android.R.string.yes, (dialog, which) -> { FeatureFlags.isExtremeMode = true; FeatureFlags.isDistractionFree = true; @@ -557,7 +577,7 @@ private static void showDistractionOptions(Context context) { disableAllSwitches(switches, enableAllSwitch, onlyInDMSwitch); extremeModeSwitch.setEnabled(false); }); - builder.setNegativeButton("Cancel", (dialog, which) -> extremeModeSwitch.setChecked(false)); + builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> extremeModeSwitch.setChecked(false)); builder.show(); } }); @@ -617,7 +637,7 @@ private static void showDistractionOptions(Context context) { layout.addView(s); } - showSectionDialog(context, "Distraction-Free Instagram 🧘", layout, () -> { + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_distraction_free), layout, () -> { FeatureFlags.disableStories = disableStoriesSwitch.isChecked(); FeatureFlags.disableFeed = disableFeedSwitch.isChecked(); FeatureFlags.disableReels = disableReelsSwitch.isChecked(); @@ -663,15 +683,15 @@ private static void showMiscOptions(Context context) { // Create all child switches Switch[] switches = new Switch[]{ - createSwitch(context, "Disable Story Auto-Swipe", FeatureFlags.disableStoryFlipping), - createSwitch(context, "Disable Video Autoplay", FeatureFlags.disableVideoAutoPlay), - createSwitch(context, "Disable Repost", FeatureFlags.disableRepost), - createSwitch(context, "Show Follower Toast", FeatureFlags.showFollowerToast), - createSwitch(context, "Show Feature Toasts", FeatureFlags.showFeatureToasts) + createSwitch(context, I18n.t(context, R.string.ig_dialog_misc_disable_story_autoswipe), FeatureFlags.disableStoryFlipping), + createSwitch(context, I18n.t(context, R.string.ig_dialog_misc_disable_video_autoplay), FeatureFlags.disableVideoAutoPlay), + createSwitch(context, I18n.t(context, R.string.ig_dialog_disable_repost), FeatureFlags.disableRepost), + createSwitch(context, I18n.t(context, R.string.ig_dialog_misc_show_follower_toast), FeatureFlags.showFollowerToast), + createSwitch(context, I18n.t(context, R.string.ig_dialog_misc_show_feature_toasts), FeatureFlags.showFeatureToasts) }; // Create Enable/Disable All switch - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, "Enable/Disable All", areAllEnabled(switches)); + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch enableAllSwitch = createSwitch(context, I18n.t(context, R.string.ig_dialog_enable_disable_all), areAllEnabled(switches)); enableAllSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { for (Switch s : switches) { @@ -723,7 +743,7 @@ private static void showMiscOptions(Context context) { } // Show dialog - showSectionDialog(context, "Miscellaneous ⚙️", layout, () -> { + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_misc), layout, () -> { }); } @@ -736,21 +756,21 @@ private static void showAboutDialog(Context context) { layout.setGravity(Gravity.CENTER_HORIZONTAL); TextView title = new TextView(context); - title.setText("InstaEclipse 🌘"); + title.setText(I18n.t(context, R.string.ig_dialog_title)); title.setTextColor(Color.WHITE); title.setTextSize(20f); title.setGravity(Gravity.CENTER); title.setPadding(0, 0, 0, 20); TextView creator = new TextView(context); - creator.setText("Created by @reso7200"); + creator.setText(I18n.t(context, R.string.ig_dialog_created_by)); creator.setTextColor(Color.LTGRAY); creator.setTextSize(16f); creator.setGravity(Gravity.CENTER); creator.setPadding(0, 0, 0, 30); Button githubButton = new Button(context); - githubButton.setText("🌐 GitHub Repo"); + githubButton.setText(I18n.t(context, R.string.ig_dialog_github_repo)); githubButton.setTextColor(Color.WHITE); githubButton.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#3F51B5"))); githubButton.setPadding(40, 20, 40, 20); @@ -770,7 +790,7 @@ private static void showAboutDialog(Context context) { layout.addView(creator); layout.addView(githubButton); - showSectionDialog(context, "About", layout, () -> { + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_about), layout, () -> { }); } @@ -782,14 +802,14 @@ private static void showRestartSection(Context context) { layout.setGravity(Gravity.CENTER_HORIZONTAL); TextView message = new TextView(context); - message.setText("⚠️ Clear app cache and restart?"); + message.setText(I18n.t(context, R.string.ig_dialog_restart_message)); message.setTextColor(Color.WHITE); message.setTextSize(18f); message.setGravity(Gravity.CENTER); message.setPadding(0, 0, 0, 30); Button restartButton = new Button(context); - restartButton.setText("🔁 Restart Now"); + restartButton.setText(I18n.t(context, R.string.ig_dialog_restart_now)); restartButton.setTextColor(Color.WHITE); restartButton.setPadding(40, 20, 40, 20); @@ -798,7 +818,7 @@ private static void showRestartSection(Context context) { layout.addView(message); layout.addView(restartButton); - showSectionDialog(context, "Restart App", layout, () -> { + showSectionDialog(context, I18n.t(context, R.string.ig_dialog_section_restart), layout, () -> { }); } @@ -834,7 +854,7 @@ private static void showSectionDialog(Context context, String title, LinearLayou // Footer button TextView backBtn = new TextView(context); - backBtn.setText("← Back"); + backBtn.setText(I18n.t(context, R.string.ig_dialog_back)); backBtn.setTextColor(Color.WHITE); backBtn.setTextSize(16); backBtn.setGravity(Gravity.CENTER); diff --git a/app/src/main/java/ps/reso/instaeclipse/utils/ghost/GhostModeUtils.java b/app/src/main/java/ps/reso/instaeclipse/utils/ghost/GhostModeUtils.java index aa4fc6d2..254f1b35 100644 --- a/app/src/main/java/ps/reso/instaeclipse/utils/ghost/GhostModeUtils.java +++ b/app/src/main/java/ps/reso/instaeclipse/utils/ghost/GhostModeUtils.java @@ -4,10 +4,12 @@ import android.content.Context; import android.widget.Toast; +import ps.reso.instaeclipse.R; import ps.reso.instaeclipse.mods.ghost.ui.GhostEmojiManager; import ps.reso.instaeclipse.mods.ui.UIHookManager; import ps.reso.instaeclipse.utils.core.SettingsManager; import ps.reso.instaeclipse.utils.feature.FeatureFlags; +import ps.reso.instaeclipse.utils.i18n.I18n; public class GhostModeUtils { public static boolean isGhostModeActive() { @@ -54,7 +56,7 @@ public static void toggleSelectedGhostOptions(Context context) { if (activity != null) { GhostEmojiManager.addGhostEmojiNextToInbox(activity, false); } - Toast.makeText(context, "❗ No Ghost Mode options selected!", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, I18n.t(context, R.string.ig_toast_no_ghost_option_selected), Toast.LENGTH_SHORT).show(); return; // Nothing to do } @@ -78,9 +80,9 @@ public static void toggleSelectedGhostOptions(Context context) { // Toast if (newState) { - Toast.makeText(context, "👻 Ghost Mode Enabled", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, I18n.t(context, R.string.ig_toast_ghost_enabled), Toast.LENGTH_SHORT).show(); } else { - Toast.makeText(context, "❌ Ghost Mode Disabled", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, I18n.t(context, R.string.ig_toast_ghost_disabled), Toast.LENGTH_SHORT).show(); } } } diff --git a/app/src/main/java/ps/reso/instaeclipse/utils/i18n/I18n.java b/app/src/main/java/ps/reso/instaeclipse/utils/i18n/I18n.java new file mode 100644 index 00000000..6bd371f8 --- /dev/null +++ b/app/src/main/java/ps/reso/instaeclipse/utils/i18n/I18n.java @@ -0,0 +1,69 @@ +package ps.reso.instaeclipse.utils.i18n; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; + +import androidx.annotation.StringRes; + +import java.util.Locale; + +import ps.reso.instaeclipse.utils.core.CommonUtils; + +public final class I18n { + + private I18n() { + } + + private static Context getModuleContext(Context hostContext) { + try { + return hostContext.createPackageContext(CommonUtils.MY_PACKAGE_NAME, Context.CONTEXT_IGNORE_SECURITY); + } catch (Exception ignored) { + return hostContext; + } + } + + private static Locale resolvePreferredLocale() { + Locale systemLocale = Resources.getSystem().getConfiguration().getLocales().get(0); + if (systemLocale == null) { + return Locale.ENGLISH; + } + + if ("zh".equalsIgnoreCase(systemLocale.getLanguage())) { + String country = systemLocale.getCountry(); + if ("TW".equalsIgnoreCase(country) || "HK".equalsIgnoreCase(country) || "MO".equalsIgnoreCase(country)) { + return Locale.forLanguageTag("zh-TW"); + } + return Locale.SIMPLIFIED_CHINESE; + } + + return Locale.ENGLISH; + } + + private static Context getLocalizedModuleContext(Context hostContext) { + Context moduleContext = getModuleContext(hostContext); + Resources moduleResources = moduleContext.getResources(); + Configuration localizedConfig = new Configuration(moduleResources.getConfiguration()); + localizedConfig.setLocale(resolvePreferredLocale()); + return moduleContext.createConfigurationContext(localizedConfig); + } + + public static String t(Context hostContext, @StringRes int resId, Object... args) { + try { + Context localizedContext = getLocalizedModuleContext(hostContext); + if (args == null || args.length == 0) { + return localizedContext.getString(resId); + } + return localizedContext.getString(resId, args); + } catch (Exception ignored) { + try { + if (args == null || args.length == 0) { + return hostContext.getString(resId); + } + return hostContext.getString(resId, args); + } catch (Exception ignoredAgain) { + return ""; + } + } + } +} diff --git a/app/src/main/java/ps/reso/instaeclipse/utils/version/VersionCheckUtility.java b/app/src/main/java/ps/reso/instaeclipse/utils/version/VersionCheckUtility.java index 65790179..4b632113 100644 --- a/app/src/main/java/ps/reso/instaeclipse/utils/version/VersionCheckUtility.java +++ b/app/src/main/java/ps/reso/instaeclipse/utils/version/VersionCheckUtility.java @@ -13,6 +13,8 @@ import java.net.HttpURLConnection; import java.net.URL; +import ps.reso.instaeclipse.R; + public class VersionCheckUtility { private static final String CURRENT_VERSION = "0.4.5"; // Current version @@ -62,14 +64,14 @@ private static void handleVersionCheckResult(Context context, VersionCheck versi private static void showUpdateDialog(Context context, String updateUrl, String newVersion) { new MaterialAlertDialogBuilder(context) - .setTitle("Update Available") - .setMessage("A new version (" + newVersion + ") is available. Would you like to update now?") - .setPositiveButton("Update", (dialogInterface, which) -> { + .setTitle(context.getString(R.string.ig_update_available)) + .setMessage(context.getString(R.string.ig_update_message, newVersion)) + .setPositiveButton(R.string.ig_update_action_update, (dialogInterface, which) -> { // Open the update URL in the browser Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(updateUrl)); context.startActivity(browserIntent); }) - .setNegativeButton("Later", (dialogInterface, which) -> { + .setNegativeButton(R.string.ig_update_action_later, (dialogInterface, which) -> { // Dismiss the dialog dialogInterface.dismiss(); }) @@ -78,9 +80,9 @@ private static void showUpdateDialog(Context context, String updateUrl, String n private static void showErrorDialog(Context context) { new MaterialAlertDialogBuilder(context) - .setTitle("Error") - .setMessage("Failed to check for updates. Please try again later.") - .setPositiveButton("OK", (dialogInterface, which) -> dialogInterface.dismiss()) + .setTitle(context.getString(R.string.ig_update_error_title)) + .setMessage(context.getString(R.string.ig_update_error_message)) + .setPositiveButton(android.R.string.ok, (dialogInterface, which) -> dialogInterface.dismiss()) .show(); } } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index cf32ff6b..75a887f0 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -114,6 +114,95 @@ 禁用视频自动播放 显示关注者提示 显示已启用功能提示 + + + InstaEclipse 🌘 + 🎛 开发者选项 + 👻 幽灵模式设置 + 🛡 广告/分析拦截 + 🧘 无干扰 Instagram + ⚙ 杂项功能 + ℹ️ 关于 + 🔁 重启应用 + ❌ 关闭 + ← 返回 + 开发者选项 🎛 + 幽灵模式 👻 + 广告/分析拦截 🛡️ + 无干扰 Instagram 🧘 + 杂项 ⚙️ + 关于 + 重启应用 + 自定义快速开关 🛠️ + 启用/禁用所有 + 启用开发者模式 + 📥 导入开发者配置 + 📤 导出开发者配置 + 错误 + 无法打开 InstaEclipse 界面。 + Instagram 未打开或尚未准备就绪。 + 🛠 自定义快速开关 + 包含:隐藏已读 + 包含:隐藏输入状态 + 包含:禁用截图检测 + 包含:隐藏查看一次 + 包含:隐藏动态已读 + 包含:隐藏直播已读 + 隐藏已读 + 隐藏输入状态 + 禁用截图检测 + 隐藏查看一次 + 隐藏动态已读 + 隐藏直播已读 + 拦截广告 + 拦截分析 + 禁用追踪链接 + 极限模式 🔒(重新安装前不可撤销) + 禁用 Reels(私信除外) + 启用极限模式? + 启用后,在重新安装应用之前无法关闭无干扰模式。继续? + 禁用动态自动翻页 + 禁用视频自动播放 + 禁用转发 + 显示关注提示 + 显示功能提示 + 作者:@reso7200 + 🌐 GitHub 仓库 + ⚠️ 清除应用缓存并重启? + 🔁 立即重启 + 找不到要重启的应用。 + 重启失败:%1$s + ❗ 未选择任何幽灵模式选项! + 👻 幽灵模式已启用 + ❌ 幽灵模式已禁用 + ✅ 消息已标记为已读 + InstaEclipse 已加载 🎯 + + + 发现更新 + 发现新版本(%1$s)。现在更新吗? + 更新 + 稍后 + 错误 + 检查更新失败,请稍后重试。 + + + 正在导入配置... + ✅ 已导入到 mc_overrides.json + ❌ 导入配置失败 + 选择 JSON 配置 + ❌ 不是有效的 JSON 文件 + ❌ 读取文件失败:%1$s + 已取消或未选择文件 + mc_overrides_exported.json + ❌ 无效的 URI + ❌ 剪贴板为空。 + ❌ 剪贴板没有数据。 + ❌ 剪贴板文本为空。 + ❌ 剪贴板中不是有效 JSON。 + ✅ JSON 导出成功。 + ❌ 保存文件失败:%1$s + Contributor Name diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2bbdb1c2..74c94507 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -116,7 +116,95 @@ 顯示關注者提示 顯示已啟用功能提示 + + InstaEclipse 🌘 + 🎛 開發者選項 + 👻 幽靈模式設定 + 🛡 廣告/分析攔截 + 🧘 無干擾 Instagram + ⚙ 雜項功能 + ℹ️ 關於 + 🔁 重啟應用 + ❌ 關閉 + ← 返回 + 開發者選項 🎛 + 幽靈模式 👻 + 廣告/分析攔截 🛡️ + 無干擾 Instagram 🧘 + 雜項 ⚙️ + 關於 + 重啟應用 + 自訂快速開關 🛠️ + 啟用/禁用所有 + 啟用開發者模式 + 📥 匯入開發者配置 + 📤 匯出開發者配置 + 錯誤 + 無法打開 InstaEclipse 介面。 + Instagram 未打開或尚未就緒。 + 🛠 自訂快速開關 + 包含:隱藏已讀 + 包含:隱藏輸入狀態 + 包含:禁用截圖偵測 + 包含:隱藏查看一次 + 包含:隱藏動態已讀 + 包含:隱藏直播已讀 + 隱藏已讀 + 隱藏輸入狀態 + 禁用截圖偵測 + 隱藏查看一次 + 隱藏動態已讀 + 隱藏直播已讀 + 攔截廣告 + 攔截分析 + 禁用追蹤連結 + 極限模式 🔒(重新安裝前不可撤銷) + 禁用 Reels(私訊除外) + 啟用極限模式? + 啟用後,在重新安裝應用之前無法關閉無干擾模式。繼續? + 禁用動態自動翻頁 + 禁用影片自動播放 + 禁用轉發 + 顯示關注提示 + 顯示功能提示 + 作者:@reso7200 + 🌐 GitHub 倉庫 + ⚠️ 清除應用快取並重啟? + 🔁 立即重啟 + 找不到要重啟的應用。 + 重啟失敗:%1$s + ❗ 未選擇任何幽靈模式選項! + 👻 幽靈模式已啟用 + ❌ 幽靈模式已禁用 + ✅ 訊息已標記為已讀 + InstaEclipse 已載入 🎯 + + + 發現更新 + 發現新版本(%1$s)。現在更新嗎? + 更新 + 稍後 + 錯誤 + 檢查更新失敗,請稍後再試。 + + + 正在匯入配置... + ✅ 已匯入到 mc_overrides.json + ❌ 匯入配置失敗 + 選擇 JSON 配置 + ❌ 不是有效的 JSON 檔案 + ❌ 讀取檔案失敗:%1$s + 已取消或未選擇檔案 + mc_overrides_exported.json + ❌ 無效的 URI + ❌ 剪貼簿為空。 + ❌ 剪貼簿沒有資料。 + ❌ 剪貼簿文字為空。 + ❌ 剪貼簿中不是有效 JSON。 + ✅ JSON 匯出成功。 + ❌ 儲存檔案失敗:%1$s + Contributor Name - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 738c692b..4c8a2ee5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -116,6 +116,94 @@ Show Follower Toast Show Enabled Features Toast + + InstaEclipse 🌘 + 🎛 Developer Options + 👻 Ghost Mode Settings + 🛡 Ad/Analytics Block + 🧘 Distraction-Free Instagram + ⚙ Misc Features + ℹ️ About + 🔁 Restart App + ❌ Close + ← Back + Developer Options 🎛 + Ghost Mode 👻 + Ad/Analytics Block 🛡️ + Distraction-Free Instagram 🧘 + Miscellaneous ⚙️ + About + Restart App + Customize Quick Toggle 🛠️ + Enable/Disable All + Enable Developer Mode + 📥 Import Dev Config + 📤 Export Dev Config + Error + Unable to open InstaEclipse UI. + Instagram is not open or ready. + 🛠 Customize Quick Toggle + Include Hide Seen + Include Hide Typing + Include Disable Screenshot Detection + Include Hide View Once + Include Hide Story Seen + Include Hide Live Seen + Hide Seen + Hide Typing + Disable Screenshot Detection + Hide View Once + Hide Story Seen + Hide Live Seen + Block Ads + Block Analytics + Disable Tracking Links + Extreme Mode 🔒 (Irreversible until reinstall) + Disable Reels Except in DMs + Activate Extreme Mode? + Once activated, you cannot disable Distraction-Free Mode until you reinstall the app. Continue? + Disable Story Auto-Swipe + Disable Video Autoplay + Disable Repost + Show Follower Toast + Show Feature Toasts + Created by @reso7200 + 🌐 GitHub Repo + ⚠️ Clear app cache and restart? + 🔁 Restart Now + Could not find the app to restart. + Restart failed: %1$s + ❗ No Ghost Mode options selected! + 👻 Ghost Mode Enabled + ❌ Ghost Mode Disabled + ✅ Message was marked as read + InstaEclipse Loaded 🎯 + + + Update Available + A new version (%1$s) is available. Would you like to update now? + Update + Later + Error + Failed to check for updates. Please try again later. + + + Importing config... + ✅ Imported into mc_overrides.json + ❌ Failed to import config + Select JSON Config + ❌ Not a valid JSON file + ❌ Failed to read file: %1$s + Cancelled or no file selected + mc_overrides_exported.json + ❌ Invalid URI + ❌ Clipboard is empty. + ❌ Clipboard has no data. + ❌ Clipboard text is empty. + ❌ Clipboard does not contain valid JSON. + ✅ JSON exported successfully. + ❌ Failed to save file: %1$s + Contributor Name