Compare commits

...

10 Commits

Author SHA1 Message Date
maxnes3
e247aaddb5 Залил 3 лабу 2023-12-23 11:28:02 +04:00
maxnes3
69175e82f0 Подготовка к 4 лабе(дополнил) 2023-11-25 21:44:25 +04:00
maxnes3
7076d707ea Подготовка к 4 лабе 2023-11-25 21:43:54 +04:00
maxnes3
da844b15f7 CRUD работает 2023-11-25 03:02:32 +04:00
maxnes3
f4fa24f50a БД работает 2023-11-24 21:39:43 +04:00
maxnes3
1d1a0e9be7 ВСЁ на ГИТ 2023-11-24 20:22:29 +04:00
maxnes3
1e3fcaa50f Не работает 2023-11-24 19:45:20 +04:00
maxnes3
31b936fe0e ещё немного осталось 2023-11-16 04:17:27 +04:00
maxnes3
1a3a0d4cd7 Я почти гений 2023-11-16 03:06:38 +04:00
maxnes3
6fc39a2396 Я хорош 2023-11-16 02:01:29 +04:00
24 changed files with 631 additions and 288 deletions

View File

@ -0,0 +1,41 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
</profile>
</component>

View File

@ -3,28 +3,13 @@ package com.example.mobileapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
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 com.example.mobileapp.entities.Mail
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.components.NavBar
import com.example.mobileapp.database.entities.User
import com.example.mobileapp.ui.theme.MobileAppTheme
class MainActivity : ComponentActivity() {
@ -38,57 +23,31 @@ class MainActivity : ComponentActivity() {
color = MaterialTheme.colorScheme.background
) {
val navController = rememberNavController()
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)
NavBar(navController = navController)
}
}
}
}
}
@Composable
fun AppNavigation(navController: NavHostController){
NavHost(
navController = navController, startDestination = "authorization"
) {
composable("authorization"){
Authorization(navController = navController)
}
composable("registration"){
Registration(navController = navController)
}
composable("main"){
MainScreen(navController = navController)
}
composable("listdata"){
ListDataScreen(navController = navController)
}
composable("mail"){
ListMailScreen(navController = navController)
}
composable("settings"){
SettingsScreen(navController = navController)
}
composable("editstory"){
EditStoryScreen(navController = navController)
}
composable("editmail"){
EditMailScreen(navController = navController)
class GlobalUser private constructor() {
private var user: User? = null
fun setUser(user: User?) {
this.user = user
}
fun getUser(): User? {
return user
}
companion object {
private var instance: GlobalUser? = null
fun getInstance(): GlobalUser {
return instance ?: synchronized(this) {
instance ?: GlobalUser().also { instance = it }
}
}
}
}

View File

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

View File

@ -16,57 +16,83 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
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.res.painterResource
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.sp
import androidx.navigation.NavHostController
import com.example.mobileapp.R
import com.example.mobileapp.entities.Mail
import com.example.mobileapp.entities.MailSingleton
import com.example.mobileapp.entities.Story
import com.example.mobileapp.entities.StorySingleton
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.ui.theme.BackgroundItem2
import com.example.mobileapp.ui.theme.ButtonColor1
import com.example.mobileapp.ui.theme.ButtonColor2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.Date
val dateFormat = SimpleDateFormat("dd.MM.yyyy")
@Composable
fun DataListScroll(navController: NavHostController){
val storySingleton = StorySingleton()
fun <T : Any> DataListScroll(navController: NavHostController, dataList: List<T>){
LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
){
item {
addNewListItem(navController, "editstory")
when {
dataList.isListOf<Story>() -> addNewListItem(navController, "editstory")
dataList.isListOf<Mail>() -> addNewListItem(navController, "editmail")
}
}
items(storySingleton.getStoryList()){ item ->
DataListItem(item = item, navController = navController)
items(dataList){ item ->
when(item){
is Story -> StoryListItem(item = item, navController = navController)
is Mail -> MailListItem(item = item)
}
}
}
}
inline fun <reified T> List<*>.isListOf(): Boolean {
return isNotEmpty() && all { it is T }
}
@Composable
fun DataListItem(item: Story, navController: NavHostController){
fun StoryListItem(item: Story, navController: NavHostController){
val context = LocalContext.current
val isExpanded = remember {
mutableStateOf(false)
}
val showDialog = remember {
mutableStateOf(false)
}
val delete = remember {
mutableStateOf(false)
}
Card(
modifier = Modifier
.fillMaxWidth()
@ -88,7 +114,7 @@ fun DataListItem(item: Story, navController: NavHostController){
Row(
verticalAlignment = Alignment.Top
){
Image(painter = painterResource(id = item.cover),
Image(bitmap = item.cover.asImageBitmap(),
contentDescription = item.description,
contentScale = ContentScale.Crop,
modifier = Modifier
@ -98,7 +124,7 @@ fun DataListItem(item: Story, navController: NavHostController){
modifier = Modifier.padding(8.dp)
){
Text(
text = item.title,
text = "${item.title} | ${dateFormat.format(Date(item.postdate!!))}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
@ -113,12 +139,36 @@ fun DataListItem(item: Story, navController: NavHostController){
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
){
DataListItemButton("Изменить", ButtonColor2, Color.White, onClickAction = { navController.navigate("editstory") })
DataListItemButton("Удалить", Color.Red, Color.White, onClickAction = { })
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 = {
delete.value = !delete.value
showDialog.value = !showDialog.value
}, onDismissAction = {
showDialog.value = !showDialog.value
})
}
if(delete.value) {
LaunchedEffect(Unit){
withContext(Dispatchers.IO){
MobileAppDataBase.getInstance(context).storyDao().delete(item)
}
}
delete.value = !delete.value
navController.navigate("story")
}
}
@Composable
@ -139,24 +189,6 @@ fun DataListItemButton(label: String, backgroundColor: Color, textColor: Color,
}
}
@Composable
fun MailListScroll(navController: NavHostController){
val mailSingleton = MailSingleton()
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 {
@ -194,7 +226,7 @@ fun MailListItem(item: Mail){
modifier = Modifier.padding(8.dp)
){
Text(
text = item.username,
text = "item.username | ${dateFormat.format(Date(item.postdate!!))}",
fontSize = 20.sp,
fontWeight = FontWeight.Bold)
Text(text = item.message)
@ -264,3 +296,41 @@ 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)
}
}
)
}

View File

@ -1,9 +1,11 @@
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.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
@ -12,14 +14,15 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
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.text.font.FontWeight
import androidx.compose.ui.unit.dp
@ -30,40 +33,119 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
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.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
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
fun NavBar(navController: NavHostController, itemColorFilter: Color) {
Row(
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
NavItem(navController = navController, imageId = R.drawable.home,
description = "homeButton", destination = "main", itemColorFilter = itemColorFilter)
NavItem(navController = navController, imageId = R.drawable.edit,
description = "editButton", destination = "listdata", itemColorFilter = itemColorFilter)
NavItem(navController = navController, imageId = R.drawable.mail,
description = "mailButton", destination = "mail", itemColorFilter = itemColorFilter)
NavItem(navController = navController, imageId = R.drawable.settings,
description = "settingsButton", destination = "settings", itemColorFilter = itemColorFilter)
fun NavBar(navController: NavHostController) {
val bottomBarState = rememberSaveable { (mutableStateOf(false)) }
Scaffold(
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"){
bottomBarState.value = false
Authorization(navController = navController)
}
composable("registration"){
bottomBarState.value = false
Registration(navController = navController)
}
composable("main"){
bottomBarState.value = true
MainScreen(navController = navController)
}
composable("story"){
bottomBarState.value = true
ListDataScreen(navController = navController)
}
composable("mail"){
bottomBarState.value = true
ListMailScreen(navController = navController)
}
composable("settings"){
bottomBarState.value = true
SettingsScreen(navController = navController)
}
composable("editstory"){ // Без аргумента
bottomBarState.value = false
EditStoryScreen(navController = navController)
}
composable(
"editstory/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) //С аргументом
) { backStackEntry ->
backStackEntry.arguments?.let {
bottomBarState.value = false
EditStoryScreen(navController = navController, storyId = it.getInt("id"))
}
}
composable("editmail"){ // Без аргумента
bottomBarState.value = false
EditMailScreen(navController = navController)
}
composable("edituser"){
bottomBarState.value = false
EditUserScreen(navController = navController)
}
}
}
}
@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
fun NavigationButton(navController: NavHostController,
destination: String, label: String,
@ -74,7 +156,7 @@ fun NavigationButton(navController: NavHostController,
},
modifier = Modifier
.fillMaxWidth()
.requiredHeight(64.dp)
.requiredHeight(72.dp)
.padding(top = 8.dp, start = 16.dp, bottom = 8.dp, end = 16.dp),
colors = ButtonDefaults.buttonColors(
containerColor = backgroundColor

View File

@ -1,11 +1,13 @@
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
@ -25,11 +27,29 @@ abstract class MobileAppDataBase : RoomDatabase() {
abstract fun mailDao(): MailDao
companion object{
private const val DB_NAME: String = "mobileApp.db"
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()
mailDao.insert(Mail(message = "Выложил новые страницы", userId = 1))
mailDao.insert(Mail(message = "Меня отменили в Твиттере", userId = 2))
}
}
fun getInstance(appContext: Context): MobileAppDataBase {
return INSTANCE ?: synchronized(this) {
Room.databaseBuilder(
@ -41,10 +61,11 @@ abstract class MobileAppDataBase : RoomDatabase() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
//populateDatabase()
initialDataBase(appContext)
}
}
})
.fallbackToDestructiveMigration()
.build()
.also { INSTANCE = it }
}

View File

@ -17,6 +17,9 @@ interface StoryDao {
@Query("select * from stories where stories.id = :id")
fun getById(id: Int): Story?
@Query("select * from stories where stories.user_id = :userId")
fun getByUserId(userId: Int): Flow<List<Story>>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(story: Story)

View File

@ -4,6 +4,8 @@ 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

View File

@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import java.util.Date
@Entity(
tableName = "mails",
@ -19,9 +20,11 @@ import androidx.room.PrimaryKey
)
data class Mail(
@PrimaryKey(autoGenerate = true)
var id: Int?,
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
){

View File

@ -5,6 +5,8 @@ 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",
@ -20,13 +22,15 @@ import androidx.room.PrimaryKey
)
data class Story(
@PrimaryKey(autoGenerate = true)
val id: Int?,
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
){

View File

@ -1,5 +1,6 @@
package com.example.mobileapp.database.entities
import android.graphics.Bitmap
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@ -7,13 +8,15 @@ import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
var id: Int?,
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

View File

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

View File

@ -1,15 +0,0 @@
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()
}
}

View File

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

View File

@ -1,15 +0,0 @@
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()
}
}

View File

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

View File

@ -7,10 +7,14 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
@ -18,11 +22,26 @@ import com.example.mobileapp.R
import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PasswordInputField
import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.User
import com.example.mobileapp.ui.theme.ButtonColor1
import com.example.mobileapp.ui.theme.ButtonColor2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun Authorization(navController: NavHostController){
val context = LocalContext.current
val users = remember { mutableStateListOf<User>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
MobileAppDataBase.getInstance(context).userDao().getAll().collect { data ->
users.clear()
users.addAll(data)
}
}
}
Column(
modifier = Modifier
.fillMaxSize()
@ -37,8 +56,8 @@ fun Authorization(navController: NavHostController){
.size(512.dp)
.padding(8.dp)
.align(Alignment.CenterHorizontally))
PlaceholderInputField(label = "Логин")
PasswordInputField(label = "Пароль")
PlaceholderInputField(label = "Логин", isSingleLine = true, onTextChanged = {})
PasswordInputField(label = "Пароль", onPasswordChanged = {})
NavigationButton(navController = navController, destination = "main", label = "Вход",
backgroundColor = ButtonColor2, textColor = Color.White)
NavigationButton(navController = navController, destination = "registration", label = "Регистрация",

View File

@ -1,5 +1,13 @@
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.layout.Arrangement
import androidx.compose.foundation.layout.Column
@ -7,10 +15,16 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
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.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
@ -19,11 +33,81 @@ import com.example.mobileapp.components.ActiveButton
import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PasswordInputField
import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.ui.theme.ButtonColor1
import com.example.mobileapp.ui.theme.ButtonColor2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun EditStoryScreen(navController: NavHostController) {
fun EditStoryScreen(navController: NavHostController, storyId: Int? = null) {
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)
}
}
storyId?.let{
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
val story = MobileAppDataBase.getInstance(context).storyDao().getById(storyId!!)
cover.value = story!!.cover
title.value = story!!.title
description.value = story!!.description
}
}
}
val edit = remember { mutableStateOf(false) }
if (edit.value){
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
storyId?.let {
MobileAppDataBase.getInstance(context).storyDao()
.update(
Story(
id = storyId,
title = title.value,
description = description.value,
cover = cover.value,
userId = 1)
)
} ?: run {
MobileAppDataBase.getInstance(context).storyDao()
.insert(
Story(
title = title.value,
description = description.value,
cover = cover.value,
userId = 1)
)
}
}
}
edit.value = !edit.value
navController.navigate("story")
}
Column(
modifier = Modifier
.fillMaxSize()
@ -31,23 +115,49 @@ fun EditStoryScreen(navController: NavHostController) {
verticalArrangement = Arrangement.Bottom
) {
Image(
painter = painterResource(id = R.drawable.editplaceholder),
bitmap = cover.value.asImageBitmap(),
contentDescription = "editplaceholder",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(512.dp)
.size(384.dp)
.padding(8.dp)
.align(Alignment.CenterHorizontally))
PlaceholderInputField(label = "Название")
ActiveButton(label = "Выбрать обложку", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {})
PlaceholderInputField(label = "Описание")
NavigationButton(navController = navController, destination = "listdata", label = "Назад",
ActiveButton(label = "Выбрать обложку", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {
launcher.launch("image/*")
})
PlaceholderInputField(label = "Название", isSingleLine = true,
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 = {
edit.value = !edit.value
})
NavigationButton(navController = navController, destination = "story", label = "Назад",
backgroundColor = ButtonColor2, textColor = Color.White)
}
}
@Composable
fun EditMailScreen(navController: NavHostController) {
val context = LocalContext.current
val message = remember { mutableStateOf("") }
val create = remember { mutableStateOf(false) }
if(create.value){
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
MobileAppDataBase.getInstance(context).mailDao()
.insert(Mail(message = message.value, userId = 2))
}
}
create.value = !create.value
navController.navigate("mail")
}
Column(
modifier = Modifier
.fillMaxSize()
@ -62,9 +172,76 @@ fun EditMailScreen(navController: NavHostController) {
.size(512.dp)
.padding(8.dp)
.align(Alignment.CenterHorizontally))
PlaceholderInputField(label = "Заголовок")
PlaceholderInputField(label = "Текс поста")
PlaceholderInputField(label = "Текс поста", isSingleLine = false, onTextChanged = { newmessage ->
message.value = newmessage
})
ActiveButton(label = "Сохранить", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {
create.value = !create.value
})
NavigationButton(navController = navController, destination = "mail", label = "Назад",
backgroundColor = ButtonColor2, textColor = Color.White)
}
}
@Composable
fun EditUserScreen(navController: NavHostController){
val context = LocalContext.current
val photo = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.photoplaceholder)) }
val name = 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)
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 8.dp),
verticalArrangement = Arrangement.Bottom
) {
Image(
bitmap = photo.value.asImageBitmap(),
contentDescription = "editplaceholder",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(384.dp)
.padding(8.dp)
.align(Alignment.CenterHorizontally))
ActiveButton(label = "Выбрать фото", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = {
launcher.launch("image/*")
})
PlaceholderInputField(label = "Никнейм", isSingleLine = true,
startValue = name.value, onTextChanged = { newName ->
name.value = newName
})
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 = {
//edit.value = !edit.value
})
NavigationButton(navController = navController, destination = "story", label = "Назад",
backgroundColor = ButtonColor2, textColor = Color.White)
}
}

