From e5adf214b75c44603ad0f3f42bbb19d0fe4fe927 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 7 Dec 2023 23:52:40 +0400 Subject: [PATCH] Complete lab --- .../java/com/example/testapp/MainActivity.kt | 37 ++ .../example/testapp/designElem/AlertDialog.kt | 44 ++ .../com/example/testapp/designElem/Btn.kt | 70 +++ .../example/testapp/designElem/DealItem.kt | 182 ++++++++ .../example/testapp/designElem/DropDown.kt | 85 ++++ .../example/testapp/designElem/ListItem.kt | 84 ++++ .../com/example/testapp/designElem/NavBar.kt | 108 +++++ .../testapp/designElem/SharedViewModel.kt | 24 + .../testapp/designElem/SliderWithRange.kt | 81 ++++ .../example/testapp/graphs/AuthNavGraph.kt | 29 ++ .../example/testapp/graphs/HomeNavGraph.kt | 44 ++ .../example/testapp/graphs/RootNavGraph.kt | 42 ++ .../testapp/navigate/BottomBarScreen.kt | 31 ++ .../com/example/testapp/room/dao/CoinDao.kt | 21 + .../com/example/testapp/room/dao/DealDao.kt | 24 + .../com/example/testapp/room/dao/UserDao.kt | 29 ++ .../example/testapp/room/dao/WalletItemDao.kt | 23 + .../testapp/room/database/CryptoDealDb.kt | 91 ++++ .../com/example/testapp/room/models/Coin.kt | 17 + .../com/example/testapp/room/models/Deal.kt | 22 + .../com/example/testapp/room/models/User.kt | 29 ++ .../example/testapp/room/models/WalletItem.kt | 18 + .../testapp/screensMobile/AccountPage.kt | 352 +++++++++++++++ .../testapp/screensMobile/CreateDeal.kt | 415 ++++++++++++++++++ .../example/testapp/screensMobile/DealList.kt | 367 ++++++++++++++++ .../testapp/screensMobile/EntryScreen.kt | 189 ++++++++ .../example/testapp/screensMobile/History.kt | 206 +++++++++ .../testapp/screensMobile/RegisterScreen.kt | 260 +++++++++++ .../example/testapp/screensMobile/Wallet.kt | 156 +++++++ .../com/example/testapp/ui/theme/Color.kt | 11 + .../com/example/testapp/ui/theme/Theme.kt | 70 +++ .../java/com/example/testapp/ui/theme/Type.kt | 34 ++ 32 files changed, 3195 insertions(+) create mode 100644 app/src/main/java/com/example/testapp/MainActivity.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/AlertDialog.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/Btn.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/DealItem.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/DropDown.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/ListItem.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/NavBar.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/SharedViewModel.kt create mode 100644 app/src/main/java/com/example/testapp/designElem/SliderWithRange.kt create mode 100644 app/src/main/java/com/example/testapp/graphs/AuthNavGraph.kt create mode 100644 app/src/main/java/com/example/testapp/graphs/HomeNavGraph.kt create mode 100644 app/src/main/java/com/example/testapp/graphs/RootNavGraph.kt create mode 100644 app/src/main/java/com/example/testapp/navigate/BottomBarScreen.kt create mode 100644 app/src/main/java/com/example/testapp/room/dao/CoinDao.kt create mode 100644 app/src/main/java/com/example/testapp/room/dao/DealDao.kt create mode 100644 app/src/main/java/com/example/testapp/room/dao/UserDao.kt create mode 100644 app/src/main/java/com/example/testapp/room/dao/WalletItemDao.kt create mode 100644 app/src/main/java/com/example/testapp/room/database/CryptoDealDb.kt create mode 100644 app/src/main/java/com/example/testapp/room/models/Coin.kt create mode 100644 app/src/main/java/com/example/testapp/room/models/Deal.kt create mode 100644 app/src/main/java/com/example/testapp/room/models/User.kt create mode 100644 app/src/main/java/com/example/testapp/room/models/WalletItem.kt create mode 100644 app/src/main/java/com/example/testapp/screensMobile/AccountPage.kt create mode 100644 app/src/main/java/com/example/testapp/screensMobile/CreateDeal.kt create mode 100644 app/src/main/java/com/example/testapp/screensMobile/DealList.kt create mode 100644 app/src/main/java/com/example/testapp/screensMobile/EntryScreen.kt create mode 100644 app/src/main/java/com/example/testapp/screensMobile/History.kt create mode 100644 app/src/main/java/com/example/testapp/screensMobile/RegisterScreen.kt create mode 100644 app/src/main/java/com/example/testapp/screensMobile/Wallet.kt create mode 100644 app/src/main/java/com/example/testapp/ui/theme/Color.kt create mode 100644 app/src/main/java/com/example/testapp/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/example/testapp/ui/theme/Type.kt diff --git a/app/src/main/java/com/example/testapp/MainActivity.kt b/app/src/main/java/com/example/testapp/MainActivity.kt new file mode 100644 index 0000000..11779e7 --- /dev/null +++ b/app/src/main/java/com/example/testapp/MainActivity.kt @@ -0,0 +1,37 @@ +package com.example.testapp + +import android.annotation.SuppressLint +import android.os.Bundle +import android.widget.TextView +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.viewModels +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.navigation.compose.rememberNavController +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.graphs.RootNavigationGraph +import com.example.testapp.ui.theme.TestAppTheme +import org.w3c.dom.Text + +class MainActivity : ComponentActivity() { + private val sharedViewModel: SharedViewModel by viewModels() + + @SuppressLint("MissingInflatedId", "SetTextI18n") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + TestAppTheme { + RootNavigationGraph( + navController = rememberNavController(), + sharedViewModel = sharedViewModel + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/designElem/AlertDialog.kt b/app/src/main/java/com/example/testapp/designElem/AlertDialog.kt new file mode 100644 index 0000000..a80ae7e --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/AlertDialog.kt @@ -0,0 +1,44 @@ +package com.example.testapp.designElem + +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable + +@Composable +fun AlertDialogExample( + onDismissRequest: () -> Unit, + onConfirmation: () -> Unit, + dialogTitle: String, + dialogText: String, +) { + AlertDialog( + title = { + Text(text = dialogTitle) + }, + text = { + Text(text = dialogText) + }, + onDismissRequest = { + onDismissRequest() + }, + confirmButton = { + TextButton( + onClick = { + onConfirmation() + } + ) { + Text("Confirm") + } + }, + dismissButton = { + TextButton( + onClick = { + onDismissRequest() + } + ) { + Text("Dismiss") + } + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/designElem/Btn.kt b/app/src/main/java/com/example/testapp/designElem/Btn.kt new file mode 100644 index 0000000..dbe58d7 --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/Btn.kt @@ -0,0 +1,70 @@ +package com.example.testapp.designElem + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp + +@Composable +fun Btn(modifier: Modifier = Modifier, btnConfig: btnConfig) { + Button( + onClick = btnConfig.onClick, + shape = RoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors(containerColor = btnConfig.color), + modifier = modifier + .requiredHeight(height = 44.dp) + ) { + Box( + modifier = Modifier + .requiredHeight(height = 44.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(alignment = Alignment.Center) + .offset(x = btnConfig.offsetX, y = btnConfig.offsetY) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = btnConfig.text, + color = Color.White, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp) + ) + } + } + } + } +} + +data class btnConfig( + val onClick: () -> Unit = {}, + val text: String, + val color: Color, + val offsetX: Dp, + val offsetY: Dp +) \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/designElem/DealItem.kt b/app/src/main/java/com/example/testapp/designElem/DealItem.kt new file mode 100644 index 0000000..ad641d7 --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/DealItem.kt @@ -0,0 +1,182 @@ +package com.example.testapp.designElem + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +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.em +import androidx.compose.ui.unit.sp +import com.example.testapp.room.models.Coin +import com.example.testapp.room.models.Deal + +@Composable +fun DealItem(modifier: Modifier = Modifier, deal: Deal, coins: List) { + Box( + modifier = modifier + .requiredWidth(width = 356.dp) + .requiredHeight(height = 86.dp) + ) { + Box( + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 10.dp, + y = 5.dp) + .requiredWidth(width = 336.dp) + .requiredHeight(height = 131.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = Color(0xfffafafa)) + .border(border = BorderStroke(2.dp, Color.White), + shape = RoundedCornerShape(8.dp))) + Property1ListAvatar( + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 10.dp, + y = 10.dp), deal, coins) + Box( + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 201.dp, + y = 86.dp) + .requiredWidth(width = 130.dp) + .requiredHeight(height = 40.dp) + ) { + Box( + modifier = Modifier + .requiredWidth(width = 130.dp) + .requiredHeight(height = 40.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = Color(0xff85c3ff))) + Text( + text = "${coins.first{ x -> deal.buyerCoinId == x.id }.name} ${deal.countBuy}", + color = Color.White, + lineHeight = 1.33.em, + style = TextStyle( + fontSize = 15.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 21.dp, + y = 10.dp) + .requiredWidth(width = 87.dp)) + } + Box( + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 25.dp, + y = 86.dp) + .requiredWidth(width = 170.dp) + .requiredHeight(height = 40.dp) + ) { + Box( + modifier = Modifier + .requiredWidth(width = 170.dp) + .requiredHeight(height = 40.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = Color(0xff5acb48))) + Button( + onClick = { }, + colors = ButtonDefaults.buttonColors(containerColor = Color.White), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 52.dp, + y = 10.dp) + .requiredWidth(width = 66.dp)){ } + } + } +} + +@Composable +fun Property1ListAvatar(modifier: Modifier = Modifier, deal: Deal, coins: List) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .requiredWidth(width = 336.dp) + .requiredHeight(height = 66.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = Color.White) + .padding(start = 12.dp, + end = 16.dp, + top = 4.dp, + bottom = 4.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(all = 12.dp) + ) { + Avatar(deal = deal, coins = coins) + } + Text( + text = coins.first {x -> x.id == deal.sellerCoinId}.name, + color = Color(0xff0b1f33), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(align = Alignment.CenterVertically)) + } +} + +@Composable +fun Avatar(modifier: Modifier = Modifier, deal: Deal, coins: List) { + Box( + modifier = modifier + .requiredSize(size = 32.dp) + .clip(shape = MaterialTheme.shapes.small) + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(color = Color(0xfff9a825))) + Box( + modifier = Modifier + .fillMaxSize() + .background(brush = Brush.linearGradient( + 0f to Color.White, + 1f to Color.White, + start = Offset(16f, 0f), + end = Offset(16f, 32f)))) + Text( + text = coins.first {x -> x.id == deal.sellerCoinId}.shortName(), + color = Color.White, + textAlign = TextAlign.Center, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxSize() + .wrapContentHeight(align = Alignment.CenterVertically)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/designElem/DropDown.kt b/app/src/main/java/com/example/testapp/designElem/DropDown.kt new file mode 100644 index 0000000..7107866 --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/DropDown.kt @@ -0,0 +1,85 @@ +package com.example.testapp.designElem + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp + +data class DropDownConfig( + val values: List, + var title: String, + val onValueChange: (T) -> Unit, + val selected: T? +) + +@Composable +fun DropDown(modifier: Modifier = Modifier, downConfig: DropDownConfig) { + var expanded by remember { mutableStateOf(false) } + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .fillMaxWidth() + .clip(shape = RoundedCornerShape(8.dp)) + .clickable { expanded = !expanded } + .background(color = Color.Transparent) + .border( + border = BorderStroke(1.dp, Color.Black), + shape = RoundedCornerShape(8.dp) + ) + .padding( + horizontal = 10.dp, + vertical = 8.dp + ) + ) { + Text( + text = if (downConfig.selected == null) downConfig.title else downConfig.selected.toString(), + color = Color.Black, + textAlign = TextAlign.Center, + lineHeight = 1.43.em, + style = TextStyle( + fontSize = 14.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + Modifier.background(color = Color.Transparent), + ) { + downConfig.values.forEach { x -> + DropdownMenuItem( + text = { Text(x.toString()) }, + onClick = { + downConfig.onValueChange(x); + expanded = false; + downConfig.title = x.toString() + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/designElem/ListItem.kt b/app/src/main/java/com/example/testapp/designElem/ListItem.kt new file mode 100644 index 0000000..6aa27b1 --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/ListItem.kt @@ -0,0 +1,84 @@ +package com.example.testapp.designElem + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +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.em +import androidx.compose.ui.unit.sp +import com.example.testapp.room.models.Coin + +@Composable +fun ListItem(modifier: Modifier = Modifier, coin : Coin, count: Float) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .requiredWidth(width = 340.dp) + .requiredHeight(height = 36.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = Color.White) + .padding(end = 12.dp, + top = 4.dp, + bottom = 4.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .requiredWidth(width = 56.dp) + .padding(all = 12.dp) + ) { + Box( + modifier = Modifier + .requiredWidth(width = 40.dp) + .requiredHeight(height = 32.dp) + .clip(shape = MaterialTheme.shapes.small) + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(color = Color(0xfff9a825))) + Text( + text = coin.shortName(), + color = Color.Black, + textAlign = TextAlign.Center, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxSize() + .wrapContentHeight(align = Alignment.CenterVertically)) + } + } + Text( + text = "$count ${coin.name}", + color = Color(0xff0b1f33), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/designElem/NavBar.kt b/app/src/main/java/com/example/testapp/designElem/NavBar.kt new file mode 100644 index 0000000..169afb6 --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/NavBar.kt @@ -0,0 +1,108 @@ +package com.example.pmulabs.designElem + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.shrinkHorizontally +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +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.text.toUpperCase +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.NavDestination +import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState +import com.example.testapp.navigate.BottomBarScreen +import java.util.Locale + +@Composable +fun NavBar(navController: NavHostController){ + val screens = listOf( + BottomBarScreen.Profile, + BottomBarScreen.Wallet, + BottomBarScreen.Deals, + BottomBarScreen.History + ) + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentDestination=navBackStackEntry?.destination + val bottomBarDestination=screens.any{ it.route==currentDestination?.route } + NavigationBar( + modifier = Modifier + .height(48.dp) + ) { + Row( + modifier = Modifier + .padding(horizontal = 5.dp) + .background(Color.Transparent), + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically + ) { + if (bottomBarDestination) { + screens.forEach { screen -> + AddItem( + screen = screen, + currentDestination = currentDestination, + navController = navController + ) + } + } + } + } +} + +@Composable +fun AddItem( + screen: BottomBarScreen, + currentDestination: NavDestination?, + navController: NavController +){ + val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true + val background = if (selected) Color(0xff4BB2F9) else Color.Transparent + val contentColor = if (selected) Color.White else Color(0xFF4BB2F9) + + Box( + modifier = Modifier + .height(40.dp) + .background(background) + .clickable(onClick = { + navController.navigate(screen.route) { + popUpTo(navController.graph.findStartDestination().id) + launchSingleTop = true + } + }) + .clip(shape = RoundedCornerShape(10.dp)) + .requiredWidth(100.dp) + ) { + Row( + modifier = Modifier + .padding(start = 5.dp, end = 5.dp, top = 8.dp, bottom = 8.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + AnimatedVisibility(visible = true) { + Text( + text = screen.shortName(), + color = contentColor + ) + } + } + } +} diff --git a/app/src/main/java/com/example/testapp/designElem/SharedViewModel.kt b/app/src/main/java/com/example/testapp/designElem/SharedViewModel.kt new file mode 100644 index 0000000..85c3274 --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/SharedViewModel.kt @@ -0,0 +1,24 @@ +package com.example.testapp.designElem + +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel + +class SharedViewModel : ViewModel() { + val argument = mutableStateOf(null) + val argument_edit = mutableStateOf(null) + val argument_add_f = mutableStateOf(null) + val argument_add_c = mutableStateOf(null) + + fun setArgumentAdd(arg1: Any, arg2: Any) { + argument_add_f.value = arg1 + argument_add_c.value = arg2 + } + + fun setArgumentEdit(arg: Any) { + argument_edit.value = arg + } + + fun setArgument(arg: String) { + argument.value = arg + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/designElem/SliderWithRange.kt b/app/src/main/java/com/example/testapp/designElem/SliderWithRange.kt new file mode 100644 index 0000000..ab6d664 --- /dev/null +++ b/app/src/main/java/com/example/testapp/designElem/SliderWithRange.kt @@ -0,0 +1,81 @@ +package com.example.testapp.designElem + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Slider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableDoubleStateOf +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp + +data class SliderRangeConfig( + val start: Float, + val end: Float +) + +@Composable +fun SliderWithRange(modifier: Modifier = Modifier, + sliderRangeConfig: SliderRangeConfig = SliderRangeConfig(0.0f, 1.0f), + onValueChange: (Float) -> Unit = {} +) { + var value by remember { mutableFloatStateOf(sliderRangeConfig.start) } + Column( + verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.Top), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .fillMaxWidth() + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = Color.Transparent) + .border( + border = BorderStroke(1.dp, Color.Black), + shape = RoundedCornerShape(8.dp) + ) + .padding( + horizontal = 10.dp, + vertical = 8.dp + ) + ) { + Slider( + value = value, + onValueChange = { value = it; onValueChange(value) }, + onValueChangeFinished = { }, + valueRange = sliderRangeConfig.start..sliderRangeConfig.end, + modifier = modifier + .fillMaxWidth() + .padding( + horizontal = 10.dp, + vertical = 2.dp + )) + Text( + text = value.toString(), + color = Color.Black, + textAlign = TextAlign.Center, + lineHeight = 1.43.em, + style = TextStyle( + fontSize = 14.sp, + letterSpacing = 0.1.sp), + modifier = modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/graphs/AuthNavGraph.kt b/app/src/main/java/com/example/testapp/graphs/AuthNavGraph.kt new file mode 100644 index 0000000..35d37ad --- /dev/null +++ b/app/src/main/java/com/example/testapp/graphs/AuthNavGraph.kt @@ -0,0 +1,29 @@ +package com.example.testapp.graphs + +import androidx.compose.ui.Modifier +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.navigation +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.screensMobile.EntryScreen +import com.example.testapp.screensMobile.RegisterScreen + +fun NavGraphBuilder.authNavGraph(navController: NavHostController, sharedViewModel: SharedViewModel){ + navigation( + route=Graph.AUTHENTICATION, + startDestination = AuthScreen.Entry.route + ){ + composable(route=AuthScreen.Entry.route){ + EntryScreen(navController = navController, modifier = Modifier, sharedViewModel = sharedViewModel) + } + composable(route=AuthScreen.Register.route){ + RegisterScreen(navController = navController, modifier = Modifier, sharedViewModel = sharedViewModel) + } + } +} + +sealed class AuthScreen(val route: String){ + object Entry : AuthScreen(route="ENTRY") + object Register : AuthScreen(route="REGISTER") +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/graphs/HomeNavGraph.kt b/app/src/main/java/com/example/testapp/graphs/HomeNavGraph.kt new file mode 100644 index 0000000..da68798 --- /dev/null +++ b/app/src/main/java/com/example/testapp/graphs/HomeNavGraph.kt @@ -0,0 +1,44 @@ +package com.example.testapp.graphs + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.navigate.BottomBarScreen +import com.example.testapp.screensMobile.AccountPage +import com.example.testapp.screensMobile.CreateDeal +import com.example.testapp.screensMobile.DealList +import com.example.testapp.screensMobile.History +import com.example.testapp.screensMobile.Wallet + +@RequiresApi(34) +@Composable +fun HomeNavGraph(navController: NavHostController, sharedViewModel: SharedViewModel){ + NavHost( + navController = navController, + route = Graph.MAIN, + startDestination = BottomBarScreen.Wallet.route + ){ + composable(route=BottomBarScreen.Wallet.route){ + Wallet(sharedViewModel = sharedViewModel) + } + composable(route=BottomBarScreen.Profile.route){ + AccountPage(sharedViewModel = sharedViewModel, navController = navController) + } + composable(route=BottomBarScreen.Deals.route){ + DealList(navController = navController, sharedViewModel = sharedViewModel) + } + composable(route=BottomBarScreen.CDEAL.route) { + CreateDeal(sharedViewModel = sharedViewModel, navController = navController) + } + composable(route=BottomBarScreen.History.route){ + History(sharedViewModel = sharedViewModel) + } + } +} diff --git a/app/src/main/java/com/example/testapp/graphs/RootNavGraph.kt b/app/src/main/java/com/example/testapp/graphs/RootNavGraph.kt new file mode 100644 index 0000000..9f6e6d3 --- /dev/null +++ b/app/src/main/java/com/example/testapp/graphs/RootNavGraph.kt @@ -0,0 +1,42 @@ +package com.example.testapp.graphs + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.runtime.Composable +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.screensMobile.LoadScreen + +const val USERID_ARGUMENT="userId" + +@RequiresApi(34) +@Composable +fun RootNavigationGraph(navController: NavHostController, sharedViewModel: SharedViewModel){ + NavHost( + navController=navController, + route = Graph.ROOT, + startDestination = Graph.AUTHENTICATION + ){ + authNavGraph(navController=navController,sharedViewModel) + composable(route=Graph.MAIN, + arguments = listOf(navArgument(USERID_ARGUMENT){ + type= NavType.StringType + })){ + LoadScreen(sharedViewModel = sharedViewModel) + } + } +} + +object Graph{ + const val ROOT="root_graph" + const val AUTHENTICATION="auth_graph" + const val MAIN="main_graph/{$USERID_ARGUMENT}" + + fun passUserId(userId: String): String{ + return "main_graph/$userId" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/navigate/BottomBarScreen.kt b/app/src/main/java/com/example/testapp/navigate/BottomBarScreen.kt new file mode 100644 index 0000000..d5c214c --- /dev/null +++ b/app/src/main/java/com/example/testapp/navigate/BottomBarScreen.kt @@ -0,0 +1,31 @@ +package com.example.testapp.navigate + +sealed class BottomBarScreen( + val route: String, + val title: String +) { + object Profile: BottomBarScreen( + route = "PROFILE", + title = "Account", + ); + object Wallet: BottomBarScreen( + route = "WALLET", + title = "Wallet" + ); + object Deals: BottomBarScreen( + route = "DEALS", + title = "Deals" + ) + object History: BottomBarScreen( + route = "HISTORY", + title = "History" + ) + object CDEAL: BottomBarScreen( + route = "CDEAL", + title = "CDEAL" + ) + + fun shortName(): String { + return title.uppercase().substring(0, 4) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/dao/CoinDao.kt b/app/src/main/java/com/example/testapp/room/dao/CoinDao.kt new file mode 100644 index 0000000..16c17ed --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/dao/CoinDao.kt @@ -0,0 +1,21 @@ +package com.example.testapp.room.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.example.testapp.room.models.Coin +import kotlinx.coroutines.flow.Flow + +@Dao +interface CoinDao{ + @Query("select * from coin") + fun getAll(): Flow> + @Insert + suspend fun insert(obj: Coin) + @Update + suspend fun update(obj: Coin) + @Delete + suspend fun delete(obj: Coin) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/dao/DealDao.kt b/app/src/main/java/com/example/testapp/room/dao/DealDao.kt new file mode 100644 index 0000000..17ec4ac --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/dao/DealDao.kt @@ -0,0 +1,24 @@ +package com.example.testapp.room.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.example.testapp.room.models.Coin +import com.example.testapp.room.models.Deal +import kotlinx.coroutines.flow.Flow + +@Dao +interface DealDao{ + @Query("select * from deal") + fun getAll(): Flow> + @Query("select * from deal where deal.buyerId = :idUser OR deal.sellerId = :idUser") + fun getUserDeals(idUser: Int): Flow> + @Insert + suspend fun insert(obj: Deal) + @Update + suspend fun update(obj: Deal) + @Delete + suspend fun delete(obj: Deal) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/dao/UserDao.kt b/app/src/main/java/com/example/testapp/room/dao/UserDao.kt new file mode 100644 index 0000000..ace904f --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/dao/UserDao.kt @@ -0,0 +1,29 @@ +package com.example.testapp.room.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.example.testapp.room.models.Deal +import com.example.testapp.room.models.User +import com.example.testapp.room.models.WalletItem +import kotlinx.coroutines.flow.Flow + +@Dao +interface UserDao { + @Query("select * from user") + fun getAll(): Flow> + @Query("select * from user where user.id = :idUser") + fun getUserById(idUser: Int): Flow + @Query("select * from walletitem where walletitem.userId = :idUser") + fun getUserWallet(idUser: Int): Flow> + @Query("select * from deal where deal.buyerId = :idUser OR deal.sellerId = :idUser") + fun getUserDeals(idUser: Int): Flow> + @Insert + fun insert(obj: User) + @Update + fun update(obj: User) + @Delete + fun delete(obj: User) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/dao/WalletItemDao.kt b/app/src/main/java/com/example/testapp/room/dao/WalletItemDao.kt new file mode 100644 index 0000000..aa37858 --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/dao/WalletItemDao.kt @@ -0,0 +1,23 @@ +package com.example.testapp.room.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.example.testapp.room.models.Deal +import com.example.testapp.room.models.User +import com.example.testapp.room.models.WalletItem +import kotlinx.coroutines.flow.Flow + +@Dao +interface WalletItemDao { + @Query("select * from walletitem") + fun getAll(): Flow> + @Insert + suspend fun insert(obj: WalletItem) + @Update + suspend fun update(obj: WalletItem) + @Delete + suspend fun delete(obj: WalletItem) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/database/CryptoDealDb.kt b/app/src/main/java/com/example/testapp/room/database/CryptoDealDb.kt new file mode 100644 index 0000000..1795a14 --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/database/CryptoDealDb.kt @@ -0,0 +1,91 @@ +package com.example.testapp.room.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.sqlite.db.SupportSQLiteDatabase +import com.example.testapp.room.dao.* +import com.example.testapp.room.models.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +@Database( + entities = [User::class, Deal::class, Coin::class, WalletItem::class], + version = 2, + exportSchema = false) +abstract class CryptoDealDb: RoomDatabase() { + abstract fun userDao(): UserDao; + abstract fun coinDao(): CoinDao; + abstract fun dealDao(): DealDao; + abstract fun walletItemDao(): WalletItemDao; + + companion object { + private const val DB_NAME: String = "crypto-deal2" + + @Volatile + private var INSTANCE: CryptoDealDb? = null + private suspend fun populateDatabase() { + INSTANCE?.let { database -> + val userDao = database.userDao(); + val user1 = User(0, "u11@gmail.com","12345") + val user2 = User(1, "u22@gmail.com","12345") + val user3 = User(2, "u33@gmail.com","12345") + userDao.insert(user1) + userDao.insert(user2) + userDao.insert(user3) + + val coinDao = database.coinDao(); + val c1 = Coin(0, "BidCoin"); + val c2 = Coin(1, "Edhereum"); + val c3 = Coin(2, "CatCoin"); + val c4 = Coin(3, "BuzCoin"); + coinDao.insert(c1); + coinDao.insert(c2) + coinDao.insert(c3) + coinDao.insert(c4) + + val walletItemDao = database.walletItemDao(); + val wi1 = WalletItem(0, 0, 0.5f); + val wi2 = WalletItem(1, 0, 0.6f); + val wi3 = WalletItem(3, 0, 0.7f); + val wi4 = WalletItem(0, 1, 1000f); + val wi5 = WalletItem(3, 1, 10f); + val wi6 = WalletItem(2, 1, 1f); + walletItemDao.insert(wi1); + walletItemDao.insert(wi2); + walletItemDao.insert(wi3); + walletItemDao.insert(wi4); + walletItemDao.insert(wi5); + walletItemDao.insert(wi6); + + val dealDao = database.dealDao(); + val d1 = Deal(0, null, 0, 2, 0, 0.1f, 0.2f, "Buy", null, "TEST1") + val d2 = Deal(1, null, 0, 0, 2, 0.1f, 0.2f, "Buy", null, "TEST2") + dealDao.insert(d1); + dealDao.insert(d2); + } + } + + fun getInstance(appContext: Context): CryptoDealDb { + return INSTANCE ?: synchronized(this) { + Room.databaseBuilder( + appContext, + CryptoDealDb::class.java, + DB_NAME + ) + .addCallback(object : Callback() { + override fun onCreate(db: SupportSQLiteDatabase) { + super.onCreate(db) + CoroutineScope(Dispatchers.IO).launch { + populateDatabase() + } + } + }) + .build() + .also { INSTANCE = it } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/models/Coin.kt b/app/src/main/java/com/example/testapp/room/models/Coin.kt new file mode 100644 index 0000000..e92277a --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/models/Coin.kt @@ -0,0 +1,17 @@ +package com.example.testapp.room.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "coin") +class Coin( + @PrimaryKey(autoGenerate = true) + val id: Int?, + @ColumnInfo(name = "name") + val name: String +) { + fun shortName(): String { + return this.name.substring(0, 2) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/models/Deal.kt b/app/src/main/java/com/example/testapp/room/models/Deal.kt new file mode 100644 index 0000000..cebb04b --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/models/Deal.kt @@ -0,0 +1,22 @@ +package com.example.testapp.room.models + +import androidx.room.Entity +import androidx.room.PrimaryKey +import java.time.LocalDateTime + +@Entity +class Deal ( + @PrimaryKey(autoGenerate = true) + val id: Int?, + val sellerId: Int?, + val buyerId: Int?, + val sellerCoinId: Int, + val buyerCoinId: Int, + val countSell: Float, + val countBuy: Float, + val operation: String, + var date: Long?, + val tip: String, +) { + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/models/User.kt b/app/src/main/java/com/example/testapp/room/models/User.kt new file mode 100644 index 0000000..a9b16d4 --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/models/User.kt @@ -0,0 +1,29 @@ +package com.example.testapp.room.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity(tableName = "user", + indices = [Index(value = ["email"], unique = true)]) +class User( + @PrimaryKey(autoGenerate = true) + val id: Int?, + @ColumnInfo(name = "email") + var email: String, + @ColumnInfo(name = "password") + var password: String +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as User + if (id != other.id) return false + return true + } + + override fun hashCode(): Int { + return id ?: -1 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/room/models/WalletItem.kt b/app/src/main/java/com/example/testapp/room/models/WalletItem.kt new file mode 100644 index 0000000..41cc486 --- /dev/null +++ b/app/src/main/java/com/example/testapp/room/models/WalletItem.kt @@ -0,0 +1,18 @@ +package com.example.testapp.room.models + +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.PrimaryKey + +@Entity( + primaryKeys = ["coinId", "userId"], + foreignKeys = [ + ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["userId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE), + ForeignKey(entity = Coin::class, parentColumns = ["id"], childColumns = ["coinId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE) + ] +) +class WalletItem ( + val coinId: Int, + val userId: Int, + val count: Float +) \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/screensMobile/AccountPage.kt b/app/src/main/java/com/example/testapp/screensMobile/AccountPage.kt new file mode 100644 index 0000000..24407bf --- /dev/null +++ b/app/src/main/java/com/example/testapp/screensMobile/AccountPage.kt @@ -0,0 +1,352 @@ +package com.example.testapp.screensMobile + +import android.annotation.SuppressLint +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.mutableStateListOf +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.platform.LocalContext +import androidx.compose.ui.text.TextStyle +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.em +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import androidx.navigation.NavGraph.Companion.findStartDestination +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.graphs.AuthScreen +import com.example.testapp.room.database.CryptoDealDb +import com.example.testapp.room.models.User +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +@SuppressLint("CoroutineCreationDuringComposition") +@Composable +fun AccountPage(modifier: Modifier = Modifier, sharedViewModel: SharedViewModel, navController: NavController) { + val argument = sharedViewModel.argument.value + val context = LocalContext.current + val users = remember { mutableStateListOf() } + var user: User? = null; + CoroutineScope(Dispatchers.IO).launch { + CryptoDealDb.getInstance(context).userDao().getUserById(argument!!.toInt()).collect { data -> + user = data + } + } + + Box( + modifier = modifier + .background(color = Color(0xfff4f7fb)) + ) { + Column( + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset( + x = 0.dp, + y = 104.dp + ) + .background(color = Color.White) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .requiredSize(size = 84.dp) + ) { + if (user != null) { + Container( + name = user!!.email.substring(0, 2), + modifier = Modifier.align(alignment = Alignment.TopStart).offset(15.dp, 15.dp) + ) + } + } + } + Column( + modifier = Modifier + .padding(vertical = 7.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.Start), + modifier = Modifier + .padding(vertical = 3.dp) + ) { + if (user != null) { + Text( + text = user!!.email, + color = Color(0xff0b1f33), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp)) + } + } + Box( + modifier = Modifier + .requiredWidth(width = 17.dp) + .requiredHeight(height = 4.dp)) + } + } + } + Column( + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset( + x = 0.dp, + y = 204.dp + ) + ) { + Property1Switch(modifier = Modifier.padding(vertical = 5.dp)) + Property1Arrow(modifier = Modifier.padding(vertical = 5.dp)) + } + Property1Clear(navController = navController) + Property1( + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset( + x = 0.dp, + y = 24.dp + )) + } +} + +@Composable +fun Property1Switch(modifier: Modifier = Modifier) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .background(color = Color.White) + .padding( + start = 12.dp, + end = 16.dp, + top = 4.dp, + bottom = 4.dp + ) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(all = 12.dp) + ) { +// Icon( +// painter = painterResource(id = R.drawable.sizem), +// contentDescription = "IconFavorite", +// tint = Color(0xff002033).copy(alpha = 0.35f)) + } + Text( + text = "Enable Notifications", + color = Color(0xff0b1f33), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .weight(weight = 1f) + .wrapContentHeight(align = Alignment.CenterVertically)) + Viewchecked() + } +} + +@Composable +fun Container(modifier: Modifier = Modifier, name: String) { + Column( + verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .requiredSize(size = 54.dp) + .clip(shape = RoundedCornerShape(27.dp)) + .background(color = Color(0xff4bb2f9)) + .padding(all = 10.dp) + ) { + Text( + text = name, + color = Color.White, + textAlign = TextAlign.Center, + style = TextStyle( + fontSize = 24.sp, + fontWeight = FontWeight.Medium), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } +} + +@Composable +fun Viewchecked(modifier: Modifier = Modifier) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + ) { + Box( + modifier = Modifier + .requiredWidth(width = 44.dp) + .requiredHeight(height = 24.dp) + ) { + Box( + modifier = Modifier + .fillMaxSize() + .clip(shape = RoundedCornerShape(100.dp)) + .background(color = Color(0xff4bb2f9))) + Box( + modifier = Modifier + .fillMaxSize() + .clip(shape = CircleShape) + .background(color = Color.White)) + } + } +} + +@Composable +fun Property1Arrow(modifier: Modifier = Modifier) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .background(color = Color.White) + .padding( + start = 12.dp, + end = 16.dp, + top = 4.dp, + bottom = 4.dp + ) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(all = 12.dp) + ) { +// Icon( +// painter = painterResource(id = R.drawable.sizem), +// contentDescription = "IconFavorite", +// tint = Color(0xff002033).copy(alpha = 0.35f)) + } + Text( + text = "Confirm Account", + color = Color(0xff0b1f33), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .weight(weight = 1f) + .wrapContentHeight(align = Alignment.CenterVertically)) + } +} + +@Composable +fun Property1Clear(modifier: Modifier = Modifier, navController: NavController) { + Box( + modifier = modifier + .fillMaxSize() + .clip(shape = RoundedCornerShape(10.dp)) + .clickable{ + navController.navigate(route = AuthScreen.Entry.route) { + popUpTo(navController.graph.findStartDestination().id) + launchSingleTop = true + } + } + .padding( + start = 16.dp, + end = 16.dp, + top = 580.dp, + bottom = 20.dp + ) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(alignment = Alignment.Center) + .offset( + x = 0.dp, + y = 0.dp + ) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Log Out", + color = Color(0xffee3f58), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp)) + } + } + } +} + +@Composable +fun Property1(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .requiredHeight(height = 56.dp) + .background(color = Color.White) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxSize() + .padding(end = 56.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.Start), + modifier = Modifier + .padding(all = 16.dp) + ) { +// Icon( +// painter = painterResource(id = R.drawable.drawer), +// contentDescription = "Drawer", +// tint = Color(0xff0b1f33)) + } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + Text( + text = "Account", + color = Color(0xff0b1f33), + lineHeight = 1.14.em, + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Medium), + modifier = Modifier + .fillMaxWidth()) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/screensMobile/CreateDeal.kt b/app/src/main/java/com/example/testapp/screensMobile/CreateDeal.kt new file mode 100644 index 0000000..e283367 --- /dev/null +++ b/app/src/main/java/com/example/testapp/screensMobile/CreateDeal.kt @@ -0,0 +1,415 @@ +package com.example.testapp.screensMobile + +import androidx.annotation.RequiresApi +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +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.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import com.example.testapp.designElem.DropDown +import com.example.testapp.designElem.DropDownConfig +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.navigate.BottomBarScreen +import com.example.testapp.room.database.CryptoDealDb +import com.example.testapp.room.models.Coin +import com.example.testapp.room.models.Deal +import com.example.testapp.room.models.User +import com.example.testapp.room.models.WalletItem +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +@RequiresApi(34) +@Composable +fun CreateDeal(modifier: Modifier = Modifier, + sharedViewModel: SharedViewModel, + navController: NavHostController) { + val argument = sharedViewModel.argument.value + val editDeal: Deal? = sharedViewModel.argument_edit.value as? Deal + val isEdit = editDeal != null + val id = if (isEdit) editDeal?.buyerId else argument?.toInt() + + val context = LocalContext.current + val coins = remember { mutableStateListOf() } + SideEffect() { + CoroutineScope(Dispatchers.IO).launch { + CryptoDealDb.getInstance(context).coinDao().getAll().collect { data -> + coins.clear() + coins.addAll(data) + } + } + } + + val wallet = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + if (id != null) { + CryptoDealDb.getInstance(context).userDao().getUserWallet(id).collect{data -> + wallet.clear(); + wallet.addAll(data); + } + } + } + } + + val coinsBuyer = wallet.filter { x -> x.userId == id }.toList() + var coinBuyer by rememberSaveable { + mutableStateOf(if (isEdit) coins.first{y -> y.id == editDeal?.buyerCoinId }.name else coinsBuyer[0]) + } + + var buyCount by remember { + mutableFloatStateOf(if (isEdit) editDeal?.countBuy!! else 0f) + } + var tip by remember { + mutableStateOf(if (isEdit) editDeal?.tip else "") + } + + val coinsSeller = wallet.map { x -> coins.first{y -> y.id == x.coinId}.name }.toList() + var coinSeller by rememberSaveable { + mutableStateOf(if (isEdit) coins.first{y -> y.id == editDeal?.sellerCoinId }.name else coinsSeller[0]) + } + var sellCount by remember { + mutableFloatStateOf(if (isEdit) editDeal?.countSell!! else 0f) + } + + + LazyColumn( + verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.Top), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .fillMaxSize() + .background(color = Color(0xfff4f7fb)) + .padding( + horizontal = 0.dp, + vertical = 20.dp + ) + ) { + item { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth(1f) + .requiredHeight(height = 56.dp) + .background(color = Color.White) + .padding( + horizontal = 17.dp, + vertical = 6.dp + ) + ) { + Text( + text = "CREATE DEAL", + color = Color.Black, + lineHeight = 1.14.em, + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Medium) + ) + Text( + text = "-", + color = Color(0xff4bb2f9), + textAlign = TextAlign.Center, + lineHeight = 0.83.em, + style = TextStyle( + fontSize = 24.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .clickable { + navController.navigate(route = BottomBarScreen.Deals.route) + } + .wrapContentHeight(align = Alignment.CenterVertically)) + } + } + item { + Text( + text = "You", + color = Color(0xff66727f), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } + item { + DropDown( + modifier = Modifier.padding(horizontal = 10.dp), + downConfig = DropDownConfig( + values = coinsBuyer.map { x -> coins.first{y -> y.id == x.coinId}.name }.toList(), + title = "Select coin", + onValueChange = { x -> coinBuyer = x }, + selected = coinBuyer as String + ) + ) + } + item { + OutlinedTextField( + value = buyCount.toString(), + onValueChange = { + val value = coinsBuyer.first{ x -> coinBuyer == coins.first{y -> y.id == x.coinId} } + if (it.toFloatOrNull() != null && it.toFloat() <= value.count) { + buyCount = it.toFloat() + } + }, + label = { + Text( + text = "Fill count 0 -> ${coinsBuyer.first{ x -> coinBuyer == coins.first{y -> y.id == x.coinId} }.count}", + color = Color.Black, + textAlign = TextAlign.Center, + lineHeight = 1.43.em, + style = TextStyle( + fontSize = 14.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + }, + modifier = Modifier + .fillMaxWidth() + .clip(shape = RoundedCornerShape(8.dp)) + .padding( + horizontal = 10.dp, + vertical = 2.dp + )) + } + item { + OutlinedTextField( + value = tip!!, + onValueChange = { tip = it }, + label = { + Text( + text = "Enter tip (up to 100 symbols)", + color = Color.Black, + textAlign = TextAlign.Center, + lineHeight = 1.43.em, + style = TextStyle( + fontSize = 14.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + }, + modifier = Modifier + .fillMaxWidth() + .requiredHeight(height = 100.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .padding( + horizontal = 10.dp, + vertical = 2.dp + )) + } + item { + Text( + text = "Buyer", + color = Color(0xff66727f), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } + item { + DropDown( + modifier = Modifier.padding(horizontal = 10.dp), + downConfig = DropDownConfig( + values = coinsSeller.filter { x -> x != (coinBuyer as String) }, + title = "Select coin", + onValueChange = { x -> coinSeller = x }, + selected = coinSeller + ) + ) + } + item { + OutlinedTextField( + value = sellCount.toString(), + onValueChange = { sellCount = it.toFloat() }, + label = { + Text( + text = "Fill count", + color = Color.Black, + textAlign = TextAlign.Center, + lineHeight = 1.43.em, + style = TextStyle( + fontSize = 14.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + }, + modifier = Modifier + .fillMaxWidth() + .clip(shape = RoundedCornerShape(8.dp)) + .padding( + horizontal = 10.dp, + vertical = 2.dp + )) + } + item { + Button( + onClick = { + if (isEdit) { + val deal = Deal( + id = editDeal?.id, + sellerId = editDeal?.sellerId, + buyerId = id, + buyerCoinId = coins.first { x -> x.name == coinBuyer }.id!!, + countBuy = buyCount, + sellerCoinId = coins.first { x -> x.name == coinSeller }.id!!, + countSell = sellCount, + tip = tip!!, + operation = "Buy", + date = null, + ) + CoroutineScope(Dispatchers.IO).launch { + CryptoDealDb.getInstance(context).dealDao().update(deal) + } + } else { + val deal = Deal( + id = null, + sellerId = null, + buyerId = id, + buyerCoinId = coins.first { x -> x.name == coinBuyer }.id!!, + countBuy = buyCount, + sellerCoinId = coins.first { x -> x.name == coinSeller }.id!!, + countSell = sellCount, + tip = tip!!, + operation = "Buy", + date = null, + ) + CoroutineScope(Dispatchers.IO).launch { + CryptoDealDb.getInstance(context).dealDao().insert(deal) + } + } + navController.navigate(route = BottomBarScreen.Deals.route) + }, + shape = RoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors(containerColor = Color(0xff4bb2f9)), + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp, top = 30.dp) + .requiredHeight(height = 44.dp) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .requiredHeight(height = 44.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(alignment = Alignment.Center) + .offset( + x = 0.dp, + y = 0.dp + ) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = if (isEdit) "Confirm" else "Create", + color = Color.White, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp)) + } + } + } + } + } + item { + Button( + onClick = { + navController.navigate(route = BottomBarScreen.Deals.route) + }, + shape = RoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors(containerColor = Color(0xff4bb2f9)), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 10.dp) + .requiredHeight(height = 44.dp) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .requiredHeight(height = 44.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(alignment = Alignment.Center) + .offset( + x = 0.dp, + y = 0.dp + ) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Cancel", + color = Color.White, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp)) + } + } + } + } + } + } +} + +@RequiresApi(34) +@Preview +@Composable +private fun Frame20Preview() { + val sharedViewModel = SharedViewModel() + sharedViewModel.setArgument("0") + CreateDeal(Modifier, + navController = rememberNavController(), + sharedViewModel = sharedViewModel + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/screensMobile/DealList.kt b/app/src/main/java/com/example/testapp/screensMobile/DealList.kt new file mode 100644 index 0000000..195cd2f --- /dev/null +++ b/app/src/main/java/com/example/testapp/screensMobile/DealList.kt @@ -0,0 +1,367 @@ +package com.example.testapp.screensMobile + +import android.annotation.SuppressLint +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +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.draw.clip +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle +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.em +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import com.example.testapp.R +import com.example.testapp.designElem.AlertDialogExample +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.graphs.Graph +import com.example.testapp.navigate.BottomBarScreen +import com.example.testapp.room.database.CryptoDealDb +import com.example.testapp.room.models.Coin +import com.example.testapp.room.models.Deal +import com.example.testapp.room.models.WalletItem +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.time.LocalDate +import java.time.LocalDateTime + +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun DealList(navController: NavHostController, + sharedViewModel: SharedViewModel, + @SuppressLint("ModifierParameter") modifier: Modifier = Modifier +) { + val argument = sharedViewModel.argument.value + val id = argument?.toInt() + + val context = LocalContext.current + val deals = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).dealDao().getAll().collect { data -> + deals.clear() + deals.addAll(data) + } + } + } + val wallet = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + if (id != null) { + CryptoDealDb.getInstance(context).userDao().getUserWallet(id).collect{data -> + wallet.clear(); + wallet.addAll(data); + } + } + } + } + + val coins = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).coinDao().getAll().collect { data -> + coins.clear() + coins.addAll(data) + } + } + } + + LazyColumn ( + verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .background(color = Color(0xfff4f7fb)) + .padding(vertical = 20.dp) + .fillMaxSize() + ) { + item { + PropertyDeal(navController = navController) + } + item { + deals.filter { x -> x.date == null }.forEach{ x -> Deal( + deal = x, + coins = coins, + modifier = Modifier.padding(vertical = 5.dp), + id = id, + navController = navController, + sharedViewModel = sharedViewModel, + wallet = wallet)} + } + } +} + +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun Deal(modifier: Modifier = Modifier, + deal: Deal, + coins: List, + id: Int?, + navController: NavHostController, + sharedViewModel: SharedViewModel, + wallet: List) { + Column( + verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .requiredWidth(width = 360.dp) + .clip(shape = RoundedCornerShape(10.dp)) + .background(color = Color(0xffEEEEEE)) + .padding( + start = 10.dp, + end = 10.dp, + bottom = 10.dp + ) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .requiredWidth(width = 360.dp) + .requiredHeight(height = 60.dp) + .clip(shape = RoundedCornerShape(10.dp)) + .background(color = Color.White) + .padding(horizontal = 22.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .requiredSize(size = 35.dp) + .clip(shape = MaterialTheme.shapes.small) + .background( + brush = Brush.linearGradient( + 0f to Color(0xffffcc7a), + 1f to Color(0xffe4a031), + start = Offset(17.5f, 0f), + end = Offset(17.5f, 35f) + ) + ) + ) { + Text( + text = coins.first{x -> x.id == deal.buyerCoinId}.shortName(), + color = Color.White, + lineHeight = 1.em, + style = TextStyle( + fontSize = 20.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } + Text( + text = deal.countBuy.toString(), + color = Color.Black, + textAlign = TextAlign.End, + lineHeight = 1.em, + style = TextStyle( + fontSize = 20.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(align = Alignment.CenterVertically)) + } + Text( + text = deal.tip, + color = Color(0xffa3abb3), + textAlign = TextAlign.Center, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth() + .requiredHeight(height = 40.dp) + .wrapContentHeight(align = Alignment.CenterVertically)) + Row( + horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .requiredWidth(width = 360.dp) + .requiredHeight(height = 45.dp) + .padding( + horizontal = 10.dp, + vertical = 5.dp + ) + ) { + Button( + onClick = { + if (id != null && id != deal.buyerId) { +// val userRepository = UserRepository() +// val buyer = deal.buyerId?.let { userRepository.getById(it) } +// val seller = userRepository.getById(id) +// +// val coin = seller.wallet[deal.sellerCoin] +// if (coin != null && coin >= deal.countSell) { +// if (buyer != null) { +// if (buyer.wallet.containsKey(deal.sellerCoin)) +// buyer.wallet[deal.sellerCoin] = buyer.wallet[deal.sellerCoin]!! + deal.countSell +// else buyer.wallet[deal.sellerCoin] = deal.countSell +// buyer.wallet[deal.buyerCoin] = buyer.wallet[deal.buyerCoin]!! - deal.countBuy +// } +// seller.wallet[deal.sellerCoin] = seller.wallet[deal.sellerCoin]!! - deal.countSell +// if (seller.wallet.containsKey(deal.buyerCoin)) +// seller.wallet[deal.buyerCoin] = seller.wallet[deal.buyerCoin]!! + deal.countBuy +// else seller.wallet[deal.buyerCoin] = deal.countSell +// } +// deal.date = LocalDateTime.now() +// deal.sellerId = id +// DealRepository().update(deal) +// navController.navigate(BottomBarScreen.Deals.route) { +// popUpTo(navController.graph.findStartDestination().id) +// launchSingleTop = true +// } + } else { + sharedViewModel.setArgumentEdit(deal) + sharedViewModel.setArgumentAdd(wallet, coins) + navController.navigate(BottomBarScreen.CDEAL.route) { + popUpTo(navController.graph.findStartDestination().id) + launchSingleTop = true + } + } + }, + shape = RoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors(containerColor = Color(0xff5acb48)), + modifier = Modifier + .fillMaxSize() + .weight(weight = 0.5f) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .requiredWidth(width = 168.dp) + .requiredHeight(height = 35.dp) + ) { + Text( + text = if (id == deal.buyerId) "Edit" else deal.operation, + color = Color.White, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp), + modifier = Modifier + .requiredWidth(width = 29.dp)) + } + } + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxSize() + .weight(weight = 0.5f) + .clip(shape = RoundedCornerShape(10.dp)) + .background(color = Color(0xff85c3ff)) + .padding(horizontal = 10.dp) + ) { + Text( + text = coins.first{x -> x.id == deal.sellerCoinId}.shortName(), + color = Color.White, + textAlign = TextAlign.End, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp)) + Text( + text = "${deal.countSell}\n", + color = Color.White, + textAlign = TextAlign.End, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth() + .requiredHeight(height = 20.dp)) + } + } + } +} + +@Composable +fun PropertyDeal(modifier: Modifier = Modifier, navController: NavHostController) { + Box( + modifier = modifier + .fillMaxWidth() + .requiredHeight(height = 56.dp) + .background(color = Color.White) + ) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .fillMaxWidth() + .requiredHeight(height = 56.dp) + .background(color = Color.White) + .padding( + horizontal = 17.dp, + vertical = 6.dp + ) + ) { + Text( + text = "CREATE DEAL", + color = Color.Black, + lineHeight = 1.14.em, + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Medium)) + Text( + text = "+", + color = Color(0xff4bb2f9), + textAlign = TextAlign.Center, + lineHeight = 0.83.em, + style = TextStyle( + fontSize = 24.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .clickable { + navController.navigate(BottomBarScreen.CDEAL.route) { + popUpTo(navController.graph.findStartDestination().id) + launchSingleTop = true + } + } + .wrapContentHeight(align = Alignment.CenterVertically)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/screensMobile/EntryScreen.kt b/app/src/main/java/com/example/testapp/screensMobile/EntryScreen.kt new file mode 100644 index 0000000..3d31801 --- /dev/null +++ b/app/src/main/java/com/example/testapp/screensMobile/EntryScreen.kt @@ -0,0 +1,189 @@ +package com.example.testapp.screensMobile + +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.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import com.example.testapp.designElem.Btn +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.designElem.btnConfig +import com.example.testapp.graphs.AuthScreen +import com.example.testapp.graphs.Graph +import com.example.testapp.room.database.CryptoDealDb +import com.example.testapp.room.models.User +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +fun isValidEmail(email: String): Boolean { + val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex() + return email.matches(emailRegex) +} + +@Composable +fun EntryScreen(navController: NavController, + modifier: Modifier = Modifier, + sharedViewModel: SharedViewModel) { + var emailValue by rememberSaveable { mutableStateOf("") } + var passwordValue by rememberSaveable { mutableStateOf("") } + val context = LocalContext.current + val users = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).userDao().getAll().collect { data -> + users.clear() + users.addAll(data) + } + } + } + + Box( + modifier = modifier + .fillMaxSize() + .background(color = Color.White) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 0.dp, + y = 40.dp) + ) { + Text( + text = "Sign On", + color = Color(0xff0b1f33), + textAlign = TextAlign.Center, + style = TextStyle( + fontSize = 24.sp, + fontWeight = FontWeight.Medium), + modifier = Modifier + .fillMaxSize()) + } + Column( + verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 0.dp, y = 278.dp) + .padding(start = 5.dp, end = 5.dp) + ) { + TextField( + value = emailValue, + onValueChange = { emailValue = it }, + label = { + Text( + text = "Email", + color = Color(0xff66727f), + lineHeight = 1.33.em, + style = TextStyle( + fontSize = 15.sp, + letterSpacing = 0.2.sp) + ) + }, + placeholder = { Text("Enter email") }, + textStyle = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth()) + TextField( + value = passwordValue, + onValueChange = { passwordValue = it }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + label = { + Text( + text = "Password", + color = Color(0xff66727f), + lineHeight = 1.33.em, + style = TextStyle( + fontSize = 15.sp, + letterSpacing = 0.2.sp)) + }, + placeholder = { Text("Enter password") }, + textStyle = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth()) + } + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 0.dp, + y = 602.dp) + .padding(horizontal = 5.dp, + vertical = 5.dp) + .fillMaxWidth() + ) { + Btn(btnConfig = btnConfig( + onClick = { + if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) { + users.forEach { user -> + if (user.password == passwordValue && user.email == emailValue) { + sharedViewModel.setArgument(user.id.toString()) + navController.navigate(route = Graph.passUserId(user.id.toString())) + } + } + }}, + text = "Sign In", + color = Color(0xff85c3ff), + offsetX = 0.dp, + offsetY = 0.dp + ), modifier = Modifier.fillMaxWidth()) + } + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 0.dp, + y = 656.dp) + .padding(horizontal = 5.dp, + vertical = 5.dp) + .fillMaxWidth() + ) { + Btn(btnConfig = btnConfig( + onClick = { + navController.navigate(route = AuthScreen.Register.route) + { + popUpTo(AuthScreen.Register.route) + } + }, + text = "Sign On", + color = Color(0xff85c3f3), + offsetX = 0.dp, + offsetY = 0.dp + ), modifier = Modifier.fillMaxWidth()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/screensMobile/History.kt b/app/src/main/java/com/example/testapp/screensMobile/History.kt new file mode 100644 index 0000000..aa64ffb --- /dev/null +++ b/app/src/main/java/com/example/testapp/screensMobile/History.kt @@ -0,0 +1,206 @@ +package com.example.testapp.screensMobile + +import android.annotation.SuppressLint +import android.os.Build +import androidx.annotation.RequiresApi +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.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +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.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.room.database.CryptoDealDb +import com.example.testapp.room.models.Coin +import com.example.testapp.room.models.Deal +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun History(navController: NavHostController = rememberNavController(), + @SuppressLint("ModifierParameter") modifier: Modifier = Modifier, + sharedViewModel: SharedViewModel +) { + val argument = sharedViewModel.argument.value + val id = argument?.toInt() + val context = LocalContext.current + val deals = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).dealDao().getAll().collect { data -> + deals.clear() + deals.addAll(data) + } + } + } + + val coins = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).coinDao().getAll().collect { data -> + coins.clear() + coins.addAll(data) + } + } + } + var history: List = listOf(); + if (id != null) { + history = deals.filter { x -> x.buyerId == id || x.sellerId == id } + } + + Column( + verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .requiredHeight(height = 720.dp) + .background(color = Color(0xfff4f7fb)) + .padding(vertical = 20.dp) + .verticalScroll(rememberScrollState()) + ) { + PropertyHistory() + history.forEach { + x -> HistoryCard(deal = x, modifier = Modifier.padding( vertical = 5.dp, horizontal = 5.dp), coins = coins) + } + } +} + +@Composable +fun HistoryCard(modifier: Modifier = Modifier, deal: Deal, coins: List) { + val status = !(deal.buyerId == null || deal.sellerId == null) + val text = if (!status) "In work" else deal.date.toString() + val color = if (!status) 0xfff96161 else 0xff5acb48 + + Column( + verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .requiredHeight(height = 150.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = Color.White) + .padding( + horizontal = 12.dp, + vertical = 5.dp + ) + ) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .padding(all = 10.dp) + ) { + Text( + text = "-${deal.countSell} ${coins.first{x -> x.id == deal.sellerCoinId}.shortName()}", + color = Color(0xfff96161), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + Text( + text = "+${deal.countBuy} ${coins.first{x -> x.id == deal.buyerCoinId}.shortName()}", + color = Color(0xff5acb48), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } + Column( + verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .clip(shape = RoundedCornerShape(5.dp)) + .background(color = Color(0xfff4f7fb)) + .padding(all = 10.dp) + ) { + Text( + text = deal.tip, + color = Color.Black, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } + Text( + lineHeight = 1.sp, + text = buildAnnotatedString { + withStyle(style = SpanStyle( + color = Color(0xff1e1e1e), + fontSize = 16.sp) + ) {append("Status: ")} + withStyle(style = SpanStyle( + color = Color(color), + fontSize = 16.sp)) {append(text)}}, + modifier = Modifier + .wrapContentHeight(align = Alignment.CenterVertically)) + } +} + +@Composable +fun PropertyHistory(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .fillMaxWidth() + .requiredHeight(height = 56.dp) + .background(color = Color.White) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxSize() + .padding(end = 56.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + Text( + text = "HISTORY", + color = Color(0xff0b1f33), + lineHeight = 1.14.em, + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Medium), + modifier = Modifier + .fillMaxWidth()) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/screensMobile/RegisterScreen.kt b/app/src/main/java/com/example/testapp/screensMobile/RegisterScreen.kt new file mode 100644 index 0000000..245ff2b --- /dev/null +++ b/app/src/main/java/com/example/testapp/screensMobile/RegisterScreen.kt @@ -0,0 +1,260 @@ +package com.example.testapp.screensMobile + +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.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +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.platform.LocalContext +import androidx.compose.ui.text.TextStyle +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.em +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.graphs.AuthScreen +import com.example.testapp.graphs.Graph +import com.example.testapp.room.database.CryptoDealDb +import com.example.testapp.room.models.User +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RegisterScreen(navController: NavController, + modifier: Modifier = Modifier, + sharedViewModel: SharedViewModel) { + var emailValue by rememberSaveable { mutableStateOf("") } + var passwordValue by rememberSaveable { mutableStateOf("") } + var passwordConfirmValue by rememberSaveable { mutableStateOf("") } + val context = LocalContext.current + val users = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).userDao().getAll().collect { data -> + users.clear() + users.addAll(data) + } + } + } + + Box( + modifier = modifier + .fillMaxSize() + .background(color = Color.White) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 0.dp, + y = 40.dp) + ) { + Text( + text = "Sign On", + color = Color(0xff0b1f33), + textAlign = TextAlign.Center, + style = TextStyle( + fontSize = 24.sp, + fontWeight = FontWeight.Medium + ), + modifier = Modifier + .fillMaxSize() + ) + } + Column( + verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .padding(start = 5.dp, end = 5.dp) + .offset(x = 0.dp, + y = 232.dp) + ) { + TextField( + value = emailValue, + onValueChange = { emailValue = it }, + label = { + Text( + text = "Email", + color = Color(0xff66727f), + lineHeight = 1.33.em, + style = TextStyle( + fontSize = 15.sp, + letterSpacing = 0.2.sp)) + }, + placeholder = { Text("Enter email") }, + textStyle = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth()) + TextField( + value = passwordValue, + onValueChange = { passwordValue = it }, + label = { + Text( + text = "Password", + color = Color(0xff66727f), + lineHeight = 1.33.em, + style = TextStyle( + fontSize = 15.sp, + letterSpacing = 0.2.sp)) + }, + placeholder = { Text("Enter password") }, + textStyle = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth()) + TextField( + value = passwordConfirmValue, + onValueChange = { passwordConfirmValue = it }, + label = { + Text( + text = "Confirm Password", + color = Color(0xff66727f), + lineHeight = 1.33.em, + style = TextStyle( + fontSize = 15.sp, + letterSpacing = 0.2.sp)) + }, + placeholder = { Text("Confirm password") }, + textStyle = TextStyle( + fontSize = 16.sp, + letterSpacing = 0.1.sp), + modifier = Modifier + .fillMaxWidth()) + } + TextButton( + onClick = { + var isExist = false; + if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) { + users.forEach { user -> + if (user.email == emailValue) { + isExist = true + } + } + + if (!isExist) { + val newUser = User(null, emailValue, passwordValue) + CoroutineScope(Dispatchers.IO).launch { + CryptoDealDb.getInstance(context).userDao().insert(newUser) + CryptoDealDb.getInstance(context).userDao().getAll() + .collect { data -> + data.forEach { user -> + if ((user.password == passwordValue) && (user.email == emailValue)) { + withContext(Dispatchers.Main) { + sharedViewModel.setArgument(user.id.toString()) + navController.navigate(route = Graph.passUserId(user.id.toString())) + } + } + } + } + } + } + } + }, + colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .offset(x = 0.dp, + y = 656.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.Top) + ) { + Property1Primary() + } + } + TextButton( + onClick = { + navController.navigate(route = AuthScreen.Entry.route) + { + popUpTo(AuthScreen.Entry.route) + } + }, + colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), + contentPadding = PaddingValues(horizontal = 10.dp, vertical = 12.dp), + modifier = Modifier + .align(alignment = Alignment.TopStart) + .fillMaxWidth() + .offset(x = 0.dp, + y = 602.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Sign In", + color = Color(0xff4bb2f9), + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp)) + } + } + } +} + +@Composable +fun Property1Primary(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .fillMaxWidth() + .requiredHeight(height = 44.dp) + .clip(shape = RoundedCornerShape(10.dp)) + .background(color = Color(0xff85c3ff)) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(alignment = Alignment.Center) + .offset(x = 0.dp, + y = 0.dp) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Sign On", + color = Color.White, + lineHeight = 1.25.em, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 0.1.sp)) + } + } + } +} diff --git a/app/src/main/java/com/example/testapp/screensMobile/Wallet.kt b/app/src/main/java/com/example/testapp/screensMobile/Wallet.kt new file mode 100644 index 0000000..511047a --- /dev/null +++ b/app/src/main/java/com/example/testapp/screensMobile/Wallet.kt @@ -0,0 +1,156 @@ +package com.example.testapp.screensMobile + +import android.annotation.SuppressLint +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +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.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import com.example.pmulabs.designElem.NavBar +import com.example.testapp.designElem.ListItem +import com.example.testapp.designElem.SharedViewModel +import com.example.testapp.graphs.HomeNavGraph +import com.example.testapp.room.database.CryptoDealDb +import com.example.testapp.room.models.Coin +import com.example.testapp.room.models.User +import com.example.testapp.room.models.WalletItem +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun Wallet(navController: NavHostController = rememberNavController(), + @SuppressLint("ModifierParameter") modifier: Modifier = Modifier, + sharedViewModel: SharedViewModel) { + val argument = sharedViewModel.argument.value + val id = argument?.toInt() + val context = LocalContext.current + val users = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).userDao().getAll().collect { data -> + users.clear() + users.addAll(data) + } + } + } + var wallet: List = listOf() + val walletItem = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + if (id != null) { + CryptoDealDb.getInstance(context).walletItemDao().getAll().collect{ data -> + walletItem.clear() + walletItem.addAll(data) + } + } + } + } + + wallet = walletItem.filter { x -> x.userId == id }; + + val coins = remember { mutableStateListOf() } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + CryptoDealDb.getInstance(context).coinDao().getAll().collect { data -> + coins.clear() + coins.addAll(data) + } + } + } + + LazyColumn( + verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.Top), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .background(color = Color(0xfff4f7fb)) + .padding(vertical = 20.dp) + .fillMaxSize() + ) { + item { + PropertyWallet() + } + item { + wallet.forEach { coin -> + ListItem( + coin = coins.first{ x -> x.id == coin.coinId }, + count = coin.count, + modifier = Modifier.padding( vertical = 5.dp) + ) + } + } + } +} + +@RequiresApi(34) +@Composable +fun LoadScreen(navController: NavHostController = rememberNavController(), + @SuppressLint("ModifierParameter") modifier: Modifier = Modifier, + sharedViewModel: SharedViewModel) { + Scaffold( + bottomBar = { NavBar(navController = navController) }, + ) { + Modifier + .padding(it) + HomeNavGraph(navController, sharedViewModel) + } +} + +@Composable +fun PropertyWallet(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .fillMaxWidth() + .requiredHeight(height = 56.dp) + .background(color = Color.White) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxSize() + .padding(end = 56.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.Start), + modifier = Modifier + .padding(all = 16.dp) + ) { + Text( + text = "Wallet", + color = Color(0xff0b1f33), + lineHeight = 1.14.em, + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Medium), + modifier = Modifier + .fillMaxWidth()) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/ui/theme/Color.kt b/app/src/main/java/com/example/testapp/ui/theme/Color.kt new file mode 100644 index 0000000..da10465 --- /dev/null +++ b/app/src/main/java/com/example/testapp/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.testapp.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/ui/theme/Theme.kt b/app/src/main/java/com/example/testapp/ui/theme/Theme.kt new file mode 100644 index 0000000..83832a8 --- /dev/null +++ b/app/src/main/java/com/example/testapp/ui/theme/Theme.kt @@ -0,0 +1,70 @@ +package com.example.testapp.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun TestAppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/testapp/ui/theme/Type.kt b/app/src/main/java/com/example/testapp/ui/theme/Type.kt new file mode 100644 index 0000000..4bd6618 --- /dev/null +++ b/app/src/main/java/com/example/testapp/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.testapp.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file