Compare commits

...

No commits in common. "main" and "0b319c0ea7dcc10de6db3228b013ccb2f9f8f53f" have entirely different histories.

105 changed files with 6347 additions and 54 deletions

67
.gitignore vendored
View File

@ -1,52 +1,15 @@
# ---> Kotlin
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
# ---> Java
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

6
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>

17
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\ankav\.android\avd\Pixel_6_API_31_2.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-10-27T17:41:35.449717700Z" />
</component>
</project>

20
.idea/gradle.xml generated Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="corretto-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

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

6
.idea/kotlinc.xml generated Normal file
View File

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

9
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="corretto-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -1,2 +0,0 @@
# PMULabs_Zhimol

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

84
app/build.gradle.kts Normal file
View File

@ -0,0 +1,84 @@
plugins {
id("com.android.application")
id("com.google.devtools.ksp")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.example.pmulabs"
compileSdk = 34
defaultConfig {
applicationId = "com.example.pmulabs"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.5"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
kotlin {
jvmToolchain(11)
}
dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("androidx.activity:activity-compose:1.7.2")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3:1.2.0-alpha08")
implementation("androidx.compose.ui:ui-tooling-preview-android:1.5.2")
implementation("androidx.leanback:leanback:1.0.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.navigation:navigation-compose:2.6.0")
implementation("androidx.navigation:navigation-compose:2.4.0-alpha10")
val room_version = "2.5.2"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version")
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,24 @@
package com.example.pmulabs
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.pmulabs", appContext.packageName)
}
}

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PMULabs"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.PMULabs">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,24 @@
package com.example.pmulabs
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.navigation.compose.rememberNavController
import com.example.pmulabs.graphs.RootNavigationGraph
import com.example.pmulabs.ui.theme.PMULabsTheme
import com.example.pmulabs.viewModels.SearchViewModel
import com.example.pmulabs.viewModels.SharedViewModel
class MainActivity : ComponentActivity() {
private val searchViewModel: SearchViewModel by viewModels()
private val sharedViewModel: SharedViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PMULabsTheme {
RootNavigationGraph(navController = rememberNavController(),searchViewModel, sharedViewModel = sharedViewModel)
}
}
}
}

View File

@ -0,0 +1,131 @@
package com.example.pmulabs.basecomponents.navigate
import androidx.compose.animation.AnimatedVisibility
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.RowScope
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
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.res.painterResource
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
@Composable
fun BottomBar(navController: NavHostController){
val screens = listOf(
BottomBarScreen.Profile,
BottomBarScreen.Categories,
BottomBarScreen.Main,
BottomBarScreen.Cooperation,
BottomBarScreen.Info
)
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination=navBackStackEntry?.destination
val bottomBarDestination=screens.any{ it.route==currentDestination?.route }
Row(
modifier = Modifier
.padding(start = 17.dp, end = 17.dp, top = 8.dp, bottom = 8.dp)
.background(Color.Transparent),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
if (bottomBarDestination) {
NavigationBar(
containerColor = Color(0xFFDBDBF1),
modifier = Modifier
.height(40.dp)
.clip(shape = RoundedCornerShape(20.dp))
) {
screens.forEach { screen ->
AddItem(
screen = screen,
currentDestination = currentDestination,
navController = navController
)
}
}
}
}
}
@Composable
fun RowScope.AddItem(
screen: BottomBarScreen,
currentDestination: NavDestination?,
navController: NavController
){
val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true
val background = if (selected) Color(0xff423a99) else Color.Transparent
val contentColor =
if (selected) Color.White else Color(0xff423a99)
Box(
modifier = Modifier
.height(40.dp)
.clip(CircleShape)
.background(background)
.clickable(onClick = {
navController.navigate(screen.route) {
popUpTo(navController.graph.findStartDestination().id)
launchSingleTop = true
}
})
) {
Row(
modifier = Modifier
.padding(start = 17.dp, end = 17.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
Icon(
painter = painterResource(id = if (selected) screen.iconFocused else screen.icon),
contentDescription = "icon",
tint = Color.Unspecified
)
AnimatedVisibility(visible = selected) {
Text(
text = screen.title,
color = contentColor
)
}
}
}
/*NavigationBarItem(
label = {
Text(text=screen.title, color = Color(0xff423a99))
},
icon = {
Icon(
painter = painterResource(id = screen.icon),
tint = Color.Unspecified,
contentDescription = "navigation icon")
},
selected = selected,
onClick = {
navController.navigate(screen.route)
}
)*/
}

View File

@ -0,0 +1,87 @@
package com.example.pmulabs.basecomponents.navigate
import com.example.pmulabs.R
const val SEARCH_ARGUMENT_TEXT="text"
const val CALENDAR_ARGUMENT_DATE="date"
const val SEARCHBYTAG_ARGUMENT_KEY="id"
const val ARTICLE_ARGUMENT_KEY="id"
sealed class BottomBarScreen(
val route: String,
val title: String,
val icon: Int,
val iconFocused: Int
){
object Profile: BottomBarScreen(
route = "PROFILE",
title="Me",
icon= R.drawable.ic_bottom_profile,
iconFocused=R.drawable.ic_bottom_profile_focused
)
object Categories: BottomBarScreen(
route = "CATEGORIES",
title="Tags",
icon= R.drawable.ic_bottom_categories,
iconFocused=R.drawable.ic_bottom_categories_focused
)
object Main: BottomBarScreen(
route = "MAIN",
title="Main",
icon= R.drawable.ic_bottom_main,
iconFocused=R.drawable.ic_bottom_main_focused
)
object ArticlePage: BottomBarScreen(
route = "ARTICLEPAGE/{$ARTICLE_ARGUMENT_KEY}",
title="Article",
icon= R.drawable.ic_bottom_main,
iconFocused=R.drawable.ic_bottom_main_focused
){
fun passId(id: String): String{
return "ARTICLEPAGE/$id"
}
}
object Search: BottomBarScreen(
route = "SEARCH/{$SEARCH_ARGUMENT_TEXT}",
title="Search",
icon= R.drawable.ic_bottom_main,
iconFocused=R.drawable.ic_bottom_main_focused
){
fun passText(text: String): String{
return "SEARCH/$text"
}
}
object Calendar: BottomBarScreen(
route = "CALENDAR/{$CALENDAR_ARGUMENT_DATE}",
title="Calendar",
icon= R.drawable.ic_bottom_main,
iconFocused=R.drawable.ic_bottom_main_focused
){
fun passDate(date: String): String{
return "CALENDAR/$date"
}
}
object SearchByTag: BottomBarScreen(
route = "SEARCHBYTAG/{$SEARCHBYTAG_ARGUMENT_KEY}",
title="SEARCHBYTAG",
icon= R.drawable.ic_bottom_main,
iconFocused=R.drawable.ic_bottom_main_focused
){
fun passId(id: String): String{
return "SEARCHBYTAG/$id"
}
}
object Cooperation: BottomBarScreen(
route = "COOPERATION",
title="Coop",
icon= R.drawable.ic_bottom_cooperation,
iconFocused=R.drawable.ic_bottom_cooperation_focused
)
object Info: BottomBarScreen(
route = "INFO",
title="Info",
icon= R.drawable.ic_bottom_info,
iconFocused=R.drawable.ic_bottom_info_focused
)
}

View File

@ -0,0 +1,155 @@
package com.example.pmulabs.basecomponents.navigate
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CalendarToday
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.pmulabs.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TopBar(onSearchClicked:() -> Unit, onCalendarClicked: () -> Unit) {
TopAppBar(
colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = Color(0xff423a99) ),
title = {
Image(
painter = painterResource(id = R.drawable.ellipse7),
contentDescription = "Ellipse 7",
modifier = Modifier
.requiredHeight(height = 62.dp)
)
Image(
painter = painterResource(id = R.drawable.ixbtcom_colored_logo1),
contentDescription = "IXBT.com_colored_logo 1",
modifier = Modifier
.offset(
x = 4.dp,
y = 0.dp
)
.requiredHeight(height = 60.dp)
)
},
actions = {
IconButton(onClick = { onSearchClicked() }) {
Icon(
imageVector = Icons.Filled.Search,
contentDescription = "Search Icon",
tint = Color.White
)
}
IconButton(onClick = { onCalendarClicked() }) {
Icon(
imageVector = Icons.Filled.CalendarToday,
contentDescription = "Calendar Icon",
tint = Color.White
)
}
})
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SearchAppBar(
text: String,
onTextChange: (String) -> Unit,
onCloseClicked: () -> Unit,
onSearchClicked: (String) -> Unit
){
Surface(
modifier = Modifier
.fillMaxWidth()
.height(62.dp),
color = Color(0xff423a99)
) {
TextField(
colors=TextFieldDefaults.textFieldColors(
Color.White, containerColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth(),
value=text,
onValueChange={
onTextChange(it)
},
placeholder = {
Text(
text ="Search...",
color = Color.White
)
},
textStyle = TextStyle(
fontSize = MaterialTheme.typography.titleMedium.fontSize
),
singleLine = true,
leadingIcon = {
IconButton(
onClick = { }
) {
Icon(imageVector = Icons.Default.Search,
contentDescription = "Search Icon",
tint = Color.White)
}
},
trailingIcon = {
IconButton(
onClick = {
if(text.isNotEmpty()){
onTextChange("")
}else{
onCloseClicked()
}
}
) {
Icon(imageVector = Icons.Default.Close,
contentDescription = "Close Icon",
tint = Color.White)
}
},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Search,
),
keyboardActions = KeyboardActions(
onSearch = {
onSearchClicked(text)
}
)
)
}
}
@Composable
@Preview
fun TopBarPreview(){
TopBar(onSearchClicked = {},onCalendarClicked = {})
}
@Composable
@Preview
fun SearchBarPreview(){
SearchAppBar(text = "вапвапв", onSearchClicked = {}, onCloseClicked = {}, onTextChange = {})
}

View File

@ -0,0 +1,47 @@
package com.example.pmulabs.designElem.elem
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
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.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.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.sp
@Composable
fun BackButton(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.requiredWidth(width = 80.dp)
.requiredHeight(height = 30.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 80.dp)
.requiredHeight(height = 30.dp)
.clip(shape = RoundedCornerShape(6.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Back",
color = Color.White,
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 17.dp,
y = 3.dp))
}
}

View File

