Compare commits

...

3 Commits

Author SHA1 Message Date
maxnes3
8e644e6ba0 5 лаба готова и сдана 2023-12-23 11:23:33 +04:00
maxnes3
ca101dfb80 Уже что-то 2023-12-23 08:43:17 +04:00
maxnes3
6bce075545 Начало 2023-12-14 00:48:13 +04:00
38 changed files with 801 additions and 91 deletions

View File

@ -2,6 +2,7 @@ plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp") id("com.google.devtools.ksp")
kotlin("plugin.serialization") version "1.4.21"
} }
android { android {
@ -68,6 +69,7 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation("androidx.compose.ui:ui-test-manifest")
implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0-alpha03")
// Room // Room
val room_version = "2.5.2" val room_version = "2.5.2"
@ -80,4 +82,12 @@ dependencies {
//Paging //Paging
implementation ("androidx.paging:paging-compose:3.2.1") implementation ("androidx.paging:paging-compose:3.2.1")
implementation ("androidx.paging:paging-runtime:3.2.1") implementation ("androidx.paging:paging-runtime:3.2.1")
// 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")
} }

View File

@ -1,6 +1,8 @@
<?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.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application <application
android:name=".MobileApp" android:name=".MobileApp"
@ -12,7 +14,8 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.MobileApp" android:theme="@style/Theme.MobileApp"
tools:targetApi="31"> tools:targetApi="31"
android:networkSecurityConfig="@xml/network_security_config">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@ -1,11 +1,16 @@
package com.example.mobileapp package com.example.mobileapp
import android.content.Context import android.content.Context
import com.example.mobileapp.api.ServerService
import com.example.mobileapp.api.repository.RestMailRepository
import com.example.mobileapp.api.repository.RestStoryRepository
import com.example.mobileapp.api.repository.RestUserRepository
import com.example.mobileapp.database.MobileAppDataBase import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.repositories.MailRepository import com.example.mobileapp.database.repositories.MailRepository
import com.example.mobileapp.database.repositories.OfflineMailRepository import com.example.mobileapp.database.repositories.OfflineMailRepository
import com.example.mobileapp.database.repositories.OfflineStoryRepository import com.example.mobileapp.database.repositories.OfflineStoryRepository
import com.example.mobileapp.database.repositories.OfflineUserRepository import com.example.mobileapp.database.repositories.OfflineUserRepository
import com.example.mobileapp.database.repositories.RemoteKeysRepositoryImpl
import com.example.mobileapp.database.repositories.StoryRepository import com.example.mobileapp.database.repositories.StoryRepository
import com.example.mobileapp.database.repositories.UserRepository import com.example.mobileapp.database.repositories.UserRepository
@ -13,22 +18,42 @@ interface MobileAppContainer {
val mailRepository: MailRepository val mailRepository: MailRepository
val storyRepository: StoryRepository val storyRepository: StoryRepository
val userRepository: UserRepository val userRepository: UserRepository
companion object{
const val TIMEOUT = 5000L
const val LIMIT = 10
}
} }
class MobileAppDataContainer(private val context: Context): MobileAppContainer { class MobileAppDataContainer(private val context: Context): MobileAppContainer {
override val mailRepository: MailRepository by lazy { override val mailRepository: MailRepository by lazy {
OfflineMailRepository(MobileAppDataBase.getInstance(context).mailDao()) //OfflineMailRepository(MobileAppDataBase.getInstance(context).mailDao())
RestMailRepository(ServerService.getInstance())
} }
override val storyRepository: StoryRepository by lazy { override val storyRepository: StoryRepository by lazy {
OfflineStoryRepository(MobileAppDataBase.getInstance(context).storyDao()) //OfflineStoryRepository(MobileAppDataBase.getInstance(context).storyDao())
RestStoryRepository(ServerService.getInstance(),
storyReposLocal,
userReposLocal,
MobileAppDataBase.getInstance(context),
remoteKeyRepository)
} }
override val userRepository: UserRepository by lazy { override val userRepository: UserRepository by lazy {
OfflineUserRepository(MobileAppDataBase.getInstance(context).userDao()) //OfflineUserRepository(MobileAppDataBase.getInstance(context).userDao())
RestUserRepository(ServerService.getInstance())
} }
companion object{ private val remoteKeyRepository: RemoteKeysRepositoryImpl by lazy{
const val TIMEOUT = 5000L RemoteKeysRepositoryImpl(MobileAppDataBase.getInstance(context).remoteKeysDao())
}
private val storyReposLocal: OfflineStoryRepository by lazy {
OfflineStoryRepository(MobileAppDataBase.getInstance(context).storyDao())
}
private val userReposLocal: OfflineUserRepository by lazy {
OfflineUserRepository(MobileAppDataBase.getInstance(context).userDao())
} }
} }

View File

