Skip to content

Commit

Permalink
feat: users rating list
Browse files Browse the repository at this point in the history
  • Loading branch information
makeevrserg committed Oct 15, 2023
1 parent 80e0701 commit ac4eeca
Show file tree
Hide file tree
Showing 29 changed files with 527 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ modules/features/settings/build
modules/features/lesson/build
modules/features/dicts-local/build
modules/features/dicts-remote/build
modules/features/rating/build
# Faq
modules/features/faq/build
modules/features/ui/build
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ ktor-client-serialization = { module = "io.ktor:ktor-client-serialization", vers
ktor-client-contentNegitiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-client-json = { module = "io.ktor:ktor-client-json", version.ref = "ktor" }
ktor-serialization-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }

# Moko`
moko-network-generator = { module = "dev.icerock.moko:network-generator", version.ref = "moko-network" }
Expand Down
47 changes: 47 additions & 0 deletions modules/features/rating/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@file:Suppress("UnusedPrivateMember")

import ru.astrainteractive.gradleplugin.util.ProjectProperties.projectInfo

plugins {
id("com.android.library")
kotlin("multiplatform")
id("ru.astrainteractive.gradleplugin.java.core")
id("ru.astrainteractive.gradleplugin.android.core")
alias(libs.plugins.kotlin.serialization)
}

