diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2ee0207..c525edc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { id("com.android.application") id("com.google.devtools.ksp") id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.serialization") } android { @@ -95,4 +96,12 @@ dependencies { implementation ("androidx.paging:paging-guava:$paging_version") // optional - Jetpack Compose integration implementation ("androidx.paging:paging-compose:1.0.0-alpha18") + // retrofit + val retrofitVersion = "2.9.0" + implementation("com.squareup.retrofit2:retrofit:$retrofitVersion") + implementation("com.squareup.okhttp3:logging-interceptor:4.11.0") + implementation("androidx.paging:paging-compose:3.2.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") + implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0") + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b8d8988..61fa420 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - + + @GET("tags") + suspend fun getTags( + @Query("_page") page: Int, + @Query("_limit") limit: Int, + ): List + @GET("tags") + suspend fun getAllTags(): List + @GET("articles") + suspend fun getAllArticles(): List + @GET("comments") + suspend fun getAllComments(): List + @GET("articles") + suspend fun getArticles( + @Query("_page") page: Int, + @Query("_limit") limit: Int, + ): List + @GET("comments") + suspend fun getComments( + @Query("_page") page: Int, + @Query("_limit") limit: Int, + ): List + + @GET("comments") + suspend fun getCountComment( + @Query("articleId") articleId: Int + ): List + @GET("comments") + suspend fun getUserComments(@Query("userId") userId: Int): List + + @GET("articles") + suspend fun getUserArticles(@Query("userId") userId: Int): List + + @GET("tags") + suspend fun getUserTags(@Query("userId") userId: Int): List + + @GET("users/{id}") + suspend fun getUser( + @Path("id") id: Int, + ): UserRemote + @POST("users") + suspend fun createUser( + @Body user: UserRemote, + ): UserRemote + @PUT("users/{id}") + suspend fun updateUser( + @Path("id") id: Int, + @Body user: UserRemote, + ): UserRemote + @DELETE("users/{id}") + suspend fun deleteUser( + @Path("id") id: Int, + ): UserRemote + + @GET("tags") + suspend fun getTagByName( + @Query("title") title: String, + ): List + + @GET("tags/{id}") + suspend fun getTag( + @Path("id") id: Int, + ): TagRemote + @POST("tags") + suspend fun createTag( + @Body tag: TagRemote, + ): TagRemote + @PUT("tags/{id}") + suspend fun updateTag( + @Path("id") id: Int, + @Body tag: TagRemote, + ): TagRemote + @DELETE("tags/{id}") + suspend fun deleteTag( + @Path("id") id: Int, + ): TagRemote + + @GET("articles/{id}") + suspend fun getArticle( + @Path("id") id: Int, + ): ArticleRemote + @POST("articles") + suspend fun createArticle( + @Body article: ArticleRemote, + ): ArticleRemote + @PUT("articles/{id}") + suspend fun updateArticle( + @Path("id") id: Int, + @Body article: ArticleRemote, + ): ArticleRemote + @DELETE("articles/{id}") + suspend fun deleteArticle( + @Path("id") id: Int, + ): ArticleRemote + + @GET("comments/{id}") + suspend fun getComment( + @Path("id") id: Int, + ): CommentRemote + @POST("comments") + suspend fun createComment( + @Body comment: CommentRemote, + ): CommentRemote + @PUT("comments/{id}") + suspend fun updateComment( + @Path("id") id: Int, + @Body comment: CommentRemote, + ): CommentRemote + @DELETE("comments/{id}") + suspend fun deleteComment( + @Path("id") id: Int, + ): CommentRemote + + companion object { + private const val BASE_URL = "http://10.0.2.2:8079/" + + @Volatile + private var INSTANCE: NewsPortalService? = null + + fun getInstance(): NewsPortalService { + return INSTANCE ?: synchronized(this) { + val logger = HttpLoggingInterceptor() + logger.level = HttpLoggingInterceptor.Level.BASIC + val client = OkHttpClient.Builder() + .addInterceptor(logger) + .build() + return Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) + .build() + .create(NewsPortalService::class.java) + .also { INSTANCE = it } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/mediator/ArticleRemoteMediator.kt b/app/src/main/java/com/example/pmulabs/api/mediator/ArticleRemoteMediator.kt new file mode 100644 index 0000000..da94e2e --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/mediator/ArticleRemoteMediator.kt @@ -0,0 +1,112 @@ +package com.example.pmulabs.api.mediator + +import androidx.paging.ExperimentalPagingApi +import androidx.paging.LoadType +import androidx.paging.PagingState +import androidx.paging.RemoteMediator +import androidx.room.withTransaction +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.model.toArticle +import com.example.pmulabs.api.repository.RestTagRepository +import com.example.pmulabs.room.database.NewsPortalDatabase +import com.example.pmulabs.room.models.Article +import com.example.pmulabs.room.models.RemoteKeyType +import com.example.pmulabs.room.models.RemoteKeys +import com.example.pmulabs.room.repository.OfflineArticleRepository +import com.example.pmulabs.room.repository.OfflineRemoteKeyRepository +import retrofit2.HttpException +import java.io.IOException + +@OptIn(ExperimentalPagingApi::class) +class ArticleRemoteMediator( + private val service: NewsPortalService, + private val dbArticleRepository: OfflineArticleRepository, + private val dbRemoteKeyRepository: OfflineRemoteKeyRepository, + private val tagRestRepository: RestTagRepository, + private val database: NewsPortalDatabase +) : RemoteMediator() { + + override suspend fun initialize(): InitializeAction { + return InitializeAction.LAUNCH_INITIAL_REFRESH + } + + override suspend fun load( + loadType: LoadType, + state: PagingState + ): MediatorResult { + val page = when (loadType) { + LoadType.REFRESH -> { + val remoteKeys = getRemoteKeyClosestToCurrentPosition(state) + remoteKeys?.nextKey?.minus(1) ?: 1 + } + + LoadType.PREPEND -> { + val remoteKeys = getRemoteKeyForFirstItem(state) + remoteKeys?.prevKey + ?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null) + } + + LoadType.APPEND -> { + val remoteKeys = getRemoteKeyForLastItem(state) + remoteKeys?.nextKey + ?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null) + } + } + + try { + val articles = service.getArticles(page, state.config.pageSize).map { it.toArticle() } + val endOfPaginationReached = articles.isEmpty() + database.withTransaction { + if (loadType == LoadType.REFRESH) { + dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.ARTICLE) + dbArticleRepository.clearArticles() + } + val prevKey = if (page == 1) null else page - 1 + val nextKey = if (endOfPaginationReached) null else page + 1 + val keys = articles.map { + it.id?.let { it1 -> + RemoteKeys( + entityId = it1, + type = RemoteKeyType.ARTICLE, + prevKey = prevKey, + nextKey = nextKey + ) + } + } + dbRemoteKeyRepository.createRemoteKeys(keys) + tagRestRepository.getAllTags() + dbArticleRepository.insertArticles(articles) + } + return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached) + } catch (exception: IOException) { + return MediatorResult.Error(exception) + } catch (exception: HttpException) { + return MediatorResult.Error(exception) + } + } + + private suspend fun getRemoteKeyForLastItem(state: PagingState): RemoteKeys? { + return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull() + ?.let { art -> + art.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.ARTICLE) } + } + } + + private suspend fun getRemoteKeyForFirstItem(state: PagingState): RemoteKeys? { + return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull() + ?.let { art -> + art.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.ARTICLE) } + } + } + + private suspend fun getRemoteKeyClosestToCurrentPosition( + state: PagingState + ): RemoteKeys? { + return state.anchorPosition?.let { position -> + state.closestItemToPosition(position)?.id?.let { artid -> + dbRemoteKeyRepository.getAllRemoteKeys(artid, RemoteKeyType.ARTICLE) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/mediator/CommentRemoteMediator.kt b/app/src/main/java/com/example/pmulabs/api/mediator/CommentRemoteMediator.kt new file mode 100644 index 0000000..59d06ce --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/mediator/CommentRemoteMediator.kt @@ -0,0 +1,111 @@ +package com.example.pmulabs.api.mediator + +import androidx.paging.ExperimentalPagingApi +import androidx.paging.LoadType +import androidx.paging.PagingState +import androidx.paging.RemoteMediator +import androidx.room.withTransaction +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.model.toComment +import com.example.pmulabs.api.repository.RestArticleRepository +import com.example.pmulabs.room.database.NewsPortalDatabase +import com.example.pmulabs.room.models.Comment +import com.example.pmulabs.room.models.RemoteKeyType +import com.example.pmulabs.room.models.RemoteKeys +import com.example.pmulabs.room.repository.OfflineCommentRepository +import com.example.pmulabs.room.repository.OfflineRemoteKeyRepository +import retrofit2.HttpException +import java.io.IOException + +@OptIn(ExperimentalPagingApi::class) +class CommentRemoteMediator( + private val service: NewsPortalService, + private val dbCommentRepository: OfflineCommentRepository, + private val dbRemoteKeyRepository: OfflineRemoteKeyRepository, + private val articleRestRepository: RestArticleRepository, + private val database: NewsPortalDatabase +) : RemoteMediator() { + + override suspend fun initialize(): InitializeAction { + return InitializeAction.LAUNCH_INITIAL_REFRESH + } + + override suspend fun load( + loadType: LoadType, + state: PagingState + ): MediatorResult { + val page = when (loadType) { + LoadType.REFRESH -> { + val remoteKeys = getRemoteKeyClosestToCurrentPosition(state) + remoteKeys?.nextKey?.minus(1) ?: 1 + } + + LoadType.PREPEND -> { + val remoteKeys = getRemoteKeyForFirstItem(state) + remoteKeys?.prevKey + ?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null) + } + + LoadType.APPEND -> { + val remoteKeys = getRemoteKeyForLastItem(state) + remoteKeys?.nextKey + ?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null) + } + } + + try { + val comms = service.getComments(page, state.config.pageSize).map { it.toComment() } + val endOfPaginationReached = comms.isEmpty() + database.withTransaction { + if (loadType == LoadType.REFRESH) { + dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.COMMENT) + dbCommentRepository.clearComments() + } + val prevKey = if (page == 1) null else page - 1 + val nextKey = if (endOfPaginationReached) null else page + 1 + val keys = comms.map { + it.id?.let { it1 -> + RemoteKeys( + entityId = it1, + type = RemoteKeyType.COMMENT, + prevKey = prevKey, + nextKey = nextKey + ) + } + } + dbRemoteKeyRepository.createRemoteKeys(keys) + articleRestRepository.getAllArticles() + dbCommentRepository.insertComments(comms) + } + return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached) + } catch (exception: IOException) { + return MediatorResult.Error(exception) + } catch (exception: HttpException) { + return MediatorResult.Error(exception) + } + } + + private suspend fun getRemoteKeyForLastItem(state: PagingState): RemoteKeys? { + return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull() + ?.let { comm -> + comm.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.COMMENT) } + } + } + + private suspend fun getRemoteKeyForFirstItem(state: PagingState): RemoteKeys? { + return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull() + ?.let { comm -> + comm.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.COMMENT) } + } + } + + private suspend fun getRemoteKeyClosestToCurrentPosition( + state: PagingState + ): RemoteKeys? { + return state.anchorPosition?.let { position -> + state.closestItemToPosition(position)?.id?.let { commid -> + dbRemoteKeyRepository.getAllRemoteKeys(commid, RemoteKeyType.COMMENT) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/mediator/TagRemoteMediator.kt b/app/src/main/java/com/example/pmulabs/api/mediator/TagRemoteMediator.kt new file mode 100644 index 0000000..0005617 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/mediator/TagRemoteMediator.kt @@ -0,0 +1,109 @@ +package com.example.pmulabs.api.mediator + +import androidx.paging.ExperimentalPagingApi +import androidx.paging.LoadType +import androidx.paging.PagingState +import androidx.paging.RemoteMediator +import androidx.room.withTransaction +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.model.toTag +import com.example.pmulabs.room.database.NewsPortalDatabase +import com.example.pmulabs.room.models.RemoteKeyType +import com.example.pmulabs.room.models.RemoteKeys +import com.example.pmulabs.room.models.Tag +import com.example.pmulabs.room.repository.OfflineRemoteKeyRepository +import com.example.pmulabs.room.repository.OfflineTagRepository +import retrofit2.HttpException +import java.io.IOException + +@OptIn(ExperimentalPagingApi::class) +class TagRemoteMediator( + private val service: NewsPortalService, + private val dbTagRepository: OfflineTagRepository, + private val dbRemoteKeyRepository: OfflineRemoteKeyRepository, + private val database: NewsPortalDatabase +) : RemoteMediator() { + + override suspend fun initialize(): InitializeAction { + return InitializeAction.LAUNCH_INITIAL_REFRESH + } + + override suspend fun load( + loadType: LoadType, + state: PagingState + ): MediatorResult { + val page = when (loadType) { + LoadType.REFRESH -> { + val remoteKeys = getRemoteKeyClosestToCurrentPosition(state) + remoteKeys?.nextKey?.minus(1) ?: 1 + } + + LoadType.PREPEND -> { + val remoteKeys = getRemoteKeyForFirstItem(state) + remoteKeys?.prevKey + ?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null) + } + + LoadType.APPEND -> { + val remoteKeys = getRemoteKeyForLastItem(state) + remoteKeys?.nextKey + ?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null) + } + } + + try { + val tags = service.getTags(page, state.config.pageSize).map { it.toTag() } + val endOfPaginationReached = tags.isEmpty() + database.withTransaction { + if (loadType == LoadType.REFRESH) { + dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.TAG) + dbTagRepository.clearTags() + } + val prevKey = if (page == 1) null else page - 1 + val nextKey = if (endOfPaginationReached) null else page + 1 + val keys = tags.map { + it.id?.let { it1 -> + RemoteKeys( + entityId = it1, + type = RemoteKeyType.TAG, + prevKey = prevKey, + nextKey = nextKey + ) + } + } + dbRemoteKeyRepository.createRemoteKeys(keys) + dbTagRepository.insertTags(tags) + } + return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached) + } catch (exception: IOException) { + return MediatorResult.Error(exception) + } catch (exception: HttpException) { + return MediatorResult.Error(exception) + } + } + + private suspend fun getRemoteKeyForLastItem(state: PagingState): RemoteKeys? { + return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull() + ?.let { tag -> + tag.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.TAG) } + } + } + + private suspend fun getRemoteKeyForFirstItem(state: PagingState): RemoteKeys? { + return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull() + ?.let { tag -> + tag.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.TAG) } + } + } + + private suspend fun getRemoteKeyClosestToCurrentPosition( + state: PagingState + ): RemoteKeys? { + return state.anchorPosition?.let { position -> + state.closestItemToPosition(position)?.id?.let { tagid -> + dbRemoteKeyRepository.getAllRemoteKeys(tagid, RemoteKeyType.TAG) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/model/ArticleRemote.kt b/app/src/main/java/com/example/pmulabs/api/model/ArticleRemote.kt new file mode 100644 index 0000000..7647c79 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/model/ArticleRemote.kt @@ -0,0 +1,32 @@ +package com.example.pmulabs.api.model + +import com.example.pmulabs.room.models.Article +import kotlinx.serialization.Serializable + +@Serializable +data class ArticleRemote( + val id: Int?=0, + var title: String="", + var text: String="", + val publishDate: Long=0, + val userId: Int=0, + var tagId: Int=0 +) + +fun ArticleRemote.toArticle(): Article = Article( + id, + title, + text, + publishDate, + userId, + tagId +) + +fun Article.toArticleRemote(): ArticleRemote = ArticleRemote( + id, + title, + text, + publishDate, + userId, + tagId +) \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/model/CommentRemote.kt b/app/src/main/java/com/example/pmulabs/api/model/CommentRemote.kt new file mode 100644 index 0000000..6fdb0e1 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/model/CommentRemote.kt @@ -0,0 +1,26 @@ +package com.example.pmulabs.api.model + +import com.example.pmulabs.room.models.Comment +import kotlinx.serialization.Serializable + +@Serializable +data class CommentRemote( + val id: Int?=0, + var text: String="", + val userId: Int=0, + val articleId: Int=0 +) + +fun CommentRemote.toComment(): Comment = Comment( + id, + text, + userId, + articleId +) + +fun Comment.toCommentRemote(): CommentRemote = CommentRemote( + id, + text, + userId, + articleId +) \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/model/TagRemote.kt b/app/src/main/java/com/example/pmulabs/api/model/TagRemote.kt new file mode 100644 index 0000000..dceb253 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/model/TagRemote.kt @@ -0,0 +1,23 @@ +package com.example.pmulabs.api.model + +import com.example.pmulabs.room.models.Tag +import kotlinx.serialization.Serializable + +@Serializable +data class TagRemote( + var title: String="", + val id: Int?=0, + val userId: Int=0 +) + +fun TagRemote.toTag(): Tag = Tag( + title, + id, + userId +) + +fun Tag.toTagRemote(): TagRemote = TagRemote( + title, + id, + userId +) \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/model/UserRemote.kt b/app/src/main/java/com/example/pmulabs/api/model/UserRemote.kt new file mode 100644 index 0000000..de84d7c --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/model/UserRemote.kt @@ -0,0 +1,29 @@ +package com.example.pmulabs.api.model + +import com.example.pmulabs.room.models.User +import kotlinx.serialization.Serializable + +@Serializable +data class UserRemote( + val id: Int?=0, + var nickname: String="", + var email: String="", + var password: String="", + val role: String="" +) + +fun UserRemote.toUser(): User = User( + id, + nickname, + email, + password, + role +) + +fun User.toUserRemote(): UserRemote = UserRemote( + id, + nickname, + email, + password, + role +) \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/repository/RestArticleRepository.kt b/app/src/main/java/com/example/pmulabs/api/repository/RestArticleRepository.kt new file mode 100644 index 0000000..353b2d1 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/repository/RestArticleRepository.kt @@ -0,0 +1,79 @@ +package com.example.pmulabs.api.repository + +import androidx.paging.ExperimentalPagingApi +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.mediator.ArticleRemoteMediator +import com.example.pmulabs.api.model.toArticle +import com.example.pmulabs.api.model.toArticleRemote +import com.example.pmulabs.room.AppContainer +import com.example.pmulabs.room.database.NewsPortalDatabase +import com.example.pmulabs.room.models.Article +import com.example.pmulabs.room.repository.ArticleRepository +import com.example.pmulabs.room.repository.OfflineArticleRepository +import com.example.pmulabs.room.repository.OfflineRemoteKeyRepository +import kotlinx.coroutines.flow.Flow + +class RestArticleRepository( + private val service: NewsPortalService, + private val dbArticleRepository: OfflineArticleRepository, + private val dbRemoteKeyRepository: OfflineRemoteKeyRepository, + private val dbTagRepository: RestTagRepository, + private val database: NewsPortalDatabase +) : ArticleRepository { + override suspend fun insertArticle(article: Article) { + service.createArticle(article.toArticleRemote()).toArticle() + } + + override suspend fun updateArticle(article: Article) { + article.id?.let { service.updateArticle(it, article.toArticleRemote()).toArticle() } + } + + override suspend fun deleteArticle(article: Article) { + article.id?.let { service.deleteArticle(it).toArticle() } + } + + override suspend fun getAllArticles(): List
{ + dbTagRepository.getAllTags() + val existArticles = dbArticleRepository.getAllArticles().associateBy { it.id }.toMutableMap() + + service.getAllArticles() + .map { it.toArticle() } + .forEach { art -> + val existArt = existArticles[art.id] + if (existArt == null) { + dbArticleRepository.insertArticle(art) + } else if (existArt != art) { + dbArticleRepository.updateArticle(art) + } + existArticles[art.id] = art + } + + return existArticles.map { it.value }.sortedBy { it.id } + } + + override suspend fun getArticleById(idArticle: Int): Article? = + idArticle?.let { service.getArticle(it).toArticle() } + + override fun getArticles(): Flow> { + val pagingSourceFactory = { dbArticleRepository.getAllArticlesPagingSource() } + + @OptIn(ExperimentalPagingApi::class) + return Pager( + config = PagingConfig( + pageSize = AppContainer.LIMIT, + enablePlaceholders = false + ), + remoteMediator = ArticleRemoteMediator( + service, + dbArticleRepository, + dbRemoteKeyRepository, + dbTagRepository, + database, + ), + pagingSourceFactory = pagingSourceFactory + ).flow + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/repository/RestCommentRepository.kt b/app/src/main/java/com/example/pmulabs/api/repository/RestCommentRepository.kt new file mode 100644 index 0000000..1c5412b --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/repository/RestCommentRepository.kt @@ -0,0 +1,85 @@ +package com.example.pmulabs.api.repository + +import androidx.paging.ExperimentalPagingApi +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.mediator.CommentRemoteMediator +import com.example.pmulabs.api.model.toComment +import com.example.pmulabs.api.model.toCommentRemote +import com.example.pmulabs.api.model.toUser +import com.example.pmulabs.room.AppContainer +import com.example.pmulabs.room.database.NewsPortalDatabase +import com.example.pmulabs.room.models.Comment +import com.example.pmulabs.room.models.User +import com.example.pmulabs.room.repository.CommentRepository +import com.example.pmulabs.room.repository.OfflineCommentRepository +import com.example.pmulabs.room.repository.OfflineRemoteKeyRepository +import kotlinx.coroutines.flow.Flow + +class RestCommentRepository( + private val service: NewsPortalService, + private val dbCommentRepository: OfflineCommentRepository, + private val dbRemoteKeyRepository: OfflineRemoteKeyRepository, + private val dbArticleRepository: RestArticleRepository, + private val database: NewsPortalDatabase +) : CommentRepository { + override suspend fun insertComment(comment: Comment) { + service.createComment(comment.toCommentRemote()).toComment() + } + + override suspend fun updateComment(comment: Comment) { + comment.id?.let { service.updateComment(it, comment.toCommentRemote()).toComment() } + } + + override suspend fun deleteComment(comment: Comment) { + comment.id?.let { service.deleteComment(it).toComment() } + } + + override suspend fun getAllComments(): List { + val existComms = dbCommentRepository.getAllComments().associateBy { it.id }.toMutableMap() + + service.getAllComments() + .map { it.toComment() } + .forEach { comm -> + val existComm = existComms[comm.id] + if (existComm == null) { + dbCommentRepository.insertComment(comm) + } else if (existComm != comm) { + dbCommentRepository.updateComment(comm) + } + existComms[comm.id] = comm + } + + return existComms.map { it.value }.sortedBy { it.id } + } + + override suspend fun getCountComment(idArticle: Int?): Int? { + return idArticle?.let { service.getCountComment(it).size } + } + + override suspend fun getUser(commId : Int) : User? = + commId?.let { service.getUser(it).toUser() } + + + override fun getComments(): Flow> { + val pagingSourceFactory = { dbCommentRepository.getAllCommentsPagingSource() } + + @OptIn(ExperimentalPagingApi::class) + return Pager( + config = PagingConfig( + pageSize = AppContainer.LIMIT, + enablePlaceholders = false + ), + remoteMediator = CommentRemoteMediator( + service, + dbCommentRepository, + dbRemoteKeyRepository, + dbArticleRepository, + database, + ), + pagingSourceFactory = pagingSourceFactory + ).flow + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/repository/RestTagRepository.kt b/app/src/main/java/com/example/pmulabs/api/repository/RestTagRepository.kt new file mode 100644 index 0000000..68eff4d --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/repository/RestTagRepository.kt @@ -0,0 +1,80 @@ +package com.example.pmulabs.api.repository + +import androidx.paging.ExperimentalPagingApi +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.mediator.TagRemoteMediator +import com.example.pmulabs.api.model.toTag +import com.example.pmulabs.api.model.toTagRemote +import com.example.pmulabs.room.AppContainer +import com.example.pmulabs.room.database.NewsPortalDatabase +import com.example.pmulabs.room.models.Tag +import com.example.pmulabs.room.repository.OfflineRemoteKeyRepository +import com.example.pmulabs.room.repository.OfflineTagRepository +import com.example.pmulabs.room.repository.TagRepository +import kotlinx.coroutines.flow.Flow + +class RestTagRepository( + private val service: NewsPortalService, + private val dbTagRepository: OfflineTagRepository, + private val dbRemoteKeyRepository: OfflineRemoteKeyRepository, + private val database: NewsPortalDatabase +) : TagRepository { + override suspend fun insertTag(tag: Tag) { + service.createTag(tag.toTagRemote()).toTag() + } + + override suspend fun updateTag(tag: Tag) { + tag.id?.let { service.updateTag(it, tag.toTagRemote()).toTag() } + } + + override suspend fun deleteTag(tag: Tag) { + tag.id?.let { service.deleteTag(it).toTag() } + } + + override suspend fun getAllTags(): List { + val existTags = dbTagRepository.getAllTags().associateBy { it.id }.toMutableMap() + + service.getAllTags() + .map { it.toTag() } + .forEach { tag -> + val existTag = existTags[tag.id] + if (existTag == null) { + dbTagRepository.insertTag(tag) + } else if (existTag != tag) { + dbTagRepository.updateTag(tag) + } + existTags[tag.id] = tag + } + + return existTags.map { it.value }.sortedBy { it.id } + } + + override suspend fun getTagById(idTag: Int): Tag? = + idTag?.let { service.getTag(it).toTag() } + + override suspend fun getTagByName(nameTag: String): Tag? = + nameTag?.let { service.getTagByName(it)[0].toTag() } + + override fun getTags(): Flow> { + val pagingSourceFactory = { dbTagRepository.getAllTagsPagingSource() } + + @OptIn(ExperimentalPagingApi::class) + return Pager( + config = PagingConfig( + pageSize = AppContainer.LIMIT, + enablePlaceholders = false + ), + remoteMediator = TagRemoteMediator( + service, + dbTagRepository, + dbRemoteKeyRepository, + database, + ), + pagingSourceFactory = pagingSourceFactory + ).flow + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/api/repository/RestUserRepository.kt b/app/src/main/java/com/example/pmulabs/api/repository/RestUserRepository.kt new file mode 100644 index 0000000..47cbbd9 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/api/repository/RestUserRepository.kt @@ -0,0 +1,119 @@ +package com.example.pmulabs.api.repository + +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.model.toArticle +import com.example.pmulabs.api.model.toComment +import com.example.pmulabs.api.model.toTag +import com.example.pmulabs.api.model.toUser +import com.example.pmulabs.api.model.toUserRemote +import com.example.pmulabs.room.models.Article +import com.example.pmulabs.room.models.Comment +import com.example.pmulabs.room.models.Tag +import com.example.pmulabs.room.models.User +import com.example.pmulabs.room.repository.OfflineArticleRepository +import com.example.pmulabs.room.repository.OfflineCommentRepository +import com.example.pmulabs.room.repository.OfflineTagRepository +import com.example.pmulabs.room.repository.OfflineUserRepository +import com.example.pmulabs.room.repository.UserRepository + +class RestUserRepository( + private val service: NewsPortalService, + private val dbUserRepository: OfflineUserRepository, + private val dbCommentRepository: OfflineCommentRepository, + private val dbTagRepository: OfflineTagRepository, + private val dbArticleRepository: OfflineArticleRepository +) : UserRepository { + override suspend fun insertUser(user: User) { + service.createUser(user.toUserRemote()).toUser() + } + + override suspend fun updateUser(user: User) { + user.id?.let { service.updateUser(it, user.toUserRemote()).toUser() } + } + + override suspend fun deleteUser(user: User) { + user.id?.let { service.deleteUser(it).toUser() } + } + + override suspend fun getAllUsers(): List { + val existUsers = dbUserRepository.getAllUsers().associateBy { it.id }.toMutableMap() + + service.getUsers() + .map { it.toUser() } + .forEach { user -> + val existUser = existUsers[user.id] + if (existUser == null) { + dbUserRepository.insertUser(user) + } else if (existUser != user) { + dbUserRepository.updateUser(user) + } + existUsers[user.id] = user + } + + return existUsers.map { it.value }.sortedBy { it.id } + } + + override suspend fun getUserById(idUser: Int?): User? = + idUser?.let { service.getUser(it).toUser() } + + + override suspend fun getUserComms(idUser: Int): List { + val existComments = dbUserRepository.getUserComms(idUser).associateBy { it.id }.toMutableMap() + + service.getUserComments(idUser) + .map { it.toComment() } + .forEach { comm -> + if(comm.userId==idUser) { + val existComm = existComments[comm.id] + if (existComm == null) { + dbCommentRepository.insertComment(comm) + } else if (existComm != comm) { + dbCommentRepository.updateComment(comm) + } + existComments[comm.id] = comm + } + } + + return existComments.map { it.value }.sortedBy { it.id } + } + + override suspend fun getUserArticles(idUser: Int): List
{ + val existArticles = dbUserRepository.getUserArticles(idUser).associateBy { it.id }.toMutableMap() + + service.getUserArticles(idUser) + .map { it.toArticle() } + .forEach { art -> + if(art.userId==idUser) { + val existArt = existArticles[art.id] + if (existArt == null) { + dbArticleRepository.insertArticle(art) + } else if (existArt != art) { + dbArticleRepository.updateArticle(art) + } + existArticles[art.id] = art + } + } + + return existArticles.map { it.value }.sortedBy { it.id } + } + + override suspend fun getUserTags(idUser: Int): List { + val existTags = dbUserRepository.getUserTags(idUser).associateBy { it.id }.toMutableMap() + + service.getUserTags(idUser) + .map { it.toTag() } + .forEach { tag -> + if(tag.userId==idUser) { + val existTag = existTags[tag.id] + if (existTag == null) { + dbTagRepository.insertTag(tag) + } else if (existTag != tag) { + dbTagRepository.updateTag(tag) + } + existTags[tag.id] = tag + } + } + + return existTags.map { it.value }.sortedBy { it.id } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/designElem/items/ArticleItem.kt b/app/src/main/java/com/example/pmulabs/designElem/items/ArticleItem.kt index dfd6f66..edccbb7 100644 --- a/app/src/main/java/com/example/pmulabs/designElem/items/ArticleItem.kt +++ b/app/src/main/java/com/example/pmulabs/designElem/items/ArticleItem.kt @@ -68,6 +68,7 @@ import com.example.pmulabs.room.models.Tag import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.ArticleItemViewModel import com.example.pmulabs.viewModels.CurrentUserViewModel +import kotlinx.coroutines.async import kotlinx.coroutines.launch import java.text.SimpleDateFormat @@ -180,7 +181,7 @@ fun ArticleItem(navController: NavController,article: Article, modifier: Modifie text= {Text(text=label)}, onClick = { selectedText = label coroutineScope.launch { - tagId= articleItemViewModel.getTagByName(selectedText).id!! + tagId= articleItemViewModel.getTagByName(selectedText)?.id!! } } ) @@ -242,15 +243,18 @@ fun ArticleItem(navController: NavController,article: Article, modifier: Modifie ), onClick = { openDialog = false - article.text=text - article.title=title - tagName=selectedText - Log.d("Tag",tagId.toString()) - if(tagId!=null) { + article.text = text + article.title = title + tagName = selectedText + Log.d("Tag", tagId.toString()) + if (tagId != null) { article.tagId = tagId } coroutineScope.launch { - articleItemViewModel.updateArticle(article) + val upResult = async { + articleItemViewModel.updateArticle(article) + } + upResult.await() } }, modifier = Modifier diff --git a/app/src/main/java/com/example/pmulabs/designElem/items/CommentItem.kt b/app/src/main/java/com/example/pmulabs/designElem/items/CommentItem.kt index b719db6..f33cdb7 100644 --- a/app/src/main/java/com/example/pmulabs/designElem/items/CommentItem.kt +++ b/app/src/main/java/com/example/pmulabs/designElem/items/CommentItem.kt @@ -1,6 +1,7 @@ package com.example.pmulabs.designElem.items import android.annotation.SuppressLint +import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -51,20 +52,12 @@ import kotlinx.coroutines.launch @SuppressLint("CoroutineCreationDuringComposition", "UnrememberedMutableState") @OptIn(ExperimentalMaterial3Api::class) @Composable -fun CommentItem(navController: NavController,modifier: Modifier = Modifier, comm : Comment,commentItemViewModel: CommentItemViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { +fun CommentItem(navController: NavController, modifier: Modifier = Modifier, comm : Comment, user : User, commentItemViewModel: CommentItemViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { var getUser by remember { mutableStateOf(currentUserViewModel.user) } var openDialog by remember { mutableStateOf(false) } var text by remember { mutableStateOf(comm.text) } val coroutineScope = rememberCoroutineScope() - commentItemViewModel.getUsersByArticle(comm.articleId) - var users by mutableStateOf(commentItemViewModel.userListByArticle) - var user by mutableStateOf(null) - for(item in users){ - if(comm.userId==item.id){ - user=item - } - } if (openDialog) { AlertDialog( @@ -126,7 +119,7 @@ fun CommentItem(navController: NavController,modifier: Modifier = Modifier, comm } }, modifier = Modifier - .padding(start=100.dp) + .padding(start = 100.dp) .fillMaxWidth(0.5f) .height(40.dp) ) { @@ -150,28 +143,29 @@ fun CommentItem(navController: NavController,modifier: Modifier = Modifier, comm .padding(start = 10.dp,top=10.dp) ) { Row() { + Log.d("User",user.toString()) Text( - text = "${user?.nickname}", - color = Color(0xff423a99), - style = TextStyle( - textDecoration = TextDecoration.Underline, - fontSize = 17.sp, - fontWeight = FontWeight.Bold - ), + text = "${user.nickname}", + color = Color(0xff423a99), + style = TextStyle( + textDecoration = TextDecoration.Underline, + fontSize = 17.sp, + fontWeight = FontWeight.Bold + ), ) if(getUser?.id==comm.userId) { Icon( - modifier=Modifier + modifier= Modifier .requiredHeight(20.dp) .clickable { - openDialog=true + openDialog = true }, imageVector = Icons.Filled.Edit, contentDescription = "Update Icon", tint = Color(0xff423a99) ) Icon( - modifier=Modifier + modifier= Modifier .requiredHeight(20.dp) .clickable { coroutineScope.launch { diff --git a/app/src/main/java/com/example/pmulabs/room/AppContainer.kt b/app/src/main/java/com/example/pmulabs/room/AppContainer.kt index 99bd426..15da5d2 100644 --- a/app/src/main/java/com/example/pmulabs/room/AppContainer.kt +++ b/app/src/main/java/com/example/pmulabs/room/AppContainer.kt @@ -1,38 +1,78 @@ package com.example.pmulabs.room import android.content.Context +import com.example.pmulabs.api.NewsPortalService +import com.example.pmulabs.api.repository.RestArticleRepository +import com.example.pmulabs.api.repository.RestCommentRepository +import com.example.pmulabs.api.repository.RestTagRepository +import com.example.pmulabs.api.repository.RestUserRepository import com.example.pmulabs.room.database.NewsPortalDatabase -import com.example.pmulabs.room.repository.ArticleRepository -import com.example.pmulabs.room.repository.CommentRepository import com.example.pmulabs.room.repository.OfflineArticleRepository import com.example.pmulabs.room.repository.OfflineCommentRepository +import com.example.pmulabs.room.repository.OfflineRemoteKeyRepository import com.example.pmulabs.room.repository.OfflineTagRepository import com.example.pmulabs.room.repository.OfflineUserRepository -import com.example.pmulabs.room.repository.TagRepository -import com.example.pmulabs.room.repository.UserRepository interface AppContainer { - val userRepository: UserRepository - val articleRepository: ArticleRepository - val tagRepository: TagRepository - val commentRepository: CommentRepository + val userRestRepository: RestUserRepository + val tagRestRepository: RestTagRepository + val articleRestRepository: RestArticleRepository + val commentRestRepository: RestCommentRepository + companion object { + const val TIMEOUT = 5000L + const val LIMIT = 10 + } } class AppDataContainer(private val context: Context) : AppContainer { - override val userRepository: UserRepository by lazy { + private val userRepository: OfflineUserRepository by lazy { OfflineUserRepository(NewsPortalDatabase.getInstance(context).userDao()) } - override val articleRepository: ArticleRepository by lazy { + private val articleRepository: OfflineArticleRepository by lazy { OfflineArticleRepository(NewsPortalDatabase.getInstance(context).articleDao()) } - override val tagRepository: TagRepository by lazy { + private val tagRepository: OfflineTagRepository by lazy { OfflineTagRepository(NewsPortalDatabase.getInstance(context).tagDao()) } - override val commentRepository: CommentRepository by lazy { + private val commentRepository: OfflineCommentRepository by lazy { OfflineCommentRepository(NewsPortalDatabase.getInstance(context).commentDao()) } - - companion object { - const val TIMEOUT = 5000L + private val remoteKeyRepository: OfflineRemoteKeyRepository by lazy { + OfflineRemoteKeyRepository(NewsPortalDatabase.getInstance(context).remoteKeysDao()) + } + override val userRestRepository: RestUserRepository by lazy { + RestUserRepository( + NewsPortalService.getInstance(), + userRepository, + commentRepository, + tagRepository, + articleRepository + ) + } + override val tagRestRepository: RestTagRepository by lazy { + RestTagRepository( + NewsPortalService.getInstance(), + tagRepository, + remoteKeyRepository, + NewsPortalDatabase.getInstance(context) + ) + } + override val articleRestRepository: RestArticleRepository by lazy { + RestArticleRepository( + NewsPortalService.getInstance(), + articleRepository, + remoteKeyRepository, + tagRestRepository, + NewsPortalDatabase.getInstance(context) + ) + } + override val commentRestRepository: RestCommentRepository by lazy { + RestCommentRepository( + NewsPortalService.getInstance(), + commentRepository, + remoteKeyRepository, + articleRestRepository, + NewsPortalDatabase.getInstance(context) + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/dao/ArticleDao.kt b/app/src/main/java/com/example/pmulabs/room/dao/ArticleDao.kt index 962c36c..794a563 100644 --- a/app/src/main/java/com/example/pmulabs/room/dao/ArticleDao.kt +++ b/app/src/main/java/com/example/pmulabs/room/dao/ArticleDao.kt @@ -1,5 +1,6 @@ package com.example.pmulabs.room.dao +import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert @@ -11,20 +12,23 @@ import kotlinx.coroutines.flow.Flow @Dao interface ArticleDao { @Query("select * from article") - fun getAll(): Flow> + fun getAll(): List
@Query("select * from article where article.id = :idArticle") fun getArticleById(idArticle: Int): Flow
- @Query("SELECT * FROM article ORDER BY id DESC LIMIT :limit OFFSET :offset") - suspend fun getArticles(limit: Int, offset: Int): List
+ @Query("SELECT * FROM article ORDER BY id ASC") + fun getArticles(): PagingSource @Insert - suspend fun insert(article: Article) + suspend fun insert(vararg article: Article) @Update suspend fun update(article: Article) @Delete suspend fun delete(article: Article) + + @Query("DELETE FROM tag") + suspend fun deleteAll() } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/dao/CommentDao.kt b/app/src/main/java/com/example/pmulabs/room/dao/CommentDao.kt index 90f2d5a..1615c53 100644 --- a/app/src/main/java/com/example/pmulabs/room/dao/CommentDao.kt +++ b/app/src/main/java/com/example/pmulabs/room/dao/CommentDao.kt @@ -1,30 +1,38 @@ package com.example.pmulabs.room.dao +import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert import androidx.room.Query import androidx.room.Update import com.example.pmulabs.room.models.Comment +import com.example.pmulabs.room.models.User import kotlinx.coroutines.flow.Flow @Dao interface CommentDao { @Query("select * from comment") - fun getAll(): Flow> + fun getAll(): List @Query("select COUNT(*) from comment WHERE comment.text!='' AND comment.article_id= :idArticle") fun getCountComment(idArticle : Int?) : Int - @Query("SELECT * FROM comment ORDER BY id DESC LIMIT :limit OFFSET :offset") - suspend fun getComments(limit: Int, offset: Int): List + @Query("SELECT * FROM comment ORDER BY id ASC") + fun getComments(): PagingSource + + @Query("SELECT * FROM user WHERE user.id=:commId") + fun getUser(commId:Int): Flow @Insert - suspend fun insert(comment: Comment) + suspend fun insert(vararg comment: Comment) @Update suspend fun update(comment: Comment) @Delete suspend fun delete(comment: Comment) + + @Query("DELETE FROM tag") + suspend fun deleteAll() } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/dao/RemoteKeysDao.kt b/app/src/main/java/com/example/pmulabs/room/dao/RemoteKeysDao.kt new file mode 100644 index 0000000..a3c7cf0 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/room/dao/RemoteKeysDao.kt @@ -0,0 +1,20 @@ +package com.example.pmulabs.room.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.example.pmulabs.room.models.RemoteKeyType +import com.example.pmulabs.room.models.RemoteKeys + +@Dao +interface RemoteKeysDao { + @Query("SELECT * FROM remote_keys WHERE entityId = :entityId AND type = :type") + suspend fun getRemoteKeys(entityId: Int, type: RemoteKeyType): RemoteKeys? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertAll(remoteKey: List) + + @Query("DELETE FROM remote_keys WHERE type = :type") + suspend fun clearRemoteKeys(type: RemoteKeyType) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/dao/TagDao.kt b/app/src/main/java/com/example/pmulabs/room/dao/TagDao.kt index 39aeb88..d9d9ca4 100644 --- a/app/src/main/java/com/example/pmulabs/room/dao/TagDao.kt +++ b/app/src/main/java/com/example/pmulabs/room/dao/TagDao.kt @@ -1,5 +1,6 @@ package com.example.pmulabs.room.dao +import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert @@ -11,7 +12,7 @@ import kotlinx.coroutines.flow.Flow @Dao interface TagDao { @Query("select * from tag") - fun getAll(): Flow> + fun getAll(): List @Query("select * from tag where tag.id = :idTag") fun getTagById(idTag: Int): Flow @@ -19,15 +20,18 @@ interface TagDao { @Query("select * from tag where tag.title = :nameTag") fun getTagByName(nameTag: String): Flow - @Query("SELECT * FROM tag ORDER BY id ASC LIMIT :limit OFFSET :offset") - suspend fun getTags(limit: Int, offset: Int): List + @Query("SELECT * FROM tag ORDER BY id ASC") + fun getTags(): PagingSource @Insert - suspend fun insert(tag: Tag) + suspend fun insert(vararg tag: Tag) @Update suspend fun update(tag: Tag) @Delete suspend fun delete(tag: Tag) + + @Query("DELETE FROM tag") + suspend fun deleteAll() } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/dao/UserDao.kt b/app/src/main/java/com/example/pmulabs/room/dao/UserDao.kt index 72327a6..a99d234 100644 --- a/app/src/main/java/com/example/pmulabs/room/dao/UserDao.kt +++ b/app/src/main/java/com/example/pmulabs/room/dao/UserDao.kt @@ -14,19 +14,19 @@ import kotlinx.coroutines.flow.Flow @Dao interface UserDao { @Query("select * from user") - fun getAll(): Flow> + suspend fun getAll(): List @Query("select * from user where user.id = :idUser") fun getUserById(idUser: Int?): Flow @Query("select * from comment WHERE comment.text!='' AND comment.user_id= :idUser") - fun getUserComms(idUser: Int): Flow> + suspend fun getUserComms(idUser: Int): List @Query("select * from article WHERE article.text!='' AND article.user_id= :idUser") - fun getUserArticles(idUser: Int): Flow> + suspend fun getUserArticles(idUser: Int): List
@Query("select * from tag WHERE tag.title!='' AND tag.user_id= :idUser") - fun getUserTags(idUser: Int): Flow> + suspend fun getUserTags(idUser: Int): List @Insert suspend fun insert(user: User) diff --git a/app/src/main/java/com/example/pmulabs/room/database/NewsPortalDatabase.kt b/app/src/main/java/com/example/pmulabs/room/database/NewsPortalDatabase.kt index 8f7da07..6d16f8d 100644 --- a/app/src/main/java/com/example/pmulabs/room/database/NewsPortalDatabase.kt +++ b/app/src/main/java/com/example/pmulabs/room/database/NewsPortalDatabase.kt @@ -4,30 +4,29 @@ import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase -import androidx.sqlite.db.SupportSQLiteDatabase import com.example.pmulabs.room.dao.ArticleDao import com.example.pmulabs.room.dao.CommentDao +import com.example.pmulabs.room.dao.RemoteKeysDao import com.example.pmulabs.room.dao.TagDao import com.example.pmulabs.room.dao.UserDao import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Comment +import com.example.pmulabs.room.models.RemoteKeys import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.User -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import java.util.Date -@Database(entities = [User::class, Tag::class, Comment::class, Article::class], version = 5, exportSchema = false) +@Database(entities = [RemoteKeys::class, User::class, Tag::class, Comment::class, Article::class], version = 5, exportSchema = false) abstract class NewsPortalDatabase : RoomDatabase() { abstract fun userDao(): UserDao abstract fun tagDao(): TagDao abstract fun commentDao(): CommentDao abstract fun articleDao(): ArticleDao + abstract fun remoteKeysDao(): RemoteKeysDao companion object { - private const val DB_NAME: String = "news-portal" + private const val DB_NAME: String = "newsportaldb" @Volatile private var INSTANCE: NewsPortalDatabase? = null @@ -41,12 +40,12 @@ abstract class NewsPortalDatabase : RoomDatabase() { userDao.insert(user2) userDao.insert(user3) val tagDao = database.tagDao() - val tag1 = Tag(1, "Тег_1",2) - val tag2 = Tag(2, "Тег_2",1) - val tag3 = Tag(3, "Тег_3",3) - val tag4 = Tag(4, "Тег_4",2) - val tag5 = Tag(5, "Тег_5",1) - val tag6 = Tag(6, "Тег_6",3) + val tag1 = Tag(id=1, title = "Тег_1", userId = 2) + val tag2 = Tag(id=2, title ="Тег_2",userId = 1) + val tag3 = Tag(id=3, title ="Тег_3",userId = 3) + val tag4 = Tag(id=4, title ="Тег_4",userId = 2) + val tag5 = Tag(id=5, title ="Тег_5",userId = 1) + val tag6 = Tag(id=6, title ="Тег_6",userId = 3) tagDao.insert(tag1) tagDao.insert(tag2) tagDao.insert(tag3) @@ -103,14 +102,14 @@ abstract class NewsPortalDatabase : RoomDatabase() { NewsPortalDatabase::class.java, DB_NAME ) - .addCallback(object : Callback() { + /*.addCallback(object : Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) CoroutineScope(Dispatchers.IO).launch { populateDatabase() } } - }) + })*/ .build() .also { INSTANCE = it } } diff --git a/app/src/main/java/com/example/pmulabs/room/models/RemoteKeys.kt b/app/src/main/java/com/example/pmulabs/room/models/RemoteKeys.kt new file mode 100644 index 0000000..656b68e --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/room/models/RemoteKeys.kt @@ -0,0 +1,27 @@ +package com.example.pmulabs.room.models + +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.TypeConverter +import androidx.room.TypeConverters + +enum class RemoteKeyType(private val type: String) { + ARTICLE(Article::class.simpleName ?: "Article"), + TAG(Tag::class.simpleName ?: "Tag"), + COMMENT(Comment::class.simpleName ?: "Comment"); + + @TypeConverter + fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value } + + @TypeConverter + fun fromRemoteKeyType(value: RemoteKeyType) = value.type +} + +@Entity(tableName = "remote_keys") +data class RemoteKeys( + @PrimaryKey val entityId: Int, + @TypeConverters(RemoteKeyType::class) + val type: RemoteKeyType, + val prevKey: Int?, + val nextKey: Int? +) \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/models/Tag.kt b/app/src/main/java/com/example/pmulabs/room/models/Tag.kt index 8be75b8..d6325c7 100644 --- a/app/src/main/java/com/example/pmulabs/room/models/Tag.kt +++ b/app/src/main/java/com/example/pmulabs/room/models/Tag.kt @@ -10,10 +10,10 @@ import androidx.room.PrimaryKey foreignKeys = [ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["user_id"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE)], indices = [Index(value = ["title"], unique = true)]) data class Tag( - @PrimaryKey(autoGenerate = true) - val id: Int?, @ColumnInfo(name = "title") var title: String, + @PrimaryKey(autoGenerate = true) + val id: Int?, @ColumnInfo(name = "user_id") val userId: Int ) { diff --git a/app/src/main/java/com/example/pmulabs/room/pagingSource/ArticlePagingSource.kt b/app/src/main/java/com/example/pmulabs/room/pagingSource/ArticlePagingSource.kt deleted file mode 100644 index d1ad4fa..0000000 --- a/app/src/main/java/com/example/pmulabs/room/pagingSource/ArticlePagingSource.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.pmulabs.room.pagingSource - -import android.util.Log -import androidx.paging.PagingSource -import androidx.paging.PagingState -import com.example.pmulabs.room.dao.ArticleDao -import com.example.pmulabs.room.models.Article -import kotlinx.coroutines.delay - -class ArticlePagingSource( - private val dao: ArticleDao, -) : PagingSource() { - override suspend fun load(params: LoadParams): LoadResult { - val page = params.key ?: 0 - - return try { - Log.d("MainPagingSource", "load: $page") - val entities = dao.getArticles(params.loadSize, page * params.loadSize) - if (page != 0) delay(1000) - LoadResult.Page( - data = entities, - prevKey = if (page == 0) null else page - 1, - nextKey = if (entities.isEmpty()) null else page + 1 - ) - } catch (e: Exception) { - LoadResult.Error(e) - } - } - - override val jumpingSupported: Boolean = true - - override fun getRefreshKey(state: PagingState): Int? { - return state.anchorPosition?.let { anchorPosition -> - val anchorPage = state.closestPageToPosition(anchorPosition) - anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/pagingSource/CommentPagingSource.kt b/app/src/main/java/com/example/pmulabs/room/pagingSource/CommentPagingSource.kt deleted file mode 100644 index d32dadd..0000000 --- a/app/src/main/java/com/example/pmulabs/room/pagingSource/CommentPagingSource.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.pmulabs.room.pagingSource - -import android.util.Log -import androidx.paging.PagingSource -import androidx.paging.PagingState -import com.example.pmulabs.room.dao.CommentDao -import com.example.pmulabs.room.models.Comment -import kotlinx.coroutines.delay - -class CommentPagingSource( - private val dao: CommentDao, -) : PagingSource() { - override suspend fun load(params: LoadParams): LoadResult { - val page = params.key ?: 0 - - return try { - Log.d("MainPagingSource", "load: $page") - val entities = dao.getComments(params.loadSize, page * params.loadSize) - if (page != 0) delay(1000) - LoadResult.Page( - data = entities, - prevKey = if (page == 0) null else page - 1, - nextKey = if (entities.isEmpty()) null else page + 1 - ) - } catch (e: Exception) { - LoadResult.Error(e) - } - } - - override val jumpingSupported: Boolean = true - - override fun getRefreshKey(state: PagingState): Int? { - return state.anchorPosition?.let { anchorPosition -> - val anchorPage = state.closestPageToPosition(anchorPosition) - anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/pagingSource/TagPagingSource.kt b/app/src/main/java/com/example/pmulabs/room/pagingSource/TagPagingSource.kt deleted file mode 100644 index d50e430..0000000 --- a/app/src/main/java/com/example/pmulabs/room/pagingSource/TagPagingSource.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.pmulabs.room.pagingSource - -import android.util.Log -import androidx.paging.PagingSource -import androidx.paging.PagingState -import com.example.pmulabs.room.dao.TagDao -import com.example.pmulabs.room.models.Tag -import kotlinx.coroutines.delay - -class TagPagingSource( - private val dao: TagDao, -) : PagingSource() { - override suspend fun load(params: LoadParams): LoadResult { - val page = params.key ?: 0 - - return try { - Log.d("MainPagingSource", "load: $page") - val entities = dao.getTags(params.loadSize, page * params.loadSize) - if (page != 0) delay(1000) - LoadResult.Page( - data = entities, - prevKey = if (page == 0) null else page - 1, - nextKey = if (entities.isEmpty()) null else page + 1 - ) - } catch (e: Exception) { - LoadResult.Error(e) - } - } - - override val jumpingSupported: Boolean = true - - override fun getRefreshKey(state: PagingState): Int? { - return state.anchorPosition?.let { anchorPosition -> - val anchorPage = state.closestPageToPosition(anchorPosition) - anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/ArticleRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/ArticleRepository.kt index 18d6258..f37db2a 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/ArticleRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/ArticleRepository.kt @@ -8,7 +8,7 @@ interface ArticleRepository { suspend fun insertArticle(article: Article) suspend fun updateArticle(article: Article) suspend fun deleteArticle(article: Article) - fun getAllArticles(): Flow> - fun getArticleById(idArticle: Int): Flow
+ suspend fun getAllArticles(): List
+ suspend fun getArticleById(idArticle: Int): Article? fun getArticles(): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/CommentRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/CommentRepository.kt index ee74477..2415320 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/CommentRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/CommentRepository.kt @@ -2,13 +2,15 @@ package com.example.pmulabs.room.repository import androidx.paging.PagingData import com.example.pmulabs.room.models.Comment +import com.example.pmulabs.room.models.User import kotlinx.coroutines.flow.Flow interface CommentRepository { suspend fun insertComment(comment: Comment) suspend fun updateComment(comment: Comment) suspend fun deleteComment(comment: Comment) - fun getAllComments(): Flow> - fun getCountComment(idArticle : Int?) : Int + suspend fun getAllComments(): List + suspend fun getCountComment(idArticle : Int?) : Int? fun getComments(): Flow> + suspend fun getUser(commId: Int): User? } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/OfflineArticleRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/OfflineArticleRepository.kt index e37cc26..2813072 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/OfflineArticleRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/OfflineArticleRepository.kt @@ -3,17 +3,29 @@ package com.example.pmulabs.room.repository import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData +import androidx.paging.PagingSource import com.example.pmulabs.room.dao.ArticleDao import com.example.pmulabs.room.models.Article -import com.example.pmulabs.room.pagingSource.ArticlePagingSource import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first class OfflineArticleRepository(private val articleDao: ArticleDao) : ArticleRepository { override suspend fun insertArticle(article: Article) = articleDao.insert(article) override suspend fun updateArticle(article: Article) = articleDao.update(article) override suspend fun deleteArticle(article: Article) = articleDao.delete(article) - override fun getAllArticles(): Flow> = articleDao.getAll() - override fun getArticleById(idArticle: Int): Flow
= articleDao.getArticleById(idArticle) - override fun getArticles(): Flow> = Pager(config = PagingConfig(pageSize = 4, jumpThreshold = 4, initialLoadSize = 4) ){ ArticlePagingSource(articleDao) }.flow + override suspend fun getAllArticles(): List
= articleDao.getAll() + override suspend fun getArticleById(idArticle: Int): Article? = articleDao.getArticleById(idArticle).first() + override fun getArticles(): Flow> = Pager( + config = PagingConfig( + pageSize = 4, + enablePlaceholders = false + ), + pagingSourceFactory = articleDao::getArticles + ).flow + fun getAllArticlesPagingSource(): PagingSource = articleDao.getArticles() + suspend fun clearArticles() = articleDao.deleteAll() + + suspend fun insertArticles(articles: List
) = + articleDao.insert(*articles.toTypedArray()) } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/OfflineCommentRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/OfflineCommentRepository.kt index c3cd1d7..7e504a3 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/OfflineCommentRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/OfflineCommentRepository.kt @@ -3,17 +3,34 @@ package com.example.pmulabs.room.repository import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData +import androidx.paging.PagingSource import com.example.pmulabs.room.dao.CommentDao import com.example.pmulabs.room.models.Comment -import com.example.pmulabs.room.pagingSource.CommentPagingSource import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first class OfflineCommentRepository(private val commentDao: CommentDao) : CommentRepository { override suspend fun insertComment(comment: Comment) = commentDao.insert(comment) override suspend fun updateComment(comment: Comment) = commentDao.update(comment) override suspend fun deleteComment(comment: Comment) = commentDao.delete(comment) - override fun getAllComments(): Flow> = commentDao.getAll() - override fun getCountComment(idArticle : Int?) : Int = commentDao.getCountComment(idArticle) - override fun getComments(): Flow> = Pager(config = PagingConfig(pageSize = 4, jumpThreshold = 4, initialLoadSize = 4) ){ CommentPagingSource(commentDao) }.flow + override suspend fun getAllComments(): List = commentDao.getAll() + override suspend fun getCountComment(idArticle : Int?) : Int = commentDao.getCountComment(idArticle) + override fun getComments(): Flow> = Pager( + config = PagingConfig( + pageSize = 20, + enablePlaceholders = false + ), + pagingSourceFactory =commentDao::getComments + ).flow + + fun getAllCommentsPagingSource(): PagingSource = commentDao.getComments() + + suspend fun clearComments() = commentDao.deleteAll() + + override suspend fun getUser(commId: Int) = commentDao.getUser(commId).first() + + suspend fun insertComments(comments: List) { + commentDao.insert(*comments.toTypedArray()) + } +} -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/OfflineRemoteKeyRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/OfflineRemoteKeyRepository.kt new file mode 100644 index 0000000..f942dc3 --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/room/repository/OfflineRemoteKeyRepository.kt @@ -0,0 +1,16 @@ +package com.example.pmulabs.room.repository + +import com.example.pmulabs.room.dao.RemoteKeysDao +import com.example.pmulabs.room.models.RemoteKeyType +import com.example.pmulabs.room.models.RemoteKeys + +class OfflineRemoteKeyRepository(private val remoteKeysDao: RemoteKeysDao) : RemoteKeyRepository { + override suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType) = + remoteKeysDao.getRemoteKeys(id, type) + + override suspend fun createRemoteKeys(remoteKeys: List) = + remoteKeysDao.insertAll(remoteKeys) + + override suspend fun deleteRemoteKey(type: RemoteKeyType) = + remoteKeysDao.clearRemoteKeys(type) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/OfflineTagRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/OfflineTagRepository.kt index 16d73a4..ad5dfdb 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/OfflineTagRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/OfflineTagRepository.kt @@ -3,18 +3,32 @@ package com.example.pmulabs.room.repository import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData +import androidx.paging.PagingSource +import com.example.pmulabs.room.AppContainer import com.example.pmulabs.room.dao.TagDao import com.example.pmulabs.room.models.Tag -import com.example.pmulabs.room.pagingSource.TagPagingSource import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first class OfflineTagRepository(private val tagDao: TagDao) : TagRepository { override suspend fun insertTag(tag: Tag) = tagDao.insert(tag) override suspend fun updateTag(tag: Tag) = tagDao.update(tag) override suspend fun deleteTag(tag: Tag) = tagDao.delete(tag) - override fun getAllTags(): Flow> = tagDao.getAll() - override fun getTagById(idTag: Int): Flow = tagDao.getTagById(idTag) - override fun getTagByName(nameTag: String): Flow = tagDao.getTagByName(nameTag) - override fun getTags(): Flow> = Pager(config = PagingConfig(pageSize = 4, jumpThreshold = 4, initialLoadSize = 4) ){ TagPagingSource(tagDao) }.flow + override suspend fun getAllTags(): List = tagDao.getAll() + override suspend fun getTagById(idTag: Int): Tag? = tagDao.getTagById(idTag).first() + override suspend fun getTagByName(nameTag: String): Tag? = tagDao.getTagByName(nameTag).first() + override fun getTags(): Flow> = Pager( + config = PagingConfig( + pageSize = AppContainer.LIMIT, + enablePlaceholders = false + ), + pagingSourceFactory = tagDao::getTags + ).flow + fun getAllTagsPagingSource(): PagingSource = tagDao.getTags() + + suspend fun clearTags() = tagDao.deleteAll() + + suspend fun insertTags(tags: List) = + tagDao.insert(*tags.toTypedArray()) } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/OfflineUserRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/OfflineUserRepository.kt index eaa82e5..f765989 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/OfflineUserRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/OfflineUserRepository.kt @@ -5,15 +5,15 @@ import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Comment import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.User -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first class OfflineUserRepository(private val userDao: UserDao) : UserRepository { override suspend fun insertUser(user: User) = userDao.insert(user) override suspend fun updateUser(user: User) = userDao.update(user) override suspend fun deleteUser(user: User) = userDao.delete(user) - override fun getAllUsers(): Flow> = userDao.getAll() - override fun getUserById(idUser: Int?): Flow = userDao.getUserById(idUser) - override fun getUserComms(idUser: Int): Flow> = userDao.getUserComms(idUser) - override fun getUserArticles(idUser: Int): Flow> = userDao.getUserArticles(idUser) - override fun getUserTags(idUser: Int): Flow> = userDao.getUserTags(idUser) + override suspend fun getAllUsers(): List = userDao.getAll() + override suspend fun getUserById(idUser: Int?): User? = userDao.getUserById(idUser).first() + override suspend fun getUserComms(idUser: Int): List = userDao.getUserComms(idUser) + override suspend fun getUserArticles(idUser: Int): List
= userDao.getUserArticles(idUser) + override suspend fun getUserTags(idUser: Int): List = userDao.getUserTags(idUser) } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/RemoteKeyRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/RemoteKeyRepository.kt new file mode 100644 index 0000000..26a423f --- /dev/null +++ b/app/src/main/java/com/example/pmulabs/room/repository/RemoteKeyRepository.kt @@ -0,0 +1,10 @@ +package com.example.pmulabs.room.repository + +import com.example.pmulabs.room.models.RemoteKeyType +import com.example.pmulabs.room.models.RemoteKeys + +interface RemoteKeyRepository { + suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys? + suspend fun createRemoteKeys(remoteKeys: List) + suspend fun deleteRemoteKey(type: RemoteKeyType) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/TagRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/TagRepository.kt index 762d470..cd06f6f 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/TagRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/TagRepository.kt @@ -8,8 +8,8 @@ interface TagRepository { suspend fun insertTag(tag: Tag) suspend fun updateTag(tag: Tag) suspend fun deleteTag(tag: Tag) - fun getAllTags(): Flow> - fun getTagById(idTag: Int): Flow - fun getTagByName(nameTag: String): Flow + suspend fun getAllTags(): List + suspend fun getTagById(idTag: Int): Tag? + suspend fun getTagByName(nameTag: String): Tag? fun getTags(): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/room/repository/UserRepository.kt b/app/src/main/java/com/example/pmulabs/room/repository/UserRepository.kt index a9c1e6e..2c03030 100644 --- a/app/src/main/java/com/example/pmulabs/room/repository/UserRepository.kt +++ b/app/src/main/java/com/example/pmulabs/room/repository/UserRepository.kt @@ -4,15 +4,14 @@ import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Comment import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.User -import kotlinx.coroutines.flow.Flow interface UserRepository { suspend fun insertUser(user: User) suspend fun updateUser(user: User) suspend fun deleteUser(user: User) - fun getAllUsers(): Flow> - fun getUserById(idUser: Int?): Flow - fun getUserComms(idUser: Int): Flow> - fun getUserArticles(idUser: Int): Flow> - fun getUserTags(idUser: Int): Flow> + suspend fun getAllUsers(): List + suspend fun getUserById(idUser: Int?): User? + suspend fun getUserComms(idUser: Int): List + suspend fun getUserArticles(idUser: Int): List
+ suspend fun getUserTags(idUser: Int): List } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/screensMobile/ArticlePageScreen.kt b/app/src/main/java/com/example/pmulabs/screensMobile/ArticlePageScreen.kt index 070c0b3..b8c0cea 100644 --- a/app/src/main/java/com/example/pmulabs/screensMobile/ArticlePageScreen.kt +++ b/app/src/main/java/com/example/pmulabs/screensMobile/ArticlePageScreen.kt @@ -65,7 +65,7 @@ import java.util.Date @OptIn(ExperimentalMaterial3Api::class) @Composable fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifier,articlePageScreenViewModel: ArticlePageScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { - + articlePageScreenViewModel.setUserList() var id = navController.currentBackStackEntry?.arguments?.getString(ARTICLE_ARGUMENT_KEY).toString() try { @@ -89,6 +89,8 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie val publishDate = formatter.format(Date(article?.publishDate ?: 0)) val comms = articlePageScreenViewModel.comments.collectAsLazyPagingItems() + var users = mutableStateOf( articlePageScreenViewModel.userList) + Log.d("ListOfUsers", users.toString()) var getUser by remember { mutableStateOf(currentUserViewModel.user) } val coroutineScope = rememberCoroutineScope() @@ -257,6 +259,7 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie items(count = comms.itemCount) { index -> val comm = comms[index] + val user = comm?.userId?.let { users.value.get(it-1) }!! if (comm != null) { if (comm.articleId == article?.id && comm.text != "") { Spacer(modifier = Modifier.padding(0.dp)) @@ -265,7 +268,7 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie modifier = Modifier .border(BorderStroke(3.dp, Color(0xff423a99))), color = Color(0xff423a99) ) - CommentItem(navController,comm = comm, currentUserViewModel = currentUserViewModel) + CommentItem(navController,comm = comm,user=user, currentUserViewModel = currentUserViewModel) } } } diff --git a/app/src/main/java/com/example/pmulabs/screensMobile/MainScreen.kt b/app/src/main/java/com/example/pmulabs/screensMobile/MainScreen.kt index e964675..ee2562f 100644 --- a/app/src/main/java/com/example/pmulabs/screensMobile/MainScreen.kt +++ b/app/src/main/java/com/example/pmulabs/screensMobile/MainScreen.kt @@ -65,7 +65,9 @@ fun MainScreen(navController: NavController, modifier: Modifier = Modifier, arti items(count = articles.itemCount) { index -> val article = articles[index] if (article != null) { - ArticleItem(navController=navController,article = article, currentUserViewModel = currentUserViewModel, onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))}) + ArticleItem(navController=navController,article = article, currentUserViewModel = currentUserViewModel, onArticleClick = { + navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString())) + }) } } articles.apply { diff --git a/app/src/main/java/com/example/pmulabs/screensMobile/ProfileScreen.kt b/app/src/main/java/com/example/pmulabs/screensMobile/ProfileScreen.kt index 0f2ca93..c676190 100644 --- a/app/src/main/java/com/example/pmulabs/screensMobile/ProfileScreen.kt +++ b/app/src/main/java/com/example/pmulabs/screensMobile/ProfileScreen.kt @@ -30,7 +30,6 @@ import androidx.compose.material.icons.filled.ArrowDropUp import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonColors -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api @@ -52,7 +51,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle @@ -63,10 +61,7 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.toSize import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController -import androidx.paging.LoadState -import androidx.paging.compose.collectAsLazyPagingItems import com.example.pmulabs.R -import com.example.pmulabs.basecomponents.navigate.BottomBarScreen import com.example.pmulabs.designElem.elem.ValidateEmail import com.example.pmulabs.designElem.elem.isValidEmail import com.example.pmulabs.room.models.Article @@ -83,15 +78,14 @@ import java.util.Date @OptIn(ExperimentalMaterial3Api::class) @Composable fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,articleScreenViewModel: ArticleScreenViewModel= viewModel(factory = AppViewModelProvider.Factory),tagItemViewModel: TagItemViewModel= viewModel(factory = AppViewModelProvider.Factory),articlePageScreenViewModel: ArticlePageScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { - val context = LocalContext.current + + articleScreenViewModel.setArticleList() var getUser by remember { mutableStateOf(currentUserViewModel.user) } var openDialogUser by remember { mutableStateOf(false) } var email by remember { mutableStateOf(getUser?.email) } var password by remember { mutableStateOf(getUser?.password) } var nickname by remember { mutableStateOf(getUser?.nickname) } - val getArticles = articleScreenViewModel.articles.collectAsLazyPagingItems() - val getComms = articlePageScreenViewModel.comments.collectAsLazyPagingItems() - val getTags = tagItemViewModel.tags.collectAsLazyPagingItems() + val getArticles = articleScreenViewModel.getArticles val coroutineScope = rememberCoroutineScope() articlePageScreenViewModel.setTagList() @@ -178,7 +172,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar selectedText = label coroutineScope.launch { tagId = - articlePageScreenViewModel.getTagByName(selectedText).id!! + articlePageScreenViewModel.getTagByName(selectedText)?.id!! } } ) @@ -523,159 +517,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar } } } - item { - Box( - modifier = Modifier - .offset( - x = 9.dp, - y = 220.dp - ) - .requiredWidth(width = 393.dp) - .requiredHeight(height = 182.dp) - ) { - Box( - modifier = Modifier - .align(alignment = Alignment.TopStart) - .offset( - x = 0.dp, - y = 27.1240234375.dp - ) - .requiredWidth(width = 393.dp) - .requiredHeight(height = 155.dp) - ) { - Box( - modifier = Modifier - .requiredWidth(width = 393.dp) - .requiredHeight(height = 155.dp) - .clip(shape = RoundedCornerShape(5.dp)) - .background(color = Color.White) - .border( - border = BorderStroke(3.dp, Color(0xffdbdbf1)), - shape = RoundedCornerShape(5.dp) - ) - ) - LazyColumn( - contentPadding = PaddingValues( - top = 28.dp, - bottom = 0.dp, - start = 10.dp, - end = 10.dp - ), - verticalArrangement = Arrangement.spacedBy(1.dp) - ) { - if (getComms.itemCount != 0) { - items(count = getComms.itemCount) { index -> - val comment = getComms[index] - if (comment?.userId == getUser?.id) { - Spacer(modifier = Modifier.padding(5.dp)) - Text( - text = "${comment?.text}", - color = Color(0xff423a99), - style = TextStyle( - fontSize = 15.sp, - fontWeight = FontWeight.Bold - ), - modifier = Modifier - .align(alignment = Alignment.TopStart) - .clickable { - navController.navigate( - BottomBarScreen.ArticlePage.passId( - comment?.articleId.toString() - ) - ) - } - ) - Spacer(modifier = Modifier.padding(5.dp)) - HorizontalDivider( - thickness = 3.dp, - modifier = Modifier - .border(BorderStroke(3.dp, Color(0xffdbdbf1))), - color = Color(0xffdbdbf1) - ) - } - } - getComms.apply { - when { - loadState.refresh is LoadState.Loading -> { - item { - CircularProgressIndicator( - modifier = Modifier.fillParentMaxSize(), - color = Color(0xff423a99) - ) - } - } - - loadState.append is LoadState.Loading -> { - item { - CircularProgressIndicator( - modifier = Modifier.fillParentMaxSize(), - color = Color(0xff423a99) - ) - } - } - - loadState.refresh is LoadState.Error -> { - val err = getComms.loadState.refresh as LoadState.Error - item { Text(err.error.localizedMessage) } - } - - loadState.append is LoadState.Error -> { - val err = getComms.loadState.append as LoadState.Error - item { Text(err.error.localizedMessage) } - } - } - } - } else { - item { - Text( - text = "Комментариев пока нет!", - color = Color(0xff423a99), - style = TextStyle( - fontSize = 15.sp, - fontWeight = FontWeight.Bold - ), - modifier = Modifier - .align(alignment = Alignment.TopStart) - ) - } - } - - } - - } - Box( - modifier = Modifier - .requiredWidth(width = 393.dp) - .requiredHeight(height = 54.dp) - ) { - Box( - modifier = Modifier - .requiredWidth(width = 393.dp) - .requiredHeight(height = 54.dp) - .clip(shape = RoundedCornerShape(15.dp)) - .background(color = Color(0xff423a99)) - ) - Text( - text = "Comments:", - color = Color.White, - style = TextStyle( - fontSize = 17.sp, - fontWeight = FontWeight.Bold - ), - modifier = Modifier - .align(alignment = Alignment.TopStart) - .offset( - x = 24.dp, - y = 0.dp - ) - .requiredWidth(width = 210.dp) - .requiredHeight(height = 54.dp) - .wrapContentHeight(align = Alignment.CenterVertically) - ) - } - } - } item { Spacer(modifier = Modifier.padding(10.dp)) Box( @@ -685,7 +527,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar y = 220.dp ) .requiredWidth(width = 393.dp) - .requiredHeight(height = 182.dp) + .requiredHeight(height = 282.dp) ) { Box( modifier = Modifier @@ -695,12 +537,12 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar y = 27.1240234375.dp ) .requiredWidth(width = 393.dp) - .requiredHeight(height = 155.dp) + .requiredHeight(height = 255.dp) ) { Box( modifier = Modifier .requiredWidth(width = 393.dp) - .requiredHeight(height = 155.dp) + .requiredHeight(height = 255.dp) .clip(shape = RoundedCornerShape(5.dp)) .background(color = Color.White) .border( @@ -718,8 +560,8 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar ), verticalArrangement = Arrangement.spacedBy(1.dp) ) { - if (getArticles.itemCount != 0) { - items(count = getArticles.itemCount) { index -> + if (getArticles.size != 0) { + items(count = getArticles.size) { index -> val article = getArticles[index] if (article?.userId == getUser?.id) { Spacer(modifier = Modifier.padding(5.dp)) @@ -732,13 +574,13 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar ), modifier = Modifier .align(alignment = Alignment.TopStart) - .clickable { + /*.clickable { navController.navigate( BottomBarScreen.ArticlePage.passId( article?.id.toString() ) ) - } + }*/ ) Spacer(modifier = Modifier.padding(5.dp)) HorizontalDivider( @@ -749,37 +591,6 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar ) } } - getArticles.apply { - when { - loadState.refresh is LoadState.Loading -> { - item { - CircularProgressIndicator( - modifier = Modifier.fillParentMaxSize(), - color = Color(0xff423a99) - ) - } - } - - loadState.append is LoadState.Loading -> { - item { - CircularProgressIndicator( - modifier = Modifier.fillParentMaxSize(), - color = Color(0xff423a99) - ) - } - } - - loadState.refresh is LoadState.Error -> { - val err = getArticles.loadState.refresh as LoadState.Error - item { Text(err.error.localizedMessage) } - } - - loadState.append is LoadState.Error -> { - val err = getArticles.loadState.append as LoadState.Error - item { Text(err.error.localizedMessage) } - } - } - } } else { item { Text( @@ -830,129 +641,6 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,ar } } } - item { - Spacer(modifier = Modifier.padding(10.dp)) - Box( - modifier = Modifier - .offset( - x = 9.dp, - y = 220.dp - ) - .requiredWidth(width = 393.dp) - .requiredHeight(height = 182.dp) - ) { - Box( - modifier = Modifier - .align(alignment = Alignment.TopStart) - .offset( - x = 0.dp, - y = 27.1240234375.dp - ) - .requiredWidth(width = 393.dp) - .requiredHeight(height = 155.dp) - ) { - Box( - modifier = Modifier - .requiredWidth(width = 393.dp) - .requiredHeight(height = 155.dp) - .clip(shape = RoundedCornerShape(5.dp)) - .background(color = Color.White) - .border( - border = BorderStroke(3.dp, Color(0xffdbdbf1)), - shape = RoundedCornerShape(5.dp) - ) - ) - - LazyColumn( - contentPadding = PaddingValues( - top = 28.dp, - bottom = 0.dp, - start = 10.dp, - end = 10.dp - ), - verticalArrangement = Arrangement.spacedBy(1.dp) - ) { - if (getTags.itemCount != 0) { - items(count = getTags.itemCount) { index -> - val tag = getTags[index] - if (tag?.userId == getUser?.id) { - Spacer(modifier = Modifier.padding(5.dp)) - Text( - text = "${tag?.title}", - color = Color(0xff423a99), - style = TextStyle( - fontSize = 15.sp, - fontWeight = FontWeight.Bold - ), - modifier = Modifier - .align(alignment = Alignment.TopStart) - .clickable { - navController.navigate( - BottomBarScreen.SearchByTag.passId( - tag?.id.toString() - ) - ) - } - ) - Spacer(modifier = Modifier.padding(5.dp)) - HorizontalDivider( - thickness = 3.dp, - modifier = Modifier - .border(BorderStroke(3.dp, Color(0xffdbdbf1))), - color = Color(0xffdbdbf1) - ) - } - } - } else { - item { - Text( - text = "Тэгов пока нет!", - color = Color(0xff423a99), - style = TextStyle( - fontSize = 15.sp, - fontWeight = FontWeight.Bold - ), - modifier = Modifier - .align(alignment = Alignment.TopStart) - ) - } - } - - } - - } - Box( - modifier = Modifier - .requiredWidth(width = 393.dp) - .requiredHeight(height = 54.dp) - ) { - Box( - modifier = Modifier - .requiredWidth(width = 393.dp) - .requiredHeight(height = 54.dp) - .clip(shape = RoundedCornerShape(15.dp)) - .background(color = Color(0xff423a99)) - ) - Text( - text = "Tags:", - color = Color.White, - style = TextStyle( - fontSize = 17.sp, - fontWeight = FontWeight.Bold - ), - modifier = Modifier - .align(alignment = Alignment.TopStart) - .offset( - x = 24.dp, - y = 0.dp - ) - .requiredWidth(width = 210.dp) - .requiredHeight(height = 54.dp) - .wrapContentHeight(align = Alignment.CenterVertically) - ) - } - } - } } } diff --git a/app/src/main/java/com/example/pmulabs/screensMobile/TagsScreen.kt b/app/src/main/java/com/example/pmulabs/screensMobile/TagsScreen.kt index c4d0eeb..aec6b4f 100644 --- a/app/src/main/java/com/example/pmulabs/screensMobile/TagsScreen.kt +++ b/app/src/main/java/com/example/pmulabs/screensMobile/TagsScreen.kt @@ -117,7 +117,7 @@ fun TagsScreen(navController: NavController, modifier: Modifier = Modifier, tagI onClick = { openDialog = false if(text.isNotEmpty()) { - val newTag = Tag(null, text, getUser?.id.toString().toInt()) + val newTag = Tag(text, null, getUser?.id.toString().toInt()) coroutineScope.launch { tagItemViewModel.insertTag(newTag) } diff --git a/app/src/main/java/com/example/pmulabs/viewModels/AppViewModelProvider.kt b/app/src/main/java/com/example/pmulabs/viewModels/AppViewModelProvider.kt index 01df35a..3d39aa4 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/AppViewModelProvider.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/AppViewModelProvider.kt @@ -9,28 +9,28 @@ import com.example.pmulabs.NewsPortalApplication object AppViewModelProvider { val Factory = viewModelFactory { initializer { - CurrentUserViewModel(newsPortalApplication().container.userRepository) + CurrentUserViewModel(newsPortalApplication().container.userRestRepository) } initializer { - TagItemViewModel(newsPortalApplication().container.tagRepository) + TagItemViewModel(newsPortalApplication().container.tagRestRepository) } initializer { - CommentItemViewModel(newsPortalApplication().container.userRepository,newsPortalApplication().container.commentRepository) + CommentItemViewModel(newsPortalApplication().container.userRestRepository,newsPortalApplication().container.commentRestRepository) } initializer { - ArticleItemViewModel(newsPortalApplication().container.tagRepository,newsPortalApplication().container.commentRepository,newsPortalApplication().container.articleRepository) + ArticleItemViewModel(newsPortalApplication().container.tagRestRepository,newsPortalApplication().container.commentRestRepository,newsPortalApplication().container.articleRestRepository) } initializer { - EntryScreenViewModel(newsPortalApplication().container.userRepository) + EntryScreenViewModel(newsPortalApplication().container.userRestRepository) } initializer { - RegisterScreenViewModel(newsPortalApplication().container.userRepository) + RegisterScreenViewModel(newsPortalApplication().container.userRestRepository) } initializer { - ArticleScreenViewModel(newsPortalApplication().container.articleRepository) + ArticleScreenViewModel(newsPortalApplication().container.articleRestRepository) } initializer { - ArticlePageScreenViewModel(newsPortalApplication().container.tagRepository,newsPortalApplication().container.commentRepository,newsPortalApplication().container.articleRepository,newsPortalApplication().container.userRepository) + ArticlePageScreenViewModel(newsPortalApplication().container.tagRestRepository,newsPortalApplication().container.commentRestRepository,newsPortalApplication().container.articleRestRepository,newsPortalApplication().container.userRestRepository) } } } diff --git a/app/src/main/java/com/example/pmulabs/viewModels/ArticleItemViewModel.kt b/app/src/main/java/com/example/pmulabs/viewModels/ArticleItemViewModel.kt index 93d611e..89e04ef 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/ArticleItemViewModel.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/ArticleItemViewModel.kt @@ -11,7 +11,6 @@ import com.example.pmulabs.room.repository.ArticleRepository import com.example.pmulabs.room.repository.CommentRepository import com.example.pmulabs.room.repository.TagRepository import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -22,8 +21,8 @@ class ArticleItemViewModel( ) : ViewModel() { var tagList by mutableStateOf>(emptyList()) fun setTagList() { - viewModelScope.launch { - tagList=tagRepository.getAllTags().first() + viewModelScope.launch(Dispatchers.IO) { + tagList=tagRepository.getAllTags() } } @@ -35,11 +34,11 @@ class ArticleItemViewModel( articleRepository.deleteArticle(article) } - suspend fun getTagByName(name: String) : Tag { - return tagRepository.getTagByName(name).first() + suspend fun getTagByName(name: String) : Tag? { + return tagRepository.getTagByName(name) } - suspend fun getCount(articleId: Int?): Int = withContext(Dispatchers.IO) { + suspend fun getCount(articleId: Int?): Int? = withContext(Dispatchers.IO) { commentRepository.getCountComment(articleId) } diff --git a/app/src/main/java/com/example/pmulabs/viewModels/ArticlePageScreenViewModel.kt b/app/src/main/java/com/example/pmulabs/viewModels/ArticlePageScreenViewModel.kt index 2763324..13c5393 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/ArticlePageScreenViewModel.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/ArticlePageScreenViewModel.kt @@ -14,9 +14,8 @@ import com.example.pmulabs.room.repository.ArticleRepository import com.example.pmulabs.room.repository.CommentRepository import com.example.pmulabs.room.repository.TagRepository import com.example.pmulabs.room.repository.UserRepository +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch class ArticlePageScreenViewModel( @@ -31,19 +30,31 @@ class ArticlePageScreenViewModel( var tag by mutableStateOf(null) val comments: Flow> = commentRepository.getComments() + var getComments by mutableStateOf>(emptyList()) + fun setCommentList() { + viewModelScope.launch(Dispatchers.IO) { + getComments=commentRepository.getAllComments() + } + } + fun getArticleById(articleId:Int) { articleid.value = articleId viewModelScope.launch { article = articleRepository.getArticleById(articleid.value!!) - .filterNotNull() - .first() + } + } + + var userList by mutableStateOf>(emptyList()) + fun setUserList() { + viewModelScope.launch(Dispatchers.IO) { + userList=userRepository.getAllUsers() } } var tagList by mutableStateOf>(emptyList()) fun setTagList() { - viewModelScope.launch { - tagList=tagRepository.getAllTags().first() + viewModelScope.launch(Dispatchers.IO) { + tagList=tagRepository.getAllTags() } } @@ -59,16 +70,14 @@ class ArticlePageScreenViewModel( articleRepository.insertArticle(article) } - suspend fun getTagByName(name: String) : Tag { - return tagRepository.getTagByName(name).first() + suspend fun getTagByName(name: String) : Tag? { + return tagRepository.getTagByName(name) } fun getTagById(tagId:Int) { tagid.value = tagId viewModelScope.launch { tag = tagRepository.getTagById(tagid.value!!) - .filterNotNull() - .first() } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/viewModels/ArticleScreenViewModel.kt b/app/src/main/java/com/example/pmulabs/viewModels/ArticleScreenViewModel.kt index 6dbc8c4..3f5b360 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/ArticleScreenViewModel.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/ArticleScreenViewModel.kt @@ -1,11 +1,24 @@ package com.example.pmulabs.viewModels +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import androidx.paging.PagingData import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.repository.ArticleRepository +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch class ArticleScreenViewModel(private val articleRepository: ArticleRepository) : ViewModel() { val articles: Flow> = articleRepository.getArticles() + + var getArticles by mutableStateOf>(emptyList()) + fun setArticleList() { + viewModelScope.launch(Dispatchers.IO) { + getArticles=articleRepository.getAllArticles() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/viewModels/CommentItemViewModel.kt b/app/src/main/java/com/example/pmulabs/viewModels/CommentItemViewModel.kt index 20e6506..0383ab0 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/CommentItemViewModel.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/CommentItemViewModel.kt @@ -1,8 +1,5 @@ package com.example.pmulabs.viewModels -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.pmulabs.room.models.Comment @@ -10,8 +7,6 @@ import com.example.pmulabs.room.models.User import com.example.pmulabs.room.repository.CommentRepository import com.example.pmulabs.room.repository.UserRepository import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -22,36 +17,20 @@ class CommentItemViewModel( suspend fun updateComment(comment: Comment) { commentRepository.updateComment(comment) } + var user : User? = null - var commentList by mutableStateOf>>(commentRepository.getAllComments()) - var commListByArticle by mutableStateOf>(emptyList()) - var userListByArticle by mutableStateOf>(emptyList()) - - suspend fun getCount(articleId: Int): Int = withContext(Dispatchers.IO) { + suspend fun getCount(articleId: Int): Int? = withContext(Dispatchers.IO) { commentRepository.getCountComment(articleId) } - fun getUsersByArticle(articleId: Int) { - viewModelScope.launch { - val count=getCount(articleId) - for(item in commentList.first()){ - if(item.articleId==articleId){ - commListByArticle+=item - } - if(commListByArticle.size>count){ - commListByArticle -= commListByArticle[commListByArticle.size-1] - } - } - for(item in commListByArticle){ - userListByArticle+=userRepository.getUserById(item.userId).first() - if(userListByArticle.size>count){ - userListByArticle -= userListByArticle[userListByArticle.size-1] - } - } + fun getUser(commId: Int) { + viewModelScope.launch(Dispatchers.IO) { + user=userRepository.getUserById(commId) } } suspend fun deleteComment(comment: Comment) { commentRepository.deleteComment(comment) } -} \ No newline at end of file +} + diff --git a/app/src/main/java/com/example/pmulabs/viewModels/CurrentUserViewModel.kt b/app/src/main/java/com/example/pmulabs/viewModels/CurrentUserViewModel.kt index 2bedddf..cdd7f74 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/CurrentUserViewModel.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/CurrentUserViewModel.kt @@ -7,8 +7,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.pmulabs.room.models.User import com.example.pmulabs.room.repository.UserRepository -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch class CurrentUserViewModel(private val userRepository: UserRepository) : ViewModel(){ @@ -21,8 +19,6 @@ class CurrentUserViewModel(private val userRepository: UserRepository) : ViewMod userid.value = arg.toInt() viewModelScope.launch { user = userRepository.getUserById(userid.value) - .filterNotNull() - .first() } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/viewModels/EntryScreenViewModel.kt b/app/src/main/java/com/example/pmulabs/viewModels/EntryScreenViewModel.kt index 9f33c6a..f84e827 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/EntryScreenViewModel.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/EntryScreenViewModel.kt @@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.pmulabs.room.models.User import com.example.pmulabs.room.repository.UserRepository -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch class EntryScreenViewModel(private val userRepository: UserRepository) : ViewModel() { @@ -15,7 +14,7 @@ class EntryScreenViewModel(private val userRepository: UserRepository) : ViewMod var userList by mutableStateOf>(emptyList()) fun setUserList() { viewModelScope.launch { - userList=userRepository.getAllUsers().first() + userList=userRepository.getAllUsers() } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmulabs/viewModels/RegisterScreenViewModel.kt b/app/src/main/java/com/example/pmulabs/viewModels/RegisterScreenViewModel.kt index 830eb7f..153ba9a 100644 --- a/app/src/main/java/com/example/pmulabs/viewModels/RegisterScreenViewModel.kt +++ b/app/src/main/java/com/example/pmulabs/viewModels/RegisterScreenViewModel.kt @@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.pmulabs.room.models.User import com.example.pmulabs.room.repository.UserRepository -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch class RegisterScreenViewModel(private val userRepository: UserRepository) : ViewModel() { @@ -16,7 +15,7 @@ class RegisterScreenViewModel(private val userRepository: UserRepository) : View fun setUserList() { viewModelScope.launch { - _users.value = userRepository.getAllUsers().first() + _users.value = userRepository.getAllUsers() } } diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..eb7159c --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + 10.0.2.2 + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index bd1eb8a..20095f5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,4 +3,6 @@ plugins { id("com.android.application") version "8.1.1" apply false id("org.jetbrains.kotlin.android") version "1.8.10" apply false id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false + id("org.jetbrains.kotlin.plugin.serialization") version "1.8.20" apply false + } \ No newline at end of file diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..1a051f8 --- /dev/null +++ b/server/package.json @@ -0,0 +1,12 @@ +{ + "name": "fake-db", + "version": "1.0.0", + "scripts": { + "start": "json-server --watch data.json --host 0.0.0.0 -p 8079" + }, + "dependencies": { + }, + "devDependencies": { + "json-server": "^0.17.4" + } +} \ No newline at end of file