Repository navigation
fix: request permissions only on user tap + startup and lifecycle fixes - #5
Conversation
The welcome page automatically fired the all-files-access settings screen, the runtime media dialogs and the notification dialog as soon as the page appeared. Permissions must only be requested when truly needed (AGENTS.md section 6), so every permission now stays behind its row's Grant button, the same pattern the notification row already used. - Remove autoRequestMissing() and its call from onViewCreated - Files row: on Android 11+ open the all-files settings screen on tap; on Android 8-10 fall back to the runtime storage dialog (the button previously did nothing on those versions) - Catch ActivityNotFoundException on the two settings intents and show a toast instead of crashing on devices without those settings pages - Remove the unused PermissionUtils.requestPermissions(Activity) helper that silently opened the all-files settings screen - Clear the view binding in onDestroyView and guard refreshGranted()
- Initialize PluginManager in GhostIdeAppLoader so the file manager can register with plugins on first launch; previously the registration NPE was swallowed until EditorActivity had been opened once - Drop PluginManager's write-only activity fields (static leaks) - Add clearEditorActivityReferences()/clearFileManagerActivityReferences() and call them from EditorActivity/FileManagerActivity onDestroy so plugins no longer retain destroyed activities - Cancel the delayed plugin-host Runnable on FileManagerActivity destroy - Reorder FileManagerActivity.onDestroy so the host registration, git helper and executor are always disposed; guard receiver unregistration and the music preview against a missing binding - Extract cursor.zip off the main thread with try-with-resources, reject zip entries that escape the target directory, and log failures instead of ignoring them
- OnboardingViewModel now detaches its DebianInstaller listener in onCleared(); DebianInstaller keeps the listener in a static field, so the ViewModel leaked until a new terminal screen attached - NetworkChangeReceiver ignores deliveries when no callback is set; manifest-instantiated receivers would otherwise crash with an NPE
|
@Afton-programmer Tank you in Fork |
|
Two more fixes are pushed ( 1. Icon pack / background plugin sections now hide when no plugin is installed. 2. Section expansion no longer clips rows or freezes the screen:
A fresh دو مورد گفتهشده انجام و push شد: بخشهای «آیکون پک» و «پلاگین بکگراند» وقتی پلاگینی نصب نباشه کامل مخفی میشن، و مشکل نمایش ناقص هنگام expand (ارتفاع fix شده قدیمی) و هنگ کردن صفحه تنظیمات (انیمیشن همزمان هشت کارت شیشهای در جستجو) برطرف شد. APK جدید هم از همین commit ساخته شد. |
I reviewed the project end to end and fixed several issues found along the way. The main one is the first-launch permission UX.
1. Storage permission was auto-requested on app entry (main fix)
The onboarding welcome page called
autoRequestMissing()fromonViewCreated(), so the moment the page appeared the app automatically opened the All files access settings screen, then the runtime media dialogs, then the notification dialog — before the user tapped anything. Users perceive this as the app grabbing permissions on its own, which is intrusive.Every permission is now requested only when the user taps its row's Grant button — the same pattern the Notifications row already used — which also matches AGENTS.md section 6 (permissions only when truly needed).
autoRequestMissing()and its call fromonViewCreated()ActivityNotFoundExceptionhandling (toast instead of crash on devices without those settings pages)PermissionUtils.requestPermissions(Activity)helper that silently opened the all-files settings screen (dead code, no callers)2. Lifecycle / memory-leak fixes
PluginManageris now initialized inGhostIdeAppLoader, so plugins receive the file-manager host on first launch; previously the registration NPE was silently swallowed untilEditorActivityhad been opened oncePluginManager's write-only activity fields (static leaks) and addedclearEditorActivityReferences()/clearFileManagerActivityReferences(), called from the activities'onDestroy()so plugins no longer retain destroyed activitiesFileManagerActivity.onDestroy()now always disposes the host registration, git helper and executor; previously an exception fromunregisterReceiver()skipped all of them. The unregistration is guarded, the binding is null-checked and the delayed plugin-hostRunnableis cancelledOnboardingViewModel.onCleared()now detaches itsDebianInstallerlistener (the installer keeps it in astaticfield, so the ViewModel leaked after onboarding)NetworkChangeReceiverignores deliveries when no callback is attached (manifest-instantiated receivers would NPE)3. Startup robustness
extractCursorZip()now runs off the main thread, uses try-with-resources, rejects zip entries that escape the target directory (path traversal) and logs failures instead of silently ignoring them. The old code leaked streams on any read error and failed silently on every first launch, because storage permission is not granted yet at that pointVerification
./gradlew assembleDebug) on my fork; CI is greenmap.mddid not need an update (AGENTS.md section 8)Suggestions (not included here; happy to send separate PRs)
SplashActivityholds every launch for a fixed 3.8 s; shortening it would make the app feel much snappierTerminalActivity/TerminalBottomSheetFragmentstill auto-requestPOST_NOTIFICATIONSwhen opened; if the tap-only policy should apply everywhere, those need a small affordance tooapp/build.gradlecontains the release keystore alias and passwords in plaintext in a public repo. Please rotate the keystore and move the credentials to CI secretsسلام! پروژه را کامل بررسی کردم و چند مشکل را برطرف کردم؛ مهمترینشان رفتار آزاردهندهی درخواست خودکار دسترسی به فایلها در اولین ورود بود که حالا فقط با کلیک کاربر روی دکمهی Grant درخواست میشود. لطفاً نگاهی بیندازید؛ اگر مورد تأیید بود ممنون میشوم merge کنید.