Реализована функция копирования в буфер обмена

This commit is contained in:
2024-12-02 21:30:19 +03:00
parent 589464e69c
commit 11cafec847
79 changed files with 242 additions and 139 deletions
Regular → Executable
View File
-3
View File
@@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
-6
View File
@@ -5,12 +5,6 @@
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
</SelectionState> </SelectionState>
<SelectionState runConfigName="SearchTextFieldPrev">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="SearchContextMenuPrev">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates> </selectionStates>
</component> </component>
</project> </project>
+1 -1
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules"> <option name="modules">
-53
View File
@@ -1,53 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="ComposePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="ComposePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="ComposePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="ComposePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<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="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="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
</profile>
</component>
+1
View File
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
+4
View File
@@ -5,8 +5,12 @@
<set> <set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" /> <option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" /> <option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" /> <option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" /> <option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set> </set>
</option> </option>
</component> </component>
Generated
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="" vcs="Git" />
</component> </component>
</project> </project>
Regular → Executable
View File
Regular → Executable
+2 -2
View File
@@ -2,7 +2,7 @@ plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.compose)
kotlin("kapt") id("com.google.devtools.ksp")
id("com.google.dagger.hilt.android") id("com.google.dagger.hilt.android")
} }
@@ -60,7 +60,7 @@ dependencies {
debugImplementation(libs.androidx.ui.test.manifest) debugImplementation(libs.androidx.ui.test.manifest)
implementation(libs.hilt.android) implementation(libs.hilt.android)
kapt(libs.hilt.android.compiler) ksp(libs.hilt.android.compiler)
implementation(libs.voyager.navigator) implementation(libs.voyager.navigator)
Regular → Executable
View File
Regular → Executable
View File
Vendored Regular → Executable
View File
View File
View File
Regular → Executable
View File
Regular → Executable
View File
View File
Vendored Regular → Executable
View File
Regular → Executable
View File
+105
View File
@@ -0,0 +1,105 @@
{
"ИДО": "Институт дополнительного образования",
"ИМО": "Институт международного образования",
"ИДП": "Институт довузовской подготовки",
"ИТХТ": "Институт тонких химических технологий имени М.В. Ломоносова",
"ИИИ": "Институт искусственного интеллекта",
"БК250": "Базовая кафедра № 250 - математического обеспечения информационных систем",
"ИПТ": "Институт перспективных технологий и индустриального программирования",
"БК235": "Базовая кафедра № 235 - цифровых устройств и систем защиты информации",
"КСТУ": "Кафедра современных технологий управления",
"БК536": "Базовая кафедра № 536 - программного обеспечения систем РЭА",
"ИКДТ": "Институт кибербезопасности и цифровых технологий",
"УПО": "Управление платных образовательных услуг",
"КВМ3": "Кафедра высшей математики-3",
"КФТМ": "Кафедра физики и технической механики",
"УОРТ": "Учебный отдел Института радиотехнических и телекоммуникационных систем",
"БК333": "Базовая кафедра № 333 имени профессора Лобанова Б.С. - систем радиоэлектронной борьбы",
"БК334": "Базовая кафедра № 334 - дальней радиосвязи",
"БК338": "Базовая кафедра № 338 - космической радиоэлектроники",
"КИЭТ": "Кафедра инженерной экологии техносферы",
"КИЯ1": "Кафедра иностранных языков 1",
"КРЭСК": "Кафедра радиоэлектронных систем и комплексов",
"КБПФ": "Кафедра биотехнологии и промышленной фармации",
"КДГП": "Кафедра документоведения, истории государства и права",
"БК340": "Базовая кафедра № 340 - информационных космических систем",
"БК343": "Базовая кафедра № 343 - моделирования радиофизических процессов",
"ЦДО": "Центр дистанционного обучения",
"КФТМ2024": "Кафедра физики и технической механики (от 19.06.2024 № 26-ст)",
"КИТГУ": "Кафедра информационных технологий в государственном управлении",
"КМОСИТ": "Кафедра математического обеспечения и стандартизации информационных технологий",
"КПК": "Колледж программирования и кибербезопасности",
"КВТ": "Кафедра вычислительной техники",
"ИИТ": "Институт информационных технологий",
"КИГ": "Кафедра инженерной графики",
"КЭТ": "Кафедра экономической теории",
"КОИ": "Кафедра общей информатики",
"ККПРЭС": "Кафедра конструирования и производства радиоэлектронных средств",
"КСИ": "Кафедра системной инженерии",
"Аспирантура": "Аспирантура",
"ПОДГ": "Подготовительное отделение для иностранных граждан",
"Ректорат": "Ректорат",
"ИРИ": "Институт радиоэлектроники и информатики",
"ЮО": "Юридический отдел",
"УМУ": "Учебно-методическое управление",
"УК": "Управление кадров",
"ФФГБОУВОС": "Филиал федерального государственного бюджетного образовательного учреждения высшего образования «МИРЭА - Российский технологический университет» в г. Ставрополе",
"УГОЧС": "Управление гражданской обороны и чрезвычайных ситуаций",
"КН": "Кафедра наноэлектроники",
"Бухгалтерия": "Бухгалтерия",
"УОИМО": "Учебный отдел института международного образования",
"СПВ86": "Сектор «Проспект Вернадского, 86»",
"СИАО": "Студенческий информационно-архивный отдел",
"УЭФ": "Управление экономики и финансов",
"УМС": "Управление международных связей",
"УВСР": "Управление по воспитательной и социальной работе",
"ПР": "Первый отдел",
"СГИ": "Служба главного инженера",
"НТБ": "Научно-техническая библиотека",
"УИ": "Управление информатизации",
"КМС": "Кафедра метрологии и стандартизации",
"ССт20": "Сектор «Стромынка, 20»",
"ИАО": "Информационно-аналитический отдел",
"ОСПР": "Отдел судебно-претензионной работы",
"БК140": "Базовая кафедра № 140 - фотоники",
"УД": "Управление делами",
"УМП": "Управление мобилизационной подготовки",
"БК130": "Базовая кафедра № 130 - твердотельной электроники",
"НОЦТЦ": "Научно-образовательный центр «Технологический центр»",
"БК131": "Базовая кафедра № 131 - оптико-физических измерений",
"БК132": "Базовая кафедра № 132 - лазерной техники",
"БК136": "Базовая кафедра № 136 - СВЧ приборов и устройств",
"ФМШ": "Физико-математическая школа",
"КПВВ": "Курсы по подготовке к поступлению в вуз",
"ОМКО": "Отдел менеджмента качества образования",
"ОТСО": "Отдел технических средств обучения",
"ОЗЗИ": "Отдел обеспечения защиты информации",
"ОТК": "Отдел технического контроля",
"Автобаза": "Автобаза",
"Академия ТВ": "Академия ТВ",
"ГИВЦ": "Главный информационно-вычислительный центр",
"УНИР": "Управление научно-исследовательских разработок",
"КДЦ": "Культурно-досуговый центр",
"МНТЦИС": "Межотраслевой научно-технический центр интеллектуальных технологий обработки информации и управления «Интеллектуальные системы»",
"НТЦН": "Научно-технологический центр «Наука»",
"НИЦРСВТ": "Научно-исследовательский центр разработки специальной вычислительной техники",
"НИЦИПМ": "Научно-исследовательский центр «Инновационные полимерные материалы и изделия»",
"ОИТОСБ": "Отдел инженерно-технического обеспечения средств безопасности",
"ЦПИС": "Центр проектирования интегральных схем, устройств наноэлектроники и микросистем",
"ЦЯП": "Центр языковой подготовки",
"ИМПМО": "Институт молодежной политики и международных отношений",
"НИИМФП": "Научно-исследовательский институт медицинской и фармацевтической промышленности",
"ИПЦСНК": "Инженерно-научный производственный центр «Средства неразрушающего контроля» МИРЭА",
"УЦВ": "Учебный центр подготовки водителей",
"ИТП": "Институт технологического предпринимательства",
"СУЛСДФ": "Специализированная учебно-научная лаборатория сверхбыстрой динамики ферроиков",
"УНИИСУ": "Учебно-научный институт информатики и систем управления",
"УМЦИТ": "Учебно-методический центр интерактивных технологий",
"ОКБМИРЭА": "Особое конструкторское бюро МИРЭА",
"ИУС": "Институт учета и статистики",
"НИЦПНТП": "Научно-инжиниринговый центр «Перспективные научно-технические проекты»",
"Наноцентр МИРЭА": "Наноцентр МИРЭА",
"НТЦИРФ": "Научно-технологический центр «Интегральная радиофотоника»",
"РИО": "Редакционно-издательский отдел",
"ПЛМА": "Проблемная лаборатория молекулярной активации"
}
+1
View File
@@ -26,6 +26,7 @@ import ru.megboyzz.lks.profile.ui.theme.MainTheme
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
View File
View File
View File
View File
View File
View File
View File
View File
+26
View File
@@ -1,5 +1,9 @@
package ru.megboyzz.lks.profile.ui package ru.megboyzz.lks.profile.ui
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
@@ -24,5 +28,27 @@ fun Modifier.clickableWithNormalRipple(
onLongClick = onLongClick onLongClick = onLongClick
) )
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Modifier.clickableWithNoEffect(
onClick: () -> Unit = {},
onLongClick: () -> Unit = {},
) = this.combinedClickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = onClick,
onLongClick = onLongClick
)
@Composable @Composable
fun Int.asPainter() = painterResource(this) fun Int.asPainter() = painterResource(this)
fun Context.copyToClipboard(content: String) {
val clipboardManager = this.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("label", content)
clipboardManager.setPrimaryClip(clip)
Toast.makeText(this, "Текст скопирован в буфер обмена", Toast.LENGTH_SHORT).show()
}
+3
View File
@@ -9,14 +9,17 @@ import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
import cafe.adriel.voyager.transitions.SlideTransition import cafe.adriel.voyager.transitions.SlideTransition
import ru.megboyzz.lks.profile.ui.screens.SearchScreen import ru.megboyzz.lks.profile.ui.screens.SearchScreen
import ru.megboyzz.lks.profile.ui.theme.MainTheme
@Composable @Composable
fun MainNavigator(screen: Screen) { fun MainNavigator(screen: Screen) {
BottomSheetNavigator( BottomSheetNavigator(
sheetShape = RoundedCornerShape(12.dp) sheetShape = RoundedCornerShape(12.dp)
) { ) {
MainTheme {
Navigator(screen) { Navigator(screen) {
SlideTransition(it) SlideTransition(it)
} }
} }
} }
}
+27 -14
View File
@@ -1,7 +1,6 @@
package ru.megboyzz.lks.profile.ui.components package ru.megboyzz.lks.profile.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -18,19 +17,18 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.KeyboardArrowUp import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.material.icons.outlined.AccountCircle
import androidx.compose.material.icons.outlined.Person
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
@@ -42,7 +40,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@@ -62,7 +60,7 @@ fun ContextMenuContainer(
Column( Column(
modifier = Modifier modifier = Modifier
.padding(4.dp) .padding(horizontal = 4.dp, vertical = 8.dp)
.fillMaxWidth() .fillMaxWidth()
.navigationBarsPadding(), .navigationBarsPadding(),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
@@ -264,7 +262,7 @@ fun ContextMenuButton(
Box( Box(
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(0.dp)
.clickableWithNormalRipple(onClick = onClick) .clickableWithNormalRipple(onClick = onClick)
) { ) {
Row( Row(
@@ -275,19 +273,20 @@ fun ContextMenuButton(
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp) horizontalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
Icon( Icon(
painter = icon, painter = icon,
contentDescription = null, contentDescription = null,
tint = Color.Unspecified tint = Color.Unspecified,
modifier = Modifier.size(36.dp)
) )
Text(text = label) Text(text = label)
} }
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight, imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
contentDescription = null contentDescription = null,
) )
} }
@@ -311,10 +310,12 @@ fun ContextMenuButtonPrev() {
@Composable @Composable
fun LongPressCardContextMenu( fun LongPressCardContextMenu(
lksStudent: LksStudent, lksStudent: LksStudent,
onClick: () -> Unit onGoToVk: () -> Unit,
onCopyName: (String) -> Unit,
onCopyGroup: (String) -> Unit
) { ) {
ContextMenuContainer { ContextMenuContainer {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
Text( Text(
"${lksStudent.studentFullName} ${lksStudent.group}" "${lksStudent.studentFullName} ${lksStudent.group}"
@@ -323,7 +324,17 @@ fun LongPressCardContextMenu(
ContextMenuButton( ContextMenuButton(
icon = R.drawable.vk_ic.asPainter(), icon = R.drawable.vk_ic.asPainter(),
label = "Переидти в VK", label = "Переидти в VK",
onClick = onClick onClick = onGoToVk
)
ContextMenuButton(
icon = rememberVectorPainter(Icons.Outlined.AccountCircle),
label = "Скопировать имя пользователя",
onClick = { onCopyName.invoke(lksStudent.studentFullName ?: "") }
)
ContextMenuButton(
icon = rememberVectorPainter(Icons.Outlined.Person),
label = "Скопировать группу",
onClick = { onCopyGroup.invoke(lksStudent.group ?: "") }
) )
} }
} }
@@ -340,7 +351,9 @@ private fun LongPressCardContextMenuPrev() {
LongPressCardContextMenu( LongPressCardContextMenu(
lksStudent = lksStudent, lksStudent = lksStudent,
onClick = {} onGoToVk = {},
onCopyName = {},
onCopyGroup = {}
) )
+10 -2
View File
@@ -52,6 +52,7 @@ import kotlinx.coroutines.withContext
import ru.megboyzz.lks.profile.MainActivity import ru.megboyzz.lks.profile.MainActivity
import ru.megboyzz.lks.profile.domain.entities.LksResponse import ru.megboyzz.lks.profile.domain.entities.LksResponse
import ru.megboyzz.lks.profile.domain.entities.LksStudent import ru.megboyzz.lks.profile.domain.entities.LksStudent
import ru.megboyzz.lks.profile.ui.clickableWithNoEffect
import ru.megboyzz.lks.profile.ui.clickableWithNormalRipple import ru.megboyzz.lks.profile.ui.clickableWithNormalRipple
import ru.megboyzz.lks.profile.ui.screens.sub.LongPressMenu import ru.megboyzz.lks.profile.ui.screens.sub.LongPressMenu
import ru.megboyzz.lks.profile.ui.theme.MainTheme import ru.megboyzz.lks.profile.ui.theme.MainTheme
@@ -120,12 +121,16 @@ fun ProfileCard(
@Composable @Composable
fun MainScaffold( fun MainScaffold(
onFloatingButtonClick: () -> Unit, onFloatingButtonClick: () -> Unit,
onTopClick: () -> Unit = {},
content: @Composable (PaddingValues) -> Unit content: @Composable (PaddingValues) -> Unit
) { ) {
Scaffold( Scaffold(
topBar = { topBar = {
Surface(shadowElevation = 8.dp) { Surface(
shadowElevation = 8.dp,
modifier = Modifier.clickableWithNoEffect(onTopClick)
) {
TopAppBar( TopAppBar(
title = { Text("LKS Search") } title = { Text("LKS Search") }
) )
@@ -217,7 +222,10 @@ fun CardsColumn(
} }
} }
Column(modifier) { Column(
modifier = modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
LazyColumn( LazyColumn(
state = listState, state = listState,
contentPadding = PaddingValues(12.dp), contentPadding = PaddingValues(12.dp),
+17 -20
View File
@@ -39,28 +39,27 @@ class SearchScreenModel @Inject constructor(
val state = MutableStateFlow<UiState>(UiState.Idle) val state = MutableStateFlow<UiState>(UiState.Idle)
init { suspend fun nextPage() {
_curPageNumber.onEach { if(_responseList.value.availablePages > _curPageNumber.value) {
_curPageNumber.emit(_curPageNumber.value + 1)
update(_request.value) update(_request.value)
}.launchIn(CoroutineScope(Dispatchers.IO)) }
} }
fun nextPage() = screenModelScope.launch { _curPageNumber.emit(_curPageNumber.value++) } suspend fun resetStudents() {
_curPageNumber.value = 1
fun resetStudents() = screenModelScope.launch {
_responseList.emit(LksResponse()) _responseList.emit(LksResponse())
} }
fun newSearch(request: LksRequest) { fun newSearch(request: LksRequest) {
screenModelScope.launch(Dispatchers.IO) { screenModelScope.launch(Dispatchers.IO) {
resetStudents()
update(request)
}
}
private suspend fun update(request: LksRequest) {
state.emit(UiState.Loading) state.emit(UiState.Loading)
resetStudents()
state.emit(update(request))
}
}
suspend fun update(request: LksRequest): UiState {
_request.emit(request) _request.emit(request)
@@ -68,21 +67,19 @@ class SearchScreenModel @Inject constructor(
val result = lksRepository.getPage(request, repoCookies, curPageNumber.value) val result = lksRepository.getPage(request, repoCookies, curPageNumber.value)
if(result.isFailure) { if(result.isFailure)
state.emit(UiState.Error("Ошибка :-(")) return UiState.Error("Ошибка :-(")
return
}
val list = result.getOrElse { LksResponse() } val list = result.getOrElse { LksResponse() }
val updatedStudents = _responseList.value.copy( val updatedStudents = LksResponse(
students = _responseList.value.students + list.students, students = _responseList.value.students + list.students,
availablePages = _responseList.value.availablePages + list.availablePages availablePages = list.availablePages
) )
_responseList.emit(updatedStudents) _responseList.emit(updatedStudents)
state.emit(UiState.Idle) return UiState.Idle
} }
+3 -4
View File
@@ -43,10 +43,9 @@ class SearchScreen : Screen {
val list by screenModel.responseList.collectAsState() val list by screenModel.responseList.collectAsState()
val context = LocalContext.current
MainScaffold( MainScaffold(
onFloatingButtonClick = { bottomSheetNavigator.show(SearchBottomScreen(screenModel)) } onFloatingButtonClick = { bottomSheetNavigator.show(SearchBottomScreen(screenModel)) },
onTopClick = { }
) { ) {
when (state) { when (state) {
@@ -60,7 +59,7 @@ class SearchScreen : Screen {
onColumnOverflow = { onColumnOverflow = {
//Toast.makeText(context, "Hello!", Toast.LENGTH_SHORT).show() //Toast.makeText(context, "Hello!", Toast.LENGTH_SHORT).show()
screenModel.nextPage() screenModel.nextPage()
screenModel.update(screenModel.request.value) //screenModel.update(screenModel.request.value)
//screenModel.nextPage() //screenModel.nextPage()
} }
) )
+2
View File
@@ -1,5 +1,7 @@
package ru.megboyzz.lks.profile.ui.screens package ru.megboyzz.lks.profile.ui.screens
import android.os.Parcel
import android.os.Parcelable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
+10 -2
View File
@@ -8,6 +8,7 @@ import androidx.compose.ui.platform.LocalContext
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import ru.megboyzz.lks.profile.domain.entities.LksStudent import ru.megboyzz.lks.profile.domain.entities.LksStudent
import ru.megboyzz.lks.profile.ui.components.LongPressCardContextMenu import ru.megboyzz.lks.profile.ui.components.LongPressCardContextMenu
import ru.megboyzz.lks.profile.ui.copyToClipboard
class LongPressMenu(private val lksStudent: LksStudent) : Screen { class LongPressMenu(private val lksStudent: LksStudent) : Screen {
@@ -18,13 +19,20 @@ class LongPressMenu(private val lksStudent: LksStudent) : Screen {
val context = LocalContext.current val context = LocalContext.current
LongPressCardContextMenu( LongPressCardContextMenu(
lksStudent = lksStudent lksStudent = lksStudent,
) { onCopyName = {
context.copyToClipboard(lksStudent.studentFullName.toString())
},
onCopyGroup = {
context.copyToClipboard(lksStudent.studentFullName.toString())
},
onGoToVk = {
Toast.makeText(context, "Переход на VK", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Переход на VK", Toast.LENGTH_SHORT).show()
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://vk.com/search?q=${lksStudent.studentFullName?.split(" ")?.dropLast(1)?.joinToString(" ")}")) val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://vk.com/search?q=${lksStudent.studentFullName?.split(" ")?.dropLast(1)?.joinToString(" ")}"))
browserIntent.`package` = "com.vkontakte.android" browserIntent.`package` = "com.vkontakte.android"
context.startActivity(browserIntent) context.startActivity(browserIntent)
} }
)
} }
View File
+22 -25
View File
@@ -12,43 +12,40 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme( private val DarkColorScheme = darkColorScheme(
primary = Purple80, primary = Color(0xFFB0BEC5), // Серый с голубым оттенком
secondary = PurpleGrey80, secondary = Color(0xFF90A4AE), // Более мягкий серо-голубой
tertiary = Pink80 tertiary = Color(0xFFB39DDB), // Нежный фиолетовый
background = Color(0xFF121212), // Темный фон для контраста
surface = Color(0xFF1E1E1E), // Темная поверхность
onPrimary = Color.Black,
onSecondary = Color.Black,
onTertiary = Color.Black,
onBackground = Color(0xFFECEFF1), // Светлый текст на темном фоне
onSurface = Color(0xFFECEFF1) // Светлый текст на поверхностях
) )
private val LightColorScheme = lightColorScheme( private val LightColorScheme = lightColorScheme(
primary = Purple40, primary = Color(0xFF90CAF9), // Голубой с пастельным оттенком
secondary = PurpleGrey40, secondary = Color(0xFFB3E5FC), // Мягкий голубой
tertiary = Pink40, tertiary = Color(0xFFC5CAE9), // Светлый фиолетовый
// Other default colors to override background = Color(0xFFF5F5F5), // Очень светлый фон
background = Color(0xFFFFFBFE), surface = Color(0xFFFFFFFF), // Чисто белая поверхность
surface = Color(0xFFFFFBFE),
onPrimary = Color.White, onPrimary = Color.White,
onSecondary = Color.White, onSecondary = Color.Black,
onTertiary = Color.White, onTertiary = Color.Black,
onBackground = Color(0xFF1C1B1F), onBackground = Color(0xFF212121), // Темный текст на светлом фоне
onSurface = Color(0xFF1C1B1F), onSurface = Color(0xFF212121) // Темный текст на поверхностях
) )
@Composable @Composable
fun MainTheme( fun MainTheme(
darkTheme: Boolean = isSystemInDarkTheme(), darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+ dynamicColor: Boolean = false, // Отключаем динамические цвета для четкости палитры
dynamicColor: Boolean = true,
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
val colorScheme = when { val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme( MaterialTheme(
colorScheme = colorScheme, colorScheme = colorScheme,
View File
View File
View File
View File
View File
View File
View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 982 B

After

Width:  |  Height:  |  Size: 982 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File
View File
View File
View File
Regular → Executable
+1
View File
@@ -5,5 +5,6 @@ plugins {
alias(libs.plugins.kotlin.compose) apply false alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.jetbrains.kotlin.jvm) apply false alias(libs.plugins.jetbrains.kotlin.jvm) apply false
alias(libs.plugins.android.library) apply false alias(libs.plugins.android.library) apply false
id("com.google.devtools.ksp") version "2.0.0-1.0.24" apply false
id("com.google.dagger.hilt.android") version "2.51.1" apply false id("com.google.dagger.hilt.android") version "2.51.1" apply false
} }
Regular → Executable
View File
Regular → Executable
View File
Vendored Regular → Executable
View File
Vendored Regular → Executable
View File
Vendored Regular → Executable
View File
Regular → Executable
View File