Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Build, test, and lint

- Setup: `git submodule update --init --recursive`, `local.properties` with `sdk.dir=...`, and `app/google-services.json` from `google-services.json.debug`.
- Setup: initialize the `lib` submodule with `git submodule update --init --recursive`, create `local.properties` with `sdk.dir=...`, and provide debug Google Services config as `app/google-services.json` copied from `google-services.json.debug`.
- In task worktrees, copy ignored local build inputs from the main checkout before building: `local.properties`, `app/google-services.json` when present, and any other required local/private files. Keep these files untracked and do not print their contents.
- Commands:
- Build debug APK: `./gradlew :app:assembleDebug`
Expand All @@ -11,7 +11,7 @@
- Run one test class/method: `./gradlew :app:testDebugUnitTest --tests "com.anod.appwatcher.watchlist.WatchListPagingSourceTest"`
- Android lint: `./gradlew :app:lintDebug`
- ktlint checks: `./gradlew ktlintCheck`
- On Windows, use `.\gradlew.bat` instead of `./gradlew`.
- On Windows, use `.\gradlew.bat` instead of `./gradlew`, and run it from the repository/worktree root.
- CI runs JDK 21, writes `app/google-services.json` from secrets, initializes submodules, and runs `./gradlew testDebugUnitTest`; test failures are `continue-on-error`, so inspect uploaded reports.

## Crashlytics investigation
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ build
.DS_Store
*.iml
/captures
/wt/

app/google-services.json
/firebase-crashreporting.json
/src/main/res/raw/third_party_license_metadata
/src/main/res/raw/third_party_licenses
.kotlin
/wt/
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ android {
applicationId = "com.anod.appwatcher"
minSdk = 31
targetSdk = 36
versionCode = 17005
versionCode = 17006
versionName = "1.7.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ fun InstalledListScreen(
enablePullToRefresh = screenState.enablePullToRefresh,
selection = screenState.selection,
selectionMode = screenState.selectionMode,
onEvent = { event -> onEvent(InstalledListEvent.ListEvent(event)) },
listContext = "installed"
onEvent = { event -> onEvent(InstalledListEvent.ListEvent(event)) }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ fun TagWatchListScreen(screenState: WatchListSharedState, listPagerFactory: (fil
subtitle = subtitle,
onEvent = onEvent,
)
},
listContext = "tag-${screenState.tag.id}",
}
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,7 @@ fun MainScreen(
}
},
)
},
listContext = "main",
}
)
}

