Skip to content

Commit 3b0fc10

Browse files
committed
feat: Implement functionality of the photolibrary module
1 parent 8fcab62 commit 3b0fc10

File tree

17 files changed

+568
-119
lines changed

17 files changed

+568
-119
lines changed

build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
3636
add("androidTestImplementation", kotlin("test"))
3737
add("androidTestImplementation", project(":core:testing"))
3838

39+
// Paging 3
40+
add("implementation", libs.findLibrary("paging-runtime").get())
41+
add("implementation", libs.findLibrary("paging-compose").get())
42+
add("testImplementation", libs.findLibrary("paging-common").get())
43+
3944
// Timber
4045
add("implementation", libs.findLibrary("timber").get())
4146
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.wei.picquest.core.data.model
2+
3+
import com.wei.picquest.core.network.model.NetworkImageDetail
4+
5+
data class ImageDetail(
6+
val id: Int,
7+
val pageURL: String,
8+
val type: String,
9+
val tags: String,
10+
val previewURL: String,
11+
val previewWidth: Int,
12+
val previewHeight: Int,
13+
val webformatURL: String,
14+
val webformatWidth: Int,
15+
val webformatHeight: Int,
16+
val largeImageURL: String,
17+
val imageWidth: Int,
18+
val imageHeight: Int,
19+
val imageSize: Long,
20+
val views: Int,
21+
val downloads: Int,
22+
val likes: Int,
23+
val comments: Int,
24+
val userId: Int,
25+
val user: String,
26+
val userImageURL: String,
27+
) {
28+
val aspectRatio get() = imageWidth.toFloat() / imageHeight.toFloat()
29+
}
30+
31+
fun NetworkImageDetail.asExternalModel() = ImageDetail(
32+
id = this.id,
33+
pageURL = this.pageURL,
34+
type = this.type,
35+
tags = this.tags,
36+
previewURL = this.previewURL,
37+
previewWidth = this.previewWidth,
38+
previewHeight = this.previewHeight,
39+
webformatURL = this.webformatURL,
40+
webformatWidth = this.webformatWidth,
41+
webformatHeight = this.webformatHeight,
42+
largeImageURL = this.largeImageURL,
43+
imageWidth = this.imageWidth,
44+
imageHeight = this.imageHeight,
45+
imageSize = this.imageSize,
46+
views = this.views,
47+
downloads = this.downloads,
48+
likes = this.likes,
49+
comments = this.comments,
50+
userId = this.userId,
51+
user = this.user,
52+
userImageURL = this.userImageURL,
53+
)

core/data/src/main/java/com/wei/picquest/core/data/model/SearchImages.kt

Lines changed: 0 additions & 63 deletions
This file was deleted.
Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,31 @@
11
package com.wei.picquest.core.data.repository
22

3-
import com.wei.picquest.core.network.Dispatcher
4-
import com.wei.picquest.core.network.PqDispatchers
3+
import androidx.paging.Pager
4+
import androidx.paging.PagingConfig
5+
import androidx.paging.PagingData
6+
import androidx.paging.map
7+
import com.wei.picquest.core.data.model.ImageDetail
8+
import com.wei.picquest.core.data.model.asExternalModel
59
import com.wei.picquest.core.network.PqNetworkDataSource
6-
import com.wei.picquest.core.network.model.NetworkSearchImages
7-
import kotlinx.coroutines.CoroutineDispatcher
10+
import com.wei.picquest.core.network.pagingsource.PixabayPagingSource
811
import kotlinx.coroutines.flow.Flow
9-
import kotlinx.coroutines.flow.flow
10-
import kotlinx.coroutines.withContext
12+
import kotlinx.coroutines.flow.map
1113
import javax.inject.Inject
1214

