Лабораторная работа №5: Как будто бы готова
This commit is contained in:
parent
0f8abfbb99
commit
87332767e7
@ -2,6 +2,7 @@ plugins {
|
|||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'org.jetbrains.kotlin.android'
|
id 'org.jetbrains.kotlin.android'
|
||||||
id 'kotlin-kapt'
|
id 'kotlin-kapt'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.serialization'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
@ -86,4 +87,9 @@ dependencies {
|
|||||||
implementation "androidx.paging:paging-runtime-ktx:$paging_version"
|
implementation "androidx.paging:paging-runtime-ktx:$paging_version"
|
||||||
implementation "androidx.paging:paging-compose:$paging_version"
|
implementation "androidx.paging:paging-compose:$paging_version"
|
||||||
implementation("androidx.room:room-paging:2.5.0")
|
implementation("androidx.room:room-paging:2.5.0")
|
||||||
|
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
|
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||||
|
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".DTFApp"
|
android:name=".DTFApp"
|
||||||
@ -11,6 +14,7 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.DTF"
|
android:theme="@style/Theme.DTF"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
@ -2,13 +2,12 @@ package com.example.dtf
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import com.example.dtf.api.ServerService
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
import com.example.dtf.db.AppDatabase
|
import com.example.dtf.db.AppDatabase
|
||||||
import com.example.dtf.models.User
|
|
||||||
import com.example.dtf.repositories.*
|
import com.example.dtf.repositories.*
|
||||||
|
import com.example.dtf.repositories.offline.*
|
||||||
|
import com.example.dtf.repositories.online.*
|
||||||
|
import com.example.dtf.repositories.online.mediator.RestCategoryRepository
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
@ -32,21 +31,65 @@ object AppModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideCategoryRepository(db: AppDatabase) = CategoryRepository(db.categoryDao())
|
fun provideServerService(): ServerService = ServerService.getInstance()
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideCommentRepository(db: AppDatabase) = CommentRepository(db.commentDao())
|
fun provideICategoryRepository(db: AppDatabase, serverService: ServerService): ICategoryRepository = RestCategoryRepository(db, serverService)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideLikeRepository(db: AppDatabase) = LikeRepository(db.likeDao())
|
fun provideICommentRepository(db: AppDatabase, serverService: ServerService): ICommentRepository = RestCommentRepository(db, serverService)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providePostRepository(db: AppDatabase) = PostRepository(db.postDao())
|
fun provideILikeRepository(db: AppDatabase, serverService: ServerService): ILikeRepository = RestLikeRepository(db, serverService)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun proviveUserRepository(db: AppDatabase) = UserRepository(db.userDao())
|
fun provideIPostRepository(db: AppDatabase, serverService: ServerService): IPostRepository = RestPostRepository(db, serverService)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideIUserRepository(db: AppDatabase, serverService: ServerService): IUserRepository = RestUserRepository(db, serverService)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOfflineCategoryRepository(db: AppDatabase): OfflineCategoryRepository = OfflineCategoryRepository(db.categoryDao())
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOfflineCommentRepository(db: AppDatabase): OfflineCommentRepository = OfflineCommentRepository(db.commentDao())
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOfflineLikeRepository(db: AppDatabase): OfflineLikeRepository = OfflineLikeRepository(db.likeDao())
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOfflinePostRepository(db: AppDatabase): OfflinePostRepository = OfflinePostRepository(db.postDao())
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOfflineUserRepository(db: AppDatabase): OfflineUserRepository = OfflineUserRepository(db.userDao())
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRestCategoryRepository(db: AppDatabase, serverService: ServerService): RestCategoryRepository = RestCategoryRepository(db, serverService)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRestCommentRepository(db: AppDatabase, serverService: ServerService): RestCommentRepository = RestCommentRepository(db, serverService)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRestLikeRepository(db: AppDatabase, serverService: ServerService): RestLikeRepository = RestLikeRepository(db, serverService)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRestPostRepository(db: AppDatabase, serverService: ServerService): RestPostRepository = RestPostRepository(db, serverService)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRestUserRepository(db: AppDatabase, serverService: ServerService): RestUserRepository = RestUserRepository(db, serverService)
|
||||||
}
|
}
|
152
app/src/main/java/com/example/dtf/api/ServerService.kt
Normal file
152
app/src/main/java/com/example/dtf/api/ServerService.kt
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package com.example.dtf.api
|
||||||
|
|
||||||
|
import com.example.dtf.dto.Credentials
|
||||||
|
import com.example.dtf.dto.EditPostDto
|
||||||
|
import com.example.dtf.dto.MeUser
|
||||||
|
import com.example.dtf.dto.NewCommentDto
|
||||||
|
import com.example.dtf.dto.NewPostDto
|
||||||
|
import com.example.dtf.dto.Token
|
||||||
|
import com.example.dtf.dto.remote.CategoriesResponse
|
||||||
|
import com.example.dtf.dto.remote.CommentsResponse
|
||||||
|
import com.example.dtf.dto.remote.PostsResponse
|
||||||
|
import com.example.dtf.models.Category
|
||||||
|
import com.example.dtf.models.Comment
|
||||||
|
import com.example.dtf.models.Post
|
||||||
|
import com.example.dtf.models.User
|
||||||
|
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import retrofit2.http.POST
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import retrofit2.http.Header
|
||||||
|
|
||||||
|
interface ServerService {
|
||||||
|
@POST("auth/login")
|
||||||
|
suspend fun login(
|
||||||
|
@Body credentials: Credentials
|
||||||
|
): Token
|
||||||
|
|
||||||
|
@POST("auth/register")
|
||||||
|
suspend fun register(
|
||||||
|
@Body credentials: Credentials
|
||||||
|
): String
|
||||||
|
|
||||||
|
@GET("user/me")
|
||||||
|
suspend fun getCurrentUser(): MeUser
|
||||||
|
|
||||||
|
@GET("category")
|
||||||
|
suspend fun getCategories(
|
||||||
|
@Query("offset") offset: Int?,
|
||||||
|
@Query("limit") limit: Int?
|
||||||
|
): CategoriesResponse
|
||||||
|
|
||||||
|
@GET("post")
|
||||||
|
suspend fun getPosts(
|
||||||
|
@Query("category") category: Int?,
|
||||||
|
@Query("offset") offset: Int?,
|
||||||
|
@Query("limit") limit: Int?
|
||||||
|
): PostsResponse
|
||||||
|
|
||||||
|
@GET("post/{postId}")
|
||||||
|
suspend fun getPost(
|
||||||
|
@Path("postId") postId: Int
|
||||||
|
): Post
|
||||||
|
|
||||||
|
@POST("post")
|
||||||
|
suspend fun createPost(
|
||||||
|
@Body post: NewPostDto
|
||||||
|
)
|
||||||
|
|
||||||
|
@POST("post/{postId}")
|
||||||
|
suspend fun updatePost(
|
||||||
|
@Path("postId") postId: Int,
|
||||||
|
@Body post: EditPostDto
|
||||||
|
)
|
||||||
|
|
||||||
|
@GET("comment")
|
||||||
|
suspend fun getComments(
|
||||||
|
@Query("postId") postId: Int?,
|
||||||
|
@Query("offset") offset: Int?,
|
||||||
|
@Query("limit") limit: Int?
|
||||||
|
): CommentsResponse
|
||||||
|
|
||||||
|
@GET("comment/{commentId}")
|
||||||
|
suspend fun getComment(
|
||||||
|
@Path("commentId") commentId: Int
|
||||||
|
): Comment
|
||||||
|
|
||||||
|
@POST("comment")
|
||||||
|
suspend fun createComment(
|
||||||
|
@Body comment: NewCommentDto
|
||||||
|
)
|
||||||
|
|
||||||
|
@POST("post/{postId}/like")
|
||||||
|
suspend fun likePost(
|
||||||
|
@Path("postId") postId: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@GET("post/{postId}/liked")
|
||||||
|
suspend fun postIsLiked(
|
||||||
|
@Path("postId") postId: Int
|
||||||
|
): Boolean
|
||||||
|
|
||||||
|
@GET("post/{postId}/likes")
|
||||||
|
suspend fun getPostLikes(
|
||||||
|
@Path("postId") postId: Int
|
||||||
|
): Int
|
||||||
|
|
||||||
|
@GET("user/{userId}")
|
||||||
|
suspend fun getUser(
|
||||||
|
@Path("userId") userId: Int
|
||||||
|
): User
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL = "http://192.168.1.9:8000/"
|
||||||
|
|
||||||
|
private var _token: String = ""
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var INSTANCE: ServerService? = null
|
||||||
|
|
||||||
|
fun getInstance(): ServerService {
|
||||||
|
return INSTANCE ?: synchronized(this) {
|
||||||
|
val logger = HttpLoggingInterceptor()
|
||||||
|
logger.level = HttpLoggingInterceptor.Level.BASIC
|
||||||
|
val client = OkHttpClient.Builder()
|
||||||
|
.addInterceptor(logger)
|
||||||
|
.addInterceptor {
|
||||||
|
val originalRequest = it.request()
|
||||||
|
if (_token.isEmpty()) {
|
||||||
|
it.proceed(originalRequest)
|
||||||
|
} else {
|
||||||
|
it.proceed(
|
||||||
|
originalRequest
|
||||||
|
.newBuilder()
|
||||||
|
.header("Authorization", "Bearer $_token")
|
||||||
|
.method(originalRequest.method, originalRequest.body)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL)
|
||||||
|
.client(client)
|
||||||
|
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
|
||||||
|
.build()
|
||||||
|
.create(ServerService::class.java)
|
||||||
|
.also { INSTANCE = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setToken(token: String) {
|
||||||
|
_token = token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,13 @@
|
|||||||
package com.example.dtf.dao
|
package com.example.dtf.dao
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import com.example.dtf.models.*
|
import com.example.dtf.models.*
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface CategoryDao {
|
interface CategoryDao {
|
||||||
@Insert
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insert(category: Category)
|
suspend fun insert(category: Category)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
@ -16,8 +17,14 @@ interface CategoryDao {
|
|||||||
suspend fun delete(category: Category)
|
suspend fun delete(category: Category)
|
||||||
|
|
||||||
@Query("select * from category")
|
@Query("select * from category")
|
||||||
fun getAll() : Flow<List<Category>>
|
fun getAll() : PagingSource<Int, Category>
|
||||||
|
|
||||||
|
@Query("select * from category")
|
||||||
|
fun getAllCached() : Flow<List<Category>>
|
||||||
|
|
||||||
@Query("select * from category where category.id = :id")
|
@Query("select * from category where category.id = :id")
|
||||||
fun getById(id: Int) : Flow<Category>
|
fun getById(id: Int) : Flow<Category>
|
||||||
|
|
||||||
|
@Query("select * from category limit 1")
|
||||||
|
fun getFirst() : Flow<Category>
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface CommentDao {
|
interface CommentDao {
|
||||||
@Insert
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insert(comment: Comment)
|
suspend fun insert(comment: Comment)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
@ -16,12 +16,12 @@ interface CommentDao {
|
|||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(comment: Comment)
|
suspend fun delete(comment: Comment)
|
||||||
|
|
||||||
@Query("select * from comment")
|
|
||||||
fun getAll() : Flow<List<Comment>>
|
|
||||||
|
|
||||||
@Query("select * from comment where comment.id = :id")
|
@Query("select * from comment where comment.id = :id")
|
||||||
fun getById(id: Int) : Flow<Comment>
|
fun getById(id: Int) : Flow<Comment>
|
||||||
|
|
||||||
@Query("select * from comment where comment.post_id = :postId ORDER BY date DESC")
|
@Query("select * from comment where comment.post_id = :postId ORDER BY id DESC")
|
||||||
fun getByPost(postId: Int) : PagingSource<Int, Comment>
|
fun getByPost(postId: Int) : PagingSource<Int, Comment>
|
||||||
|
|
||||||
|
@Query("delete from comment where post_id = :query")
|
||||||
|
fun deleteByQuery(query: String)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface LikeDao {
|
interface LikeDao {
|
||||||
@Insert
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insert(like: Like)
|
suspend fun insert(like: Like)
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
|
@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface PostDao {
|
interface PostDao {
|
||||||
@Insert
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insert(post: Post)
|
suspend fun insert(post: Post)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
@ -16,12 +16,12 @@ interface PostDao {
|
|||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(post: Post)
|
suspend fun delete(post: Post)
|
||||||
|
|
||||||
@Query("select * from post")
|
|
||||||
fun getAll() : Flow<List<Post>>
|
|
||||||
|
|
||||||
@Query("select * from post where post.id = :id")
|
@Query("select * from post where post.id = :id")
|
||||||
fun getById(id: Int) : Flow<Post>
|
fun getById(id: Int) : Flow<Post>
|
||||||
|
|
||||||
@Query("select * from post where post.category_id = :categoryId ORDER BY date DESC")
|
@Query("select * from post where post.category_id = :categoryId ORDER BY date DESC")
|
||||||
fun getByCategory(categoryId: String) : PagingSource<Int, Post>
|
fun getByCategory(categoryId: String) : PagingSource<Int, Post>
|
||||||
|
|
||||||
|
@Query("delete from post where category_id = :query")
|
||||||
|
fun deleteByQuery(query: String)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface UserDao {
|
interface UserDao {
|
||||||
@Insert
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insert(user: User)
|
suspend fun insert(user: User)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
@ -15,12 +15,6 @@ interface UserDao {
|
|||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(user: User)
|
suspend fun delete(user: User)
|
||||||
|
|
||||||
@Query("select * from user order by username collate nocase asc")
|
|
||||||
fun getAll() : Flow<List<User>>
|
|
||||||
|
|
||||||
@Query("select * from user where user.id = :id")
|
@Query("select * from user where user.id = :id")
|
||||||
fun getById(id: Int): Flow<User>
|
fun getById(id: Int): Flow<User>
|
||||||
|
|
||||||
@Query("select * from user where user.username = :username and user.password = :password")
|
|
||||||
fun getByUsernameAndPassword(username: String, password: String): Flow<User?>
|
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ import java.util.Date
|
|||||||
Like::class,
|
Like::class,
|
||||||
Comment::class
|
Comment::class
|
||||||
],
|
],
|
||||||
version = 2,
|
version = 4,
|
||||||
exportSchema = false
|
exportSchema = false
|
||||||
)
|
)
|
||||||
@TypeConverters(Converter::class)
|
@TypeConverters(Converter::class)
|
||||||
|
9
app/src/main/java/com/example/dtf/dto/Credentials.kt
Normal file
9
app/src/main/java/com/example/dtf/dto/Credentials.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.dtf.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Credentials(
|
||||||
|
val username: String = "",
|
||||||
|
val password: String = ""
|
||||||
|
)
|
9
app/src/main/java/com/example/dtf/dto/EditPostDto.kt
Normal file
9
app/src/main/java/com/example/dtf/dto/EditPostDto.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.dtf.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class EditPostDto(
|
||||||
|
val title: String,
|
||||||
|
val content: String
|
||||||
|
)
|
10
app/src/main/java/com/example/dtf/dto/MeUser.kt
Normal file
10
app/src/main/java/com/example/dtf/dto/MeUser.kt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.dtf.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MeUser(
|
||||||
|
val id: Int,
|
||||||
|
val username: String,
|
||||||
|
val is_moderator: Boolean
|
||||||
|
)
|
9
app/src/main/java/com/example/dtf/dto/NewCommentDto.kt
Normal file
9
app/src/main/java/com/example/dtf/dto/NewCommentDto.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.dtf.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class NewCommentDto(
|
||||||
|
val post_id: Int,
|
||||||
|
val content: String
|
||||||
|
)
|
10
app/src/main/java/com/example/dtf/dto/NewPostDto.kt
Normal file
10
app/src/main/java/com/example/dtf/dto/NewPostDto.kt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.dtf.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class NewPostDto(
|
||||||
|
val title: String,
|
||||||
|
val content: String,
|
||||||
|
val category_id: Int
|
||||||
|
)
|
8
app/src/main/java/com/example/dtf/dto/Token.kt
Normal file
8
app/src/main/java/com/example/dtf/dto/Token.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package com.example.dtf.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Token(
|
||||||
|
val token: String
|
||||||
|
)
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.dtf.dto.remote
|
||||||
|
|
||||||
|
import com.example.dtf.models.Category
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CategoriesResponse(
|
||||||
|
val categories: List<Category>,
|
||||||
|
val nextKey: Int?
|
||||||
|
)
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.dtf.dto.remote
|
||||||
|
|
||||||
|
import com.example.dtf.models.Comment
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CommentsResponse(
|
||||||
|
val comments: List<Comment>,
|
||||||
|
val nextKey: Int?
|
||||||
|
)
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.dtf.dto.remote
|
||||||
|
|
||||||
|
import com.example.dtf.models.Post
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PostsResponse(
|
||||||
|
val posts: List<Post>,
|
||||||
|
val nextKey: Int?
|
||||||
|
)
|
@ -1,8 +1,10 @@
|
|||||||
package com.example.dtf.models
|
package com.example.dtf.models
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Entity(tableName = "category")
|
@Entity(tableName = "category")
|
||||||
|
@Serializable
|
||||||
data class Category(
|
data class Category(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package com.example.dtf.models
|
|
||||||
|
|
||||||
import androidx.room.Embedded
|
|
||||||
import androidx.room.Relation
|
|
||||||
|
|
||||||
data class CategoryWithPosts(
|
|
||||||
@Embedded val category: Category,
|
|
||||||
@Relation(parentColumn = "id", entityColumn = "category_id")
|
|
||||||
val posts: List<Post>
|
|
||||||
)
|
|
@ -1,21 +1,24 @@
|
|||||||
package com.example.dtf.models
|
package com.example.dtf.models
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import java.util.Date
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Entity(tableName = "comment")
|
@Entity(tableName = "comment")
|
||||||
|
@Serializable
|
||||||
data class Comment(
|
data class Comment(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
val id: Int?,
|
val id: Int?,
|
||||||
@ColumnInfo(name = "user_id")
|
@ColumnInfo(name = "user_id")
|
||||||
val userId: Int,
|
val user_id: Int,
|
||||||
@ColumnInfo(name = "post_id")
|
@ColumnInfo(name = "post_id")
|
||||||
val postId: Int,
|
val post_id: Int,
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
val content: String,
|
val content: String,
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
val date: Date
|
val date: String,
|
||||||
|
@ColumnInfo
|
||||||
|
val author: String = ""
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package com.example.dtf.models
|
package com.example.dtf.models
|
||||||
|
|
||||||
import androidx.compose.runtime.collection.MutableVector
|
|
||||||
import androidx.compose.runtime.collection.mutableVectorOf
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import java.util.Date
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
//private val posts = listOf(
|
//private val posts = listOf(
|
||||||
// Post(
|
// Post(
|
||||||
@ -60,11 +58,9 @@ import java.util.Date
|
|||||||
//)
|
//)
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
tableName = "post",
|
tableName = "post"
|
||||||
foreignKeys = [
|
|
||||||
ForeignKey(User::class, ["id"], ["user_id"])
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
@Serializable
|
||||||
data class Post(
|
data class Post(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
@ -74,11 +70,13 @@ data class Post(
|
|||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
val content: String,
|
val content: String,
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
val date: Date,
|
val date: String,
|
||||||
@ColumnInfo(name = "user_id")
|
@ColumnInfo(name = "user_id")
|
||||||
val userId: Int,
|
val user_id: Int,
|
||||||
@ColumnInfo(name = "category_id")
|
@ColumnInfo(name = "category_id")
|
||||||
val categoryId: Int
|
val category_id: Int,
|
||||||
|
@ColumnInfo
|
||||||
|
val likes: Int = 0,
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package com.example.dtf.models
|
|
||||||
|
|
||||||
import androidx.room.Embedded
|
|
||||||
import androidx.room.Relation
|
|
||||||
|
|
||||||
data class PostWithComments(
|
|
||||||
@Embedded val post: Post,
|
|
||||||
@Relation(parentColumn = "id", entityColumn = "post_id")
|
|
||||||
val comments: List<Comment>
|
|
||||||
)
|
|
@ -1,18 +1,16 @@
|
|||||||
package com.example.dtf.models
|
package com.example.dtf.models
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Entity(tableName = "user")
|
@Entity(tableName = "user")
|
||||||
|
@Serializable
|
||||||
data class User(
|
data class User(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
val id: Int?,
|
val id: Int?,
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
val username: String,
|
val username: String,
|
||||||
@ColumnInfo
|
|
||||||
val password: String,
|
|
||||||
@ColumnInfo
|
|
||||||
val isModerator: Boolean
|
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package com.example.dtf.repositories
|
|
||||||
|
|
||||||
import com.example.dtf.dao.CategoryDao
|
|
||||||
import com.example.dtf.models.Category
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class CategoryRepository @Inject constructor(
|
|
||||||
private val categoryDao: CategoryDao
|
|
||||||
) {
|
|
||||||
suspend fun insert(category: Category) = categoryDao.insert(category)
|
|
||||||
|
|
||||||
suspend fun update(category: Category) = categoryDao.update(category)
|
|
||||||
|
|
||||||
suspend fun delete(category: Category) = categoryDao.delete(category)
|
|
||||||
|
|
||||||
fun getAll() = categoryDao.getAll()
|
|
||||||
|
|
||||||
fun getById(id: Int) = categoryDao.getById(id)
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package com.example.dtf.repositories
|
|
||||||
|
|
||||||
import androidx.paging.*
|
|
||||||
import com.example.dtf.dao.CommentDao
|
|
||||||
import com.example.dtf.models.Comment
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class CommentRepository @Inject constructor(
|
|
||||||
private val commentDao: CommentDao
|
|
||||||
) {
|
|
||||||
suspend fun insert(comment: Comment) = commentDao.insert(comment)
|
|
||||||
|
|
||||||
suspend fun update(comment: Comment) = commentDao.update(comment)
|
|
||||||
|
|
||||||
suspend fun delete(comment: Comment) = commentDao.delete(comment)
|
|
||||||
|
|
||||||
fun getAll() = commentDao.getAll()
|
|
||||||
|
|
||||||
fun getById(id: Int) = commentDao.getById(id)
|
|
||||||
|
|
||||||
fun getByPost(postId: Int) = Pager(
|
|
||||||
PagingConfig(
|
|
||||||
pageSize = 5,
|
|
||||||
enablePlaceholders = false
|
|
||||||
),
|
|
||||||
pagingSourceFactory = { commentDao.getByPost(postId) }
|
|
||||||
).flow
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.dtf.repositories
|
||||||
|
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import com.example.dtf.models.Category
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface ICategoryRepository {
|
||||||
|
fun getAll(): Flow<PagingData<Category>>
|
||||||
|
fun getAllCached(): Flow<List<Category>>
|
||||||
|
|
||||||
|
fun getFirst(): Flow<Category?>
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.dtf.repositories
|
||||||
|
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import com.example.dtf.models.Comment
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface ICommentRepository {
|
||||||
|
suspend fun insert(comment: Comment)
|
||||||
|
|
||||||
|
fun getById(id: Int): Flow<Comment>
|
||||||
|
fun getByPost(postId: Int): Flow<PagingData<Comment>>
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.dtf.repositories
|
||||||
|
|
||||||
|
import com.example.dtf.models.Like
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface ILikeRepository {
|
||||||
|
suspend fun insert(like: Like)
|
||||||
|
suspend fun delete(like: Like)
|
||||||
|
|
||||||
|
fun countByPost(postId: Int): Flow<Int>
|
||||||
|
fun isLikedByUser(userId: Int, postId: Int): Flow<Boolean>
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.example.dtf.repositories
|
||||||
|
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import com.example.dtf.models.Post
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface IPostRepository {
|
||||||
|
suspend fun insert(post: Post)
|
||||||
|
suspend fun update(post: Post)
|
||||||
|
|
||||||
|
fun getById(id: Int): Flow<Post>
|
||||||
|
fun getByCategory(categoryId: Int): Flow<PagingData<Post>>
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.example.dtf.repositories
|
||||||
|
|
||||||
|
import com.example.dtf.models.User
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface IUserRepository {
|
||||||
|
fun getById(id: Int) : Flow<User>
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
package com.example.dtf.repositories
|
|
||||||
|
|
||||||
import com.example.dtf.dao.LikeDao
|
|
||||||
import com.example.dtf.models.Like
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class LikeRepository @Inject constructor(
|
|
||||||
private val likeDao: LikeDao
|
|
||||||
) {
|
|
||||||
suspend fun insert(like: Like) = likeDao.insert(like)
|
|
||||||
|
|
||||||
suspend fun delete(like: Like) = likeDao.delete(like)
|
|
||||||
|
|
||||||
fun countByPost(postId: Int) = likeDao.countByPost(postId)
|
|
||||||
|
|
||||||
fun isLikedByUser(userId: Int, postId: Int) = likeDao.isLikedByUser(userId, postId)
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package com.example.dtf.repositories
|
|
||||||
|
|
||||||
import androidx.paging.*
|
|
||||||
import com.example.dtf.dao.PostDao
|
|
||||||
import com.example.dtf.models.Post
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class PostRepository @Inject constructor(
|
|
||||||
private val postDao: PostDao
|
|
||||||
) {
|
|
||||||
suspend fun insert(post: Post) = postDao.insert(post)
|
|
||||||
|
|
||||||
suspend fun update(post: Post) = postDao.update(post)
|
|
||||||
|
|
||||||
suspend fun delete(post: Post) = postDao.delete(post)
|
|
||||||
|
|
||||||
fun getAll() = postDao.getAll()
|
|
||||||
|
|
||||||
fun getById(id: Int) = postDao.getById(id)
|
|
||||||
|
|
||||||
fun getByCategory(categoryId: Int) = Pager(
|
|
||||||
PagingConfig(
|
|
||||||
pageSize = 3,
|
|
||||||
enablePlaceholders = false
|
|
||||||
),
|
|
||||||
pagingSourceFactory = { postDao.getByCategory(categoryId.toString()) }
|
|
||||||
).flow
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package com.example.dtf.repositories
|
|
||||||
|
|
||||||
import com.example.dtf.dao.UserDao
|
|
||||||
import com.example.dtf.models.User
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class UserRepository @Inject constructor(
|
|
||||||
private val userDao: UserDao
|
|
||||||
) {
|
|
||||||
suspend fun insert(user: User) = userDao.insert(user)
|
|
||||||
|
|
||||||
suspend fun update(user: User) = userDao.update(user)
|
|
||||||
|
|
||||||
suspend fun delete(user: User) = userDao.delete(user)
|
|
||||||
|
|
||||||
fun getAll() = userDao.getAll()
|
|
||||||
|
|
||||||
fun getById(id: Int) = userDao.getById(id)
|
|
||||||
|
|
||||||
fun getByUsernameAndPassword(username: String, password: String) = userDao.getByUsernameAndPassword(username, password)
|
|
||||||
}
|
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.example.dtf.repositories.offline
|
||||||
|
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import com.example.dtf.dao.CategoryDao
|
||||||
|
import com.example.dtf.models.Category
|
||||||
|
import com.example.dtf.repositories.ICategoryRepository
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class OfflineCategoryRepository @Inject constructor(
|
||||||
|
private val categoryDao: CategoryDao
|
||||||
|
) : ICategoryRepository {
|
||||||
|
|
||||||
|
override fun getAll() = Pager(
|
||||||
|
PagingConfig(
|
||||||
|
pageSize = 5,
|
||||||
|
enablePlaceholders = false
|
||||||
|
),
|
||||||
|
pagingSourceFactory = { categoryDao.getAll() }
|
||||||
|
).flow
|
||||||
|
|
||||||
|
override fun getAllCached(): Flow<List<Category>> {
|
||||||
|
return categoryDao.getAllCached()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFirst(): Flow<Category?> {
|
||||||
|
return categoryDao.getFirst()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.example.dtf.repositories.offline
|
||||||
|
|
||||||
|
import androidx.paging.*
|
||||||
|
import com.example.dtf.dao.CommentDao
|
||||||
|
import com.example.dtf.models.Comment
|
||||||
|
import com.example.dtf.repositories.ICommentRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class OfflineCommentRepository @Inject constructor(
|
||||||
|
private val commentDao: CommentDao
|
||||||
|
) : ICommentRepository {
|
||||||
|
override suspend fun insert(comment: Comment) = commentDao.insert(comment)
|
||||||
|
|
||||||
|
override fun getById(id: Int) = commentDao.getById(id)
|
||||||
|
|
||||||
|
override fun getByPost(postId: Int) = Pager(
|
||||||
|
PagingConfig(
|
||||||
|
pageSize = 5,
|
||||||
|
enablePlaceholders = false
|
||||||
|
),
|
||||||
|
pagingSourceFactory = { commentDao.getByPost(postId) }
|
||||||
|
).flow
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.example.dtf.repositories.offline
|
||||||
|
|
||||||
|
import com.example.dtf.dao.LikeDao
|
||||||
|
import com.example.dtf.models.Like
|
||||||
|
import com.example.dtf.repositories.ILikeRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class OfflineLikeRepository @Inject constructor(
|
||||||
|
private val likeDao: LikeDao
|
||||||
|
) : ILikeRepository {
|
||||||
|
override suspend fun insert(like: Like) = likeDao.insert(like)
|
||||||
|
|
||||||
|
override suspend fun delete(like: Like) = likeDao.delete(like)
|
||||||
|
|
||||||
|
override fun countByPost(postId: Int) = likeDao.countByPost(postId)
|
||||||
|
|
||||||
|
override fun isLikedByUser(userId: Int, postId: Int) = likeDao.isLikedByUser(userId, postId)
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.example.dtf.repositories.offline
|
||||||
|
|
||||||
|
import androidx.paging.*
|
||||||
|
import com.example.dtf.dao.PostDao
|
||||||
|
import com.example.dtf.models.Post
|
||||||
|
import com.example.dtf.repositories.IPostRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class OfflinePostRepository @Inject constructor(
|
||||||
|
private val postDao: PostDao
|
||||||
|
) : IPostRepository {
|
||||||
|
override suspend fun insert(post: Post) = postDao.insert(post)
|
||||||
|
|
||||||
|
override suspend fun update(post: Post) = postDao.update(post)
|
||||||
|
|
||||||
|
override fun getById(id: Int) = postDao.getById(id)
|
||||||
|
|
||||||
|
override fun getByCategory(categoryId: Int) = Pager(
|
||||||
|
PagingConfig(
|
||||||
|
pageSize = 3,
|
||||||
|
enablePlaceholders = false
|
||||||
|
),
|
||||||
|
pagingSourceFactory = { postDao.getByCategory(categoryId.toString()) }
|
||||||
|
).flow
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.dtf.repositories.offline
|
||||||
|
|
||||||
|
import com.example.dtf.dao.UserDao
|
||||||
|
import com.example.dtf.models.User
|
||||||
|
import com.example.dtf.repositories.IUserRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class OfflineUserRepository @Inject constructor(
|
||||||
|
private val userDao: UserDao
|
||||||
|
) : IUserRepository {
|
||||||
|
override fun getById(id: Int) = userDao.getById(id)
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.example.dtf.repositories.online.mediator
|
||||||
|
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.models.Category
|
||||||
|
import com.example.dtf.repositories.ICategoryRepository
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RestCategoryRepository @Inject constructor(
|
||||||
|
private val appDatabase: AppDatabase,
|
||||||
|
private val serverService: ServerService
|
||||||
|
) : ICategoryRepository {
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
override fun getAll(): Flow<PagingData<Category>> = Pager(
|
||||||
|
PagingConfig(
|
||||||
|
pageSize = 3,
|
||||||
|
enablePlaceholders = false
|
||||||
|
),
|
||||||
|
remoteMediator = CategoryMediator(appDatabase, serverService),
|
||||||
|
pagingSourceFactory = { appDatabase.categoryDao().getAll() }
|
||||||
|
).flow
|
||||||
|
|
||||||
|
override fun getAllCached(): Flow<List<Category>> {
|
||||||
|
return appDatabase.categoryDao().getAllCached()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFirst(): Flow<Category?> {
|
||||||
|
return appDatabase.categoryDao().getFirst()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.example.dtf.repositories.online
|
||||||
|
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.dto.NewCommentDto
|
||||||
|
import com.example.dtf.models.Comment
|
||||||
|
import com.example.dtf.repositories.ICommentRepository
|
||||||
|
import com.example.dtf.repositories.online.mediator.CommentMediator
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RestCommentRepository @Inject constructor(
|
||||||
|
private val appDatabase: AppDatabase,
|
||||||
|
private val serverService: ServerService
|
||||||
|
) : ICommentRepository {
|
||||||
|
override suspend fun insert(comment: Comment) {
|
||||||
|
serverService.createComment(
|
||||||
|
comment = NewCommentDto(post_id = comment.post_id, content = comment.content)
|
||||||
|
)
|
||||||
|
appDatabase.commentDao().insert(comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getById(id: Int): Flow<Comment> {
|
||||||
|
return flow { emit(serverService.getComment(id)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
override fun getByPost(postId: Int): Flow<PagingData<Comment>> = Pager(
|
||||||
|
PagingConfig(
|
||||||
|
pageSize = 5,
|
||||||
|
enablePlaceholders = false,
|
||||||
|
),
|
||||||
|
remoteMediator = CommentMediator(appDatabase, serverService, postId.toString()),
|
||||||
|
pagingSourceFactory = { appDatabase.commentDao().getByPost(postId) }
|
||||||
|
).flow
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.example.dtf.repositories.online
|
||||||
|
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.models.Like
|
||||||
|
import com.example.dtf.repositories.ILikeRepository
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RestLikeRepository @Inject constructor(
|
||||||
|
private val appDatabase: AppDatabase,
|
||||||
|
private val serverService: ServerService
|
||||||
|
) : ILikeRepository {
|
||||||
|
override suspend fun insert(like: Like) {
|
||||||
|
serverService.likePost(like.postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun delete(like: Like) {
|
||||||
|
serverService.likePost(like.postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun countByPost(postId: Int): Flow<Int> {
|
||||||
|
return flow { emit(serverService.getPostLikes(postId)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isLikedByUser(userId: Int, postId: Int): Flow<Boolean> {
|
||||||
|
return flow { emit(serverService.postIsLiked(postId)) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.example.dtf.repositories.online
|
||||||
|
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.dto.EditPostDto
|
||||||
|
import com.example.dtf.dto.NewPostDto
|
||||||
|
import com.example.dtf.models.Post
|
||||||
|
import com.example.dtf.repositories.IPostRepository
|
||||||
|
import com.example.dtf.repositories.online.mediator.PostMediator
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RestPostRepository @Inject constructor(
|
||||||
|
private val appDatabase: AppDatabase,
|
||||||
|
private val serverService: ServerService
|
||||||
|
) : IPostRepository {
|
||||||
|
override suspend fun insert(post: Post) {
|
||||||
|
serverService.createPost(
|
||||||
|
post = NewPostDto(post.title, post.content, post.category_id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun update(post: Post) {
|
||||||
|
serverService.updatePost(
|
||||||
|
postId = post.id!!,
|
||||||
|
post = EditPostDto(post.title, post.content)
|
||||||
|
)
|
||||||
|
appDatabase.postDao().update(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getById(id: Int): Flow<Post> {
|
||||||
|
return flow { emit(serverService.getPost(id)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
override fun getByCategory(categoryId: Int): Flow<PagingData<Post>> = Pager(
|
||||||
|
PagingConfig(
|
||||||
|
pageSize = 4,
|
||||||
|
enablePlaceholders = false
|
||||||
|
),
|
||||||
|
remoteMediator = PostMediator(appDatabase, serverService, categoryId.toString()),
|
||||||
|
pagingSourceFactory = { appDatabase.postDao().getByCategory(categoryId.toString()) }
|
||||||
|
).flow
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.example.dtf.repositories.online
|
||||||
|
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.models.User
|
||||||
|
import com.example.dtf.repositories.IUserRepository
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RestUserRepository @Inject constructor(
|
||||||
|
private val appDatabase: AppDatabase,
|
||||||
|
private val serverService: ServerService
|
||||||
|
) : IUserRepository {
|
||||||
|
override fun getById(id: Int): Flow<User> {
|
||||||
|
return flow { emit(serverService.getUser(id)) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.example.dtf.repositories.online.mediator
|
||||||
|
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.LoadType
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import androidx.paging.RemoteMediator
|
||||||
|
import androidx.room.withTransaction
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.models.Category
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
class CategoryMediator (
|
||||||
|
private val database: AppDatabase,
|
||||||
|
private val serverService: ServerService
|
||||||
|
) : RemoteMediator<Int, Category>(){
|
||||||
|
|
||||||
|
private val categoryDao = database.categoryDao()
|
||||||
|
|
||||||
|
override suspend fun load(
|
||||||
|
loadType: LoadType,
|
||||||
|
state: PagingState<Int, Category>
|
||||||
|
): MediatorResult {
|
||||||
|
return try {
|
||||||
|
var loadKey = when (loadType) {
|
||||||
|
LoadType.REFRESH -> null
|
||||||
|
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
|
||||||
|
LoadType.APPEND -> {
|
||||||
|
val lastItem = state.lastItemOrNull()
|
||||||
|
?: return MediatorResult.Success(endOfPaginationReached = true)
|
||||||
|
|
||||||
|
lastItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadKey == null) {
|
||||||
|
loadKey = 0
|
||||||
|
}
|
||||||
|
val response = serverService.getCategories(
|
||||||
|
offset = loadKey,
|
||||||
|
limit = state.config.pageSize
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
database.withTransaction {
|
||||||
|
if (loadType == LoadType.REFRESH) {
|
||||||
|
for (category in response.categories) {
|
||||||
|
categoryDao.delete(category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (category in response.categories) {
|
||||||
|
categoryDao.insert(category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MediatorResult.Success(endOfPaginationReached = response.nextKey == null)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
MediatorResult.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.example.dtf.repositories.online.mediator
|
||||||
|
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.LoadType
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import androidx.paging.RemoteMediator
|
||||||
|
import androidx.room.withTransaction
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.models.Comment
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
class CommentMediator (
|
||||||
|
private val database: AppDatabase,
|
||||||
|
private val serverService: ServerService,
|
||||||
|
private val query: String
|
||||||
|
) : RemoteMediator<Int, Comment>(){
|
||||||
|
|
||||||
|
private val commentDao = database.commentDao()
|
||||||
|
|
||||||
|
override suspend fun load(
|
||||||
|
loadType: LoadType,
|
||||||
|
state: PagingState<Int, Comment>
|
||||||
|
): MediatorResult {
|
||||||
|
return try {
|
||||||
|
var loadKey = when (loadType) {
|
||||||
|
LoadType.REFRESH -> null
|
||||||
|
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
|
||||||
|
LoadType.APPEND -> {
|
||||||
|
val lastItem = state.lastItemOrNull()
|
||||||
|
?: return MediatorResult.Success(endOfPaginationReached = true)
|
||||||
|
|
||||||
|
lastItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadKey == null) {
|
||||||
|
loadKey = 0
|
||||||
|
}
|
||||||
|
val response = serverService.getComments(
|
||||||
|
postId = query.toInt(),
|
||||||
|
offset = loadKey,
|
||||||
|
limit = state.config.pageSize
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
database.withTransaction {
|
||||||
|
if (loadType == LoadType.REFRESH) {
|
||||||
|
commentDao.deleteByQuery(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (comment in response.comments) {
|
||||||
|
commentDao.insert(comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MediatorResult.Success(endOfPaginationReached = response.nextKey == null)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
MediatorResult.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.example.dtf.repositories.online.mediator
|
||||||
|
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.LoadType
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import androidx.paging.RemoteMediator
|
||||||
|
import androidx.room.withTransaction
|
||||||
|
import com.example.dtf.api.ServerService
|
||||||
|
import com.example.dtf.db.AppDatabase
|
||||||
|
import com.example.dtf.models.Post
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
class PostMediator (
|
||||||
|
private val database: AppDatabase,
|
||||||
|
private val serverService: ServerService,
|
||||||
|
private val query: String
|
||||||
|
) : RemoteMediator<Int, Post>(){
|
||||||
|
|
||||||
|
private val postDao = database.postDao()
|
||||||
|
|
||||||
|
override suspend fun load(
|
||||||
|
loadType: LoadType,
|
||||||
|
state: PagingState<Int, Post>
|
||||||
|
): MediatorResult {
|
||||||
|
return try {
|
||||||
|
var loadKey = when (loadType) {
|
||||||
|
LoadType.REFRESH -> null
|
||||||
|
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
|
||||||
|
LoadType.APPEND -> {
|
||||||
|
val lastItem = state.lastItemOrNull()
|
||||||
|
?: return MediatorResult.Success(endOfPaginationReached = true)
|
||||||
|
|
||||||
|
lastItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadKey == null) {
|
||||||
|
loadKey = 0
|
||||||
|
}
|
||||||
|
val response = serverService.getPosts(
|
||||||
|
category = query.toInt(),
|
||||||
|
offset = loadKey,
|
||||||
|
limit = state.config.pageSize
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
database.withTransaction {
|
||||||
|
if (loadType == LoadType.REFRESH) {
|
||||||
|
postDao.deleteByQuery(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (comment in response.posts) {
|
||||||
|
postDao.insert(comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MediatorResult.Success(endOfPaginationReached = response.nextKey == null)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
MediatorResult.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.models.Category
|
import com.example.dtf.models.Category
|
||||||
import com.example.dtf.utils.ScreenPaths
|
import com.example.dtf.utils.ScreenPaths
|
||||||
@ -36,9 +37,7 @@ fun NewPostScreen(navController: NavHostController) {
|
|||||||
|
|
||||||
val viewModel = hiltViewModel<NewPostViewModel>()
|
val viewModel = hiltViewModel<NewPostViewModel>()
|
||||||
val success = viewModel.addingPostState.observeAsState().value
|
val success = viewModel.addingPostState.observeAsState().value
|
||||||
val categories = viewModel.categories.observeAsState().value
|
val categories = viewModel.getCategories().collectAsState(initial = listOf())
|
||||||
|
|
||||||
viewModel.retrieveCategories()
|
|
||||||
|
|
||||||
if (success == true) {
|
if (success == true) {
|
||||||
navController.navigate(ScreenPaths.Posts.route) {
|
navController.navigate(ScreenPaths.Posts.route) {
|
||||||
@ -91,7 +90,9 @@ fun NewPostScreen(navController: NavHostController) {
|
|||||||
colors = ButtonDefaults.buttonColors(Color(0xFFFFFFFF)),
|
colors = ButtonDefaults.buttonColors(Color(0xFFFFFFFF)),
|
||||||
border = BorderStroke(1.dp, Color(0xFF0085FF)),
|
border = BorderStroke(1.dp, Color(0xFF0085FF)),
|
||||||
shape = RoundedCornerShape(15.dp),
|
shape = RoundedCornerShape(15.dp),
|
||||||
modifier = Modifier.fillMaxWidth().padding(15.dp, 10.dp, 15.dp, 0.dp)
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(15.dp, 10.dp, 15.dp, 0.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = selectedCategory.value.name,
|
text = selectedCategory.value.name,
|
||||||
@ -102,11 +103,13 @@ fun NewPostScreen(navController: NavHostController) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 15.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 15.dp),
|
||||||
expanded = expanded.value,
|
expanded = expanded.value,
|
||||||
onDismissRequest = {expanded.value = false}
|
onDismissRequest = {expanded.value = false}
|
||||||
) {
|
) {
|
||||||
categories?.forEach { category ->
|
categories.value.forEach { category ->
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
onClick = {
|
onClick = {
|
||||||
selectedCategory.value = category
|
selectedCategory.value = category
|
||||||
@ -126,17 +129,23 @@ fun NewPostScreen(navController: NavHostController) {
|
|||||||
value = title,
|
value = title,
|
||||||
"Заголовок",
|
"Заголовок",
|
||||||
onChanged = {title.value = it},
|
onChanged = {title.value = it},
|
||||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 15.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 15.dp),
|
||||||
backgroundColor = Color(0xFFFEFEFE)
|
backgroundColor = Color(0xFFFEFEFE)
|
||||||
)
|
)
|
||||||
MyTextField(
|
MyTextField(
|
||||||
value = content,
|
value = content,
|
||||||
"Содержимое",
|
"Содержимое",
|
||||||
onChanged = {content.value = it},
|
onChanged = {content.value = it},
|
||||||
modifier = Modifier.fillMaxWidth().heightIn(min = 500.dp).padding(horizontal = 15.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.heightIn(min = 400.dp)
|
||||||
|
.padding(horizontal = 15.dp),
|
||||||
backgroundColor = Color(0xFFFEFEFE),
|
backgroundColor = Color(0xFFFEFEFE),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
{
|
{
|
||||||
if (selectedCategory.value.id != null) {
|
if (selectedCategory.value.id != null) {
|
||||||
|
@ -19,23 +19,14 @@ import androidx.compose.ui.text.input.TextFieldValue
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import androidx.paging.compose.itemKey
|
import androidx.paging.compose.itemKey
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.db.AppDatabase
|
|
||||||
import com.example.dtf.models.Comment
|
import com.example.dtf.models.Comment
|
||||||
import com.example.dtf.models.Post
|
|
||||||
import com.example.dtf.models.PostWithComments
|
|
||||||
import com.example.dtf.models.User
|
|
||||||
import com.example.dtf.utils.ScreenPaths
|
import com.example.dtf.utils.ScreenPaths
|
||||||
import com.example.dtf.viewmodels.PostViewModel
|
import com.example.dtf.viewmodels.PostViewModel
|
||||||
import com.example.dtf.widgets.MyTextField
|
import com.example.dtf.widgets.MyTextField
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PostScreen(postId: Int, navController: NavHostController) {
|
fun PostScreen(postId: Int, navController: NavHostController) {
|
||||||
@ -89,16 +80,7 @@ fun PostScreen(postId: Int, navController: NavHostController) {
|
|||||||
) {
|
) {
|
||||||
if (post != null) {
|
if (post != null) {
|
||||||
Text(
|
Text(
|
||||||
text = "day.month.year".replace(
|
text = post.date,
|
||||||
"day",
|
|
||||||
post.date.day.toString()
|
|
||||||
).replace(
|
|
||||||
"month",
|
|
||||||
post.date.month.toString()
|
|
||||||
).replace(
|
|
||||||
"year",
|
|
||||||
post.date.year.toString()
|
|
||||||
),
|
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color(0xFFCECCCC)
|
color = Color(0xFFCECCCC)
|
||||||
)
|
)
|
||||||
@ -115,16 +97,7 @@ fun PostScreen(postId: Int, navController: NavHostController) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row (
|
Row (
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier,
|
||||||
if (isLiked.value) {
|
|
||||||
viewModel.unlikePost(sharedPref, postId)
|
|
||||||
likes.intValue--
|
|
||||||
} else {
|
|
||||||
viewModel.likePost(sharedPref, postId)
|
|
||||||
likes.intValue++
|
|
||||||
}
|
|
||||||
isLiked.value = !isLiked.value
|
|
||||||
},
|
|
||||||
horizontalArrangement = Arrangement.End
|
horizontalArrangement = Arrangement.End
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@ -133,7 +106,16 @@ fun PostScreen(postId: Int, navController: NavHostController) {
|
|||||||
color = Color.Green
|
color = Color.Green
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.padding(start = 8.dp),
|
modifier = Modifier.padding(start = 8.dp).clickable {
|
||||||
|
if (isLiked.value) {
|
||||||
|
viewModel.unlikePost(sharedPref, postId)
|
||||||
|
likes.intValue--
|
||||||
|
} else {
|
||||||
|
viewModel.likePost(sharedPref, postId)
|
||||||
|
likes.intValue++
|
||||||
|
}
|
||||||
|
isLiked.value = !isLiked.value
|
||||||
|
},
|
||||||
imageVector = Icons.Default.ThumbUp,
|
imageVector = Icons.Default.ThumbUp,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = if (isLiked.value) { Color(40, 200, 40, 255) } else {Color.Black}
|
tint = if (isLiked.value) { Color(40, 200, 40, 255) } else {Color.Black}
|
||||||
@ -202,20 +184,11 @@ private fun Comment(comment: Comment) {
|
|||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = user?.username ?: "Loading...",
|
text = comment.author.ifEmpty { user?.username ?: "Loading..." },
|
||||||
fontSize = 20.sp
|
fontSize = 20.sp
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "day.month.year".replace(
|
text = comment.date,
|
||||||
"day",
|
|
||||||
comment.date.day.toString()
|
|
||||||
).replace(
|
|
||||||
"month",
|
|
||||||
comment.date.month.toString()
|
|
||||||
).replace(
|
|
||||||
"year",
|
|
||||||
comment.date.year.toString()
|
|
||||||
),
|
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color(0xFFCECCCC)
|
color = Color(0xFFCECCCC)
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,7 @@ package com.example.dtf.screens
|
|||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ThumbUp
|
import androidx.compose.material.icons.filled.ThumbUp
|
||||||
@ -18,21 +19,14 @@ import androidx.compose.ui.unit.*
|
|||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import androidx.paging.compose.LazyPagingItems
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import androidx.paging.compose.itemKey
|
import androidx.paging.compose.itemKey
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.db.AppDatabase
|
|
||||||
import com.example.dtf.models.Category
|
import com.example.dtf.models.Category
|
||||||
import com.example.dtf.models.CategoryWithPosts
|
|
||||||
import com.example.dtf.models.Post
|
import com.example.dtf.models.Post
|
||||||
import com.example.dtf.utils.ScreenPaths
|
import com.example.dtf.utils.ScreenPaths
|
||||||
import com.example.dtf.viewmodels.PostsViewModel
|
import com.example.dtf.viewmodels.PostsViewModel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PostsScreen(navController: NavHostController) {
|
fun PostsScreen(navController: NavHostController) {
|
||||||
@ -47,19 +41,8 @@ fun PostsScreen(navController: NavHostController) {
|
|||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
Categories(viewModel, currentCategory, posts)
|
||||||
.fillMaxWidth()
|
|
||||||
.fillMaxHeight(0.1f)
|
|
||||||
.horizontalScroll(
|
|
||||||
rememberScrollState()
|
|
||||||
)
|
|
||||||
.background(Color.White),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(25.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Categories(viewModel, currentCategory, posts)
|
|
||||||
}
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
@ -72,36 +55,50 @@ fun PostsScreen(navController: NavHostController) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Categories(viewModel: PostsViewModel, currentCategory: MutableState<Category?>, posts: MutableState<Flow<PagingData<Post>>?>) {
|
private fun Categories(viewModel: PostsViewModel, currentCategory: MutableState<Category?>, posts: MutableState<Flow<PagingData<Post>>?>) {
|
||||||
val categories = viewModel.getCategories().collectAsState(listOf()).value
|
val categories = viewModel.getCategoriesListUiState().collectAsLazyPagingItems()
|
||||||
|
|
||||||
if (categories.isNotEmpty() && currentCategory.value == null) {
|
|
||||||
currentCategory.value = categories[0]
|
|
||||||
posts.value = viewModel.getPostsListUiState(currentCategory.value!!.id!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(5.dp))
|
LazyRow(
|
||||||
categories.forEach {category ->
|
modifier = Modifier
|
||||||
Text(
|
.fillMaxWidth()
|
||||||
modifier = Modifier
|
.fillMaxHeight(0.1f)
|
||||||
.clickable {
|
.background(Color.White),
|
||||||
currentCategory.value = category
|
horizontalArrangement = Arrangement.spacedBy(25.dp),
|
||||||
posts.value = viewModel.getPostsListUiState(category.id!!)
|
verticalAlignment = Alignment.CenterVertically
|
||||||
}
|
) {
|
||||||
.drawBehind {
|
item {
|
||||||
if (category.name == currentCategory.value?.name) {
|
Spacer(modifier = Modifier.width(5.dp))
|
||||||
val strokeWidthPx = 2.dp.toPx()
|
}
|
||||||
val verticalOffset = size.height + 2.sp.toPx()
|
items(
|
||||||
drawLine(
|
count = categories.itemCount,
|
||||||
color = Color(0xFF319CFF),
|
key = categories.itemKey()
|
||||||
strokeWidth = strokeWidthPx,
|
) {
|
||||||
start = Offset(0f, verticalOffset),
|
if (currentCategory.value == null) {
|
||||||
end = Offset(size.width, verticalOffset)
|
currentCategory.value = categories[0]
|
||||||
)
|
posts.value = viewModel.getPostsListUiState(currentCategory.value!!.id!!)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
currentCategory.value = categories[it]!!
|
||||||
|
posts.value = viewModel.getPostsListUiState(categories[it]!!.id!!)
|
||||||
}
|
}
|
||||||
},
|
.drawBehind {
|
||||||
text = category.name,
|
if (categories[it]!!.name == currentCategory.value?.name) {
|
||||||
fontSize = 22.sp
|
val strokeWidthPx = 2.dp.toPx()
|
||||||
)
|
val verticalOffset = size.height + 2.sp.toPx()
|
||||||
|
drawLine(
|
||||||
|
color = Color(0xFF319CFF),
|
||||||
|
strokeWidth = strokeWidthPx,
|
||||||
|
start = Offset(0f, verticalOffset),
|
||||||
|
end = Offset(size.width, verticalOffset)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = categories[it]!!.name,
|
||||||
|
fontSize = 22.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +126,7 @@ private fun PostsByCategory(viewModel: PostsViewModel, navController: NavHostCon
|
|||||||
private fun Post(viewModel: PostsViewModel, navController: NavHostController, post: Post) {
|
private fun Post(viewModel: PostsViewModel, navController: NavHostController, post: Post) {
|
||||||
val sharedPref = PreferencesManager(LocalContext.current)
|
val sharedPref = PreferencesManager(LocalContext.current)
|
||||||
|
|
||||||
val likes = remember { mutableIntStateOf(0) }
|
val likes = remember { mutableIntStateOf(post.likes) }
|
||||||
val isLiked = remember { mutableStateOf(false) }
|
val isLiked = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@ -162,41 +159,28 @@ private fun Post(viewModel: PostsViewModel, navController: NavHostController, po
|
|||||||
fontSize = 26.sp
|
fontSize = 26.sp
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.fillMaxHeight(0.6f).padding(10.dp, 0.dp, 10.dp, 0.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxHeight(0.6f)
|
||||||
|
.padding(10.dp, 0.dp, 10.dp, 0.dp),
|
||||||
text = post.content,
|
text = post.content,
|
||||||
fontSize = 20.sp,
|
fontSize = 20.sp,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(10.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
verticalAlignment = Alignment.Bottom,
|
verticalAlignment = Alignment.Bottom,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "day.month.year".replace(
|
text = post.date,
|
||||||
"day",
|
|
||||||
post.date.day.toString()
|
|
||||||
).replace(
|
|
||||||
"month",
|
|
||||||
post.date.month.toString()
|
|
||||||
).replace(
|
|
||||||
"year",
|
|
||||||
post.date.year.toString()
|
|
||||||
),
|
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color(0xFFCECCCC)
|
color = Color(0xFFCECCCC)
|
||||||
)
|
)
|
||||||
Row (
|
Row (
|
||||||
modifier = Modifier.fillMaxWidth().clickable {
|
modifier = Modifier
|
||||||
if (isLiked.value) {
|
.fillMaxWidth(),
|
||||||
viewModel.unlikePost(sharedPref, post.id!!)
|
|
||||||
likes.intValue--
|
|
||||||
} else {
|
|
||||||
viewModel.likePost(sharedPref, post.id!!)
|
|
||||||
likes.intValue++
|
|
||||||
}
|
|
||||||
isLiked.value = !isLiked.value
|
|
||||||
},
|
|
||||||
horizontalArrangement = Arrangement.End
|
horizontalArrangement = Arrangement.End
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@ -205,7 +189,18 @@ private fun Post(viewModel: PostsViewModel, navController: NavHostController, po
|
|||||||
color = Color.Green
|
color = Color.Green
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.padding(start = 8.dp),
|
modifier = Modifier
|
||||||
|
.padding(start = 8.dp)
|
||||||
|
.clickable {
|
||||||
|
if (isLiked.value) {
|
||||||
|
viewModel.unlikePost(sharedPref, post.id!!)
|
||||||
|
likes.intValue--
|
||||||
|
} else {
|
||||||
|
viewModel.likePost(sharedPref, post.id!!)
|
||||||
|
likes.intValue++
|
||||||
|
}
|
||||||
|
isLiked.value = !isLiked.value
|
||||||
|
},
|
||||||
imageVector = Icons.Default.ThumbUp,
|
imageVector = Icons.Default.ThumbUp,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = if (isLiked.value) { Color(40, 200, 40, 255) } else {Color.Black}
|
tint = if (isLiked.value) { Color(40, 200, 40, 255) } else {Color.Black}
|
||||||
|
@ -6,14 +6,14 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.models.Post
|
import com.example.dtf.models.Post
|
||||||
import com.example.dtf.repositories.PostRepository
|
import com.example.dtf.repositories.IPostRepository
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class EditPostViewModel @Inject constructor(
|
class EditPostViewModel @Inject constructor(
|
||||||
private val postRepository: PostRepository
|
private val postRepository: IPostRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _editingPostState = MutableLiveData<Boolean?>(null)
|
private val _editingPostState = MutableLiveData<Boolean?>(null)
|
||||||
val editingPostState: LiveData<Boolean?>
|
val editingPostState: LiveData<Boolean?>
|
||||||
@ -41,7 +41,7 @@ class EditPostViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (title.isNotEmpty() && content.isNotEmpty()) {
|
if (title.isNotEmpty() && content.isNotEmpty()) {
|
||||||
postRepository.getById(postId).collect {
|
postRepository.getById(postId).collect {
|
||||||
postRepository.update(Post(postId, title, content, it.date, it.userId, it.categoryId))
|
postRepository.update(Post(postId, title, content, it.date, it.user_id, it.category_id))
|
||||||
_editingPostState.postValue(true)
|
_editingPostState.postValue(true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,55 +5,44 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.models.Category
|
import com.example.dtf.api.ServerService
|
||||||
import com.example.dtf.models.User
|
import com.example.dtf.dto.Credentials
|
||||||
import com.example.dtf.repositories.CategoryRepository
|
import com.example.dtf.repositories.IUserRepository
|
||||||
import com.example.dtf.repositories.UserRepository
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class LoginViewModel @Inject constructor(
|
class LoginViewModel @Inject constructor(
|
||||||
private val userRepository: UserRepository,
|
private val serverService: ServerService,
|
||||||
private val categoryRepository: CategoryRepository
|
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _successState = MutableLiveData<Boolean?>()
|
private val _successState = MutableLiveData<Boolean?>()
|
||||||
val successState: LiveData<Boolean?>
|
val successState: LiveData<Boolean?>
|
||||||
get() = _successState
|
get() = _successState
|
||||||
|
|
||||||
init {
|
|
||||||
addAdmin()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun calmSuccessState() {
|
fun calmSuccessState() {
|
||||||
_successState.postValue(null)
|
_successState.postValue(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun login(sharedPref: PreferencesManager, username: String, password: String) {
|
fun login(sharedPref: PreferencesManager, username: String, password: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
userRepository.getByUsernameAndPassword(username, password).collect {
|
val token = serverService.login(Credentials(username, password))
|
||||||
if (it == null) {
|
|
||||||
_successState.postValue(false)
|
|
||||||
} else {
|
|
||||||
sharedPref.saveData("userId", it.id.toString())
|
|
||||||
sharedPref.saveData("isModerator", it.isModerator.toString())
|
|
||||||
_successState.postValue(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addAdmin() {
|
if (token.token.isEmpty()) {
|
||||||
viewModelScope.launch {
|
_successState.postValue(false)
|
||||||
userRepository.getAll().collect {
|
return@launch
|
||||||
if (it.size == 0) {
|
|
||||||
userRepository.insert(User(1, "admin", "admin", true))
|
|
||||||
categoryRepository.insert(Category(1, "Аниме"))
|
|
||||||
categoryRepository.insert(Category(2, "Игры"))
|
|
||||||
categoryRepository.insert(Category(3, "Фильмы"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerService.setToken(token.token)
|
||||||
|
|
||||||
|
val user = serverService.getCurrentUser()
|
||||||
|
|
||||||
|
sharedPref.saveData("token", token.token)
|
||||||
|
sharedPref.saveData("username", user.username)
|
||||||
|
sharedPref.saveData("isModerator", user.is_moderator.toString())
|
||||||
|
sharedPref.saveData("userId", user.id.toString())
|
||||||
|
|
||||||
|
_successState.postValue(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,36 +5,24 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.models.Category
|
|
||||||
import com.example.dtf.models.Post
|
import com.example.dtf.models.Post
|
||||||
import com.example.dtf.repositories.CategoryRepository
|
import com.example.dtf.repositories.ICategoryRepository
|
||||||
import com.example.dtf.repositories.PostRepository
|
import com.example.dtf.repositories.IPostRepository
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.time.LocalDate
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class NewPostViewModel @Inject constructor(
|
class NewPostViewModel @Inject constructor(
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: IPostRepository,
|
||||||
private val categoryRepository: CategoryRepository
|
private val categoryRepository: ICategoryRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _addingPostState = MutableLiveData<Boolean?>(null)
|
private val _addingPostState = MutableLiveData<Boolean?>(null)
|
||||||
val addingPostState: LiveData<Boolean?>
|
val addingPostState: LiveData<Boolean?>
|
||||||
get() = _addingPostState
|
get() = _addingPostState
|
||||||
|
|
||||||
private val _categories = MutableLiveData<List<Category>>(listOf())
|
fun getCategories() = categoryRepository.getAllCached()
|
||||||
val categories: LiveData<List<Category>>
|
|
||||||
get() = _categories
|
|
||||||
|
|
||||||
fun retrieveCategories() {
|
|
||||||
viewModelScope.launch {
|
|
||||||
categoryRepository.getAll().collect {
|
|
||||||
_categories.postValue(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun calmAddingState() {
|
fun calmAddingState() {
|
||||||
_addingPostState.value = null
|
_addingPostState.value = null
|
||||||
@ -50,7 +38,7 @@ class NewPostViewModel @Inject constructor(
|
|||||||
null,
|
null,
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
Date(),
|
"${Date().year + 1900}-${Date().month + 1}-${Date().date}",
|
||||||
sharedPref.getData("userId", "0").toInt(),
|
sharedPref.getData("userId", "0").toInt(),
|
||||||
categoryId
|
categoryId
|
||||||
)
|
)
|
||||||
|
@ -4,16 +4,15 @@ import androidx.lifecycle.LiveData
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.models.Comment
|
import com.example.dtf.models.Comment
|
||||||
import com.example.dtf.models.Like
|
import com.example.dtf.models.Like
|
||||||
import com.example.dtf.models.Post
|
import com.example.dtf.models.Post
|
||||||
import com.example.dtf.repositories.CommentRepository
|
import com.example.dtf.repositories.ICommentRepository
|
||||||
import com.example.dtf.repositories.LikeRepository
|
import com.example.dtf.repositories.ILikeRepository
|
||||||
import com.example.dtf.repositories.PostRepository
|
import com.example.dtf.repositories.IPostRepository
|
||||||
import com.example.dtf.repositories.UserRepository
|
import com.example.dtf.repositories.IUserRepository
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -22,10 +21,10 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class PostViewModel @Inject constructor(
|
class PostViewModel @Inject constructor(
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: IPostRepository,
|
||||||
private val commentRepository: CommentRepository,
|
private val commentRepository: ICommentRepository,
|
||||||
private val likeRepository: LikeRepository,
|
private val likeRepository: ILikeRepository,
|
||||||
private val userRepository: UserRepository
|
private val userRepository: IUserRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _post = MutableLiveData<Post>()
|
private val _post = MutableLiveData<Post>()
|
||||||
val post: LiveData<Post>
|
val post: LiveData<Post>
|
||||||
@ -79,13 +78,14 @@ class PostViewModel @Inject constructor(
|
|||||||
userId,
|
userId,
|
||||||
postId,
|
postId,
|
||||||
content,
|
content,
|
||||||
Date()
|
"${Date().year + 1900}-${Date().month + 1}-${Date().date}",
|
||||||
|
sharedPref.getData("username", "Unknown")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCommentsAuthor(comment: Comment) = userRepository.getById(comment.userId)
|
fun getCommentsAuthor(comment: Comment) = userRepository.getById(comment.user_id)
|
||||||
|
|
||||||
fun getCommentsListUiState(postId: Int): Flow<PagingData<Comment>> = commentRepository.getByPost(postId)
|
fun getCommentsListUiState(postId: Int): Flow<PagingData<Comment>> = commentRepository.getByPost(postId)
|
||||||
}
|
}
|
@ -4,18 +4,18 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.models.Like
|
import com.example.dtf.models.Like
|
||||||
import com.example.dtf.repositories.CategoryRepository
|
import com.example.dtf.repositories.ICategoryRepository
|
||||||
import com.example.dtf.repositories.LikeRepository
|
import com.example.dtf.repositories.ILikeRepository
|
||||||
import com.example.dtf.repositories.PostRepository
|
import com.example.dtf.repositories.IPostRepository
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class PostsViewModel @Inject constructor(
|
class PostsViewModel @Inject constructor(
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: IPostRepository,
|
||||||
private val categoryRepository: CategoryRepository,
|
private val categoryRepository: ICategoryRepository,
|
||||||
private val likeRepository: LikeRepository
|
private val likeRepository: ILikeRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
fun getLikes(postId: Int) = likeRepository.countByPost(postId)
|
fun getLikes(postId: Int) = likeRepository.countByPost(postId)
|
||||||
|
|
||||||
@ -45,7 +45,9 @@ class PostsViewModel @Inject constructor(
|
|||||||
postId
|
postId
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getCategories() = categoryRepository.getAll()
|
fun getCategoriesListUiState() = categoryRepository.getAll()
|
||||||
|
|
||||||
|
fun getInitialCategory() = categoryRepository.getFirst()
|
||||||
|
|
||||||
fun getPostsListUiState(categoryId: Int) = postRepository.getByCategory(categoryId)
|
fun getPostsListUiState(categoryId: Int) = postRepository.getByCategory(categoryId)
|
||||||
}
|
}
|
@ -6,33 +6,26 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.PreferencesManager
|
||||||
import com.example.dtf.models.User
|
import com.example.dtf.models.User
|
||||||
import com.example.dtf.repositories.UserRepository
|
import com.example.dtf.repositories.offline.OfflineUserRepository
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class ProfileViewModel @Inject constructor(
|
class ProfileViewModel @Inject constructor(
|
||||||
private val userRepository: UserRepository
|
private val userRepository: OfflineUserRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _user = MutableLiveData<User>()
|
private val _user = MutableLiveData<User>()
|
||||||
val user: LiveData<User>
|
val user: LiveData<User>
|
||||||
get() = _user
|
get() = _user
|
||||||
|
|
||||||
fun retrieveUser(sharedPref: PreferencesManager) {
|
fun retrieveUser(sharedPref: PreferencesManager) {
|
||||||
val userId = sharedPref.getData("userId", "-1").toInt()
|
_user.postValue(User(null, sharedPref.getData("username", "Nickname")))
|
||||||
|
|
||||||
if (userId == -1) return
|
|
||||||
|
|
||||||
viewModelScope.launch {
|
|
||||||
userRepository.getById(userId).collect {
|
|
||||||
_user.postValue(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logout(sharedPref: PreferencesManager) {
|
fun logout(sharedPref: PreferencesManager) {
|
||||||
sharedPref.deleteData("userId")
|
sharedPref.deleteData("token")
|
||||||
|
sharedPref.deleteData("username")
|
||||||
sharedPref.deleteData("isModerator")
|
sharedPref.deleteData("isModerator")
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,16 +4,16 @@ import androidx.lifecycle.LiveData
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.dtf.PreferencesManager
|
import com.example.dtf.api.ServerService
|
||||||
import com.example.dtf.models.User
|
import com.example.dtf.dto.Credentials
|
||||||
import com.example.dtf.repositories.UserRepository
|
import com.example.dtf.repositories.offline.OfflineUserRepository
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class RegisterViewModel @Inject constructor(
|
class RegisterViewModel @Inject constructor(
|
||||||
private val userRepository: UserRepository
|
private val serverService: ServerService
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _successState = MutableLiveData<Boolean?>()
|
private val _successState = MutableLiveData<Boolean?>()
|
||||||
val successState: LiveData<Boolean?>
|
val successState: LiveData<Boolean?>
|
||||||
@ -38,15 +38,11 @@ class RegisterViewModel @Inject constructor(
|
|||||||
_successState.postValue(false)
|
_successState.postValue(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
userRepository.getByUsernameAndPassword(username, password).collect {
|
if (serverService.register(Credentials(username, password)) == "NOT OK") {
|
||||||
if (it != null) {
|
_successState.postValue(false)
|
||||||
_successState.postValue(false)
|
} else {
|
||||||
} else {
|
_successState.postValue(true)
|
||||||
userRepository.insert(User(null, username, password, false))
|
|
||||||
_successState.postValue(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,6 @@ plugins {
|
|||||||
id 'com.android.application' version '7.4.2' apply false
|
id 'com.android.application' version '7.4.2' apply false
|
||||||
id 'com.android.library' version '7.4.2' apply false
|
id 'com.android.library' version '7.4.2' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.7.0' apply false
|
id 'org.jetbrains.kotlin.android' version '1.7.0' apply false
|
||||||
|
id 'org.jetbrains.kotlin.plugin.serialization' version '1.7.0' apply false
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.7.0' apply false
|
||||||
}
|
}
|
@ -4,5 +4,5 @@
|
|||||||
# Location of the SDK. This is only used by Gradle.
|
# Location of the SDK. This is only used by Gradle.
|
||||||
# For customization when using a Version Control System, please read the
|
# For customization when using a Version Control System, please read the
|
||||||
# header note.
|
# header note.
|
||||||
#Tue Nov 07 09:36:13 SAMT 2023
|
#Fri Dec 22 01:26:17 GMT+04:00 2023
|
||||||
sdk.dir=C\:\\Users\\Aqua\\AppData\\Local\\Android\\Sdk
|
sdk.dir=D\:\\Programs\\Android
|
||||||
|
Loading…
Reference in New Issue
Block a user