14 Commits

Author SHA1 Message Date
Imran
b3965b8199 Update DEVELOPER_GUIDE.md 2026-07-08 11:29:45 +01:00
Imran Remtulla
8e91619882 fix: remove dead service classes, fix external multi-APK install wait, fix docs
- Remove unused ConnectivityService, InstallContextService, and AppIdService
  from apps_provider.dart (defined but never referenced anywhere)
- Fix ExternalInstaller: the foreground-return future was created once but
  awaited inside the per-path loop, so every path after the first resolved
  instantly instead of waiting for the user to return. Create a fresh future
  per launch (subscribed before the intent launch to avoid missing the event)
- Remove 'flutter test' from DEVELOPER_GUIDE build steps; it contradicted the
  same section's note that the project has no automated tests
2026-07-03 15:09:47 +01:00
Imran Remtulla
7a8082cbe1 fix: remove tarball size limit, fix docs, clean up code quality issues
- Remove all tarball size limits (500MB cap deleted)
- Remove redundant 'late' keywords from AppsFilter fields that have constructor defaults
- Add logging to previously-silent catch in download size probe
- Fix DEVELOPER_GUIDE.md: remove nonexistent AppListCategorySection, fix showGeneratedFormModal reference, correct tarball docs, add installers/ and external_install_bridge.dart to directory tree, fix double backtick fence
- Update pubspec.yaml TODO comments for all git-fork dependencies to be more specific
2026-07-03 14:52:21 +01:00
Imran Remtulla
4b0c5405df fix: resolve 30+ bugs, safety issues, and code quality problems across the codebase
HIGH severity fixes:
- Fix indexOf -> startsWith for URL scheme detection to prevent corrupting
  non-http URLs (source_provider.dart)
- Fix OOM risk: use XFile(path) instead of readAsBytes() for large APKs
  (apps_provider_install.dart)
- Fix GeneratedFormSwitch.ensureType returning String instead of bool,
  causing runtime _CastError (generated_form_model.dart)
- Fix initForm() called during build() triggering parent setState by moving
  init to didUpdateWidget + postFrameCallback (generated_form_renderer.dart)
- Fix CI sed no-op: update regex to match actual signingConfig pattern in
  build.gradle.kts (release.yml)
- Fix build.sh auto git push on no-args: require explicit arg to sync+build
- Pin all git dependencies to commit SHAs instead of mutable branches

MEDIUM severity fixes:
- Sequence background service start/stop calls to prevent races (main.dart)
- Move loadSystemFont() from build() to init to prevent visible font flash
- Prevent concurrent bgUpdateCheck calls in onRepeatEvent with guard flag
- Extend download retry to SocketException and TimeoutException
- Cap install permission loop at 10 attempts to prevent infinite hang
- Remove dead unused headers variable causing double bcrypt hash (coolapk.dart)
- Remove HTTP 304 from redirect status check (huaweiappgallery.dart)
- Guard result.files.single against empty file picker results (import_export.dart)
- Add error logging to linkFn catch block (add_app.dart)
- Disable continue button when no download URL available (app_detail_widgets.dart)
- Fix DEVELOPER_GUIDE.md: list all git-pinned deps, correct android_package_manager

LOW severity fixes:
- Use 'final' instead of 'late' for FDroid field (izzyondroid.dart)
- Use stable 'name' instead of runtime-type sourceIdentifier (neutroncode.dart)
- Fix typo: finalUrlKey -> urlDataKey (uptodown.dart)
- Fix aptoide constructor field order for consistency
- Remove dead app?.app == null condition (app.dart)
- Reuse SourceProvider instance instead of throwaway (apps.dart)
- Support descending sort for 'as added' column (app_list_tile.dart)
- Remove SDK >= 31 guard causing layout shift for material-you option (settings.dart)
- Secure standardize.mjs: atomic write-then-rename, Object.hasOwn, error handling
- Add flutter_launcher_icons to dev_dependencies
2026-07-02 15:53:06 +01:00
Imran Remtulla
6e2c2c592c fix: resolve bugs, dead code, unsafe patterns, and infrastructure issues
HIGH severity:
- Fix Completer double-completion masking CheckUpdatesException as StateError
- Delete orphaned APK files on install-already-pending status code
- Stop transient source-load errors from permanently deleting user app entries
- Await saveApps in setCategories to avoid data inconsistency
- Guard packageManager.openApp double-tap behind installed check
- Fix hashCode.abs() overflow on min int value in DownloadNotification

