lab 4 complete(finally...)

This commit is contained in:
AnnZhimol 2023-11-23 19:40:59 +04:00
parent 41536e89d9
commit 5f4c36f00a
34 changed files with 936 additions and 658 deletions

View File

@ -1,3 +1,4 @@
plugins { plugins {
id("com.android.application") id("com.android.application")
id("com.google.devtools.ksp") id("com.google.devtools.ksp")
@ -39,6 +40,7 @@ android {
} }
buildFeatures { buildFeatures {
compose = true compose = true
viewBinding = true
} }
composeOptions { composeOptions {
kotlinCompilerExtensionVersion = "1.4.5" kotlinCompilerExtensionVersion = "1.4.5"
@ -81,4 +83,16 @@ dependencies {
ksp("androidx.room:room-compiler:$room_version") ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version") implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version") implementation("androidx.room:room-paging:$room_version")
val paging_version = "3.1.1"
implementation ("androidx.paging:paging-runtime:$paging_version")
// alternatively - without Android dependencies for tests
testImplementation ("androidx.paging:paging-common:$paging_version")
// optional - RxJava2 support
implementation ("androidx.paging:paging-rxjava2:$paging_version")
// optional - RxJava3 support
implementation ("androidx.paging:paging-rxjava3:$paging_version")
// optional - Guava ListenableFuture support
implementation ("androidx.paging:paging-guava:$paging_version")
// optional - Jetpack Compose integration
implementation ("androidx.paging:paging-compose:1.0.0-alpha18")
} }

View File

@ -60,7 +60,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize import androidx.compose.ui.unit.toSize
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.pmulabs.R import com.example.pmulabs.R
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
@ -72,7 +74,7 @@ import java.text.SimpleDateFormat
@SuppressLint("UnrememberedMutableState", "CoroutineCreationDuringComposition") @SuppressLint("UnrememberedMutableState", "CoroutineCreationDuringComposition")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ArticleItem(article: Article, modifier: Modifier = Modifier, onArticleClick: () -> Unit, articleItemViewModel: ArticleItemViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { fun ArticleItem(navController: NavController,article: Article, modifier: Modifier = Modifier, onArticleClick: () -> Unit, articleItemViewModel: ArticleItemViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
articleItemViewModel.setTagList() articleItemViewModel.setTagList()
@ -360,6 +362,7 @@ fun ArticleItem(article: Article, modifier: Modifier = Modifier, onArticleClick:
coroutineScope.launch { coroutineScope.launch {
articleItemViewModel.deleteArticle(article) articleItemViewModel.deleteArticle(article)
} }
navController.navigate(BottomBarScreen.Main.route)
}, },
imageVector = Icons.Filled.Close, imageVector = Icons.Filled.Close,
contentDescription = "Delete Icon", contentDescription = "Delete Icon",

View File

@ -39,6 +39,8 @@ import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.room.models.Comment import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.User import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
@ -49,7 +51,7 @@ import kotlinx.coroutines.launch
@SuppressLint("CoroutineCreationDuringComposition", "UnrememberedMutableState") @SuppressLint("CoroutineCreationDuringComposition", "UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun CommentItem(modifier: Modifier = Modifier, comm : Comment,commentItemViewModel: CommentItemViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { fun CommentItem(navController: NavController,modifier: Modifier = Modifier, comm : Comment,commentItemViewModel: CommentItemViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
var getUser by remember { mutableStateOf(currentUserViewModel.user) } var getUser by remember { mutableStateOf(currentUserViewModel.user) }
var openDialog by remember { mutableStateOf(false) } var openDialog by remember { mutableStateOf(false) }
@ -175,6 +177,7 @@ fun CommentItem(modifier: Modifier = Modifier, comm : Comment,commentItemViewMod
coroutineScope.launch { coroutineScope.launch {
commentItemViewModel.deleteComment(comm) commentItemViewModel.deleteComment(comm)
} }
navController.navigate(BottomBarScreen.ArticlePage.passId(comm.articleId.toString()))
}, },
imageVector = Icons.Filled.Close, imageVector = Icons.Filled.Close,
contentDescription = "Delete Icon", contentDescription = "Delete Icon",

View File

@ -41,7 +41,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.pmulabs.R import com.example.pmulabs.R
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.CurrentUserViewModel import com.example.pmulabs.viewModels.CurrentUserViewModel
@ -50,7 +52,7 @@ import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun TagItem(teg: Tag, modifier: Modifier = Modifier, onTagClick: () -> Unit, viewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory), tagViewModel: TagItemViewModel =viewModel(factory = AppViewModelProvider.Factory)) { fun TagItem(navController: NavController,teg: Tag, modifier: Modifier = Modifier, onTagClick: () -> Unit, viewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory), tagViewModel: TagItemViewModel =viewModel(factory = AppViewModelProvider.Factory)) {
var getUser by remember { mutableStateOf(viewModel.user) } var getUser by remember { mutableStateOf(viewModel.user) }
var openDialog by remember { mutableStateOf(false) } var openDialog by remember { mutableStateOf(false) }
@ -197,6 +199,7 @@ fun TagItem(teg: Tag, modifier: Modifier = Modifier, onTagClick: () -> Unit, vie
coroutineScope.launch { coroutineScope.launch {
tagViewModel.deleteTag(teg) tagViewModel.deleteTag(teg)
} }
navController.navigate(BottomBarScreen.Categories.route)
}, },
imageVector = Icons.Filled.Close, imageVector = Icons.Filled.Close,
contentDescription = "Delete Icon", contentDescription = "Delete Icon",

View File

@ -9,8 +9,10 @@ import com.example.pmulabs.screensMobile.authScreens.EntryScreen
import com.example.pmulabs.screensMobile.authScreens.RegisterScreen import com.example.pmulabs.screensMobile.authScreens.RegisterScreen
import com.example.pmulabs.screensMobile.authScreens.SplashScreen import com.example.pmulabs.screensMobile.authScreens.SplashScreen
import com.example.pmulabs.viewModels.CurrentUserViewModel import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.viewModels.EntryScreenViewModel
import com.example.pmulabs.viewModels.RegisterScreenViewModel
fun NavGraphBuilder.authNavGraph(navController: NavHostController, currentUserViewModel: CurrentUserViewModel){ fun NavGraphBuilder.authNavGraph(navController: NavHostController,registerScreenViewModel: RegisterScreenViewModel,entryScreenViewModel: EntryScreenViewModel, currentUserViewModel: CurrentUserViewModel){
navigation( navigation(
route=Graph.AUTHENTICATION, route=Graph.AUTHENTICATION,
startDestination = AuthScreen.Splash.route startDestination = AuthScreen.Splash.route
@ -19,10 +21,10 @@ fun NavGraphBuilder.authNavGraph(navController: NavHostController, currentUserVi
SplashScreen(navController = navController, Modifier) SplashScreen(navController = navController, Modifier)
} }
composable(route=AuthScreen.Entry.route){ composable(route=AuthScreen.Entry.route){
EntryScreen(navController = navController, Modifier,currentUserViewModel) EntryScreen(navController = navController, Modifier,entryScreenViewModel,currentUserViewModel)
} }
composable(route=AuthScreen.Register.route){ composable(route=AuthScreen.Register.route){
RegisterScreen(navController = navController, Modifier,currentUserViewModel) RegisterScreen(navController = navController, Modifier,registerScreenViewModel,currentUserViewModel)
} }
} }
} }

View File

@ -13,7 +13,6 @@ import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.CALENDAR_ARGUMENT_DATE import com.example.pmulabs.basecomponents.navigate.CALENDAR_ARGUMENT_DATE
import com.example.pmulabs.basecomponents.navigate.SEARCHBYTAG_ARGUMENT_KEY import com.example.pmulabs.basecomponents.navigate.SEARCHBYTAG_ARGUMENT_KEY
import com.example.pmulabs.basecomponents.navigate.SEARCH_ARGUMENT_TEXT import com.example.pmulabs.basecomponents.navigate.SEARCH_ARGUMENT_TEXT
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.screensMobile.ArticlePageScreen import com.example.pmulabs.screensMobile.ArticlePageScreen
import com.example.pmulabs.screensMobile.CoopScreen import com.example.pmulabs.screensMobile.CoopScreen
import com.example.pmulabs.screensMobile.InfoScreen import com.example.pmulabs.screensMobile.InfoScreen
@ -24,9 +23,13 @@ import com.example.pmulabs.screensMobile.filterScreens.CalendarScreen
import com.example.pmulabs.screensMobile.filterScreens.SearchByTagScreen import com.example.pmulabs.screensMobile.filterScreens.SearchByTagScreen
import com.example.pmulabs.screensMobile.filterScreens.SearchScreen import com.example.pmulabs.screensMobile.filterScreens.SearchScreen
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.ArticlePageScreenViewModel
import com.example.pmulabs.viewModels.ArticleScreenViewModel
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.viewModels.TagItemViewModel
@Composable @Composable
fun HomeNavGraph(navController: NavHostController, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){ fun HomeNavGraph(navController: NavHostController,articlePageScreenViewModel: ArticlePageScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), tagItemViewModel: TagItemViewModel = viewModel(factory = AppViewModelProvider.Factory), articleScreenViewModel: ArticleScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
NavHost( NavHost(
navController = navController, navController = navController,
route = Graph.MAIN, route = Graph.MAIN,
@ -35,7 +38,7 @@ fun HomeNavGraph(navController: NavHostController, currentUserViewModel: Current
composable( composable(
route=BottomBarScreen.Main.route route=BottomBarScreen.Main.route
){ ){
MainScreen(navController,Modifier,currentUserViewModel) MainScreen(navController,Modifier,articleScreenViewModel,currentUserViewModel)
} }
composable( composable(
route=BottomBarScreen.SearchByTag.route, route=BottomBarScreen.SearchByTag.route,
@ -43,7 +46,7 @@ fun HomeNavGraph(navController: NavHostController, currentUserViewModel: Current
type= NavType.StringType type= NavType.StringType
}) })
){ ){
SearchByTagScreen(navController,Modifier,currentUserViewModel) SearchByTagScreen(navController,Modifier,articleScreenViewModel,currentUserViewModel)
} }
composable( composable(
route=BottomBarScreen.ArticlePage.route, route=BottomBarScreen.ArticlePage.route,
@ -51,7 +54,7 @@ fun HomeNavGraph(navController: NavHostController, currentUserViewModel: Current
type= NavType.StringType type= NavType.StringType
}) })
){ ){
ArticlePageScreen(navController,Modifier,currentUserViewModel) ArticlePageScreen(navController,Modifier,articlePageScreenViewModel,currentUserViewModel)
} }
composable( composable(
route=BottomBarScreen.Search.route, route=BottomBarScreen.Search.route,
@ -59,7 +62,7 @@ fun HomeNavGraph(navController: NavHostController, currentUserViewModel: Current
type= NavType.StringType type= NavType.StringType
}) })
){ ){
SearchScreen(navController,Modifier,currentUserViewModel) SearchScreen(navController,Modifier,articleScreenViewModel,currentUserViewModel)
} }
composable( composable(
route=BottomBarScreen.Calendar.route, route=BottomBarScreen.Calendar.route,
@ -67,10 +70,10 @@ fun HomeNavGraph(navController: NavHostController, currentUserViewModel: Current
type= NavType.StringType type= NavType.StringType
}) })
){ ){
CalendarScreen(navController,Modifier,currentUserViewModel) CalendarScreen(navController,articleScreenViewModel,Modifier,currentUserViewModel)
} }
composable(route=BottomBarScreen.Profile.route){ composable(route=BottomBarScreen.Profile.route){
ProfileScreen(navController,Modifier,currentUserViewModel) ProfileScreen(navController,Modifier,articleScreenViewModel, tagItemViewModel, articlePageScreenViewModel,currentUserViewModel)
} }
composable(route=BottomBarScreen.Info.route){ composable(route=BottomBarScreen.Info.route){
InfoScreen(navController,Modifier) InfoScreen(navController,Modifier)
@ -79,7 +82,7 @@ fun HomeNavGraph(navController: NavHostController, currentUserViewModel: Current
CoopScreen(navController,Modifier) CoopScreen(navController,Modifier)
} }
composable(route=BottomBarScreen.Categories.route){ composable(route=BottomBarScreen.Categories.route){
TagsScreen(navController,Modifier,currentUserViewModel) TagsScreen(navController,Modifier, tagItemViewModel, currentUserViewModel)
} }
} }
} }

