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 0242ff63..7eea190b 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 @@ -1,7 +1,5 @@ package ps.reso.instaeclipse.mods.devops.config; -import static ps.reso.instaeclipse.utils.feature.FeatureFlags.isImportingConfig; - import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -14,7 +12,6 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.nio.charset.StandardCharsets; -import java.util.Objects; import de.robv.android.xposed.XposedBridge; import ps.reso.instaeclipse.utils.feature.FeatureFlags; @@ -23,62 +20,57 @@ public class ConfigManager { // Import meta config from clipboard public static void importConfigFromClipboard(Context context) { - if (isImportingConfig) { - android.app.ProgressDialog progress = new android.app.ProgressDialog(context); - progress.setMessage("Importing config..."); - progress.setCancelable(false); - progress.show(); - - new Thread(() -> { - try { - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - if (clipboard == null || !clipboard.hasPrimaryClip()) { - return; - } - - ClipData clipData = clipboard.getPrimaryClip(); - if (clipData == null || clipData.getItemCount() == 0) { - return; - } - - CharSequence clipText = clipData.getItemAt(0).getText(); - if (clipText == null || clipText.length() == 0) { - return; - } - - String json = clipText.toString().trim(); - if (!json.startsWith("{") || !json.endsWith("}")) { - return; - } - - File dest = new File(context.getFilesDir(), "mobileconfig/mc_overrides.json"); - if (!Objects.requireNonNull(dest.getParentFile()).exists()) { - dest.getParentFile().mkdirs(); - } - - try (FileOutputStream fos = new FileOutputStream(dest, false)) { - fos.write(json.getBytes(StandardCharsets.UTF_8)); - fos.flush(); - } - - new Handler(Looper.getMainLooper()).post(() -> { - progress.dismiss(); - Toast.makeText(context, "✅ Imported into mc_overrides.json", 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(); - }); + + android.app.ProgressDialog progress = new android.app.ProgressDialog(context); + progress.setMessage("Importing config..."); + progress.setCancelable(false); + progress.show(); + + new Thread(() -> { + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + try { + if (clipboard == null || !clipboard.hasPrimaryClip()) throw new IllegalStateException("Empty clipboard"); + + ClipData clipData = clipboard.getPrimaryClip(); + if (clipData == null || clipData.getItemCount() == 0) throw new IllegalStateException("Empty clipboard"); + + CharSequence clipText = clipData.getItemAt(0).getText(); + if (clipText == null || clipText.length() == 0) throw new IllegalStateException("Empty clipboard"); + + String json = clipText.toString().trim(); + if (!json.startsWith("{") || !json.endsWith("}")) throw new IllegalArgumentException("Clipboard is not valid JSON"); + + File dest = new File(context.getFilesDir(), "mobileconfig/mc_overrides.json"); + File parent = dest.getParentFile(); + if (parent != null && !parent.exists()) parent.mkdirs(); + + try (FileOutputStream fos = new FileOutputStream(dest, false)) { + fos.write(json.getBytes(StandardCharsets.UTF_8)); + fos.flush(); } - }).start(); - } + // (Optional) clear clipboard to avoid stale re-imports later + try { clipboard.setPrimaryClip(ClipData.newPlainText("", "")); } catch (Exception ignored) {} + + new Handler(Looper.getMainLooper()).post(() -> { + progress.dismiss(); + Toast.makeText(context, "✅ Imported into mc_overrides.json", 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(); + }); + } finally { + // 100% guarantee the flag is OFF after an attempt + FeatureFlags.isImportingConfig = false; + } + }).start(); } + // Export meta config to Device public static void exportCurrentDevConfig(Context context) { if (!FeatureFlags.isExportingConfig) { 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 234f9912..915fc74a 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,8 @@ import java.nio.charset.StandardCharsets; import java.util.Scanner; +import ps.reso.instaeclipse.utils.feature.FeatureFlags; + public class JsonImportActivity extends Activity { private static final int PICK_JSON_FILE = 1234; @@ -20,6 +22,7 @@ public class JsonImportActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + FeatureFlags.isImportingConfig = false; openJsonPicker(); } @@ -30,21 +33,34 @@ private void openJsonPicker() { startActivityForResult(Intent.createChooser(intent, "Select JSON Config"), PICK_JSON_FILE); } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == PICK_JSON_FILE && resultCode == RESULT_OK && data != null) { - Uri uri = data.getData(); - try (InputStream inputStream = getContentResolver().openInputStream(uri)) { - String json = readStream(inputStream); - ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("json", json); - clipboard.setPrimaryClip(clip); - - } catch (Exception e) { - Toast.makeText(this, "❌ Failed to read file: " + e.getMessage(), Toast.LENGTH_LONG).show(); + if (requestCode == PICK_JSON_FILE) { + if (resultCode == RESULT_OK && data != null) { + Uri uri = data.getData(); + try (InputStream inputStream = getContentResolver().openInputStream(uri)) { + String json = readStream(inputStream).trim(); + + // Validate before enabling the flag + if (json.startsWith("{") && json.endsWith("}")) { + ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("json", json); + clipboard.setPrimaryClip(clip); + + FeatureFlags.isImportingConfig = true; // <- only now turn it ON + //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(); + } + } 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(); + } + } else { + // User pressed back / cancelled + FeatureFlags.isImportingConfig = false; // <- ensure OFF on cancel + Toast.makeText(this, "Cancelled or no file selected", Toast.LENGTH_SHORT).show(); } - } else { - Toast.makeText(this, "Cancelled or no file selected", 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 a37fbbec..081246a0 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 @@ -138,25 +138,31 @@ protected void afterHookedMethod(MethodHookParam param) { }); // Hook onResume - Instagram Main - XposedHelpers.findAndHookMethod("com.instagram.mainactivity.InstagramMainActivity", classLoader, "onResume", new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) { - final Activity activity = (Activity) param.thisObject; - currentActivity = activity; - activity.runOnUiThread(() -> { - try { - setupHooks(activity); - addGhostEmojiNextToInbox(activity, isAnyGhostOptionEnabled()); - if (FeatureFlags.isImportingConfig) { - FeatureFlags.isImportingConfig = false; - ConfigManager.importConfigFromClipboard(activity); - } - - } catch (Exception ignored) { + XposedHelpers.findAndHookMethod( + "com.instagram.mainactivity.InstagramMainActivity", + classLoader, + "onResume", + new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) { + final Activity activity = (Activity) param.thisObject; + currentActivity = activity; + activity.runOnUiThread(() -> { + try { + setupHooks(activity); + addGhostEmojiNextToInbox(activity, isAnyGhostOptionEnabled()); + + if (FeatureFlags.isImportingConfig) { + // De-bounce: flip it off first so it won't re-trigger on next onResume + FeatureFlags.isImportingConfig = false; + ConfigManager.importConfigFromClipboard(activity); + } + } catch (Exception ignored) {} + }); } - }); - } - }); + } + ); + // Hook getBottomSheetNavigator - Instagram Main BottomSheetHookUtil.hookBottomSheetNavigator(Module.dexKitBridge);