MEDIUM severity:
- Wrap checkETagHeader client.send in try/finally to prevent resource leak
- Remove unused loadingCompleter dead code in loadApps
- Pass additionalSettings (not {}) in apkcombo sourceRequest call
- Remove dead getRequestHeaders call in coolapk
- Add missing == true on boolean setting checks in fdroidrepo
- Zero-pad month/day in itchio date version string
- Deep-copy form items by value in izzyondroid and codeberg constructors
- Remove redundant double-reverse for sort=none in github release sorting
- Clamp negative gradient stop to valid range in app_list_tile
- Show WebView error state when main frame resource fails to load
- Defer WebView appId changes until page load completes
- Defer category pruning side effect out of build into post-frame callback
- Expand URL regex in import_export to match whitespace-delimited URLs
- Remove future-update-in-build side effect for source notes in add_app
- Add items hash to form reinit check alongside widget key

LOW severity:
- Add 'name' field to all 11 AppSource subclasses that lacked it
- Remove unused source_provider imports from app_detail_widgets, category_editor
- Rename copy-pasted bool show param to bool value on non-show setter pairs
- Delete dead proguard-rules.pro (Gson is not a dependency)
- Remove npm package files from git tracking in assets/translations
- Fix DEVELOPER_GUIDE test directory reference
2026-07-02 14:38:17 +01:00
Imran
f85d9206c7 Rearchitect (#3002)
* architecture: consolidate and simplify

- Collapse 14 directories into 4 (app_sources, components, pages, providers)
- Replace DI container with inline construction in main.dart
- Fold page controllers back into their pages (one file per screen)
- Merge small files into their natural homes (removing 40 files)
- Standardize error handling across all 28 app sources (rethrowOrWrapError)
- Make App immutable with copyWith() replacing deepCopy()
- Replace globalNavigatorKey with go_router
- Add error boundaries, source health monitor, typed settings
- Eliminate all silent catch blocks
- Add tests and CI pipeline
- Extend lint rules

97 files → 56 files. 0 errors, 4/4 tests passing.

* fix: remove unused go_router, restore internal navigation

- Drop go_router (ShellRoute broke tab switching and disabled the
  tablet/TV two-pane layout); revert to MaterialApp + navigatorKey
- Move appNavigatorKey into main.dart; delete router.dart
- Remove HomePage.child branch so the internal switcher drives the UI
- Fix dead 'Restart' button in the error fallback screen
- Remove TypedSettings []= mutation backdoor
- Persist clamped preferredApkIndex to the in-memory app map
- Use settings.getBool('trackOnly') instead of raw map access

* fix: remove dead rethrowOrWrapError, add missing import, update stale comments and docs

* fix: satisfy lint rules, wrap fire-and-forget futures, drop unused CI

- Fix use_build_context_synchronously via mounted/context.mounted guards
- Wrap deliberate fire-and-forget futures in unawaited()
- Document static app-lifetime event bus for close_sinks
- Apply dart format and dart fix across the codebase
- Drop avoid_catches_without_on_clauses (noisy in source scrapers)
- Remove test.yml CI workflow
- Rename test/services to test/providers

* fix: show real HTTP error messages, remove source health monitor and dead event-bus code

- Bypass deferred localization for HTTP_ERROR so the real reason phrase/status is shown instead of a generic 'unexpected error'
- Remove SourceHealthMonitor entirely (per-instance state made it ineffective for background checks)
- Simplify save-notification bus to StreamController<void>; drop unused AppRepositoryEvent/AppRepositoryEventType and events getter
- Scrub stale docs (SourceHealthMonitor, event type, deleted test.yml workflow)

* fix: preserve installedVersion on import, correct stale theme doc reference

* fix: type logger as Logger?, simplify ErrorWidget builder, document _sentinel, resolve TextDirection conflict

- Change dynamic logger to Logger? in AppsProvider for type safety (the
  field was unused but the contract should be explicit).
- Replace MaterialApp wrapper in ErrorWidget.builder with a minimal
  Directionality + Scaffold; MaterialApp is wasteful for a one-shot
  error screen.
- Add a doc comment explaining the _sentinel pattern used by
  App.copyWith to distinguish unset from explicitly-null nullable fields.
- Hide TextDirection from easy_localization (which re-exports intl's
  conflicting TextDirection enum that lacks ltr/rtl) so the Flutter
  dart:ui TextDirection.ltr resolves correctly.

* fix: register SourceForge, restore Palestine banner, drop dead code and tests

- Register the implemented SourceForge source in _buildSources() so the
  README's supported-sources list is accurate.
- Restore the Support Palestine banner in README.md (unintentionally removed).
- Remove unused ConfigProvider, CredentialHealth, getCredentialHealth, and
  the never-injected _configProvider path from settings_provider.
- Remove unit tests and their test-only dev dependencies.
2026-07-02 01:58:45 +01:00
Imran Remtulla
6d8dfe33a8 chore: standardize code quality, logging, docs, and dependencies
- Replace print/debugPrint with LogsProvider across 11 files
- Convert all Future.ignore() to unawaited() across 7 files
- Fix import ordering (dart: first) in apps_provider, source_provider, coolapk
- Remove unnecessary late keywords (apps, githubstars)
- Add const where applicable (EdgeInsets, TextStyle)
- Standardize mounted → context.mounted across StatefulWidget pages
- Reduce pickedSource! null assertions in add_app (14→2)
- Break up 320-line _fetchReleaseDetails into 5 methods in github.dart
- Extract share callbacks from bottom sheet in apps.dart
- Replace Provider.of with context.read in ui_widgets
- Remove unused dart:ui import, fix clampDouble usage
- Add TypeError catch in App.fromJson() for corrupt JSON
- Preserve original error details in 8 catch blocks
- Remove redundant lint ignores (unnecessary_non_null_assertion, invalid_return_type)
- Update DEVELOPER_GUIDE for theme.dart, app_info_dialog, logging, naming
- Upgrade cross_file transitive dependency
2026-07-01 12:33:26 +01:00
Imran Remtulla
226eab22a0 Fix bugs, improve readability, and clean up across the codebase
Bugs fixed:
- generated_form.dart: initForm() crashed on GeneratedFormSwitch (missing case)
- apps_provider.dart: HttpClient leak in downloadFile(), now protected by try/finally
- apps_provider_install.dart: magic numbers 0/3 replaced with named constants
- app.dart: unstable hash from Map.toString() replaced with jsonEncode
- home.dart: context.read in build() → context.select (no rebuild on app add/remove)
- apps.dart: O(n²) string concat → StringBuffer; setState without mounted guard
- farsroid.dart: Uri.encodeFull encoded ?/& → removed; missing status code check added
- rustore.dart: null appId creating .../null URL; error-swallowing try/catch fixed
- jenkins.dart: unsafe json['timestamp'] as int cast → int.tryParse
- aptoide.dart: fragile substring+12 ID extraction → capturing regex group
- apkpure.dart: unguarded DeviceInfoPlugin; empty arch filename trailing dash
- apkmirror.dart: regex filter producing misleading NoVersionError
- apk4free.dart: empty-string version bypassing title-parsing fallback
- tencent.dart: substring(18) magic number → jsVar.length constant
- rockmods.dart: unsafe as Map? cast → is Map guard
- fdroid.dart: null appId in URL interpolation; RegExp instantiated in for loop

Refactored:
- source_provider.dart: ~290 lines of legacy JSON migrations → app_migrations.dart
- import_export.dart: IIFE pattern → normal async/try/catch/finally
- import_export.dart: deduplicated PlatformException handling
- add_app.dart: cleaned up state mutation outside setState pattern
- app_list_builder.dart: sort(added) returns List.from() instead of mutable ref
- codeberg.dart: gh → _gh for consistency with gitlab.dart
- uptodown.dart: parseDateTimeMMMddCommayyyy → parseUptodownDate
- app_list_tile.dart: redundant SizedBox.shrink() → if-spread; IIFE → helper method

Docs & comments:
- README: removed redundant source-code link
- DEVELOPER_GUIDE: added app_migrations.dart; improved settings reference
- Comments: prevApp flag, home SizedBox.shrink, huawei date logic, gradient stop,
  telegramapp URL discard, gitlab _gh usage, coolapk device fingerprint note
- Fixed outdated 'Previous 2 variables' comment in source_provider.dart

CI & infra:
- release.yml: fixed undefined inputs.checkout; added fetch-depth: 0; v3→v4
- translation-validate.yaml: fixed @v6.0.2 typo → @v4
- build.sh: added set -euo pipefail
- proguard-rules.pro: removed dead Gson example rule
- standardize.mjs: warns on untracked keys; fixed broken error logging

Translations:
- en.json: added 4 missing keys (downloadFailed, downloadedXNotifChannel,
  import, noMatchingReleaseFound)
2026-07-01 10:11:08 +01:00
Imran Remtulla
3c0bca53a0 refactor: fix bugs, deduplicate code, remove dead code, improve naming, clean comments
Bugs fixed:
- Null assertion crash in _downloadAppForInstall unexpected download types
- Null assertion crash in bgUpdateCheck on missing Map keys
- Silently swallowed network errors during foreground update checks
- SettingsProvider state desync between AppsProvider and widget tree
- Jenkins regex matching any host instead of only Jenkins servers
- GitHubStars bypassing authentication tokens and proxy settings
- Aptoide/Uptodown subdomain regex requiring 2+ subdomain segments
- undoGHProxyMod constructing 'https://null/' prefix when unconfigured
- Negative hashCode used as Android notification IDs
- farsroid.dart force-unwrap on nullable Response.request
- vivoappstore.dart replaceAll/replaceFirst and unencoded URL params
- apkmirror.dart getAppNames missing bounds checks
- apkcombo.dart empty catch on DateFormat.parse
- rustore.dart useless inner catch/rethrow

Code deduplication & simplification:
- Extracted AppSource.buildMergedSettings() helper (3 sites)
- Extracted AppInMemory.needsRefreshBeforeDownload getter (2 sites)
- Extracted AppSource.fallbackToOlderReleasesFormItem static getter (5 sources)
- Extracted AppSource.rethrowOrWrapError() helper (3 sources)
- Added AppSource.changeLogPageIsStandardUrl flag (3 sources → 0 overrides)
- Removed HttpClientMixin, moved getRequestHeaders onto AppSource
- 17+ app sources using standardizeUrlWithRegex() consistently
- neutroncode.dart: 50-line switch → const map lookup
- import_export filter simplified to single-expression lambda

Dead code removed:
- 151-line buildRepoRenameWarning() method in app.dart (never called)
- Redundant condition installedOnly && nonInstalledOnly
- Dead ternary branch in getApp()
- Redundant if(valid) guard in generated_form_modal onPressed
- Redundant message = '' in AppsRemovedNotification
- Duplicated // ignore: comment
- DirectAPKLink/RockMods unused scraping for track-only

Naming improvements:
- fdroid → isFdroidBuild, MyTaskHandler → BackgroundUpdateTaskHandler
- pm → packageManager, AppNames → AppIdentity
- findExistingUpdates → findAppIdsWithPendingUpdates
- endOfGetAppChanges → postProcessApp
- someValueChanged → notifyFormChange
- _isNumeric → _isDigit, _maxChangeLogBytes → _maxChangeLogCodeUnits
- customDateParse → formatDateForParsing
- LogLevels → LogLevel

Comment cleanup:
- Removed 20+ noise/obvious comments across 10 files
- Shortened verbose doc comments (bgUpdateCheck 15→6 lines)
- Fixed ALL-CAPS section headers in apps_provider_lifecycle
- Fixed @param Javadoc → Dart doc style
- Removed empty/blind comments
- Cleaned unprofessional wording ('pacify')
- Shortened verbose block comments in custom_app_bar, ui_shapes, motion

Performance:
- Cached SourceProvider() in app.dart (was per-build) and home.dart (was per-deep-link)
- home.dart: context.read → context.watch for reactive page transitions

- code changes: 47 files, +263/-512 lines
2026-06-30 22:26:21 +01:00
Imran Remtulla
f7d9e9740a Refactor: improve readability, fix bugs, remove dead code, consolidate duplication
Critical bugs fixed:
- itchio: invalid ?cookies Dart syntax
- github: sourceConfigSettingValues type mismatch for checkRepoRename
- github: object vs string comparison in release repositioning
- source_provider: copy-paste bug in _migrateAdditionalDataToSettings
- html: hashCode for APKLinkHash preserved (user confirmed stable)

Medium bugs fixed:
- source_provider: URI parsed 3x in stripLastPathSegment (now cached)
- source_provider: HTTP 304 excluded from redirect range
- source_provider: unsafe type cast in migration guarded
- apps_provider_lifecycle: non-FormatException rethrow no longer kills all loading
- apps_provider_lifecycle: renameSync -> rename (non-blocking)
- add_app: null guard on downloadedArtifact type dispatch
- import_export: empty map guard on .first access
- github: double DateTime.now() race consolidated
- Empty catch blocks now log via debugPrint or LogsProvider

Dead code removed:
- intValidator (zero callers)
- Duplicate http import consolidated
- late -> final on constructor-initialized fields
- print() in fdroidrepo replaced with LogsProvider

Structural refactors:
- app.dart: build() ~395 -> ~116 lines (7 methods extracted)
- apps_provider_install: 4 closures lifted to private methods
- import_export: 7 widget builders extracted + dedup init logic
- generated_form: type-checking extracted to named helpers
- source_provider: _resolveAppId() extracted from 5-level ?? chain
- source_provider: _migrateHtmlSpecificMigrations readability
- apps_provider_lifecycle: standardVersionDetection/realVersion helpers

Duplicated code consolidated:
- ensureAbsoluteUrl moved to source_provider (shared utility)
- APK filename matching extracted to preferMatchingApk
- Lifecycle helpers for naiveStandardVersionDetection/realInstalledVersion

Magic numbers -> named constants:
- _foregroundServiceId (666), _fgTaskRepeatMs (900000)
- _maxChangeLogBytes (2048)
- _androidApiLevelR (30), _androidApiLevelS (31)
- _installingProgressSentinel (-1)
- _corruptFileSuffix (.corrupt)
- _defaultMatchGroup (0)

Comments: 37+ doc comments added to error classes, utility functions, providers
Documentation: DEVELOPER_GUIDE.md updated for accuracy
Lint: 20+ use_build_context_synchronously ignores replaced with mounted guards

hashListOfLists: SHA-256 truncated to 8 chars (was 64, too long for version display)
flutter analyze: clean (no issues found)
2026-06-30 19:35:05 +01:00
Imran Remtulla
8eb2f092c2 Refactor: fix bugs, extract helpers, improve code structure
Bugs fixed:
- hashListOfLists double-hashing (sha256.hex.hashCode losing 224 bits)
- undrained HTTP response streams in downloadFile/checkETagHeader
- destructive useMaterialYou setter (removed unused getter/setter)
- 5 bare .endsWith('.apk') replaced with AppSource.isApkOrContainerFile
- fire-and-forget async IIFE in AppsProvider constructor missing error handling

Refactors:
- Extracted appJSONCompatibilityModifiers into 6 named sub-migration helpers
- Split bgUpdateCheck: extracted _bgRunUpdateCheck helper (~170 lines)
- Moved showMessage/showError from custom_errors.dart to components/ui_widgets.dart
- Replaced 'source is! HTML && source is! SourceForge' with AppSource.suppressStandardVersionExtraction flag
- Extracted buildObtainiumTheme to new lib/theme.dart
- Cleaned up BG workaround TODO, verbose comments, docs errors
2026-06-30 17:44:55 +01:00
Imran Remtulla
5877d168ed refactor: improve code clarity, fix bugs, and clean up comments
Bug fixes:
- downloadAppAssets now populates downloadedIds list
- preStandardizeUrl handles IPv6 addresses (URLs with brackets)
- github.dart getAppNames validates path before extracting names
- direct_apk_link.dart normalizes non-selection URLs via Uri.tryParse
- apps.dart deferred selectedAppIds mutation out of build() to post-frame
- Replaced unsafe 'as DownloadedDir' casts with 'is DownloadedDir' checks

Code quality:
- Replaced .runtimeType comparisons with 'is' checks where applicable
- Simplified .runtimeType.toString() to .name (identical values)
- Removed unused userPickedTrackOnly parameter
- Removed unnecessary 'late' from AppNames fields
- Fixed side-effect predicate in apps.dart (pre-compute track-only IDs)
- Clarified sourceforge.dart double-reverse version extraction
- Split _cachedIsTV initialization to avoid atomicity issues
- Replaced @visibleForTesting access with _fgServiceInitialized flag
- Used ??= for conditional assignments

Comments:
- Added doc comments to LogsProvider, AppInMemory, Jenkins, DirectAPKLink,
  GitHubStars, SourceForge, getInstallPermission, appJSONCompatibilityModifiers
- Shortened verbose comments in settings_provider.dart and source_provider.dart
- Clarified fdroid variable pattern in main.dart

Lint suppressions:
- Replaced file-wide ignore_for_file in import_export.dart with targeted
  per-line ignores for the 6 remaining deliberate uses

Documentation:
- DEVELOPER_GUIDE.md: added error handling and categories sections,
  condensed conventions
- README.md: reformatted verification info as table, removed extraneous banner

All changes pass flutter analyze with zero issues.
2026-06-30 15:39:41 +01:00
Imran Remtulla
7a15172d2a chore: readability/maintainability pass across entire codebase
Phase 1 — quick wins:
- Fix 4 flutter_analyze lint issues
- Remove dead code (incrementCountCommand, noAPKFound, duplicate date parse)
- Standardize comment style (remove outlier emoji)

Phase 2 — bug fixes:
- Fix inverted parallel-downloads logic in downloadAppAssets
- Replace unsafe int.parse/DateTime.parse with tryParse in scraped/user input
- Fix _reloadIfBgSaved to clear timestamp on failure (was stuck-in-loop)

Phase 3 — source deduplication:
- Migrate 8 hand-rolled standardizeURL regexes to base-class standardizeUrlWithRegex
- Route githubstars.dart through sourceRequest instead of raw http.get

Phase 4 — structural refactors:
- Extract caption/fieldTile/colorPickerDialog/footer from 735-line settings build()
- Fix void async anti-pattern on uninstallApp -> Future<void>

Phase 5 — docs:
- Remove fabricated config_keys.dart/AppConfigKey references from developer guide
- Correct/trim README troubleshooting section
2026-06-30 14:30:21 +01:00
Imran Remtulla
5c02742bb2 Add developer docs: architecture guide, M3E changes summary, lessons learned 2026-06-29 02:46:26 +01:00