@ -0,0 +1,129 @@
package com.example.mobileapp.api
import com.example.mobileapp.api.model.MailRemote
import com.example.mobileapp.api.model.StoryRemote
import com.example.mobileapp.api.model.UserRemote
import com.example.mobileapp.api.model.UserRemoteSignIn
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
interface ServerService {
//USER
@GET("user/get/{id}")
suspend fun getUser(
@Path("id") id: Int,
): UserRemote
@POST("user/signup")
suspend fun SignUp(
@Body user: UserRemote,
): UserRemote
@POST("user/signin")
suspend fun SignIn(
@Body user: UserRemoteSignIn
): UserRemote
@POST("user/update")
suspend fun updateUser(
@Body user: UserRemote
): UserRemote
@GET("user/getAll")
suspend fun getUsers(): List<UserRemote>
//STORY
@GET("story/get/{id}")
suspend fun getStory(
@Path("id") id: Int,
): StoryRemote
@GET("story/getAll")
suspend fun getStories(
@Query("page") page: Int,
@Query("size") size: Int,
): List<StoryRemote>
@POST("story/create")
suspend fun createStory(
@Body service: StoryRemote,
): StoryRemote
@PUT("story/update/{id}")
suspend fun updateStory(
@Path("id") id: Int,
@Body service: StoryRemote
): StoryRemote
@DELETE("story/delete/{id}")
suspend fun deleteStory(
@Path("id") id: Int
)
@GET("story/getByUser")
suspend fun getUserStories(
@Query("page") page: Int,
@Query("size") size: Int,
@Query("userId") userId: Int,
): List<StoryRemote>
//MAIL
@GET("mail/get/{id}")
suspend fun getMail(
@Path("id") id: Int,
): MailRemote
@GET("mail/getAll")
suspend fun getMails(
@Query("page") page: Int,
@Query("size") size: Int,
): List<MailRemote>
@POST("mail/create")
suspend fun createMail(
@Body service: MailRemote,
): MailRemote
@PUT("mail/update/{id}")
suspend fun updateMail(
@Path("id") id: Int,
@Body service: MailRemote
): MailRemote
@DELETE("mail/delete/{id}")
suspend fun deleteMail(
@Path("id") id: Int
)
//INSTANCE
companion object {
private const val BASE_URL = "https://7hz21fz1-8080.euw.devtunnels.ms/api/"
@Volatile
private var INSTANCE: ServerService? = null
fun getInstance(): ServerService {
return INSTANCE ?: synchronized(this) {
val client = OkHttpClient.Builder()
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
.create(ServerService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,108 @@
package com.example.mobileapp.api
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.mobileapp.api.model.toStory
import com.example.mobileapp.api.model.toUser
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.RemoteKeyType
import com.example.mobileapp.database.entities.RemoteKeys
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.repositories.OfflineStoryRepository
import com.example.mobileapp.database.repositories.OfflineUserRepository
import com.example.mobileapp.database.repositories.RemoteKeysRepositoryImpl
import retrofit2.HttpException
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class ServiceRemoteMediator(private val service: ServerService,
private val storyRepository: OfflineStoryRepository,
private val userRepository: OfflineUserRepository,
private val database: MobileAppDataBase,
private val dbRemoteKeyRepository: RemoteKeysRepositoryImpl
) : RemoteMediator<Int, Story>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Story>
): 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 users = service.getUsers().map { it.toUser() }
val stories = service.getStories(page, state.config.pageSize).map { it.toStory() }
val endOfPaginationReached = stories.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.STORY)
storyRepository.clearStories()
userRepository.clearUsers()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = stories.map {
RemoteKeys(
entityId = it.id!!,
type = RemoteKeyType.STORY,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
userRepository.insertUsers(users)
storyRepository.insertStories(stories)
}
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<Int, Story>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { story ->
story.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.STORY) }
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Story>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { story ->
story.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.STORY) }
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Story>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.id?.let { storyUid ->
dbRemoteKeyRepository.getAllRemoteKeys(storyUid, RemoteKeyType.STORY)
}
}
}
}

View File

@ -0,0 +1,27 @@
package com.example.mobileapp.api.model
import com.example.mobileapp.database.entities.Mail
import kotlinx.serialization.Serializable
import java.util.Date
@Serializable
data class MailRemote(
val id: Int? = null,
val message: String,
val postdate: Long? = Date().time,
val userId: Int
)
fun MailRemote.toMail(): Mail = Mail(
id,
message,
postdate,
userId
)
fun Mail.toMailRemote():MailRemote = MailRemote(
id,
message,
postdate,
userId
)

View File

