diff --git a/app/build.gradle b/app/build.gradle index fbb9fc9..0d54f8f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -123,7 +123,7 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-datetime:0.5.0' - implementation 'com.github.dutwrapper:dutwrapper-java:v1.9.0' + implementation 'com.github.dutwrapper:dutwrapper-java:484d2f6f4a' implementation 'com.google.android.material:material:1.12.0' diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountInfoBanner.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountInfoBanner.kt index 280fdc1..4ced207 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountInfoBanner.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountInfoBanner.kt @@ -7,9 +7,14 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountCircle +import androidx.compose.material.icons.outlined.AccountCircle import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -18,17 +23,20 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import io.zoemeow.dutschedule.R import io.zoemeow.dutschedule.ui.component.base.OutlinedTextBox +import io.zoemeow.dutschedule.utils.capitalized @Composable fun AccountInfoBanner( context: Context, padding: PaddingValues, isLoading: Boolean = false, + name: String? = null, username: String? = null, schoolClass: String? = null, - trainingProgramPlan: String? = null, + specialization: String? = null, opacity: Float = 1.0f ) { Surface( @@ -42,7 +50,7 @@ fun AccountInfoBanner( .fillMaxWidth() .wrapContentHeight() .padding(10.dp), - horizontalAlignment = Alignment.Start, + horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top, content = { if (isLoading) { @@ -74,20 +82,25 @@ fun AccountInfoBanner( ) } ) - OutlinedTextBox( - title = "Username", - value = username ?: context.getString(R.string.data_unknown), - modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp) + Icon( + Icons.Outlined.AccountCircle, + "Account Icon", + modifier = Modifier.size(64.dp) ) - OutlinedTextBox( - title = "Class", - value = schoolClass ?: context.getString(R.string.data_unknown), - modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp) + Text( + name?.capitalized() ?: "(unknown name)", + fontSize = 20.sp, + modifier = Modifier.padding(top = 7.dp) ) - OutlinedTextBox( - title = "Training program plan", - value = trainingProgramPlan ?: context.getString(R.string.data_unknown), - modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp) + Text( + "${username ?: "(unknown student ID)"} - ${schoolClass ?: "(unknown class)"}", + fontSize = 17.sp, + modifier = Modifier.padding(top = 5.dp) + ) + Text( + specialization ?: "(unknown specialization)", + fontSize = 17.sp, + modifier = Modifier.padding(top = 5.dp) ) } } diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountSubjectMoreInformation.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountSubjectMoreInformation.kt index 91f28bb..eb77258 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountSubjectMoreInformation.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/component/account/AccountSubjectMoreInformation.kt @@ -54,53 +54,57 @@ fun AccountSubjectMoreInformation( // Subject study Spacer(modifier = Modifier.size(15.dp)) ContentInBoxWithBorder( - title = "Schedule Study", + title = context.getString(R.string.account_subjectinfo_data_schedulestudy_title), content = { - var schList = "" - item?.let { - schList = it.subjectStudy.scheduleList.joinToString( - separator = "; ", - transform = { item1 -> - "${CustomDateUtil.dayOfWeekInString(item1.dayOfWeek + 1)},${item1.lesson.start}-${item1.lesson.end},${item1.room}" - } - ) - } - CustomText("Day of week: $schList") - var schWeek = "" - item?.let { - schWeek = it.subjectStudy.weekList.joinToString( - separator = "; ", - transform = { item1 -> - "${item1.start}-${item1.end}" - } - ) - } - CustomText("Week range: $schWeek") + CustomText(context.getString( + R.string.account_subjectinfo_data_schedulestudy_dayofweek, + item?.let { + it.subjectStudy.scheduleList.joinToString( + separator = "; ", + transform = { item1 -> + "${CustomDateUtil.dayOfWeekInString(item1.dayOfWeek + 1)},${item1.lesson.start}-${item1.lesson.end},${item1.room}" + } + ) + } ?: "" + )) + CustomText(context.getString( + R.string.account_subjectinfo_data_schedulestudy_weekrange, + item?.let { + it.subjectStudy.weekList.joinToString( + separator = "; ", + transform = { item1 -> + "${item1.start}-${item1.end}" + } + ) + } ?: "" + )) }, ) // Subject examination Spacer(modifier = Modifier.size(15.dp)) ContentInBoxWithBorder( - title = "Schedule Examination", + title = context.getString(R.string.account_subjectinfo_data_scheduleexam_title), content = { if (item != null) { - CustomText( - "Group: ${item.subjectExam.group}" + - if (item.subjectExam.isGlobal) " (global exam)" else "" - ) - CustomText( - "Date: ${ - CustomDateUtil.dateUnixToString( - item.subjectExam.date, - "dd/MM/yyyy HH:mm", - "GMT+7" - ) - }" - ) - CustomText("Room: ${item.subjectExam.room}") - + CustomText(context.getString( + R.string.account_subjectinfo_data_scheduleexam_group, + item.subjectExam.group, + if (item.subjectExam.isGlobal) context.getString(R.string.account_subjectinfo_data_scheduleexam_groupglobal) else "" + )) + CustomText(context.getString( + R.string.account_subjectinfo_data_scheduleexam_date, + CustomDateUtil.dateUnixToString( + item.subjectExam.date, + "dd/MM/yyyy HH:mm", + "GMT+7" + ) + )) + CustomText(context.getString( + R.string.account_subjectinfo_data_scheduleexam_room, + item.subjectExam.room + )) } else { - CustomText("Currently no examination schedule yet for this subject.") + CustomText(context.getString(R.string.account_subjectinfo_data_scheduleexam_noexamdate)) } } ) diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt index f67d429..6779796 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt @@ -185,9 +185,10 @@ fun AccountMainView( opacity = componentBackgroundAlpha, padding = PaddingValues(10.dp), isLoading = accInfo.processState.value == ProcessState.Running, + name = accInfo.data.value?.name, username = accInfo.data.value?.studentId, schoolClass = accInfo.data.value?.schoolClass, - trainingProgramPlan = accInfo.data.value?.trainingProgramPlan + specialization = accInfo.data.value?.specialization ) } ButtonBase( diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt index 7dab93b..d3626ee 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt @@ -101,7 +101,7 @@ fun AccountActivity.SubjectFee( modifier = Modifier .fillMaxWidth() .padding(horizontal = 15.dp) - .padding(vertical = 3.dp), + .padding(vertical = 2.dp), horizontalAlignment = Alignment.CenterHorizontally, content = { Text(getMainViewModel().appSettings.value.currentSchoolYear.toString()) diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt index 47d3e19..29259a3 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt @@ -110,7 +110,7 @@ fun AccountActivity.SubjectInformation( modifier = Modifier .fillMaxWidth() .padding(horizontal = 15.dp) - .padding(vertical = 3.dp), + .padding(vertical = 2.dp), horizontalAlignment = Alignment.CenterHorizontally, content = { Text(getMainViewModel().appSettings.value.currentSchoolYear.toString()) diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt index 64cd381..419ca3b 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt @@ -60,7 +60,7 @@ fun AccountActivity.TrainingResult( contentAlignment = Alignment.BottomCenter, content = { TopAppBar( - title = { Text("Account Training Result") }, + title = { Text(context.getString(R.string.account_trainingstatus_title)) }, colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), navigationIcon = { IconButton( diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt index b09ba34..34f9ada 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt @@ -93,7 +93,7 @@ fun AccountActivity.TrainingSubjectResult( fun subjectResultToMap(item: SubjectResult): Map { return mapOf( - "Subject Year" to (item.schoolYear ?: "(unknown)"), + "Subject Year" to "${item.schoolYear ?: "(unknown)"}${ if (item.isExtendedSemester) "in summer" else "" }", "Subject Code" to (item.id ?: "(unknown)"), "Credit" to item.credit.toString(), "Point formula" to (item.pointFormula ?: "(unknown)"), @@ -291,21 +291,21 @@ fun AccountActivity.TrainingSubjectResult( backgroundColor = MaterialTheme.colorScheme.background.copy(alpha = getControlBackgroundAlpha()), text = "Index", textAlign = TextAlign.Center, - weight = 0.2f + weight = 0.17f ) TableCell( modifier = Modifier.fillMaxHeight(), backgroundColor = MaterialTheme.colorScheme.background.copy(alpha = getControlBackgroundAlpha()), text = "Subject name", textAlign = TextAlign.Center, - weight = 0.6f + weight = 0.58f ) TableCell( modifier = Modifier.fillMaxHeight(), backgroundColor = MaterialTheme.colorScheme.background.copy(alpha = getControlBackgroundAlpha()), - text = "Result (T4/C)", + text = "Result T10(T4)", textAlign = TextAlign.Center, - weight = 0.2f + weight = 0.25f ) } ) @@ -337,7 +337,7 @@ fun AccountActivity.TrainingSubjectResult( backgroundColor = MaterialTheme.colorScheme.background.copy(alpha = getControlBackgroundAlpha()), text = "${subjectItem.index}", textAlign = TextAlign.Center, - weight = 0.2f + weight = 0.17f ) TableCell( modifier = Modifier.fillMaxHeight(), @@ -345,18 +345,18 @@ fun AccountActivity.TrainingSubjectResult( text = subjectItem.name, contentAlign = Alignment.CenterStart, textAlign = TextAlign.Start, - weight = 0.6f + weight = 0.58f ) TableCell( modifier = Modifier.fillMaxHeight(), backgroundColor = MaterialTheme.colorScheme.background.copy(alpha = getControlBackgroundAlpha()), text = String.format( "%s (%s)", - if (subjectItem.resultT4 != null) "${subjectItem.resultT4}" else "---", - if (subjectItem.resultByCharacter != null) "${subjectItem.resultByCharacter}" else "-" + subjectItem.resultT10?.toString() ?: "---", + subjectItem.resultT4?.toString() ?: "---" ), textAlign = TextAlign.Center, - weight = 0.2f + weight = 0.25f ) } ) diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt index 990ce40..f6023fb 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt @@ -256,7 +256,7 @@ fun SettingsActivity.NewsNotificationSettings( getMainViewModel().saveSettings(saveSettingsOnly = true) showSnackBar( text = context.getString( - R.string.settings_newsnotify_newsfilter_notify_add, + R.string.settings_newsnotify_newsfilter_notify_delete, tempDeleteItem.value.subjectName, tempDeleteItem.value.studentYearId, ".Nh", @@ -398,7 +398,7 @@ private fun MainView( 1 -> context.getString(R.string.settings_newsnotify_fetchnewsinbackground_modifiedvalue_enabled1) else -> context.getString( R.string.settings_newsnotify_fetchnewsinbackground_modifiedvalue_enabled2, - fetchNewsInBackgroundDuration + durationTemp.intValue ) } ) @@ -553,68 +553,69 @@ private fun MainView( clicked = { }, opacity = opacity ) - } - SimpleCardItem( - padding = PaddingValues(horizontal = 20.4.dp, vertical = 5.dp), - title = context.getString(R.string.settings_newsnotify_newsfilter_list_title), - clicked = { }, - opacity = opacity, - content = { - Column( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(horizontal = 15.dp) - .padding(bottom = 15.dp), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.Start - ) { - if (subjectFilterList.size == 0) { - Text(context.getString(R.string.settings_newsnotify_newsfilter_list_nofilters)) - } - subjectFilterList.forEach { code -> - OptionItem( - modifier = Modifier.padding(vertical = 3.dp), - modifierInside = Modifier, - title = "${code.subjectName} [${code.studentYearId}.Nh${code.classId}]", - onClick = { }, - trailingIcon = { - IconButton( - onClick = { - if (fetchNewsInBackgroundDuration > 0) { - onSubjectFilterDelete?.let { it(code) } + } else { + SimpleCardItem( + padding = PaddingValues(horizontal = 20.4.dp, vertical = 5.dp), + title = context.getString(R.string.settings_newsnotify_newsfilter_list_title), + clicked = { }, + opacity = opacity, + content = { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 15.dp) + .padding(bottom = 15.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.Start + ) { + if (subjectFilterList.size == 0) { + Text(context.getString(R.string.settings_newsnotify_newsfilter_list_nofilters)) + } + subjectFilterList.forEach { code -> + OptionItem( + modifier = Modifier.padding(vertical = 3.dp), + modifierInside = Modifier, + title = "${code.subjectName} [${code.studentYearId}.Nh${code.classId}]", + onClick = { }, + trailingIcon = { + IconButton( + onClick = { + if (fetchNewsInBackgroundDuration > 0) { + onSubjectFilterDelete?.let { it(code) } + } + }, + content = { + Icon(Icons.Default.Delete, context.getString(R.string.action_delete)) } - }, - content = { - Icon(Icons.Default.Delete, context.getString(R.string.action_delete)) - } - ) - } - ) + ) + } + ) + } } } - } - ) - OptionItem( - modifierInside = Modifier.padding(horizontal = 20.dp, vertical = 15.dp), - title = context.getString(R.string.settings_newsnotify_newsfilter_add), - leadingIcon = { Icon(Icons.Default.Add, context.getString(R.string.settings_newsnotify_newsfilter_add)) }, - isEnabled = isNewsSubjectEnabled == 2, - onClick = { - // Add a subject news filter - onSubjectFilterAdd?.let { it() } - } - ) - OptionItem( - modifierInside = Modifier.padding(horizontal = 20.dp, vertical = 15.dp), - title = context.getString(R.string.settings_newsnotify_newsfilter_deleteall), - leadingIcon = { Icon(Icons.Default.Delete, context.getString(R.string.settings_newsnotify_newsfilter_deleteall)) }, - isEnabled = isNewsSubjectEnabled == 2, - onClick = { - // Clear all subject news filter list - onSubjectFilterClear?.let { it() } - } - ) + ) + OptionItem( + modifierInside = Modifier.padding(horizontal = 20.dp, vertical = 15.dp), + title = context.getString(R.string.settings_newsnotify_newsfilter_add), + leadingIcon = { Icon(Icons.Default.Add, context.getString(R.string.settings_newsnotify_newsfilter_add)) }, + isEnabled = isNewsSubjectEnabled == 2, + onClick = { + // Add a subject news filter + onSubjectFilterAdd?.let { it() } + } + ) + OptionItem( + modifierInside = Modifier.padding(horizontal = 20.dp, vertical = 15.dp), + title = context.getString(R.string.settings_newsnotify_newsfilter_deleteall), + leadingIcon = { Icon(Icons.Default.Delete, context.getString(R.string.settings_newsnotify_newsfilter_deleteall)) }, + isEnabled = isNewsSubjectEnabled == 2, + onClick = { + // Clear all subject news filter list + onSubjectFilterClear?.let { it() } + } + ) + } } } } diff --git a/app/src/main/java/io/zoemeow/dutschedule/utils/FunctionExtension.kt b/app/src/main/java/io/zoemeow/dutschedule/utils/FunctionExtension.kt index afde51d..6b17971 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/utils/FunctionExtension.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/utils/FunctionExtension.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import java.math.BigInteger import java.security.MessageDigest import java.text.Normalizer +import java.util.Locale fun Context.openLink( url: String, @@ -51,6 +52,11 @@ fun Context.openLink( } } +fun String.capitalized(): String { + return this.split(" ") + .joinToString(separator = " ") { it.lowercase().replaceFirstChar(Char::uppercase) } +} + @Composable fun Modifier.endOfListReached( lazyListState: LazyListState, diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 2507491..07046e8 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -244,6 +244,17 @@ Số tín chỉ Chất lượng cao Công thức điểm + Lịch học + Lịch học trong tuần: %1$s + Tuần: %1$s + Lịch thi + Nhóm: %1$s %2$s + (thi chung) + Ngày thi: %1$s + Phòng: %1$s + Hiện tại không có lịch thi cho môn học này. + + Kết quả rèn luyện (không rõ) \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 96cd393..d6184a1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -229,7 +229,7 @@ Subject Information Subject Fee Account Information - Account Training Result + Training Result Logout Logout Are you sure you want to logout?\n\nNote that:\n- You won\'t be received your any subject schedule anymore.\n- Your news filter settings won\'t be affected. @@ -244,6 +244,17 @@ Credit(s) High Quality Final score formula + Schedule Study + Schedule in a week: %1$s + Week(s): %1$s + Schedule Examination + Group: %1$s %2$s + (global group) + Exam date: %1$s + Room: %1$s + Currently no examination schedule yet for this subject. + + Training Result (unknown) \ No newline at end of file diff --git a/build.gradle b/build.gradle index 8de17f9..f317c5f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.4.0' apply false + id 'com.android.application' version '8.4.1' apply false id 'org.jetbrains.kotlin.android' version '1.8.10' apply false id 'com.google.dagger.hilt.android' version '2.44' apply false }