View File

@ -7,26 +7,31 @@ import androidx.navigation.NavType
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.navArgument import androidx.navigation.navArgument
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.screensMobile.LoadScreen import com.example.pmulabs.screensMobile.LoadScreen
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.ArticlePageScreenViewModel
import com.example.pmulabs.viewModels.ArticleScreenViewModel
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.viewModels.EntryScreenViewModel
import com.example.pmulabs.viewModels.RegisterScreenViewModel
import com.example.pmulabs.viewModels.SearchViewModel import com.example.pmulabs.viewModels.SearchViewModel
import com.example.pmulabs.viewModels.TagItemViewModel
const val USERID_ARGUMENT="userId" const val USERID_ARGUMENT="userId"
@Composable @Composable
fun RootNavigationGraph(navController: NavHostController, searchViewModel: SearchViewModel, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){ fun RootNavigationGraph(navController: NavHostController, searchViewModel: SearchViewModel,articlePageScreenViewModel: ArticlePageScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), tagItemViewModel: TagItemViewModel = viewModel(factory = AppViewModelProvider.Factory), articleScreenViewModel: ArticleScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), registerScreenViewModel: RegisterScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), entryScreenViewModel: EntryScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
NavHost( NavHost(
navController=navController, navController=navController,
route = Graph.ROOT, route = Graph.ROOT,
startDestination = Graph.AUTHENTICATION startDestination = Graph.AUTHENTICATION
){ ){
authNavGraph(navController=navController,currentUserViewModel) authNavGraph(navController=navController,registerScreenViewModel,entryScreenViewModel,currentUserViewModel)
composable(route=Graph.MAIN, composable(route=Graph.MAIN,
arguments = listOf(navArgument(USERID_ARGUMENT){ arguments = listOf(navArgument(USERID_ARGUMENT){
type= NavType.StringType type= NavType.StringType
})){ })){
LoadScreen(searchViewModel = searchViewModel, currentUserViewModel = currentUserViewModel) LoadScreen(searchViewModel = searchViewModel, articleScreenViewModel = articleScreenViewModel, articlePageScreenViewModel = articlePageScreenViewModel, tagItemViewModel = tagItemViewModel,currentUserViewModel = currentUserViewModel)
} }
} }
} }

View File