@ -0,0 +1,24 @@
package com.example.mobileapp.api.model
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64
import java.io.ByteArrayOutputStream
class RemoteConverters {
companion object {
private const val CHARSET_UTF8 = "UTF-8"
fun fromBitmap(bitmap: Bitmap): String {
val outputStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
val byteArray = outputStream.toByteArray()
return Base64.encodeToString(byteArray, Base64.NO_WRAP)
}
fun toBitmap(base64String: String): Bitmap {
val byteArray = Base64.decode(base64String, Base64.NO_WRAP)
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
}
}

View File

@ -0,0 +1,35 @@
package com.example.mobileapp.api.model
import android.graphics.Bitmap
import com.example.mobileapp.database.entities.Story
import kotlinx.serialization.Serializable
import java.util.Date
@Serializable
data class StoryRemote(
val id: Int? = null,
val title: String,
val description: String,
val cover: String,
val postdate: Long? = Date().time,
val userId: Int
)
fun StoryRemote.toStory(): Story = Story(
id,
title,
description,
RemoteConverters.toBitmap(cover),
postdate,
userId
)
fun Story.toStoryRemote(): StoryRemote = StoryRemote(
id,
title,
description,
RemoteConverters.fromBitmap(cover),
postdate,
userId
)

View File

@ -0,0 +1,29 @@
package com.example.mobileapp.api.model
import com.example.mobileapp.database.entities.User
import kotlinx.serialization.Serializable
@Serializable
data class UserRemote(
val id: Int? = 0,
val login: String,
val password: String = "",
val email: String = "",
val photo: String? = null
)
fun UserRemote.toUser(): User = User(
id,
login,
password,
email,
photo?.let { RemoteConverters.toBitmap(it) },
)
fun User.toUserRemote():UserRemote = UserRemote(
id,
login,
password,
email,
photo?.let { RemoteConverters.fromBitmap(it) },
)

View File

@ -0,0 +1,9 @@
package com.example.mobileapp.api.model
import kotlinx.serialization.Serializable
@Serializable
data class UserRemoteSignIn(
val login: String = "",
val password: String = "",
)

View File

@ -0,0 +1,64 @@
package com.example.mobileapp.api.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.example.mobileapp.MobileAppContainer
import com.example.mobileapp.api.ServerService
import com.example.mobileapp.api.model.toMail
import com.example.mobileapp.api.model.toMailRemote
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.repositories.MailRepository
import kotlinx.coroutines.flow.Flow
class RestMailRepository(private var service: ServerService): MailRepository {
override fun getAllMails(): Flow<PagingData<Mail>> {
return Pager(
config = PagingConfig(
pageSize = MobileAppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = { MailPagingSource(service) }
).flow
}
override suspend fun getMail(id: Int): Mail? = service.getMail(id).toMail()
override suspend fun insertMail(mail: Mail) {
service.createMail(mail.toMailRemote())
}
override suspend fun updateMail(mail: Mail) {
TODO("Not yet implemented")
}
override suspend fun deleteMail(mail: Mail) {
TODO("Not yet implemented")
}
}
class MailPagingSource(private val service: ServerService) : PagingSource<Int, Mail>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Mail> {
try {
val nextPageNumber = params.key ?: 1
val pageSize = params.loadSize
val response = service.getMails(nextPageNumber, pageSize)
val mails = response.map { it.toMail() } // Преобразование MailRemote в Mail
return LoadResult.Page(
data = mails,
prevKey = if (nextPageNumber == 1) null else nextPageNumber - 1,
nextKey = if (mails.isEmpty()) null else nextPageNumber + 1
)
} catch (exception: Exception) {
return LoadResult.Error(exception)
}
}
override fun getRefreshKey(state: PagingState<Int, Mail>): Int? {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,118 @@
package com.example.mobileapp.api.repository
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.example.mobileapp.MobileAppContainer
import com.example.mobileapp.api.ServerService
import com.example.mobileapp.api.ServiceRemoteMediator
import com.example.mobileapp.api.model.toMail
import com.example.mobileapp.api.model.toStory
import com.example.mobileapp.api.model.toStoryRemote
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.repositories.OfflineStoryRepository
import com.example.mobileapp.database.repositories.OfflineUserRepository
import com.example.mobileapp.database.repositories.RemoteKeysRepositoryImpl
import com.example.mobileapp.database.repositories.StoryRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
class RestStoryRepository(private var service: ServerService,
private val dbStoryRepository: OfflineStoryRepository,
private val dbUserRepository: OfflineUserRepository,
private val database: MobileAppDataBase,
private val dbRemoteKeyRepository: RemoteKeysRepositoryImpl
): StoryRepository {
override fun getAllStories(): Flow<PagingData<Story>> {
val pagingSourceFactory = {
dbStoryRepository.getAllStoriesPagingSource()
}
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = MobileAppContainer.LIMIT,
enablePlaceholders = false
),
remoteMediator = ServiceRemoteMediator(
service,
dbStoryRepository,
dbUserRepository,
database,
dbRemoteKeyRepository,
),
pagingSourceFactory = pagingSourceFactory
).flow
/*return Pager(
config = PagingConfig(
pageSize = MobileAppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = { StoryPagingSource(service) }
).flow*/
}
override fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>> {
return Pager(
config = PagingConfig(
pageSize = MobileAppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = { StoryPagingSource(service, userId) }
).flow
}
override suspend fun getStoryById(id: Int): Story? = service.getStory(id).toStory()
override suspend fun insertStory(story: Story) {
service.createStory(story.toStoryRemote())
}
override suspend fun updateStory(story: Story) {
story.id?.let {
service.updateStory(it, story.toStoryRemote())
}
}
override suspend fun deleteStory(story: Story) {
try {
story.id?.let { this.service.deleteStory(it) }
dbStoryRepository.deleteStory(story)
}catch (ex: Exception){}
}
}
class StoryPagingSource(private val service: ServerService,
private val userId: Int? = null) : PagingSource<Int, Story>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Story> {
try {
val nextPageNumber = params.key ?: 1
val pageSize = params.loadSize
val response = if (userId != null) {
service.getUserStories(nextPageNumber, pageSize, userId)
} else {
service.getStories(nextPageNumber, pageSize)
}
val stories = response.map { it.toStory() }
return LoadResult.Page(
data = stories,
prevKey = if (nextPageNumber == 1) null else nextPageNumber - 1,
nextKey = if (stories.isEmpty()) null else nextPageNumber + 1
)
} catch (exception: Exception) {
return LoadResult.Error(exception)
}
}
override fun getRefreshKey(state: PagingState<Int, Story>): Int? {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,34 @@
package com.example.mobileapp.api.repository
import com.example.mobileapp.api.ServerService
import com.example.mobileapp.api.model.UserRemoteSignIn
import com.example.mobileapp.api.model.toUser
import com.example.mobileapp.api.model.toUserRemote
import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.repositories.UserRepository
import kotlinx.coroutines.flow.Flow
class RestUserRepository(private var service: ServerService): UserRepository {
override fun getAllUsers(): Flow<List<User>> {
TODO("Not yet implemented")
}
override suspend fun getUser(id: Int): User = service.getUser(id).toUser()
override suspend fun getUserByLogin(user: UserRemoteSignIn): User {
return service.SignIn(user).toUser()
}
override suspend fun insertUser(user: User) {
service.SignUp(user.toUserRemote())
}
override suspend fun updateUser(user: User) {
service.updateUser(user.toUserRemote())
}
override suspend fun deleteUser(user: User) {
TODO("Not yet implemented")
}
}

View File

@ -1,5 +1,7 @@
package com.example.mobileapp.components package com.example.mobileapp.components
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -170,6 +172,7 @@ fun StoryListItem(item: Story, navController: NavHostController,
message = "Вы уверены что хотите удалить запись?", onConfirmAction = { message = "Вы уверены что хотите удалить запись?", onConfirmAction = {
storyViewModel.deleteStory(item) storyViewModel.deleteStory(item)
showDialog.value = !showDialog.value showDialog.value = !showDialog.value
navController.navigate("story")
}, onDismissAction = { }, onDismissAction = {
showDialog.value = !showDialog.value showDialog.value = !showDialog.value
}) })
@ -199,16 +202,20 @@ fun MailListItem(item: Mail, navController: NavHostController,
userViewModel: UserViewModel = viewModel( userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory factory = MobileAppViewModelProvider.Factory
)) { )) {
val context = LocalContext.current
val isExpanded = remember { val isExpanded = remember {
mutableStateOf(false) mutableStateOf(false)
} }
val userName = remember { mutableStateOf("") } val userPhoto = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.post)) }
val userName = remember { mutableStateOf("UserName") }
LaunchedEffect(Unit){ LaunchedEffect(Unit){
userViewModel.getUser(item.userId).collect { val user = userViewModel.getUser(item.userId)
if (it != null) { if (user != null) {
userName.value = it.email userName.value = user.email
if (user.photo != null){
userPhoto.value = user.photo
} }
} }
} }
@ -234,7 +241,7 @@ fun MailListItem(item: Mail, navController: NavHostController,
Row( Row(
verticalAlignment = Alignment.Top verticalAlignment = Alignment.Top
){ ){
Image(painter = painterResource(id = R.drawable.post), Image(bitmap = userPhoto.value.asImageBitmap(),
contentDescription = "message", contentDescription = "message",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier

View File

@ -9,22 +9,25 @@ import androidx.room.TypeConverters
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.database.dao.MailDao import com.example.mobileapp.database.dao.MailDao
import com.example.mobileapp.database.dao.RemoteKeysDao
import com.example.mobileapp.database.dao.StoryDao import com.example.mobileapp.database.dao.StoryDao
import com.example.mobileapp.database.dao.UserDao import com.example.mobileapp.database.dao.UserDao
import com.example.mobileapp.database.entities.Converters import com.example.mobileapp.database.entities.Converters
import com.example.mobileapp.database.entities.Mail import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.RemoteKeys
import com.example.mobileapp.database.entities.Story import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.entities.User import com.example.mobileapp.database.entities.User
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Database(entities = [User::class, Story::class, Mail::class], version = 1, exportSchema = false) @Database(entities = [User::class, Story::class, Mail::class, RemoteKeys::class], version = 10, exportSchema = false)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class MobileAppDataBase : RoomDatabase() { abstract class MobileAppDataBase : RoomDatabase() {
abstract fun userDao(): UserDao abstract fun userDao(): UserDao
abstract fun storyDao(): StoryDao abstract fun storyDao(): StoryDao
abstract fun mailDao(): MailDao abstract fun mailDao(): MailDao
abstract fun remoteKeysDao(): RemoteKeysDao
companion object{ companion object{
private const val DB_NAME: String = "my-db" private const val DB_NAME: String = "my-db"
@ -33,7 +36,7 @@ abstract class MobileAppDataBase : RoomDatabase() {
private var INSTANCE: MobileAppDataBase? = null private var INSTANCE: MobileAppDataBase? = null
suspend fun initialDataBase(appContext: Context){ suspend fun initialDataBase(appContext: Context){
INSTANCE?.let { database -> /*INSTANCE?.let { database ->
val userDao = database.userDao() val userDao = database.userDao()
userDao.insert(User(id = 1, login = "Дзюнзи Ито", password = "1234", email = "ito@gmail.com")) userDao.insert(User(id = 1, login = "Дзюнзи Ито", password = "1234", email = "ito@gmail.com"))
userDao.insert(User(id = 2, login = "Стивен Кинг", password = "4321", email = "king@gmail.com")) userDao.insert(User(id = 2, login = "Стивен Кинг", password = "4321", email = "king@gmail.com"))
@ -53,9 +56,7 @@ abstract class MobileAppDataBase : RoomDatabase() {
mailDao.insert(Mail(message = "Меня отменили в Твиттере", userId = 2)) mailDao.insert(Mail(message = "Меня отменили в Твиттере", userId = 2))
} }
} }
/*mailDao.insert(Mail(message = "Выложил новые страницы", userId = 1)) }*/
mailDao.insert(Mail(message = "Меня отменили в Твиттере", userId = 2))*/
}
} }
fun getInstance(appContext: Context): MobileAppDataBase { fun getInstance(appContext: Context): MobileAppDataBase {

View File

@ -17,7 +17,7 @@ interface MailDao {
fun getAll(): PagingSource<Int, Mail> fun getAll(): PagingSource<Int, Mail>
@Query("select * from mails where mails.id = :id") @Query("select * from mails where mails.id = :id")
fun getById(id: Int): Flow<Mail?> suspend fun getById(id: Int): Mail?
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(mail: Mail) suspend fun insert(mail: Mail)

View File

@ -0,0 +1,18 @@
package com.example.mobileapp.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.mobileapp.database.entities.RemoteKeyType
import com.example.mobileapp.database.entities.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<RemoteKeys>)
@Query("DELETE FROM remote_keys WHERE type = :type")
suspend fun clearRemoteKeys(type: RemoteKeyType)
}

View File

@ -16,17 +16,20 @@ interface StoryDao {
fun getAll(): PagingSource<Int, Story> fun getAll(): PagingSource<Int, Story>
@Query("select * from stories where stories.id = :id") @Query("select * from stories where stories.id = :id")
fun getById(id: Int): Flow<Story?> suspend fun getById(id: Int): Story?
@Query("select * from stories where stories.user_id = :userId order by stories.id desc") @Query("select * from stories where stories.user_id = :userId order by stories.id desc")
fun getByUserId(userId: Int): PagingSource<Int, Story> fun getByUserId(userId: Int): Flow<List<Story>>
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(story: Story) suspend fun insert(vararg story: Story)
@Update @Update
suspend fun update(story: Story) suspend fun update(story: Story)
@Delete @Delete
suspend fun delete(story: Story) suspend fun delete(story: Story)
@Query("delete from stories")
suspend fun deleteAll()
} }

View File

@ -15,17 +15,20 @@ interface UserDao {
fun getAll(): Flow<List<User>> fun getAll(): Flow<List<User>>
@Query("select * from users where users.id = :id") @Query("select * from users where users.id = :id")
fun getById(id: Int): Flow<User?> suspend fun getById(id: Int): User?
@Query("select * from users where users.login = :login") @Query("select * from users where users.login = :login")
suspend fun getByLogin(login: String): User? suspend fun getByLogin(login: String): User?
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(user: User) suspend fun insert(vararg user: User)
@Update @Update
suspend fun update(user: User) suspend fun update(user: User)
@Delete @Delete
suspend fun delete(user: User) suspend fun delete(user: User)
@Query("delete from stories")
suspend fun deleteAll()
} }

View File

@ -4,8 +4,6 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import androidx.room.TypeConverter import androidx.room.TypeConverter
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.text.SimpleDateFormat
import java.util.Date
class Converters { class Converters {
@TypeConverter @TypeConverter

View File

@ -0,0 +1,23 @@
package com.example.mobileapp.database.entities
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
enum class RemoteKeyType(private val type: String) {
STORY(Story::class.simpleName ?: "Story");
@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?
)

View File

@ -5,7 +5,6 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.util.Calendar
import java.util.Date import java.util.Date
@Entity( @Entity(

View File

@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow
interface MailRepository { interface MailRepository {
fun getAllMails(): Flow<PagingData<Mail>> fun getAllMails(): Flow<PagingData<Mail>>
fun getMail(id: Int): Flow<Mail?> suspend fun getMail(id: Int): Mail?
suspend fun insertMail(mail: Mail) suspend fun insertMail(mail: Mail)

View File

@ -23,7 +23,7 @@ class OfflineMailRepository(private val mailDao: MailDao): MailRepository {
).flow ).flow
} }
override fun getMail(id: Int): Flow<Mail?> = mailDao.getById(id) override suspend fun getMail(id: Int): Mail? = mailDao.getById(id)
override suspend fun insertMail(mail: Mail) = mailDao.insert(mail) override suspend fun insertMail(mail: Mail) = mailDao.insert(mail)

View File

@ -3,6 +3,7 @@ package com.example.mobileapp.database.repositories
import androidx.paging.Pager import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.mobileapp.database.dao.StoryDao import com.example.mobileapp.database.dao.StoryDao
import com.example.mobileapp.database.entities.Story import com.example.mobileapp.database.entities.Story
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -24,25 +25,20 @@ class OfflineStoryRepository(private val storyDao: StoryDao): StoryRepository {
} }
override fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>> { override fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>> {
return Pager( TODO("Not yet implemented")
config = PagingConfig(
pageSize = 5,
prefetchDistance = 1,
enablePlaceholders = true,
initialLoadSize = 10,
maxSize = 15
),
pagingSourceFactory = {
storyDao.getByUserId(userId)
}
).flow
} }
override fun getStoryById(id: Int): Flow<Story?> = storyDao.getById(id) override suspend fun getStoryById(id: Int): Story? = storyDao.getById(id)
override suspend fun insertStory(story: Story) = storyDao.insert(story) override suspend fun insertStory(story: Story) = storyDao.insert(story)
override suspend fun updateStory(story: Story) = storyDao.update(story) override suspend fun updateStory(story: Story) = storyDao.update(story)
override suspend fun deleteStory(story: Story) = storyDao.delete(story) override suspend fun deleteStory(story: Story) = storyDao.delete(story)
suspend fun clearStories() = storyDao.deleteAll()
suspend fun insertStories(stories: List<Story>) =
storyDao.insert(*stories.toTypedArray())
fun getAllStoriesPagingSource(): PagingSource<Int, Story> = storyDao.getAll()
} }

View File

@ -1,19 +1,25 @@
package com.example.mobileapp.database.repositories package com.example.mobileapp.database.repositories
import com.example.mobileapp.api.model.UserRemoteSignIn
import com.example.mobileapp.database.dao.UserDao import com.example.mobileapp.database.dao.UserDao
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.entities.User import com.example.mobileapp.database.entities.User
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class OfflineUserRepository(private val userDao: UserDao): UserRepository { class OfflineUserRepository(private val userDao: UserDao): UserRepository {
override fun getAllUsers(): Flow<List<User>> = userDao.getAll() override fun getAllUsers(): Flow<List<User>> = userDao.getAll()
override fun getUser(id: Int): Flow<User?> = userDao.getById(id) override suspend fun getUser(id: Int): User? = userDao.getById(id)
override suspend fun getUserByLogin(login: String): User? = userDao.getByLogin(login) override suspend fun getUserByLogin(user: UserRemoteSignIn): User? = userDao.getByLogin(user.login)
override suspend fun insertUser(user: User) = userDao.insert(user) override suspend fun insertUser(user: User) = userDao.insert(user)
override suspend fun updateUser(user: User) = userDao.update(user) override suspend fun updateUser(user: User) = userDao.update(user)
override suspend fun deleteUser(user: User) = userDao.delete(user) override suspend fun deleteUser(user: User) = userDao.delete(user)
suspend fun clearUsers() = userDao.deleteAll()
suspend fun insertUsers(users: List<User>) =
userDao.insert(*users.toTypedArray())
} }

View File

@ -0,0 +1,10 @@
package com.example.mobileapp.database.repositories
import com.example.mobileapp.database.entities.RemoteKeyType
import com.example.mobileapp.database.entities.RemoteKeys
interface RemoteKeyRepository {
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
suspend fun deleteRemoteKey(type: RemoteKeyType)
}

View File

@ -0,0 +1,16 @@
package com.example.mobileapp.database.repositories
import com.example.mobileapp.database.dao.RemoteKeysDao
import com.example.mobileapp.database.entities.RemoteKeyType
import com.example.mobileapp.database.entities.RemoteKeys
class RemoteKeysRepositoryImpl(private val remoteKeysDao: RemoteKeysDao): RemoteKeyRepository {
override suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType) =
remoteKeysDao.getRemoteKeys(id, type)
override suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>) =
remoteKeysDao.insertAll(remoteKeys)
override suspend fun deleteRemoteKey(type: RemoteKeyType) =
remoteKeysDao.clearRemoteKeys(type)
}

View File

@ -10,7 +10,7 @@ interface StoryRepository {
fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>> fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>>
fun getStoryById(id: Int): Flow<Story?> suspend fun getStoryById(id: Int): Story?
suspend fun insertStory(story: Story) suspend fun insertStory(story: Story)

View File

@ -1,14 +1,15 @@
package com.example.mobileapp.database.repositories package com.example.mobileapp.database.repositories
import com.example.mobileapp.api.model.UserRemoteSignIn
import com.example.mobileapp.database.entities.User import com.example.mobileapp.database.entities.User
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
interface UserRepository { interface UserRepository {
fun getAllUsers(): Flow<List<User>> fun getAllUsers(): Flow<List<User>>
fun getUser(id: Int): Flow<User?> suspend fun getUser(id: Int): User?
suspend fun getUserByLogin(login: String): User? suspend fun getUserByLogin(user: UserRemoteSignIn): User?
suspend fun insertUser(user: User) suspend fun insertUser(user: User)

View File

@ -12,7 +12,7 @@ import kotlinx.coroutines.launch
class MailViewModel(private val mailRepository: MailRepository): ViewModel() { class MailViewModel(private val mailRepository: MailRepository): ViewModel() {
val getAllMails: Flow<PagingData<Mail>> = mailRepository.getAllMails().cachedIn(viewModelScope) val getAllMails: Flow<PagingData<Mail>> = mailRepository.getAllMails().cachedIn(viewModelScope)
fun getMail(id: Int): Flow<Mail?> = mailRepository.getMail(id) suspend fun getMail(id: Int): Mail? = mailRepository.getMail(id)
fun insertMail(mail: Mail) = viewModelScope.launch { fun insertMail(mail: Mail) = viewModelScope.launch {
mailRepository.insertMail(mail) mailRepository.insertMail(mail)

View File

@ -4,18 +4,22 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.cachedIn import androidx.paging.cachedIn
import com.example.mobileapp.GlobalUser
import com.example.mobileapp.database.entities.Story import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.repositories.StoryRepository import com.example.mobileapp.database.repositories.StoryRepository
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class StoryViewModel(private val storyRepository: StoryRepository): ViewModel() { class StoryViewModel(private val storyRepository: StoryRepository): ViewModel() {
val getAllStories: Flow<PagingData<Story>> = storyRepository.getAllStories().cachedIn(viewModelScope) val getAllStories: Flow<PagingData<Story>> = storyRepository.getAllStories().cachedIn(viewModelScope)
fun getStoryById(id: Int): Flow<Story?> = storyRepository.getStoryById(id) suspend fun getStoryById(id: Int): Story? = storyRepository.getStoryById(id)
fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>> = storyRepository.getStoriesByUserId(userId).cachedIn(viewModelScope) val getStoriesByUserId: Flow<PagingData<Story>> = GlobalUser.getInstance().getUser()?.id?.let {
storyRepository.getStoriesByUserId(it).cachedIn(viewModelScope)
} ?: flowOf(PagingData.empty())
fun insertStory(story: Story) = viewModelScope.launch { fun insertStory(story: Story) = viewModelScope.launch {
storyRepository.insertStory(story) storyRepository.insertStory(story)

View File

@ -3,15 +3,18 @@ package com.example.mobileapp.database.viewmodels
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.mobileapp.GlobalUser import com.example.mobileapp.GlobalUser
import com.example.mobileapp.api.model.UserRemoteSignIn
import com.example.mobileapp.api.model.toUserRemote
import com.example.mobileapp.database.entities.User import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.repositories.OfflineUserRepository
import com.example.mobileapp.database.repositories.UserRepository import com.example.mobileapp.database.repositories.UserRepository
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class UserViewModel(private val userRepository: UserRepository): ViewModel() { class UserViewModel(private val userRepository: UserRepository): ViewModel() {
val getAllUsers = userRepository.getAllUsers() //val getAllUsers = userRepository.getAllUsers()
fun getUser(id: Int): Flow<User?> = userRepository.getUser(id) suspend fun getUser(id: Int): User? = userRepository.getUser(id)
fun updateUser(user: User) = viewModelScope.launch { fun updateUser(user: User) = viewModelScope.launch {
if (user.login.isEmpty()){ if (user.login.isEmpty()){
@ -34,24 +37,20 @@ class UserViewModel(private val userRepository: UserRepository): ViewModel() {
} }
fun regUser(user: User) = viewModelScope.launch { fun regUser(user: User) = viewModelScope.launch {
val globalUser = userRepository.getUserByLogin(user.login) if(user.password.isEmpty()){
globalUser?.let {
return@launch return@launch
} ?: run {
if(user.password.isEmpty()){
return@launch
}
if(user.email.isEmpty() || !isValidEmail(user.email)){
return@launch
}
userRepository.insertUser(user)
GlobalUser.getInstance().setUser(userRepository.getUserByLogin(user.login))
} }
if(user.email.isEmpty() || !isValidEmail(user.email)){
return@launch
}
userRepository.insertUser(user)
GlobalUser.getInstance().setUser(userRepository.getUserByLogin(
UserRemoteSignIn(user.login, user.password)))
} }
fun authUser(user: User) = viewModelScope.launch { fun authUser(user: User) = viewModelScope.launch {
val globalUser = userRepository.getUserByLogin(user.login) val globalUser = userRepository.getUserByLogin(UserRemoteSignIn(user.login, user.password))
globalUser?.let { globalUser?.let {
if (user.password.isNotEmpty() && user.password == globalUser.password){ if (user.password.isNotEmpty() && user.password == globalUser.password){
GlobalUser.getInstance().setUser(globalUser) GlobalUser.getInstance().setUser(globalUser)

View File

@ -40,7 +40,7 @@ fun Authorization(navController: NavHostController,
userViewModel: UserViewModel = viewModel( userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory factory = MobileAppViewModelProvider.Factory
)) { )) {
val users = userViewModel.getAllUsers.collectAsState(emptyList()).value //val users = userViewModel.getAllUsers.collectAsState(emptyList()).value
val login = remember { mutableStateOf("") } val login = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") } val password = remember { mutableStateOf("") }

View File

@ -78,16 +78,11 @@ fun EditStoryScreen(navController: NavHostController, storyId: Int? = null,
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
storyId?.let { storyId?.let {
storyViewModel.getStoryById(storyId).collect { val story = storyViewModel.getStoryById(storyId)
if (it != null) { if (story != null) {
cover.value = it.cover cover.value = story.cover
} title.value = story.title
if (it != null) { description.value = story.description
title.value = it.title
}
if (it != null) {
description.value = it.description
}
} }
} }
} }

View File

@ -58,6 +58,5 @@ fun ListMailScreen(navController: NavHostController,
} }
} }
} }
//DataListScroll(navController, mails)
} }
} }

View File

@ -3,10 +3,17 @@ package com.example.mobileapp.screens
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
@ -20,14 +27,15 @@ import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.StoryViewModel import com.example.mobileapp.database.viewmodels.StoryViewModel
import com.example.mobileapp.ui.theme.BackgroundItem1 import com.example.mobileapp.ui.theme.BackgroundItem1
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable @Composable
fun ListStoryScreen(navController: NavHostController, fun ListStoryScreen(navController: NavHostController,
storyViewModel: StoryViewModel = viewModel( storyViewModel: StoryViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory factory = MobileAppViewModelProvider.Factory
)) { )) {
val stories = storyViewModel.getStoriesByUserId(GlobalUser.getInstance().getUser()?.id!!).collectAsLazyPagingItems() val stories = storyViewModel.getStoriesByUserId.collectAsLazyPagingItems()
//val stories = storyViewModel.getAllStories.collectAsLazyPagingItems()
Column( Column(
modifier = Modifier modifier = Modifier
@ -50,6 +58,5 @@ fun ListStoryScreen(navController: NavHostController,
} }
} }
} }
//DataListScroll(navController, stories)
} }
} }

View File

@ -54,12 +54,24 @@ fun StoryViewScreen(navController: NavHostController, storyId: Int,
val description = remember { mutableStateOf("") } val description = remember { mutableStateOf("") }
val postdate = remember { mutableStateOf<Long>(0) } val postdate = remember { mutableStateOf<Long>(0) }
val story by storyViewModel.getStoryById(storyId).collectAsState(null) /*val story by storyViewModel.getStoryById(storyId).collectAsState(null)
story?.let { story?.let {
cover.value = it.cover cover.value = it.cover
title.value = it.title title.value = it.title
description.value = it.description description.value = it.description
postdate.value = it.postdate!! postdate.value = it.postdate!!
}*/
LaunchedEffect(Unit) {
storyId?.let {
val story = storyViewModel.getStoryById(storyId)
if (story != null) {
cover.value = story.cover
title.value = story.title
description.value = story.description
postdate.value = story.postdate!!
}
}
} }
Column( Column(
@ -112,19 +124,17 @@ fun MailViewScreen(navController: NavHostController, mailId: Int,
val postdate = remember { mutableStateOf<Long>(0) } val postdate = remember { mutableStateOf<Long>(0) }
LaunchedEffect(Unit){ LaunchedEffect(Unit){
mailViewModel.getMail(mailId).collect{ val mail = mailViewModel.getMail(mailId)
if (it != null) { if (mail != null) {
message.value = it.message message.value = mail.message
postdate.value = it.postdate!! postdate.value = mail.postdate!!
userViewModel.getUser(it.userId).collect {user -> }
if (user != null) { val user = mail?.let { userViewModel.getUser(it.userId) }
if(user.photo != null) { if (user != null) {
photo.value = user.photo if(user.photo != null) {
} photo.value = user.photo
userName.value = user.email
}
}
} }
userName.value = user.email
} }
} }