Compare commits

..

2 Commits

Author SHA1 Message Date
maxnes3
105629fa62 Добавил 2023-12-23 11:27:17 +04:00
maxnes3
469c57088c Залил 2 лабу 2023-12-23 11:24:54 +04:00
44 changed files with 374 additions and 1684 deletions

2
.idea/kotlinc.xml generated

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="KotlinJpsPluginSettings"> <component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.20" /> <option name="version" value="1.8.10" />
</component> </component>
</project> </project>

@ -1,7 +1,6 @@
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp")
} }
android { android {
@ -31,17 +30,17 @@ android {
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_1_8
} }
kotlinOptions { kotlinOptions {
jvmTarget = "17" jvmTarget = "1.8"
} }
buildFeatures { buildFeatures {
compose = true compose = true
} }
composeOptions { composeOptions {
kotlinCompilerExtensionVersion = "1.4.5" kotlinCompilerExtensionVersion = "1.4.3"
} }
packaging { packaging {
resources { resources {
@ -68,16 +67,4 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation("androidx.compose.ui:ui-test-manifest")
// Room
val room_version = "2.5.2"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version")
//Paging
implementation ("androidx.paging:paging-compose:3.2.1")
implementation ("androidx.paging:paging-runtime:3.2.1")
} }

@ -3,7 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<application <application
android:name=".MobileApp"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"

@ -3,13 +3,28 @@ package com.example.mobileapp
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.example.mobileapp.components.NavBar import com.example.mobileapp.entities.Mail
import com.example.mobileapp.database.entities.User import com.example.mobileapp.entities.MailSingleton
import com.example.mobileapp.entities.Story
import com.example.mobileapp.entities.StorySingleton
import com.example.mobileapp.screens.Authorization
import com.example.mobileapp.screens.EditMailScreen
import com.example.mobileapp.screens.EditStoryScreen
import com.example.mobileapp.screens.ListDataScreen
import com.example.mobileapp.screens.ListMailScreen
import com.example.mobileapp.screens.MainScreen
import com.example.mobileapp.screens.Registration
import com.example.mobileapp.screens.SettingsScreen
import com.example.mobileapp.ui.theme.MobileAppTheme import com.example.mobileapp.ui.theme.MobileAppTheme
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ -23,31 +38,57 @@ class MainActivity : ComponentActivity() {
color = MaterialTheme.colorScheme.background color = MaterialTheme.colorScheme.background
) { ) {
val navController = rememberNavController() val navController = rememberNavController()
NavBar(navController = navController) val mailSingleton = MailSingleton()
mailSingleton.addMail(Mail(0, 0, "Дзюнзи Ито", "Выложил новый"))
mailSingleton.addMail(Mail(1, 1, "Стивен Кинг", "Меня отменили в Твиттере"))
mailSingleton.addMail(Mail(0, 0, "Дзюнзи Ито", "Выложил новый"))
mailSingleton.addMail(Mail(1, 1, "Стивен Кинг", "Меня отменили в Твиттере"))
mailSingleton.addMail(Mail(0, 0, "Дзюнзи Ито", "Выложил новый"))
mailSingleton.addMail(Mail(1, 1, "Стивен Кинг", "Меня отменили в Твиттере"))
mailSingleton.addMail(Mail(0, 0, "Дзюнзи Ито", "Выложил новый"))
mailSingleton.addMail(Mail(1, 1, "Стивен Кинг", "Меня отменили в Твиттере"))
val storySingleton = StorySingleton()
storySingleton.addStory(Story(0, "Чужак", "Знаменитая книга стивена кинга", R.drawable.king))
storySingleton.addStory(Story(1, "Переулок", "История ужасов от Дзюнзи Ито", R.drawable.dzun))
storySingleton.addStory(Story(2, "Чужак", "Знаменитая книга стивена кинга", R.drawable.king))
storySingleton.addStory(Story(3, "Переулок", "История ужасов от Дзюнзи Ито", R.drawable.dzun))
AppNavigation(navController = navController)
} }
} }
} }
} }
} }
class GlobalUser private constructor() { @Composable
private var user: User? = null fun AppNavigation(navController: NavHostController){
NavHost(
fun setUser(user: User?) { navController = navController, startDestination = "authorization"
this.user = user ) {
} composable("authorization"){
Authorization(navController = navController)
fun getUser(): User? { }
return user composable("registration"){
} Registration(navController = navController)
}
companion object { composable("main"){
private var instance: GlobalUser? = null MainScreen(navController = navController)
}
fun getInstance(): GlobalUser { composable("listdata"){
return instance ?: synchronized(this) { ListDataScreen(navController = navController)
instance ?: GlobalUser().also { instance = it } }
} composable("mail"){
ListMailScreen(navController = navController)
}
composable("settings"){
SettingsScreen(navController = navController)
}
composable("editstory"){
EditStoryScreen(navController = navController)
}
composable("editmail"){
EditMailScreen(navController = navController)
} }
} }
} }

@ -1,12 +0,0 @@
package com.example.mobileapp
import android.app.Application
class MobileApp: Application() {
lateinit var container: MobileAppContainer
override fun onCreate() {
super.onCreate()
container = MobileAppDataContainer(this)
}
}

@ -1,34 +0,0 @@
package com.example.mobileapp
import android.content.Context
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.repositories.MailRepository
import com.example.mobileapp.database.repositories.OfflineMailRepository
import com.example.mobileapp.database.repositories.OfflineStoryRepository
import com.example.mobileapp.database.repositories.OfflineUserRepository
import com.example.mobileapp.database.repositories.StoryRepository
import com.example.mobileapp.database.repositories.UserRepository
interface MobileAppContainer {
val mailRepository: MailRepository
val storyRepository: StoryRepository
val userRepository: UserRepository
}
class MobileAppDataContainer(private val context: Context): MobileAppContainer {
override val mailRepository: MailRepository by lazy {
OfflineMailRepository(MobileAppDataBase.getInstance(context).mailDao())
}
override val storyRepository: StoryRepository by lazy {
OfflineStoryRepository(MobileAppDataBase.getInstance(context).storyDao())
}
override val userRepository: UserRepository by lazy {
OfflineUserRepository(MobileAppDataBase.getInstance(context).userDao())
}
companion object{
const val TIMEOUT = 5000L
}
}