@ -16,6 +16,9 @@ interface ArticleDao {
@Query("select * from article where article.id = :idArticle") @Query("select * from article where article.id = :idArticle")
fun getArticleById(idArticle: Int): Flow<Article> fun getArticleById(idArticle: Int): Flow<Article>
@Query("SELECT * FROM article ORDER BY id DESC LIMIT :limit OFFSET :offset")
suspend fun getArticles(limit: Int, offset: Int): List<Article>
@Insert @Insert
suspend fun insert(article: Article) suspend fun insert(article: Article)

View File

@ -16,6 +16,9 @@ interface CommentDao {
@Query("select COUNT(*) from comment WHERE comment.text!='' AND comment.article_id= :idArticle") @Query("select COUNT(*) from comment WHERE comment.text!='' AND comment.article_id= :idArticle")
fun getCountComment(idArticle : Int?) : Int fun getCountComment(idArticle : Int?) : Int
@Query("SELECT * FROM comment ORDER BY id DESC LIMIT :limit OFFSET :offset")
suspend fun getComments(limit: Int, offset: Int): List<Comment>
@Insert @Insert
suspend fun insert(comment: Comment) suspend fun insert(comment: Comment)

View File

@ -19,6 +19,9 @@ interface TagDao {
@Query("select * from tag where tag.title = :nameTag") @Query("select * from tag where tag.title = :nameTag")
fun getTagByName(nameTag: String): Flow<Tag> fun getTagByName(nameTag: String): Flow<Tag>
@Query("SELECT * FROM tag ORDER BY id ASC LIMIT :limit OFFSET :offset")
suspend fun getTags(limit: Int, offset: Int): List<Tag>
@Insert @Insert
suspend fun insert(tag: Tag) suspend fun insert(tag: Tag)

View File

@ -0,0 +1,38 @@
package com.example.pmulabs.room.pagingSource
import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.example.pmulabs.room.dao.ArticleDao
import com.example.pmulabs.room.models.Article
import kotlinx.coroutines.delay
class ArticlePagingSource(
private val dao: ArticleDao,
) : PagingSource<Int, Article>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Article> {
val page = params.key ?: 0
return try {
Log.d("MainPagingSource", "load: $page")
val entities = dao.getArticles(params.loadSize, page * params.loadSize)
if (page != 0) delay(1000)
LoadResult.Page(
data = entities,
prevKey = if (page == 0) null else page - 1,
nextKey = if (entities.isEmpty()) null else page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override val jumpingSupported: Boolean = true
override fun getRefreshKey(state: PagingState<Int, Article>): Int? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
}

View File

@ -0,0 +1,38 @@
package com.example.pmulabs.room.pagingSource
import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.example.pmulabs.room.dao.CommentDao
import com.example.pmulabs.room.models.Comment
import kotlinx.coroutines.delay
class CommentPagingSource(
private val dao: CommentDao,
) : PagingSource<Int, Comment>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Comment> {
val page = params.key ?: 0
return try {
Log.d("MainPagingSource", "load: $page")
val entities = dao.getComments(params.loadSize, page * params.loadSize)
if (page != 0) delay(1000)
LoadResult.Page(
data = entities,
prevKey = if (page == 0) null else page - 1,
nextKey = if (entities.isEmpty()) null else page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override val jumpingSupported: Boolean = true
override fun getRefreshKey(state: PagingState<Int, Comment>): Int? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
}

View File

@ -0,0 +1,38 @@
package com.example.pmulabs.room.pagingSource
import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.example.pmulabs.room.dao.TagDao
import com.example.pmulabs.room.models.Tag
import kotlinx.coroutines.delay
class TagPagingSource(
private val dao: TagDao,
) : PagingSource<Int, Tag>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Tag> {
val page = params.key ?: 0
return try {
Log.d("MainPagingSource", "load: $page")
val entities = dao.getTags(params.loadSize, page * params.loadSize)
if (page != 0) delay(1000)
LoadResult.Page(
data = entities,
prevKey = if (page == 0) null else page - 1,
nextKey = if (entities.isEmpty()) null else page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override val jumpingSupported: Boolean = true
override fun getRefreshKey(state: PagingState<Int, Tag>): Int? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
}

View File

@ -1,5 +1,6 @@
package com.example.pmulabs.room.repository package com.example.pmulabs.room.repository
import androidx.paging.PagingData
import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Article
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -9,4 +10,5 @@ interface ArticleRepository {
suspend fun deleteArticle(article: Article) suspend fun deleteArticle(article: Article)
fun getAllArticles(): Flow<List<Article>> fun getAllArticles(): Flow<List<Article>>
fun getArticleById(idArticle: Int): Flow<Article> fun getArticleById(idArticle: Int): Flow<Article>
fun getArticles(): Flow<PagingData<Article>>
} }

View File

@ -1,5 +1,6 @@
package com.example.pmulabs.room.repository package com.example.pmulabs.room.repository
import androidx.paging.PagingData
import com.example.pmulabs.room.models.Comment import com.example.pmulabs.room.models.Comment
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -9,4 +10,5 @@ interface CommentRepository {
suspend fun deleteComment(comment: Comment) suspend fun deleteComment(comment: Comment)
fun getAllComments(): Flow<List<Comment>> fun getAllComments(): Flow<List<Comment>>
fun getCountComment(idArticle : Int?) : Int fun getCountComment(idArticle : Int?) : Int
fun getComments(): Flow<PagingData<Comment>>
} }

View File

@ -1,7 +1,11 @@
package com.example.pmulabs.room.repository package com.example.pmulabs.room.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.pmulabs.room.dao.ArticleDao import com.example.pmulabs.room.dao.ArticleDao
import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.pagingSource.ArticlePagingSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class OfflineArticleRepository(private val articleDao: ArticleDao) : ArticleRepository { class OfflineArticleRepository(private val articleDao: ArticleDao) : ArticleRepository {
@ -10,4 +14,6 @@ class OfflineArticleRepository(private val articleDao: ArticleDao) : ArticleRepo
override suspend fun deleteArticle(article: Article) = articleDao.delete(article) override suspend fun deleteArticle(article: Article) = articleDao.delete(article)
override fun getAllArticles(): Flow<List<Article>> = articleDao.getAll() override fun getAllArticles(): Flow<List<Article>> = articleDao.getAll()
override fun getArticleById(idArticle: Int): Flow<Article> = articleDao.getArticleById(idArticle) override fun getArticleById(idArticle: Int): Flow<Article> = articleDao.getArticleById(idArticle)
override fun getArticles(): Flow<PagingData<Article>> = Pager(config = PagingConfig(pageSize = 4, jumpThreshold = 4, initialLoadSize = 4) ){ ArticlePagingSource(articleDao) }.flow
} }

View File

@ -1,7 +1,11 @@
package com.example.pmulabs.room.repository package com.example.pmulabs.room.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.pmulabs.room.dao.CommentDao import com.example.pmulabs.room.dao.CommentDao
import com.example.pmulabs.room.models.Comment import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.pagingSource.CommentPagingSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class OfflineCommentRepository(private val commentDao: CommentDao) : CommentRepository { class OfflineCommentRepository(private val commentDao: CommentDao) : CommentRepository {
@ -10,4 +14,6 @@ class OfflineCommentRepository(private val commentDao: CommentDao) : CommentRepo
override suspend fun deleteComment(comment: Comment) = commentDao.delete(comment) override suspend fun deleteComment(comment: Comment) = commentDao.delete(comment)
override fun getAllComments(): Flow<List<Comment>> = commentDao.getAll() override fun getAllComments(): Flow<List<Comment>> = commentDao.getAll()
override fun getCountComment(idArticle : Int?) : Int = commentDao.getCountComment(idArticle) override fun getCountComment(idArticle : Int?) : Int = commentDao.getCountComment(idArticle)
override fun getComments(): Flow<PagingData<Comment>> = Pager(config = PagingConfig(pageSize = 4, jumpThreshold = 4, initialLoadSize = 4) ){ CommentPagingSource(commentDao) }.flow
} }

View File

@ -1,7 +1,11 @@
package com.example.pmulabs.room.repository package com.example.pmulabs.room.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.pmulabs.room.dao.TagDao import com.example.pmulabs.room.dao.TagDao
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.pagingSource.TagPagingSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class OfflineTagRepository(private val tagDao: TagDao) : TagRepository { class OfflineTagRepository(private val tagDao: TagDao) : TagRepository {
@ -11,4 +15,6 @@ class OfflineTagRepository(private val tagDao: TagDao) : TagRepository {
override fun getAllTags(): Flow<List<Tag>> = tagDao.getAll() override fun getAllTags(): Flow<List<Tag>> = tagDao.getAll()
override fun getTagById(idTag: Int): Flow<Tag> = tagDao.getTagById(idTag) override fun getTagById(idTag: Int): Flow<Tag> = tagDao.getTagById(idTag)
override fun getTagByName(nameTag: String): Flow<Tag> = tagDao.getTagByName(nameTag) override fun getTagByName(nameTag: String): Flow<Tag> = tagDao.getTagByName(nameTag)
override fun getTags(): Flow<PagingData<Tag>> = Pager(config = PagingConfig(pageSize = 4, jumpThreshold = 4, initialLoadSize = 4) ){ TagPagingSource(tagDao) }.flow
} }

View File

@ -1,5 +1,6 @@
package com.example.pmulabs.room.repository package com.example.pmulabs.room.repository
import androidx.paging.PagingData
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -10,4 +11,5 @@ interface TagRepository {
fun getAllTags(): Flow<List<Tag>> fun getAllTags(): Flow<List<Tag>>
fun getTagById(idTag: Int): Flow<Tag> fun getTagById(idTag: Int): Flow<Tag>
fun getTagByName(nameTag: String): Flow<Tag> fun getTagByName(nameTag: String): Flow<Tag>
fun getTags(): Flow<PagingData<Tag>>
} }

View File

@ -1,5 +1,7 @@
package com.example.pmulabs.screensMobile package com.example.pmulabs.screensMobile
import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@ -20,6 +22,7 @@ import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonColors
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -27,102 +30,83 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.basecomponents.navigate.ARTICLE_ARGUMENT_KEY import com.example.pmulabs.basecomponents.navigate.ARTICLE_ARGUMENT_KEY
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.designElem.elem.BackButton import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.CommentItem import com.example.pmulabs.designElem.items.CommentItem
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Comment import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.ArticlePageScreenViewModel
import com.example.pmulabs.viewModels.CurrentUserViewModel import com.example.pmulabs.viewModels.CurrentUserViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifier,articlePageScreenViewModel: ArticlePageScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val argument = currentUserViewModel.argument.value
val context = LocalContext.current
var id=navController.currentBackStackEntry?.arguments?.getString(ARTICLE_ARGUMENT_KEY).toString() var id =
var textComm by rememberSaveable { mutableStateOf("") } navController.currentBackStackEntry?.arguments?.getString(ARTICLE_ARGUMENT_KEY).toString()
var article by remember { mutableStateOf<Article?>(null) } try {
var tag by remember { mutableStateOf<Tag?>(null) } articlePageScreenViewModel.getArticleById(id.toInt())
var tagId = 0 } catch (e: NumberFormatException) {
if (id.toString() != "null") { e.printStackTrace()
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getArticleById(id.toInt()).collect { data ->
article=data
tagId=data.tagId
NewsPortalDatabase.getInstance(context).tagDao().getTagById(tagId).collect { data ->
tag=data
}
}
}
}
} }
var textComm by rememberSaveable { mutableStateOf("") }
var article by mutableStateOf<Article?>(articlePageScreenViewModel.article)
try {
article?.tagId?.let { articlePageScreenViewModel.getTagById(it) }
} catch (e: Exception) {
e.printStackTrace()
}
var tag by mutableStateOf<Tag?>(articlePageScreenViewModel.tag)
Log.d("Tag:", tag.toString())
var tagId = articlePageScreenViewModel.tag?.id
val formatter = SimpleDateFormat("dd.MM.YY") val formatter = SimpleDateFormat("dd.MM.YY")
val publishDate=formatter.format(Date(article?.publishDate ?: 0)) val publishDate = formatter.format(Date(article?.publishDate ?: 0))
val comms = remember { mutableStateListOf<Comment>() } val comms = articlePageScreenViewModel.comments.collectAsLazyPagingItems()
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).commentDao().getAll().collect { data ->
comms.clear()
comms.addAll(data)
}
}
}
var getUser by remember { mutableStateOf<User?>(null) } var getUser by remember { mutableStateOf(currentUserViewModel.user) }
LaunchedEffect(Unit) { val coroutineScope = rememberCoroutineScope()
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(argument.toString().toInt()).collect { data ->
getUser=data
}
}
}
LazyColumn( LazyColumn(
contentPadding= PaddingValues(top=105.dp, bottom = 50.dp,start=15.dp,end=15.dp), contentPadding = PaddingValues(top = 105.dp, bottom = 50.dp, start = 15.dp, end = 15.dp),
modifier = modifier modifier = modifier
.requiredWidth(width = 412.dp) .requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp) .requiredHeight(height = 915.dp)
.background(color = Color.White) .background(color = Color.White)
.fillMaxSize(), .fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(10.dp) verticalArrangement = Arrangement.spacedBy(1.dp)
) { ) {
item{ item {
BackButton(modifier=Modifier BackButton(modifier = Modifier
.clickable { navController.popBackStack()} .clickable { navController.navigate(BottomBarScreen.Main.route) }
.offset( .offset(
y=0.dp y = 0.dp
)) ))
} }
item { item {
@ -131,20 +115,24 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie
.requiredWidth(width = 350.dp) .requiredWidth(width = 350.dp)
.requiredHeight(height = 33.dp) .requiredHeight(height = 33.dp)
.offset( .offset(
y=0.dp y = 0.dp
) )
) { ) {
Text( Text(
text = "${publishDate}", text = "${publishDate}",
color = Color(0xff423a99), color = Color(0xff423a99),
style = MaterialTheme.typography.headlineMedium) style = MaterialTheme.typography.headlineMedium
)
Text( Text(
text = "#${tag?.title}", text = "#${tag?.title}",
color = Color(0xff423a99), color = Color(0xff423a99),
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
modifier = Modifier modifier = Modifier
.offset(x = 20.dp, .offset(
y = 0.dp)) x = 20.dp,
y = 0.dp
)
)
} }
} }
item { item {
@ -153,11 +141,15 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie
color = Color(0xff423a99), color = Color(0xff423a99),
style = TextStyle( style = TextStyle(
fontSize = 32.sp, fontSize = 32.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.offset(x = 10.dp, .offset(
y = 0.dp) x = 10.dp,
.requiredWidth(width = 395.dp)) y = 0.dp
)
.requiredWidth(width = 395.dp)
)
} }
item { item {
@ -166,9 +158,12 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie
color = Color(0xff423a99), color = Color(0xff423a99),
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
modifier = Modifier modifier = Modifier
.offset(x = 5.dp, .offset(
y = 0.dp) x = 5.dp,
.requiredWidth(width = 375.dp)) y = 0.dp
)
.requiredWidth(width = 375.dp)
)
} }
item { item {
Box( Box(
@ -176,7 +171,7 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie
.requiredWidth(width = 412.dp) .requiredWidth(width = 412.dp)
.requiredHeight(height = 53.dp) .requiredHeight(height = 53.dp)
.offset( .offset(
y=0.dp y = 0.dp
) )
) { ) {
Text( Text(
@ -184,33 +179,38 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie
color = Color(0xff423a99), color = Color(0xff423a99),
style = TextStyle( style = TextStyle(
fontSize = 32.sp, fontSize = 32.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.offset(x = 15.dp, .offset(
y = 6.dp) x = 15.dp,
y = 6.dp
)
.requiredWidth(width = 395.dp) .requiredWidth(width = 395.dp)
.requiredHeight(height = 43.dp)) .requiredHeight(height = 43.dp)
)
HorizontalDivider( HorizontalDivider(
thickness=5.dp, thickness = 5.dp,
modifier = Modifier modifier = Modifier
.border(BorderStroke(3.dp, Color(0xff423a99))), color = Color(0xff423a99) .border(BorderStroke(3.dp, Color(0xff423a99))), color = Color(0xff423a99)
) )
HorizontalDivider( HorizontalDivider(
thickness=5.dp, thickness = 5.dp,
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.border(BorderStroke(3.dp, Color(0xff423a99))) .border(BorderStroke(3.dp, Color(0xff423a99)))
.offset( .offset(
y = 53.dp), color = Color(0xff423a99) y = 53.dp
), color = Color(0xff423a99)
) )
} }
} }
item{ item {
OutlinedTextField( OutlinedTextField(
value = textComm, value = textComm,
onValueChange = { onValueChange = {
textComm=it textComm = it
}, },
colors = TextFieldDefaults.textFieldColors( colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White, containerColor = Color.White,
@ -236,13 +236,14 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie
disabledContentColor = Color.White disabledContentColor = Color.White
), ),
onClick = { onClick = {
if(textComm.isNotEmpty()) { if (textComm.isNotEmpty()) {
var newComment = var newComment =
Comment(null, textComm, getUser?.id.toString().toInt(), id.toInt()) Comment(null, textComm, getUser?.id.toString().toInt(), id.toInt())
CoroutineScope(Dispatchers.IO).launch { coroutineScope.launch {
NewsPortalDatabase.getInstance(context).commentDao().insert(newComment) articlePageScreenViewModel.insertComment(newComment)
} }
textComm = "" textComm = ""
navController.navigate(BottomBarScreen.ArticlePage.passId(article?.id.toString()))
} }
}, },
modifier = Modifier modifier = Modifier
@ -253,19 +254,52 @@ fun ArticlePageScreen(navController: NavController, modifier: Modifier = Modifie
Text(text = "Send", fontSize = 20.sp) Text(text = "Send", fontSize = 20.sp)
} }
} }
item{
comms.forEach{ comm -> items(count = comms.itemCount) { index ->
if(comm.articleId==article?.id && comm.text!="") { val comm = comms[index]
if (comm != null) {
if (comm.articleId == article?.id && comm.text != "") {
Spacer(modifier = Modifier.padding(0.dp)) Spacer(modifier = Modifier.padding(0.dp))
HorizontalDivider( HorizontalDivider(
thickness=3.dp, thickness = 3.dp,
modifier = Modifier modifier = Modifier
.border(BorderStroke(3.dp, Color(0xff423a99))), color = Color(0xff423a99) .border(BorderStroke(3.dp, Color(0xff423a99))), color = Color(0xff423a99)
) )
CommentItem(comm = comm, currentUserViewModel = currentUserViewModel) CommentItem(navController,comm = comm, currentUserViewModel = currentUserViewModel)
} }
} }
} }
comms.apply {
when {
loadState.refresh is LoadState.Loading -> {
item {
CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(),
color = Color(0xff423a99)
)
}
}
loadState.append is LoadState.Loading -> {
item {
CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(),
color = Color(0xff423a99)
)
}
}
loadState.refresh is LoadState.Error -> {
val err = comms.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = comms.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
}
}
} }
} }