@ -0,0 +1,63 @@
package com.example.pmulabs.designElem.elem
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EmailTextField(email: String, onEmailChange: (String) -> Unit) {
TextField(
value = email,
onValueChange = {
onEmailChange(it)
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White
),
modifier = Modifier
.requiredWidth(width = 269.dp)
.requiredHeight(height = 53.dp)
.shadow(shape = RoundedCornerShape(40.dp), elevation = 5.dp)
.clip(shape = RoundedCornerShape(40.dp)),
label = { Text("Email") },
placeholder = { Text("Email") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
singleLine = true,
)
}
fun isValidEmail(email: String): Boolean {
val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex()
return email.matches(emailRegex)
}
@Composable
fun ValidateEmail(email: String, onEmailChange: (String) -> Unit) {
Column (modifier = Modifier.padding(16.dp)) {
EmailTextField(email = email, onEmailChange = { onEmailChange(it)})
if (email.isNotEmpty()) {
if (isValidEmail(email)) {
Text(text = "Email is valid", color = Color(0xFF5D925E))
} else {
Text(text = "Email is not valid", color = Color(0xFF94474D))
}
}
}
}

View File

@ -0,0 +1,462 @@
package com.example.pmulabs.designElem.items
import android.util.Log
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
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.fillMaxWidth
import androidx.compose.foundation.layout.height
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.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
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.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize
import com.example.pmulabs.R
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ArticleItem(article: Article, modifier: Modifier = Modifier, onArticleClick: () -> Unit,sharedViewModel: SharedViewModel) {
val context = LocalContext.current
//список тэгов
val tags = remember { mutableStateListOf<Tag>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).tagDao().getAll().collect { data ->
tags.clear()
tags.addAll(data)
}
}
}
//количество комментариев для статьи
var countComm by rememberSaveable { mutableStateOf(0) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
countComm = article.id?.let {
NewsPortalDatabase.getInstance(context).commentDao().getCountComment(
it
)
}?.toInt() ?: 0
}
}
//текущий пользователь
val argument = sharedViewModel.argument.value
var getUser by remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(argument.toString().toInt()).collect { data ->
getUser=data
}
}
}
//формат даты
val formatter = SimpleDateFormat("dd.MM.YY")
val publishDate=formatter.format(article.publishDate)
//список названий тэгов
var tagName=""
var tagsNames= remember { mutableStateListOf<String>() }
tags.forEach{teg ->
if(article.tagId == teg.id){
tagName=teg.title
}
if(!tagsNames.contains(teg.title)) {
tagsNames.add(teg.title)
}
}
//открыто ли диалоговое окно
var openDialog by remember { mutableStateOf(false) }
//переменные article для update
var text by remember { mutableStateOf(article.text) }
var tagId by remember { mutableStateOf(article.tagId) }
var title by remember { mutableStateOf(article.title) }
//переменные для dropdown
var expanded by remember { mutableStateOf(false) }
val suggestions = tagsNames
var selectedText by remember { mutableStateOf(tagName) }
var textfieldSize by remember { mutableStateOf(Size.Zero)}
val icon = if (expanded)
Icons.Filled.ArrowDropUp
else
Icons.Filled.ArrowDropDown
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).tagDao().getTagById(tagId).collect { data ->
selectedText=data.title
}
}
}
//диалоговое окно
if (openDialog) {
AlertDialog(
onDismissRequest = {
openDialog = false
text=article.text
selectedText=tagName
},
content = {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color.White)
.padding(16.dp),
) {
Text(
text = "Edit your article",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 20.sp,
),
)
Box() {
OutlinedTextField(
value = selectedText,
onValueChange = { selectedText = it },
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.onGloballyPositioned { coordinates ->
textfieldSize = coordinates.size.toSize()
},
label = {Text("Select Tag")},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
trailingIcon = {
Icon(icon,"List of tags",
Modifier.clickable { expanded = !expanded })
}
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier
.width(with(LocalDensity.current){textfieldSize.width.toDp()})
) {
suggestions.forEach { label ->
DropdownMenuItem(
text= {Text(text=label)},
onClick = { selectedText = label
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).tagDao().getTagByName(selectedText).collect{ tag ->
tagId=tag?.id.toString().toInt()
}
}}
)
}
}
}
OutlinedTextField(
value = title,
onValueChange = {
title=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Article Title") },
placeholder = { Text("Write title of article...") },
minLines = 3,
maxLines = 3,
)
OutlinedTextField(
value = text,
onValueChange = {
text=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Article Text") },
placeholder = { Text("Write text of article...") },
minLines = 3,
maxLines = 3,
)
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
openDialog = false
article.text=text
article.title=title
tagName=selectedText
Log.d("Tag",tagId.toString())
if(tagId!=null) {
article.tagId = tagId
}
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).articleDao().update(article)
}
},
modifier = Modifier
.padding(start=100.dp)
.fillMaxWidth(0.5f)
.height(40.dp)
) {
Text(text = "Edit", fontSize = 20.sp)
}
}
}
},
)
}
Card(
colors = CardDefaults.outlinedCardColors(
containerColor = Color.White,
contentColor = Color(0xff423a99)
),
border = BorderStroke(3.dp, Color(0xffdbdbf1)),
modifier = modifier
.clip(shape = RoundedCornerShape(5.dp))
.clickable{onArticleClick()}
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 199.dp)
) {
Card(
colors = CardDefaults.outlinedCardColors(
containerColor = Color.White
),
border = BorderStroke(3.dp, Color(0xffdbdbf1)),
content = {},
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 199.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)))
LazyRow(
modifier = Modifier
.requiredWidth(width = 387.dp)
.requiredHeight(height = 199.dp)
) {
item {
Column(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 15.dp,
y = 8.dp)
.requiredWidth(width = 351.dp)
.requiredHeight(height = 177.dp)
) {
LazyColumn(
modifier = Modifier
.requiredWidth(width = 351.dp)
.requiredHeight(height = 150.dp)
) {
item {
LazyRow(
modifier = Modifier
.requiredWidth(width = 351.dp)
.requiredHeight(height = 20.dp)
) {
item {
Text(
text = "${publishDate}",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 17.sp))
}
item {
Text(
text = "#${tagName}",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 17.sp),
modifier = Modifier
//.align(alignment = Alignment.TopStart)
.offset(x = 12.dp,
y = 0.dp))
}
item{
if(getUser?.id==article.userId) {
Icon(
modifier=Modifier
.align(Alignment.End)
.offset(x = 20.dp,
y = 0.dp)
.requiredHeight(30.dp)
.clickable {
openDialog=true
},
imageVector = Icons.Filled.Edit,
contentDescription = "Update Icon",
tint = Color(0xff423a99)
)
Icon(
modifier=Modifier
.align(Alignment.End)
.offset(x = 20.dp,
y = 0.dp)
.requiredHeight(30.dp)
.clickable {
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).articleDao().delete(article)
}
},
imageVector = Icons.Filled.Close,
contentDescription = "Delete Icon",
tint = Color(0xff423a99)
)
}
}
}
}
item {
Text(
text = "${article.title}",
maxLines=4,
color = Color(0xff423a99),
style = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
//.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 15.dp)
.requiredWidth(width = 351.dp)
.requiredHeight(height = 100.dp))
}
}
LazyRow(
modifier = Modifier
//.align(alignment = Alignment.TopStart)
.offset(x = 3.dp,
y = 5.dp)
.requiredWidth(width = 80.dp)
.requiredHeight(height = 25.dp)
) {
item {
Row(
modifier = Modifier
.requiredWidth(width = 58.dp)
.requiredHeight(height = 22.dp)
) {
Image(
painter = painterResource(id = R.drawable.ic_comment),
contentDescription = "icon \"heart\"",
modifier = Modifier
.requiredWidth(width = 25.dp)
.requiredHeight(height = 22.dp))
Text(
text = "${countComm}",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 17.sp),
modifier = Modifier
//.align(alignment = Alignment.TopStart)
.offset(x = 5.dp,
y = 1.dp))
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,207 @@
package com.example.pmulabs.designElem.items
import androidx.compose.foundation.background
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.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CommentItem(modifier: Modifier = Modifier,comm : Comment,sharedViewModel: SharedViewModel) {
val context = LocalContext.current
var user by remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(comm.userId).collect { data ->
user=data
}
}
}
val argument = sharedViewModel.argument.value
var getUser by remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(argument.toString().toInt()).collect { data ->
getUser=data
}
}
}
var openDialog by remember { mutableStateOf(false) }
var text by remember { mutableStateOf(comm.text) }
if (openDialog) {
AlertDialog(
onDismissRequest = {
openDialog = false
text=comm.text
},
content = {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color.White)
.padding(16.dp),
) {
Text(
text = "Edit your comment",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 20.sp,
),
)
OutlinedTextField(
value = text,
onValueChange = {
text=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Comment") },
placeholder = { Text("Write comment...") },
minLines = 3,
maxLines = 3,
)
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
openDialog = false
comm.text=text
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).commentDao().update(comm)
}
},
modifier = Modifier
.padding(start=100.dp)
.fillMaxWidth(0.5f)
.height(40.dp)
) {
Text(text = "Edit", fontSize = 20.sp)
}
}
}
},
)
}
Row(
modifier = Modifier
.padding(3.dp)
.fillMaxWidth()
.background(Color.White)
)
{
Column(
modifier= Modifier
.padding(start = 10.dp,top=10.dp)
) {
Row() {
Text(
text = "${user?.nickname}",
color = Color(0xff423a99),
style = TextStyle(
textDecoration = TextDecoration.Underline,
fontSize = 17.sp,
fontWeight = FontWeight.Bold
),
)
if(getUser?.id==comm.userId) {
Icon(
modifier=Modifier
.requiredHeight(20.dp)
.clickable {
openDialog=true
},
imageVector = Icons.Filled.Edit,
contentDescription = "Update Icon",
tint = Color(0xff423a99)
)
Icon(
modifier=Modifier
.requiredHeight(20.dp)
.clickable {
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).commentDao().delete(comm)
}
},
imageVector = Icons.Filled.Close,
contentDescription = "Delete Icon",
tint = Color(0xff423a99)
)
}
}
Text(
text = "${comm.text}",
color = Color(0xff423a99),
style = TextStyle(fontSize = 15.sp, fontWeight = FontWeight.Bold),
)
Spacer(modifier = Modifier.padding(10.dp))
}
}
}

View File

@ -0,0 +1,220 @@
package com.example.pmulabs.designElem.items
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.fillMaxWidth
import androidx.compose.foundation.layout.height
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.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.res.painterResource
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.sp
import com.example.pmulabs.R
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TagItem(teg: Tag, modifier: Modifier = Modifier, onTagClick: () -> Unit,sharedViewModel: SharedViewModel) {
val context = LocalContext.current
val argument = sharedViewModel.argument.value
var getUser by remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(argument.toString().toInt()).collect { data ->
getUser = data
}
}
}
var openDialog by remember { mutableStateOf(false) }
var text by remember { mutableStateOf(teg.title) }
if (openDialog) {
AlertDialog(
onDismissRequest = {
openDialog = false
text = teg.title
},
content = {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color.White)
.padding(16.dp),
) {
Text(
text = "Edit your tag",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 20.sp,
),
)
OutlinedTextField(
value = text,
onValueChange = {
text = it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Tag") },
placeholder = { Text("Write tag...") },
minLines = 3,
maxLines = 3,
)
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
openDialog = false
teg.title = text
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).tagDao().update(teg)
}
},
modifier = Modifier
.padding(start = 100.dp)
.fillMaxWidth(0.5f)
.height(40.dp)
) {
Text(text = "Edit", fontSize = 20.sp)
}
}
}
},
)
}
Box(
modifier = modifier
.requiredWidth(width = 365.dp)
.requiredHeight(height = 58.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 365.dp)
.requiredHeight(height = 58.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xFFDBDBF1))
.clickable { onTagClick() }
)
Icon(
painter = painterResource(id = R.drawable.iconhashtag1),
tint = Color(0xff423a99),
contentDescription = "icon \"hashtag 1\"",
modifier = Modifier
.offset(
x = 20.dp,
y = 14.dp
)
.requiredWidth(width = 31.dp)
.requiredHeight(height = 29.dp)
)
Text(
text = "${teg.title}",
color = Color(0xff423a99),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.offset(
x = 64.dp,
y = 14.dp
)
)
if (getUser?.id == teg.userId) {
Icon(
modifier = Modifier
.requiredHeight(40.dp)
.offset(
x = 290.dp,
y = 9.dp
)
.clickable {
openDialog = true
},
imageVector = Icons.Filled.Edit,
contentDescription = "Update Icon",
tint = Color(0xff423a99)
)
Icon(
modifier = Modifier
.requiredHeight(40.dp)
.offset(
x = 320.dp,
y = 9.dp
)
.clickable {
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).tagDao().delete(teg)
}
},
imageVector = Icons.Filled.Close,
contentDescription = "Delete Icon",
tint = Color(0xff423a99)
)
}
}
}

View File