@ -27,23 +27,18 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
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.navigation.NavHostController
import com.example.mobileapp.ui.theme.MobileAppTheme import com.example.mobileapp.ui.theme.MobileAppTheme
val buttonHeightStandard = 72.dp
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PlaceholderInputField(label: String, startValue: String? = null, isSingleLine: Boolean, onTextChanged: (String) -> Unit){ fun PlaceholderInputField(label: String){
var text = remember { mutableStateOf("") } var text = remember { mutableStateOf("") }
startValue?.let{
text.value = startValue
}
OutlinedTextField( OutlinedTextField(
value = text.value, value = text.value,
onValueChange = { onValueChange = {
text.value = it text.value = it
onTextChanged(it)
}, },
placeholder = { placeholder = {
Text(label) Text(label)
@ -51,24 +46,18 @@ fun PlaceholderInputField(label: String, startValue: String? = null, isSingleLin
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp), .padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp),
shape = RoundedCornerShape(10.dp), shape = RoundedCornerShape(10.dp))
singleLine = isSingleLine
)
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PasswordInputField(label: String, startValue: String? = null, onPasswordChanged: (String) -> Unit){ fun PasswordInputField(label: String){
var text = remember { mutableStateOf("") } var text = remember { mutableStateOf("") }
startValue?.let{
text.value = startValue
}
OutlinedTextField( OutlinedTextField(
value = text.value, value = text.value,
onValueChange = { onValueChange = {
text.value = it text.value = it
onPasswordChanged(it)
}, },
placeholder = { placeholder = {
Text(label) Text(label)
@ -82,14 +71,13 @@ fun PasswordInputField(label: String, startValue: String? = null, onPasswordChan
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SearchInputField(onTextChanged: (String) -> Unit){ fun SearchInputField(){
var text = remember { mutableStateOf("") } var text = remember { mutableStateOf("") }
OutlinedTextField( OutlinedTextField(
value = text.value, value = text.value,
onValueChange = { onValueChange = {
text.value = it text.value = it
onTextChanged(it)
}, },
leadingIcon = { leadingIcon = {
Icon( Icon(
@ -104,8 +92,7 @@ fun SearchInputField(onTextChanged: (String) -> Unit){
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(top = 16.dp, start = 16.dp, bottom = 8.dp, end = 16.dp), .padding(top = 16.dp, start = 16.dp, bottom = 8.dp, end = 16.dp),
shape = RoundedCornerShape(10.dp), shape = RoundedCornerShape(10.dp)
singleLine = true
) )
} }
@ -115,7 +102,7 @@ fun IconButton(iconLeft: ImageVector, label: String, backgroundColor: Color, tex
onClick = onClickAction, onClick = onClickAction,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.requiredHeight(buttonHeightStandard) .requiredHeight(64.dp)
.padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp), .padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = backgroundColor containerColor = backgroundColor
@ -147,7 +134,7 @@ fun ActiveButton(label: String, backgroundColor: Color, textColor: Color, onClic
onClick = onClickAction, onClick = onClickAction,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.requiredHeight(buttonHeightStandard) .requiredHeight(64.dp)
.padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp), .padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = backgroundColor containerColor = backgroundColor
@ -168,7 +155,7 @@ fun ActiveButton(label: String, backgroundColor: Color, textColor: Color, onClic
fun PlaceholderTextFieldPreview() { fun PlaceholderTextFieldPreview() {
MobileAppTheme { MobileAppTheme {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
PlaceholderInputField("Email", null,true, { }) PlaceholderInputField("Email")
} }
} }
} }

@ -14,92 +14,60 @@ import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.items 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.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
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.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
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.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.database.MobileAppDataBase import com.example.mobileapp.entities.Mail
import com.example.mobileapp.database.entities.Mail import com.example.mobileapp.entities.MailSingleton
import com.example.mobileapp.database.entities.Story import com.example.mobileapp.entities.Story
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider import com.example.mobileapp.entities.StorySingleton
import com.example.mobileapp.database.viewmodels.StoryViewModel
import com.example.mobileapp.database.viewmodels.UserViewModel
import com.example.mobileapp.ui.theme.BackgroundItem2 import com.example.mobileapp.ui.theme.BackgroundItem2
import com.example.mobileapp.ui.theme.ButtonColor1 import com.example.mobileapp.ui.theme.ButtonColor1
import com.example.mobileapp.ui.theme.ButtonColor2 import com.example.mobileapp.ui.theme.ButtonColor2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.Date
val dateFormat = SimpleDateFormat("dd.MM.yyyy")
@Composable @Composable
fun <T : Any> DataListScroll(navController: NavHostController, dataList: List<T>){ fun DataListScroll(navController: NavHostController){
val storySingleton = StorySingleton()
val isFirstTime = remember { mutableStateOf(true) }
LazyColumn( LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
){ ){
item { item {
when { addNewListItem(navController, "editstory")
dataList.isListOf<Story>() -> addNewListItem(navController, "editstory")
dataList.isListOf<Mail>() -> addNewListItem(navController, "editmail")
}
} }
items(dataList){ item -> items(storySingleton.getStoryList()){ item ->
when(item){ DataListItem(item = item, navController = navController)
is Story -> StoryListItem(item = item, navController = navController)
is Mail -> MailListItem(item = item, navController = navController)
}
} }
} }
} }
inline fun <reified T> List<*>.isListOf(): Boolean {
return isNotEmpty() && all { it is T }
}
@Composable @Composable
fun StoryListItem(item: Story, navController: NavHostController, fun DataListItem(item: Story, navController: NavHostController){
isReadOnly: Boolean? = false,
storyViewModel: StoryViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val isExpanded = remember { val isExpanded = remember {
mutableStateOf(false) mutableStateOf(false)
} }
val showDialog = remember {
mutableStateOf(false)
}
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -121,7 +89,7 @@ fun StoryListItem(item: Story, navController: NavHostController,
Row( Row(
verticalAlignment = Alignment.Top verticalAlignment = Alignment.Top
){ ){
Image(bitmap = item.cover.asImageBitmap(), Image(painter = painterResource(id = item.cover),
contentDescription = item.description, contentDescription = item.description,
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier
@ -131,7 +99,7 @@ fun StoryListItem(item: Story, navController: NavHostController,
modifier = Modifier.padding(8.dp) modifier = Modifier.padding(8.dp)
){ ){
Text( Text(
text = "${item.title} | ${dateFormat.format(Date(item.postdate!!))}", text = item.title,
fontSize = 20.sp, fontSize = 20.sp,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
@ -142,38 +110,16 @@ fun StoryListItem(item: Story, navController: NavHostController,
visible = isExpanded.value, visible = isExpanded.value,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
if (isReadOnly!!){ Row(
DataListItemButton(label = "Подробнее", backgroundColor = ButtonColor2, modifier = Modifier.fillMaxWidth(),
textColor = Color.White, onClickAction = { horizontalArrangement = Arrangement.End
navController.navigate("viewstory/${item.id}") ){
}) DataListItemButton("Изменить", ButtonColor2, Color.White, onClickAction = { navController.navigate("editstory") })
} DataListItemButton("Удалить", Color.Red, Color.White, onClickAction = { })
else{
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
){
DataListItemButton("Изменить", ButtonColor2, Color.White, onClickAction = {
navController.navigate("editstory/${item.id}")
})
DataListItemButton("Удалить", Color.Red, Color.White, onClickAction = {
showDialog.value = !showDialog.value
})
}
} }
} }
} }
} }
if(showDialog.value) {
DialogWindow(label = "Подтверждение",
message = "Вы уверены что хотите удалить запись?", onConfirmAction = {
storyViewModel.deleteStory(item)
showDialog.value = !showDialog.value
}, onDismissAction = {
showDialog.value = !showDialog.value
})
}
} }
@Composable @Composable
@ -195,24 +141,29 @@ fun DataListItemButton(label: String, backgroundColor: Color, textColor: Color,
} }
@Composable @Composable
fun MailListItem(item: Mail, navController: NavHostController, fun MailListScroll(navController: NavHostController){
userViewModel: UserViewModel = viewModel( val mailSingleton = MailSingleton()
factory = MobileAppViewModelProvider.Factory
)) { LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
){
item {
addNewListItem(navController, "editmail")
}
items(mailSingleton.getMailList()){ item ->
MailListItem(item = item)
}
}
}
@Composable
fun MailListItem(item: Mail){
val isExpanded = remember { val isExpanded = remember {
mutableStateOf(false) mutableStateOf(false)
} }
val userName = remember { mutableStateOf("") }
LaunchedEffect(Unit){
userViewModel.getUser(item.userId).collect {
if (it != null) {
userName.value = it.email
}
}
}
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -244,7 +195,7 @@ fun MailListItem(item: Mail, navController: NavHostController,
modifier = Modifier.padding(8.dp) modifier = Modifier.padding(8.dp)
){ ){
Text( Text(
text = "${userName.value} | ${dateFormat.format(Date(item.postdate!!))}", text = item.username,
fontSize = 20.sp, fontSize = 20.sp,
fontWeight = FontWeight.Bold) fontWeight = FontWeight.Bold)
Text(text = item.message) Text(text = item.message)
@ -254,10 +205,22 @@ fun MailListItem(item: Mail, navController: NavHostController,
visible = isExpanded.value, visible = isExpanded.value,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
DataListItemButton(label = "Подробнее", backgroundColor = ButtonColor2, Button(
textColor = Color.White, onClickAction = { onClick = { /* Действие при нажатии кнопки */ },
navController.navigate("viewmail/${item.id}") modifier = Modifier
}) .requiredHeight(64.dp)
.fillMaxWidth(),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
containerColor = ButtonColor2
)
) {
Text(
text = "Подробнее",
color = Color.White,
fontSize = 18.sp,
)
}
} }
} }
} }
@ -302,41 +265,3 @@ fun addNewListItem(navController: NavHostController, destination: String){
} }
} }
} }
@Composable
fun DialogWindow(label: String, message: String, onConfirmAction: () -> Unit, onDismissAction: () -> Unit){
AlertDialog(onDismissRequest = onDismissAction,
title = {
Text(text = label,
fontSize = 20.sp,
fontWeight = FontWeight.Bold)
},
text = {
Text(text = message)
},
confirmButton = {
Button(
onClick = onConfirmAction,
colors = ButtonDefaults.buttonColors(
containerColor = ButtonColor2
),
shape = RoundedCornerShape(5.dp)
) {
Text(text = "Подтвердить",
color = Color.White)
}
},
dismissButton = {
Button(
onClick = onDismissAction,
colors = ButtonDefaults.buttonColors(
containerColor = ButtonColor1
),
shape = RoundedCornerShape(5.dp)
) {
Text(text = "Отмена",
color = Color.Black)
}
}
)
}

@ -1,11 +0,0 @@
package com.example.mobileapp.components
import androidx.annotation.DrawableRes
class NavBarItem(
val route: String,
val label: String,
@DrawableRes
val icon: Int
) {
}

@ -1,11 +1,9 @@
package com.example.mobileapp.components package com.example.mobileapp.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.requiredHeight
@ -14,21 +12,16 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Alignment
import androidx.compose.runtime.saveable.rememberSaveable
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.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
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.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
@ -37,174 +30,40 @@ 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.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.screens.Authorization
import com.example.mobileapp.screens.EditMailScreen
import com.example.mobileapp.screens.EditStoryScreen
import com.example.mobileapp.screens.EditUserScreen
import com.example.mobileapp.screens.ListMailScreen
import com.example.mobileapp.screens.ListStoryScreen
import com.example.mobileapp.screens.MailViewScreen
import com.example.mobileapp.screens.MainScreen
import com.example.mobileapp.screens.Registration
import com.example.mobileapp.screens.SettingsScreen
import com.example.mobileapp.screens.StoryViewScreen
val navBarItems = listOf(
NavBarItem(route = "main", label = "Главная", icon = R.drawable.home),
NavBarItem(route = "story", label = "Создание", icon = R.drawable.edit),
NavBarItem(route = "mail", label = "Уведомления", icon = R.drawable.mail),
NavBarItem(route = "settings", label = "Настройки", icon = R.drawable.settings),
)
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun NavBar(navController: NavHostController) { fun NavBar(navController: NavHostController, itemColorFilter: Color) {
val topBarState = rememberSaveable { (mutableStateOf(false)) } Row(
val bottomBarState = rememberSaveable { (mutableStateOf(false)) } modifier = Modifier
.fillMaxWidth(),
Scaffold( horizontalArrangement = Arrangement.SpaceEvenly,
topBar = { verticalAlignment = Alignment.CenterVertically
AnimatedVisibility( ) {
visible = topBarState.value, NavItem(navController = navController, imageId = R.drawable.home,
enter = slideInVertically(initialOffsetY = { it }), description = "homeButton", destination = "main", itemColorFilter = itemColorFilter)
exit = slideOutVertically(targetOffsetY = { it }), NavItem(navController = navController, imageId = R.drawable.edit,
content = { description = "editButton", destination = "listdata", itemColorFilter = itemColorFilter)
TopAppBar( NavItem(navController = navController, imageId = R.drawable.mail,
title = { description = "mailButton", destination = "mail", itemColorFilter = itemColorFilter)
Text( NavItem(navController = navController, imageId = R.drawable.settings,
text = "Storyteller!", description = "settingsButton", destination = "settings", itemColorFilter = itemColorFilter)
textAlign = TextAlign.Center,
fontFamily = FontFamily(
Font(
R.font.irishgrover_regular, FontWeight.Bold
)
)
)
}
)
}
)
},
bottomBar = {
AnimatedVisibility(
visible = bottomBarState.value,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
content = {
NavigationBar {
navBarItems.forEach{item ->
NavigationBarItem(
icon = {
Image(
painter = painterResource(item.icon),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.padding(bottom = 6.dp)
)
},
label = {
Text(
text = item.label
)
},
onClick = {
navController.navigate(item.route)
},
selected = false,
modifier = Modifier.fillMaxSize()
)
}
}
}
)
},
modifier = Modifier.background(Color.White)
) {innerPaddings ->
NavHost(
navController = navController,
startDestination = "authorization",
modifier = Modifier.padding(innerPaddings)
) {
composable("authorization"){
topBarState.value = true
bottomBarState.value = false
Authorization(navController = navController)
}
composable("registration"){
topBarState.value = true
bottomBarState.value = false
Registration(navController = navController)
}
composable("main"){
topBarState.value = false
bottomBarState.value = true
MainScreen(navController = navController)
}
composable("story"){
topBarState.value = false
bottomBarState.value = true
ListStoryScreen(navController = navController)
}
composable("mail"){
topBarState.value = false
bottomBarState.value = true
ListMailScreen(navController = navController)
}
composable("settings"){
topBarState.value = true
bottomBarState.value = true
SettingsScreen(navController = navController)
}
composable("editstory"){ // Без аргумента
topBarState.value = false
bottomBarState.value = false
EditStoryScreen(navController = navController)
}
composable(
"editstory/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) //С аргументом
) { backStackEntry ->
backStackEntry.arguments?.let {
topBarState.value = false
bottomBarState.value = false
EditStoryScreen(navController = navController, storyId = it.getInt("id"))
}
}
composable("editmail"){ // Без аргумента
topBarState.value = false
bottomBarState.value = false
EditMailScreen(navController = navController)
}
composable("edituser"){
topBarState.value = false
bottomBarState.value = false
EditUserScreen(navController = navController)
}
composable(
"viewstory/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) //С аргументом
) { backStackEntry ->
backStackEntry.arguments?.let {
topBarState.value = false
bottomBarState.value = false
StoryViewScreen(navController = navController, storyId = it.getInt("id"))
}
}
composable(
"viewmail/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) //С аргументом
) { backStackEntry ->
backStackEntry.arguments?.let {
topBarState.value = false
bottomBarState.value = false
MailViewScreen(navController = navController, mailId = it.getInt("id"))
}
}
}
} }
} }
@Composable
fun NavItem(navController: NavHostController, imageId: Int,
description: String, destination: String, itemColorFilter: Color){
Image(painter = painterResource(id = imageId),
contentDescription = description,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clickable {
navController.navigate(destination)
},
colorFilter = ColorFilter.tint(itemColorFilter))
}
@Composable @Composable
fun NavigationButton(navController: NavHostController, fun NavigationButton(navController: NavHostController,
destination: String, label: String, destination: String, label: String,
@ -215,7 +74,7 @@ fun NavigationButton(navController: NavHostController,
}, },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.requiredHeight(72.dp) .requiredHeight(64.dp)
.padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp), .padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = backgroundColor containerColor = backgroundColor

@ -1,82 +0,0 @@
package com.example.mobileapp.database
import android.content.Context
import android.graphics.BitmapFactory
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.mobileapp.R
import com.example.mobileapp.database.dao.MailDao
import com.example.mobileapp.database.dao.StoryDao
import com.example.mobileapp.database.dao.UserDao
import com.example.mobileapp.database.entities.Converters
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.entities.User
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Database(entities = [User::class, Story::class, Mail::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class MobileAppDataBase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun storyDao(): StoryDao
abstract fun mailDao(): MailDao
companion object{
private const val DB_NAME: String = "my-db"
@Volatile
private var INSTANCE: MobileAppDataBase? = null
suspend fun initialDataBase(appContext: Context){
INSTANCE?.let { database ->
val userDao = database.userDao()
userDao.insert(User(id = 1, login = "Дзюнзи Ито", password = "1234", email = "ito@gmail.com"))
userDao.insert(User(id = 2, login = "Стивен Кинг", password = "4321", email = "king@gmail.com"))
val storyDao = database.storyDao()
storyDao.insert(Story(title = "Переулок", description = "История ужасов от Дзюнзи Ито",
cover = BitmapFactory.decodeResource(appContext.resources, R.drawable.dzun), userId = 1))
storyDao.insert(Story(title = "Чужак", description = "Знаменитая книга стивена кинга",
cover = BitmapFactory.decodeResource(appContext.resources, R.drawable.king), userId = 2))
val mailDao = database.mailDao()
for (i in 0..50){
if (i % 2 == 0){
mailDao.insert(Mail(message = "Выложил новые страницы", userId = 1))
}
else{
mailDao.insert(Mail(message = "Меня отменили в Твиттере", userId = 2))
}
}
/*mailDao.insert(Mail(message = "Выложил новые страницы", userId = 1))
mailDao.insert(Mail(message = "Меня отменили в Твиттере", userId = 2))*/
}
}
fun getInstance(appContext: Context): MobileAppDataBase {
return INSTANCE ?: synchronized(this) {
Room.databaseBuilder(
appContext,
MobileAppDataBase::class.java,
DB_NAME
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
initialDataBase(appContext)
}
}
})
.fallbackToDestructiveMigration()
.build()
.also { INSTANCE = it }
}
}
}
}

@ -1,30 +0,0 @@
package com.example.mobileapp.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story
import kotlinx.coroutines.flow.Flow
@Dao
interface MailDao {
@Query("select * from mails order by id desc")
fun getAll(): PagingSource<Int, Mail>
@Query("select * from mails where mails.id = :id")
fun getById(id: Int): Flow<Mail?>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(mail: Mail)
@Update
suspend fun update(mail: Mail)
@Delete
suspend fun delete(mail: Mail)
}

@ -1,32 +0,0 @@
package com.example.mobileapp.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.example.mobileapp.database.entities.Story
import kotlinx.coroutines.flow.Flow
@Dao
interface StoryDao {
@Query("select * from stories order by id desc")
fun getAll(): PagingSource<Int, Story>
@Query("select * from stories where stories.id = :id")
fun getById(id: Int): Flow<Story?>
@Query("select * from stories where stories.user_id = :userId order by stories.id desc")
fun getByUserId(userId: Int): PagingSource<Int, Story>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(story: Story)
@Update
suspend fun update(story: Story)
@Delete
suspend fun delete(story: Story)
}

@ -1,31 +0,0 @@
package com.example.mobileapp.database.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.example.mobileapp.database.entities.User
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Query("select * from users")
fun getAll(): Flow<List<User>>
@Query("select * from users where users.id = :id")
fun getById(id: Int): Flow<User?>
@Query("select * from users where users.login = :login")
suspend fun getByLogin(login: String): User?
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(user: User)
@Update
suspend fun update(user: User)
@Delete
suspend fun delete(user: User)
}

@ -1,22 +0,0 @@
package com.example.mobileapp.database.entities
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.room.TypeConverter
import java.io.ByteArrayOutputStream
import java.text.SimpleDateFormat
import java.util.Date
class Converters {
@TypeConverter
fun fromBitmap(bitmap: Bitmap) : ByteArray {
val outputStream = ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
return outputStream.toByteArray()
}
@TypeConverter
fun toBitmap(byteArray: ByteArray): Bitmap {
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
}

@ -1,34 +0,0 @@
package com.example.mobileapp.database.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import java.util.Date
@Entity(
tableName = "mails",
foreignKeys = [
ForeignKey(
entity = User::class,
parentColumns = ["id"],
childColumns = ["user_id"],
onDelete = ForeignKey.RESTRICT,
onUpdate = ForeignKey.RESTRICT
)
]
)
data class Mail(
@PrimaryKey(autoGenerate = true)
val id: Int? = null,
@ColumnInfo(name = "message")
val message: String,
@ColumnInfo(name = "postdate")
val postdate: Long? = Date().time,
@ColumnInfo(name="user_id")
val userId: Int
){
override fun hashCode(): Int {
return id ?: -1
}
}

@ -1,40 +0,0 @@
package com.example.mobileapp.database.entities
import android.graphics.Bitmap
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import java.util.Calendar
import java.util.Date
@Entity(
tableName = "stories",
foreignKeys = [
ForeignKey(
entity = User::class,
parentColumns = ["id"],
childColumns = ["user_id"],
onDelete = ForeignKey.RESTRICT,
onUpdate = ForeignKey.RESTRICT
)
]
)
data class Story(
@PrimaryKey(autoGenerate = true)
val id: Int? = null,
@ColumnInfo(name = "title")
val title: String,
@ColumnInfo(name = "description")
val description: String,
@ColumnInfo(name = "cover")
val cover: Bitmap,
@ColumnInfo(name = "postdate")
val postdate: Long? = Date().time,
@ColumnInfo(name="user_id")
val userId: Int
){
override fun hashCode(): Int {
return id ?: -1
}
}

@ -1,24 +0,0 @@
package com.example.mobileapp.database.entities
import android.graphics.Bitmap
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int? = null,
@ColumnInfo(name = "login")
val login: String,
@ColumnInfo(name = "password")
val password: String,
@ColumnInfo(name = "email")
val email: String,
@ColumnInfo(name = "photo")
val photo: Bitmap? = null
){
override fun hashCode(): Int {
return id ?: -1
}
}

@ -1,17 +0,0 @@
package com.example.mobileapp.database.repositories
import androidx.paging.PagingData
import com.example.mobileapp.database.entities.Mail
import kotlinx.coroutines.flow.Flow
interface MailRepository {
fun getAllMails(): Flow<PagingData<Mail>>
fun getMail(id: Int): Flow<Mail?>
suspend fun insertMail(mail: Mail)
suspend fun updateMail(mail: Mail)
suspend fun deleteMail(mail: Mail)
}

@ -1,33 +0,0 @@
package com.example.mobileapp.database.repositories
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.mobileapp.database.dao.MailDao
import com.example.mobileapp.database.entities.Mail
import kotlinx.coroutines.flow.Flow
class OfflineMailRepository(private val mailDao: MailDao): MailRepository {
override fun getAllMails(): Flow<PagingData<Mail>> {
return Pager(
config = PagingConfig(
pageSize = 8,
prefetchDistance = 2,
enablePlaceholders = true,
initialLoadSize = 12,
maxSize = 24
),
pagingSourceFactory = {
mailDao.getAll()
}
).flow
}
override fun getMail(id: Int): Flow<Mail?> = mailDao.getById(id)
override suspend fun insertMail(mail: Mail) = mailDao.insert(mail)
override suspend fun updateMail(mail: Mail) = mailDao.update(mail)
override suspend fun deleteMail(mail: Mail) = mailDao.delete(mail)
}

@ -1,48 +0,0 @@
package com.example.mobileapp.database.repositories
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.mobileapp.database.dao.StoryDao
import com.example.mobileapp.database.entities.Story
import kotlinx.coroutines.flow.Flow
class OfflineStoryRepository(private val storyDao: StoryDao): StoryRepository {
override fun getAllStories(): Flow<PagingData<Story>> {
return Pager(
config = PagingConfig(
pageSize = 5,
prefetchDistance = 1,
enablePlaceholders = true,
initialLoadSize = 10,
maxSize = 15
),
pagingSourceFactory = {
storyDao.getAll()
}
).flow
}
override fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>> {
return Pager(
config = PagingConfig(
pageSize = 5,
prefetchDistance = 1,
enablePlaceholders = true,
initialLoadSize = 10,
maxSize = 15
),
pagingSourceFactory = {
storyDao.getByUserId(userId)
}
).flow
}
override fun getStoryById(id: Int): Flow<Story?> = storyDao.getById(id)
override suspend fun insertStory(story: Story) = storyDao.insert(story)
override suspend fun updateStory(story: Story) = storyDao.update(story)
override suspend fun deleteStory(story: Story) = storyDao.delete(story)
}

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

@ -1,20 +0,0 @@
package com.example.mobileapp.database.repositories
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.mobileapp.database.entities.Story
import kotlinx.coroutines.flow.Flow
interface StoryRepository {
fun getAllStories(): Flow<PagingData<Story>>
fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>>
fun getStoryById(id: Int): Flow<Story?>
suspend fun insertStory(story: Story)
suspend fun updateStory(story: Story)
suspend fun deleteStory(story: Story)
}

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

@ -1,28 +0,0 @@
package com.example.mobileapp.database.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.repositories.MailRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
class MailViewModel(private val mailRepository: MailRepository): ViewModel() {
val getAllMails: Flow<PagingData<Mail>> = mailRepository.getAllMails().cachedIn(viewModelScope)
fun getMail(id: Int): Flow<Mail?> = mailRepository.getMail(id)
fun insertMail(mail: Mail) = viewModelScope.launch {
mailRepository.insertMail(mail)
}
fun updateMail(mail: Mail) = viewModelScope.launch {
mailRepository.updateMail(mail)
}
fun deleteMail(mail: Mail) = viewModelScope.launch {
mailRepository.deleteMail(mail)
}
}

@ -1,24 +0,0 @@
package com.example.mobileapp.database.viewmodels
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.mobileapp.MobileApp
object MobileAppViewModelProvider {
val Factory = viewModelFactory {
initializer {
MailViewModel(app().container.mailRepository)
}
initializer {
StoryViewModel(app().container.storyRepository)
}
initializer {
UserViewModel(app().container.userRepository)
}
}
}
fun CreationExtras.app(): MobileApp =
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as MobileApp)

@ -1,31 +0,0 @@
package com.example.mobileapp.database.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.repositories.StoryRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
class StoryViewModel(private val storyRepository: StoryRepository): ViewModel() {
val getAllStories: Flow<PagingData<Story>> = storyRepository.getAllStories().cachedIn(viewModelScope)
fun getStoryById(id: Int): Flow<Story?> = storyRepository.getStoryById(id)
fun getStoriesByUserId(userId: Int): Flow<PagingData<Story>> = storyRepository.getStoriesByUserId(userId).cachedIn(viewModelScope)
fun insertStory(story: Story) = viewModelScope.launch {
storyRepository.insertStory(story)
}
fun updateStory(story: Story) = viewModelScope.launch {
storyRepository.updateStory(story)
}
fun deleteStory(story: Story) = viewModelScope.launch {
storyRepository.deleteStory(story)
}
}

@ -1,65 +0,0 @@
package com.example.mobileapp.database.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.mobileapp.GlobalUser
import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.repositories.UserRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
class UserViewModel(private val userRepository: UserRepository): ViewModel() {
val getAllUsers = userRepository.getAllUsers()
fun getUser(id: Int): Flow<User?> = userRepository.getUser(id)
fun updateUser(user: User) = viewModelScope.launch {
if (user.login.isEmpty()){
return@launch
}
if (user.email.isEmpty() || !isValidEmail(user.email)){
return@launch
}
if (user.password.isEmpty()){
return@launch
}
userRepository.updateUser(user)
GlobalUser.getInstance().setUser(user)
}
fun deleteUser(user: User) = viewModelScope.launch {
userRepository.deleteUser(user)
}
fun regUser(user: User) = viewModelScope.launch {
val globalUser = userRepository.getUserByLogin(user.login)
globalUser?.let {
return@launch
} ?: run {
if(user.password.isEmpty()){
return@launch
}
if(user.email.isEmpty() || !isValidEmail(user.email)){
return@launch
}
userRepository.insertUser(user)
GlobalUser.getInstance().setUser(userRepository.getUserByLogin(user.login))
}
}
fun authUser(user: User) = viewModelScope.launch {
val globalUser = userRepository.getUserByLogin(user.login)
globalUser?.let {
if (user.password.isNotEmpty() && user.password == globalUser.password){
GlobalUser.getInstance().setUser(globalUser)
}
}
}
private fun isValidEmail(email: String): Boolean {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()
}
}

@ -0,0 +1,8 @@
package com.example.mobileapp.entities
data class Mail(
val id: Int,
val userId: Int,
val username: String,
val message: String
)

@ -0,0 +1,15 @@
package com.example.mobileapp.entities
class MailSingleton {
companion object {
val mailList: MutableList<Mail> = mutableListOf()
}
fun addMail(mail: Mail) {
mailList.add(mail)
}
fun getMailList(): List<Mail> {
return mailList.toList()
}
}

@ -0,0 +1,8 @@
package com.example.mobileapp.entities
data class Story(
val id: Int,
val title: String,
val description: String,
val cover: Int
)

@ -0,0 +1,15 @@
package com.example.mobileapp.entities
class StorySingleton {
companion object {
val storyList: MutableList<Story> = mutableListOf()
}
fun addStory(story: Story) {
storyList.add(story)
}
fun getStoryList(): List<Story> {
return storyList.toList()
}
}

@ -0,0 +1,7 @@
package com.example.mobileapp.entities
data class User(
val email: String,
val login: String,
val password: String
)

@ -7,44 +7,22 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
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.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.components.ActiveButton
import com.example.mobileapp.components.NavigationButton import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PasswordInputField import com.example.mobileapp.components.PasswordInputField
import com.example.mobileapp.components.PlaceholderInputField import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.UserViewModel
import com.example.mobileapp.ui.theme.ButtonColor1 import com.example.mobileapp.ui.theme.ButtonColor1
import com.example.mobileapp.ui.theme.ButtonColor2 import com.example.mobileapp.ui.theme.ButtonColor2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable @Composable
fun Authorization(navController: NavHostController, fun Authorization(navController: NavHostController){
userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val users = userViewModel.getAllUsers.collectAsState(emptyList()).value
val login = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -56,28 +34,13 @@ fun Authorization(navController: NavHostController,
contentDescription = "login", contentDescription = "login",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier
.size(448.dp) .size(512.dp)
.padding(8.dp) .padding(8.dp)
.align(Alignment.CenterHorizontally)) .align(Alignment.CenterHorizontally))
PlaceholderInputField(label = "Логин", isSingleLine = true, onTextChanged = {newlogin -> PlaceholderInputField(label = "Логин")
login.value = newlogin PasswordInputField(label = "Пароль")
}) NavigationButton(navController = navController, destination = "main", label = "Вход",
PasswordInputField(label = "Пароль", onPasswordChanged = {newpassword -> backgroundColor = ButtonColor2, textColor = Color.White)
password.value = newpassword
})
ActiveButton(label = "Вход", backgroundColor = ButtonColor2,
textColor = Color.White, onClickAction = {
if (login.value.isNotEmpty() && password.value.isNotEmpty()) {
userViewModel.authUser(
User(
login = login.value,
password = password.value,
email = String()
)
)
navController.navigate("main")
}
})
NavigationButton(navController = navController, destination = "registration", label = "Регистрация", NavigationButton(navController = navController, destination = "registration", label = "Регистрация",
backgroundColor = ButtonColor1, textColor = Color.Black) backgroundColor = ButtonColor1, textColor = Color.Black)
} }