View File

@ -8,9 +8,9 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonColors
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DatePicker import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerColors import androidx.compose.material3.DatePickerColors
import androidx.compose.material3.DatePickerDialog import androidx.compose.material3.DatePickerDialog
@ -21,61 +21,70 @@ import androidx.compose.material3.TextButton
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.rememberDatePickerState import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.basecomponents.navigate.BottomBar import com.example.pmulabs.basecomponents.navigate.BottomBar
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.SearchAppBar import com.example.pmulabs.basecomponents.navigate.SearchAppBar
import com.example.pmulabs.basecomponents.navigate.TopBar import com.example.pmulabs.basecomponents.navigate.TopBar
import com.example.pmulabs.designElem.items.ArticleItem import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.graphs.HomeNavGraph import com.example.pmulabs.graphs.HomeNavGraph
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.ArticlePageScreenViewModel
import com.example.pmulabs.viewModels.ArticleScreenViewModel
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.viewModels.SearchViewModel import com.example.pmulabs.viewModels.SearchViewModel
import com.example.pmulabs.viewModels.SearchWidget import com.example.pmulabs.viewModels.SearchWidget
import kotlinx.coroutines.Dispatchers import com.example.pmulabs.viewModels.TagItemViewModel
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
@Composable @Composable
fun MainScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){ fun MainScreen(navController: NavController, modifier: Modifier = Modifier, articleScreenViewModel: ArticleScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val articles = articleScreenViewModel.articles.collectAsLazyPagingItems()
val context = LocalContext.current
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
LazyColumn( LazyColumn(
modifier=Modifier modifier=Modifier
.background(Color.White) .background(Color.White)
.fillMaxSize(), .fillMaxSize(),
contentPadding = PaddingValues(top=75.dp, bottom = 70.dp, start = 10.dp,end=10.dp), contentPadding = PaddingValues(top=75.dp, bottom = 70.dp, start = 10.dp,end=10.dp),
verticalArrangement = Arrangement.spacedBy(15.dp)){ verticalArrangement = Arrangement.spacedBy(15.dp)){
items(items = articles){ article -> items(count = articles.itemCount) { index ->
ArticleItem(article = article, currentUserViewModel = currentUserViewModel, onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))}) val article = articles[index]
if (article != null) {
ArticleItem(navController=navController,article = article, currentUserViewModel = currentUserViewModel, onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))})
}
}
articles.apply {
when {
loadState.refresh is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.append is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.refresh is LoadState.Error -> {
val err = articles.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = articles.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
}
} }
} }
} }
@ -83,14 +92,14 @@ fun MainScreen(navController: NavController, modifier: Modifier = Modifier, curr
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun LoadScreen(navController: NavHostController=rememberNavController(), searchViewModel: SearchViewModel, currentUserViewModel: CurrentUserViewModel){ fun LoadScreen(navController: NavHostController=rememberNavController(),articlePageScreenViewModel: ArticlePageScreenViewModel, tagItemViewModel: TagItemViewModel, articleScreenViewModel: ArticleScreenViewModel, searchViewModel: SearchViewModel, currentUserViewModel: CurrentUserViewModel){
val searchWidgetState by searchViewModel.searchWidgetState val searchWidgetState by searchViewModel.searchWidgetState
val searchTextState by searchViewModel.searchTextState val searchTextState by searchViewModel.searchTextState
val formatter = SimpleDateFormat("dd-MMMM-YY") val formatter = SimpleDateFormat("dd-MMMM-YY")
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.set(2023, 0, 1) // add year, month (Jan), date calendar.set(2023,10,23)
// set the initial date // set the initial date
val datePickerState = rememberDatePickerState(initialSelectedDateMillis = calendar.timeInMillis) val datePickerState = rememberDatePickerState(initialSelectedDateMillis = calendar.timeInMillis)
@ -133,7 +142,7 @@ fun LoadScreen(navController: NavHostController=rememberNavController(), searchV
selectedYearContentColor=Color.White, selectedYearContentColor=Color.White,
subheadContentColor=Color(0xff423a99), subheadContentColor=Color(0xff423a99),
titleContentColor=Color(0xff423a99), titleContentColor=Color(0xff423a99),
todayContentColor=Color.White, todayContentColor=Color(0xff423a99),
todayDateBorderColor=Color(0xff423a99), todayDateBorderColor=Color(0xff423a99),
weekdayContentColor=Color(0xff423a99), weekdayContentColor=Color(0xff423a99),
yearContentColor=Color(0xff423a99) yearContentColor=Color(0xff423a99)
@ -212,7 +221,7 @@ fun LoadScreen(navController: NavHostController=rememberNavController(), searchV
selectedYearContentColor=Color.White, selectedYearContentColor=Color.White,
subheadContentColor=Color(0xff423a99), subheadContentColor=Color(0xff423a99),
titleContentColor=Color(0xff423a99), titleContentColor=Color(0xff423a99),
todayContentColor=Color.White, todayContentColor=Color(0xff423a99),
todayDateBorderColor=Color(0xff423a99), todayDateBorderColor=Color(0xff423a99),
weekdayContentColor=Color(0xff423a99), weekdayContentColor=Color(0xff423a99),
yearContentColor=Color(0xff423a99) yearContentColor=Color(0xff423a99)
@ -246,7 +255,7 @@ fun LoadScreen(navController: NavHostController=rememberNavController(), searchV
) { ) {
Modifier Modifier
.padding(it) .padding(it)
HomeNavGraph(navController = navController,currentUserViewModel) HomeNavGraph(navController = navController,articlePageScreenViewModel, tagItemViewModel,articleScreenViewModel,currentUserViewModel)
} }
} }

View File

@ -1,5 +1,6 @@
package com.example.pmulabs.screensMobile package com.example.pmulabs.screensMobile
import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
@ -21,7 +22,6 @@ import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -30,6 +30,7 @@ import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonColors
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@ -39,11 +40,11 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -62,80 +63,45 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize import androidx.compose.ui.unit.toSize
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.R import com.example.pmulabs.R
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.designElem.elem.ValidateEmail import com.example.pmulabs.designElem.elem.ValidateEmail
import com.example.pmulabs.designElem.elem.isValidEmail import com.example.pmulabs.designElem.elem.isValidEmail
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.ArticlePageScreenViewModel
import com.example.pmulabs.viewModels.ArticleScreenViewModel
import com.example.pmulabs.viewModels.CurrentUserViewModel import com.example.pmulabs.viewModels.CurrentUserViewModel
import kotlinx.coroutines.CoroutineScope import com.example.pmulabs.viewModels.TagItemViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.Date import java.util.Date
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,articleScreenViewModel: ArticleScreenViewModel= viewModel(factory = AppViewModelProvider.Factory),tagItemViewModel: TagItemViewModel= viewModel(factory = AppViewModelProvider.Factory),articlePageScreenViewModel: ArticlePageScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val context = LocalContext.current val context = LocalContext.current
var getUser by remember { mutableStateOf(currentUserViewModel.user) } var getUser by remember { mutableStateOf(currentUserViewModel.user) }
var openDialogUser by remember { mutableStateOf(false) } var openDialogUser by remember { mutableStateOf(false) }
var email by remember { mutableStateOf(getUser?.email) } var email by remember { mutableStateOf(getUser?.email) }
var password by remember { mutableStateOf(getUser?.password) } var password by remember { mutableStateOf(getUser?.password) }
var nickname by remember { mutableStateOf(getUser?.nickname) } var nickname by remember { mutableStateOf(getUser?.nickname) }
val getArticles = articleScreenViewModel.articles.collectAsLazyPagingItems()
val getComms = articlePageScreenViewModel.comments.collectAsLazyPagingItems()
val getTags = tagItemViewModel.tags.collectAsLazyPagingItems()
val coroutineScope = rememberCoroutineScope()
articlePageScreenViewModel.setTagList()
val getComms = remember { mutableStateListOf<Comment>() } val tags = mutableStateOf<List<Tag>>(articlePageScreenViewModel.tagList)
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserComms(getUser?.id.toString().toInt()).collect { data ->
getComms.clear()
getComms.addAll(data)
}
}
}
val getArticles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserArticles(getUser?.id.toString().toInt()).collect { data ->
getArticles.clear()
getArticles.addAll(data)
}
}
}
val getTags = remember { mutableStateListOf<Tag>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserTags(getUser?.id.toString().toInt()).collect { data ->
getTags.clear()
getTags.addAll(data)
}
}
}
//список тэгов
val tags = remember { mutableStateListOf<Tag>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).tagDao().getAll().collect { data ->
tags.clear()
tags.addAll(data)
}
}
}
//список названий тэгов //список названий тэгов
var tagsNames= remember { mutableStateListOf<String>() } var tagsNames = remember { mutableStateListOf<String>() }
tags.forEach{teg -> tags.value.forEach { teg ->
if(!tagsNames.contains(teg.title)) { if (!tagsNames.contains(teg.title)) {
tagsNames.add(teg.title) tagsNames.add(teg.title)
} }
} }
@ -149,7 +115,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
val suggestions = tagsNames val suggestions = tagsNames
var selectedText by remember { mutableStateOf("") } var selectedText by remember { mutableStateOf("") }
var textfieldSize by remember { mutableStateOf(Size.Zero)} var textfieldSize by remember { mutableStateOf(Size.Zero) }
val icon = if (expanded) val icon = if (expanded)
Icons.Filled.ArrowDropUp Icons.Filled.ArrowDropUp
else else
@ -159,8 +125,8 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
AlertDialog( AlertDialog(
onDismissRequest = { onDismissRequest = {
openDialog = false openDialog = false
text="" text = ""
title="" title = ""
}, },
content = { content = {
Column( Column(
@ -186,7 +152,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.onGloballyPositioned { coordinates -> .onGloballyPositioned { coordinates ->
textfieldSize = coordinates.size.toSize() textfieldSize = coordinates.size.toSize()
}, },
label = {Text("Select Tag")}, label = { Text("Select Tag") },
colors = TextFieldDefaults.textFieldColors( colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White, containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99), focusedIndicatorColor = Color(0xff423a99),
@ -195,7 +161,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
unfocusedLabelColor = Color(0xff423a99) unfocusedLabelColor = Color(0xff423a99)
), ),
trailingIcon = { trailingIcon = {
Icon(icon,"List of tags", Icon(icon, "List of tags",
Modifier.clickable { expanded = !expanded }) Modifier.clickable { expanded = !expanded })
} }
) )
@ -203,17 +169,18 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
expanded = expanded, expanded = expanded,
onDismissRequest = { expanded = false }, onDismissRequest = { expanded = false },
modifier = Modifier modifier = Modifier
.width(with(LocalDensity.current){textfieldSize.width.toDp()}) .width(with(LocalDensity.current) { textfieldSize.width.toDp() })
) { ) {
suggestions.forEach { label -> suggestions.forEach { label ->
DropdownMenuItem( DropdownMenuItem(
text= {Text(text=label)}, text = { Text(text = label) },
onClick = { selectedText = label onClick = {
CoroutineScope(Dispatchers.IO).launch { selectedText = label
NewsPortalDatabase.getInstance(context).tagDao().getTagByName(selectedText).collect{ tag -> coroutineScope.launch {
tagId=tag?.id.toString().toInt() tagId =
} articlePageScreenViewModel.getTagByName(selectedText).id!!
}} }
}
) )
} }
} }
@ -221,7 +188,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
OutlinedTextField( OutlinedTextField(
value = title, value = title,
onValueChange = { onValueChange = {
title=it title = it
}, },
colors = TextFieldDefaults.textFieldColors( colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White, containerColor = Color.White,
@ -242,7 +209,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
OutlinedTextField( OutlinedTextField(
value = text, value = text,
onValueChange = { onValueChange = {
text=it text = it
}, },
colors = TextFieldDefaults.textFieldColors( colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White, containerColor = Color.White,
@ -273,14 +240,13 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
), ),
onClick = { onClick = {
openDialog = false openDialog = false
if(title.isNotEmpty() && text.isNotEmpty() && tagId!=null) { if (title.isNotEmpty() && text.isNotEmpty() && tagId != null) {
val newArticle = Article( val newArticle = Article(
null, title, text, null, title, text,
Date().time, getUser?.id.toString().toInt(), tagId Date().time, getUser?.id.toString().toInt(), tagId
) )
CoroutineScope(Dispatchers.IO).launch { coroutineScope.launch {
NewsPortalDatabase.getInstance(context).articleDao() articlePageScreenViewModel.insertArticle(newArticle)
.insert(newArticle)
} }
} }
}, },
@ -301,9 +267,9 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
AlertDialog( AlertDialog(
onDismissRequest = { onDismissRequest = {
openDialogUser = false openDialogUser = false
email=getUser?.email.toString() email = getUser?.email.toString()
password=getUser?.password.toString() password = getUser?.password.toString()
nickname=getUser?.nickname.toString() nickname = getUser?.nickname.toString()
}, },
content = { content = {
Column( Column(
@ -319,12 +285,12 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
fontSize = 20.sp, fontSize = 20.sp,
), ),
) )
email?.let { ValidateEmail(it, {email=it} ) } email?.let { ValidateEmail(it, { email = it }) }
password?.let { password?.let {
OutlinedTextField( OutlinedTextField(
value = it, value = it,
onValueChange = { onValueChange = {
password=it password = it
}, },
colors = TextFieldDefaults.textFieldColors( colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White, containerColor = Color.White,
@ -347,7 +313,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
OutlinedTextField( OutlinedTextField(
value = it, value = it,
onValueChange = { onValueChange = {
nickname=it nickname = it
}, },
colors = TextFieldDefaults.textFieldColors( colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White, containerColor = Color.White,
@ -379,17 +345,16 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
), ),
onClick = { onClick = {
openDialogUser = false openDialogUser = false
if(password?.isNotEmpty() == true && email?.isNotEmpty() == true && isValidEmail( if (password?.isNotEmpty() == true && email?.isNotEmpty() == true && isValidEmail(
email!! email!!
) && nickname?.isNotEmpty() == true ) && nickname?.isNotEmpty() == true
) { ) {
getUser?.password= password as String getUser?.password = password as String
getUser?.email= email as String getUser?.email = email as String
getUser?.nickname= nickname as String getUser?.nickname = nickname as String
CoroutineScope(Dispatchers.IO).launch { coroutineScope.launch {
getUser?.let { getUser?.let {
NewsPortalDatabase.getInstance(context).userDao() articlePageScreenViewModel.updateUser(it)
.update(it)
} }
} }
} }
@ -409,7 +374,7 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
LazyColumn( LazyColumn(
contentPadding= PaddingValues(top=5.dp, bottom = 320.dp), contentPadding = PaddingValues(top = 5.dp, bottom = 320.dp),
modifier = modifier modifier = modifier
.requiredWidth(width = 412.dp) .requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp) .requiredHeight(height = 915.dp)
@ -430,7 +395,8 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
contentDescription = "Ellipse 8", contentDescription = "Ellipse 8",
modifier = Modifier modifier = Modifier
.requiredSize(size = 200.dp) .requiredSize(size = 200.dp)
.clip(shape = CircleShape)) .clip(shape = CircleShape)
)
Box( Box(
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
@ -446,18 +412,21 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xffdbdbf1))) .background(color = Color(0xffdbdbf1))
)
Text( Text(
text = "${getUser?.nickname}", text = "${getUser?.nickname}",
color = Color(0xff423a99), color = Color(0xff423a99),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
style = TextStyle( style = TextStyle(
fontSize = 17.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
Box( Box(
modifier = Modifier modifier = Modifier
@ -474,18 +443,21 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xffdbdbf1))) .background(color = Color(0xffdbdbf1))
)
Text( Text(
text = "${getUser?.email}", text = "${getUser?.email}",
color = Color(0xff423a99), color = Color(0xff423a99),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
style = TextStyle( style = TextStyle(
fontSize = 17.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
Box( Box(
modifier = Modifier modifier = Modifier
@ -502,14 +474,16 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99))) .background(color = Color(0xff423a99))
)
Text( Text(
text = "Add Article!", text = "Add Article!",
color = Color(0xffdbdbf1), color = Color(0xffdbdbf1),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
style = TextStyle( style = TextStyle(
fontSize = 17.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
@ -531,14 +505,16 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99))) .background(color = Color(0xff423a99))
)
Text( Text(
text = "Edit my Data", text = "Edit my Data",
color = Color(0xffdbdbf1), color = Color(0xffdbdbf1),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
style = TextStyle( style = TextStyle(
fontSize = 17.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.requiredWidth(width = 200.dp) .requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp) .requiredHeight(height = 44.dp)
@ -588,35 +564,69 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
), ),
verticalArrangement = Arrangement.spacedBy(1.dp) verticalArrangement = Arrangement.spacedBy(1.dp)
) { ) {
if (!getComms.isEmpty()) { if (getComms.itemCount != 0) {
items(items = getComms) { comment -> items(count = getComms.itemCount) { index ->
Spacer(modifier = Modifier.padding(5.dp)) val comment = getComms[index]
Text( if (comment?.userId == getUser?.id) {
text = "${comment.text}", Spacer(modifier = Modifier.padding(5.dp))
color = Color(0xff423a99), Text(
style = TextStyle( text = "${comment?.text}",
fontSize = 15.sp, color = Color(0xff423a99),
fontWeight = FontWeight.Bold style = TextStyle(
), fontSize = 15.sp,
modifier = Modifier fontWeight = FontWeight.Bold
.align(alignment = Alignment.TopStart) ),
.clickable { modifier = Modifier
navController.navigate( .align(alignment = Alignment.TopStart)
BottomBarScreen.ArticlePage.passId( .clickable {
comment.articleId.toString() navController.navigate(
BottomBarScreen.ArticlePage.passId(
comment?.articleId.toString()
)
) )
}
)
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider(
thickness = 3.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xffdbdbf1))),
color = Color(0xffdbdbf1)
)
}
}
getComms.apply {
when {
loadState.refresh is LoadState.Loading -> {
item {
CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(),
color = Color(0xff423a99)
) )
} }
) }
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider( loadState.append is LoadState.Loading -> {
thickness=3.dp, item {
modifier = Modifier CircularProgressIndicator(
.border(BorderStroke(3.dp, Color(0xffdbdbf1))), color = Color(0xffdbdbf1) modifier = Modifier.fillParentMaxSize(),
) color = Color(0xff423a99)
)
}
}
loadState.refresh is LoadState.Error -> {
val err = getComms.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = getComms.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
}
} }
} } else {
else{
item { item {
Text( Text(
text = "Комментариев пока нет!", text = "Комментариев пока нет!",
@ -644,13 +654,15 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.requiredWidth(width = 393.dp) .requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp) .requiredHeight(height = 54.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99))) .background(color = Color(0xff423a99))
)
Text( Text(
text = "Comments:", text = "Comments:",
color = Color.White, color = Color.White,
style = TextStyle( style = TextStyle(
fontSize = 17.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.offset( .offset(
@ -659,7 +671,8 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
) )
.requiredWidth(width = 210.dp) .requiredWidth(width = 210.dp)
.requiredHeight(height = 54.dp) .requiredHeight(height = 54.dp)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
} }
} }
@ -705,35 +718,69 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
), ),
verticalArrangement = Arrangement.spacedBy(1.dp) verticalArrangement = Arrangement.spacedBy(1.dp)
) { ) {
if (!getArticles.isEmpty()) { if (getArticles.itemCount != 0) {
items(items = getArticles) { article -> items(count = getArticles.itemCount) { index ->
Spacer(modifier = Modifier.padding(5.dp)) val article = getArticles[index]
Text( if (article?.userId == getUser?.id) {
text = "${article.title}", Spacer(modifier = Modifier.padding(5.dp))
color = Color(0xff423a99), Text(
style = TextStyle( text = "${article?.title}",
fontSize = 15.sp, color = Color(0xff423a99),
fontWeight = FontWeight.Bold style = TextStyle(
), fontSize = 15.sp,
modifier = Modifier fontWeight = FontWeight.Bold
.align(alignment = Alignment.TopStart) ),
.clickable { modifier = Modifier
navController.navigate( .align(alignment = Alignment.TopStart)
BottomBarScreen.ArticlePage.passId( .clickable {
article.id.toString() navController.navigate(
BottomBarScreen.ArticlePage.passId(
article?.id.toString()
)
) )
}
)
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider(
thickness = 3.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xffdbdbf1))),
color = Color(0xffdbdbf1)
)
}
}
getArticles.apply {
when {
loadState.refresh is LoadState.Loading -> {
item {
CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(),
color = Color(0xff423a99)
) )
} }
) }
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider( loadState.append is LoadState.Loading -> {
thickness=3.dp, item {
modifier = Modifier CircularProgressIndicator(
.border(BorderStroke(3.dp, Color(0xffdbdbf1))), color = Color(0xffdbdbf1) modifier = Modifier.fillParentMaxSize(),
) color = Color(0xff423a99)
)
}
}
loadState.refresh is LoadState.Error -> {
val err = getArticles.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = getArticles.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
}
} }
} } else {
else{
item { item {
Text( Text(
text = "Статей пока нет!", text = "Статей пока нет!",
@ -761,13 +808,15 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.requiredWidth(width = 393.dp) .requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp) .requiredHeight(height = 54.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99))) .background(color = Color(0xff423a99))
)
Text( Text(
text = "Articles:", text = "Articles:",
color = Color.White, color = Color.White,
style = TextStyle( style = TextStyle(
fontSize = 17.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.offset( .offset(
@ -776,7 +825,8 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
) )
.requiredWidth(width = 210.dp) .requiredWidth(width = 210.dp)
.requiredHeight(height = 54.dp) .requiredHeight(height = 54.dp)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
} }
} }
@ -822,29 +872,38 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
), ),
verticalArrangement = Arrangement.spacedBy(1.dp) verticalArrangement = Arrangement.spacedBy(1.dp)
) { ) {
if (!getTags.isEmpty()) { if (getTags.itemCount != 0) {
items(items = getTags) { tag -> items(count = getTags.itemCount) { index ->
Spacer(modifier = Modifier.padding(5.dp)) val tag = getTags[index]
Text( if (tag?.userId == getUser?.id) {
text = "${tag.title}", Spacer(modifier = Modifier.padding(5.dp))
color = Color(0xff423a99), Text(
style = TextStyle( text = "${tag?.title}",
fontSize = 15.sp, color = Color(0xff423a99),
fontWeight = FontWeight.Bold style = TextStyle(
), fontSize = 15.sp,
modifier = Modifier fontWeight = FontWeight.Bold
.align(alignment = Alignment.TopStart) ),
.clickable {navController.navigate(BottomBarScreen.SearchByTag.passId(tag.id.toString()))} modifier = Modifier
) .align(alignment = Alignment.TopStart)
Spacer(modifier = Modifier.padding(5.dp)) .clickable {
HorizontalDivider( navController.navigate(
thickness=3.dp, BottomBarScreen.SearchByTag.passId(
modifier = Modifier tag?.id.toString()
.border(BorderStroke(3.dp, Color(0xffdbdbf1))), color = Color(0xffdbdbf1) )
) )
}
)
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider(
thickness = 3.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xffdbdbf1))),
color = Color(0xffdbdbf1)
)
}
} }
} } else {
else{
item { item {
Text( Text(
text = "Тэгов пока нет!", text = "Тэгов пока нет!",
@ -872,13 +931,15 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
.requiredWidth(width = 393.dp) .requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp) .requiredHeight(height = 54.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99))) .background(color = Color(0xff423a99))
)
Text( Text(
text = "Tags:", text = "Tags:",
color = Color.White, color = Color.White,
style = TextStyle( style = TextStyle(
fontSize = 17.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold), fontWeight = FontWeight.Bold
),
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.offset( .offset(
@ -887,9 +948,11 @@ fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier, c
) )
.requiredWidth(width = 210.dp) .requiredWidth(width = 210.dp)
.requiredHeight(height = 54.dp) .requiredHeight(height = 54.dp)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
} }
} }
} }
} }

View File

@ -16,26 +16,24 @@ import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonColors
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@ -43,34 +41,24 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.designElem.items.TagItem import com.example.pmulabs.designElem.items.TagItem
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.CurrentUserViewModel import com.example.pmulabs.viewModels.CurrentUserViewModel
import kotlinx.coroutines.CoroutineScope import com.example.pmulabs.viewModels.TagItemViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun TagsScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){ fun TagsScreen(navController: NavController, modifier: Modifier = Modifier, tagItemViewModel: TagItemViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val context = LocalContext.current var tags = tagItemViewModel.tags.collectAsLazyPagingItems()
val tags = remember { mutableStateListOf<Tag>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).tagDao().getAll().collect { data ->
tags.clear()
tags.addAll(data)
}
}
}
var getUser by remember { mutableStateOf(currentUserViewModel.user) } var getUser by remember { mutableStateOf(currentUserViewModel.user) }
val coroutineScope = rememberCoroutineScope()
var openDialog by remember { mutableStateOf(false) } var openDialog by remember { mutableStateOf(false) }
var text by remember { mutableStateOf("") } var text by remember { mutableStateOf("") }
@ -130,10 +118,10 @@ fun TagsScreen(navController: NavController, modifier: Modifier = Modifier, curr
openDialog = false openDialog = false
if(text.isNotEmpty()) { if(text.isNotEmpty()) {
val newTag = Tag(null, text, getUser?.id.toString().toInt()) val newTag = Tag(null, text, getUser?.id.toString().toInt())
CoroutineScope(Dispatchers.IO).launch { coroutineScope.launch {
NewsPortalDatabase.getInstance(context).tagDao() tagItemViewModel.insertTag(newTag)
.insert(newTag)
} }
navController.navigate(BottomBarScreen.Categories.route)
} }
}, },
modifier = Modifier modifier = Modifier
@ -186,12 +174,34 @@ fun TagsScreen(navController: NavController, modifier: Modifier = Modifier, curr
) )
} }
} }
items(items = tags){ tag -> items(count = tags.itemCount) { index ->
TagItem( val tag = tags[index]
teg = tag, if (tag != null) {
viewModel = currentUserViewModel, TagItem(
onTagClick = {navController.navigate(BottomBarScreen.SearchByTag.passId(tag.id.toString()))} navController=navController,
teg = tag,
viewModel = currentUserViewModel,
onTagClick = {navController.navigate(BottomBarScreen.SearchByTag.passId(tag?.id.toString()))}
) )
}
}
tags.apply {
when {
loadState.refresh is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.append is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.refresh is LoadState.Error -> {
val err = tags.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = tags.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
}
} }
} }
} }