@ -0,0 +1,60 @@
package com.example.pmulabs.designElem.statDesign
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.requiredWidth
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.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.shape.CircleShape
@Composable
fun LeftCircles(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.requiredWidth(width = 250.dp)
.requiredHeight(height = 290.dp)
.rotate(degrees = -13.96f)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 166.4320068359375.dp,
y = 30.8746337890625.dp)
.requiredWidth(width = 122.dp)
.requiredHeight(height = 115.dp)
.clip(shape = CircleShape)
.background(color = Color(0xff423a99).copy(alpha = 0.7f)))
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = (-0.000030517578125).dp,
y = 145.57101440429688.dp)
.requiredWidth(width = 144.dp)
.requiredHeight(height = 140.dp)
.clip(shape = CircleShape)
.background(color = Color(0xff423a99).copy(alpha = 0.7f)))
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 74.10296630859375.dp,
y = 48.450347900390625.dp)
.requiredSize(size = 155.dp)
.clip(shape = CircleShape)
.background(color = Color(0xffb7b7e3).copy(alpha = 0.5f)))
}
}
@Preview(widthDp = 250, heightDp = 290)
@Composable
private fun LeftCirclesPreview() {
LeftCircles(Modifier)
}

View File

@ -0,0 +1,47 @@
package com.example.pmulabs.designElem.statDesign
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
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.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.pmulabs.R
@Composable
fun LogoMobile(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.requiredWidth(width = 250.dp)
.requiredHeight(height = 138.dp)
) {
Image(
painter = painterResource(id = R.drawable.ellipse7),
contentDescription = "Ellipse 7",
modifier = Modifier
.fillMaxWidth()
.requiredHeight(height = 115.dp)
)
Image(
painter = painterResource(id = R.drawable.ixbtcom_colored_logo1),
contentDescription = "IXBT.com_colored_logo 1",
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 0.dp)
.fillMaxWidth()
.requiredHeight(height = 113.dp))
}
}
@Preview(widthDp = 250, heightDp = 138)
@Composable
private fun LogoMobilePreview() {
LogoMobile(Modifier)
}

View File

@ -0,0 +1,59 @@
package com.example.pmulabs.designElem.statDesign
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.shape.CircleShape
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.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Composable
fun RightCircles(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.requiredWidth(width = 355.dp)
.requiredHeight(height = 267.dp)
.rotate(degrees = -6.33f)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 171.71197509765625.dp,
y = 17.979248046875.dp)
.requiredWidth(width = 192.dp)
.requiredHeight(height = 179.dp)
.clip(shape = CircleShape)
.background(color = Color(0xff423a99).copy(alpha = 0.7f)))
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 86.4691162109375.dp,
y = 75.193603515625.dp)
.requiredSize(size = 201.dp)
.clip(shape = CircleShape)
.background(color = Color(0xff423a99).copy(alpha = 0.7f)))
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.7720947265625.dp,
y = 122.24951171875.dp)
.requiredSize(size = 137.dp)
.clip(shape = CircleShape)
.background(color = Color(0xffb7b7e3).copy(alpha = 0.5f)))
}
}
@Preview(widthDp = 355, heightDp = 267)
@Composable
private fun RightCirclesPreview() {
RightCircles(Modifier)
}

View File

@ -0,0 +1,34 @@
package com.example.pmulabs.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.pmulabs.screensMobile.authScreens.EntryScreen
import com.example.pmulabs.screensMobile.authScreens.RegisterScreen
import com.example.pmulabs.screensMobile.authScreens.SplashScreen
import com.example.pmulabs.viewModels.SharedViewModel
fun NavGraphBuilder.authNavGraph(navController: NavHostController,sharedViewModel: SharedViewModel){
navigation(
route=Graph.AUTHENTICATION,
startDestination = AuthScreen.Splash.route
){
composable(route=AuthScreen.Splash.route){
SplashScreen(navController = navController, Modifier)
}
composable(route=AuthScreen.Entry.route){
EntryScreen(navController = navController, Modifier,sharedViewModel)
}
composable(route=AuthScreen.Register.route){
RegisterScreen(navController = navController, Modifier,sharedViewModel)
}
}
}
sealed class AuthScreen(val route: String){
object Splash : AuthScreen(route = "SPLASH")
object Entry : AuthScreen(route = "ENTRY")
object Register : AuthScreen(route="REGISTER")
}

View File

@ -0,0 +1,83 @@
package com.example.pmulabs.graphs
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.pmulabs.basecomponents.navigate.ARTICLE_ARGUMENT_KEY
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.CALENDAR_ARGUMENT_DATE
import com.example.pmulabs.basecomponents.navigate.SEARCHBYTAG_ARGUMENT_KEY
import com.example.pmulabs.basecomponents.navigate.SEARCH_ARGUMENT_TEXT
import com.example.pmulabs.screensMobile.ArticlePageScreen
import com.example.pmulabs.screensMobile.CoopScreen
import com.example.pmulabs.screensMobile.InfoScreen
import com.example.pmulabs.screensMobile.MainScreen
import com.example.pmulabs.screensMobile.ProfileScreen
import com.example.pmulabs.screensMobile.TagsScreen
import com.example.pmulabs.screensMobile.filterScreens.CalendarScreen
import com.example.pmulabs.screensMobile.filterScreens.SearchByTagScreen
import com.example.pmulabs.screensMobile.filterScreens.SearchScreen
import com.example.pmulabs.viewModels.SharedViewModel
@Composable
fun HomeNavGraph(navController: NavHostController,sharedViewModel: SharedViewModel){
NavHost(
navController = navController,
route = Graph.MAIN,
startDestination = BottomBarScreen.Main.route
){
composable(
route=BottomBarScreen.Main.route
){
MainScreen(navController,Modifier,sharedViewModel)
}
composable(
route=BottomBarScreen.SearchByTag.route,
arguments = listOf(navArgument(SEARCHBYTAG_ARGUMENT_KEY){
type= NavType.StringType
})
){
SearchByTagScreen(navController,Modifier,sharedViewModel)
}
composable(
route=BottomBarScreen.ArticlePage.route,
arguments = listOf(navArgument(ARTICLE_ARGUMENT_KEY){
type= NavType.StringType
})
){
ArticlePageScreen(navController,Modifier,sharedViewModel)
}
composable(
route=BottomBarScreen.Search.route,
arguments = listOf(navArgument(SEARCH_ARGUMENT_TEXT){
type= NavType.StringType
})
){
SearchScreen(navController,Modifier,sharedViewModel)
}
composable(
route=BottomBarScreen.Calendar.route,
arguments = listOf(navArgument(CALENDAR_ARGUMENT_DATE){
type= NavType.StringType
})
){
CalendarScreen(navController,Modifier,sharedViewModel)
}
composable(route=BottomBarScreen.Profile.route){
ProfileScreen(navController,Modifier,sharedViewModel)
}
composable(route=BottomBarScreen.Info.route){
InfoScreen(navController,Modifier)
}
composable(route=BottomBarScreen.Cooperation.route){
CoopScreen(navController,Modifier)
}
composable(route=BottomBarScreen.Categories.route){
TagsScreen(navController,Modifier,sharedViewModel)
}
}
}

View File

@ -0,0 +1,39 @@
package com.example.pmulabs.graphs
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.pmulabs.screensMobile.LoadScreen
import com.example.pmulabs.viewModels.SearchViewModel
import com.example.pmulabs.viewModels.SharedViewModel
const val USERID_ARGUMENT="userId"
@Composable
fun RootNavigationGraph(navController: NavHostController, searchViewModel: SearchViewModel, 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(searchViewModel = searchViewModel, 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"
}
}

View File

@ -0,0 +1,27 @@
package com.example.pmulabs.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.pmulabs.room.models.Article
import kotlinx.coroutines.flow.Flow
@Dao
interface ArticleDao {
@Query("select * from article ORDER BY publish_date ASC")
fun getAll(): Flow<List<Article>>
@Query("select * from article where article.id = :idArticle")
fun getArticleById(idArticle: Int): Flow<Article>
@Insert
suspend fun insert(article: Article)
@Update
suspend fun update(article: Article)
@Delete
suspend fun delete(article: Article)
}

View File

@ -0,0 +1,27 @@
package com.example.pmulabs.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.pmulabs.room.models.Comment
import kotlinx.coroutines.flow.Flow
@Dao
interface CommentDao {
@Query("select * from comment ORDER BY id DESC")
fun getAll(): Flow<List<Comment>>
@Query("select COUNT(*) from comment WHERE comment.text!='' AND comment.article_id= :idArticle")
fun getCountComment(idArticle : Int) : Int
@Insert
suspend fun insert(comment: Comment)
@Update
suspend fun update(comment: Comment)
@Delete
suspend fun delete(comment: Comment)
}

View File

@ -0,0 +1,30 @@
package com.example.pmulabs.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.pmulabs.room.models.Tag
import kotlinx.coroutines.flow.Flow
@Dao
interface TagDao {
@Query("select * from tag")
fun getAll(): Flow<List<Tag>>
@Query("select * from tag where tag.id = :idTag")
fun getTagById(idTag: Int): Flow<Tag>
@Query("select * from tag where tag.title = :nameTag")
fun getTagByName(nameTag: String): Flow<Tag>
@Insert
suspend fun insert(tag: Tag)
@Update
suspend fun update(tag: Tag)
@Delete
suspend fun delete(tag: Tag)
}

View File

@ -0,0 +1,39 @@
package com.example.pmulabs.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.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Query("select * from user")
fun getAll(): Flow<List<User>>
@Query("select * from user where user.id = :idUser")
fun getUserById(idUser: Int): Flow<User>
@Query("select * from comment WHERE comment.text!='' AND comment.user_id= :idUser")
fun getUserComms(idUser: Int): Flow<List<Comment>>
@Query("select * from article WHERE article.text!='' AND article.user_id= :idUser")
fun getUserArticles(idUser: Int): Flow<List<Article>>
@Query("select * from tag WHERE tag.title!='' AND tag.user_id= :idUser")
fun getUserTags(idUser: Int): Flow<List<Tag>>
@Insert
suspend fun insert(user: User)
@Update
suspend fun update(user: User)
@Delete
suspend fun delete(user: User)
}

View File