@ -1,97 +1,29 @@
package com.example.mobileapp.screens package com.example.mobileapp.screens
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.mobileapp.GlobalUser
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.components.ActiveButton import com.example.mobileapp.components.ActiveButton
import com.example.mobileapp.components.NavigationButton import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PasswordInputField
import com.example.mobileapp.components.PlaceholderInputField import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.viewmodels.MailViewModel
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.StoryViewModel
import com.example.mobileapp.database.viewmodels.UserViewModel
import com.example.mobileapp.ui.theme.ButtonColor1 import com.example.mobileapp.ui.theme.ButtonColor1
import com.example.mobileapp.ui.theme.ButtonColor2 import com.example.mobileapp.ui.theme.ButtonColor2
@Composable @Composable
fun EditStoryScreen(navController: NavHostController, storyId: Int? = null, fun EditStoryScreen(navController: NavHostController) {
storyViewModel: StoryViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val context = LocalContext.current
val cover = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.editplaceholder)) }
val title = remember { mutableStateOf("") }
val description = remember { mutableStateOf("") }
val imageData = remember { mutableStateOf<Uri?>(null) }
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {uri: Uri? ->
imageData.value = uri
}
imageData.value?.let {
if (Build.VERSION.SDK_INT < 28) {
cover.value = MediaStore.Images
.Media.getBitmap(context.contentResolver, imageData.value)
} else {
val source = ImageDecoder
.createSource(context.contentResolver, imageData.value!!)
cover.value = ImageDecoder.decodeBitmap(source)
}
}
LaunchedEffect(Unit) {
storyId?.let {
storyViewModel.getStoryById(storyId).collect {
if (it != null) {
cover.value = it.cover
}
if (it != null) {
title.value = it.title
}
if (it != null) {
description.value = it.description
}
}
}
}
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -99,59 +31,23 @@ fun EditStoryScreen(navController: NavHostController, storyId: Int? = null,
verticalArrangement = Arrangement.Bottom verticalArrangement = Arrangement.Bottom
) { ) {
Image( Image(
bitmap = cover.value.asImageBitmap(), painter = painterResource(id = R.drawable.editplaceholder),
contentDescription = "editplaceholder", contentDescription = "editplaceholder",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier
.size(384.dp) .size(512.dp)
.padding(8.dp) .padding(8.dp)
.align(Alignment.CenterHorizontally)) .align(Alignment.CenterHorizontally))
ActiveButton(label = "Выбрать обложку", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { PlaceholderInputField(label = "Название")
launcher.launch("image/*") ActiveButton(label = "Выбрать обложку", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {})
}) PlaceholderInputField(label = "Описание")
PlaceholderInputField(label = "Название", isSingleLine = true, NavigationButton(navController = navController, destination = "listdata", label = "Назад",
startValue = title.value, onTextChanged = { newName ->
title.value = newName
})
PlaceholderInputField(label = "Описание", isSingleLine = true,
startValue = description.value, onTextChanged = { newDescription ->
description.value = newDescription
})
ActiveButton(label = "Сохранить", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {
storyId?.let {
storyViewModel.updateStory(
Story(
id = storyId,
cover = cover.value,
title = title.value,
description = description.value,
userId = GlobalUser.getInstance().getUser()?.id!!
)
)
} ?: run {
storyViewModel.insertStory(
Story(
cover = cover.value,
title = title.value,
description = description.value,
userId = GlobalUser.getInstance().getUser()?.id!!
)
)
}
navController.navigate("story")
})
NavigationButton(navController = navController, destination = "story", label = "Назад",
backgroundColor = ButtonColor2, textColor = Color.White) backgroundColor = ButtonColor2, textColor = Color.White)
} }
} }
@Composable @Composable
fun EditMailScreen(navController: NavHostController, fun EditMailScreen(navController: NavHostController) {
mailViewModel: MailViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val message = remember { mutableStateOf("") }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -166,112 +62,9 @@ fun EditMailScreen(navController: NavHostController,
.size(512.dp) .size(512.dp)
.padding(8.dp) .padding(8.dp)
.align(Alignment.CenterHorizontally)) .align(Alignment.CenterHorizontally))
PlaceholderInputField(label = "Текс поста", isSingleLine = false, onTextChanged = { newmessage -> PlaceholderInputField(label = "Заголовок")
message.value = newmessage PlaceholderInputField(label = "Текс поста")
})
ActiveButton(label = "Сохранить", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {
mailViewModel.insertMail(
Mail(
message = message.value,
userId = GlobalUser.getInstance().getUser()?.id!!
)
)
navController.navigate("mail")
})
NavigationButton(navController = navController, destination = "mail", label = "Назад", NavigationButton(navController = navController, destination = "mail", label = "Назад",
backgroundColor = ButtonColor2, textColor = Color.White) backgroundColor = ButtonColor2, textColor = Color.White)
} }
} }
@Composable
fun EditUserScreen(navController: NavHostController,
userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val context = LocalContext.current
var userId = remember { mutableStateOf(0) }
val photo = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.photoplaceholder)) }
val login = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") }
val email = remember { mutableStateOf("") }
val imageData = remember { mutableStateOf<Uri?>(null) }
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {uri: Uri? ->
imageData.value = uri
}
imageData.value?.let {
if (Build.VERSION.SDK_INT < 28) {
photo.value = MediaStore.Images
.Media.getBitmap(context.contentResolver, imageData.value)
} else {
val source = ImageDecoder
.createSource(context.contentResolver, imageData.value!!)
photo.value = ImageDecoder.decodeBitmap(source)
}
}
LaunchedEffect(Unit) {
GlobalUser.getInstance().getUser()?.let { user ->
if (user!!.photo != null)
photo.value = user!!.photo!!
userId.value = user!!.id!!
login.value = user!!.login
password.value = user!!.password
email.value = user!!.email
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 8.dp),
verticalArrangement = Arrangement.Bottom
) {
Image(
bitmap = photo.value.asImageBitmap(),
contentDescription = "editplaceholder",
contentScale = ContentScale.Crop,
modifier = Modifier
.padding(8.dp)
.clip(CircleShape)
.size(384.dp)
.border(
width = 2.dp,
color = MaterialTheme.colorScheme.onPrimary,
)
.align(Alignment.CenterHorizontally))
ActiveButton(label = "Выбрать фото", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {
launcher.launch("image/*")
})
PlaceholderInputField(label = "Никнейм", isSingleLine = true,
startValue = login.value, onTextChanged = { newLogin ->
login.value = newLogin
})
PlaceholderInputField(label = "Пароль", isSingleLine = true,
startValue = password.value, onTextChanged = { newPassword ->
password.value = newPassword
})
PlaceholderInputField(label = "Почта", isSingleLine = true,
startValue = email.value, onTextChanged = { newEmail ->
email.value = newEmail
})
ActiveButton(label = "Сохранить", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {
userViewModel.updateUser(
User(
id = userId.value,
login = login.value,
password = password.value,
email = email.value,
photo = photo.value
)
)
navController.navigate("settings")
})
ActiveButton(label = "Назад", backgroundColor = ButtonColor2, textColor = Color.White,
onClickAction = {
navController.navigate("settings")
})
}
}