View File

@ -1,5 +1,6 @@
package com.example.pmulabs.screensMobile.authScreens package com.example.pmulabs.screensMobile.authScreens
import android.annotation.SuppressLint
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -28,11 +29,9 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -41,7 +40,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
@ -58,33 +56,24 @@ import com.example.pmulabs.designElem.statDesign.LogoMobile
import com.example.pmulabs.designElem.statDesign.RightCircles import com.example.pmulabs.designElem.statDesign.RightCircles
import com.example.pmulabs.graphs.AuthScreen import com.example.pmulabs.graphs.AuthScreen
import com.example.pmulabs.graphs.Graph import com.example.pmulabs.graphs.Graph
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.User import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import com.example.pmulabs.viewModels.CurrentUserViewModel import com.example.pmulabs.viewModels.CurrentUserViewModel
import kotlinx.coroutines.Dispatchers import com.example.pmulabs.viewModels.EntryScreenViewModel
import kotlinx.coroutines.withContext
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun EntryScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { fun EntryScreen(navController: NavController, modifier: Modifier = Modifier,entryScreenViewModel: EntryScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
var emailValue by rememberSaveable { mutableStateOf("") } var emailValue by rememberSaveable { mutableStateOf("") }
var passwordValue by rememberSaveable { mutableStateOf("") } var passwordValue by rememberSaveable { mutableStateOf("") }
val context = LocalContext.current entryScreenViewModel.setUserList()
val users = remember { mutableStateListOf<User>() } val users = mutableStateOf<List<User>>(entryScreenViewModel.userList)
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao().getAll().collect { data ->
users.clear()
users.addAll(data)
}
}
}
val argument = currentUserViewModel.argument.value val argument = currentUserViewModel.argument.value
var passwordVisibility by rememberSaveable { mutableStateOf(false) } var passwordVisibility by rememberSaveable { mutableStateOf(false) }
val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex() val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex()
val coroutineScope = rememberCoroutineScope()
Box( Box(
modifier = modifier modifier = modifier
@ -205,7 +194,7 @@ fun EntryScreen(navController: NavController, modifier: Modifier = Modifier, cur
), ),
onClick = { onClick = {
if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) { if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) {
users.forEach { user -> users.value.forEach { user ->
if (user.password == passwordValue && user.email == emailValue) { if (user.password == passwordValue && user.email == emailValue) {
currentUserViewModel.setArgument(user.id.toString()) currentUserViewModel.setArgument(user.id.toString())
navController.navigate(route = Graph.passUserId(user.id.toString())) { navController.navigate(route = Graph.passUserId(user.id.toString())) {

View File

@ -1,5 +1,6 @@
package com.example.pmulabs.screensMobile.authScreens package com.example.pmulabs.screensMobile.authScreens
import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -29,11 +30,9 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -42,7 +41,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
@ -54,36 +52,31 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.pmulabs.designElem.elem.ValidateEmail import com.example.pmulabs.designElem.elem.ValidateEmail
import com.example.pmulabs.designElem.elem.isValidEmail import com.example.pmulabs.designElem.elem.isValidEmail
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.designElem.statDesign.LeftCircles import com.example.pmulabs.designElem.statDesign.LeftCircles
import com.example.pmulabs.designElem.statDesign.LogoMobile import com.example.pmulabs.designElem.statDesign.LogoMobile
import com.example.pmulabs.designElem.statDesign.RightCircles import com.example.pmulabs.designElem.statDesign.RightCircles
import com.example.pmulabs.graphs.AuthScreen import com.example.pmulabs.graphs.AuthScreen
import com.example.pmulabs.graphs.Graph import com.example.pmulabs.graphs.Graph
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.User import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import kotlinx.coroutines.CoroutineScope import com.example.pmulabs.viewModels.CurrentUserViewModel
import kotlinx.coroutines.Dispatchers import com.example.pmulabs.viewModels.RegisterScreenViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun RegisterScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) { fun RegisterScreen(navController: NavController, modifier: Modifier = Modifier,registerScreenViewModel: RegisterScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
var emailValue by rememberSaveable { mutableStateOf("") } var emailValue by rememberSaveable { mutableStateOf("") }
var passwordValue by rememberSaveable { mutableStateOf("") } var passwordValue by rememberSaveable { mutableStateOf("") }
var nicknameValue by rememberSaveable { mutableStateOf("") } var nicknameValue by rememberSaveable { mutableStateOf("") }
val context = LocalContext.current val coroutineScope = rememberCoroutineScope()
val users = remember { mutableStateListOf<User>() } registerScreenViewModel.setUserList()
LaunchedEffect(Unit) { var users = mutableStateOf<List<User>>(emptyList())
withContext(Dispatchers.IO) { registerScreenViewModel.users.observeForever { userList ->
NewsPortalDatabase.getInstance(context).userDao().getAll().collect { data -> users.value = userList
users.clear()
users.addAll(data)
}
}
} }
var passwordVisibility by rememberSaveable { mutableStateOf(false) } var passwordVisibility by rememberSaveable { mutableStateOf(false) }
@ -169,7 +162,7 @@ fun RegisterScreen(navController: NavController, modifier: Modifier = Modifier,
TextField( TextField(
value = nicknameValue, value = nicknameValue,
onValueChange = { onValueChange = {
nicknameValue=it nicknameValue = it
}, },
colors = TextFieldDefaults.textFieldColors( colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White containerColor = Color.White
@ -185,7 +178,7 @@ fun RegisterScreen(navController: NavController, modifier: Modifier = Modifier,
singleLine = true, singleLine = true,
) )
Spacer(modifier = Modifier.padding(3.dp)) Spacer(modifier = Modifier.padding(3.dp))
ValidateEmail(emailValue, {emailValue=it} ) ValidateEmail(emailValue, { emailValue = it })
Spacer(modifier = Modifier.padding(3.dp)) Spacer(modifier = Modifier.padding(3.dp))
TextField( TextField(
value = passwordValue, value = passwordValue,
@ -228,32 +221,32 @@ fun RegisterScreen(navController: NavController, modifier: Modifier = Modifier,
onClick = { onClick = {
var isExist = false; var isExist = false;
if (passwordValue.isNotEmpty() && isValidEmail(emailValue) && nicknameValue.isNotEmpty()) { if (passwordValue.isNotEmpty() && isValidEmail(emailValue) && nicknameValue.isNotEmpty()) {
users.forEach { user -> users.value.forEach { user ->
if (user.email == emailValue || user.nickname == nicknameValue) { if (user.email == emailValue || user.nickname == nicknameValue) {
Log.d("User already exist. User id: ", user.id.toString()) Log.d("User already exist. User id: ", user.id.toString())
isExist = true isExist = true
} }
} }
if (!isExist) { if (!isExist) {
var newUser = User(null, nicknameValue, emailValue, passwordValue, "user") val newUser = User(null, nicknameValue, emailValue, passwordValue, "user")
CoroutineScope(Dispatchers.IO).launch { coroutineScope.launch {
NewsPortalDatabase.getInstance(context).userDao().insert(newUser) val insertResult = async {
NewsPortalDatabase.getInstance(context).userDao().getAll() registerScreenViewModel.insertUser(newUser)
.collect { data -> }
data.forEach { user ->
if (user.password == passwordValue && user.email == emailValue) { insertResult.await()
withContext(Dispatchers.Main) {
currentUserViewModel.setArgument(user.id.toString()) registerScreenViewModel.setUserList()
navController.navigate( registerScreenViewModel.users.observeForever { userList ->
route = Graph.passUserId( users.value = userList
user.id.toString() Log.println(Log.ASSERT, "UsersList", users.value.toString())
) users.value?.forEach { user ->
) if (user.password == passwordValue && user.email == emailValue) {
} currentUserViewModel.setArgument(user.id.toString())
} navController.navigate(route = Graph.passUserId(user.id.toString()))
} }
} }
}
} }
} }
} }
@ -288,195 +281,9 @@ fun RegisterScreen(navController: NavController, modifier: Modifier = Modifier,
} }
) )
Spacer(modifier = Modifier.padding(20.dp)) Spacer(modifier = Modifier.padding(20.dp))
} }
} }
} }
} }
} }
/*
@Composable
fun RegisterScreen(navController: NavController,modifier: Modifier = Modifier) {
Box(
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp)
.background(color = Color.White)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = (-17).dp,
y = 329.dp
)
.requiredWidth(width = 436.dp)
.requiredHeight(height = 325.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 69.1444091796875.dp,
y = 122.9124755859375.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 61.dp)
) {
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 69.1444091796875.dp,
y = 193.824951171875.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 61.dp)
) {
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 68.dp,
y = 52.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 61.dp)
) {
}
Text(
textAlign = TextAlign.Center,
text = buildAnnotatedString {
withStyle(style = SpanStyle(
color = Color(0xff7d7dbd),
fontSize = 20.sp)) {append("Please, ")}
withStyle(style = SpanStyle(
color = Color(0xff7d7dbd),
fontSize = 20.sp,
fontWeight = FontWeight.Bold)) {append("Sign Up")}},
modifier = Modifier
.fillMaxSize())
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 128.dp,
y = 730.dp
)
.requiredWidth(width = 381.dp)
.requiredHeight(height = 268.dp)
.rotate(degrees = 8.33f)
) {
RightCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = (-111.28436279296875).dp,
y = (-96.86965942382812).dp
)
.requiredWidth(width = 250.dp)
.requiredHeight(height = 290.dp)
) {
Box(
modifier = Modifier
.rotate(degrees = 12.96f)
) {
LeftCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 140.35101318359375.dp,
y = 152.06341552734375.dp
)
.requiredWidth(width = 66.dp)
.requiredHeight(height = 27.dp)
) {
BackButton(modifier=Modifier
.clickable { navController.navigate(route = AuthScreen.Entry.route){
popUpTo(AuthScreen.Splash.route)
} })}
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 50.dp,
y = 681.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 127.dp)
) {
Text(
text = "Do you have an account? ",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp),
modifier = Modifier
.fillMaxSize()
.offset(
x = 0.dp,
y = 75.dp
))
Text(
text = "Sign In",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.fillMaxSize()
.offset(
x = 0.dp,
y = 95.dp
)
.clickable { navController.navigate(route = AuthScreen.Entry.route)
{
popUpTo(AuthScreen.Splash.route)
}})
Box(
modifier = Modifier
.requiredWidth(width = 308.dp)
.requiredHeight(height = 82.dp)
) {
ButtonCustom(name = "Sign Up",modifier = Modifier
.fillMaxSize()
.clickable { navController.navigate(route = Graph.MAIN){
popUpTo(Graph.MAIN)
} }
)
}
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 57.dp,
y = 165.dp
)
.requiredWidth(width = 302.dp)
.requiredHeight(height = 140.dp)
) {
LogoMobile(modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 9.dp
)
.fillMaxWidth()
.requiredHeight(height = 131.dp))
}
}
}*/

View File

@ -1,5 +1,6 @@
package com.example.pmulabs.screensMobile.filterScreens package com.example.pmulabs.screensMobile.filterScreens
import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -7,41 +8,29 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.CALENDAR_ARGUMENT_DATE import com.example.pmulabs.basecomponents.navigate.CALENDAR_ARGUMENT_DATE
import com.example.pmulabs.designElem.elem.BackButton import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.ArticleItem import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import kotlinx.coroutines.Dispatchers import com.example.pmulabs.viewModels.ArticleScreenViewModel
import kotlinx.coroutines.withContext import com.example.pmulabs.viewModels.CurrentUserViewModel
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@SuppressLint("UnrememberedMutableState")
@Composable @Composable
fun CalendarScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){ fun CalendarScreen(navController: NavController, articleScreenViewModel: ArticleScreenViewModel= viewModel(factory = AppViewModelProvider.Factory), modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val context = LocalContext.current val articles = articleScreenViewModel.articles.collectAsLazyPagingItems()
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
var date=navController.currentBackStackEntry?.arguments?.getString(CALENDAR_ARGUMENT_DATE).toString() var date=navController.currentBackStackEntry?.arguments?.getString(CALENDAR_ARGUMENT_DATE).toString()
Log.d("date: ",date) Log.d("date: ",date)
val formatter = SimpleDateFormat("dd-MMMM-YY") val formatter = SimpleDateFormat("dd-MMMM-YY")
@ -56,14 +45,43 @@ fun CalendarScreen(navController: NavController, modifier: Modifier = Modifier,
BackButton(modifier=Modifier BackButton(modifier=Modifier
.clickable { navController.popBackStack()}) .clickable { navController.popBackStack()})
} }
items(items = articles){ article -> items(count = articles.itemCount) { index ->
val publishDate=formatter.format(article.publishDate) val article = articles[index]
val publishDate=formatter.format(article?.publishDate)
if(publishDate==date) { if(publishDate==date) {
ArticleItem( if (article != null) {
article = article, ArticleItem(
currentUserViewModel=currentUserViewModel, navController=navController,
onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))} article = article,
) currentUserViewModel = currentUserViewModel,
onArticleClick = {
navController.navigate(
BottomBarScreen.ArticlePage.passId(
article?.id.toString()
)
)
}
)
}
}
}
articles.apply {
when {
loadState.refresh is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.append is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.refresh is LoadState.Error -> {
val err = articles.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = articles.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
} }
} }
} }

View File

@ -7,40 +7,28 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.SEARCHBYTAG_ARGUMENT_KEY import com.example.pmulabs.basecomponents.navigate.SEARCHBYTAG_ARGUMENT_KEY
import com.example.pmulabs.designElem.elem.BackButton import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.ArticleItem import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import kotlinx.coroutines.Dispatchers import com.example.pmulabs.viewModels.ArticleScreenViewModel
import kotlinx.coroutines.withContext import com.example.pmulabs.viewModels.CurrentUserViewModel
@Composable @Composable
fun SearchByTagScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){ fun SearchByTagScreen(navController: NavController, modifier: Modifier = Modifier, articleScreenViewModel: ArticleScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val context = LocalContext.current val articles = articleScreenViewModel.articles.collectAsLazyPagingItems()
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
var id=navController.currentBackStackEntry?.arguments?.getString(SEARCHBYTAG_ARGUMENT_KEY).toString() var id=navController.currentBackStackEntry?.arguments?.getString(SEARCHBYTAG_ARGUMENT_KEY).toString()
Log.d("id: ",id) Log.d("id: ",id)
@ -53,9 +41,30 @@ fun SearchByTagScreen(navController: NavController, modifier: Modifier = Modifie
BackButton(modifier=Modifier BackButton(modifier=Modifier
.clickable { navController.popBackStack()}) .clickable { navController.popBackStack()})
} }
items(items = articles){ article -> items(count = articles.itemCount) { index ->
if(article.tagId.toString()==id) { val article = articles[index]
ArticleItem(article = article, currentUserViewModel = currentUserViewModel, onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))}) if(article?.tagId.toString()==id) {
if (article != null) {
ArticleItem(navController=navController,article = article, currentUserViewModel = currentUserViewModel, onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))})
}
}
}
articles.apply {
when {
loadState.refresh is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.append is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.refresh is LoadState.Error -> {
val err = articles.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = articles.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
} }
} }
} }