Expand Down
16 changes: 11 additions & 5 deletions app/src/main/java/com/anod/appwatcher/watchlist/Section.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ sealed interface SectionItem {

@Immutable
class Header(val type: SectionHeader) : SectionItem {
override val sectionKey = "header:${hashCode()}"
override val sectionKey = when (type) {
SectionHeader.New -> "header:new"
SectionHeader.RecentlyDiscovered -> "header:recently-discovered"
SectionHeader.Watching -> "header:watching"
SectionHeader.RecentlyInstalled -> "header:recently-installed"
SectionHeader.OnDevice -> "header:on-device"
}
override val contentType = "Header"
override fun hashCode(): Int = hashCodeOf("SectionItem.Header", type)

Expand All @@ -33,7 +39,7 @@ sealed interface SectionItem {
}

object Recent : SectionItem {
override val sectionKey = "recent:${hashCode()}"
override val sectionKey = "recent"
override val contentType = "Recent"
override fun hashCode(): Int = hashCodeOf("SectionItem.Recent")

Expand All @@ -44,7 +50,7 @@ sealed interface SectionItem {
}

object Empty : SectionItem {
override val sectionKey = "empty:${hashCode()}"
override val sectionKey = "empty"
override val contentType = "Empty"
override fun hashCode(): Int = hashCodeOf("SectionItem.Empty")

Expand All @@ -56,7 +62,7 @@ sealed interface SectionItem {

@Immutable
class App(val appListItem: AppListItem, val isLocal: Boolean, val packageInfo: InstalledApps.Info) : SectionItem {
override val sectionKey = "app-${appListItem.app.rowId}:${hashCode()}"
override val sectionKey = "app-${appListItem.app.rowId}-${appListItem.app.packageName}"
override val contentType = "App"
val changesHtml: String = appListItem.cleanChangeHtml()

Expand All @@ -70,7 +76,7 @@ sealed interface SectionItem {

@Immutable
class OnDevice(val appListItem: AppListItem, var showSelection: Boolean, val packageInfo: InstalledApps.Info) : SectionItem {
override val sectionKey = "ondevice-${appListItem.app.rowId}:${hashCode()}"
override val sectionKey = "ondevice-${appListItem.app.packageName}"
override val contentType = "OnDevice"
val changesHtml: String = appListItem.cleanChangeHtml()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ fun WatchListPage(
items: LazyPagingItems<SectionItem>,
isRefreshing: Boolean,
enablePullToRefresh: Boolean,
listContext: String,
onEvent: (WatchListEvent) -> Unit,
selection: SelectionState = SelectionState(),
selectionMode: Boolean = false,
Expand All @@ -124,7 +123,6 @@ fun WatchListPage(
WatchList(
items = items,
onEvent = onEvent,
listContext = listContext,
recentlyInstalledApps = recentlyInstalledApps,
selection = selection,
selectionMode = selectionMode
Expand All @@ -141,13 +139,11 @@ fun WatchListPage(
fun WatchList(
items: LazyPagingItems<SectionItem>,
onEvent: (WatchListEvent) -> Unit,
listContext: String,
recentlyInstalledApps: ImmutableList<App>? = null,
selection: SelectionState = SelectionState(),
selectionMode: Boolean = false,
) {
val isEmpty = items.loadState.source.refresh is LoadState.NotLoading && items.itemCount < 1
val recentlyInstalledAppsHashCode = remember(recentlyInstalledApps) { recentlyInstalledApps?.hashCode() ?: 0 }
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = WindowInsets.navigationBars.asPaddingValues()
Expand All @@ -160,10 +156,7 @@ fun WatchList(
items(
count = items.itemCount,
key = items.itemKey {
when (it) {
is SectionItem.Recent -> "$listContext-${it.sectionKey}-$recentlyInstalledAppsHashCode"
else -> "$listContext-${it.sectionKey}"
}
it.sectionKey
},
contentType = items.itemContentType { it.contentType }
) { index ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ fun WatchListScreen(
listPagerFactory: (filterId: Int, tag: Tag) -> WatchListPagerFactory,
onEvent: (WatchListEvent) -> Unit,
topBarContent: @Composable (subtitle: String?, filterId: Int) -> Unit,
listContext: String
) {
var subtitle: String? by remember { mutableStateOf(null) }
val filterPagesTitles = listOf(
Expand Down Expand Up @@ -80,8 +79,7 @@ fun WatchListScreen(
RefreshKey(
titleFilter = screenState.titleFilter,
tagAppsChange = screenState.tagAppsChange,
sortId = screenState.sortId,
dbAppsChange = screenState.dbAppsChange
sortId = screenState.sortId
)
}

Expand All @@ -96,15 +94,12 @@ fun WatchListScreen(
}
}

val pageListContext = "$listContext-rr:${screenState.refreshRequest}-f:$filterId-rk:$refreshKey"

WatchListPage(
items = items,
isRefreshing = screenState.syncProgress?.isRefreshing == true,
enablePullToRefresh = screenState.enablePullToRefresh,
onEvent = onEvent,
recentlyInstalledApps = screenState.recentlyInstalledApps,
listContext = pageListContext
recentlyInstalledApps = screenState.recentlyInstalledApps
)
}
}
Expand All @@ -123,6 +118,6 @@ fun WatchListScreen(
}
}

data class RefreshKey(val titleFilter: String, val sortId: Int, val tagAppsChange: Int, val dbAppsChange: Int) {
override fun toString() = "$titleFilter-$sortId-$tagAppsChange-$dbAppsChange"
data class RefreshKey(val titleFilter: String, val sortId: Int, val tagAppsChange: Int) {
override fun toString() = "$titleFilter-$sortId-$tagAppsChange"
}
Loading
Loading