13-
/**
14-
* Implementation of the [SearchImagesRepository].
15-
* @param ioDispatcher 用於執行 IO 相關操作的 CoroutineDispatcher。
16-
* @param network 數據源的網路接口。
17-
*/
1815
class DefaultSearchImagesRepository @Inject constructor(
19-
@Dispatcher(PqDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
20-
private val network: PqNetworkDataSource,
16+
private val pqNetworkDataSource: PqNetworkDataSource,
2117
) : SearchImagesRepository {
2218

23-
/**
24-
* @param query。A URL encoded search term. If omitted, all images are returned. This value may not exceed 100 characters.
25-
* Example: "yellow+flower"
26-
* @return 一個 Flow,內容為 Search Images 的數據。
27-
*/
28-
override suspend fun getSearchImages(
29-
query: String,
30-
): Flow<NetworkSearchImages> = withContext(ioDispatcher) {
31-
flow {
32-
emit(network.searchImages(query))
19+
override suspend fun getSearchImages(query: String): Flow<PagingData<ImageDetail>> {
20+
return Pager(
21+
config = PagingConfig(
22+
pageSize = 20,
23+
prefetchDistance = 5,
24+
enablePlaceholders = false,
25+
),
26+
pagingSourceFactory = { PixabayPagingSource(pqNetworkDataSource, query) },
27+
).flow.map { pagingData ->
28+
pagingData.map { it.asExternalModel() }
3329
}
3430
}
3531
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.wei.picquest.core.data.repository
22

3-
import com.wei.picquest.core.network.model.NetworkSearchImages
3+
import androidx.paging.PagingData
4+
import com.wei.picquest.core.data.model.ImageDetail
45
import kotlinx.coroutines.flow.Flow
56

67
interface SearchImagesRepository {
78

8-
suspend fun getSearchImages(query: String): Flow<NetworkSearchImages>
9+
suspend fun getSearchImages(query: String): Flow<PagingData<ImageDetail>>
910
}

core/designsystem/src/main/java/com/wei/picquest/core/designsystem/icon/PqIcons.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import androidx.compose.material.icons.rounded.ArrowForward
1414
import androidx.compose.material.icons.rounded.ArrowForwardIos
1515
import androidx.compose.material.icons.rounded.CalendarMonth
1616
import androidx.compose.material.icons.rounded.Close
17+
import androidx.compose.material.icons.rounded.GridView
1718
import androidx.compose.material.icons.rounded.Home
1819
import androidx.compose.material.icons.rounded.Info
20+
import androidx.compose.material.icons.rounded.List
1921
import androidx.compose.material.icons.rounded.Menu
2022
import androidx.compose.material.icons.rounded.Person
2123
import androidx.compose.material.icons.rounded.Phone
@@ -55,4 +57,6 @@ object PqIcons {
5557
val Person = Icons.Rounded.Person
5658
val Menu = Icons.Rounded.Menu
5759
val Add = Icons.Rounded.Add
60+
val ListView = Icons.Rounded.List
61+
val GridView = Icons.Rounded.GridView
5862
}

core/network/src/main/java/com/wei/picquest/core/network/PqNetworkDataSource.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ import com.wei.picquest.core.network.model.NetworkSearchImages
77
*/
88
interface PqNetworkDataSource {
99

10-
suspend fun searchImages(query: String): NetworkSearchImages
10+
suspend fun searchImages(query: String, page: Int, perPage: Int): NetworkSearchImages
1111
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.wei.picquest.core.network.pagingsource
2+
3+
import androidx.paging.PagingSource
4+
import androidx.paging.PagingState
5+
import com.wei.picquest.core.network.PqNetworkDataSource
6+
import com.wei.picquest.core.network.model.NetworkImageDetail
7+
8+
class PixabayPagingSource(
9+
private val pqNetworkDataSource: PqNetworkDataSource,
10+
private val query: String,
11+
) : PagingSource<Int, NetworkImageDetail>() {
12+
13+
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, NetworkImageDetail> {
14+
try {
15+
val currentPage = params.key ?: 1
16+
val response = pqNetworkDataSource.searchImages(
17+
query = query,
18+
page = currentPage,
19+
perPage = 20,
20+
)
21+
22+
val endOfPaginationReached = response.hits.isEmpty()
23+
24+
return LoadResult.Page(
25+
data = response.hits,
26+
prevKey = if (currentPage == 1) null else currentPage - 1,
27+
nextKey = if (endOfPaginationReached) null else currentPage + 1,
28+
)
29+
} catch (exception: Exception) {
30+
return LoadResult.Error(exception)
31+
}
32+
}
33+
34+
override fun getRefreshKey(state: PagingState<Int, NetworkImageDetail>): Int? {
35+
return state.anchorPosition
36+
}
37+
}

core/network/src/main/java/com/wei/picquest/core/network/retrofit/RetrofitPqNetwork.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ interface RetrofitPixabayApi {
2828
@Query("key") apiKey: String = API_KEY,
2929
@Query("q") query: String,
3030
@Query("image_type") imageType: String = "photo",
31+
@Query("page") page: Int,
32+
@Query("perPage") perPage: Int,
3133
// Add more parameters as needed
3234
): NetworkSearchImages
3335
}
@@ -50,7 +52,7 @@ class RetrofitPqNetwork @Inject constructor(
5052
.build()
5153
.create(RetrofitPixabayApi::class.java)
5254

53-
override suspend fun searchImages(query: String): NetworkSearchImages {
54-
return pixabayApi.searchImages(query = query)
55+
override suspend fun searchImages(query: String, page: Int, perPage: Int): NetworkSearchImages {
56+
return pixabayApi.searchImages(query = query, page = page, perPage = perPage)
5557
}
5658
}

0 commit comments

Comments
 (0)