View File

@ -7,40 +7,27 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.SEARCH_ARGUMENT_TEXT import com.example.pmulabs.basecomponents.navigate.SEARCH_ARGUMENT_TEXT
import com.example.pmulabs.designElem.elem.BackButton import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.ArticleItem import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.viewModels.CurrentUserViewModel
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.AppViewModelProvider import com.example.pmulabs.viewModels.AppViewModelProvider
import kotlinx.coroutines.Dispatchers import com.example.pmulabs.viewModels.ArticleScreenViewModel
import kotlinx.coroutines.withContext import com.example.pmulabs.viewModels.CurrentUserViewModel
@Composable @Composable
fun SearchScreen(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){ fun SearchScreen(navController: NavController, modifier: Modifier = Modifier, articleScreenViewModel: ArticleScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val context = LocalContext.current val articles = articleScreenViewModel.articles.collectAsLazyPagingItems()
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
var text=navController.currentBackStackEntry?.arguments?.getString(SEARCH_ARGUMENT_TEXT).toString() var text=navController.currentBackStackEntry?.arguments?.getString(SEARCH_ARGUMENT_TEXT).toString()
Log.d("text: ",text) Log.d("text: ",text)
@ -54,9 +41,30 @@ fun SearchScreen(navController: NavController, modifier: Modifier = Modifier, cu
BackButton(modifier=Modifier BackButton(modifier=Modifier
.clickable { navController.popBackStack()}) .clickable { navController.popBackStack()})
} }
items(items = articles){ article -> items(count = articles.itemCount) { index ->
if(article.title.contains(text)) { val article = articles[index]
ArticleItem(article = article,currentUserViewModel=currentUserViewModel,onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))}) if(article?.title?.contains(text)==true) {
if (article != null) {
ArticleItem(navController=navController,article = article,currentUserViewModel=currentUserViewModel,onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))})
}
}
}
articles.apply {
when {
loadState.refresh is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.append is LoadState.Loading -> {
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = Color(0xff423a99)) }
}
loadState.refresh is LoadState.Error -> {
val err = articles.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) }
}
loadState.append is LoadState.Error -> {
val err = articles.loadState.append as LoadState.Error
item { Text(err.error.localizedMessage) }
}
} }
} }
} }