View File

@ -8,33 +8,41 @@ 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.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavHostController
import com.example.mobileapp.components.DataListScroll
import com.example.mobileapp.components.NavBar
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.ui.theme.BackgroundItem1
import com.example.mobileapp.ui.theme.BackgroundItem2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun ListDataScreen(navController: NavHostController){
val context = LocalContext.current
val stories = remember { mutableStateListOf<Story>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
MobileAppDataBase.getInstance(context).storyDao().getAll().collect { data ->
stories.clear()
stories.addAll(data)
}
}
}
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)
}
DataListScroll(navController, stories)
}
}

View File

@ -1,40 +1,42 @@
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.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavHostController
import com.example.mobileapp.components.MailListScroll
import com.example.mobileapp.components.NavBar
import com.example.mobileapp.components.DataListScroll
import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.ui.theme.BackgroundItem1
import com.example.mobileapp.ui.theme.BackgroundItem2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun ListMailScreen(navController: NavHostController){
val context = LocalContext.current
val mails = remember { mutableStateListOf<Mail>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
MobileAppDataBase.getInstance(context).mailDao().getAll().collect { data ->
mails.clear()
mails.addAll(data)
}
}
}
Column(
modifier = Modifier
.fillMaxSize()
.background(BackgroundItem1)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.9f)
){
MailListScroll(navController)
}
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
NavBar(navController = navController, itemColorFilter = BackgroundItem2)
}
DataListScroll(navController, mails)
}
}

View File

@ -51,12 +51,5 @@ fun MainScreen(navController: NavHostController) {
fontWeight = FontWeight.Bold
)
}
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
NavBar(navController = navController, itemColorFilter = Color.Black)
}
}
}

View File

@ -37,10 +37,10 @@ fun Registration(navController: NavHostController){
.size(384.dp)
.padding(8.dp)
.align(Alignment.CenterHorizontally))
PlaceholderInputField(label = "Логин")
PlaceholderInputField(label = "Email")
PasswordInputField(label = "Пароль")
PasswordInputField(label = "Пароль ещё раз")
PlaceholderInputField(label = "Логин", isSingleLine = true, onTextChanged = {})
PlaceholderInputField(label = "Email", isSingleLine = true, onTextChanged = {})
PasswordInputField(label = "Пароль", onPasswordChanged = {})
PasswordInputField(label = "Пароль ещё раз", onPasswordChanged = {})
NavigationButton(navController = navController, destination = "main",
label = "Зарегистрироваться", backgroundColor = ButtonColor2, textColor = Color.White)
NavigationButton(navController = navController, destination = "authorization",

View File

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

Binary file not shown.