@ -0,0 +1,40 @@
package com.example.mobileapp.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import com.example.mobileapp.components.DataListScroll
import com.example.mobileapp.components.NavBar
import com.example.mobileapp.ui.theme.BackgroundItem1
import com.example.mobileapp.ui.theme.BackgroundItem2
@Composable
fun ListDataScreen(navController: NavHostController){
Column(
modifier = Modifier
.fillMaxSize()
.background(BackgroundItem1)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.9f)
){
DataListScroll(navController)
}
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
NavBar(navController = navController, itemColorFilter = BackgroundItem2)
}
}
}

@ -1,63 +1,40 @@
package com.example.mobileapp.screens package com.example.mobileapp.screens
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems import com.example.mobileapp.components.MailListScroll
import androidx.paging.compose.itemKey import com.example.mobileapp.components.NavBar
import com.example.mobileapp.components.DataListScroll
import com.example.mobileapp.components.MailListItem
import com.example.mobileapp.components.StoryListItem
import com.example.mobileapp.components.addNewListItem
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.viewmodels.MailViewModel
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.ui.theme.BackgroundItem1 import com.example.mobileapp.ui.theme.BackgroundItem1
import kotlinx.coroutines.Dispatchers import com.example.mobileapp.ui.theme.BackgroundItem2
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.withContext
@Composable @Composable
fun ListMailScreen(navController: NavHostController, fun ListMailScreen(navController: NavHostController){
mailViewModel: MailViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val mails = mailViewModel.getAllMails.collectAsLazyPagingItems()
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(BackgroundItem1) .background(BackgroundItem1)
) { ) {
LazyVerticalGrid( Box(
columns = GridCells.Fixed(1) modifier = Modifier
) { .fillMaxWidth()
item { .fillMaxHeight(0.9f)
addNewListItem(navController, "editmail") ){
} MailListScroll(navController)
items( }
count = mails.itemCount, Column(
key = mails.itemKey { item -> item.id!! } modifier = Modifier
) { index: Int -> .fillMaxSize(),
val mail: Mail? = mails[index] verticalArrangement = Arrangement.Center
if (mail != null) { ) {
MailListItem(item = mail, navController = navController) NavBar(navController = navController, itemColorFilter = BackgroundItem2)
}
}
} }
//DataListScroll(navController, mails)
} }
} }