@ -0,0 +1,119 @@
package com.example.pmulabs.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.pmulabs.room.dao.ArticleDao
import com.example.pmulabs.room.dao.CommentDao
import com.example.pmulabs.room.dao.TagDao
import com.example.pmulabs.room.dao.UserDao
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.Date
@Database(entities = [User::class, Tag::class, Comment::class, Article::class], version = 5, exportSchema = false)
abstract class NewsPortalDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun tagDao(): TagDao
abstract fun commentDao(): CommentDao
abstract fun articleDao(): ArticleDao
companion object {
private const val DB_NAME: String = "news-portal"
@Volatile
private var INSTANCE: NewsPortalDatabase? = null
private suspend fun populateDatabase() {
INSTANCE?.let { database ->
val userDao = database.userDao()
val user1 = User(1, "LatinMisha","llmisha@gmail.com","user1","user")
val user2 = User(2, "Kasablanka","kasyul@gmail.com","user2","user")
val user3 = User(3, "Ilonherber","ihlon82@gmail.com","user3","user")
userDao.insert(user1)
userDao.insert(user2)
userDao.insert(user3)
val tagDao = database.tagDao()
val tag1 = Tag(1, "Тег_1",2)
val tag2 = Tag(2, "Тег_2",1)
val tag3 = Tag(3, "Тег_3",3)
val tag4 = Tag(4, "Тег_4",2)
val tag5 = Tag(5, "Тег_5",1)
val tag6 = Tag(6, "Тег_6",3)
tagDao.insert(tag1)
tagDao.insert(tag2)
tagDao.insert(tag3)
tagDao.insert(tag4)
tagDao.insert(tag5)
tagDao.insert(tag6)
val articleDao = database.articleDao()
val article1 = Article(1, "Заголовок 1","Текст статьи с заголовком 1", Date(2023,5,22).time,1,6)
val article2 = Article(2, "Заголовок 2","Текст статьи с заголовком 2", Date(2022,11,13).time,3,2)
val article3 = Article(3, "Заголовок 3","Текст статьи с заголовком 3", Date(2023,5,4).time,2,1)
val article4 = Article(4, "Заголовок 4","Текст статьи с заголовком 4", Date(2023,2,14).time,3,3)
val article5 = Article(5, "Заголовок 5","Текст статьи с заголовком 5", Date(2023,0,19).time,1,4)
val article6 = Article(6, "Заголовок 6","Текст статьи с заголовком 6", Date(2023,5,22).time,2,4)
val article7 = Article(7, "Заголовок 7","Текст статьи с заголовком 7", Date(2023,0,19).time,3,5)
val article8 = Article(8, "Заголовок 8","Текст статьи с заголовком 8", Date(2022,11,13).time,1,6)
articleDao.insert(article1)
articleDao.insert(article2)
articleDao.insert(article3)
articleDao.insert(article4)
articleDao.insert(article5)
articleDao.insert(article6)
articleDao.insert(article7)
articleDao.insert(article8)
val commentDao = database.commentDao()
val comment1 = Comment(1, "Текст комментария 1",1,8)
val comment2 = Comment(2, "Текст комментария 2",2,2)
val comment3 = Comment(3, "Текст комментария 3",3,3)
val comment4 = Comment(4, "Текст комментария 4",1,4)
val comment5 = Comment(5, "Текст комментария 5",2,1)
val comment6 = Comment(6, "Текст комментария 6",3,4)
val comment7 = Comment(7, "Текст комментария 7",1,6)
val comment8 = Comment(8, "Текст комментария 8",2,7)
val comment9 = Comment(9, "Текст комментария 9",3,1)
val comment10 = Comment(10, "Текст комментария 10",1,2)
val comment11 = Comment(11, "Текст комментария 11",2,3)
commentDao.insert(comment1)
commentDao.insert(comment2)
commentDao.insert(comment3)
commentDao.insert(comment4)
commentDao.insert(comment5)
commentDao.insert(comment6)
commentDao.insert(comment7)
commentDao.insert(comment8)
commentDao.insert(comment9)
commentDao.insert(comment10)
commentDao.insert(comment11)
}
}
fun getInstance(appContext: Context): NewsPortalDatabase {
return INSTANCE ?: synchronized(this) {
Room.databaseBuilder(
appContext,
NewsPortalDatabase::class.java,
DB_NAME
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
populateDatabase()
}
}
})
.build()
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,37 @@
package com.example.pmulabs.room.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@Entity(tableName = "article",
foreignKeys = [ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["user_id"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE),
ForeignKey(entity = Tag::class, parentColumns = ["id"], childColumns = ["tag_id"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE)])
data class Article(
@PrimaryKey(autoGenerate = true)
val id: Int?,
@ColumnInfo(name = "title")
var title: String,
@ColumnInfo(name = "text")
var text: String,
@ColumnInfo(name = "publish_date")
val publishDate: Long,
@ColumnInfo(name = "user_id")
val userId: Int,
@ColumnInfo(name = "tag_id")
var tagId: Int
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Article
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -0,0 +1,32 @@
package com.example.pmulabs.room.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@Entity(tableName = "comment",
foreignKeys = [ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["user_id"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE),
ForeignKey(entity = Article::class, parentColumns = ["id"], childColumns = ["article_id"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE)])
data class Comment(
@PrimaryKey(autoGenerate = true)
val id: Int?,
@ColumnInfo(name = "text")
var text: String,
@ColumnInfo(name = "user_id")
val userId: Int,
@ColumnInfo(name = "article_id")
val articleId: Int
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Comment
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -0,0 +1,31 @@
package com.example.pmulabs.room.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
@Entity(tableName = "tag",
foreignKeys = [ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["user_id"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE)],
indices = [Index(value = ["title"], unique = true)])
data class Tag(
@PrimaryKey(autoGenerate = true)
val id: Int?,
@ColumnInfo(name = "title")
var title: String,
@ColumnInfo(name = "user_id")
val userId: Int
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Tag
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -0,0 +1,35 @@
package com.example.pmulabs.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),
Index(value = ["nickname"], unique = true)
])
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int?,
@ColumnInfo(name = "nickname")
var nickname: String,
@ColumnInfo(name = "email")
var email: String,
@ColumnInfo(name = "password")
var password: String,
@ColumnInfo(name = "role")
val role: 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
}
}

View File

@ -0,0 +1,269 @@
package com.example.pmulabs.screensMobile
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.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
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.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.example.pmulabs.basecomponents.navigate.ARTICLE_ARGUMENT_KEY
import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.CommentItem
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.Date
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ArticlePageScreen(navController: NavController,modifier: Modifier = Modifier,sharedViewModel: SharedViewModel) {
val argument = sharedViewModel.argument.value
val context = LocalContext.current
var id=navController.currentBackStackEntry?.arguments?.getString(ARTICLE_ARGUMENT_KEY).toString()
var textComm by rememberSaveable { mutableStateOf("") }
var article by remember { mutableStateOf<Article?>(null) }
var tag by remember { mutableStateOf<Tag?>(null) }
var tagId = 0
if (id.toString() != "null") {
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getArticleById(id.toInt()).collect { data ->
article=data
tagId=data.tagId
NewsPortalDatabase.getInstance(context).tagDao().getTagById(tagId).collect { data ->
tag=data
}
}
}
}
}
val formatter = SimpleDateFormat("dd.MM.YY")
val publishDate=formatter.format(Date(article?.publishDate ?: 0))
val comms = remember { mutableStateListOf<Comment>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).commentDao().getAll().collect { data ->
comms.clear()
comms.addAll(data)
}
}
}
var getUser by remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(argument.toString().toInt()).collect { data ->
getUser=data
}
}
}
LazyColumn(
contentPadding= PaddingValues(top=105.dp, bottom = 50.dp,start=15.dp,end=15.dp),
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp)
.background(color = Color.White)
.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
item{
BackButton(modifier=Modifier
.clickable { navController.popBackStack()}
.offset(
y=0.dp
))
}
item {
Row(
modifier = Modifier
.requiredWidth(width = 350.dp)
.requiredHeight(height = 33.dp)
.offset(
y=0.dp
)
) {
Text(
text = "${publishDate}",
color = Color(0xff423a99),
style = MaterialTheme.typography.headlineMedium)
Text(
text = "#${tag?.title}",
color = Color(0xff423a99),
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier
.offset(x = 20.dp,
y = 0.dp))
}
}
item {
Text(
text = "${article?.title}",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 32.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.offset(x = 10.dp,
y = 0.dp)
.requiredWidth(width = 395.dp))
}
item {
Text(
text = "${article?.text}",
color = Color(0xff423a99),
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier
.offset(x = 5.dp,
y = 0.dp)
.requiredWidth(width = 375.dp))
}
item {
Box(
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 53.dp)
.offset(
y=0.dp
)
) {
Text(
text = "Comments:",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 32.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 15.dp,
y = 6.dp)
.requiredWidth(width = 395.dp)
.requiredHeight(height = 43.dp))
HorizontalDivider(
thickness=5.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xff423a99))), color = Color(0xff423a99)
)
HorizontalDivider(
thickness=5.dp,
modifier = Modifier
.align(alignment = Alignment.TopStart)
.border(BorderStroke(3.dp, Color(0xff423a99)))
.offset(
y = 53.dp), color = Color(0xff423a99)
)
}
}
item{
OutlinedTextField(
value = textComm,
onValueChange = {
textComm=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Comment") },
placeholder = { Text("Write comment...") },
minLines = 3,
maxLines = 3,
)
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
if(textComm.isNotEmpty()) {
var newComment =
Comment(null, textComm, getUser?.id.toString().toInt(), id.toInt())
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).commentDao().insert(newComment)
}
textComm = ""
}
},
modifier = Modifier
.padding(start = 230.dp)
.fillMaxWidth(0.9f)
.height(40.dp)
) {
Text(text = "Send", fontSize = 20.sp)
}
}
item{
comms.forEach{ comm ->
if(comm.articleId==article?.id && comm.text!="") {
Spacer(modifier = Modifier.padding(0.dp))
HorizontalDivider(
thickness=3.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xff423a99))), color = Color(0xff423a99)
)
CommentItem(comm = comm, sharedViewModel = sharedViewModel)
}
}
}
}
}

View File

