diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a000a3d..ddfe2df 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -41,6 +41,8 @@ android { dependencies { + implementation(files("libs/libary-release.aar")) + implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) @@ -56,6 +58,4 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - - implementation(project(":libary")) } \ No newline at end of file diff --git a/app/libs/libary-release.aar b/app/libs/libary-release.aar new file mode 100644 index 0000000..7d72b16 Binary files /dev/null and b/app/libs/libary-release.aar differ diff --git a/app/src/main/java/com/example/ui_kit/MainActivity.kt b/app/src/main/java/com/example/ui_kit/MainActivity.kt index f0f12e4..331a030 100644 --- a/app/src/main/java/com/example/ui_kit/MainActivity.kt +++ b/app/src/main/java/com/example/ui_kit/MainActivity.kt @@ -4,12 +4,14 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import com.example.libary.theme.UikitTheme @@ -19,11 +21,15 @@ class MainActivity : ComponentActivity() { enableEdgeToEdge() setContent { UikitTheme { - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Greeting( - name = "Android", + Scaffold( + modifier = Modifier.fillMaxSize(), + containerColor = Color.White + ) { innerPadding -> + Column( modifier = Modifier.padding(innerPadding) - ) + ) { + StoryBook() + } } } } diff --git a/app/src/main/java/com/example/ui_kit/StoryBook.kt b/app/src/main/java/com/example/ui_kit/StoryBook.kt new file mode 100644 index 0000000..54d463d --- /dev/null +++ b/app/src/main/java/com/example/ui_kit/StoryBook.kt @@ -0,0 +1,406 @@ +package com.example.ui_kit + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +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.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.BaseCard +import com.example.libary.BigButton +import com.example.libary.BigButtonState +import com.example.libary.BottomSheet +import com.example.libary.CartButton +import com.example.libary.CartCard +import com.example.libary.ChipButton +import com.example.libary.ChipButtonState +import com.example.libary.Header +import com.example.libary.HeaderState +import com.example.libary.Input +import com.example.libary.LoginButton +import com.example.libary.LoginState +import com.example.libary.PrimaryCard +import com.example.libary.ProjectCard +import com.example.libary.SearchInput +import com.example.libary.Select +import com.example.libary.SmallButton +import com.example.libary.SmallButtonState +import com.example.libary.TabBar +import com.example.libary.defaultTabBarData +import com.example.libary.theme.BlackColor +import com.example.libary.theme.IconsColor + +@Composable +fun StoryBook( + +) { + var modal by remember { mutableStateOf(false) } + + var inVal by remember { mutableStateOf("") } + var passinVal by remember { mutableStateOf("123456789") } + + val searchInput = remember { mutableStateOf("") } + val valSelect = remember { mutableStateOf("") } + val valSelect1 = remember { mutableStateOf("Гарвард Троцкий") } + + val valueTabBar1 = remember { mutableStateOf(defaultTabBarData[0]) } + val valueTabBar2 = remember { mutableStateOf(defaultTabBarData[1]) } + val valueTabBar3 = remember { mutableStateOf(defaultTabBarData[2]) } + val valueTabBar4 = remember { mutableStateOf(defaultTabBarData[3]) } + + if (modal) { + BottomSheet { + Row { + Text( + text = "Рубашка Воскресенье для машинного вязания", + color = BlackColor, + fontSize = 20.sp, + fontWeight = FontWeight.W800, + modifier = Modifier.weight(1f) + ) + + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.size(24.dp) + .background(IconsColor.copy(0.3f), AbsoluteRoundedCornerShape(90.dp)) + .clip(AbsoluteRoundedCornerShape(90.dp)) + ) { + Image( + painter = painterResource(com.example.libary.R.drawable.delete), + contentDescription = null + ) + } + } + + Spacer(Modifier.height(84.dp)) + } + } + + LazyColumn( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + item { + Spacer(Modifier.height(20.dp)) + + Header( + state = HeaderState.Big, + title = "Корзина" + ) + + Spacer(Modifier.height(39.dp)) + + Header( + state = HeaderState.Small, + title = "Корзина" + ) + + Spacer(Modifier.height(40.dp)) + + + BigButton( + state = BigButtonState.Property, + text = "Открытить модальное окно", + onClick = { + modal = !modal + } + ) + + Spacer(Modifier.height(40.dp)) + + BaseCard( + modifier = Modifier.height(138.dp).width(335.dp) + ) {} + + Spacer(Modifier.height(18.dp)) + + PrimaryCard( + name = "Рубашка Воскресенье для машинного вязания", + category = "Мужская одежда", + price = "300", + isAdd = true, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + ) + + Spacer(Modifier.height(18.dp)) + + PrimaryCard( + name = "Рубашка Воскресенье для машинного вязания", + category = "Мужская одежда", + price = "300", + isAdd = false, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + ) + + Spacer(Modifier.height(18.dp)) + + CartCard( + name = "Рубашка воскресенье для машинного вязания", + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + price = "300", + count = "1" + ) + + Spacer(Modifier.height(18.dp)) + + ProjectCard( + name = "Мой первый проект", + date = "Прошло 2 дня", + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + ) + + Spacer(Modifier.height(40.dp)) + + Input( + value = inVal, + modifier = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + placeholder = "Введите имя", + onValueChange = { + inVal = it + } + ) + + Spacer(Modifier.height(18.dp)) + + Input( + value = "Иван", + modifier = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + placeholder = "Иван", + onValueChange = { + inVal = it + } + ) + + Spacer(Modifier.height(18.dp)) + + Input( + value = inVal, + modifier = Modifier.fillMaxWidth(), + modifierColumn = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + topText = "Имя", + placeholder = "Введите имя", + onValueChange = { + inVal = it + } + ) + + Spacer(Modifier.height(18.dp)) + + Input( + value = inVal, + modifier = Modifier.fillMaxWidth(), + modifierColumn = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + placeholder = "Иван", + errorText = "Введите ваше имя", + onValueChange = { + inVal = it + } + ) + + Spacer(Modifier.height(18.dp)) + + Input( + value = inVal, + modifier = Modifier.fillMaxWidth(), + modifierColumn = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + topText = "Имя", + placeholder = "Введите имя", + onValueChange = { + inVal = it + } + ) + + Spacer(Modifier.height(18.dp)) + + Input( + value = "Введите имя", + modifier = Modifier.fillMaxWidth(), + modifierColumn = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + topText = "Имя", + placeholder = "Введите имя", + onValueChange = { + inVal = it + } + ) + + Spacer(Modifier.height(18.dp)) + + Input( + value = passinVal, + modifier = Modifier.fillMaxWidth(), + modifierColumn = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + topText = "Имя", + placeholder = "Введите имя", + pasMode = true, + onValueChange = { + passinVal = it + } + ) + + Spacer(Modifier.height(18.dp)) + + Input( + value = inVal, + modifier = Modifier.fillMaxWidth(), + modifierColumn = Modifier.fillMaxWidth().padding(start = 16.dp, end = 26.dp), + placeholder = "--.--.----", + onValueChange = { + inVal = it + } + ) + + Spacer(Modifier.height(40.dp)) + + Select( + value = valSelect, + modifier = Modifier.fillMaxWidth() + .padding(start = 16.dp, end = 26.dp), + placeholder = "Пол", + data = listOf( + "Мужской", + "Женский" + ) + ) + + Spacer(Modifier.height(18.dp)) + + Select( + value = valSelect1, + modifier = Modifier.fillMaxWidth() + .padding(start = 16.dp, end = 26.dp), + leadingIcon = { + Image( + painter = painterResource(R.drawable.user_icon), + contentDescription = null, + modifier = Modifier.size(24.dp) + ) + }, + data = listOf( + "Гарвард Троцкий", + "Гарвард Троцкий" + ) + ) + + Spacer(Modifier.height(40.dp)) + + SearchInput( + value = searchInput.value, + onValueChange = { + searchInput.value = it + } + ) + + Spacer(Modifier.height(40.dp)) + + BigButtonState.entries.forEach { + BigButton( + state = it, + text = "Подтвердить", + modifier = Modifier.fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 16.dp) + ) + } + + Spacer(Modifier.height(40.dp)) + + SmallButton( + state = SmallButtonState.Property, + text = "Добавить" + ) + + Spacer(Modifier.height(5.dp)) + + SmallButton( + state = SmallButtonState.Secondary, + text = "Убрать" + ) + + Spacer(Modifier.height(5.dp)) + + SmallButton( + state = SmallButtonState.Inactive, + text = "Добавить" + ) + + Spacer(Modifier.height(5.dp)) + + SmallButton( + state = SmallButtonState.Tetriary, + text = "Подтвердить" + ) + + Spacer(Modifier.height(40.dp)) + + ChipButton( + state = ChipButtonState.On, + text = "Популярные" + ) + + Spacer(Modifier.height(5.dp)) + + ChipButton( + state = ChipButtonState.Off, + text = "Популярные" + ) + + Spacer(Modifier.height(40.dp)) + + CartButton( + price = "500" + ) + + Spacer(Modifier.height(40.dp)) + + LoginState.entries.forEach { + LoginButton( + state = it + ) + + Spacer(Modifier.height(5.dp)) + } + + Spacer(Modifier.height(40.dp)) + + TabBar( + value = valueTabBar1 + ) + + Spacer(Modifier.height(15.dp)) + + TabBar( + value = valueTabBar2 + ) + + Spacer(Modifier.height(15.dp)) + + TabBar( + value = valueTabBar3 + ) + + Spacer(Modifier.height(15.dp)) + + TabBar( + value = valueTabBar4 + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/user_icon.png b/app/src/main/res/drawable/user_icon.png new file mode 100644 index 0000000..1d3ff15 Binary files /dev/null and b/app/src/main/res/drawable/user_icon.png differ diff --git a/libary/src/androidTest/java/com/example/libary/BottomSheetTest.kt b/libary/src/androidTest/java/com/example/libary/BottomSheetTest.kt new file mode 100644 index 0000000..9519cef --- /dev/null +++ b/libary/src/androidTest/java/com/example/libary/BottomSheetTest.kt @@ -0,0 +1,33 @@ +package com.example.libary + +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import org.junit.Rule +import org.junit.Test + +class BottomSheetTest { + + @get:Rule + val composeRule = createComposeRule() + + @Test + fun test1() { + composeRule.setContent { + val ins = remember { mutableStateOf("") } + Select( + value = ins, + data = listOf( + "test1" + ) + ) + } + + composeRule.onNodeWithTag("dr_1").performClick() + composeRule.onNodeWithText("test1").assertIsDisplayed() + } +} \ No newline at end of file diff --git a/libary/src/androidTest/java/com/example/libary/ButtonChipTest.kt b/libary/src/androidTest/java/com/example/libary/ButtonChipTest.kt new file mode 100644 index 0000000..c34d2e4 --- /dev/null +++ b/libary/src/androidTest/java/com/example/libary/ButtonChipTest.kt @@ -0,0 +1,22 @@ +package com.example.libary + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.test.junit4.createComposeRule +import org.junit.Assert +import org.junit.Rule +import org.junit.Test + +class ButtonChipTest { + + @get:Rule + val composeRule = createComposeRule() + + @Test + fun test() { + Assert.assertEquals(ChipButtonState.On.textColor, Color(0xFFFFFFFF)) + Assert.assertEquals(ChipButtonState.On.containerColor, Color(0xFF1A6FEE)) + + Assert.assertEquals(ChipButtonState.Off.textColor, Color(0xFF7E7E9A)) + Assert.assertEquals(ChipButtonState.Off.containerColor, Color(0xFFF5F5F9)) + } +} \ No newline at end of file diff --git a/libary/src/androidTest/java/com/example/libary/CardPrimaryTest.kt b/libary/src/androidTest/java/com/example/libary/CardPrimaryTest.kt new file mode 100644 index 0000000..678b7eb --- /dev/null +++ b/libary/src/androidTest/java/com/example/libary/CardPrimaryTest.kt @@ -0,0 +1,47 @@ +package com.example.libary + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import org.junit.Rule +import org.junit.Test + +class CardPrimaryTest { + + @get:Rule + val composeRule = createComposeRule() + + @Test + fun test() { + composeRule.setContent { + PrimaryCard( + name = "name", + category = "category", + price = "100", + isAdd = false + ) + } + + composeRule.onNodeWithText("name").assertIsDisplayed() + composeRule.onNodeWithText("category").assertIsDisplayed() + composeRule.onNodeWithText("100 ₽").assertIsDisplayed() + composeRule.onNodeWithText("Убрать").assertIsDisplayed() + } + + @Test + fun test1() { + composeRule.setContent { + PrimaryCard( + name = "name", + category = "category", + price = "100", + isAdd = true + ) + } + + composeRule.onNodeWithText("name").assertIsDisplayed() + composeRule.onNodeWithText("category").assertIsDisplayed() + composeRule.onNodeWithText("100 ₽").assertIsDisplayed() + composeRule.onNodeWithText("Добавить").assertIsDisplayed() + } +} \ No newline at end of file diff --git a/libary/src/androidTest/java/com/example/libary/InputTest.kt b/libary/src/androidTest/java/com/example/libary/InputTest.kt new file mode 100644 index 0000000..5e59587 --- /dev/null +++ b/libary/src/androidTest/java/com/example/libary/InputTest.kt @@ -0,0 +1,26 @@ +package com.example.libary + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import org.junit.Rule +import org.junit.Test + +class InputTest { + + @get:Rule + val composeRule = createComposeRule() + + @Test + fun test1() { + composeRule.setContent { + Input( + value = "", + onValueChange = {}, + errorText = "error test" + ) + } + + composeRule.onNodeWithText("error test").assertIsDisplayed() + } +} \ No newline at end of file diff --git a/libary/src/androidTest/java/com/example/libary/TabbarTest.kt b/libary/src/androidTest/java/com/example/libary/TabbarTest.kt new file mode 100644 index 0000000..e7010b7 --- /dev/null +++ b/libary/src/androidTest/java/com/example/libary/TabbarTest.kt @@ -0,0 +1,46 @@ +package com.example.libary + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import androidx.compose.ui.unit.dp +import org.junit.Assert +import org.junit.Rule +import org.junit.Test + +class TabbarTest { + + @get:Rule + val composeRule = createComposeRule() + + @Test + fun test() { + + var valueName = "" + + composeRule.setContent { + val value = remember { mutableStateOf(defaultTabBarData[0]) } + + LaunchedEffect(value.value) { + valueName = value.value.name + } + + Column { + Spacer(Modifier.height(100.dp)) + TabBar( + value = value + ) + } + } + + composeRule.onNodeWithTag("Главная").performClick() + Assert.assertEquals(valueName, "Главная") + } +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/BottomSheet.kt b/libary/src/main/java/com/example/libary/BottomSheet.kt new file mode 100644 index 0000000..7d7ee7b --- /dev/null +++ b/libary/src/main/java/com/example/libary/BottomSheet.kt @@ -0,0 +1,39 @@ +package com.example.libary + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.example.libary.theme.WhiteColor + +// Модальные окна +// modifier - модификаторы +// content - контент будет отображаться внутри модального окна +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BottomSheet( + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit +) { + ModalBottomSheet( + modifier = modifier, + onDismissRequest = {}, + containerColor = WhiteColor, + shape = AbsoluteRoundedCornerShape(topLeft = 24.dp, topRight = 24.dp), + dragHandle = null + ) { + Column( + modifier = Modifier.padding(horizontal = 20.dp) + ) { + Spacer(Modifier.height(24.dp)) + content() + } + } +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/Buttons.kt b/libary/src/main/java/com/example/libary/Buttons.kt new file mode 100644 index 0000000..ef1c790 --- /dev/null +++ b/libary/src/main/java/com/example/libary/Buttons.kt @@ -0,0 +1,323 @@ +package com.example.libary + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +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.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.theme.AccentColor +import com.example.libary.theme.AccentInactive +import com.example.libary.theme.BlackColor +import com.example.libary.theme.Desc +import com.example.libary.theme.InputBGColor +import com.example.libary.theme.InputStroke +import com.example.libary.theme.WhiteColor + +enum class BigButtonState( + val containerColor: Color, + val textColor: Color, + val enabled: Boolean = true, + val border: BorderStroke? = null +) { + Property( + containerColor = AccentColor, + textColor = Color.White, + ), + Inactive( + containerColor = AccentInactive, + textColor = WhiteColor, + enabled = false + ), + Secondary( + containerColor = Color.White, + textColor = AccentColor, + border = BorderStroke(1.dp, AccentColor) + ), + Tetriary( + containerColor = InputBGColor, + textColor = BlackColor, + ) +} + +// большая кнопка +// state - состояние кнопки +// modifier - модификаторы +// onClick - вызовиться при нажатии на кнопку +// text - текст кнопки +@Composable +fun BigButton( + state: BigButtonState, + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, + text: String = "" +) { + Button( + onClick = { + if (state.enabled) onClick() + }, + modifier = modifier + .width(335.dp) + .height(56.dp), + border = state.border, + shape = AbsoluteRoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors( + containerColor = state.containerColor + ), + contentPadding = PaddingValues(0.dp) + ) { + Text( + text = text, + color = state.textColor, + fontWeight = FontWeight.W600, + fontSize = 17.sp + ) + } +} + +enum class SmallButtonState( + val containerColor: Color, + val textColor: Color, + val enabled: Boolean = true, + val border: BorderStroke? = null +) { + Property( + containerColor = AccentColor, + textColor = Color.White, + ), + Inactive( + containerColor = AccentInactive, + textColor = WhiteColor, + enabled = false + ), + Secondary( + containerColor = Color.White, + textColor = AccentColor, + border = BorderStroke(1.dp, AccentColor) + ), + Tetriary( + containerColor = InputBGColor, + textColor = BlackColor, + ) +} + +// маленькая кнопка +// state - состояние кнопки +// modifier - модификаторы +// onClick - вызовиться при нажатии на кнопку +// text - текст кнопки +@Composable +fun SmallButton( + state: SmallButtonState, + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, + text: String = "" +) { + Button( + onClick = { + if (state.enabled) onClick() + }, + modifier = modifier + .width(96.dp) + .height(40.dp), + border = state.border, + shape = AbsoluteRoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors( + containerColor = state.containerColor + ), + contentPadding = PaddingValues(horizontal = 13.5.dp, vertical = 0.dp) + ) { + Text( + text = text, + color = state.textColor, + maxLines = 1, + fontWeight = FontWeight.W600, + fontSize = 14.sp, + overflow = TextOverflow.Ellipsis + ) + } +} + +// кнопка корзины +// price - сумма которая лежит в корзине +// modifier - модификаторы +// onClick - вызовиться при нажатии на кнопку +// text - текст кнопки +@Composable +fun CartButton( + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, + price: String = "" +) { + Button( + onClick = onClick, + modifier = modifier + .width(335.dp) + .height(56.dp), + contentPadding = PaddingValues(0.dp), + colors = ButtonDefaults.buttonColors( + containerColor = AccentColor + ), + shape = AbsoluteRoundedCornerShape(10.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painterResource(R.drawable.cart), + contentDescription = null + ) + + Spacer(Modifier.width(16.dp)) + + Text( + text = "В корзину", + fontWeight = FontWeight.W600, + fontSize = 17.sp, + color = WhiteColor + ) + } + + Text( + text = "$price ₽", + fontWeight = FontWeight.W600, + fontSize = 17.sp, + color = WhiteColor + ) + } + } +} + +enum class LoginState( + val icon: Int, + val text: String +) { + VK(R.drawable.vk, "Войти с VK"), + Yandex(R.drawable.yandex, "Войти с Yandex") +} + +// кнопка авторизации +// state - состояние кнопки +// modifier - модификаторы +// onClick - вызовиться при нажатии на кнопку +@Composable +fun LoginButton( + modifier: Modifier = Modifier, + state: LoginState = LoginState.VK, + onClick: () -> Unit = {} +) { + Button( + onClick = onClick, + modifier = modifier + .width(335.dp) + .height(60.dp), + shape = AbsoluteRoundedCornerShape(10.dp), + border = BorderStroke(1.dp, InputStroke), + colors = ButtonDefaults.buttonColors( + containerColor = Color.White + ) + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(state.icon), + contentDescription = null, + modifier = Modifier.size(32.dp) + ) + + Spacer(Modifier.width(16.dp)) + + Text( + text = state.text, + color = Color.Black, + fontWeight = FontWeight.W500, + fontSize = 17.sp + ) + } + } +} + +enum class ChipButtonState( + val containerColor: Color, + val textColor: Color +) { + On(AccentColor, Color.White), + Off(InputBGColor, Desc) +} + +// chip кнопка +// state - состояние кнопки +// modifier - модификаторы +// onClick - вызовиться при нажатии на кнопку +// text - текст кнопки +@Composable +fun ChipButton( + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, + state: ChipButtonState = ChipButtonState.On, + text: String = "" +) { + Button( + onClick = onClick, + modifier = modifier + .width(129.dp) + .height(48.dp), + shape = AbsoluteRoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors( + containerColor = state.containerColor + ), + contentPadding = PaddingValues(0.dp) + ) { + Text( + text = text, + color = state.textColor, + maxLines = 1, + fontWeight = FontWeight.W600, + fontSize = 14.sp, + overflow = TextOverflow.Ellipsis + ) + } +} + +@Preview +@Composable +private fun BigButtonPrev() { + Column { + BigButtonState.entries.forEach { + BigButton( + state = it, + text = "test" + ) + Spacer(Modifier.height(5.dp)) + } + } +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/Cards.kt b/libary/src/main/java/com/example/libary/Cards.kt new file mode 100644 index 0000000..3146e10 --- /dev/null +++ b/libary/src/main/java/com/example/libary/Cards.kt @@ -0,0 +1,287 @@ +package com.example.libary + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image +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.ColumnScope +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.width +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Text +import androidx.compose.material3.VerticalDivider +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.shadow +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.theme.Black1Color +import com.example.libary.theme.CaptionColor +import com.example.libary.theme.CartShadowColor +import com.example.libary.theme.DividerColor +import com.example.libary.theme.InputBGColor +import com.example.libary.theme.White1Color + +// базовая карта +// modifier - модификаторы +// content - контент который будет внктри карточки +@Composable +fun BaseCard( + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit +) { + Card( + modifier = modifier + .shadow(10.dp, AbsoluteRoundedCornerShape(12.dp), + ambientColor = CartShadowColor, spotColor = CartShadowColor + ), + shape = AbsoluteRoundedCornerShape(12.dp), + colors = CardDefaults.cardColors( + containerColor = White1Color + ), + border = BorderStroke(1.dp, DividerColor) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + content() + } + } +} + +// карточка продукции +// modifier - модификаторы +// name - название продукции +// category - категория продукции +// price - цена продукуии +// isAdd - если равен true тогда отображаеться кнопка "Добавить" иначе "Убрать" +// onClick - вызываеться при нажатии на кнопку Добавить" или "Убрать" +@Composable +fun PrimaryCard( + modifier: Modifier = Modifier, + name: String, + category: String, + price: String, + isAdd: Boolean, + onClick: () -> Unit = {} +) { + BaseCard( + modifier = modifier + ) { + Text( + text = name, + color = Black1Color, + fontWeight = FontWeight.W500, + fontSize = 16.sp + ) + + Spacer(Modifier.height(16.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column { + Text( + text = category, + color = CaptionColor, + fontWeight = FontWeight.W600, + fontSize = 14.sp + ) + + Spacer(Modifier.height(4.dp)) + + Text( + text = "$price ₽", + color = Black1Color, + fontWeight = FontWeight.W600, + fontSize = 17.sp + ) + } + + SmallButton( + state = if (isAdd) SmallButtonState.Property else SmallButtonState.Secondary, + text = if (isAdd) "Добавить" else "Убрать", + onClick = onClick + ) + } + } +} + +// карточка продукции для корзины +// modifier - модификаторы +// name - название продукции +// price - цена продукуии +// count - количество продукции в корине +// onClose - вызываеться при нажатии на крестик +// onPlus - вызываеться при нажатии на плюс +// onMinus - вызываеться при нажатии на минус +@Composable +fun CartCard( + modifier: Modifier = Modifier, + name: String, + price: String, + count: String, + onClose: () -> Unit = {}, + onPlus: () -> Unit = {}, + onMinus: () -> Unit = {} +) { + BaseCard( + modifier = modifier + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = name, + fontWeight = FontWeight.W500, + fontSize = 16.sp, + color = Black1Color, + modifier = Modifier.weight(1.0f) + ) + + Image( + painter = painterResource(R.drawable.delete), + contentDescription = null, + modifier = Modifier.clickable { + onClose() + } + ) + } + + Spacer(Modifier.height(34.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "$price ₽", + color = Black1Color, + fontWeight = FontWeight.W500, + fontSize = 17.sp + ) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "$count штук", + fontWeight = FontWeight.W400, + fontSize = 15.sp, + color = Black1Color + ) + + Spacer(Modifier.width(42.dp)) + + Box( + modifier = Modifier + .width(64.dp) + .height(32.dp) + .background(InputBGColor, AbsoluteRoundedCornerShape(8.dp)) + .clip(AbsoluteRoundedCornerShape(8.dp)), + contentAlignment = Alignment.Center + ) { + Row( + modifier = Modifier.padding(6.dp) + ) { + Image( + painter = painterResource(R.drawable.minus), + contentDescription = null, + modifier = Modifier.clickable { + onMinus() + } + ) + + Spacer(Modifier.width(6.dp)) + + VerticalDivider() + + Spacer(Modifier.width(6.dp)) + + Image( + painter = painterResource(R.drawable.plus), + contentDescription = null, + modifier = Modifier.clickable { + onPlus() + } + ) + } + } + } + } + } +} + +// карточка проекта +// modifier - модификаторы +// name - название проекта +// date - дата проекта +// open - вызываеться при нажатии на кнопку "Открыть" +@Composable +fun ProjectCard( + modifier: Modifier = Modifier, + name: String, + date: String, + open: () -> Unit = {} +) { + BaseCard( + modifier = modifier, + content = { + Text( + text = name, + fontWeight = FontWeight.W500, + fontSize = 16.sp, + color = Black1Color + ) + + Spacer(Modifier.height(44.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = date, + color = CaptionColor, + fontWeight = FontWeight.W600, + fontSize = 14.sp + ) + + SmallButton( + state = SmallButtonState.Property, + text = "Открыть", + onClick = open + ) + } + } + ) +} + +@Preview +@Composable +private fun PrimaryCardPrev() { + ProjectCard( + modifier = Modifier.padding(horizontal = 20.dp), + name = "Рубашка Воскресенье для машинного вязания", + date = "Прошло 2 дня" + ) +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/Header.kt b/libary/src/main/java/com/example/libary/Header.kt new file mode 100644 index 0000000..fd17d2f --- /dev/null +++ b/libary/src/main/java/com/example/libary/Header.kt @@ -0,0 +1,152 @@ +package com.example.libary + +import androidx.compose.foundation.Image +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.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +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.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.HeaderState.* +import com.example.libary.theme.Black1Color +import com.example.libary.theme.InputBGColor + +enum class HeaderState { + Big, + Small +} + +// Хэдер +// modifier - модификаторы +// state - состояние хзэдера +// title - загаловок +// onBack - вызываеться при нажатии на кнопку назад +// onRm - вызываеться при нажатии на кнопку удалить +@Composable +fun Header( + modifier: Modifier = Modifier, + state: HeaderState, + title: String, + onBack: () -> Unit = {}, + onRm: () -> Unit = {} +) { + when(state) { + Big -> { + Column( + modifier = modifier + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(end = 11.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + HeaderBt( + icon = R.drawable.back, + onClick = onBack + ) + + Image( + painter = painterResource(R.drawable.rm), + contentDescription = null, + modifier = Modifier.clickable { + onRm() + } + ) + } + + Spacer(Modifier.height(24.dp)) + + Text( + text = title, + color = Black1Color, + fontWeight = FontWeight.W800, + fontSize = 24.sp + ) + } + } + Small -> { + Row( + modifier = modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 26.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + HeaderBt( + icon = R.drawable.back, + onClick = onBack + ) + + Text( + text = title, + color = Black1Color, + fontWeight = FontWeight.W600, + fontSize = 20.sp + ) + + Image( + painter = painterResource(R.drawable.rm), + contentDescription = null, + modifier = Modifier.clickable { + onRm() + } + ) + } + } + } +} + +@Composable +internal fun HeaderBt( + icon: Int, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .size(32.dp) + .background(InputBGColor, AbsoluteRoundedCornerShape(8.dp)) + .clip(AbsoluteRoundedCornerShape(8.dp)), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(icon), + contentDescription = null, + modifier = Modifier.padding(6.dp).clickable { + onClick() + } + ) + } +} + +@Preview +@Composable +private fun HeaderPr() { + Column( + modifier = Modifier.fillMaxSize().background(Color.White).padding(10.dp) + ) { + Header( + state = HeaderState.Big, + title = "Корзина" + ) + } +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/Input.kt b/libary/src/main/java/com/example/libary/Input.kt new file mode 100644 index 0000000..f8ded48 --- /dev/null +++ b/libary/src/main/java/com/example/libary/Input.kt @@ -0,0 +1,146 @@ +package com.example.libary + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.theme.AccentColor +import com.example.libary.theme.BlackColor +import com.example.libary.theme.CaptionColor +import com.example.libary.theme.Error1Color +import com.example.libary.theme.InputBGColor +import com.example.libary.theme.InputStroke + +/** + * текстовое поле + * modifier - модификаторы + * value - значение + * placeholder - the optional placeholder to be displayed when the text field is in focus and the input text is empty. + * topText - текст сверху + * errorText - текст ошибки + * pasMode - пароль мод + * onValueChange - вызываеться при изминение текста + * */ +@Composable +fun Input( + modifier: Modifier = Modifier, + modifierColumn: Modifier = Modifier, + value: String = "", + placeholder: String = "", + topText: String = "", + errorText: String = "", + pasMode: Boolean = false, + onValueChange: (String) -> Unit, +) { + var vis by remember { mutableStateOf(false) } + + Column(modifierColumn) { + if (topText.isNotEmpty()) { + Text( + text = topText, + color = Color(0xFF7E7E9A), + fontWeight = FontWeight.W400, + fontSize = 14.sp + ) + + Spacer(Modifier.height(8.dp)) + } + + OutlinedTextField( + value = value, + modifier = modifier, + onValueChange = onValueChange, + placeholder = { + Text( + text = placeholder, + color = CaptionColor, + fontWeight = FontWeight.W400, + fontSize = 16.sp + ) + }, + trailingIcon = { + if (pasMode) { + if (vis) { + Image( + painter = painterResource(R.drawable.gl_2), + contentDescription = null, + modifier = Modifier.clickable { + vis = false + } + ) + }else { + Image( + painter = painterResource(R.drawable.gl_1), + contentDescription = null, + modifier = Modifier.clickable { + vis = true + } + ) + } + } + }, + shape = AbsoluteRoundedCornerShape(10.dp), + colors = TextFieldDefaults.colors( + cursorColor = AccentColor, + focusedPlaceholderColor = CaptionColor, + unfocusedPlaceholderColor = CaptionColor, + + focusedTextColor = BlackColor, + unfocusedTextColor = BlackColor, + + focusedIndicatorColor = if (errorText.isNotEmpty()) Error1Color else AccentColor, + unfocusedIndicatorColor = if (errorText.isNotEmpty()) Error1Color else InputStroke, + + focusedContainerColor = if (errorText.isNotEmpty()) Error1Color.copy(0.1f) else InputBGColor, + unfocusedContainerColor = if (errorText.isNotEmpty()) Error1Color.copy(0.1f) else InputBGColor + ), + visualTransformation = if (!vis && pasMode) PasswordVisualTransformation('*') else VisualTransformation.None + ) + + if (errorText.isNotEmpty()) { + Spacer(Modifier.height(8.dp)) + + Text( + text = errorText, + color = Error1Color, + fontSize = 14.sp, + fontWeight = FontWeight.W400 + ) + } + } +} + +@Preview +@Composable +private fun InputPrev() { + var value by remember { mutableStateOf("") } + + Input( + value = value, + placeholder = "Введите имя", + topText = "Вве имя", + pasMode = true, + onValueChange = { + value = it + } + ) +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/SearchInput.kt b/libary/src/main/java/com/example/libary/SearchInput.kt new file mode 100644 index 0000000..4f27595 --- /dev/null +++ b/libary/src/main/java/com/example/libary/SearchInput.kt @@ -0,0 +1,97 @@ +package com.example.libary + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.theme.AccentColor +import com.example.libary.theme.BlackColor +import com.example.libary.theme.CaptionColor +import com.example.libary.theme.InputBGColor +import com.example.libary.theme.InputStroke + +/*** + * текстовое поле поиска + * modifier - модификаторы + * value - значение + * onValueChange - вызываеться при изминение текста + */ +@Composable +fun SearchInput( + modifier: Modifier = Modifier, + value: String = "", + onValueChange: (String) -> Unit, +) { + var focus by remember { mutableStateOf(false) } + + OutlinedTextField( + value = value, + modifier = modifier.onFocusChanged { + focus = it.hasFocus + }, + onValueChange = onValueChange, + placeholder = { + Text( + text = "Искать описание", + color = CaptionColor, + fontWeight = FontWeight.W400, + fontSize = 16.sp + ) + }, + leadingIcon = { + Image( + painter = painterResource(R.drawable.icon_search), + contentDescription = null + ) + }, + trailingIcon = { + if (focus) { + Image( + painter = painterResource(R.drawable.delete), + contentDescription = null + ) + } + }, + shape = AbsoluteRoundedCornerShape(10.dp), + colors = TextFieldDefaults.colors( + cursorColor = AccentColor, + focusedPlaceholderColor = CaptionColor, + unfocusedPlaceholderColor = CaptionColor, + focusedTextColor = BlackColor, + unfocusedTextColor = BlackColor, + focusedIndicatorColor = InputStroke, + unfocusedIndicatorColor = InputStroke, + focusedContainerColor = InputBGColor, + unfocusedContainerColor = InputBGColor + ) + ) +} + +@Preview +@Composable +private fun SearchInputPrev() { + var value by remember { mutableStateOf("") } + + SearchInput( + value = value, + modifier = Modifier.fillMaxWidth().padding(horizontal = 20.dp, vertical = 7.dp), + onValueChange = { + value = it + } + ) +} diff --git a/libary/src/main/java/com/example/libary/Select.kt b/libary/src/main/java/com/example/libary/Select.kt new file mode 100644 index 0000000..575fedb --- /dev/null +++ b/libary/src/main/java/com/example/libary/Select.kt @@ -0,0 +1,116 @@ +package com.example.libary + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +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.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.theme.BlackColor +import com.example.libary.theme.CaptionColor +import com.example.libary.theme.InputBGColor +import com.example.libary.theme.InputStroke + +/*** + * текстовое поле поиска + * modifier - модификаторы + * value - значение + * onValueChange - вызываеться при изминение текста + * placeholder - the optional placeholder to be displayed when the text field is in focus and the input text is empty. + * data - список который будет отображатся в модальном окне + * leadingIcon - the optional leading icon to be displayed at the beginning of the text field container + */ +@Composable +fun Select( + modifier: Modifier = Modifier, + value: MutableState, + data: List, + placeholder: String = "", + leadingIcon: @Composable (() -> Unit)? = null, + ) { + var modal by remember { mutableStateOf(false) } + + OutlinedTextField( + value = value.value, + onValueChange = {}, + modifier = modifier, + shape = AbsoluteRoundedCornerShape(10.dp), + leadingIcon = leadingIcon, + placeholder = { + Text( + text = placeholder, + fontWeight = FontWeight.W400, + fontSize = 16.sp, + color = CaptionColor + ) + }, + colors = TextFieldDefaults.colors( + focusedPlaceholderColor = CaptionColor, + unfocusedPlaceholderColor = CaptionColor, + focusedTextColor = BlackColor, + unfocusedTextColor = BlackColor, + focusedIndicatorColor = InputStroke, + unfocusedIndicatorColor = InputStroke, + focusedContainerColor = InputBGColor, + unfocusedContainerColor = InputBGColor + ), + trailingIcon = { + Image( + painter = painterResource(R.drawable.dr_1), + contentDescription = null, + modifier = Modifier.testTag("dr_1").clickable { + modal = true + } + ) + } + ) + + if (modal) { + BottomSheet { + LazyColumn { + items(data) { + Text( + text = it, + fontSize = 20.sp, + fontWeight = FontWeight.W600, + modifier = Modifier + .padding(5.dp) + .clickable { + value.value = it + modal = false + } + ) + HorizontalDivider() + } + } + } + } +} + +@Preview +@Composable +private fun SelectPrev() { + val value = remember { mutableStateOf("") } + + Select( + value = value, + data = listOf("test") + ) +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/Tabbar.kt b/libary/src/main/java/com/example/libary/Tabbar.kt new file mode 100644 index 0000000..0ee756d --- /dev/null +++ b/libary/src/main/java/com/example/libary/Tabbar.kt @@ -0,0 +1,119 @@ +package com.example.libary + +import androidx.compose.foundation.Image +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.NavigationBarItemDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.libary.theme.AccentColor +import com.example.libary.theme.IconsColor +import com.example.libary.theme.TabBarShad + +data class TabBarData( + val icon: Int, + val name: String +) + +val defaultTabBarData = listOf( + TabBarData( + icon = R.drawable.bot_1, + name = "Главная" + ), + TabBarData( + icon = R.drawable.bot_2, + name = "Каталог" + ), + TabBarData( + icon = R.drawable.bot_3, + name = "Проекты" + ), + TabBarData( + icon = R.drawable.bot_4, + name = "Профиль" + ) +) + +/** + * Нижняя панель + * modifier - модификаторы + * value - значение + * data - список элементов + * + * */ +@Composable +fun TabBar( + modifier: Modifier = Modifier, + value: MutableState, + data: List = defaultTabBarData +) { + Column( + modifier = modifier + .shadow(10.dp, spotColor = TabBarShad, ambientColor = TabBarShad) + ) { + HorizontalDivider(thickness = 1.dp, color = TabBarShad) + + NavigationBar( + containerColor = Color.White + ) { + data.forEach { + NavigationBarItem( + selected = value.value == it, + modifier = Modifier.testTag(it.name), + colors = NavigationBarItemDefaults.colors( + indicatorColor = Color.Transparent + ), + icon = { + Icon( + painter = painterResource(it.icon), + contentDescription = null, + tint = if (value.value == it) AccentColor else IconsColor + ) + }, + label = { + Text( + text = it.name, + color = if (value.value == it) AccentColor else IconsColor, + fontWeight = FontWeight.W400, + fontSize = 12.sp + ) + }, + onClick = { + value.value = it + } + ) + } + } + } +} + +@Preview +@Composable +private fun TabBarPrev() { + val value = remember { mutableStateOf(defaultTabBarData[0]) } + Column { + Spacer(Modifier.height(100.dp)) + TabBar( + value = value + ) + } +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/Toggle.kt b/libary/src/main/java/com/example/libary/Toggle.kt new file mode 100644 index 0000000..b40e403 --- /dev/null +++ b/libary/src/main/java/com/example/libary/Toggle.kt @@ -0,0 +1,38 @@ +package com.example.libary + +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CheckboxDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.example.libary.theme.AccentColor + +/** + * Checkboxes allow users to select one or more items from a set. Checkboxes can turn an option on or off. + * @param checked whether this checkbox is checked or unchecked + * @param onCheckedChange called when this checkbox is clicked. If `null`, then this checkbox will + * not be interactable, unless something else handles its input events and updates its state. + * @param modifier the [Modifier] to be applied to this checkbox + * */ +@Composable +fun Toggle( + modifier: Modifier = Modifier, + checked: Boolean, + onCheckedChange: ((Boolean) -> Unit)? = null, +) { + Checkbox( + checked = checked, + onCheckedChange = onCheckedChange, + colors = CheckboxDefaults.colors( + checkedColor = AccentColor + ) + ) +} + +@Preview +@Composable +private fun TogglePrev() { + Toggle( + checked = true + ) +} \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/theme/Color.kt b/libary/src/main/java/com/example/libary/theme/Color.kt index 3b25092..50a53e5 100644 --- a/libary/src/main/java/com/example/libary/theme/Color.kt +++ b/libary/src/main/java/com/example/libary/theme/Color.kt @@ -8,4 +8,31 @@ val Pink80 = Color(0xFFEFB8C8) val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +val Pink40 = Color(0xFF7D5260) + +val AccentColor = Color(0xFF1A6FEE) +val AccentInactiveColor = Color(0xFFC5D2FF) +val BlackColor = Color(0xFF2D2C2C) +val WhiteColor = Color(0xFFF7F7F7) +val ErrorColor = Color(0xFFFF4646) +val SuccessColor = Color(0xFF00B412) +val InputBgColor = Color(0xFFF7F7FA) +val InputStrokeColor = Color(0xFFE6E6E6) +val InputIconColor = Color(0xFFBFC7D1) +val PlaceholderColor = Color(0xFF98989A) +val DescriptionColor = Color(0xFF8787A1) +val CardStrokeColor = Color(0xFFF2F2F2) +val DividerColor = Color(0xFFF4F4F4) + +val CartShadowColor = Color(0x99E4E8F5) +val CaptionColor = Color(0xFF939396) +val InputBGColor = Color(0xFFF5F5F9) +val AccentInactive = Color(0xFFC9D4FB) +val Desc = Color(0xFF7E7E9A) +val InputStroke = Color(0xFFEBEBEB) +val IconsColor = Color(0xFFB8C1CC) +val TabBarShad = Color(0x4DA0A0A0) +val Error1Color = Color(0xFFFD3535) + +val White1Color = Color.White +val Black1Color = Color.Black \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/theme/Theme.kt b/libary/src/main/java/com/example/libary/theme/Theme.kt index 384c7d6..09e0074 100644 --- a/libary/src/main/java/com/example/libary/theme/Theme.kt +++ b/libary/src/main/java/com/example/libary/theme/Theme.kt @@ -1,14 +1,13 @@ package com.example.libary.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.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext private val DarkColorScheme = darkColorScheme( @@ -25,8 +24,8 @@ private val LightColorScheme = lightColorScheme( @Composable fun UikitTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - dynamicColor: Boolean = true, + darkTheme: Boolean = false, + dynamicColor: Boolean = false, content: @Composable () -> Unit ) { val colorScheme = when { @@ -39,9 +38,13 @@ fun UikitTheme( else -> LightColorScheme } - MaterialTheme( - colorScheme = colorScheme, - typography = Typography, - content = content - ) + CompositionLocalProvider( + LocalUiKitTypography provides UiKitTypography() + ) { + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) + } } \ No newline at end of file diff --git a/libary/src/main/java/com/example/libary/theme/Type.kt b/libary/src/main/java/com/example/libary/theme/Type.kt index 6ae6cf5..a2ca12f 100644 --- a/libary/src/main/java/com/example/libary/theme/Type.kt +++ b/libary/src/main/java/com/example/libary/theme/Type.kt @@ -2,13 +2,15 @@ package com.example.libary.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp +import com.example.libary.R val Typography = Typography( bodyLarge = TextStyle( - fontFamily = FontFamily.Default, + fontFamily = FontFamily(Font(R.font.main)), fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 24.sp, diff --git a/libary/src/main/java/com/example/libary/theme/UiKitTypography.kt b/libary/src/main/java/com/example/libary/theme/UiKitTypography.kt new file mode 100644 index 0000000..b78aebd --- /dev/null +++ b/libary/src/main/java/com/example/libary/theme/UiKitTypography.kt @@ -0,0 +1,113 @@ +package com.example.libary.theme + +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import com.example.libary.R + +data class UiKitTypography( + val title1Semibold: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 24.sp, + fontWeight = FontWeight.W600 + ), + val title1ExtraBold: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 24.sp, + fontWeight = FontWeight.W800 + ), + val title2Regular: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 20.sp, + fontWeight = FontWeight.W400 + ), + val title2Semibold: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 20.sp, + fontWeight = FontWeight.W600 + ), + val title2ExtraBold: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 20.sp, + fontWeight = FontWeight.W800 + ), + val title3Regular: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 17.sp, + fontWeight = FontWeight.W400 + ), + val title3Medium: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 17.sp, + fontWeight = FontWeight.W500 + ), + val title3Semibold: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 17.sp, + fontWeight = FontWeight.W600 + ), + val headlineRegular: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 16.sp, + fontWeight = FontWeight.W400 + ), + val headlineMedium: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 16.sp, + fontWeight = FontWeight.W500 + ), + val textRegular: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 15.sp, + fontWeight = FontWeight.W400 + ), + val textMedium: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 15.sp, + fontWeight = FontWeight.W400 + ), + val captionRegular: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 14.sp, + fontWeight = FontWeight.W400 + ), + val captionSemibold: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 14.sp, + fontWeight = FontWeight.W600 + ), + val caption2Regular: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 12.sp, + fontWeight = FontWeight.W400 + ), + val caption2Bold: TextStyle = TextStyle( + color = Color.Black, + fontFamily = FontFamily(Font(R.font.main)), + fontSize = 12.sp, + fontWeight = FontWeight.W700 + ) +) + +val LocalUiKitTypography = staticCompositionLocalOf { + error("UiKitTypography not found") +} \ No newline at end of file diff --git a/libary/src/main/res/drawable/back.xml b/libary/src/main/res/drawable/back.xml new file mode 100644 index 0000000..5e91758 --- /dev/null +++ b/libary/src/main/res/drawable/back.xml @@ -0,0 +1,13 @@ + + + diff --git a/libary/src/main/res/drawable/bot_1.xml b/libary/src/main/res/drawable/bot_1.xml new file mode 100644 index 0000000..ebffcf8 --- /dev/null +++ b/libary/src/main/res/drawable/bot_1.xml @@ -0,0 +1,9 @@ + + + diff --git a/libary/src/main/res/drawable/bot_2.xml b/libary/src/main/res/drawable/bot_2.xml new file mode 100644 index 0000000..eb1f8a1 --- /dev/null +++ b/libary/src/main/res/drawable/bot_2.xml @@ -0,0 +1,35 @@ + + + + + + + diff --git a/libary/src/main/res/drawable/bot_3.xml b/libary/src/main/res/drawable/bot_3.xml new file mode 100644 index 0000000..82c8a51 --- /dev/null +++ b/libary/src/main/res/drawable/bot_3.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/libary/src/main/res/drawable/bot_4.xml b/libary/src/main/res/drawable/bot_4.xml new file mode 100644 index 0000000..239ff91 --- /dev/null +++ b/libary/src/main/res/drawable/bot_4.xml @@ -0,0 +1,16 @@ + + + + diff --git a/libary/src/main/res/drawable/cart.xml b/libary/src/main/res/drawable/cart.xml new file mode 100644 index 0000000..dd14ef8 --- /dev/null +++ b/libary/src/main/res/drawable/cart.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/libary/src/main/res/drawable/delete.xml b/libary/src/main/res/drawable/delete.xml new file mode 100644 index 0000000..1987381 --- /dev/null +++ b/libary/src/main/res/drawable/delete.xml @@ -0,0 +1,20 @@ + + + + diff --git a/libary/src/main/res/drawable/dr_1.xml b/libary/src/main/res/drawable/dr_1.xml new file mode 100644 index 0000000..0811ea8 --- /dev/null +++ b/libary/src/main/res/drawable/dr_1.xml @@ -0,0 +1,13 @@ + + + diff --git a/libary/src/main/res/drawable/gl_1.xml b/libary/src/main/res/drawable/gl_1.xml new file mode 100644 index 0000000..f13a68e --- /dev/null +++ b/libary/src/main/res/drawable/gl_1.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/libary/src/main/res/drawable/gl_2.xml b/libary/src/main/res/drawable/gl_2.xml new file mode 100644 index 0000000..bfd9bbb --- /dev/null +++ b/libary/src/main/res/drawable/gl_2.xml @@ -0,0 +1,12 @@ + + + + diff --git a/libary/src/main/res/drawable/icon_search.xml b/libary/src/main/res/drawable/icon_search.xml new file mode 100644 index 0000000..9d83a06 --- /dev/null +++ b/libary/src/main/res/drawable/icon_search.xml @@ -0,0 +1,20 @@ + + + + diff --git a/libary/src/main/res/drawable/minus.xml b/libary/src/main/res/drawable/minus.xml new file mode 100644 index 0000000..b1b649e --- /dev/null +++ b/libary/src/main/res/drawable/minus.xml @@ -0,0 +1,13 @@ + + + diff --git a/libary/src/main/res/drawable/plus.xml b/libary/src/main/res/drawable/plus.xml new file mode 100644 index 0000000..1728df1 --- /dev/null +++ b/libary/src/main/res/drawable/plus.xml @@ -0,0 +1,20 @@ + + + + diff --git a/libary/src/main/res/drawable/rm.xml b/libary/src/main/res/drawable/rm.xml new file mode 100644 index 0000000..dce1479 --- /dev/null +++ b/libary/src/main/res/drawable/rm.xml @@ -0,0 +1,34 @@ + + + + + + diff --git a/libary/src/main/res/drawable/vk.xml b/libary/src/main/res/drawable/vk.xml new file mode 100644 index 0000000..3d68b68 --- /dev/null +++ b/libary/src/main/res/drawable/vk.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/libary/src/main/res/drawable/yandex.xml b/libary/src/main/res/drawable/yandex.xml new file mode 100644 index 0000000..8035e1a --- /dev/null +++ b/libary/src/main/res/drawable/yandex.xml @@ -0,0 +1,9 @@ + + + diff --git a/libary/src/main/res/font/main.ttf b/libary/src/main/res/font/main.ttf new file mode 100644 index 0000000..2e5c2a2 Binary files /dev/null and b/libary/src/main/res/font/main.ttf differ