kotlin {
android()
ios()
iosSimulatorArm64()
sourceSets {
val commonMain by getting {
dependencies {
// klibs
implementation(libs.klibs.mikro.core)
api(libs.klibs.mikro.platform)
implementation(libs.klibs.kstorage)
implementation(libs.klibs.kdi)
// Decompose
api(libs.decompose.core)
api(libs.essenty)
// Moko
implementation(libs.moko.resources.core)
// Paging
implementation("ru.astrainteractive.mobilex:paging:2.7.3")
// Coroutines
implementation(libs.kotlin.coroutines.core)
// MVIKotlin
implementation(libs.mvikotlin)
// Local
api(projects.modules.services.resources)
api(projects.modules.services.core)
api(projects.modules.services.apiEmpireapi)
}
}
}
}
android {
apply(plugin = "kotlin-parcelize")
namespace = "${projectInfo.group}.rating"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.makeevrserg.empireprojekt.mobile.features.rating.users

import com.arkivanov.decompose.ComponentContext
import com.arkivanov.essenty.instancekeeper.getOrCreate
import com.makeevrserg.empireprojekt.mobile.features.rating.users.RatingUsersComponent.Model
import com.makeevrserg.empireprojekt.mobile.features.rating.users.data.RatingUsersRepository
import com.makeevrserg.empireprojekt.mobile.services.core.CoroutineFeature
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class DefaultRatingUsersComponent(
componentContext: ComponentContext,
private val repository: RatingUsersRepository
) : RatingUsersComponent,
ComponentContext by componentContext {
private val coroutineFeature = instanceKeeper.getOrCreate {
CoroutineFeature.Default()
}
override val model = MutableStateFlow(Model())

private fun collectPagingState() = coroutineFeature.launch {
repository.pagingStateFlow.collectLatest {
model.update { model ->
model.copy(
isLastPage = it.isLastPage,
isLoading = it.isLoading
)
}
}
}

private fun collectListStateFlow() = coroutineFeature.launch {
repository.listStateFlow.collectLatest {
model.update { model ->
model.copy(items = it)
}
}
}

override fun reset() {
coroutineFeature.launch {
repository.reset()
repository.loadNextPage()
}
}

override fun loadNextPage() {
coroutineFeature.launch {
repository.loadNextPage()
}
}

init {
collectPagingState()
collectListStateFlow()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.makeevrserg.empireprojekt.mobile.features.rating.users

import kotlinx.coroutines.flow.StateFlow
import ru.astrainteractive.empireapi.models.rating.RatingListRequest
import ru.astrainteractive.empireapi.models.rating.RatingUserModel

interface RatingUsersComponent {
val model: StateFlow<Model>

fun reset()

fun loadNextPage()

data class Model(
val items: List<RatingUserModel> = emptyList(),
val request: RatingListRequest = RatingListRequest(),
val isLoading: Boolean = false,
val isLastPage: Boolean = false
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.makeevrserg.empireprojekt.mobile.features.rating.users.data

import com.makeevrserg.mobilex.paging.state.PagingState
import kotlinx.coroutines.flow.MutableStateFlow
import ru.astrainteractive.empireapi.models.rating.RatingListRequest
import ru.astrainteractive.empireapi.models.rating.RatingUserModel

interface RatingUsersRepository {
fun updateRequest(request: RatingListRequest)
suspend fun loadNextPage()
suspend fun reset()
val pagingStateFlow: MutableStateFlow<PagingState<Int>>
val listStateFlow: MutableStateFlow<List<RatingUserModel>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.makeevrserg.empireprojekt.mobile.features.rating.users.data

import com.makeevrserg.empireprojekt.mobile.api.empireapi.RatingApi
import com.makeevrserg.mobilex.paging.PagingCollector
import com.makeevrserg.mobilex.paging.data.LambdaPagedListDataSource
import com.makeevrserg.mobilex.paging.state.IntPagingState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.withContext
import ru.astrainteractive.empireapi.models.rating.RatingListRequest
import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers

class RatingUsersRepositoryImpl(
private val ratingApi: RatingApi,
private val dispatchers: KotlinDispatchers
) : RatingUsersRepository {
private val request = MutableStateFlow(RatingListRequest())

private val pagingCollector = PagingCollector(
initialPagingState = IntPagingState(0),
pager = LambdaPagedListDataSource {
val result = runCatching {
withContext(dispatchers.IO) {
ratingApi.users(
page = it.page,
size = 10,
body = request.value
).data
}
}.onFailure(Throwable::printStackTrace)
result.getOrNull()
}
)

override val pagingStateFlow = pagingCollector.pagingStateFlow

override val listStateFlow = pagingCollector.listStateFlow

override suspend fun reset() {
pagingCollector.reset()
}

override suspend fun loadNextPage() {
pagingCollector.loadNextPage()
}

override fun updateRequest(request: RatingListRequest) {
this.request.update {
request
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.makeevrserg.empireprojekt.mobile.features.rating.users.di

import com.makeevrserg.empireprojekt.mobile.api.empireapi.di.EmpireApiModule
import com.makeevrserg.empireprojekt.mobile.features.rating.users.data.RatingUsersRepository
import com.makeevrserg.empireprojekt.mobile.features.rating.users.data.RatingUsersRepositoryImpl
import ru.astrainteractive.klibs.kdi.Single
import ru.astrainteractive.klibs.kdi.getValue
import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers

interface RatingUsersModule {
val ratingUsersRepository: RatingUsersRepository

class Default(
empireApiModule: EmpireApiModule,
dispatchers: KotlinDispatchers
) : RatingUsersModule {
override val ratingUsersRepository: RatingUsersRepository by Single {
RatingUsersRepositoryImpl(
ratingApi = empireApiModule.ratingApi,
dispatchers = dispatchers
)
}
}
}
5 changes: 4 additions & 1 deletion modules/features/root/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ kotlin {
implementation(libs.ktor.client.serialization)
implementation(libs.ktor.client.json)
implementation(libs.ktor.serialization.json)
implementation(libs.ktor.logging)
// Moko
api(libs.moko.mvvm.core)
api(libs.moko.mvvm.flow)
Expand All @@ -67,9 +68,10 @@ kotlin {
implementation(libs.mvikotlin)
// Local
api(projects.modules.services.resources)
api(projects.modules.features.splash)
api(projects.modules.services.core)
api(projects.modules.services.apiEmpireapi)
api(projects.modules.features.splash)
api(projects.modules.features.rating)
}
}
val androidMain by getting {
Expand Down Expand Up @@ -112,6 +114,7 @@ dependencies {
implementation(libs.klibs.kstorage)
implementation(libs.google.auth)
implementation(libs.kotlin.coroutines.playServices)
implementation("io.ktor:ktor-client-logging-jvm:2.3.2")
}

multiplatformResources {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import com.makeevrserg.empireprojekt.mobile.features.root.di.factory.SettingsFac
import com.makeevrserg.empireprojekt.mobile.services.core.LinkBrowser
import io.ktor.client.HttpClient
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.logging.DEFAULT
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logger
import io.ktor.client.plugins.logging.Logging
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.MainScope
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -34,6 +38,10 @@ internal class ServicesModuleImpl : ServicesModule {
install(ContentNegotiation) {
json(jsonConfiguration)
}
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.HEADERS
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.arkivanov.decompose.router.stack.replaceAll
import com.arkivanov.decompose.router.stack.replaceCurrent
import com.arkivanov.decompose.value.Value
import com.makeevrserg.empireprojekt.mobile.features.logic.splash.SplashComponent
import com.makeevrserg.empireprojekt.mobile.features.rating.users.RatingUsersComponent
import com.makeevrserg.empireprojekt.mobile.features.root.di.RootModule
import com.makeevrserg.empireprojekt.mobile.features.root.screen.di.factory.RootScreenComponentChildFactory
import com.makeevrserg.empireprojekt.mobile.features.status.root.RootStatusComponent
Expand Down Expand Up @@ -61,5 +62,9 @@ class DefaultRootScreenComponent(
val rootStatusComponent: RootStatusComponent,
val themeSwitcherComponent: ThemeSwitcherComponent
) : Configuration

class RatingUsers(
val ratingUsersComponent: RatingUsersComponent
) : Configuration
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ interface RootScreenComponent : BackHandlerOwner {

@Parcelize
object Status : Child

@Parcelize
object RatingUsers : Child
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.makeevrserg.empireprojekt.mobile.features.root.screen.di.factory

import com.arkivanov.decompose.ComponentContext
import com.makeevrserg.empireprojekt.mobile.features.logic.splash.DefaultSplashComponent
import com.makeevrserg.empireprojekt.mobile.features.rating.users.DefaultRatingUsersComponent
import com.makeevrserg.empireprojekt.mobile.features.rating.users.di.RatingUsersModule
import com.makeevrserg.empireprojekt.mobile.features.root.di.RootModule
import com.makeevrserg.empireprojekt.mobile.features.root.screen.DefaultRootScreenComponent
import com.makeevrserg.empireprojekt.mobile.features.root.screen.RootScreenComponent
Expand All @@ -27,6 +29,19 @@ class RootScreenComponentChildFactory(
rootStatusComponent = rootModule.componentsModule.rootStatusComponent.value
)
}

RootScreenComponent.Child.RatingUsers -> {
val module = RatingUsersModule.Default(
empireApiModule = rootModule.empireApiModule,
dispatchers = rootModule.servicesModule.dispatchers.value
)
DefaultRootScreenComponent.Configuration.RatingUsers(
ratingUsersComponent = DefaultRatingUsersComponent(
componentContext = context,
repository = module.ratingUsersRepository,
)
)
}
}
}
}
3 changes: 3 additions & 0 deletions modules/features/ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ kotlin {
dependencies {
// Accompanist
implementation(libs.google.accompanist.systemuicontroller)
// Image loading
implementation("io.coil-kt:coil:2.4.0")
implementation("io.coil-kt:coil-compose:2.4.0")
}
}
}
Expand Down
Loading

0 comments on commit ac4eeca

Please sign in to comment.