@ -0,0 +1,200 @@
package com.example.pmulabs.screensMobile
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.PaddingValues
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
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.graphics.Color
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.sp
import androidx.navigation.NavController
@Composable
fun CoopScreen(navController: NavController,modifier: Modifier = Modifier) {
LazyColumn(
modifier = modifier
.background(Color.White),
contentPadding = PaddingValues(top =70.dp, bottom = 105.dp, start = 10.dp),
verticalArrangement = Arrangement.spacedBy(15.dp)
) {
item {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 275.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 21.810302734375.dp)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 253.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 253.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)))
Text(
text = " Мы предлагаем рекламные размещения под любой бюджет и аудиторию. \n\n На ресурсе самые лучшие посетители. У нас нет \"школьников\", \"мимо проходящих\", ботов, \"просто интересующихся\". Нас читают те, кто глубоко погружен в технику.\n\n У нас много трафика и нормальные цены за нормальную отдачу,а также рекламные возможности на любой бюджет. ",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 14.dp,
y = 34.189697265625.dp)
.requiredWidth(width = 368.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 44.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "О рекламе",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 24.dp,
y = 0.dp)
.requiredWidth(width = 210.dp)
.requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
item {
Box(
modifier = Modifier
.offset(x = 0.dp,
y = 11.dp)
.requiredWidth(width = 404.dp)
.requiredHeight(height = 420.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 21.dp)
.requiredWidth(width = 404.dp)
.requiredHeight(height = 420.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 420.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)))
Text(
text = buildAnnotatedString {
withStyle(style = SpanStyle(
color = Color(0xff423a99),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("КОММЕРЧЕСКИЙ ДИРЕКТОР:\n")}
withStyle(style = SpanStyle(
color = Color(0xff847fbe),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("Александр Воробьёв\nvorobiev@ixbt.com\n+7 (499) 519-00-95\n")}
withStyle(style = SpanStyle(
color = Color(0xff423a99),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("ДИРЕКТОР ПО РЕКЛАМЕ:\n")}
withStyle(style = SpanStyle(
color = Color(0xff847fbe),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("Владимир Сливко\nvslivko@ixbt.com\n+7 (916) 134-14-72\n")}
withStyle(style = SpanStyle(
color = Color(0xff423a99),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("ПРОДАКТ-МЕНЕДЖЕР:")}
withStyle(style = SpanStyle(
color = Color(0xff423a99),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append(" \n")}
withStyle(style = SpanStyle(
color = Color(0xff847fbe),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("Дарья Галиева\ndgalieva@ixbt.games\n+7 (499) 519-00-95\n")}
withStyle(style = SpanStyle(
color = Color(0xff423a99),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("ГЛАВНЫЙ РЕДАКТОР:\n")}
withStyle(style = SpanStyle(
color = Color(0xff847fbe),
fontSize = 15.sp,
fontWeight = FontWeight.Bold)) {append("Виталий Казунов\nlock@ixbt.com\n+7 (499) 519-00-95")}},
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 11.dp,
y = 10.dp)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 420.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 42.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 42.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Контакты",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 24.dp,
y = 0.dp)
.requiredWidth(width = 210.dp)
.requiredHeight(height = 42.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
}
}

View File

@ -0,0 +1,230 @@
package com.example.pmulabs.screensMobile
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.PaddingValues
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
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.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.sp
import androidx.navigation.NavController
@Composable
fun InfoScreen(navController: NavController,modifier: Modifier = Modifier) {
LazyColumn(
modifier = modifier
.background(Color.White),
contentPadding = PaddingValues(top =75.dp, bottom = 85.dp, start = 10.dp),
verticalArrangement = Arrangement.spacedBy(15.dp)
) {
item {
Box(
modifier = Modifier
.requiredWidth(width = 400.dp)
.requiredHeight(height = 309.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 22.dp)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 287.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 287.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)))
Text(
text=" iXBT.com — специализированный российский информационно-аналитический сайт с самыми актуальными новостями из сферы компьютерных и мобильных игр, развлекательной и интернет-индустрии, детальными обзорами персональных компьютеров, компьютерных комплектующих, периферийных устройств и техники для гейминга. Мы работаем для вас с 2007 года.\n\n Наш адрес: \"115201, Москва, Каширское шоссе, д. 22 кор. 3 стр. 2; тел. +7(499)519-00-95\"",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 12.dp,
y = 27.dp)
.requiredWidth(width = 364.dp)
.requiredHeight(height = 250.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 44.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "О сайте iXBT.com",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 24.dp,
y = 0.dp)
.requiredWidth(width = 210.dp)
.requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
item {
Box(
modifier = Modifier
.offset(x = 0.dp,
y = 15.dp)
.requiredWidth(width = 400.dp)
.requiredHeight(height = 200.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 23.dp)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 177.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 177.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)))
Text(
text = " Информация, размещенная на сайте iXBT.games, может быть изменена без предварительного уведомления. Все названия компаний, их логотипы и названия продуктов являются зарегистрированными торговыми марками соответствующих компаний.",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 12.dp,
y = 20.dp)
.requiredWidth(width = 364.dp)
.requiredHeight(height = 144.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 42.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 42.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Прежде всего",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 24.dp,
y = 0.dp)
.requiredWidth(width = 210.dp)
.requiredHeight(height = 42.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
item {
Box(
modifier = Modifier
.offset(x = 0.dp,
y = 25.dp)
.requiredWidth(width = 400.dp)
.requiredHeight(height = 782.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 0.dp)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 759.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 759.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)))
Text(
text = " Проект iXBT.games (Ай-Экс-Би-Ти Дот Геймс) является частью проекта iXBT.com (Ай-Экс-Би-Ти Дот Ком) - интернет-портала, освещающего новости ИТ-индустрии, технологий, техники, ПО и сети Интернет.\n\n Компания «Аспект Исследования и Публикации» (Aspect Research and Publishing, Ltd) имеет свидетельство о регистрации средства массовой информации iXBT.com (Ай-Экс-Би-Ти Дот Ком) за номером: ЭЛ № ФС 77 - 56280 от 28 ноября 2013 года. Свидетельство выдано Федеральной службой по надзору в сфере связи, информационных технологий и массовых коммуникаций в соответствии с Законом Российской Федерации от 27 декабря 1991 года.\n\n Ранее электронное периодическое издание iXBT.com (Ай-Экс-Би-Ти Дот Ком) было зарегистрировано за номером: ЭЛ № ФС77-22565 от 20 декабря 2005. СМИ перерегистрировано в связи со сменой учредителя 28 ноября 2013 года.\n\n Ранее электронное периодическое издание «Ай-Экс-Би-Ти дот ком / iXBT.com» («iXBT.com / Ай-Экс-Би-Ти дот ком») зарегистрировано Министерством Российской Федерации по делам печати, телерадиовещания и средств массовых коммуникаций — свидетельство ЭЛ № 77-6328 от 10 июня 2002 года. СМИ перерегистрировано в связи со сменой учредителя и изменением названия 20 декабря 2005 года.\n\n На все материалы, опубликованные на сайте iXBT.games, распространяются нормы законодательства о СМИ РФ.",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 12.dp,
y = 30.dp)
.requiredWidth(width = 368.dp)
.requiredHeight(height = 727.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 42.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 42.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Правовые основы деятельности сайта",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 24.dp,
y = 0.dp)
.requiredWidth(width = 354.dp)
.requiredHeight(height = 42.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
}
}

View File

@ -0,0 +1,281 @@
package com.example.pmulabs.screensMobile
import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerColors
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.unit.dp
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.pmulabs.basecomponents.navigate.BottomBar
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.SearchAppBar
import com.example.pmulabs.basecomponents.navigate.TopBar
import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.graphs.HomeNavGraph
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.SearchViewModel
import com.example.pmulabs.viewModels.SearchWidget
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
@Composable
fun MainScreen(navController: NavController, modifier: Modifier = Modifier,sharedViewModel: SharedViewModel){
val context = LocalContext.current
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
LazyColumn(
modifier=Modifier
.background(Color.White)
.fillMaxSize(),
contentPadding = PaddingValues(top=75.dp, bottom = 70.dp, start = 10.dp,end=10.dp),
verticalArrangement = Arrangement.spacedBy(15.dp)){
items(items = articles){ article ->
ArticleItem(article = article, sharedViewModel = sharedViewModel, onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))})
}
}
}
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoadScreen(navController: NavHostController=rememberNavController(), searchViewModel: SearchViewModel, sharedViewModel: SharedViewModel){
val searchWidgetState by searchViewModel.searchWidgetState
val searchTextState by searchViewModel.searchTextState
val formatter = SimpleDateFormat("dd-MMMM-YY")
val calendar = Calendar.getInstance()
calendar.set(2023, 0, 1) // add year, month (Jan), date
// set the initial date
val datePickerState = rememberDatePickerState(initialSelectedDateMillis = calendar.timeInMillis)
var showDatePicker by remember {
mutableStateOf(false)
}
var selectedDate by remember {
mutableLongStateOf(calendar.timeInMillis) // or use mutableStateOf(calendar.timeInMillis)
}
if (showDatePicker) {
DatePickerDialog(
colors= DatePickerColors(
containerColor = Color.White,
currentYearContentColor=Color(0xff423a99),
dateTextFieldColors = TextFieldDefaults.textFieldColors(
Color(0xff423a99),
containerColor = Color.White,
focusedLabelColor = Color(0xff423a99),
focusedPlaceholderColor = Color(0xff423a99),
focusedTrailingIconColor = Color(0xff423a99)
),
dayContentColor=Color(0xff423a99),
dayInSelectionRangeContainerColor=Color(0xff423a99),
dayInSelectionRangeContentColor=Color(0xff423a99),
disabledDayContentColor=Color(0xff423a99),
disabledSelectedDayContainerColor=Color(0xff423a99),
disabledSelectedDayContentColor=Color(0xff423a99),
disabledSelectedYearContainerColor=Color(0xff423a99),
disabledSelectedYearContentColor=Color(0xff423a99),
disabledYearContentColor=Color(0xff423a99),
dividerColor=Color(0xff423a99),
headlineContentColor=Color(0xff423a99),
navigationContentColor=Color(0xff423a99),
selectedDayContainerColor=Color(0xff423a99),
selectedDayContentColor=Color.White,
selectedYearContainerColor=Color(0xff423a99),
selectedYearContentColor=Color.White,
subheadContentColor=Color(0xff423a99),
titleContentColor=Color(0xff423a99),
todayContentColor=Color.White,
todayDateBorderColor=Color(0xff423a99),
weekdayContentColor=Color(0xff423a99),
yearContentColor=Color(0xff423a99)
),
onDismissRequest = {
showDatePicker = false
},
confirmButton = {
TextButton(
modifier=Modifier
.background(Color.White),
colors = ButtonColors(
contentColor = Color(0xff423a99),
containerColor=Color.Transparent,
disabledContainerColor=Color.Transparent,
disabledContentColor= Color.Transparent
),
onClick = {
showDatePicker = false
selectedDate = datePickerState.selectedDateMillis!!
Log.d("Selected date: ", formatter.format(Date(selectedDate)))
navController.navigate(BottomBarScreen.Calendar.passDate(formatter.format(Date(selectedDate)))){
popUpTo(BottomBarScreen.Main.route)
}
}) {
Text(text = "Confirm")
}
},
dismissButton = {
TextButton(
modifier=Modifier
.background(Color.White),
colors = ButtonColors(
contentColor = Color(0xff423a99),
containerColor=Color.Transparent,
disabledContainerColor=Color.Transparent,
disabledContentColor= Color.Transparent
),
onClick = {
showDatePicker = false
navController.navigate(BottomBarScreen.Main.route)
}) {
Text(text = "Cancel")
}
}
) {
DatePicker(
modifier= Modifier
.background(Color.White)
.clip(RoundedCornerShape(15.dp)),
colors = DatePickerColors(
containerColor = Color.White,
currentYearContentColor=Color(0xff423a99),
dateTextFieldColors = TextFieldDefaults.textFieldColors(
Color(0xff423a99),
containerColor = Color.White,
focusedLabelColor = Color(0xff423a99),
focusedPlaceholderColor = Color(0xff423a99),
focusedTrailingIconColor = Color(0xff423a99)
),
dayContentColor=Color(0xff423a99),
dayInSelectionRangeContainerColor=Color(0xff423a99),
dayInSelectionRangeContentColor=Color(0xff423a99),
disabledDayContentColor=Color(0xff423a99),
disabledSelectedDayContainerColor=Color(0xff423a99),
disabledSelectedDayContentColor=Color(0xff423a99),
disabledSelectedYearContainerColor=Color(0xff423a99),
disabledSelectedYearContentColor=Color(0xff423a99),
disabledYearContentColor=Color(0xff423a99),
dividerColor=Color(0xff423a99),
headlineContentColor=Color(0xff423a99),
navigationContentColor=Color(0xff423a99),
selectedDayContainerColor=Color(0xff423a99),
selectedDayContentColor=Color.White,
selectedYearContainerColor=Color(0xff423a99),
selectedYearContentColor=Color.White,
subheadContentColor=Color(0xff423a99),
titleContentColor=Color(0xff423a99),
todayContentColor=Color.White,
todayDateBorderColor=Color(0xff423a99),
weekdayContentColor=Color(0xff423a99),
yearContentColor=Color(0xff423a99)
),
state = datePickerState
)
}
}
Scaffold(
bottomBar = { BottomBar(navController = navController) },
topBar = { MainAppBar(searchWidgetState= searchWidgetState,
searchTextState= searchTextState,
onTextChange= { searchViewModel.updateSearchTextState(newValue = it)
if(it!="") {
navController.navigate(BottomBarScreen.Search.passText(it))
}},
onCloseClicked= {
searchViewModel.updateSearchWidgetState(newValue = SearchWidget.CLOSED)
navController.navigate(BottomBarScreen.Main.route)
},
onSearchClicked= {
navController.navigate(BottomBarScreen.Search.passText(it))
},
onSearchTriggered= {
searchViewModel.updateSearchWidgetState(newValue = SearchWidget.OPENED)
},
onCalendarTriggered = {
showDatePicker = true
})}
) {
Modifier
.padding(it)
HomeNavGraph(navController = navController,sharedViewModel)
}
}
@Composable
fun MainAppBar(
searchWidgetState: SearchWidget,
searchTextState: String,
onTextChange: (String) -> Unit,
onCloseClicked: () -> Unit,
onSearchClicked: (String) -> Unit,
onSearchTriggered: () -> Unit,
onCalendarTriggered: () -> Unit
) {
when (searchWidgetState) {
SearchWidget.CLOSED -> {
TopBar(
onSearchClicked = onSearchTriggered,
onCalendarClicked = onCalendarTriggered
)
}
SearchWidget.OPENED -> {
SearchAppBar(
text = searchTextState,
onTextChange = onTextChange,
onCloseClicked = onCloseClicked,
onSearchClicked = onSearchClicked
)
}
}
}

View File

@ -0,0 +1,901 @@
package com.example.pmulabs.screensMobile
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
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.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
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.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
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.sp
import androidx.compose.ui.unit.toSize
import androidx.navigation.NavController
import com.example.pmulabs.R
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.designElem.elem.ValidateEmail
import com.example.pmulabs.designElem.elem.isValidEmail
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.room.models.Comment
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.Date
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProfileScreen(navController: NavController, modifier: Modifier = Modifier,sharedViewModel: SharedViewModel) {
val argument = sharedViewModel.argument.value
val context = LocalContext.current
var openDialogUser by remember { mutableStateOf(false) }
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var nickname by remember { mutableStateOf("") }
var getUser by remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(argument.toString().toInt()).collect { data ->
getUser = data
email=data.email
password=data.password
nickname=data.nickname
}
}
}
val getComms = remember { mutableStateListOf<Comment>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserComms(argument.toString().toInt()).collect { data ->
getComms.clear()
getComms.addAll(data)
}
}
}
val getArticles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserArticles(argument.toString().toInt()).collect { data ->
getArticles.clear()
getArticles.addAll(data)
}
}
}
val getTags = remember { mutableStateListOf<Tag>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserTags(argument.toString().toInt()).collect { data ->
getTags.clear()
getTags.addAll(data)
}
}
}
//список тэгов
val tags = remember { mutableStateListOf<Tag>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).tagDao().getAll().collect { data ->
tags.clear()
tags.addAll(data)
}
}
}
//список названий тэгов
var tagsNames= remember { mutableStateListOf<String>() }
tags.forEach{teg ->
if(!tagsNames.contains(teg.title)) {
tagsNames.add(teg.title)
}
}
var openDialog by remember { mutableStateOf(false) }
var text by remember { mutableStateOf("") }
var title by remember { mutableStateOf("") }
var tagId by remember { mutableStateOf(0) }
//переменные для dropdown
var expanded by remember { mutableStateOf(false) }
val suggestions = tagsNames
var selectedText by remember { mutableStateOf("") }
var textfieldSize by remember { mutableStateOf(Size.Zero)}
val icon = if (expanded)
Icons.Filled.ArrowDropUp
else
Icons.Filled.ArrowDropDown
if (openDialog) {
AlertDialog(
onDismissRequest = {
openDialog = false
text=""
title=""
},
content = {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color.White)
.padding(16.dp),
) {
Text(
text = "Add your article",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 20.sp,
),
)
Box() {
OutlinedTextField(
value = selectedText,
onValueChange = { selectedText = it },
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.onGloballyPositioned { coordinates ->
textfieldSize = coordinates.size.toSize()
},
label = {Text("Select Tag")},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
trailingIcon = {
Icon(icon,"List of tags",
Modifier.clickable { expanded = !expanded })
}
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier
.width(with(LocalDensity.current){textfieldSize.width.toDp()})
) {
suggestions.forEach { label ->
DropdownMenuItem(
text= {Text(text=label)},
onClick = { selectedText = label
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).tagDao().getTagByName(selectedText).collect{ tag ->
tagId=tag?.id.toString().toInt()
}
}}
)
}
}
}
OutlinedTextField(
value = title,
onValueChange = {
title=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Article Title") },
placeholder = { Text("Write title of article...") },
minLines = 3,
maxLines = 3,
)
OutlinedTextField(
value = text,
onValueChange = {
text=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Article Text") },
placeholder = { Text("Write article text...") },
minLines = 3,
maxLines = 3,
)
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
openDialog = false
if(title.isNotEmpty() && text.isNotEmpty() && tagId!=null) {
val newArticle = Article(
null, title, text,
Date().time, getUser?.id.toString().toInt(), tagId
)
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).articleDao()
.insert(newArticle)
}
}
},
modifier = Modifier
.padding(start = 100.dp)
.fillMaxWidth(0.5f)
.height(40.dp)
) {
Text(text = "Add", fontSize = 20.sp)
}
}
}
},
)
}
if (openDialogUser) {
AlertDialog(
onDismissRequest = {
openDialogUser = false
email=getUser?.email.toString()
password=getUser?.password.toString()
nickname=getUser?.nickname.toString()
},
content = {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color.White)
.padding(16.dp),
) {
Text(
text = "Edit your data",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 20.sp,
),
)
ValidateEmail(email, {email=it} )
OutlinedTextField(
value = password,
onValueChange = {
password=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Password") },
placeholder = { Text("Write password...") },
minLines = 1,
maxLines = 1,
)
OutlinedTextField(
value = nickname,
onValueChange = {
nickname=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Nickname") },
placeholder = { Text("Write nickname...") },
minLines = 1,
maxLines = 1,
)
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
openDialogUser = false
if(password.isNotEmpty() && email.isNotEmpty() && isValidEmail(email) && nickname.isNotEmpty()) {
getUser?.password=password
getUser?.email=email
getUser?.nickname=nickname
CoroutineScope(Dispatchers.IO).launch {
getUser?.let {
NewsPortalDatabase.getInstance(context).userDao()
.update(it)
}
}
}
},
modifier = Modifier
.padding(start = 100.dp)
.fillMaxWidth(0.5f)
.height(40.dp)
) {
Text(text = "Edit", fontSize = 20.sp)
}
}
}
},
)
}
LazyColumn(
contentPadding= PaddingValues(top=5.dp, bottom = 320.dp),
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp)
.background(color = Color.White)
) {
item {
Box(
modifier = Modifier
.offset(
x = 106.dp,
y = 95.dp
)
.requiredWidth(width = 200.dp)
.requiredHeight(height = 310.dp)
) {
Image(
painter = painterResource(id = R.drawable.ixbtcom_colored_logo1),
contentDescription = "Ellipse 8",
modifier = Modifier
.requiredSize(size = 200.dp)
.clip(shape = CircleShape))
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 215.dp
)
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xffdbdbf1)))
Text(
text = "${getUser?.nickname}",
color = Color(0xff423a99),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 266.dp
)
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xffdbdbf1)))
Text(
text = "${getUser?.email}",
color = Color(0xff423a99),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 317.dp
)
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Add Article!",
color = Color(0xffdbdbf1),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically)
.clickable { openDialog = true })
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 368.dp
)
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Edit my Data",
color = Color(0xffdbdbf1),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.requiredWidth(width = 200.dp)
.requiredHeight(height = 44.dp)
.wrapContentHeight(align = Alignment.CenterVertically)
.clickable { openDialogUser = true })
}
}
}
item {
Box(
modifier = Modifier
.offset(
x = 9.dp,
y = 220.dp
)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 182.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 27.1240234375.dp
)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 155.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 155.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(
border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)
)
)
LazyColumn(
contentPadding = PaddingValues(
top = 28.dp,
bottom = 0.dp,
start = 10.dp,
end = 10.dp
),
verticalArrangement = Arrangement.spacedBy(1.dp)
) {
if (!getComms.isEmpty()) {
items(items = getComms) { comment ->
Spacer(modifier = Modifier.padding(5.dp))
Text(
text = "${comment.text}",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.clickable {
navController.navigate(
BottomBarScreen.ArticlePage.passId(
comment.articleId.toString()
)
)
}
)
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider(
thickness=3.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xffdbdbf1))), color = Color(0xffdbdbf1)
)
}
}
else{
item {
Text(
text = "Комментариев пока нет!",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.align(alignment = Alignment.TopStart)
)
}
}
}
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Comments:",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 24.dp,
y = 0.dp
)
.requiredWidth(width = 210.dp)
.requiredHeight(height = 54.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
item {
Spacer(modifier = Modifier.padding(10.dp))
Box(
modifier = Modifier
.offset(
x = 9.dp,
y = 220.dp
)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 182.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 27.1240234375.dp
)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 155.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 155.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(
border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)
)
)
LazyColumn(
contentPadding = PaddingValues(
top = 28.dp,
bottom = 0.dp,
start = 10.dp,
end = 10.dp
),
verticalArrangement = Arrangement.spacedBy(1.dp)
) {
if (!getArticles.isEmpty()) {
items(items = getArticles) { article ->
Spacer(modifier = Modifier.padding(5.dp))
Text(
text = "${article.title}",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.clickable {
navController.navigate(
BottomBarScreen.ArticlePage.passId(
article.id.toString()
)
)
}
)
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider(
thickness=3.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xffdbdbf1))), color = Color(0xffdbdbf1)
)
}
}
else{
item {
Text(
text = "Статей пока нет!",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.align(alignment = Alignment.TopStart)
)
}
}
}
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Articles:",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 24.dp,
y = 0.dp
)
.requiredWidth(width = 210.dp)
.requiredHeight(height = 54.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
item {
Spacer(modifier = Modifier.padding(10.dp))
Box(
modifier = Modifier
.offset(
x = 9.dp,
y = 220.dp
)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 182.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 27.1240234375.dp
)
.requiredWidth(width = 393.dp)
.requiredHeight(height = 155.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 155.dp)
.clip(shape = RoundedCornerShape(5.dp))
.background(color = Color.White)
.border(
border = BorderStroke(3.dp, Color(0xffdbdbf1)),
shape = RoundedCornerShape(5.dp)
)
)
LazyColumn(
contentPadding = PaddingValues(
top = 28.dp,
bottom = 0.dp,
start = 10.dp,
end = 10.dp
),
verticalArrangement = Arrangement.spacedBy(1.dp)
) {
if (!getTags.isEmpty()) {
items(items = getTags) { tag ->
Spacer(modifier = Modifier.padding(5.dp))
Text(
text = "${tag.title}",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.clickable {navController.navigate(BottomBarScreen.SearchByTag.passId(tag.id.toString()))}
)
Spacer(modifier = Modifier.padding(5.dp))
HorizontalDivider(
thickness=3.dp,
modifier = Modifier
.border(BorderStroke(3.dp, Color(0xffdbdbf1))), color = Color(0xffdbdbf1)
)
}
}
else{
item {
Text(
text = "Тэгов пока нет!",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.align(alignment = Alignment.TopStart)
)
}
}
}
}
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 393.dp)
.requiredHeight(height = 54.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99)))
Text(
text = "Tags:",
color = Color.White,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 24.dp,
y = 0.dp
)
.requiredWidth(width = 210.dp)
.requiredHeight(height = 54.dp)
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
}
}
}