@ -1,55 +0,0 @@
package com.example.mobileapp.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.GlobalUser
import com.example.mobileapp.components.DataListScroll
import com.example.mobileapp.components.StoryListItem
import com.example.mobileapp.components.addNewListItem
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.StoryViewModel
import com.example.mobileapp.ui.theme.BackgroundItem1
@Composable
fun ListStoryScreen(navController: NavHostController,
storyViewModel: StoryViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val stories = storyViewModel.getStoriesByUserId(GlobalUser.getInstance().getUser()?.id!!).collectAsLazyPagingItems()
//val stories = storyViewModel.getAllStories.collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(BackgroundItem1)
) {
LazyVerticalGrid(
columns = GridCells.Fixed(1)
) {
item {
addNewListItem(navController, "editstory")
}
items(
count = stories.itemCount,
key = stories.itemKey { item -> item.id!! }
) { index: Int ->
val story: Story? = stories[index]
if (story != null) {
StoryListItem(item = story, navController = navController)
}
}
}
//DataListScroll(navController, stories)
}
}

@ -8,12 +8,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
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
@ -22,69 +18,45 @@ import androidx.compose.ui.res.painterResource
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.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.components.NavBar import com.example.mobileapp.components.NavBar
import com.example.mobileapp.components.SearchInputField import com.example.mobileapp.components.SearchInputField
import com.example.mobileapp.components.StoryListItem
import com.example.mobileapp.components.addNewListItem
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.StoryViewModel
@Composable @Composable
fun MainScreen(navController: NavHostController, fun MainScreen(navController: NavHostController) {
storyViewModel: StoryViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val stories = storyViewModel.getAllStories.collectAsLazyPagingItems()
val search = remember { mutableStateOf("") }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
) { ) {
SearchInputField(onTextChanged = {newsearch -> SearchInputField()
search.value = newsearch Column(
}) modifier = Modifier
if (stories.itemCount > 0){ .fillMaxWidth()
LazyVerticalGrid( .fillMaxHeight(0.89f),
columns = GridCells.Fixed(1) verticalArrangement = Arrangement.Center,
) { horizontalAlignment = Alignment.CenterHorizontally
items( ) {
count = stories.itemCount, Image(
key = stories.itemKey { item -> item.id!! } painter = painterResource(id = R.drawable.main),
) { index: Int -> contentDescription = "main",
val story: Story? = stories[index] contentScale = ContentScale.Crop,
if (story != null && (search.value.isEmpty() || story.title.contains(search.value, ignoreCase = true))) { modifier = Modifier
StoryListItem(item = story, navController = navController, isReadOnly = true) .size(512.dp)
} .padding(8.dp)
} )
} Text(
text = "Здесь будут посты авторов",
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
} }
else { Column(
Column( modifier = Modifier
verticalArrangement = Arrangement.Center, .fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally verticalArrangement = Arrangement.Center
) { ) {
Image( NavBar(navController = navController, itemColorFilter = Color.Black)
painter = painterResource(id = R.drawable.main),
contentDescription = "main",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(512.dp)
.padding(8.dp)
)
Text(
text = "Здесь будут посты авторов",
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
} }
} }
} }

@ -7,37 +7,22 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
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.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.components.ActiveButton
import com.example.mobileapp.components.NavigationButton import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PasswordInputField import com.example.mobileapp.components.PasswordInputField
import com.example.mobileapp.components.PlaceholderInputField import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.UserViewModel
import com.example.mobileapp.ui.theme.ButtonColor1 import com.example.mobileapp.ui.theme.ButtonColor1
import com.example.mobileapp.ui.theme.ButtonColor2 import com.example.mobileapp.ui.theme.ButtonColor2
@Composable @Composable
fun Registration(navController: NavHostController, fun Registration(navController: NavHostController){
userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val login = remember { mutableStateOf("") }
val email = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") }
val repeatepassword = remember { mutableStateOf("") }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -49,34 +34,15 @@ fun Registration(navController: NavHostController,
contentDescription = "registration", contentDescription = "registration",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier
.size(320.dp) .size(384.dp)
.padding(8.dp) .padding(8.dp)
.align(Alignment.CenterHorizontally)) .align(Alignment.CenterHorizontally))
PlaceholderInputField(label = "Логин", isSingleLine = true, onTextChanged = {newlogin -> PlaceholderInputField(label = "Логин")
login.value = newlogin PlaceholderInputField(label = "Email")
}) PasswordInputField(label = "Пароль")
PlaceholderInputField(label = "Email", isSingleLine = true, onTextChanged = {newemail -> PasswordInputField(label = "Пароль ещё раз")
email.value = newemail NavigationButton(navController = navController, destination = "main",
}) label = "Зарегистрироваться", backgroundColor = ButtonColor2, textColor = Color.White)
PasswordInputField(label = "Пароль", onPasswordChanged = {newpassword ->
password.value = newpassword
})
PasswordInputField(label = "Пароль ещё раз", onPasswordChanged = {newpassword ->
repeatepassword.value = newpassword
})
ActiveButton(label = "Зарегистрироваться", backgroundColor = ButtonColor2,
textColor = Color.White, onClickAction = {
if (password.value == repeatepassword.value){
userViewModel.regUser(
User(
login = login.value,
password = password.value,
email = email.value
)
)
}
navController.navigate("main")
})
NavigationButton(navController = navController, destination = "authorization", NavigationButton(navController = navController, destination = "authorization",
label = "Назад", backgroundColor = ButtonColor1, textColor = Color.Black) label = "Назад", backgroundColor = ButtonColor1, textColor = Color.Black)
} }

