Loading cardinal-android/app/src/main/java/earth/maps/cardinal/data/room/AppDatabase.kt +13 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ import earth.maps.cardinal.data.DownloadStatusConverter @Database( entities = [OfflineArea::class, RoutingProfile::class, DownloadedTile::class, SavedList::class, SavedPlace::class, ListItem::class, RecentSearch::class], version = 13, version = 14, exportSchema = false ) @TypeConverters(TileTypeConverter::class, DownloadStatusConverter::class, ItemTypeConverter::class) Loading Loading @@ -232,6 +232,17 @@ abstract class AppDatabase : RoomDatabase() { } } private val MIGRATION_13_14 = object : Migration(13, 14) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL( "ALTER TABLE list_items ADD COLUMN placementUpdatedAt INTEGER NOT NULL DEFAULT 0" ) db.execSQL( "UPDATE list_items SET placementUpdatedAt = addedAt WHERE placementUpdatedAt = 0" ) } } fun getDatabase(context: Context): AppDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( Loading @@ -248,6 +259,7 @@ abstract class AppDatabase : RoomDatabase() { MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13, MIGRATION_13_14, ).build() INSTANCE = instance instance Loading cardinal-android/app/src/main/java/earth/maps/cardinal/data/room/ListItem.kt +2 −1 Original line number Diff line number Diff line Loading @@ -43,5 +43,6 @@ data class ListItem( val itemId: String, // ID of the place or nested list val itemType: ItemType, // Enum: PLACE or LIST val position: Int, // For ordering items within a list val addedAt: Long val addedAt: Long, val placementUpdatedAt: Long = addedAt ) cardinal-android/app/src/main/java/earth/maps/cardinal/data/room/ListItemDao.kt +11 −5 Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ interface ListItemDao { @Query( """ UPDATE list_items SET position = :newPosition SET position = :newPosition, placementUpdatedAt = :placementUpdatedAt WHERE listId = :listId AND itemId = :itemId AND itemType = :itemType """ ) Loading @@ -51,7 +52,8 @@ interface ListItemDao { listId: String, itemId: String, itemType: ItemType, newPosition: Int newPosition: Int, placementUpdatedAt: Long = System.currentTimeMillis() ) @Query( Loading Loading @@ -79,22 +81,26 @@ interface ListItemDao { @Query( """ UPDATE list_items SET listId = :newListId, position = :newPosition SET listId = :newListId, position = :newPosition, placementUpdatedAt = :placementUpdatedAt WHERE itemId = :itemId """ ) suspend fun moveItem( itemId: String, newListId: String, newPosition: Int newPosition: Int, placementUpdatedAt: Long = System.currentTimeMillis() ) // Reorder all items when positions change @Transaction suspend fun reorderItems(listId: String, items: List<ListItem>) { val placementUpdatedAt = System.currentTimeMillis() clearList(listId) items.forEachIndexed { index, item -> insertItem(item.copy(position = index)) insertItem(item.copy(position = index, placementUpdatedAt = placementUpdatedAt)) } } Loading cardinal-android/app/src/main/java/earth/maps/cardinal/data/sync/FavoritesLocalDataSource.kt +3 −2 Original line number Diff line number Diff line Loading @@ -123,8 +123,9 @@ class FavoritesLocalDataSource @Inject constructor( } private fun shouldApplyRemoteListItem(remoteItem: ListItem, localItems: List<ListItem>): Boolean { val newestLocalItem = localItems.maxByOrNull { it.addedAt } return newestLocalItem == null || remoteItem.addedAt > newestLocalItem.addedAt val newestLocalItem = localItems.maxByOrNull { it.placementUpdatedAt } return newestLocalItem == null || remoteItem.placementUpdatedAt > newestLocalItem.placementUpdatedAt } private suspend fun ensureRootList(payload: FavoritesSyncPayloadDto): SavedList { Loading cardinal-android/app/src/main/java/earth/maps/cardinal/data/sync/FavoritesSyncDtos.kt +2 −1 Original line number Diff line number Diff line Loading @@ -76,5 +76,6 @@ data class ListItemDto( val itemId: String, val itemType: String, val position: Int, val addedAt: Long val addedAt: Long, val placementUpdatedAt: Long = addedAt ) Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/data/room/AppDatabase.kt +13 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ import earth.maps.cardinal.data.DownloadStatusConverter @Database( entities = [OfflineArea::class, RoutingProfile::class, DownloadedTile::class, SavedList::class, SavedPlace::class, ListItem::class, RecentSearch::class], version = 13, version = 14, exportSchema = false ) @TypeConverters(TileTypeConverter::class, DownloadStatusConverter::class, ItemTypeConverter::class) Loading Loading @@ -232,6 +232,17 @@ abstract class AppDatabase : RoomDatabase() { } } private val MIGRATION_13_14 = object : Migration(13, 14) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL( "ALTER TABLE list_items ADD COLUMN placementUpdatedAt INTEGER NOT NULL DEFAULT 0" ) db.execSQL( "UPDATE list_items SET placementUpdatedAt = addedAt WHERE placementUpdatedAt = 0" ) } } fun getDatabase(context: Context): AppDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( Loading @@ -248,6 +259,7 @@ abstract class AppDatabase : RoomDatabase() { MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13, MIGRATION_13_14, ).build() INSTANCE = instance instance Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/data/room/ListItem.kt +2 −1 Original line number Diff line number Diff line Loading @@ -43,5 +43,6 @@ data class ListItem( val itemId: String, // ID of the place or nested list val itemType: ItemType, // Enum: PLACE or LIST val position: Int, // For ordering items within a list val addedAt: Long val addedAt: Long, val placementUpdatedAt: Long = addedAt )
cardinal-android/app/src/main/java/earth/maps/cardinal/data/room/ListItemDao.kt +11 −5 Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ interface ListItemDao { @Query( """ UPDATE list_items SET position = :newPosition SET position = :newPosition, placementUpdatedAt = :placementUpdatedAt WHERE listId = :listId AND itemId = :itemId AND itemType = :itemType """ ) Loading @@ -51,7 +52,8 @@ interface ListItemDao { listId: String, itemId: String, itemType: ItemType, newPosition: Int newPosition: Int, placementUpdatedAt: Long = System.currentTimeMillis() ) @Query( Loading Loading @@ -79,22 +81,26 @@ interface ListItemDao { @Query( """ UPDATE list_items SET listId = :newListId, position = :newPosition SET listId = :newListId, position = :newPosition, placementUpdatedAt = :placementUpdatedAt WHERE itemId = :itemId """ ) suspend fun moveItem( itemId: String, newListId: String, newPosition: Int newPosition: Int, placementUpdatedAt: Long = System.currentTimeMillis() ) // Reorder all items when positions change @Transaction suspend fun reorderItems(listId: String, items: List<ListItem>) { val placementUpdatedAt = System.currentTimeMillis() clearList(listId) items.forEachIndexed { index, item -> insertItem(item.copy(position = index)) insertItem(item.copy(position = index, placementUpdatedAt = placementUpdatedAt)) } } Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/data/sync/FavoritesLocalDataSource.kt +3 −2 Original line number Diff line number Diff line Loading @@ -123,8 +123,9 @@ class FavoritesLocalDataSource @Inject constructor( } private fun shouldApplyRemoteListItem(remoteItem: ListItem, localItems: List<ListItem>): Boolean { val newestLocalItem = localItems.maxByOrNull { it.addedAt } return newestLocalItem == null || remoteItem.addedAt > newestLocalItem.addedAt val newestLocalItem = localItems.maxByOrNull { it.placementUpdatedAt } return newestLocalItem == null || remoteItem.placementUpdatedAt > newestLocalItem.placementUpdatedAt } private suspend fun ensureRootList(payload: FavoritesSyncPayloadDto): SavedList { Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/data/sync/FavoritesSyncDtos.kt +2 −1 Original line number Diff line number Diff line Loading @@ -76,5 +76,6 @@ data class ListItemDto( val itemId: String, val itemType: String, val position: Int, val addedAt: Long val addedAt: Long, val placementUpdatedAt: Long = addedAt )