View File

@ -0,0 +1,206 @@
package com.example.pmulabs.screensMobile
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.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
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.setValue
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.sp
import androidx.navigation.NavController
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.designElem.items.TagItem
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Tag
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TagsScreen(navController: NavController, modifier: Modifier = Modifier,sharedViewModel: SharedViewModel){
val context = LocalContext.current
val tags = remember { mutableStateListOf<Tag>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).tagDao().getAll().collect { data ->
tags.clear()
tags.addAll(data)
}
}
}
val argument = sharedViewModel.argument.value
var getUser by remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao()
.getUserById(argument.toString().toInt()).collect { data ->
getUser=data
}
}
}
var openDialog by remember { mutableStateOf(false) }
var text by remember { mutableStateOf("") }
if (openDialog) {
AlertDialog(
onDismissRequest = {
openDialog = false
text = ""
},
content = {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color.White)
.padding(16.dp),
) {
Text(
text = "Add your tag",
color = Color(0xff423a99),
style = TextStyle(
fontSize = 20.sp,
),
)
OutlinedTextField(
value = text,
onValueChange = {
text = it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White,
focusedIndicatorColor = Color(0xff423a99),
focusedLabelColor = Color(0xff423a99),
unfocusedIndicatorColor = Color(0xff423a99),
unfocusedLabelColor = Color(0xff423a99)
),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp),
label = { Text("Tag") },
placeholder = { Text("Write tag...") },
minLines = 3,
maxLines = 3,
)
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
openDialog = false
if(text.isNotEmpty()) {
val newTag = Tag(null, text, getUser?.id.toString().toInt())
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).tagDao()
.insert(newTag)
}
}
},
modifier = Modifier
.padding(start = 100.dp)
.fillMaxWidth(0.5f)
.height(40.dp)
) {
Text(text = "Add", fontSize = 20.sp)
}
}
}
},
)
}
LazyColumn(
modifier= Modifier
.background(Color.White)
.fillMaxSize(),
contentPadding = PaddingValues(top =75.dp, bottom = 10.dp, start = 25.dp,end=25.dp),
verticalArrangement = Arrangement.spacedBy(15.dp)){
item{
Box(
modifier = modifier
.requiredWidth(width = 365.dp)
.requiredHeight(height = 58.dp)
) {
Box(
modifier = Modifier
.requiredWidth(width = 365.dp)
.requiredHeight(height = 58.dp)
.clip(shape = RoundedCornerShape(15.dp))
.background(color = Color(0xff423a99))
.clickable { openDialog=true }
)
Text(
text = "Add Tag!",
color = Color(0xFFFFFFFF),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier
.offset(
x = 135.dp,
y = 14.dp
)
)
}
}
items(items = tags){ tag ->
TagItem(
teg = tag,
sharedViewModel = sharedViewModel,
onTagClick = {navController.navigate(BottomBarScreen.SearchByTag.passId(tag.id.toString()))}
)
}
}
}