@ -27,7 +27,6 @@ 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.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.mobileapp.GlobalUser
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.components.IconButton import com.example.mobileapp.components.IconButton
import com.example.mobileapp.components.NavBar import com.example.mobileapp.components.NavBar
@ -38,37 +37,39 @@ import com.example.mobileapp.ui.theme.ButtonColor2
fun SettingsScreen(navController: NavHostController){ fun SettingsScreen(navController: NavHostController){
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize(), .fillMaxSize()
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Image( Column(
painter = painterResource(id = R.drawable.settingsplaceholder),
contentDescription = "settings",
contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier
.size(320.dp) .fillMaxWidth()
.padding(8.dp)) .fillMaxHeight(0.9f),
IconButton(iconLeft = Icons.Default.AccountCircle, label = "Учётная запись", verticalArrangement = Arrangement.Top,
backgroundColor = ButtonColor2, textColor = Color.White, onClickAction = { horizontalAlignment = Alignment.CenterHorizontally
navController.navigate("edituser") ){
}) Image(
IconButton(iconLeft = Icons.Default.Face, label = "Внешний вид", painter = painterResource(id = R.drawable.settingsplaceholder),
backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { contentDescription = "settings",
contentScale = ContentScale.Crop,
}) modifier = Modifier
IconButton(iconLeft = Icons.Default.Share, label = "Контакты", .size(384.dp)
backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { .padding(8.dp))
IconButton(iconLeft = Icons.Default.AccountCircle, label = "Учётная запись",
}) backgroundColor = ButtonColor2, textColor = Color.White, onClickAction = { })
IconButton(iconLeft = Icons.Default.Info, label = "О приложении", IconButton(iconLeft = Icons.Default.Face, label = "Внешний вид",
backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { })
IconButton(iconLeft = Icons.Default.Share, label = "Контакты",
}) backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { })
IconButton(iconLeft = Icons.Default.ExitToApp, label = "Выйти", IconButton(iconLeft = Icons.Default.Info, label = "О приложении",
backgroundColor = Color.Red, textColor = Color.White, onClickAction = { backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { })
GlobalUser.getInstance().setUser(null) IconButton(iconLeft = Icons.Default.ExitToApp, label = "Выйти",
navController.navigate("authorization") backgroundColor = Color.Red, textColor = Color.White, onClickAction = { })
}) }
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
NavBar(navController = navController, itemColorFilter = Color.Black)
}
} }
} }

