Skip to content

Commit be63611

Browse files
committed
images list
1 parent 8307688 commit be63611

File tree

9 files changed

+164
-11
lines changed

9 files changed

+164
-11
lines changed

app/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ dependencies {
4545
implementation fileTree(dir: 'libs', include: ['*.jar'])
4646
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
4747

48-
implementation 'androidx.appcompat:appcompat:1.2.0-beta01'
48+
implementation 'androidx.appcompat:appcompat:1.2.0-rc01'
4949
implementation 'androidx.core:core-ktx:1.3.0-rc01'
5050
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
5151
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha03'
@@ -64,8 +64,8 @@ dependencies {
6464
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.0-alpha02"
6565

6666
// coroutines
67-
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5'
68-
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'
67+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
68+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6'
6969

7070
// koin
7171
implementation 'org.koin:koin-androidx-viewmodel:2.1.5'

app/src/main/java/com/hoc081098/firestore_coroutinesflow/data/CategoryRepoImpl.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ class CategoryRepoImpl(
2525
override fun watchCategories(): Flow<List<Category>> {
2626
return firestore
2727
.collection("categories")
28+
.orderBy("name")
2829
.snapshots()
2930
.map { (querySnapshot, exception) ->
30-
if (exception !== null) throw exception
31+
exception?.let { throw it }
3132
(querySnapshot ?: return@map emptyList())
3233
.documents
3334
.mapNotNull { it.toObject(CategoryEntity::class.java)?.toCategory(it.id) }
@@ -52,7 +53,7 @@ fun Query.snapshots(): Flow<Pair<QuerySnapshot?, FirebaseFirestoreException?>> {
5253
}
5354
awaitClose {
5455
listener.remove()
55-
Log.d("###", "Remove listener $listener")
56+
Log.d("Query.snapshots", "Remove listener $listener for query ${this@snapshots}")
5657
}
5758
}
5859
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.hoc081098.firestore_coroutinesflow.data
2+
3+
import com.google.firebase.firestore.FirebaseFirestore
4+
import com.hoc081098.firestore_coroutinesflow.data.entity.ImageEntity
5+
import com.hoc081098.firestore_coroutinesflow.domain.entity.Category
6+
import com.hoc081098.firestore_coroutinesflow.domain.entity.Image
7+
import com.hoc081098.firestore_coroutinesflow.domain.repo.ImageRepo
8+
import kotlinx.coroutines.CoroutineDispatcher
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.ExperimentalCoroutinesApi
11+
import kotlinx.coroutines.flow.Flow
12+
import kotlinx.coroutines.flow.flowOn
13+
import kotlinx.coroutines.flow.map
14+
15+
@ExperimentalCoroutinesApi
16+
class ImageRepoImpl(
17+
private val firestore: FirebaseFirestore,
18+
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
19+
) : ImageRepo {
20+
override fun imagesByCategory(category: Category): Flow<List<Image>> {
21+
return firestore
22+
.collection("images")
23+
.whereEqualTo("categoryId", category.id)
24+
.orderBy("name")
25+
.snapshots()
26+
.map { (querySnapshot, exception) ->
27+
exception?.let { throw it }
28+
(querySnapshot ?: return@map emptyList())
29+
.documents
30+
.mapNotNull { it.toObject(ImageEntity::class.java)?.toImage(it.id) }
31+
}
32+
.flowOn(ioDispatcher)
33+
}
34+
}
35+
36+
private fun ImageEntity.toImage(id: String): Image {
37+
return Image(
38+
id = id,
39+
name = name,
40+
imageUrl = imageUrl,
41+
thumbnailUrl = thumbnailUrl,
42+
viewCount = viewCount,
43+
downloadCount = downloadCount,
44+
categoryId = categoryId,
45+
)
46+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.hoc081098.firestore_coroutinesflow.data.entity
2+
3+
import com.google.firebase.firestore.PropertyName
4+
5+
data class ImageEntity(
6+
@get:PropertyName("name")
7+
@set:PropertyName("name")
8+
var name: String,
9+
@get:PropertyName("imageUrl")
10+
@set:PropertyName("imageUrl")
11+
var imageUrl: String,
12+
@get:PropertyName("thumbnailUrl")
13+
@set:PropertyName("thumbnailUrl")
14+
var thumbnailUrl: String,
15+
@get:PropertyName("viewCount")
16+
@set:PropertyName("viewCount")
17+
var viewCount: Long,
18+
@get:PropertyName("downloadCount")
19+
@set:PropertyName("downloadCount")
20+
var downloadCount: Long,
21+
@get:PropertyName("categoryId")
22+
@set:PropertyName("categoryId")
23+
var categoryId: String,
24+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.hoc081098.firestore_coroutinesflow.domain.entity
2+
3+
data class Image(
4+
val id: String,
5+
val name: String,
6+
val imageUrl: String,
7+
val thumbnailUrl: String,
8+
val viewCount: Long,
9+
val downloadCount: Long,
10+
val categoryId: String,
11+
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.hoc081098.firestore_coroutinesflow.domain.repo
2+
3+
import com.hoc081098.firestore_coroutinesflow.domain.entity.Category
4+
import com.hoc081098.firestore_coroutinesflow.domain.entity.Image
5+
import kotlinx.coroutines.flow.Flow
6+
7+
interface ImageRepo {
8+
fun imagesByCategory(category: Category): Flow<List<Image>>
9+
}

app/src/main/java/com/hoc081098/firestore_coroutinesflow/ui/category_detail/CategoryDetailFragment.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
package com.hoc081098.firestore_coroutinesflow.ui.category_detail
22

33
import android.os.Bundle
4+
import android.util.Log
45
import android.view.View
56
import androidx.fragment.app.Fragment
7+
import androidx.lifecycle.lifecycleScope
8+
import androidx.navigation.fragment.navArgs
9+
import com.google.firebase.firestore.FirebaseFirestore
610
import com.hoc081098.firestore_coroutinesflow.R
11+
import com.hoc081098.firestore_coroutinesflow.data.snapshots
12+
import kotlinx.coroutines.flow.launchIn
13+
import kotlinx.coroutines.flow.onEach
14+
import org.json.JSONArray
15+
import org.koin.androidx.viewmodel.ext.android.viewModel
16+
import org.koin.core.parameter.parametersOf
717

818
class CategoryDetailFragment : Fragment(R.layout.category_detail_fragment) {
19+
private val args by navArgs<CategoryDetailFragmentArgs>()
20+
private val vm by viewModel<CategoryDetailViewModel> { parametersOf(args.category) }
21+
922
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
1023
super.onViewCreated(view, savedInstanceState)
1124

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.hoc081098.firestore_coroutinesflow.ui.category_detail
2+
3+
import androidx.lifecycle.Observer
4+
import androidx.lifecycle.ViewModel
5+
import androidx.lifecycle.asLiveData
6+
import com.hoc081098.firestore_coroutinesflow.Lce
7+
import com.hoc081098.firestore_coroutinesflow.domain.entity.Category
8+
import com.hoc081098.firestore_coroutinesflow.domain.entity.Image
9+
import com.hoc081098.firestore_coroutinesflow.domain.repo.ImageRepo
10+
import kotlinx.coroutines.ExperimentalCoroutinesApi
11+
import kotlinx.coroutines.flow.catch
12+
import kotlinx.coroutines.flow.map
13+
import kotlinx.coroutines.flow.onStart
14+
import kotlin.LazyThreadSafetyMode.NONE
15+
16+
@ExperimentalCoroutinesApi
17+
class CategoryDetailViewModel(
18+
private val category: Category,
19+
private val imageRepo: ImageRepo,
20+
) : ViewModel(), Observer<Lce<List<Image>>> {
21+
val categoriesData by lazy(NONE) {
22+
imageRepo.imagesByCategory(category)
23+
.map { Lce.content(it) }
24+
.onStart { emit(Lce.loading()) }
25+
.catch { emit(Lce.error(it)) }
26+
.asLiveData(timeoutInMs = 0)
27+
.apply { observeForever(this@CategoryDetailViewModel) }
28+
}
29+
30+
override fun onChanged(t: Lce<List<Image>>?) = Unit
31+
32+
override fun onCleared() {
33+
super.onCleared()
34+
categoriesData.removeObserver(this)
35+
}
36+
}
Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
package com.hoc081098.firestore_coroutinesflow.ui.main
22

3+
import androidx.lifecycle.Observer
34
import androidx.lifecycle.ViewModel
45
import androidx.lifecycle.asLiveData
56
import com.hoc081098.firestore_coroutinesflow.Lce
7+
import com.hoc081098.firestore_coroutinesflow.domain.entity.Category
68
import com.hoc081098.firestore_coroutinesflow.domain.repo.CategoryRepo
79
import kotlinx.coroutines.ExperimentalCoroutinesApi
810
import kotlinx.coroutines.flow.catch
911
import kotlinx.coroutines.flow.map
1012
import kotlinx.coroutines.flow.onStart
13+
import kotlin.LazyThreadSafetyMode.NONE
1114

1215
@ExperimentalCoroutinesApi
13-
class MainViewModel(categoryRepo: CategoryRepo) : ViewModel() {
14-
val categoriesData = categoryRepo.watchCategories()
15-
.map { Lce.content(it) }
16-
.onStart { emit(Lce.loading()) }
17-
.catch { emit(Lce.error(it)) }
18-
.asLiveData()
16+
class MainViewModel(categoryRepo: CategoryRepo) : ViewModel(), Observer<Lce<List<Category>>> {
17+
val categoriesData by lazy(NONE) {
18+
categoryRepo.watchCategories()
19+
.map { Lce.content(it) }
20+
.onStart { emit(Lce.loading()) }
21+
.catch { emit(Lce.error(it)) }
22+
.asLiveData(timeoutInMs = 0)
23+
.apply { observeForever(this@MainViewModel) }
24+
}
25+
26+
override fun onChanged(t: Lce<List<Category>>?) = Unit
27+
28+
override fun onCleared() {
29+
super.onCleared()
30+
categoriesData.removeObserver(this)
31+
}
1932
}

0 commit comments

Comments
 (0)