View File

@ -0,0 +1,249 @@
package com.example.pmulabs.screensMobile.authScreens
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.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
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.draw.rotate
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.example.pmulabs.designElem.elem.ValidateEmail
import com.example.pmulabs.designElem.elem.isValidEmail
import com.example.pmulabs.designElem.statDesign.LeftCircles
import com.example.pmulabs.designElem.statDesign.LogoMobile
import com.example.pmulabs.designElem.statDesign.RightCircles
import com.example.pmulabs.graphs.AuthScreen
import com.example.pmulabs.graphs.Graph
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@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<User>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao().getAll().collect { data ->
users.clear()
users.addAll(data)
}
}
}
val argument = sharedViewModel.argument.value
var passwordVisibility by rememberSaveable { mutableStateOf(false) }
val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex()
Box(
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp)
.background(color = Color.White)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 128.dp,
y = 730.dp
)
.requiredWidth(width = 381.dp)
.requiredHeight(height = 268.dp)
.rotate(degrees = 8.33f)
) {
RightCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = (-111.28436279296875).dp,
y = (-96.86965942382812).dp
)
.requiredWidth(width = 250.dp)
.requiredHeight(height = 290.dp)
.rotate(degrees = 12.96f)
) {
LeftCircles()
}
}
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.8f)
.clip(RoundedCornerShape(15.dp))
.background(Color.Transparent)
.padding(10.dp)
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.Transparent), contentAlignment = Alignment.TopCenter
) {
LogoMobile(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.fillMaxWidth()
.requiredHeight(height = 131.dp)
)
}
Text(
text = "Please, Sign In to your account",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp
),
modifier = modifier
.requiredWidth(width = 436.dp)
.requiredHeight(height = 27.dp)
)
Spacer(modifier = Modifier.padding(10.dp))
Column(horizontalAlignment = Alignment.CenterHorizontally) {
ValidateEmail(emailValue, {emailValue=it} )
Spacer(modifier = Modifier.padding(3.dp))
TextField(
value = passwordValue,
onValueChange = { passwordValue = it },
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White
),
modifier = modifier
.requiredWidth(width = 269.dp)
.requiredHeight(height = 53.dp)
.shadow(shape = RoundedCornerShape(40.dp), elevation = 5.dp)
.clip(shape = RoundedCornerShape(40.dp)),
label = { Text("Password") },
singleLine = true,
placeholder = { Text("Password") },
visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = {
val image = if (passwordVisibility)
Icons.Filled.Visibility
else Icons.Filled.VisibilityOff
val description =
if (passwordVisibility) "Hide password" else "Show password"
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
Icon(imageVector = image, description)
}
}
)
Spacer(modifier = Modifier.padding(10.dp))
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
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())) {
}
}
}
}
},
modifier = Modifier
.fillMaxWidth(0.5f)
.height(50.dp)
) {
Text(text = "Sign In", fontSize = 20.sp)
}
Spacer(modifier = Modifier.padding(3.dp))
Text(
text = "Don't have an account yet? Sign Up",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp
),
modifier = Modifier
.fillMaxSize()
.offset(
x = 0.dp,
y = 75.dp
)
.clickable {
navController.navigate(route = AuthScreen.Register.route)
{
popUpTo(AuthScreen.Splash.route)
}
}
)
Spacer(modifier = Modifier.padding(20.dp))
}
}
}
}
}

View File

@ -0,0 +1,480 @@
package com.example.pmulabs.screensMobile.authScreens
import android.util.Log
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.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
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.draw.rotate
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.example.pmulabs.designElem.elem.ValidateEmail
import com.example.pmulabs.designElem.elem.isValidEmail
import com.example.pmulabs.designElem.statDesign.LeftCircles
import com.example.pmulabs.designElem.statDesign.LogoMobile
import com.example.pmulabs.designElem.statDesign.RightCircles
import com.example.pmulabs.graphs.AuthScreen
import com.example.pmulabs.graphs.Graph
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.User
import com.example.pmulabs.viewModels.SharedViewModel
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 nicknameValue by rememberSaveable { mutableStateOf("") }
val context = LocalContext.current
val users = remember { mutableStateListOf<User>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).userDao().getAll().collect { data ->
users.clear()
users.addAll(data)
}
}
}
var passwordVisibility by rememberSaveable { mutableStateOf(false) }
val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex()
Box(
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp)
.background(color = Color.White)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 128.dp,
y = 730.dp
)
.requiredWidth(width = 381.dp)
.requiredHeight(height = 268.dp)
.rotate(degrees = 8.33f)
) {
RightCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = (-111.28436279296875).dp,
y = (-96.86965942382812).dp
)
.requiredWidth(width = 250.dp)
.requiredHeight(height = 290.dp)
.rotate(degrees = 12.96f)
) {
LeftCircles()
}
}
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.8f)
.clip(RoundedCornerShape(15.dp))
.background(Color.Transparent)
.padding(10.dp)
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.Transparent), contentAlignment = Alignment.TopCenter
) {
LogoMobile(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.fillMaxWidth()
.requiredHeight(height = 131.dp)
)
}
Text(
text = "Please, Sign In to your account",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp
),
modifier = modifier
.requiredWidth(width = 436.dp)
.requiredHeight(height = 27.dp)
)
Spacer(modifier = Modifier.padding(10.dp))
Column(horizontalAlignment = Alignment.CenterHorizontally) {
TextField(
value = nicknameValue,
onValueChange = {
nicknameValue=it
},
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White
),
modifier = Modifier
.requiredWidth(width = 269.dp)
.requiredHeight(height = 53.dp)
.shadow(shape = RoundedCornerShape(40.dp), elevation = 5.dp)
.clip(shape = RoundedCornerShape(40.dp)),
label = { Text("Nickname") },
placeholder = { Text("Nickname") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
singleLine = true,
)
Spacer(modifier = Modifier.padding(3.dp))
ValidateEmail(emailValue, {emailValue=it} )
Spacer(modifier = Modifier.padding(3.dp))
TextField(
value = passwordValue,
onValueChange = { passwordValue = it },
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.White
),
modifier = modifier
.requiredWidth(width = 269.dp)
.requiredHeight(height = 53.dp)
.shadow(shape = RoundedCornerShape(40.dp), elevation = 5.dp)
.clip(shape = RoundedCornerShape(40.dp)),
label = { Text("Password") },
singleLine = true,
placeholder = { Text("Password") },
visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = {
val image = if (passwordVisibility)
Icons.Filled.Visibility
else Icons.Filled.VisibilityOff
val description =
if (passwordVisibility) "Hide password" else "Show password"
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
Icon(imageVector = image, description)
}
}
)
Spacer(modifier = Modifier.padding(10.dp))
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {
var isExist = false;
if (passwordValue.isNotEmpty() && isValidEmail(emailValue) && nicknameValue.isNotEmpty()) {
users.forEach { user ->
if (user.email == emailValue || user.nickname == nicknameValue) {
Log.d("User already exist. User id: ", user.id.toString())
isExist = true
}
}
if (!isExist) {
var newUser = User(null, nicknameValue, emailValue, passwordValue, "user")
CoroutineScope(Dispatchers.IO).launch {
NewsPortalDatabase.getInstance(context).userDao().insert(newUser)
NewsPortalDatabase.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()
)
)
}
}
}
}
}
}
}
},
modifier = Modifier
.fillMaxWidth(0.5f)
.height(50.dp)
) {
Text(text = "Sign Up", fontSize = 20.sp)
}
Spacer(modifier = Modifier.padding(0.dp))
Text(
text = "Do you have an account? Sign In",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp
),
modifier = Modifier
.fillMaxSize()
.offset(
x = 0.dp,
y = 75.dp
)
.clickable {
navController.navigate(route = AuthScreen.Entry.route)
{
popUpTo(AuthScreen.Splash.route)
}
}
)
Spacer(modifier = Modifier.padding(20.dp))
}
}
}
}
}
/*
@Composable
fun RegisterScreen(navController: NavController,modifier: Modifier = Modifier) {
Box(
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp)
.background(color = Color.White)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = (-17).dp,
y = 329.dp
)
.requiredWidth(width = 436.dp)
.requiredHeight(height = 325.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 69.1444091796875.dp,
y = 122.9124755859375.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 61.dp)
) {
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 69.1444091796875.dp,
y = 193.824951171875.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 61.dp)
) {
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 68.dp,
y = 52.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 61.dp)
) {
}
Text(
textAlign = TextAlign.Center,
text = buildAnnotatedString {
withStyle(style = SpanStyle(
color = Color(0xff7d7dbd),
fontSize = 20.sp)) {append("Please, ")}
withStyle(style = SpanStyle(
color = Color(0xff7d7dbd),
fontSize = 20.sp,
fontWeight = FontWeight.Bold)) {append("Sign Up")}},
modifier = Modifier
.fillMaxSize())
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 128.dp,
y = 730.dp
)
.requiredWidth(width = 381.dp)
.requiredHeight(height = 268.dp)
.rotate(degrees = 8.33f)
) {
RightCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = (-111.28436279296875).dp,
y = (-96.86965942382812).dp
)
.requiredWidth(width = 250.dp)
.requiredHeight(height = 290.dp)
) {
Box(
modifier = Modifier
.rotate(degrees = 12.96f)
) {
LeftCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 140.35101318359375.dp,
y = 152.06341552734375.dp
)
.requiredWidth(width = 66.dp)
.requiredHeight(height = 27.dp)
) {
BackButton(modifier=Modifier
.clickable { navController.navigate(route = AuthScreen.Entry.route){
popUpTo(AuthScreen.Splash.route)
} })}
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 50.dp,
y = 681.dp
)
.requiredWidth(width = 308.dp)
.requiredHeight(height = 127.dp)
) {
Text(
text = "Do you have an account? ",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp),
modifier = Modifier
.fillMaxSize()
.offset(
x = 0.dp,
y = 75.dp
))
Text(
text = "Sign In",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.fillMaxSize()
.offset(
x = 0.dp,
y = 95.dp
)
.clickable { navController.navigate(route = AuthScreen.Entry.route)
{
popUpTo(AuthScreen.Splash.route)
}})
Box(
modifier = Modifier
.requiredWidth(width = 308.dp)
.requiredHeight(height = 82.dp)
) {
ButtonCustom(name = "Sign Up",modifier = Modifier
.fillMaxSize()
.clickable { navController.navigate(route = Graph.MAIN){
popUpTo(Graph.MAIN)
} }
)
}
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 57.dp,
y = 165.dp
)
.requiredWidth(width = 302.dp)
.requiredHeight(height = 140.dp)
) {
LogoMobile(modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 9.dp
)
.fillMaxWidth()
.requiredHeight(height = 131.dp))
}
}
}*/

