5 лаба готова и сдана

This commit is contained in:
maxnes3 2023-12-23 11:23:33 +04:00
parent ca101dfb80
commit 8e644e6ba0
17 changed files with 225 additions and 54 deletions

View File

@ -14,7 +14,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MobileApp"
tools:targetApi="31">
tools:targetApi="31"
android:networkSecurityConfig="@xml/network_security_config">
<activity
android:name=".MainActivity"
android:exported="true"

View File

@ -35,6 +35,7 @@ class MobileAppDataContainer(private val context: Context): MobileAppContainer {
//OfflineStoryRepository(MobileAppDataBase.getInstance(context).storyDao())
RestStoryRepository(ServerService.getInstance(),
storyReposLocal,
userReposLocal,
MobileAppDataBase.getInstance(context),
remoteKeyRepository)
}
@ -51,4 +52,8 @@ class MobileAppDataContainer(private val context: Context): MobileAppContainer {
private val storyReposLocal: OfflineStoryRepository by lazy {
OfflineStoryRepository(MobileAppDataBase.getInstance(context).storyDao())
}
private val userReposLocal: OfflineUserRepository by lazy {
OfflineUserRepository(MobileAppDataBase.getInstance(context).userDao())
}
}

View File

@ -19,7 +19,7 @@ import retrofit2.http.Query
interface ServerService {
//USER
@GET("USER/get/{id}")
@GET("user/get/{id}")
suspend fun getUser(
@Path("id") id: Int,
): UserRemote
@ -39,6 +39,9 @@ interface ServerService {
@Body user: UserRemote
): UserRemote
@GET("user/getAll")
suspend fun getUsers(): List<UserRemote>
//STORY
@GET("story/get/{id}")
suspend fun getStory(

View File

@ -6,11 +6,13 @@ 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
@ -18,6 +20,7 @@ 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>() {
@ -48,12 +51,14 @@ class ServiceRemoteMediator(private val service: ServerService,
}
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
@ -66,6 +71,7 @@ class ServiceRemoteMediator(private val service: ServerService,
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
userRepository.insertUsers(users)
storyRepository.insertStories(stories)
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)

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

@ -208,9 +208,9 @@ fun MailListItem(item: Mail, navController: NavHostController,
}
val userPhoto = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.post)) }
val userName = remember { mutableStateOf("") }
val userName = remember { mutableStateOf("UserName") }
/*LaunchedEffect(Unit){
LaunchedEffect(Unit){
val user = userViewModel.getUser(item.userId)
if (user != null) {
userName.value = user.email
@ -218,7 +218,7 @@ fun MailListItem(item: Mail, navController: NavHostController,
userPhoto.value = user.photo
}
}
}*/
}
Card(
modifier = Modifier

View File

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

View File

@ -21,11 +21,14 @@ interface UserDao {
suspend fun getByLogin(login: String): User?
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(user: User)
suspend fun insert(vararg user: User)
@Update
suspend fun update(user: User)
@Delete
suspend fun delete(user: User)
@Query("delete from stories")
suspend fun deleteAll()
}

View File

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

View File

@ -23,7 +23,7 @@ class OfflineMailRepository(private val mailDao: MailDao): MailRepository {
).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)

View File

@ -2,6 +2,7 @@ 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.entities.Story
import com.example.mobileapp.database.entities.User
import kotlinx.coroutines.flow.Flow
@ -17,4 +18,8 @@ class OfflineUserRepository(private val userDao: UserDao): UserRepository {
override suspend fun updateUser(user: User) = userDao.update(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

@ -12,7 +12,7 @@ import kotlinx.coroutines.launch
class MailViewModel(private val mailRepository: MailRepository): ViewModel() {
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 {
mailRepository.insertMail(mail)

View File

@ -84,17 +84,6 @@ fun EditStoryScreen(navController: NavHostController, storyId: Int? = null,
title.value = story.title
description.value = story.description
}
/*storyViewModel.getStoryById(storyId).collect {
if (it != null) {
cover.value = it.cover
}
if (it != null) {
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

@ -36,33 +36,12 @@ fun ListStoryScreen(navController: NavHostController,
factory = MobileAppViewModelProvider.Factory
)) {
val stories = storyViewModel.getStoriesByUserId.collectAsLazyPagingItems()
/*val stories = remember { mutableStateListOf<Story>() }
LaunchedEffect(Unit){
withContext(Dispatchers.IO) {
storyViewModel.getStoriesByUserId(GlobalUser.getInstance().getUser()?.id!!).collect {
stories.clear()
stories.addAll(it)
}
}
}*/
Column(
modifier = Modifier
.fillMaxSize()
.background(BackgroundItem1)
) {
/*LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
){
item {
addNewListItem(navController, "editstory")
}
itemsIndexed(stories){ _, item ->
StoryListItem(item = item, navController = navController)
}
}*/
LazyVerticalGrid(
columns = GridCells.Fixed(1)
) {

View File

@ -124,18 +124,17 @@ fun MailViewScreen(navController: NavHostController, mailId: Int,
val postdate = remember { mutableStateOf<Long>(0) }
LaunchedEffect(Unit){
mailViewModel.getMail(mailId).collect{
if (it != null) {
message.value = it.message
postdate.value = it.postdate!!
val user = userViewModel.getUser(it.userId)
if (user != null) {
if(user.photo != null) {
photo.value = user.photo
}
userName.value = user.email
}
val mail = mailViewModel.getMail(mailId)
if (mail != null) {
message.value = mail.message
postdate.value = mail.postdate!!
}
val user = mail?.let { userViewModel.getUser(it.userId) }
if (user != null) {
if(user.photo != null) {
photo.value = user.photo
}
userName.value = user.email
}
}