View File

@ -20,6 +20,18 @@ object AppViewModelProvider {
initializer { initializer {
ArticleItemViewModel(newsPortalApplication().container.tagRepository,newsPortalApplication().container.commentRepository,newsPortalApplication().container.articleRepository) ArticleItemViewModel(newsPortalApplication().container.tagRepository,newsPortalApplication().container.commentRepository,newsPortalApplication().container.articleRepository)
} }
initializer {
EntryScreenViewModel(newsPortalApplication().container.userRepository)
}
initializer {
RegisterScreenViewModel(newsPortalApplication().container.userRepository)
}
initializer {
ArticleScreenViewModel(newsPortalApplication().container.articleRepository)
}
initializer {
ArticlePageScreenViewModel(newsPortalApplication().container.tagRepository,newsPortalApplication().container.commentRepository,newsPortalApplication().container.articleRepository,newsPortalApplication().container.userRepository)
}
} }
} }

View File

@ -0,0 +1,74 @@
package com.example.pmulabs.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import com.example.pmulabs.room.repository.ArticleRepository
import com.example.pmulabs.room.repository.CommentRepository
import com.example.pmulabs.room.repository.TagRepository
import com.example.pmulabs.room.repository.UserRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class ArticlePageScreenViewModel(
private val tagRepository: TagRepository,
private val commentRepository: CommentRepository,
private val articleRepository: ArticleRepository,
private val userRepository: UserRepository
) : ViewModel() {
private val articleid = mutableStateOf<Int?>(null)
private val tagid = mutableStateOf<Int?>(null)
var article by mutableStateOf<Article?>(null)
var tag by mutableStateOf<Tag?>(null)
val comments: Flow<PagingData<Comment>> = commentRepository.getComments()
fun getArticleById(articleId:Int) {
articleid.value = articleId
viewModelScope.launch {
article = articleRepository.getArticleById(articleid.value!!)
.filterNotNull()
.first()
}
}
var tagList by mutableStateOf<List<Tag>>(emptyList())
fun setTagList() {
viewModelScope.launch {
tagList=tagRepository.getAllTags().first()
}
}
suspend fun insertComment(comment: Comment) {
commentRepository.insertComment(comment)
}
suspend fun updateUser(user: User) {
userRepository.updateUser(user)
}
suspend fun insertArticle(article: Article) {
articleRepository.insertArticle(article)
}
suspend fun getTagByName(name: String) : Tag {
return tagRepository.getTagByName(name).first()
}
fun getTagById(tagId:Int) {
tagid.value = tagId
viewModelScope.launch {
tag = tagRepository.getTagById(tagid.value!!)
.filterNotNull()
.first()
}
}
}

