Skip to content

Commit

Permalink
Merge pull request #8 from azrael8576/feat/photo-library
Browse files Browse the repository at this point in the history
  • Loading branch information
azrael8576 authored Dec 2, 2023
2 parents 58b63a2 + 3b0fc10 commit b149591
Show file tree
Hide file tree
Showing 26 changed files with 706 additions and 100 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ android {

dependencies {
implementation(project(":feature:home"))
implementation(project(":feature:photolibrary"))

// TODO Wei
// implementation(project(":feature:login"))
// implementation(project(":feature:contactme"))

implementation(project(":core:designsystem"))
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/com/wei/picquest/navigation/PqNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.window.layout.DisplayFeature
import com.wei.picquest.core.designsystem.ui.DeviceOrientation
import com.wei.picquest.feature.home.home.navigation.homeGraph
import com.wei.picquest.feature.home.home.navigation.homeRoute
import com.wei.picquest.feature.photolibrary.photolibrary.navigation.photoLibraryGraph
import com.wei.picquest.ui.PqAppState

/**
Expand Down Expand Up @@ -36,5 +37,8 @@ fun PqNavHost(
homeGraph(
navController = navController,
)
photoLibraryGraph(
navController = navController,
)
}
}
11 changes: 7 additions & 4 deletions app/src/main/java/com/wei/picquest/ui/PqAppState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import com.wei.picquest.core.designsystem.ui.isBookPosture
import com.wei.picquest.core.designsystem.ui.isSeparating
import com.wei.picquest.feature.home.home.navigation.homeRoute
import com.wei.picquest.feature.home.home.navigation.navigateToHome
import com.wei.picquest.feature.photolibrary.photolibrary.navigation.navigateToPhotoLibrary
import com.wei.picquest.feature.photolibrary.photolibrary.navigation.photoLibraryRoute
import com.wei.picquest.navigation.TopLevelDestination
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
Expand Down Expand Up @@ -149,6 +151,7 @@ class PqAppState(
val currentTopLevelDestination: TopLevelDestination?
@Composable get() = when (currentDestination?.route) {
homeRoute -> TopLevelDestination.HOME
photoLibraryRoute -> TopLevelDestination.PHOTO_LIBRARY
else -> null
}

Expand Down Expand Up @@ -196,10 +199,10 @@ class PqAppState(
topLevelNavOptions,
)

// TopLevelDestination.PHOTO_LIBRARY -> navController.navigateToPhotoLibrary(
// topLevelNavOptions,
// )
//
TopLevelDestination.PHOTO_LIBRARY -> navController.navigateToPhotoLibrary(
topLevelNavOptions,
)

// TopLevelDestination.CONTACT_ME -> navController.navigateToContactMe(
// topLevelNavOptions,
// )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
add("androidTestImplementation", kotlin("test"))
add("androidTestImplementation", project(":core:testing"))

// Paging 3
add("implementation", libs.findLibrary("paging-runtime").get())
add("implementation", libs.findLibrary("paging-compose").get())
add("testImplementation", libs.findLibrary("paging-common").get())

// Timber
add("implementation", libs.findLibrary("timber").get())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.wei.picquest.core.data.model

import com.wei.picquest.core.network.model.NetworkImageDetail

data class ImageDetail(
val id: Int,
val pageURL: String,
val type: String,
val tags: String,
val previewURL: String,
val previewWidth: Int,
val previewHeight: Int,
val webformatURL: String,
val webformatWidth: Int,
val webformatHeight: Int,
val largeImageURL: String,
val imageWidth: Int,
val imageHeight: Int,
val imageSize: Long,
val views: Int,
val downloads: Int,
val likes: Int,
val comments: Int,
val userId: Int,
val user: String,
val userImageURL: String,
) {
val aspectRatio get() = imageWidth.toFloat() / imageHeight.toFloat()
}

fun NetworkImageDetail.asExternalModel() = ImageDetail(
id = this.id,
pageURL = this.pageURL,
type = this.type,
tags = this.tags,
previewURL = this.previewURL,
previewWidth = this.previewWidth,
previewHeight = this.previewHeight,
webformatURL = this.webformatURL,
webformatWidth = this.webformatWidth,
webformatHeight = this.webformatHeight,
largeImageURL = this.largeImageURL,
imageWidth = this.imageWidth,
imageHeight = this.imageHeight,
imageSize = this.imageSize,
views = this.views,
downloads = this.downloads,
likes = this.likes,
comments = this.comments,
userId = this.userId,
user = this.user,
userImageURL = this.userImageURL,
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
package com.wei.picquest.core.data.repository

import com.wei.picquest.core.network.Dispatcher
import com.wei.picquest.core.network.PqDispatchers
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.map
import com.wei.picquest.core.data.model.ImageDetail
import com.wei.picquest.core.data.model.asExternalModel
import com.wei.picquest.core.network.PqNetworkDataSource
import com.wei.picquest.core.network.model.NetworkSearchImages
import kotlinx.coroutines.CoroutineDispatcher
import com.wei.picquest.core.network.pagingsource.PixabayPagingSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.withContext
import kotlinx.coroutines.flow.map
import javax.inject.Inject

/**
* Implementation of the [SearchImagesRepository].
* @param ioDispatcher 用於執行 IO 相關操作的 CoroutineDispatcher。
* @param network 數據源的網路接口。
*/
class DefaultSearchImagesRepository @Inject constructor(
@Dispatcher(PqDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
private val network: PqNetworkDataSource,
private val pqNetworkDataSource: PqNetworkDataSource,
) : SearchImagesRepository {

/**
* @param query。A URL encoded search term. If omitted, all images are returned. This value may not exceed 100 characters.
* Example: "yellow+flower"
* @return 一個 Flow,內容為 Search Images 的數據。
*/
override suspend fun getSearchImages(
query: String,
): Flow<NetworkSearchImages> = withContext(ioDispatcher) {
flow {
emit(network.searchImages(query))
override suspend fun getSearchImages(query: String): Flow<PagingData<ImageDetail>> {
return Pager(
config = PagingConfig(
pageSize = 20,
prefetchDistance = 5,
enablePlaceholders = false,
),
pagingSourceFactory = { PixabayPagingSource(pqNetworkDataSource, query) },
).flow.map { pagingData ->
pagingData.map { it.asExternalModel() }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.wei.picquest.core.data.repository

import com.wei.picquest.core.network.model.NetworkSearchImages
import androidx.paging.PagingData
import com.wei.picquest.core.data.model.ImageDetail
import kotlinx.coroutines.flow.Flow

interface SearchImagesRepository {

suspend fun getSearchImages(query: String): Flow<NetworkSearchImages>
suspend fun getSearchImages(query: String): Flow<PagingData<ImageDetail>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import androidx.compose.material.icons.rounded.ArrowForward
import androidx.compose.material.icons.rounded.ArrowForwardIos
import androidx.compose.material.icons.rounded.CalendarMonth
import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.GridView
import androidx.compose.material.icons.rounded.Home
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.List
import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material.icons.rounded.Person
import androidx.compose.material.icons.rounded.Phone
Expand Down Expand Up @@ -55,4 +57,6 @@ object PqIcons {
val Person = Icons.Rounded.Person
val Menu = Icons.Rounded.Menu
val Add = Icons.Rounded.Add
val ListView = Icons.Rounded.List
val GridView = Icons.Rounded.GridView
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import com.wei.picquest.core.network.model.NetworkSearchImages
*/
interface PqNetworkDataSource {

suspend fun searchImages(query: String): NetworkSearchImages
suspend fun searchImages(query: String, page: Int, perPage: Int): NetworkSearchImages
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.wei.picquest.core.network.pagingsource

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.wei.picquest.core.network.PqNetworkDataSource
import com.wei.picquest.core.network.model.NetworkImageDetail

class PixabayPagingSource(
private val pqNetworkDataSource: PqNetworkDataSource,
private val query: String,
) : PagingSource<Int, NetworkImageDetail>() {

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, NetworkImageDetail> {
try {
val currentPage = params.key ?: 1
val response = pqNetworkDataSource.searchImages(
query = query,
page = currentPage,
perPage = 20,
)

val endOfPaginationReached = response.hits.isEmpty()

return LoadResult.Page(
data = response.hits,
prevKey = if (currentPage == 1) null else currentPage - 1,
nextKey = if (endOfPaginationReached) null else currentPage + 1,
)
} catch (exception: Exception) {
return LoadResult.Error(exception)
}
}

override fun getRefreshKey(state: PagingState<Int, NetworkImageDetail>): Int? {
return state.anchorPosition
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ interface RetrofitPixabayApi {
@Query("key") apiKey: String = API_KEY,
@Query("q") query: String,
@Query("image_type") imageType: String = "photo",
@Query("page") page: Int,
@Query("perPage") perPage: Int,
// Add more parameters as needed
): NetworkSearchImages
}
Expand All @@ -50,7 +52,7 @@ class RetrofitPqNetwork @Inject constructor(
.build()
.create(RetrofitPixabayApi::class.java)

override suspend fun searchImages(query: String): NetworkSearchImages {
return pixabayApi.searchImages(query = query)
override suspend fun searchImages(query: String, page: Int, perPage: Int): NetworkSearchImages {
return pixabayApi.searchImages(query = query, page = page, perPage = perPage)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ internal fun HomeRoute(
internal fun HomeScreen(
withTopSpacer: Boolean = true,
withBottomSpacer: Boolean = true,
isPreview: Boolean = false,
) {
val showPopup = remember { mutableStateOf(false) }

Expand Down Expand Up @@ -108,8 +107,6 @@ internal fun HomeScreen(
@Composable
fun HomeScreenPreview() {
PqTheme {
HomeScreen(
isPreview = true,
)
HomeScreen()
}
}
1 change: 1 addition & 0 deletions feature/photolibrary/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
12 changes: 12 additions & 0 deletions feature/photolibrary/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins {
alias(libs.plugins.pq.android.feature)
alias(libs.plugins.pq.android.library.compose)
alias(libs.plugins.pq.android.hilt)
}

android {
namespace = "com.wei.picquest.feature.photolibrary"
}

dependencies {
}
4 changes: 4 additions & 0 deletions feature/photolibrary/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Loading

0 comments on commit b149591

Please sign in to comment.