From 8e644e6ba085131c1dac9e4f3945dc1f66b35dde Mon Sep 17 00:00:00 2001 From: maxnes3 <112558334+maxnes3@users.noreply.github.com> Date: Sat, 23 Dec 2023 11:23:33 +0400 Subject: [PATCH] =?UTF-8?q?5=20=D0=BB=D0=B0=D0=B1=D0=B0=20=D0=B3=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=D0=B0=20=D0=B8=20=D1=81=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 3 +- .../example/mobileapp/MobileAppContainer.kt | 5 + .../example/mobileapp/api/ServerService.kt | 5 +- .../mobileapp/api/ServiceRemoteMediator.kt | 6 + .../api/repository/RestMailRepository.kt | 64 ++++++++++ .../api/repository/RestStoryRepository.kt | 118 ++++++++++++++++++ .../mobileapp/components/ListContent.kt | 6 +- .../example/mobileapp/database/dao/MailDao.kt | 2 +- .../example/mobileapp/database/dao/UserDao.kt | 5 +- .../database/repositories/MailRepository.kt | 2 +- .../repositories/OfflineMailRepository.kt | 2 +- .../repositories/OfflineUserRepository.kt | 5 + .../database/viewmodels/MailViewModel.kt | 2 +- .../example/mobileapp/screens/EditScreens.kt | 11 -- .../mobileapp/screens/ListMailScreen.kt | 1 - .../mobileapp/screens/ListStoryScreen.kt | 21 ---- .../example/mobileapp/screens/ViewScreens.kt | 21 ++-- 17 files changed, 225 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/com/example/mobileapp/api/repository/RestMailRepository.kt create mode 100644 app/src/main/java/com/example/mobileapp/api/repository/RestStoryRepository.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 277daa4..b54eb05 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -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"> + //STORY @GET("story/get/{id}") suspend fun getStory( diff --git a/app/src/main/java/com/example/mobileapp/api/ServiceRemoteMediator.kt b/app/src/main/java/com/example/mobileapp/api/ServiceRemoteMediator.kt index b64f206..52e915e 100644 --- a/app/src/main/java/com/example/mobileapp/api/ServiceRemoteMediator.kt +++ b/app/src/main/java/com/example/mobileapp/api/ServiceRemoteMediator.kt @@ -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() { @@ -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) diff --git a/app/src/main/java/com/example/mobileapp/api/repository/RestMailRepository.kt b/app/src/main/java/com/example/mobileapp/api/repository/RestMailRepository.kt new file mode 100644 index 0000000..b223f38 --- /dev/null +++ b/app/src/main/java/com/example/mobileapp/api/repository/RestMailRepository.kt @@ -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> { + 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() { + override suspend fun load(params: LoadParams): LoadResult { + 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? { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mobileapp/api/repository/RestStoryRepository.kt b/app/src/main/java/com/example/mobileapp/api/repository/RestStoryRepository.kt new file mode 100644 index 0000000..fac7477 --- /dev/null +++ b/app/src/main/java/com/example/mobileapp/api/repository/RestStoryRepository.kt @@ -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> { + 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> { + 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() { + override suspend fun load(params: LoadParams): LoadResult { + 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? { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mobileapp/components/ListContent.kt b/app/src/main/java/com/example/mobileapp/components/ListContent.kt index 0b8d692..1633f08 100644 --- a/app/src/main/java/com/example/mobileapp/components/ListContent.kt +++ b/app/src/main/java/com/example/mobileapp/components/ListContent.kt @@ -208,9 +208,9 @@ fun MailListItem(item: Mail, navController: NavHostController, } val userPhoto = remember { mutableStateOf(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 diff --git a/app/src/main/java/com/example/mobileapp/database/dao/MailDao.kt b/app/src/main/java/com/example/mobileapp/database/dao/MailDao.kt index 9bfb515..30a53a9 100644 --- a/app/src/main/java/com/example/mobileapp/database/dao/MailDao.kt +++ b/app/src/main/java/com/example/mobileapp/database/dao/MailDao.kt @@ -17,7 +17,7 @@ interface MailDao { fun getAll(): PagingSource @Query("select * from mails where mails.id = :id") - fun getById(id: Int): Flow + suspend fun getById(id: Int): Mail? @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun insert(mail: Mail) diff --git a/app/src/main/java/com/example/mobileapp/database/dao/UserDao.kt b/app/src/main/java/com/example/mobileapp/database/dao/UserDao.kt index b76a50a..ed577e9 100644 --- a/app/src/main/java/com/example/mobileapp/database/dao/UserDao.kt +++ b/app/src/main/java/com/example/mobileapp/database/dao/UserDao.kt @@ -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() } \ No newline at end of file diff --git a/app/src/main/java/com/example/mobileapp/database/repositories/MailRepository.kt b/app/src/main/java/com/example/mobileapp/database/repositories/MailRepository.kt index ab564bf..0dfef61 100644 --- a/app/src/main/java/com/example/mobileapp/database/repositories/MailRepository.kt +++ b/app/src/main/java/com/example/mobileapp/database/repositories/MailRepository.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow interface MailRepository { fun getAllMails(): Flow> - fun getMail(id: Int): Flow + suspend fun getMail(id: Int): Mail? suspend fun insertMail(mail: Mail) diff --git a/app/src/main/java/com/example/mobileapp/database/repositories/OfflineMailRepository.kt b/app/src/main/java/com/example/mobileapp/database/repositories/OfflineMailRepository.kt index 98e50e5..adfea10 100644 --- a/app/src/main/java/com/example/mobileapp/database/repositories/OfflineMailRepository.kt +++ b/app/src/main/java/com/example/mobileapp/database/repositories/OfflineMailRepository.kt @@ -23,7 +23,7 @@ class OfflineMailRepository(private val mailDao: MailDao): MailRepository { ).flow } - override fun getMail(id: Int): Flow = mailDao.getById(id) + override suspend fun getMail(id: Int): Mail? = mailDao.getById(id) override suspend fun insertMail(mail: Mail) = mailDao.insert(mail) diff --git a/app/src/main/java/com/example/mobileapp/database/repositories/OfflineUserRepository.kt b/app/src/main/java/com/example/mobileapp/database/repositories/OfflineUserRepository.kt index 23fcf76..8f09ec4 100644 --- a/app/src/main/java/com/example/mobileapp/database/repositories/OfflineUserRepository.kt +++ b/app/src/main/java/com/example/mobileapp/database/repositories/OfflineUserRepository.kt @@ -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) = + userDao.insert(*users.toTypedArray()) } \ No newline at end of file diff --git a/app/src/main/java/com/example/mobileapp/database/viewmodels/MailViewModel.kt b/app/src/main/java/com/example/mobileapp/database/viewmodels/MailViewModel.kt index 9ba9a84..6d4d8c4 100644 --- a/app/src/main/java/com/example/mobileapp/database/viewmodels/MailViewModel.kt +++ b/app/src/main/java/com/example/mobileapp/database/viewmodels/MailViewModel.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.launch class MailViewModel(private val mailRepository: MailRepository): ViewModel() { val getAllMails: Flow> = mailRepository.getAllMails().cachedIn(viewModelScope) - fun getMail(id: Int): Flow = mailRepository.getMail(id) + suspend fun getMail(id: Int): Mail? = mailRepository.getMail(id) fun insertMail(mail: Mail) = viewModelScope.launch { mailRepository.insertMail(mail) diff --git a/app/src/main/java/com/example/mobileapp/screens/EditScreens.kt b/app/src/main/java/com/example/mobileapp/screens/EditScreens.kt index 6b0d981..00d7807 100644 --- a/app/src/main/java/com/example/mobileapp/screens/EditScreens.kt +++ b/app/src/main/java/com/example/mobileapp/screens/EditScreens.kt @@ -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 - } - }*/ } } diff --git a/app/src/main/java/com/example/mobileapp/screens/ListMailScreen.kt b/app/src/main/java/com/example/mobileapp/screens/ListMailScreen.kt index f427503..c9684c4 100644 --- a/app/src/main/java/com/example/mobileapp/screens/ListMailScreen.kt +++ b/app/src/main/java/com/example/mobileapp/screens/ListMailScreen.kt @@ -58,6 +58,5 @@ fun ListMailScreen(navController: NavHostController, } } } - //DataListScroll(navController, mails) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/mobileapp/screens/ListStoryScreen.kt b/app/src/main/java/com/example/mobileapp/screens/ListStoryScreen.kt index 0a0b452..0f712dc 100644 --- a/app/src/main/java/com/example/mobileapp/screens/ListStoryScreen.kt +++ b/app/src/main/java/com/example/mobileapp/screens/ListStoryScreen.kt @@ -36,33 +36,12 @@ fun ListStoryScreen(navController: NavHostController, factory = MobileAppViewModelProvider.Factory )) { val stories = storyViewModel.getStoriesByUserId.collectAsLazyPagingItems() - /*val stories = remember { mutableStateListOf() } - 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) ) { diff --git a/app/src/main/java/com/example/mobileapp/screens/ViewScreens.kt b/app/src/main/java/com/example/mobileapp/screens/ViewScreens.kt index 9fbb7fc..4cba9da 100644 --- a/app/src/main/java/com/example/mobileapp/screens/ViewScreens.kt +++ b/app/src/main/java/com/example/mobileapp/screens/ViewScreens.kt @@ -124,18 +124,17 @@ fun MailViewScreen(navController: NavHostController, mailId: Int, val postdate = remember { mutableStateOf(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 } }