View File

@ -0,0 +1,143 @@
package com.example.pmulabs.screensMobile.authScreens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
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.rotate
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.sp
import androidx.navigation.NavController
import com.example.pmulabs.designElem.statDesign.LeftCircles
import com.example.pmulabs.designElem.statDesign.LogoMobile
import com.example.pmulabs.designElem.statDesign.RightCircles
import com.example.pmulabs.graphs.AuthScreen
@Composable
fun SplashScreen(navController: NavController,modifier: Modifier = Modifier) {
Box(
modifier = modifier
.requiredWidth(width = 412.dp)
.requiredHeight(height = 915.dp)
.background(color = Color.White)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 128.dp,
y = 730.dp
)
.requiredWidth(width = 381.dp)
.requiredHeight(height = 268.dp)
.rotate(degrees = 8.33f)
) {
RightCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = (-111.28436279296875).dp,
y = (-96.86965942382812).dp
)
.requiredWidth(width = 250.dp)
.requiredHeight(height = 290.dp)
.rotate(degrees = 12.96f)
) {
LeftCircles()
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 200.dp
)
.requiredWidth(width = 412.dp)
.requiredHeight(height = 190.dp)
) {
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 62.00006103515625.dp,
y = 50.dp
)
.requiredWidth(width = 302.dp)
.requiredHeight(height = 140.dp)
) {
LogoMobile(modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 9.dp
)
.fillMaxWidth()
.requiredHeight(height = 131.dp))
}
Text(
text = "Welcome to",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 48.sp,
fontWeight = FontWeight.Bold),
modifier = Modifier
.fillMaxSize())
}
Box(
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 649.2312622070312.dp
)
.requiredWidth(width = 412.dp)
.requiredHeight(height = 92.dp)
) {
Text(
text = "Best app with game news!",
color = Color(0xff7d7dbd),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 20.sp),
modifier = Modifier
.fillMaxSize())
Button(
colors = ButtonColors(
containerColor = Color(0xff423a99),
disabledContainerColor = Color(0xff423a99),
contentColor = Color.White,
disabledContentColor = Color.White
),
onClick = {navController.navigate(route = AuthScreen.Entry.route)},
modifier = Modifier
.fillMaxWidth(0.5f)
.height(50.dp)
.align(alignment = Alignment.TopStart)
.offset(
x = 106.5.dp,
y = 31.31878662109375.dp
)
) {
Text(text = "Get Started", fontSize = 20.sp)
}
}
}
}

View File

@ -0,0 +1,68 @@
package com.example.pmulabs.screensMobile.filterScreens
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.CALENDAR_ARGUMENT_DATE
import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
@Composable
fun CalendarScreen(navController: NavController, modifier: Modifier = Modifier,sharedViewModel: SharedViewModel){
val context = LocalContext.current
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
var date=navController.currentBackStackEntry?.arguments?.getString(CALENDAR_ARGUMENT_DATE).toString()
Log.d("date: ",date)
val formatter = SimpleDateFormat("dd-MMMM-YY")
LazyColumn(
modifier= Modifier
.background(Color.White)
.fillMaxSize(),
contentPadding = PaddingValues(top =75.dp, bottom = 10.dp, start = 10.dp,end=10.dp),
verticalArrangement = Arrangement.spacedBy(1.dp)){
item{
BackButton(modifier=Modifier
.clickable { navController.popBackStack()})
}
items(items = articles){ article ->
val publishDate=formatter.format(article.publishDate)
if(publishDate==date) {
ArticleItem(
article = article,
sharedViewModel=sharedViewModel,
onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))}
)
}
}
}
}

View File

@ -0,0 +1,60 @@
package com.example.pmulabs.screensMobile.filterScreens
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.SEARCHBYTAG_ARGUMENT_KEY
import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun SearchByTagScreen(navController: NavController, modifier: Modifier = Modifier,sharedViewModel: SharedViewModel){
val context = LocalContext.current
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
var id=navController.currentBackStackEntry?.arguments?.getString(SEARCHBYTAG_ARGUMENT_KEY).toString()
Log.d("id: ",id)
LazyColumn(modifier= Modifier
.background(Color.White)
.fillMaxSize(),
contentPadding = PaddingValues(top =75.dp, bottom = 10.dp, start = 10.dp,end=10.dp),
verticalArrangement = Arrangement.spacedBy(1.dp)){
item{
BackButton(modifier=Modifier
.clickable { navController.popBackStack()})
}
items(items = articles){ article ->
if(article.tagId.toString()==id) {
ArticleItem(article = article, sharedViewModel = sharedViewModel, onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))})
}
}
}
}

View File

@ -0,0 +1,61 @@
package com.example.pmulabs.screensMobile.filterScreens
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.pmulabs.basecomponents.navigate.BottomBarScreen
import com.example.pmulabs.basecomponents.navigate.SEARCH_ARGUMENT_TEXT
import com.example.pmulabs.designElem.elem.BackButton
import com.example.pmulabs.designElem.items.ArticleItem
import com.example.pmulabs.room.database.NewsPortalDatabase
import com.example.pmulabs.room.models.Article
import com.example.pmulabs.viewModels.SharedViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun SearchScreen(navController: NavController, modifier: Modifier = Modifier,sharedViewModel: SharedViewModel){
val context = LocalContext.current
val articles = remember { mutableStateListOf<Article>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
NewsPortalDatabase.getInstance(context).articleDao().getAll().collect { data ->
articles.clear()
articles.addAll(data)
}
}
}
var text=navController.currentBackStackEntry?.arguments?.getString(SEARCH_ARGUMENT_TEXT).toString()
Log.d("text: ",text)
LazyColumn(
modifier= Modifier
.background(Color.White)
.fillMaxSize(),
contentPadding = PaddingValues(top =75.dp, bottom = 10.dp, start = 10.dp,end=10.dp),
verticalArrangement = Arrangement.spacedBy(1.dp)){
item{
BackButton(modifier=Modifier
.clickable { navController.popBackStack()})
}
items(items = articles){ article ->
if(article.title.contains(text)) {
ArticleItem(article = article,sharedViewModel=sharedViewModel,onArticleClick = {navController.navigate(BottomBarScreen.ArticlePage.passId(article.id.toString()))})
}
}
}
}

View File

@ -0,0 +1,11 @@
package com.example.pmulabs.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)

View File

@ -0,0 +1,70 @@
package com.example.pmulabs.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 PMULabsTheme(
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
)
}

View File

@ -0,0 +1,34 @@
package com.example.pmulabs.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
)
*/
)

View File

@ -0,0 +1,28 @@
package com.example.pmulabs.viewModels
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class SearchViewModel : ViewModel() {
private val _searchWidgetState: MutableState<SearchWidget> =
mutableStateOf(value = SearchWidget.CLOSED)
val searchWidgetState: State<SearchWidget> = _searchWidgetState
private val _searchTextState: MutableState<String> =
mutableStateOf(value = "")
val searchTextState: State<String> = _searchTextState
fun updateSearchWidgetState(newValue: SearchWidget) {
_searchWidgetState.value = newValue
}
fun updateSearchTextState(newValue: String) {
_searchTextState.value = newValue
}
}

View File

@ -0,0 +1,6 @@
package com.example.pmulabs.viewModels
enum class SearchWidget {
OPENED,
CLOSED
}

View File

@ -0,0 +1,12 @@
package com.example.pmulabs.viewModels
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class SharedViewModel : ViewModel() {
val argument = mutableStateOf<String?>(null)
fun setArgument(arg: String) {
argument.value = arg
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#423A99" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19L3,19L3,5h18v14zM5,10h9v2L5,12zM5,7h9v2L5,9z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM12,11L3,11L3,9h9v2zM12,7L3,7L3,5h9v2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#423A99"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12.31,11.14c-1.77,-0.45 -2.34,-0.94 -2.34,-1.67 0,-0.84 0.79,-1.43 2.1,-1.43 1.38,0 1.9,0.66 1.94,1.64h1.71c-0.05,-1.34 -0.87,-2.57 -2.49,-2.97L13.23,5L10.9,5v1.69c-1.51,0.32 -2.72,1.3 -2.72,2.81 0,1.79 1.49,2.69 3.66,3.21 1.95,0.46 2.34,1.15 2.34,1.87 0,0.53 -0.39,1.39 -2.1,1.39 -1.6,0 -2.23,-0.72 -2.32,-1.64L8.04,14.33c0.1,1.7 1.36,2.66 2.86,2.97L10.9,19h2.34v-1.67c1.52,-0.29 2.72,-1.16 2.73,-2.77 -0.01,-2.2 -1.9,-2.96 -3.66,-3.42z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13.41,18.09L13.41,20h-2.67v-1.93c-1.71,-0.36 -3.16,-1.46 -3.27,-3.4h1.96c0.1,1.05 0.82,1.87 2.65,1.87 1.96,0 2.4,-0.98 2.4,-1.59 0,-0.83 -0.44,-1.61 -2.67,-2.14 -2.48,-0.6 -4.18,-1.62 -4.18,-3.67 0,-1.72 1.39,-2.84 3.11,-3.21L10.74,4h2.67v1.95c1.86,0.45 2.79,1.86 2.85,3.39L14.3,9.34c-0.05,-1.11 -0.64,-1.87 -2.22,-1.87 -1.5,0 -2.4,0.68 -2.4,1.64 0,0.84 0.65,1.39 2.67,1.91s4.18,1.39 4.18,3.91c-0.01,1.83 -1.38,2.83 -3.12,3.16z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#423A99"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#423A99"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,5.69l5,4.5V18h-2v-6H9v6H7v-7.81l5,-4.5M12,3L2,12h3v8h6v-6h2v6h6v-8h3L12,3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
</vector>

View File

@ -0,0 +1,6 @@
<vector android:height="24dp" android:tint="#423A99"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7.35,18.5C8.66,17.56 10.26,17 12,17s3.34,0.56 4.65,1.5C15.34,19.44 13.74,20 12,20S8.66,19.44 7.35,18.5zM18.14,17.12L18.14,17.12C16.45,15.8 14.32,15 12,15s-4.45,0.8 -6.14,2.12l0,0C4.7,15.73 4,13.95 4,12c0,-4.42 3.58,-8 8,-8s8,3.58 8,8C20,13.95 19.3,15.73 18.14,17.12z"/>
<path android:fillColor="@android:color/white" android:pathData="M12,6c-1.93,0 -3.5,1.57 -3.5,3.5S10.07,13 12,13s3.5,-1.57 3.5,-3.5S13.93,6 12,6zM12,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,8 12,8s1.5,0.67 1.5,1.5S12.83,11 12,11z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,6c1.93,0 3.5,1.57 3.5,3.5S13.93,13 12,13s-3.5,-1.57 -3.5,-3.5S10.07,6 12,6zM12,20c-2.03,0 -4.43,-0.82 -6.14,-2.88C7.55,15.8 9.68,15 12,15s4.45,0.8 6.14,2.12C16.43,19.18 14.03,20 12,20z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="25dp"
android:tint="#423A99" android:viewportHeight="24"
android:viewportWidth="24" android:width="25dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21.99,4c0,-1.1 -0.89,-2 -1.99,-2L4,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4 -0.01,-18zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
</vector>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">PMULabs</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.PMULabs" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@ -0,0 +1,17 @@
package com.example.pmulabs
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

6
build.gradle.kts Normal file
View File

@ -0,0 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.1" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false
}

23
gradle.properties Normal file
View File

@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

Some files were not shown because too many files have changed in this diff Show More