View File

@ -0,0 +1,11 @@
package com.example.pmulabs.viewModels
import androidx.lifecycle.ViewModel
import androidx.paging.PagingData
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.repository.ArticleRepository
import kotlinx.coroutines.flow.Flow
class ArticleScreenViewModel(private val articleRepository: ArticleRepository) : ViewModel() {
val articles: Flow<PagingData<Article>> = articleRepository.getArticles()
}

View File

@ -0,0 +1,21 @@
package com.example.pmulabs.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.pmulabs.room.models.User
import com.example.pmulabs.room.repository.UserRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class EntryScreenViewModel(private val userRepository: UserRepository) : ViewModel() {
var userList by mutableStateOf<List<User>>(emptyList())
fun setUserList() {
viewModelScope.launch {
userList=userRepository.getAllUsers().first()
}
}
}

View File

@ -0,0 +1,26 @@
package com.example.pmulabs.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.pmulabs.room.models.User
import com.example.pmulabs.room.repository.UserRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class RegisterScreenViewModel(private val userRepository: UserRepository) : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> get() = _users
fun setUserList() {
viewModelScope.launch {
_users.value = userRepository.getAllUsers().first()
}
}
suspend fun insertUser(user: User) {
userRepository.insertUser(user)
}
}

View File

@ -1,12 +1,19 @@
package com.example.pmulabs.viewModels package com.example.pmulabs.viewModels
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.paging.PagingData
import com.example.pmulabs.room.models.Tag import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.repository.TagRepository import com.example.pmulabs.room.repository.TagRepository
import kotlinx.coroutines.flow.Flow
class TagItemViewModel( class TagItemViewModel(
private val tagRepository: TagRepository private val tagRepository: TagRepository
) : ViewModel() { ) : ViewModel() {
var tags: Flow<PagingData<Tag>> = tagRepository.getTags()
suspend fun insertTag(tag: Tag) {
tagRepository.insertTag(tag)
}
suspend fun updateTag(tag: Tag) { suspend fun updateTag(tag: Tag) {
tagRepository.updateTag(tag) tagRepository.updateTag(tag)
} }