@ -1,168 +0,0 @@
package com.example.mobileapp.screens
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.mobileapp.R
import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.database.viewmodels.MailViewModel
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.StoryViewModel
import com.example.mobileapp.database.viewmodels.UserViewModel
import com.example.mobileapp.ui.theme.ButtonColor2
import java.text.SimpleDateFormat
import java.util.Date
val dateFormat = SimpleDateFormat("dd.MM.yyyy")
@Composable
fun StoryViewScreen(navController: NavHostController, storyId: Int,
storyViewModel: StoryViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val context = LocalContext.current
val cover = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.editplaceholder)) }
val title = remember { mutableStateOf("") }
val description = remember { mutableStateOf("") }
val postdate = remember { mutableStateOf<Long>(0) }
val story by storyViewModel.getStoryById(storyId).collectAsState(null)
story?.let {
cover.value = it.cover
title.value = it.title
description.value = it.description
postdate.value = it.postdate!!
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 8.dp),
verticalArrangement = Arrangement.Center
) {
Image(
bitmap = cover.value.asImageBitmap(),
contentDescription = "cover",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(512.dp)
.padding(8.dp)
.align(Alignment.CenterHorizontally))
Text(text = "Название: ${title.value}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(8.dp))
Text(text = "Дата публикации: ${dateFormat.format(Date(postdate.value))}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(8.dp))
Text(text = "Описание: ${description.value}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(8.dp))
NavigationButton(navController = navController, destination = "main", label = "Назад",
backgroundColor = ButtonColor2, textColor = Color.White)
}
}
@Composable
fun MailViewScreen(navController: NavHostController, mailId: Int,
mailViewModel: MailViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
),
userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory
)) {
val context = LocalContext.current
val userName = remember { mutableStateOf("") }
val photo = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.photoplaceholder)) }
val message = remember { mutableStateOf("") }
val postdate = remember { mutableStateOf<Long>(0) }
LaunchedEffect(Unit){
mailViewModel.getMail(mailId).collect{
if (it != null) {
message.value = it.message
postdate.value = it.postdate!!
userViewModel.getUser(it.userId).collect {user ->
if (user != null) {
if(user.photo != null) {
photo.value = user.photo
}
userName.value = user.email
}
}
}
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 8.dp),
verticalArrangement = Arrangement.Center
) {
Image(
bitmap = photo.value.asImageBitmap(),
contentDescription = "editplaceholder",
contentScale = ContentScale.Crop,
modifier = Modifier
.padding(8.dp)
.clip(CircleShape)
.size(384.dp)
.border(
width = 2.dp,
color = MaterialTheme.colorScheme.onPrimary,
)
.align(Alignment.CenterHorizontally))
Text(text = "Автор: ${userName.value}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(8.dp))
Text(text = "Дата публикации: ${dateFormat.format(Date(postdate.value))}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(8.dp))
Text(text = "Текст: ${message.value}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(8.dp))
NavigationButton(navController = navController, destination = "mail", label = "Назад",
backgroundColor = ButtonColor2, textColor = Color.White)
}
}

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
</domain-config>
</network-security-config>

@ -2,5 +2,4 @@
plugins { plugins {
id("com.android.application") version "8.1.1" apply false id("com.android.application") version "8.1.1" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false id("org.jetbrains.kotlin.android") version "1.8.10" apply false
id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false
} }