Skip to content

Commit 0f441c8

Browse files
committed
完善收藏专辑的功能
1 parent e27386f commit 0f441c8

10 files changed

Lines changed: 378 additions & 28 deletions

File tree

app/src/main/java/com/ljyh/mei/data/model/AlbumList.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.ljyh.mei.data.model
22

33
import com.google.gson.annotations.SerializedName
4+
import com.ljyh.mei.data.model.room.AlbumEntity
5+
import com.ljyh.mei.data.model.room.ArtistEntity
46
import com.ljyh.mei.ui.model.Album
57

68
data class UserAlbumList(
@@ -83,4 +85,19 @@ fun UserAlbumList.Data.toAlbum(): Album {
8385
name = it.name
8486
)
8587
})
88+
}
89+
90+
91+
fun UserAlbumList.Data.toAlbumEntity(): Pair<AlbumEntity, List<ArtistEntity>>{
92+
return AlbumEntity(
93+
albumId = id,
94+
name = name,
95+
cover = picUrl,
96+
publishTime = subTime,
97+
songCount = size
98+
) to artists.map { ArtistEntity(
99+
artistId = id,
100+
name= name,
101+
avatarUrl = null
102+
) }
86103
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.ljyh.mei.data.model.room
2+
3+
import androidx.room.Embedded
4+
import androidx.room.Entity
5+
import androidx.room.Index
6+
import androidx.room.Junction
7+
import androidx.room.PrimaryKey
8+
import androidx.room.Relation
9+
10+
11+
@Entity(
12+
tableName = "album_artist_cross_ref",
13+
primaryKeys = ["albumId", "artistId"],
14+
indices = [
15+
Index("albumId"),
16+
Index("artistId")
17+
]
18+
)
19+
data class AlbumArtistCrossRef(
20+
val albumId: Long,
21+
val artistId: Long
22+
)
23+
24+
data class AlbumWithArtists(
25+
@Embedded val album: AlbumEntity,
26+
@Relation(
27+
parentColumn = "albumId",
28+
entityColumn = "artistId",
29+
associateBy = Junction(AlbumArtistCrossRef::class)
30+
)
31+
val artists: List<ArtistEntity>
32+
)
33+
34+
35+
36+
@Entity(tableName = "albums")
37+
data class AlbumEntity(
38+
@PrimaryKey val albumId: Long,
39+
val name: String,
40+
val cover: String,
41+
val publishTime:Long,
42+
val songCount: Int
43+
)
44+
45+
@Entity(tableName = "artists")
46+
data class ArtistEntity(
47+
@PrimaryKey val artistId: Long,
48+
val name: String,
49+
val avatarUrl: String?
50+
)

app/src/main/java/com/ljyh/mei/di/AppModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ object AppModule {
5252
return HistoryRepository(database.historyDao(), database.songDao())
5353
}
5454

55+
@Provides
56+
fun provideAlbumsDao(db: AppDatabase): AlbumsRepository = AlbumsRepository(db.AlbumsDao())
57+
5558
// 单例gson
5659
@Provides
5760
@Singleton

app/src/main/java/com/ljyh/mei/di/RoomDao.kt

Lines changed: 172 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ package com.ljyh.mei.di
33
import android.content.Context
44
import androidx.room.Dao
55
import androidx.room.Database
6+
import androidx.room.Delete
67
import androidx.room.Insert
78
import androidx.room.OnConflictStrategy
89
import androidx.room.Query
910
import androidx.room.Room
1011
import androidx.room.RoomDatabase
1112
import androidx.room.Transaction
13+
import com.ljyh.mei.data.model.room.AlbumArtistCrossRef
14+
import com.ljyh.mei.data.model.room.AlbumEntity
15+
import com.ljyh.mei.data.model.room.AlbumWithArtists
16+
import com.ljyh.mei.data.model.room.ArtistEntity
1217
import com.ljyh.mei.data.model.room.CacheColor
1318
import com.ljyh.mei.data.model.room.HistoryItem
1419
import com.ljyh.mei.data.model.room.Like
@@ -73,7 +78,7 @@ interface PlaylistDao {
7378
suspend fun insertPlaylists(playlists: List<Playlist>)
7479

7580
@Query("DELETE FROM playlist where id=:id")
76-
suspend fun deletePlaylistById(id:String)
81+
suspend fun deletePlaylistById(id: String)
7782
}
7883

7984
@Dao
@@ -129,9 +134,172 @@ interface HistoryDao {
129134
suspend fun deleteHistoryBySongId(songId: String)
130135
}
131136

137+
@Dao
138+
interface AlbumsDao {
139+
@Transaction
140+
@Query("SELECT * FROM albums WHERE albumId = :id")
141+
suspend fun getAlbumWithArtists(id: Long): AlbumWithArtists
142+
143+
@Transaction
144+
@Query(
145+
"""
146+
SELECT * FROM albums
147+
INNER JOIN album_artist_cross_ref
148+
ON albums.albumId = album_artist_cross_ref.albumId
149+
WHERE album_artist_cross_ref.artistId = :artistId"""
150+
)
151+
suspend fun getAlbumsByArtist(artistId: Long): List<AlbumEntity>
152+
153+
154+
155+
156+
@Transaction
157+
suspend fun insertAlbumWithArtists(
158+
album: AlbumEntity,
159+
artists: List<ArtistEntity>
160+
) {
161+
// 1. 插入 album
162+
insertAlbum(album)
163+
164+
// 2. 插入 artists(已存在的会被忽略)
165+
insertArtists(artists)
166+
167+
// 3. 建立关联
168+
val refs = artists.map {
169+
AlbumArtistCrossRef(
170+
albumId = album.albumId,
171+
artistId = it.artistId
172+
)
173+
}
174+
insertAlbumArtistRefs(refs)
175+
}
176+
177+
// --- 基础方法 ---
178+
@Insert(onConflict = OnConflictStrategy.REPLACE)
179+
suspend fun insertAlbum(album: AlbumEntity)
180+
181+
@Insert(onConflict = OnConflictStrategy.IGNORE)
182+
suspend fun insertArtists(artists: List<ArtistEntity>)
183+
184+
@Insert(onConflict = OnConflictStrategy.IGNORE)
185+
suspend fun insertAlbumArtistRefs(
186+
refs: List<AlbumArtistCrossRef>
187+
)
188+
@Query("""
189+
SELECT EXISTS(
190+
SELECT 1 FROM albums WHERE albumId = :albumId
191+
)
192+
""")
193+
suspend fun existsAlbum(albumId: Long): Boolean
194+
195+
/**
196+
* 删除指定ID的专辑及其关联关系
197+
* 注意:这会删除专辑,但不会删除关联的艺术家(其他专辑可能还在使用)
198+
*/
199+
@Transaction
200+
suspend fun deleteAlbumById(albumId: Long) {
201+
// 1. 先删除关联关系
202+
deleteAlbumArtistRefsByAlbumId(albumId)
203+
204+
// 2. 再删除专辑
205+
deleteAlbum(albumId)
206+
}
207+
208+
/**
209+
* 批量删除多个专辑及其关联关系
210+
*/
211+
@Transaction
212+
suspend fun deleteAlbumsByIds(albumIds: List<Long>) {
213+
if (albumIds.isEmpty()) return
214+
215+
// 1. 删除关联关系
216+
deleteAlbumArtistRefsByAlbumIds(albumIds)
217+
218+
// 2. 删除专辑
219+
deleteAlbums(albumIds)
220+
}
221+
222+
/**
223+
* 删除指定艺术家参与的所有专辑关联关系
224+
* 注意:这会移除该艺术家与专辑的关联,但不会删除专辑本身
225+
*/
226+
suspend fun deleteArtistFromAllAlbums(artistId: Long) {
227+
deleteAlbumArtistRefsByArtistId(artistId)
228+
}
229+
230+
/**
231+
* 删除孤立的艺术家(没有被任何专辑引用的艺术家)
232+
* 用于清理不再使用的艺术家数据
233+
*/
234+
@Transaction
235+
suspend fun deleteOrphanedArtists() {
236+
// 找到没有关联的艺术家
237+
val orphanedArtistIds = getOrphanedArtistIds()
238+
if (orphanedArtistIds.isNotEmpty()) {
239+
deleteArtistsByIds(orphanedArtistIds)
240+
}
241+
}
242+
243+
244+
@Delete
245+
suspend fun deleteAlbum(album: AlbumEntity)
246+
247+
@Query("DELETE FROM albums WHERE albumId = :albumId")
248+
suspend fun deleteAlbum(albumId: Long)
249+
250+
@Query("DELETE FROM albums WHERE albumId IN (:albumIds)")
251+
suspend fun deleteAlbums(albumIds: List<Long>)
252+
253+
@Delete
254+
suspend fun deleteArtist(artist: ArtistEntity)
255+
256+
@Query("DELETE FROM artists WHERE artistId = :artistId")
257+
suspend fun deleteArtist(artistId: Long)
258+
259+
@Query("DELETE FROM artists WHERE artistId IN (:artistIds)")
260+
suspend fun deleteArtistsByIds(artistIds: List<Long>)
261+
262+
@Delete
263+
suspend fun deleteAlbumArtistRef(ref: AlbumArtistCrossRef)
264+
265+
@Query("DELETE FROM album_artist_cross_ref WHERE albumId = :albumId")
266+
suspend fun deleteAlbumArtistRefsByAlbumId(albumId: Long)
267+
268+
@Query("DELETE FROM album_artist_cross_ref WHERE albumId IN (:albumIds)")
269+
suspend fun deleteAlbumArtistRefsByAlbumIds(albumIds: List<Long>)
270+
271+
@Query("DELETE FROM album_artist_cross_ref WHERE artistId = :artistId")
272+
suspend fun deleteAlbumArtistRefsByArtistId(artistId: Long)
273+
274+
// --- 查询辅助方法 ---
275+
276+
/**
277+
* 查找孤立的艺术家ID(没有被任何专辑引用的艺术家)
278+
*/
279+
@Query("""
280+
SELECT artistId FROM artists
281+
WHERE artistId NOT IN (
282+
SELECT DISTINCT artistId FROM album_artist_cross_ref
283+
)
284+
""")
285+
suspend fun getOrphanedArtistIds(): List<Long>
286+
287+
/**
288+
* 检查艺术家是否被任何专辑使用
289+
*/
290+
@Query("""
291+
SELECT EXISTS(
292+
SELECT 1 FROM album_artist_cross_ref WHERE artistId = :artistId
293+
)
294+
""")
295+
suspend fun isArtistUsed(artistId: Long): Boolean
296+
297+
}
298+
299+
132300
@Database(
133-
entities = [CacheColor::class, Song::class, Like::class, QQSong::class, Playlist::class, PlaybackHistory::class],
134-
version = 7
301+
entities = [CacheColor::class, Song::class, Like::class, QQSong::class, Playlist::class, PlaybackHistory::class, AlbumEntity::class, ArtistEntity::class, AlbumArtistCrossRef::class],
302+
version = 8
135303
)
136304
abstract class AppDatabase : RoomDatabase() {
137305
abstract fun colorDao(): ColorDao
@@ -140,6 +308,7 @@ abstract class AppDatabase : RoomDatabase() {
140308
abstract fun qqSongDao(): QQSongDao
141309
abstract fun playlistDao(): PlaylistDao
142310
abstract fun historyDao(): HistoryDao
311+
abstract fun AlbumsDao(): AlbumsDao
143312

144313
companion object {
145314
@Volatile

0 commit comments

Comments
 (0)