Conversation
There was a problem hiding this comment.
Pull request overview
This PR lays the groundwork for a new “Power” start destination and a portable/hosted “Power Profile” model, introducing initial UI surfaces (Power, Discover, Active, Profile details) plus data-layer storage/sanitization to support importing/exporting and tracking active profiles.
Changes:
- Switch app start destination + bottom-nav “home” to
PowerFragment, and hide bottom nav for deep Power destinations. - Add initial Power Profile data model, storage, artifact loading, and security/sanitization utilities (plus ownership tracking).
- Add documentation + sample “community-knowledge” registry/profile artifacts and a broad set of Robolectric/unit tests.
Reviewed changes
Copilot reviewed 89 out of 90 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| gradle.properties | Increases Kotlin daemon heap via kotlin.daemon.jvmargs. |
| docs/POWER_PAGE_PRODUCT_MODEL.md | Adds proposed Power-page product model/IA and merge semantics doc. |
| docs/HOSTED_PROFILES.md | Defines proposed hosted profile + registry JSON formats and fetch model. |
| community-knowledge/registry/profile-registry.v1.json | Adds example hosted registry JSON. |
| community-knowledge/README.md | Describes the example hosted registry/profile directory. |
| community-knowledge/profiles/app-horse/app-horse.power-profile.v1.json | Adds example hosted profile artifact JSON. |
| app/src/test/java/com/celzero/bravedns/ui/PowerDestinationPolicyTest.kt | Tests deep-destination + bottom-nav mapping policy. |
| app/src/test/java/com/celzero/bravedns/ui/activity/PowerProfilePreviewUiPolicyTest.kt | Tests preview-mode UI disabling/enabling policies. |
| app/src/test/java/com/celzero/bravedns/ui/activity/AppInfoActivityUnitTest.kt | Adds intent-extra coverage for preview mode. |
| app/src/test/java/com/celzero/bravedns/data/SavedPowerProfileTest.kt | Adds JSON round-trip + parsing tests for saved setups. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileTextTest.kt | Adds tests for word-based truncation utility. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileStoreTest.kt | Adds tests for saving/activating/deactivating profiles. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileSecurityTest.kt | Adds tests for sanitization and size limiting. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileOwnershipStoreTest.kt | Adds tests for per-profile ownership persistence and aggregation. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileLocalCatalogManagerTest.kt | Adds tests for local catalog hydration and tag presence. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileImportManagerTest.kt | Adds tests for importing bundled rules and counting outcomes. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileAppManagerTest.kt | Adds tests for app summaries and preview construction. |
| app/src/test/java/com/celzero/bravedns/data/PowerProfileActivationPolicyTest.kt | Tests activation action resolution based on state/tunnel. |
| app/src/test/java/com/celzero/bravedns/data/ActivePowerProfileTest.kt | Adds JSON round-trip + parsing tests for active profiles. |
| app/src/test/java/com/celzero/bravedns/adapter/WgConfigAdapterTest.kt | Updates tests for adapter constructor signature changes. |
| app/src/test/java/com/celzero/bravedns/adapter/FirewallAppListAdapterTest.kt | Updates tests for adapter constructor signature changes. |
| app/src/main/res/menu/bottom_nav_menu.xml | Replaces Home nav item with Power nav item. |
| app/src/main/res/layout/view_power_profile_section_card.xml | Adds reusable section-card layout for Power profile pages. |
| app/src/main/res/layout/view_power_profile_app_item.xml | Adds layout for Power profile app entries. |
| app/src/main/res/layout/view_power_list_item_save_setup.xml | Adds Power list-row layout for “save setup”. |
| app/src/main/res/layout/view_power_list_item_logs.xml | Adds Power list-row layout for logs. |
| app/src/main/res/layout/view_power_list_item_firewall.xml | Adds Power list-row layout for firewall. |
| app/src/main/res/layout/view_power_list_item_discover_profiles.xml | Adds Power list-row layout for discovering profiles. |
| app/src/main/res/layout/view_power_list_item_dashboard.xml | Adds Power list-row layout for dashboard. |
| app/src/main/res/layout/view_power_list_item_configure.xml | Adds Power list-row layout for configure. |
| app/src/main/res/layout/view_power_list_item_apps.xml | Adds Power list-row layout for apps. |
| app/src/main/res/layout/view_power_list_item_active_profiles.xml | Adds Power list-row layout for active profiles. |
| app/src/main/res/layout/view_discover_profile_smooth_internet.xml | Adds discover-card layout for Smooth browsing profile. |
| app/src/main/res/layout/view_discover_profile_safe_beautiful.xml | Adds discover-card layout for Safe & Beautiful profile. |
| app/src/main/res/layout/view_discover_profile_parental_control.xml | Adds discover-card layout for Parental control profile. |
| app/src/main/res/layout/view_discover_profile_import.xml | Adds discover-card layout for importing profiles. |
| app/src/main/res/layout/view_discover_profile_focus.xml | Adds discover-card layout for Deep focus profile. |
| app/src/main/res/layout/view_discover_profile_exam.xml | Adds discover-card layout for Exam profile. |
| app/src/main/res/layout/view_discover_profile_app_horse.xml | Adds discover-card layout for App Horse profile. |
| app/src/main/res/layout/view_active_power_profile_item.xml | Adds generic card layout used for profile list entries. |
| app/src/main/res/layout/fragment_power.xml | Adds the main Power screen layout. |
| app/src/main/res/layout/fragment_power_profile_entries.xml | Adds layout for a profile’s entries preview page. |
| app/src/main/res/layout/fragment_power_profile_detail.xml | Adds layout for profile detail + section cards and actions. |
| app/src/main/res/layout/fragment_power_profile_apps.xml | Adds layout for profile apps page. |
| app/src/main/res/layout/fragment_discover_profiles.xml | Adds layout for Discover Profiles screen. |
| app/src/main/res/layout/fragment_active_profiles.xml | Adds layout for Active Profiles screen. |
| app/src/main/java/com/celzero/bravedns/service/RethinkBlocklistManager.kt | Adds RDNS fallback for local stamp/tag conversion. |
| app/src/main/java/com/celzero/bravedns/database/RethinkLocalFileTagRepository.kt | Adds DAO wrapper to fetch local tags by ids. |
| app/src/main/java/com/celzero/bravedns/database/RethinkLocalFileTagDao.kt | Adds query to fetch local tags by ids. |
| app/src/main/java/com/celzero/bravedns/database/CustomIpRepository.kt | Adds bulk insert and chunked delete helpers. |
| app/src/main/java/com/celzero/bravedns/database/CustomIpDao.kt | Adds bulk insert and UID+port+ipAddress delete query. |
| app/src/main/java/com/celzero/bravedns/database/CustomDomainRepository.kt | Adds bulk insert and chunked delete helper. |
| app/src/main/java/com/celzero/bravedns/database/CustomDomainDAO.kt | Adds bulk insert and UID+domains delete query. |
| app/src/main/java/com/celzero/bravedns/data/SavedPowerProfile.kt | Adds JSON-serializable “saved setup” model. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileText.kt | Adds word-truncation helper for UI descriptions. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileStore.kt | Adds SharedPreferences-backed store for saved/active profiles. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileSecurity.kt | Adds sanitization/limits for profile/artifact inputs. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfilePortableDocument.kt | Adds portable profile document parsing/exporting. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileOwnershipStore.kt | Adds per-profile owned-rule persistence + aggregation. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileLocalCatalogManager.kt | Adds local-catalog presence + hydration helper. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileDefinition.kt | Defines a catalog/display model for Power profiles. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileCurrentSetupManager.kt | Adds “save current setup as reusable profile” helper. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileCatalog.kt | Adds combined curated+imported catalog API. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileBlocklistPreviewManager.kt | Adds grouped preview of local-blocklist tag selections. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileArtifacts.kt | Adds artifact loading + exportable portable document assembly. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileAppModels.kt | Adds app-scoped rule models + firewall/status sanitizers. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileAppManager.kt | Adds app summary + preview builders for profiles. |
| app/src/main/java/com/celzero/bravedns/data/PowerProfileActivationPolicy.kt | Adds activation action resolution policy. |
| app/src/main/java/com/celzero/bravedns/data/ImportedPowerProfileStore.kt | Adds import/export persistence for portable profiles. |
| app/src/main/java/com/celzero/bravedns/data/CuratedPowerProfileCatalog.kt | Adds curated built-in Power profiles and metadata. |
| app/src/main/java/com/celzero/bravedns/data/BundledDomainProfileArtifact.kt | Adds parsing + sanitization wrapper for bundled artifacts. |
| app/src/main/java/com/celzero/bravedns/data/ActivePowerProfile.kt | Adds JSON-serializable “active profile” model. |
| app/src/main/assets/power/app-horse-profile.json | Adds bundled artifact data for the App Horse profile. |
| app/src/full/res/navigation/app_navigation.xml | Sets Power as start destination and adds Power-related fragments. |
| app/src/full/java/com/celzero/bravedns/ui/PowerDestinationPolicy.kt | Adds helper for bottom-nav visibility + menu mapping. |
| app/src/full/java/com/celzero/bravedns/ui/HomeScreenActivity.kt | Integrates Power start destination + bottom-nav policy behavior. |
| app/src/full/java/com/celzero/bravedns/ui/fragment/PowerProfileAppsFragment.kt | Adds UI to list apps contained in a profile and open preview. |
| app/src/full/java/com/celzero/bravedns/ui/fragment/DiscoverProfilesFragment.kt | Adds curated+imported discovery UI and import flow. |
| app/src/full/java/com/celzero/bravedns/ui/fragment/ActiveProfilesFragment.kt | Adds coverage/summary UI for active/saved profiles. |
| app/src/full/java/com/celzero/bravedns/ui/activity/PowerProfilePreviewUiPolicy.kt | Adds UI policy helpers for preview/read-only state. |
| app/src/full/java/com/celzero/bravedns/ui/activity/AppInfoActivity.kt | Adds Power-profile preview mode for app details. |
| app/src/full/java/com/celzero/bravedns/RethinkDnsApplication.kt | Triggers reconciliation of active profiles during app startup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Kotlin daemon JVM args for more memory | ||
| kotlin.daemon.jvmargs=-Xmx4048m -Dfile.encoding=UTF-8 |
There was a problem hiding this comment.
kotlin.daemon.jvmargs uses -Xmx4048m, which looks like a typo / non-standard heap size (typically 4096m). If this is meant to be 4 GiB, consider correcting to 4096m to avoid confusion and accidental misconfiguration.
| val ipRules = | ||
| app.ipRules | ||
| .mapNotNull { sanitizeAppIpRule(it) } | ||
| .distinctBy { "${it.ipAddress}|${it.port}|${it.protocol}|${it.status}|${it.wildcard}" } | ||
| .take(MAX_APP_IP_RULES) |
There was a problem hiding this comment.
sanitizeApps() de-dupes ipRules without considering fields like proxyId, proxyCC, or isActive. This can collapse distinct rules into one entry and silently drop proxy configuration / activation state. Include all rule-shaping fields in the de-dupe key (similar to domainRules) to avoid data loss.
| val appJson = appsJson.optJSONObject(index) ?: continue | ||
| val packageName = appJson.optString("packageName", "").trim() | ||
| val appName = appJson.optString("appName", "").trim() | ||
| if (packageName.isEmpty() || appName.isEmpty()) continue | ||
| val domainRules = |
There was a problem hiding this comment.
fromJson() skips app entries when appName is missing/blank (if (packageName.isEmpty() || appName.isEmpty()) continue). This conflicts with PowerProfileSecurity.sanitizeApps(), which already falls back to packageName when appName is blank, and it reduces format forward-compatibility. Consider only requiring packageName here and letting the sanitizer fill in the display name.
| val appJson = appsJson.optJSONObject(index) ?: continue | ||
| val packageName = appJson.optString("packageName", "").trim() | ||
| val appName = appJson.optString("appName", "").trim() | ||
| if (packageName.isEmpty() || appName.isEmpty()) continue |
There was a problem hiding this comment.
Artifact parsing currently drops apps[] entries when appName is blank (if (packageName.isEmpty() || appName.isEmpty()) continue). Since later sanitization can already supply a fallback name, consider only requiring packageName so artifacts remain resilient to missing display names.
| if (packageName.isEmpty() || appName.isEmpty()) continue | |
| if (packageName.isEmpty()) continue |
| val first = PowerProfileStore.saveCurrentSetup(context, appConfig) | ||
| Thread.sleep(2) | ||
| val second = PowerProfileStore.saveCurrentSetup(context, appConfig) | ||
|
|
There was a problem hiding this comment.
This test relies on Thread.sleep(2) to force ordering based on System.currentTimeMillis(), which can be flaky on slow/virtualized CI runners. Consider injecting a clock/time provider into PowerProfileStore for tests or allowing saveCurrentSetup() to accept a timestamp in test builds so ordering can be deterministic without sleeping.
| <Button | ||
| android:id="@+id/fp_pause_icon" | ||
| android:layout_width="60dp" | ||
| android:layout_height="48dp" | ||
| android:layout_gravity="start" |
There was a problem hiding this comment.
fp_pause_icon is a Button with no text or contentDescription. For accessibility (screen readers) and UI semantics, consider using an ImageButton (or setting an appropriate android:contentDescription) for icon-only tappable controls. The same applies to the other icon-only button in this header.
| "artifactUrl": "https://raw.githubusercontent.com/anjani-1/rethink-again/codex/power-page-foundation/community-knowledge/profiles/app-horse/app-horse.power-profile.v1.json", | ||
| "homepageUrl": "https://github.com/anjani-1/rethink-again/tree/codex/power-page-foundation/community-knowledge/profiles/app-horse", | ||
| "readmeUrl": "https://github.com/anjani-1/rethink-again/blob/codex/power-page-foundation/community-knowledge/README.md", |
There was a problem hiding this comment.
The registry/example URLs are hard-coded to a personal fork + feature branch (anjani-1/.../codex/power-page-foundation). Once this PR is merged, those URLs will likely 404. Consider switching to stable URLs (eg, main branch in the canonical repo) or using relative links/placeholders in this sample registry.
| private fun sanitizeDomain(value: String): String? { | ||
| val normalized = value.trim().trimEnd('.').lowercase() | ||
| if (normalized.isEmpty() || normalized.length > 253) return null | ||
| if (!domainRegex.matches(normalized)) return null | ||
| if (normalized.contains("..")) return null |
There was a problem hiding this comment.
sanitizeDomain() currently accepts labels that start/end with '-' (eg, -bad.example) because of the permissive regex. These are not valid hostnames and may later cause rule insertion/behavior issues. Consider tightening validation (label rules + max label length) or delegating to existing domain validation logic used elsewhere in the app.
| private fun profileFile(context: Context, profileId: String): File { | ||
| return File(profileDirectory(context), "$profileId.json") | ||
| } |
There was a problem hiding this comment.
profileFile() uses the raw profileId to build a filename. If a caller ever passes an unsanitized id (eg, containing path separators), this can lead to directory traversal / clobbering other files under filesDir. Consider sanitizing profileId (similar to ImportedPowerProfileStore.sanitizeFileName) or enforcing the same strict id regex before writing.
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| theme.applyStyle(Themes.getCurrentTheme(isDarkThemeOn(), persistentState.theme), true) | ||
| super.onCreate(savedInstanceState) |
There was a problem hiding this comment.
AppInfoActivity no longer calls handleFrostEffectIfNeeded(persistentState.theme) in onCreate(), while most other activities still do. This can cause inconsistent UI theming/blur behavior for the App Details screen. Consider restoring the call for consistency with the rest of the app.
| super.onCreate(savedInstanceState) | |
| super.onCreate(savedInstanceState) | |
| handleFrostEffectIfNeeded(persistentState.theme) |
No description provided.