From a70ccbb0d0828a99512ae032afd46918379ab1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= <m.pich@outlook.com> Date: Sun, 24 Jan 2021 17:20:26 +0100 Subject: [PATCH 01/28] Make strings in grade class stats translatable (#1092) --- app/build.gradle | 2 +- .../statistics/GradeStatisticsAdapter.kt | 47 ++++++++++--------- .../statistics/GradeStatisticsPresenter.kt | 1 + app/src/main/res/values/strings.xml | 4 ++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 6ccd6152..12ab69ed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -138,7 +138,7 @@ ext { } dependencies { - implementation "io.github.wulkanowy:sdk:0.24.1" + implementation "io.github.wulkanowy:sdk:a722e777" coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsAdapter.kt index cbcb444a..0ffb4225 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsAdapter.kt @@ -78,18 +78,18 @@ class GradeStatisticsAdapter @Inject constructor() : override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (holder) { - is PartialViewHolder -> bindPartialChart(holder, items[position].partial!!) - is SemesterViewHolder -> bindSemesterChart(holder, items[position].semester!!) - is PointsViewHolder -> bindBarChart(holder, items[position].points!!) + is PartialViewHolder -> bindPartialChart(holder.binding, items[position].partial!!) + is SemesterViewHolder -> bindSemesterChart(holder.binding, items[position].semester!!) + is PointsViewHolder -> bindBarChart(holder.binding, items[position].points!!) } } - private fun bindPartialChart(holder: PartialViewHolder, partials: GradePartialStatistics) { - bindPieChart(holder.binding, partials.subject, partials.classAverage, partials.classAmounts) + private fun bindPartialChart(binding: ItemGradeStatisticsPieBinding, partials: GradePartialStatistics) { + bindPieChart(binding, partials.subject, partials.classAverage, partials.classAmounts) } - private fun bindSemesterChart(holder: SemesterViewHolder, semester: GradeSemesterStatistics) { - bindPieChart(holder.binding, semester.subject, semester.average, semester.amounts) + private fun bindSemesterChart(binding: ItemGradeStatisticsPieBinding, semester: GradeSemesterStatistics) { + bindPieChart(binding, semester.subject, semester.average, semester.amounts) } private fun bindPieChart(binding: ItemGradeStatisticsPieBinding, subject: String, average: String, amounts: List<Int>) { @@ -103,9 +103,12 @@ class GradeStatisticsAdapter @Inject constructor() : else -> materialGradeColors } - val dataset = PieDataSet(amounts.mapIndexed { grade, amount -> - PieEntry(amount.toFloat(), (grade + 1).toString()) - }.reversed().filterNot { it.value == 0f }, "Legenda") + val dataset = PieDataSet( + amounts.mapIndexed { grade, amount -> + PieEntry(amount.toFloat(), (grade + 1).toString()) + }.reversed().filterNot { it.value == 0f }, + binding.root.context.getString(R.string.grade_statistics_legend) + ) with(dataset) { valueTextSize = 12f @@ -138,11 +141,13 @@ class GradeStatisticsAdapter @Inject constructor() : }) } + val numberOfGradesString = amounts.fold(0) { acc, it -> acc + it } + .let { resources.getQuantityString(R.plurals.grade_number_item, it, it) } + val averageString = binding.root.context.getString(R.string.grade_statistics_average, average) + minAngleForSlices = 25f description.isEnabled = false - centerText = amounts.fold(0) { acc, it -> acc + it } - .let { resources.getQuantityString(R.plurals.grade_number_item, it, it) } + - ("\n\nŚrednia: $average").takeIf { average.isNotBlank() }.orEmpty() + centerText = numberOfGradesString + ("\n\n" + averageString).takeIf { average.isNotBlank() }.orEmpty() setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground)) setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary)) @@ -150,8 +155,8 @@ class GradeStatisticsAdapter @Inject constructor() : } } - private fun bindBarChart(holder: PointsViewHolder, points: GradePointsStatistics) { - with(holder.binding.gradeStatisticsBarTitle) { + private fun bindBarChart(binding: ItemGradeStatisticsBarBinding, points: GradePointsStatistics) { + with(binding.gradeStatisticsBarTitle) { text = points.subject visibility = if (items.size == 1) GONE else VISIBLE } @@ -159,18 +164,18 @@ class GradeStatisticsAdapter @Inject constructor() : val dataset = BarDataSet(listOf( BarEntry(1f, points.others.toFloat()), BarEntry(2f, points.student.toFloat()) - ), "Legenda") + ), binding.root.context.getString(R.string.grade_statistics_legend)) with(dataset) { valueTextSize = 12f - valueTextColor = holder.binding.root.context.getThemeAttrColor(android.R.attr.textColorPrimary) + valueTextColor = binding.root.context.getThemeAttrColor(android.R.attr.textColorPrimary) valueFormatter = object : ValueFormatter() { override fun getBarLabel(barEntry: BarEntry) = "${barEntry.y}%" } colors = gradePointsColors } - with(holder.binding.gradeStatisticsBar) { + with(binding.gradeStatisticsBar) { setTouchEnabled(false) if (items.size == 1) animateXY(1000, 1000) data = BarData(dataset).apply { @@ -179,12 +184,12 @@ class GradeStatisticsAdapter @Inject constructor() : } legend.setCustom(listOf( LegendEntry().apply { - label = "Średnia klasy" + label = binding.root.context.getString(R.string.grade_statistics_average_class) formColor = gradePointsColors[0] form = Legend.LegendForm.SQUARE }, LegendEntry().apply { - label = "Uczeń" + label = binding.root.context.getString(R.string.grade_statistics_average_student) formColor = gradePointsColors[1] form = Legend.LegendForm.SQUARE } @@ -193,7 +198,7 @@ class GradeStatisticsAdapter @Inject constructor() : description.isEnabled = false - holder.binding.root.context.getThemeAttrColor(android.R.attr.textColorPrimary).let { + binding.root.context.getThemeAttrColor(android.R.attr.textColorPrimary).let { axisLeft.textColor = it axisRight.textColor = it } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt index 37f47869..47ea52d3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt @@ -172,6 +172,7 @@ class GradeStatisticsPresenter @Inject constructor( showErrorView(false) enableSwipe(true) showRefresh(true) + showProgress(false) updateData(it.data!!, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList) showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9d707d09..4364214c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -105,6 +105,10 @@ <string name="grade_statistics_partial">Partial</string> <string name="grade_statistics_semester">Semester</string> <string name="grade_statistics_points">Points</string> + <string name="grade_statistics_legend">Legend</string> + <string name="grade_statistics_average">Average: %1$s</string> + <string name="grade_statistics_average_class">Class</string> + <string name="grade_statistics_average_student">Student</string> <plurals name="grade_number_item"> <item quantity="one">%d grade</item> <item quantity="other">%d grades</item> From 52d359827edffb5f770fd9504cac5413c37e0f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= <m.pich@outlook.com> Date: Sun, 24 Jan 2021 17:21:02 +0100 Subject: [PATCH 02/28] Fix translations of month name in attendance summary (#1091) --- .../github/wulkanowy/utils/TimeExtension.kt | 25 +++++-------------- .../wulkanowy/utils/TimeExtensionTest.kt | 17 +++++++++++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt index 9bd30e87..d80abbd1 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt @@ -1,6 +1,7 @@ package io.github.wulkanowy.utils import android.annotation.SuppressLint +import java.text.SimpleDateFormat import java.time.DayOfWeek.FRIDAY import java.time.DayOfWeek.MONDAY import java.time.DayOfWeek.SATURDAY @@ -8,12 +9,12 @@ import java.time.DayOfWeek.SUNDAY import java.time.Instant.ofEpochMilli import java.time.LocalDate import java.time.LocalDateTime +import java.time.LocalDateTime.now import java.time.LocalDateTime.ofInstant import java.time.Month import java.time.ZoneId import java.time.ZoneOffset import java.time.format.DateTimeFormatter.ofPattern -import java.time.format.TextStyle.FULL import java.time.temporal.TemporalAdjusters.firstInMonth import java.time.temporal.TemporalAdjusters.next import java.time.temporal.TemporalAdjusters.previous @@ -33,24 +34,10 @@ fun LocalDateTime.toFormattedString(format: String = DATE_PATTERN): String = for @SuppressLint("DefaultLocale") fun Month.getFormattedName(): String { - return getDisplayName(FULL, Locale.getDefault()) - .let { - when (it) { - "stycznia" -> "Styczeń" - "lutego" -> "Luty" - "marca" -> "Marzec" - "kwietnia" -> "Kwiecień" - "maja" -> "Maj" - "czerwca" -> "Czerwiec" - "lipca" -> "Lipiec" - "sierpnia" -> "Sierpień" - "września" -> "Wrzesień" - "października" -> "Październik" - "listopada" -> "Listopad" - "grudnia" -> "Grudzień" - else -> it - } - }.capitalize() + val formatter = SimpleDateFormat("LLLL", Locale.getDefault()) + + val date = now().withMonth(value) + return formatter.format(date.toInstant(ZoneOffset.UTC).toEpochMilli()).capitalize() } inline val LocalDate.nextSchoolDay: LocalDate diff --git a/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt b/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt index 3336c0d9..0ffbf78e 100644 --- a/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt +++ b/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt @@ -50,15 +50,28 @@ class TimeExtensionTest { fun monthNameTest() { Locale.setDefault(Locale.forLanguageTag("PL")) assertEquals("Styczeń", JANUARY.getFormattedName()) - Locale.setDefault(Locale.forLanguageTag("EN")) + + Locale.setDefault(Locale.forLanguageTag("CS")) + assertEquals("Leden", JANUARY.getFormattedName()) + + Locale.setDefault(Locale.ENGLISH) assertEquals("January", JANUARY.getFormattedName()) + + Locale.setDefault(Locale.forLanguageTag("DE")) + assertEquals("Januar", JANUARY.getFormattedName()) + + Locale.setDefault(Locale.forLanguageTag("RU")) + assertEquals("Январь", JANUARY.getFormattedName()) + + Locale.setDefault(Locale.forLanguageTag("UK")) + assertEquals("Січень", JANUARY.getFormattedName()) } @Test fun weekDayNameTest() { Locale.setDefault(Locale.forLanguageTag("PL")) assertEquals("poniedziałek", of(2018, 10, 1).weekDayName) - Locale.setDefault(Locale.forLanguageTag("EN")) + Locale.setDefault(Locale.ENGLISH) assertEquals("Monday", of(2018, 10, 1).weekDayName) } From 3a887f597be49ec2c482708b22a48008e8a7de3c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 16:52:16 +0000 Subject: [PATCH 03/28] Bump hilt_version from 2.30.1-alpha to 2.31.2-alpha (#1094) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 81794ab6..b2e02626 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { kotlin_version = '1.4.21' about_libraries = '8.6.7' - hilt_version = "2.30.1-alpha" + hilt_version = "2.31.2-alpha" } repositories { mavenCentral() From f37ddfe00f3b647d0cfa23c340b1178edc9dc597 Mon Sep 17 00:00:00 2001 From: Damian Czupryn <60961958+Daxxxis@users.noreply.github.com> Date: Sun, 24 Jan 2021 20:01:18 +0100 Subject: [PATCH 04/28] Disable vibrations in data picker (#1093) --- .../github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt | 1 + .../github/wulkanowy/ui/modules/timetable/TimetableFragment.kt | 1 + .../ui/modules/timetable/additional/AdditionalLessonsFragment.kt | 1 + .../ui/modules/timetable/completed/CompletedLessonsFragment.kt | 1 + 4 files changed, 4 insertions(+) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt index a106bc50..83ed163f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt @@ -222,6 +222,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag setDateRangeLimiter(SchooldaysRangeLimiter()) version = DatePickerDialog.Version.VERSION_2 scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL + vibrate(false) show(this@AttendanceFragment.parentFragmentManager, null) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt index 1bb9c920..21585cc9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt @@ -176,6 +176,7 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme setDateRangeLimiter(SchooldaysRangeLimiter()) version = DatePickerDialog.Version.VERSION_2 scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL + vibrate(false) show(this@TimetableFragment.parentFragmentManager, null) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt index 17a1cabe..559366a9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt @@ -128,6 +128,7 @@ class AdditionalLessonsFragment : setDateRangeLimiter(SchooldaysRangeLimiter()) version = DatePickerDialog.Version.VERSION_2 scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL + vibrate(false) show(this@AdditionalLessonsFragment.parentFragmentManager, null) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt index 828e1001..f8634a9b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt @@ -147,6 +147,7 @@ class CompletedLessonsFragment : setDateRangeLimiter(SchooldaysRangeLimiter()) version = DatePickerDialog.Version.VERSION_2 scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL + vibrate(false) show(this@CompletedLessonsFragment.parentFragmentManager, null) } } From e0b067faddfdbe6bbc5ffec504badbf2aaacec6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= <RafalBO99@outlook.com> Date: Wed, 27 Jan 2021 00:18:56 +0100 Subject: [PATCH 05/28] Fix selected semester after change account (#1097) --- .../io/github/wulkanowy/ui/modules/grade/GradeFragment.kt | 8 +------- .../github/wulkanowy/ui/modules/grade/GradePresenter.kt | 6 ++---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt index 0678e13e..91e39e06 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt @@ -33,7 +33,6 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade private var semesterSwitchMenu: MenuItem? = null companion object { - private const val SAVED_SEMESTER_KEY = "CURRENT_SEMESTER" fun newInstance() = GradeFragment() } @@ -52,7 +51,7 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding = FragmentGradeBinding.bind(view) - presenter.onAttachView(this, savedInstanceState?.getInt(SAVED_SEMESTER_KEY)) + presenter.onAttachView(this) } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -161,11 +160,6 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade (pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentChangeSemester() } - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putInt(SAVED_SEMESTER_KEY, presenter.selectedIndex) - } - override fun onDestroyView() { presenter.onDetachView() super.onDestroyView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt index d64613c0..bfc504d2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt @@ -21,8 +21,7 @@ class GradePresenter @Inject constructor( private val analytics: AnalyticsHelper ) : BasePresenter<GradeView>(errorHandler, studentRepository) { - var selectedIndex = 0 - private set + private var selectedIndex = 0 private var schoolYear = 0 @@ -32,9 +31,8 @@ class GradePresenter @Inject constructor( private lateinit var lastError: Throwable - fun onAttachView(view: GradeView, savedIndex: Int?) { + override fun onAttachView(view: GradeView) { super.onAttachView(view) - selectedIndex = savedIndex ?: 0 view.initView() Timber.i("Grade view was initialized with $selectedIndex index") errorHandler.showErrorMessage = ::showErrorViewOnError From 6a8161cd98bd921bebe2c1c77c008ead85ac7880 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 Jan 2021 20:26:38 +0000 Subject: [PATCH 06/28] Bump firebase-bom from 26.3.0 to 26.4.0 (#1102) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 12ab69ed..dec66756 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -194,7 +194,7 @@ dependencies { implementation "io.github.wulkanowy:AppKillerManager:3.0.0" implementation 'me.xdrop:fuzzywuzzy:1.3.1' - playImplementation platform('com.google.firebase:firebase-bom:26.3.0') + playImplementation platform('com.google.firebase:firebase-bom:26.4.0') playImplementation 'com.google.firebase:firebase-analytics-ktx' playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx' playImplementation "com.google.firebase:firebase-inappmessaging-ktx" From 5581fdcab85a3010452eb7ac831505254bc3c41c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 Jan 2021 20:56:54 +0000 Subject: [PATCH 07/28] Bump google-services from 4.3.4 to 4.3.5 (#1104) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b2e02626..5d76b1a0 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.android.tools.build:gradle:4.1.2' classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" - classpath 'com.google.gms:google-services:4.3.4' + classpath 'com.google.gms:google-services:4.3.5' classpath 'com.huawei.agconnect:agcp:1.4.2.301' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1' classpath "com.github.triplet.gradle:play-publisher:2.8.0" From 2bcbac5ab3b5c01f8553b1e091050933ab019540 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 Jan 2021 20:57:22 +0000 Subject: [PATCH 08/28] Bump about_libraries from 8.6.7 to 8.6.9 (#1098) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5d76b1a0..ca135f1e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { ext { kotlin_version = '1.4.21' - about_libraries = '8.6.7' + about_libraries = '8.6.9' hilt_version = "2.31.2-alpha" } repositories { From c0a53cb90c2b0dfe954546a7942b2978b89d132c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 Jan 2021 20:57:53 +0000 Subject: [PATCH 09/28] Bump sonarqube-gradle-plugin from 3.1 to 3.1.1 (#1100) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ca135f1e..9bdfdd2d 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ buildscript { classpath 'com.huawei.agconnect:agcp:1.4.2.301' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1' classpath "com.github.triplet.gradle:play-publisher:2.8.0" - classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.1" + classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.1.1" classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries" } From 26565b627abf6a72c6bc693391f85c6a765fe275 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 Jan 2021 20:58:15 +0000 Subject: [PATCH 10/28] Bump work_manager from 2.4.0 to 2.5.0 (#1103) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index dec66756..759be410 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -130,7 +130,7 @@ play { } ext { - work_manager = "2.4.0" + work_manager = "2.5.0" room = "2.2.6" chucker = "3.4.0" mockk = "1.10.5" From d79b1c9a58bfd09d8cdda09070304144e26d0022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= <RafalBO99@outlook.com> Date: Fri, 29 Jan 2021 21:53:46 +0100 Subject: [PATCH 11/28] Add account manager (#671) --- .idea/codeStyles/Project.xml | 15 +- app/build.gradle | 5 +- .../31.json | 2136 +++++++++++++++++ .../wulkanowy/data/TestDispatchersProvider.kt | 11 - .../github/wulkanowy/data/RepositoryModule.kt | 29 +- .../github/wulkanowy/data/db/AppDatabase.kt | 9 +- .../wulkanowy/data/db/dao/StudentInfoDao.kt | 15 + .../wulkanowy/data/db/entities/Student.kt | 10 +- .../wulkanowy/data/db/entities/StudentInfo.kt | 85 + .../data/db/migrations/Migration31.kt | 42 + .../io/github/wulkanowy/data/enums/Gender.kt | 3 + .../data/mappers/StudentInfoMapper.kt | 38 + .../data/repositories/SchoolRepository.kt | 29 +- .../repositories/StudentInfoRepository.kt | 38 + .../repositories/student/StudentRemote.kt | 0 .../ui/modules/about/AboutFragment.kt | 6 +- .../ui/modules/account/AccountAdapter.kt | 65 +- .../ui/modules/account/AccountDialog.kt | 102 - .../ui/modules/account/AccountFragment.kt | 111 + .../ui/modules/account/AccountPresenter.kt | 131 +- .../ui/modules/account/AccountView.kt | 17 +- .../accountdetails/AccountDetailsFragment.kt | 134 ++ .../accountdetails/AccountDetailsPresenter.kt | 100 + .../accountdetails/AccountDetailsView.kt | 25 + .../AccountEditDetailsDialog.kt | 38 + .../accountquick/AccountQuickDialog.kt | 82 + .../accountquick/AccountQuickPresenter.kt | 79 + .../account/accountquick/AccountQuickView.kt | 17 + .../modules/attendance/AttendanceFragment.kt | 1 + .../wulkanowy/ui/modules/main/MainActivity.kt | 125 +- .../wulkanowy/ui/modules/main/MainView.kt | 4 +- .../school/SchoolPresenter.kt | 5 +- .../modules/studentinfo/StudentInfoAdapter.kt | 42 + .../studentinfo/StudentInfoFragment.kt | 228 ++ .../studentinfo/StudentInfoPresenter.kt | 142 ++ .../ui/modules/studentinfo/StudentInfoView.kt | 48 + .../java/io/github/wulkanowy/utils/AppInfo.kt | 5 + .../io/github/wulkanowy/utils/FlowUtils.kt | 24 +- .../wulkanowy/utils/FragmentExtension.kt | 6 + .../drawable/ic_account_details_family.xml | 9 + ...{ic_about_homepage.xml => ic_all_home.xml} | 0 .../{ic_school_phone.xml => ic_all_phone.xml} | 0 .../layout/dialog_account_edit_details.xml | 82 + ...g_account.xml => dialog_account_quick.xml} | 29 +- app/src/main/res/layout/fragment_account.xml | 91 + .../res/layout/fragment_account_details.xml | 206 ++ app/src/main/res/layout/fragment_school.xml | 2 +- .../main/res/layout/fragment_student_info.xml | 108 + app/src/main/res/layout/header_account.xml | 14 +- app/src/main/res/layout/item_account.xml | 7 +- app/src/main/res/layout/item_student_info.xml | 41 + .../res/menu/action_menu_account_details.xml | 11 + app/src/main/res/values/strings.xml | 39 +- .../data/repositories/StudentTest.kt | 4 +- .../modules/grade/GradeAverageProviderTest.kt | 24 +- .../login/form/LoginFormPresenterTest.kt | 28 +- .../LoginStudentSelectPresenterTest.kt | 57 +- gradle.properties | 5 +- 58 files changed, 4409 insertions(+), 350 deletions(-) create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json delete mode 100644 app/src/androidTest/java/io/github/wulkanowy/data/TestDispatchersProvider.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/StudentInfoDao.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/StudentInfo.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration31.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/enums/Gender.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/mappers/StudentInfoMapper.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRemote.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickView.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoAdapter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoView.kt create mode 100644 app/src/main/res/drawable/ic_account_details_family.xml rename app/src/main/res/drawable/{ic_about_homepage.xml => ic_all_home.xml} (100%) rename app/src/main/res/drawable/{ic_school_phone.xml => ic_all_phone.xml} (100%) create mode 100644 app/src/main/res/layout/dialog_account_edit_details.xml rename app/src/main/res/layout/{dialog_account.xml => dialog_account_quick.xml} (62%) create mode 100644 app/src/main/res/layout/fragment_account.xml create mode 100644 app/src/main/res/layout/fragment_account_details.xml create mode 100644 app/src/main/res/layout/fragment_student_info.xml create mode 100644 app/src/main/res/layout/item_student_info.xml create mode 100644 app/src/main/res/menu/action_menu_account_details.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index cb2f4119..0ac66f64 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -18,18 +18,9 @@ </option> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" /> - <option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="false" /> - <option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="false" /> - <option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="false" /> - <option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="false" /> - <option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" /> - <option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" /> - <option name="CONTINUATION_INDENT_IN_ELVIS" value="false" /> <option name="WRAP_ELVIS_EXPRESSIONS" value="0" /> + <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> </JetCodeStyleSettings> - <MarkdownNavigatorCodeStyleSettings> - <option name="RIGHT_MARGIN" value="72" /> - </MarkdownNavigatorCodeStyleSettings> <codeStyleSettings language="XML"> <indentOptions> <option name="CONTINUATION_INDENT_SIZE" value="4" /> @@ -143,13 +134,11 @@ </arrangement> </codeStyleSettings> <codeStyleSettings language="kotlin"> + <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" /> <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> - <option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" /> - <option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" /> - <option name="EXTENDS_LIST_WRAP" value="1" /> <indentOptions> <option name="CONTINUATION_INDENT_SIZE" value="4" /> </indentOptions> diff --git a/app/build.gradle b/app/build.gradle index 759be410..6e7bb42d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -131,14 +131,14 @@ play { ext { work_manager = "2.5.0" - room = "2.2.6" + room = "2.3.0-alpha04" chucker = "3.4.0" mockk = "1.10.5" moshi = "1.11.0" } dependencies { - implementation "io.github.wulkanowy:sdk:a722e777" + implementation "io.github.wulkanowy:sdk:b7576e86" coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' @@ -214,6 +214,7 @@ dependencies { testImplementation "junit:junit:4.13.1" testImplementation "io.mockk:mockk:$mockk" testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2' + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" androidTestImplementation "androidx.test:core:1.3.0" androidTestImplementation "androidx.test:runner:1.3.0" diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json new file mode 100644 index 00000000..55a51e04 --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json @@ -0,0 +1,2136 @@ +{ + "formatVersion": 1, + "database": { + "version": 31, + "identityHash": "d642512ffa5fe81ae9308c9c55612539", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scrapperBaseUrl", + "columnName": "scrapper_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mobileBaseUrl", + "columnName": "mobile_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "login_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginMode", + "columnName": "login_mode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "certificateKey", + "columnName": "certificate_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "privateKey", + "columnName": "private_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isParent", + "columnName": "is_parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "user_login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userName", + "columnName": "user_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolShortName", + "columnName": "school_short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "current", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isStudentPlan", + "columnName": "student_plan", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timeId", + "columnName": "time_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excused", + "columnName": "excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excusable", + "columnName": "excusable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excuseStatus", + "columnName": "excuse_status", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPredictedGradeNotified", + "columnName": "is_predicted_grade_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isFinalGradeNotified", + "columnName": "is_final_grade_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "predictedGradeLastChange", + "columnName": "predicted_grade_last_change", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "finalGradeLastChange", + "columnName": "final_grade_last_change", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradePartialStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classAverage", + "columnName": "class_average", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentAverage", + "columnName": "student_average", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classAmounts", + "columnName": "class_amounts", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentAmounts", + "columnName": "student_amounts", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesPointsStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "others", + "columnName": "others", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "student", + "columnName": "student", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradeSemesterStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amounts", + "columnName": "amounts", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentGrade", + "columnName": "student_grade", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `content` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasAttachments", + "columnName": "has_attachments", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MessageAttachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))", + "fields": [ + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "oneDriveId", + "columnName": "one_drive_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filename", + "columnName": "filename", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "real_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "categoryType", + "columnName": "category_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPointsShow", + "columnName": "is_points_show", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDone", + "columnName": "is_done", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attachments", + "columnName": "attachments", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MobileDevices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "device_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "School", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contact", + "columnName": "contact", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "headmaster", + "columnName": "headmaster", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pedagogue", + "columnName": "pedagogue", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Conferences", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "agenda", + "columnName": "agenda", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presentOnConference", + "columnName": "present_on_conference", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "conferenceId", + "columnName": "conference_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "TimetableAdditional", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "StudentInfo", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `first_guardian_full_name` TEXT NOT NULL, `first_guardian_kinship` TEXT NOT NULL, `first_guardian_address` TEXT NOT NULL, `first_guardian_phones` TEXT NOT NULL, `first_guardian_email` TEXT NOT NULL, `second_guardian_full_name` TEXT NOT NULL, `second_guardian_kinship` TEXT NOT NULL, `second_guardian_address` TEXT NOT NULL, `second_guardian_phones` TEXT NOT NULL, `second_guardian_email` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "full_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "first_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondName", + "columnName": "second_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "surname", + "columnName": "surname", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "birthDate", + "columnName": "birth_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "birthPlace", + "columnName": "birth_place", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gender", + "columnName": "gender", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasPolishCitizenship", + "columnName": "has_polish_citizenship", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "familyName", + "columnName": "family_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentsNames", + "columnName": "parents_names", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "registeredAddress", + "columnName": "registered_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "correspondenceAddress", + "columnName": "correspondence_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phoneNumber", + "columnName": "phone_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cellPhoneNumber", + "columnName": "cell_phone_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.fullName", + "columnName": "first_guardian_full_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.kinship", + "columnName": "first_guardian_kinship", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.address", + "columnName": "first_guardian_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.phones", + "columnName": "first_guardian_phones", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.email", + "columnName": "first_guardian_email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.fullName", + "columnName": "second_guardian_full_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.kinship", + "columnName": "second_guardian_kinship", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.address", + "columnName": "second_guardian_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.phones", + "columnName": "second_guardian_phones", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.email", + "columnName": "second_guardian_email", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd642512ffa5fe81ae9308c9c55612539')" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/TestDispatchersProvider.kt b/app/src/androidTest/java/io/github/wulkanowy/data/TestDispatchersProvider.kt deleted file mode 100644 index 8c4354d9..00000000 --- a/app/src/androidTest/java/io/github/wulkanowy/data/TestDispatchersProvider.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.wulkanowy.data - -import io.github.wulkanowy.utils.DispatchersProvider -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers - -class TestDispatchersProvider : DispatchersProvider() { - - override val backgroundThread: CoroutineDispatcher - get() = Dispatchers.Unconfined -} diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt index 324cb89f..8b850659 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt @@ -33,17 +33,21 @@ internal class RepositoryModule { setSimpleHttpLogger { Timber.d(it) } // for debug only - addInterceptor(ChuckerInterceptor.Builder(context) - .collector(chuckerCollector) - .alwaysReadResponseBody(true) - .build(), network = true + addInterceptor( + ChuckerInterceptor.Builder(context) + .collector(chuckerCollector) + .alwaysReadResponseBody(true) + .build(), network = true ) } } @Singleton @Provides - fun provideChuckerCollector(@ApplicationContext context: Context, prefRepository: PreferencesRepository): ChuckerCollector { + fun provideChuckerCollector( + @ApplicationContext context: Context, + prefRepository: PreferencesRepository + ): ChuckerCollector { return ChuckerCollector( context = context, showNotification = prefRepository.isDebugNotificationEnable, @@ -53,7 +57,10 @@ internal class RepositoryModule { @Singleton @Provides - fun provideDatabase(@ApplicationContext context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider) + fun provideDatabase( + @ApplicationContext context: Context, + sharedPrefProvider: SharedPrefProvider, + ) = AppDatabase.newInstance(context, sharedPrefProvider) @Singleton @Provides @@ -65,7 +72,8 @@ internal class RepositoryModule { @Singleton @Provides - fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = + PreferenceManager.getDefaultSharedPreferences(context) @Singleton @Provides @@ -89,7 +97,8 @@ internal class RepositoryModule { @Singleton @Provides - fun provideGradeSemesterStatisticsDao(database: AppDatabase) = database.gradeSemesterStatisticsDao + fun provideGradeSemesterStatisticsDao(database: AppDatabase) = + database.gradeSemesterStatisticsDao @Singleton @Provides @@ -166,4 +175,8 @@ internal class RepositoryModule { @Singleton @Provides fun provideTimetableAdditionalDao(database: AppDatabase) = database.timetableAdditionalDao + + @Singleton + @Provides + fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index 6b2301fc..d1f99e3e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -28,6 +28,7 @@ import io.github.wulkanowy.data.db.dao.ReportingUnitDao import io.github.wulkanowy.data.db.dao.SchoolDao import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.StudentDao +import io.github.wulkanowy.data.db.dao.StudentInfoDao import io.github.wulkanowy.data.db.dao.SubjectDao import io.github.wulkanowy.data.db.dao.TeacherDao import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao @@ -53,6 +54,7 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.db.entities.School import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.StudentInfo import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Teacher import io.github.wulkanowy.data.db.entities.Timetable @@ -80,6 +82,7 @@ import io.github.wulkanowy.data.db.migrations.Migration28 import io.github.wulkanowy.data.db.migrations.Migration29 import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration30 +import io.github.wulkanowy.data.db.migrations.Migration31 import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration5 import io.github.wulkanowy.data.db.migrations.Migration6 @@ -116,6 +119,7 @@ import javax.inject.Singleton School::class, Conference::class, TimetableAdditional::class, + StudentInfo::class, ], version = AppDatabase.VERSION_SCHEMA, exportSchema = true @@ -124,7 +128,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 30 + const val VERSION_SCHEMA = 31 fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> { return arrayOf( @@ -157,6 +161,7 @@ abstract class AppDatabase : RoomDatabase() { Migration28(), Migration29(), Migration30(), + Migration31() ) } @@ -219,4 +224,6 @@ abstract class AppDatabase : RoomDatabase() { abstract val conferenceDao: ConferenceDao abstract val timetableAdditionalDao: TimetableAdditionalDao + + abstract val studentInfoDao: StudentInfoDao } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentInfoDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentInfoDao.kt new file mode 100644 index 00000000..5ec86af1 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentInfoDao.kt @@ -0,0 +1,15 @@ +package io.github.wulkanowy.data.db.dao + +import androidx.room.Dao +import androidx.room.Query +import io.github.wulkanowy.data.db.entities.StudentInfo +import kotlinx.coroutines.flow.Flow +import javax.inject.Singleton + +@Singleton +@Dao +interface StudentInfoDao : BaseDao<StudentInfo> { + + @Query("SELECT * FROM StudentInfo WHERE student_id = :studentId") + fun loadStudentInfo(studentId: Int): Flow<StudentInfo?> +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt index b6c75ff8..0b37b1e9 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt @@ -7,7 +7,13 @@ import androidx.room.PrimaryKey import java.io.Serializable import java.time.LocalDateTime -@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)]) +@Entity( + tableName = "Students", + indices = [Index( + value = ["email", "symbol", "student_id", "school_id", "class_id"], + unique = true + )] +) data class Student( @ColumnInfo(name = "scrapper_base_url") @@ -52,7 +58,7 @@ data class Student( @ColumnInfo(name = "school_id") val schoolSymbol: String, - @ColumnInfo(name ="school_short") + @ColumnInfo(name = "school_short") val schoolShortName: String, @ColumnInfo(name = "school_name") diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/StudentInfo.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/StudentInfo.kt new file mode 100644 index 00000000..70d00194 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/StudentInfo.kt @@ -0,0 +1,85 @@ +package io.github.wulkanowy.data.db.entities + +import androidx.room.ColumnInfo +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.PrimaryKey +import io.github.wulkanowy.data.enums.Gender +import java.io.Serializable +import java.time.LocalDate + +@Entity(tableName = "StudentInfo") +data class StudentInfo( + + @ColumnInfo(name = "student_id") + val studentId: Int, + + @ColumnInfo(name = "full_name") + val fullName: String, + + @ColumnInfo(name = "first_name") + val firstName: String, + + @ColumnInfo(name = "second_name") + val secondName: String, + + val surname: String, + + @ColumnInfo(name = "birth_date") + val birthDate: LocalDate, + + @ColumnInfo(name = "birth_place") + val birthPlace: String, + + val gender: Gender, + + @ColumnInfo(name = "has_polish_citizenship") + val hasPolishCitizenship: Boolean, + + @ColumnInfo(name = "family_name") + val familyName: String, + + @ColumnInfo(name = "parents_names") + val parentsNames: String, + + val address: String, + + @ColumnInfo(name = "registered_address") + val registeredAddress: String, + + @ColumnInfo(name = "correspondence_address") + val correspondenceAddress: String, + + @ColumnInfo(name = "phone_number") + val phoneNumber: String, + + @ColumnInfo(name = "cell_phone_number") + val cellPhoneNumber: String, + + val email: String, + + @Embedded(prefix = "first_guardian_") + val firstGuardian: StudentGuardian, + + @Embedded(prefix = "second_guardian_") + val secondGuardian: StudentGuardian + +) : Serializable { + + @PrimaryKey(autoGenerate = true) + var id: Long = 0 +} + +data class StudentGuardian( + + @ColumnInfo(name = "full_name") + val fullName: String, + + val kinship: String, + + val address: String, + + val phones: String, + + val email: String +) : Serializable diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration31.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration31.kt new file mode 100644 index 00000000..064a3e5b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration31.kt @@ -0,0 +1,42 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration31 : Migration(30, 31) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL( + """CREATE TABLE IF NOT EXISTS StudentInfo ( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + student_id INTEGER NOT NULL, + full_name TEXT NOT NULL, + first_name TEXT NOT NULL, + second_name TEXT NOT NULL, + surname TEXT NOT NULL, + birth_date INTEGER NOT NULL, + birth_place TEXT NOT NULL, + gender TEXT NOT NULL, + has_polish_citizenship INTEGER NOT NULL, + family_name TEXT NOT NULL, + parents_names TEXT NOT NULL, + address TEXT NOT NULL, + registered_address TEXT NOT NULL, + correspondence_address TEXT NOT NULL, + phone_number TEXT NOT NULL, + cell_phone_number TEXT NOT NULL, + email TEXT NOT NULL, + first_guardian_full_name TEXT NOT NULL, + first_guardian_kinship TEXT NOT NULL, + first_guardian_address TEXT NOT NULL, + first_guardian_phones TEXT NOT NULL, + first_guardian_email TEXT NOT NULL, + second_guardian_full_name TEXT NOT NULL, + second_guardian_kinship TEXT NOT NULL, + second_guardian_address TEXT NOT NULL, + second_guardian_phones TEXT NOT NULL, + second_guardian_email TEXT NOT NULL) + """ + ) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/enums/Gender.kt b/app/src/main/java/io/github/wulkanowy/data/enums/Gender.kt new file mode 100644 index 00000000..df93dcbe --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/enums/Gender.kt @@ -0,0 +1,3 @@ +package io.github.wulkanowy.data.enums + +enum class Gender { MALE, FEMALE } diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/StudentInfoMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/StudentInfoMapper.kt new file mode 100644 index 00000000..ebdf9de2 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/mappers/StudentInfoMapper.kt @@ -0,0 +1,38 @@ +package io.github.wulkanowy.data.mappers + +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.StudentGuardian +import io.github.wulkanowy.data.db.entities.StudentInfo +import io.github.wulkanowy.data.enums.Gender +import io.github.wulkanowy.sdk.pojo.StudentGuardian as SdkStudentGuardian +import io.github.wulkanowy.sdk.pojo.StudentInfo as SdkStudentInfo + +fun SdkStudentInfo.mapToEntity(semester: Semester) = StudentInfo( + studentId = semester.studentId, + fullName = fullName, + firstName = firstName, + secondName = secondName, + surname = surname, + birthDate = birthDate, + birthPlace = birthPlace, + gender = Gender.valueOf(gender.name), + hasPolishCitizenship = hasPolishCitizenship, + familyName = familyName, + parentsNames = parentsNames, + address = address, + registeredAddress = registeredAddress, + correspondenceAddress = correspondenceAddress, + phoneNumber = phoneNumber, + cellPhoneNumber = phoneNumber, + email = email, + firstGuardian = guardians[0].mapToEntity(), + secondGuardian = guardians[1].mapToEntity() +) + +fun SdkStudentGuardian.mapToEntity() = StudentGuardian( + fullName = fullName, + kinship = kinship, + address = address, + phones = phones, + email = email +) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt index 36d5c974..6b22b32c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt @@ -16,16 +16,23 @@ class SchoolRepository @Inject constructor( private val sdk: Sdk ) { - fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource( - shouldFetch = { it == null || forceRefresh }, - query = { schoolDb.load(semester.studentId, semester.classId) }, - fetch = { sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool().mapToEntity(semester) }, - saveFetchResult = { old, new -> - if (new != old && old != null) { - schoolDb.deleteAll(listOf(old)) - schoolDb.insertAll(listOf(new)) + fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) = + networkBoundResource( + shouldFetch = { it == null || forceRefresh }, + query = { schoolDb.load(semester.studentId, semester.classId) }, + fetch = { + sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool() + .mapToEntity(semester) + }, + saveFetchResult = { old, new -> + if (old != null && new != old) { + with(schoolDb) { + deleteAll(listOf(old)) + insertAll(listOf(new)) + } + } else if (old == null) { + schoolDb.insertAll(listOf(new)) + } } - schoolDb.insertAll(listOf(new)) - } - ) + ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt new file mode 100644 index 00000000..e3deb447 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt @@ -0,0 +1,38 @@ +package io.github.wulkanowy.data.repositories + +import io.github.wulkanowy.data.db.dao.StudentInfoDao +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.mappers.mapToEntity +import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init +import io.github.wulkanowy.utils.networkBoundResource +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class StudentInfoRepository @Inject constructor( + private val studentInfoDao: StudentInfoDao, + private val sdk: Sdk +) { + + fun getStudentInfo(student: Student, semester: Semester, forceRefresh: Boolean) = + networkBoundResource( + shouldFetch = { it == null || forceRefresh }, + query = { studentInfoDao.loadStudentInfo(student.studentId) }, + fetch = { + sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getStudentInfo().mapToEntity(semester) + }, + saveFetchResult = { old, new -> + if (old != null && new != old) { + with(studentInfoDao) { + deleteAll(listOf(old)) + insertAll(listOf(new)) + } + } else if (old == null) { + studentInfoDao.insertAll(listOf(new)) + } + } + ) +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRemote.kt new file mode 100644 index 00000000..e69de29b diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt index 0730033f..c616c31e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt @@ -65,7 +65,11 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about override val homepageRes: Triple<String, String, Drawable?>? get() = context?.run { - Triple(getString(R.string.about_homepage), getString(R.string.about_homepage_summary), getCompatDrawable(R.drawable.ic_about_homepage)) + Triple( + getString(R.string.about_homepage), + getString(R.string.about_homepage_summary), + getCompatDrawable(R.drawable.ic_all_home) + ) } override val licensesRes: Triple<String, String, Drawable?>? diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt index 7ecb4139..4aa17073 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt @@ -8,16 +8,16 @@ import android.view.View.VISIBLE import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import io.github.wulkanowy.R -import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.HeaderAccountBinding import io.github.wulkanowy.databinding.ItemAccountBinding -import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() { + var isAccountQuickDialogMode = false + var items = emptyList<AccountItem<*>>() var onClickListener: (StudentWithSemesters) -> Unit = {} @@ -30,54 +30,69 @@ class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.V val inflater = LayoutInflater.from(parent.context) return when (viewType) { - AccountItem.ViewType.HEADER.id -> HeaderViewHolder(HeaderAccountBinding.inflate(inflater, parent, false)) - AccountItem.ViewType.ITEM.id -> ItemViewHolder(ItemAccountBinding.inflate(inflater, parent, false)) + AccountItem.ViewType.HEADER.id -> HeaderViewHolder( + HeaderAccountBinding.inflate(inflater, parent, false) + ) + AccountItem.ViewType.ITEM.id -> ItemViewHolder( + ItemAccountBinding.inflate(inflater, parent, false) + ) else -> throw IllegalStateException() } } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (holder) { - is HeaderViewHolder -> bindHeaderViewHolder(holder.binding, items[position].value as Account) - is ItemViewHolder -> bindItemViewHolder(holder.binding, items[position].value as StudentWithSemesters) + is HeaderViewHolder -> bindHeaderViewHolder( + holder.binding, + items[position].value as Account, + position + ) + is ItemViewHolder -> bindItemViewHolder( + holder.binding, + items[position].value as StudentWithSemesters + ) } } - private fun bindHeaderViewHolder(binding: HeaderAccountBinding, account: Account) { + private fun bindHeaderViewHolder( + binding: HeaderAccountBinding, + account: Account, + position: Int + ) { with(binding) { + accountHeaderDivider.visibility = if (position == 0) GONE else VISIBLE accountHeaderEmail.text = account.email accountHeaderType.setText(if (account.isParent) R.string.account_type_parent else R.string.account_type_student) } } @SuppressLint("SetTextI18n") - private fun bindItemViewHolder(binding: ItemAccountBinding, studentWithSemesters: StudentWithSemesters) { + private fun bindItemViewHolder( + binding: ItemAccountBinding, + studentWithSemesters: StudentWithSemesters + ) { val student = studentWithSemesters.student val semesters = studentWithSemesters.semesters val diary = semesters.maxByOrNull { it.semesterId } + val isDuplicatedStudent = items.filter { + if (it.value !is StudentWithSemesters) return@filter false + val studentToCompare = it.value.student + + studentToCompare.studentId == student.studentId + && studentToCompare.schoolSymbol == student.schoolSymbol + && studentToCompare.symbol == student.symbol + }.size > 1 && isAccountQuickDialogMode with(binding) { accountItemName.text = "${student.studentName} ${diary?.diaryName.orEmpty()}" accountItemSchool.text = studentWithSemesters.student.schoolName - with(accountItemLoginMode) { - visibility = when (Sdk.Mode.valueOf(student.loginMode)) { - Sdk.Mode.API -> { - setText(R.string.account_login_mobile_api) - VISIBLE - } - Sdk.Mode.HYBRID -> { - setText(R.string.account_login_hybrid) - VISIBLE - } - Sdk.Mode.SCRAPPER -> { - GONE - } - } - } + accountItemAccountType.setText(if (student.isParent) R.string.account_type_parent else R.string.account_type_student) + accountItemAccountType.visibility = if (isDuplicatedStudent) VISIBLE else GONE with(accountItemImage) { - val colorImage = if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary) - else context.getThemeAttrColor(R.attr.colorOnSurface, 153) + val colorImage = + if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary) + else context.getThemeAttrColor(R.attr.colorOnSurface, 153) setColorFilter(colorImage, PorterDuff.Mode.SRC_IN) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt deleted file mode 100644 index 1fa87268..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt +++ /dev/null @@ -1,102 +0,0 @@ -package io.github.wulkanowy.ui.modules.account - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import android.widget.Toast.LENGTH_LONG -import androidx.appcompat.app.AlertDialog -import androidx.recyclerview.widget.LinearLayoutManager -import dagger.hilt.android.AndroidEntryPoint -import io.github.wulkanowy.R -import io.github.wulkanowy.databinding.DialogAccountBinding -import io.github.wulkanowy.ui.base.BaseDialogFragment -import io.github.wulkanowy.ui.modules.login.LoginActivity -import javax.inject.Inject - -@AndroidEntryPoint -class AccountDialog : BaseDialogFragment<DialogAccountBinding>(), AccountView { - - @Inject - lateinit var presenter: AccountPresenter - - @Inject - lateinit var accountAdapter: AccountAdapter - - companion object { - fun newInstance() = AccountDialog() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setStyle(STYLE_NO_TITLE, 0) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return DialogAccountBinding.inflate(inflater).apply { binding = this }.root - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - presenter.onAttachView(this) - } - - override fun initView() { - accountAdapter.onClickListener = presenter::onItemSelected - - with(binding) { - accountDialogAdd.setOnClickListener { presenter.onAddSelected() } - accountDialogRemove.setOnClickListener { presenter.onRemoveSelected() } - accountDialogRecycler.apply { - layoutManager = LinearLayoutManager(context) - adapter = accountAdapter - } - } - } - - override fun updateData(data: List<AccountItem<*>>) { - with(accountAdapter) { - items = data - notifyDataSetChanged() - } - } - - override fun showError(text: String, error: Throwable) { - showMessage(text) - } - - override fun showMessage(text: String) { - Toast.makeText(context, text, LENGTH_LONG).show() - } - - override fun dismissView() { - dismiss() - } - - override fun openLoginView() { - activity?.let { - startActivity(LoginActivity.getStartIntent(it)) - } - } - - override fun showConfirmDialog() { - context?.let { - AlertDialog.Builder(it) - .setTitle(R.string.account_logout_student) - .setMessage(R.string.account_confirm) - .setPositiveButton(R.string.account_logout) { _, _ -> presenter.onLogoutConfirm() } - .setNegativeButton(android.R.string.cancel) { _, _ -> } - .show() - } - } - - override fun recreateMainView() { - activity?.recreate() - } - - override fun onDestroy() { - presenter.onDetachView() - super.onDestroy() - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt new file mode 100644 index 00000000..7293527e --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt @@ -0,0 +1,111 @@ +package io.github.wulkanowy.ui.modules.account + +import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.View +import androidx.core.view.get +import androidx.recyclerview.widget.LinearLayoutManager +import dagger.hilt.android.AndroidEntryPoint +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.databinding.FragmentAccountBinding +import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment +import io.github.wulkanowy.ui.modules.login.LoginActivity +import io.github.wulkanowy.ui.modules.main.MainActivity +import io.github.wulkanowy.ui.modules.main.MainView +import javax.inject.Inject + +@AndroidEntryPoint +class AccountFragment : BaseFragment<FragmentAccountBinding>(R.layout.fragment_account), + AccountView, MainView.TitledView { + + @Inject + lateinit var presenter: AccountPresenter + + @Inject + lateinit var accountAdapter: AccountAdapter + + companion object { + + fun newInstance() = AccountFragment() + } + + override val titleStringId = R.string.account_title + + override var subtitleString = "" + + override val isViewEmpty get() = accountAdapter.items.isEmpty() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setHasOptionsMenu(true) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentAccountBinding.bind(view) + presenter.onAttachView(this) + } + + override fun initView() { + binding.accountErrorRetry.setOnClickListener { presenter.onRetry() } + binding.accountErrorDetails.setOnClickListener { presenter.onDetailsClick() } + + binding.accountRecycler.apply { + layoutManager = LinearLayoutManager(context) + adapter = accountAdapter + } + + accountAdapter.onClickListener = presenter::onItemSelected + + with(binding) { + accountAdd.setOnClickListener { presenter.onAddSelected() } + } + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + menu[0].isVisible = false + } + + override fun updateData(data: List<AccountItem<*>>) { + with(accountAdapter) { + items = data + notifyDataSetChanged() + } + } + + override fun openLoginView() { + activity?.let { + startActivity(LoginActivity.getStartIntent(it)) + } + } + + override fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters) { + (activity as? MainActivity)?.pushView( + AccountDetailsFragment.newInstance( + studentWithSemesters + ) + ) + } + + override fun showErrorView(show: Boolean) { + binding.accountError.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun setErrorDetails(message: String) { + binding.accountErrorMessage.text = message + } + + override fun showProgress(show: Boolean) { + binding.accountProgress.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun showContent(show: Boolean) { + with(binding) { + accountRecycler.visibility = if (show) View.VISIBLE else View.GONE + accountAdd.visibility = if (show) View.VISIBLE else View.GONE + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt index be01f7c5..349561f8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt @@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.modules.account import io.github.wulkanowy.data.Status import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.repositories.StudentRepository -import io.github.wulkanowy.services.sync.SyncManager import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.afterLoading @@ -15,101 +14,85 @@ import javax.inject.Inject class AccountPresenter @Inject constructor( errorHandler: ErrorHandler, studentRepository: StudentRepository, - private val syncManager: SyncManager ) : BasePresenter<AccountView>(errorHandler, studentRepository) { + private lateinit var lastError: Throwable + override fun onAttachView(view: AccountView) { super.onAttachView(view) view.initView() - Timber.i("Account dialog view was initialized") + Timber.i("Account view was initialized") + errorHandler.showErrorMessage = ::showErrorViewOnError loadData() } + fun onRetry() { + view?.run { + showErrorView(false) + showProgress(true) + } + loadData() + } + + fun onDetailsClick() { + view?.showErrorDetailsDialog(lastError) + } + fun onAddSelected() { Timber.i("Select add account") view?.openLoginView() } - fun onRemoveSelected() { - Timber.i("Select remove account") - view?.showConfirmDialog() - } - - fun onLogoutConfirm() { - flowWithResource { - val student = studentRepository.getCurrentStudent(false) - studentRepository.logoutStudent(student) - - val students = studentRepository.getSavedStudents(false) - if (students.isNotEmpty()) { - studentRepository.switchStudent(students[0]) - } - students - }.onEach { - when (it.status) { - Status.LOADING -> Timber.i("Attempt to logout current user ") - Status.SUCCESS -> view?.run { - if (it.data!!.isEmpty()) { - Timber.i("Logout result: Open login view") - syncManager.stopSyncWorker() - openClearLoginView() - } else { - Timber.i("Logout result: Switch to another student") - recreateMainView() - } - } - Status.ERROR -> { - Timber.i("Logout result: An exception occurred") - errorHandler.dispatch(it.error!!) - } - } - }.afterLoading { - view?.dismissView() - }.launch("logout") - } - fun onItemSelected(studentWithSemesters: StudentWithSemesters) { - Timber.i("Select student item ${studentWithSemesters.student.id}") - if (studentWithSemesters.student.isCurrent) { - view?.dismissView() - } else flowWithResource { studentRepository.switchStudent(studentWithSemesters) }.onEach { - when (it.status) { - Status.LOADING -> Timber.i("Attempt to change a student") - Status.SUCCESS -> { - Timber.i("Change a student result: Success") - view?.recreateMainView() - } - Status.ERROR -> { - Timber.i("Change a student result: An exception occurred") - errorHandler.dispatch(it.error!!) - } - } - }.afterLoading { - view?.dismissView() - }.launch("switch") + view?.openAccountDetailsView(studentWithSemesters) } private fun createAccountItems(items: List<StudentWithSemesters>): List<AccountItem<*>> { - return items.groupBy { Account(it.student.email, it.student.isParent) }.map { (account, students) -> - listOf(AccountItem(account, AccountItem.ViewType.HEADER)) + students.map { student -> - AccountItem(student, AccountItem.ViewType.ITEM) + return items.groupBy { + Account("${it.student.userName} (${it.student.email})", it.student.isParent) + } + .map { (account, students) -> + listOf( + AccountItem(account, AccountItem.ViewType.HEADER) + ) + students.map { student -> + AccountItem(student, AccountItem.ViewType.ITEM) + } } - }.flatten() + .flatten() } private fun loadData() { - flowWithResource { studentRepository.getSavedStudents(false) }.onEach { - when (it.status) { - Status.LOADING -> Timber.i("Loading account data started") - Status.SUCCESS -> { - Timber.i("Loading account result: Success") - view?.updateData(createAccountItems(it.data!!)) - } - Status.ERROR -> { - Timber.i("Loading account result: An exception occurred") - errorHandler.dispatch(it.error!!) + flowWithResource { studentRepository.getSavedStudents() } + .onEach { + when (it.status) { + Status.LOADING -> Timber.i("Loading account data started") + Status.SUCCESS -> { + Timber.i("Loading account result: Success") + view?.updateData(createAccountItems(it.data!!)) + view?.run { + showContent(true) + showErrorView(false) + } + } + Status.ERROR -> { + Timber.i("Loading account result: An exception occurred") + errorHandler.dispatch(it.error!!) + } } } - }.launch() + .afterLoading { view?.showProgress(false) } + .launch() + } + + private fun showErrorViewOnError(message: String, error: Throwable) { + view?.run { + if (isViewEmpty) { + lastError = error + setErrorDetails(message) + showErrorView(true) + showContent(false) + showProgress(false) + } else showError(message, error) + } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt index a1f8086c..3453909d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt @@ -1,19 +1,26 @@ package io.github.wulkanowy.ui.modules.account +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.ui.base.BaseView interface AccountView : BaseView { + val isViewEmpty: Boolean + fun initView() fun updateData(data: List<AccountItem<*>>) - fun dismissView() - - fun showConfirmDialog() - fun openLoginView() - fun recreateMainView() + fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters) + + fun showErrorView(show: Boolean) + + fun setErrorDetails(message: String) + + fun showProgress(show: Boolean) + + fun showContent(show: Boolean) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt new file mode 100644 index 00000000..bdd4946a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt @@ -0,0 +1,134 @@ +package io.github.wulkanowy.ui.modules.account.accountdetails + +import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import androidx.appcompat.app.AlertDialog +import androidx.core.view.get +import dagger.hilt.android.AndroidEntryPoint +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.databinding.FragmentAccountDetailsBinding +import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.modules.main.MainActivity +import io.github.wulkanowy.ui.modules.main.MainView +import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment +import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView +import javax.inject.Inject + +@AndroidEntryPoint +class AccountDetailsFragment : + BaseFragment<FragmentAccountDetailsBinding>(R.layout.fragment_account_details), + AccountDetailsView, MainView.TitledView { + + @Inject + lateinit var presenter: AccountDetailsPresenter + + override val titleStringId = R.string.account_details_title + + override var subtitleString = "" + + companion object { + + private const val ARGUMENT_KEY = "Data" + + fun newInstance(studentWithSemesters: StudentWithSemesters) = + AccountDetailsFragment().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, studentWithSemesters) } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setHasOptionsMenu(true) + arguments?.let { + presenter.studentWithSemesters = + it.getSerializable(ARGUMENT_KEY) as StudentWithSemesters + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentAccountDetailsBinding.bind(view) + presenter.onAttachView(this) + } + + override fun initView() { + binding.accountDetailsLogout.setOnClickListener { presenter.onRemoveSelected() } + binding.accountDetailsSelect.setOnClickListener { presenter.onStudentSelect() } + binding.accountDetailsSelect.isEnabled = !presenter.studentWithSemesters.student.isCurrent + + binding.accountDetailsPersonalData.setOnClickListener { + presenter.onStudentInfoSelected(StudentInfoView.Type.PERSONAL) + } + binding.accountDetailsAddressData.setOnClickListener { + presenter.onStudentInfoSelected(StudentInfoView.Type.ADDRESS) + } + binding.accountDetailsContactData.setOnClickListener { + presenter.onStudentInfoSelected(StudentInfoView.Type.CONTACT) + } + binding.accountDetailsFamilyData.setOnClickListener { + presenter.onStudentInfoSelected(StudentInfoView.Type.FAMILY) + } + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + menu[0].isVisible = false + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return if (item.itemId == R.id.accountDetailsMenuEdit) { + showAccountEditDetailsDialog() + return true + } else false + } + + override fun showAccountData(studentWithSemesters: StudentWithSemesters) { + with(binding) { + accountDetailsName.text = studentWithSemesters.student.studentName + accountDetailsSchool.text = studentWithSemesters.student.schoolName + } + } + + override fun showAccountEditDetailsDialog() { + (requireActivity() as MainActivity).showDialogFragment(AccountEditDetailsDialog.newInstance()) + } + + override fun showLogoutConfirmDialog() { + context?.let { + AlertDialog.Builder(it) + .setTitle(R.string.account_logout_student) + .setMessage(R.string.account_confirm) + .setPositiveButton(R.string.account_logout) { _, _ -> presenter.onLogoutConfirm() } + .setNegativeButton(android.R.string.cancel) { _, _ -> } + .show() + } + } + + override fun popView() { + (requireActivity() as MainActivity).popView(2) + } + + override fun recreateMainView() { + requireActivity().recreate() + } + + override fun openStudentInfoView( + infoType: StudentInfoView.Type, + studentWithSemesters: StudentWithSemesters + ) { + (requireActivity() as MainActivity).pushView( + StudentInfoFragment.newInstance( + infoType, + studentWithSemesters + ) + ) + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt new file mode 100644 index 00000000..da437429 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt @@ -0,0 +1,100 @@ +package io.github.wulkanowy.ui.modules.account.accountdetails + +import io.github.wulkanowy.data.Status +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.services.sync.SyncManager +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView +import io.github.wulkanowy.utils.afterLoading +import io.github.wulkanowy.utils.flowWithResource +import kotlinx.coroutines.flow.onEach +import timber.log.Timber +import javax.inject.Inject + +class AccountDetailsPresenter @Inject constructor( + errorHandler: ErrorHandler, + studentRepository: StudentRepository, + private val syncManager: SyncManager +) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) { + + lateinit var studentWithSemesters: StudentWithSemesters + + override fun onAttachView(view: AccountDetailsView) { + super.onAttachView(view) + view.initView() + Timber.i("Account details view was initialized") + + view.showAccountData(studentWithSemesters) + } + + fun onStudentInfoSelected(infoType: StudentInfoView.Type) { + view?.openStudentInfoView(infoType, studentWithSemesters) + } + + fun onStudentSelect() { + Timber.i("Select student ${studentWithSemesters.student.id}") + + flowWithResource { studentRepository.switchStudent(studentWithSemesters) } + .onEach { + when (it.status) { + Status.LOADING -> Timber.i("Attempt to change a student") + Status.SUCCESS -> { + Timber.i("Change a student result: Success") + view?.recreateMainView() + } + Status.ERROR -> { + Timber.i("Change a student result: An exception occurred") + errorHandler.dispatch(it.error!!) + } + } + }.afterLoading { + view?.popView() + }.launch("switch") + } + + fun onRemoveSelected() { + Timber.i("Select remove account") + view?.showLogoutConfirmDialog() + } + + fun onLogoutConfirm() { + flowWithResource { + val studentToLogout = studentWithSemesters.student + + studentRepository.logoutStudent(studentToLogout) + val students = studentRepository.getSavedStudents(false) + + if (studentToLogout.isCurrent && students.isNotEmpty()) { + studentRepository.switchStudent(students[0]) + } + + return@flowWithResource students + }.onEach { + when (it.status) { + Status.LOADING -> Timber.i("Attempt to logout user") + Status.SUCCESS -> view?.run { + when { + it.data!!.isEmpty() -> { + Timber.i("Logout result: Open login view") + syncManager.stopSyncWorker() + openClearLoginView() + } + studentWithSemesters.student.isCurrent -> { + Timber.i("Logout result: Logout student and switch to another") + recreateMainView() + } + else -> Timber.i("Logout result: Logout student") + } + } + Status.ERROR -> { + Timber.i("Logout result: An exception occurred") + errorHandler.dispatch(it.error!!) + } + } + }.afterLoading { + view?.popView() + }.launch("logout") + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt new file mode 100644 index 00000000..f1001fd7 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt @@ -0,0 +1,25 @@ +package io.github.wulkanowy.ui.modules.account.accountdetails + +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.ui.base.BaseView +import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView + +interface AccountDetailsView : BaseView { + + fun initView() + + fun showAccountData(studentWithSemesters: StudentWithSemesters) + + fun showAccountEditDetailsDialog() + + fun showLogoutConfirmDialog() + + fun popView() + + fun recreateMainView() + + fun openStudentInfoView( + infoType: StudentInfoView.Type, + studentWithSemesters: StudentWithSemesters + ) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt new file mode 100644 index 00000000..be0af7df --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt @@ -0,0 +1,38 @@ +package io.github.wulkanowy.ui.modules.account.accountdetails + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import io.github.wulkanowy.databinding.DialogAccountEditDetailsBinding +import io.github.wulkanowy.utils.lifecycleAwareVariable + +class AccountEditDetailsDialog : DialogFragment() { + + private var binding: DialogAccountEditDetailsBinding by lifecycleAwareVariable() + + companion object { + + fun newInstance() = AccountEditDetailsDialog() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, 0) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return DialogAccountEditDetailsBinding.inflate(inflater).apply { binding = this }.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.accountEditDetailsCancel.setOnClickListener { dismiss() } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt new file mode 100644 index 00000000..cb64a8fd --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt @@ -0,0 +1,82 @@ +package io.github.wulkanowy.ui.modules.account.accountquick + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import dagger.hilt.android.AndroidEntryPoint +import io.github.wulkanowy.databinding.DialogAccountQuickBinding +import io.github.wulkanowy.ui.base.BaseDialogFragment +import io.github.wulkanowy.ui.modules.account.AccountAdapter +import io.github.wulkanowy.ui.modules.account.AccountFragment +import io.github.wulkanowy.ui.modules.account.AccountItem +import io.github.wulkanowy.ui.modules.main.MainActivity +import javax.inject.Inject + +@AndroidEntryPoint +class AccountQuickDialog : BaseDialogFragment<DialogAccountQuickBinding>(), AccountQuickView { + + @Inject + lateinit var accountAdapter: AccountAdapter + + @Inject + lateinit var presenter: AccountQuickPresenter + + companion object { + fun newInstance() = AccountQuickDialog() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, 0) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ) = DialogAccountQuickBinding.inflate(inflater).apply { binding = this }.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + presenter.onAttachView(this) + } + + override fun initView() { + binding.accountQuickDialogManger.setOnClickListener { presenter.onManagerSelected() } + + with(accountAdapter) { + isAccountQuickDialogMode = true + onClickListener = presenter::onStudentSelect + } + + with(binding.accountQuickDialogRecycler) { + layoutManager = LinearLayoutManager(context) + adapter = accountAdapter + } + } + + override fun updateData(data: List<AccountItem<*>>) { + with(accountAdapter) { + items = data + notifyDataSetChanged() + } + } + + override fun popView() { + dismiss() + } + + override fun recreateMainView() { + activity?.recreate() + } + + override fun openAccountView() { + (requireActivity() as MainActivity).pushView(AccountFragment.newInstance()) + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt new file mode 100644 index 00000000..87b14c53 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt @@ -0,0 +1,79 @@ +package io.github.wulkanowy.ui.modules.account.accountquick + +import io.github.wulkanowy.data.Status +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.ui.modules.account.AccountItem +import io.github.wulkanowy.utils.afterLoading +import io.github.wulkanowy.utils.flowWithResource +import kotlinx.coroutines.flow.onEach +import timber.log.Timber +import javax.inject.Inject + +class AccountQuickPresenter @Inject constructor( + errorHandler: ErrorHandler, + studentRepository: StudentRepository +) : BasePresenter<AccountQuickView>(errorHandler, studentRepository) { + + override fun onAttachView(view: AccountQuickView) { + super.onAttachView(view) + view.initView() + Timber.i("Account quick dialog view was initialized") + loadData() + } + + fun onManagerSelected() { + view?.run { + openAccountView() + popView() + } + } + + fun onStudentSelect(studentWithSemesters: StudentWithSemesters) { + Timber.i("Select student ${studentWithSemesters.student.id}") + + if (studentWithSemesters.student.isCurrent) { + view?.popView() + return + } + + flowWithResource { studentRepository.switchStudent(studentWithSemesters) } + .onEach { + when (it.status) { + Status.LOADING -> Timber.i("Attempt to change a student") + Status.SUCCESS -> { + Timber.i("Change a student result: Success") + view?.recreateMainView() + } + Status.ERROR -> { + Timber.i("Change a student result: An exception occurred") + errorHandler.dispatch(it.error!!) + } + } + }.afterLoading { + view?.popView() + }.launch("switch") + } + + private fun loadData() { + flowWithResource { studentRepository.getSavedStudents(false) }.onEach { + when (it.status) { + Status.LOADING -> Timber.i("Loading account data started") + Status.SUCCESS -> { + Timber.i("Loading account result: Success") + view?.updateData(createAccountItems(it.data!!)) + } + Status.ERROR -> { + Timber.i("Loading account result: An exception occurred") + errorHandler.dispatch(it.error!!) + } + } + }.launch() + } + + private fun createAccountItems(items: List<StudentWithSemesters>) = items.map { + AccountItem(it, AccountItem.ViewType.ITEM) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickView.kt new file mode 100644 index 00000000..4a9420d9 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickView.kt @@ -0,0 +1,17 @@ +package io.github.wulkanowy.ui.modules.account.accountquick + +import io.github.wulkanowy.ui.base.BaseView +import io.github.wulkanowy.ui.modules.account.AccountItem + +interface AccountQuickView : BaseView { + + fun initView() + + fun updateData(data: List<AccountItem<*>>) + + fun recreateMainView() + + fun popView() + + fun openAccountView() +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt index 83ed163f..3bef3dc6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt @@ -60,6 +60,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag override val excuseActionMode: Boolean get() = attendanceAdapter.excuseActionMode private var actionMode: ActionMode? = null + private val actionModeCallback = object : ActionMode.Callback { override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { val inflater = mode.menuInflater diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt index 25b41aab..5d93c594 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt @@ -14,6 +14,7 @@ import android.os.Build.VERSION_CODES.LOLLIPOP import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.View import androidx.annotation.RequiresApi import androidx.core.content.getSystemService import androidx.core.view.ViewCompat @@ -28,7 +29,7 @@ import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.databinding.ActivityMainBinding import io.github.wulkanowy.ui.base.BaseActivity -import io.github.wulkanowy.ui.modules.account.AccountDialog +import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment import io.github.wulkanowy.ui.modules.exam.ExamFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment @@ -65,17 +66,19 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie private val overlayProvider by lazy { ElevationOverlayProvider(this) } - private val navController = FragNavController(supportFragmentManager, R.id.mainFragmentContainer) + private val navController = + FragNavController(supportFragmentManager, R.id.mainFragmentContainer) companion object { const val EXTRA_START_MENU = "extraStartMenu" - fun getStartIntent(context: Context, startMenu: MainView.Section? = null, clear: Boolean = false): Intent { - return Intent(context, MainActivity::class.java) - .apply { - if (clear) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK - startMenu?.let { putExtra(EXTRA_START_MENU, it.id) } - } + fun getStartIntent( + context: Context, + startMenu: MainView.Section? = null, + clear: Boolean = false + ) = Intent(context, MainActivity::class.java).apply { + if (clear) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK + startMenu?.let { putExtra(EXTRA_START_MENU, it.id) } } } @@ -83,7 +86,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie override val currentStackSize get() = navController.currentStack?.size - override val currentViewTitle get() = (navController.currentFrag as? MainView.TitledView)?.titleStringId?.let { getString(it) } + override val currentViewTitle + get() = (navController.currentFrag as? MainView.TitledView)?.titleStringId?.let { + getString(it) + } override val currentViewSubtitle get() = (navController.currentFrag as? MainView.TitledView)?.subtitleString @@ -106,7 +112,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie messageContainer = binding.mainFragmentContainer updateHelper.messageContainer = binding.mainFragmentContainer - presenter.onAttachView(this, MainView.Section.values().singleOrNull { it.id == intent.getIntExtra(EXTRA_START_MENU, -1) }) + val section = MainView.Section.values() + .singleOrNull { it.id == intent.getIntExtra(EXTRA_START_MENU, -1) } + + presenter.onAttachView(this, section) with(navController) { initialize(startMenuIndex, savedInstanceState) @@ -132,21 +141,49 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie val shortcutsList = mutableListOf<ShortcutInfo>() listOf( - Triple(getString(R.string.grade_title), R.drawable.ic_shortcut_grade, MainView.Section.GRADE), - Triple(getString(R.string.attendance_title), R.drawable.ic_shortcut_attendance, MainView.Section.ATTENDANCE), - Triple(getString(R.string.exam_title), R.drawable.ic_shortcut_exam, MainView.Section.EXAM), - Triple(getString(R.string.timetable_title), R.drawable.ic_shortcut_timetable, MainView.Section.TIMETABLE), - Triple(getString(R.string.message_title), R.drawable.ic_shortcut_message, MainView.Section.MESSAGE) + Triple( + getString(R.string.grade_title), + R.drawable.ic_shortcut_grade, + MainView.Section.GRADE + ), + Triple( + getString(R.string.attendance_title), + R.drawable.ic_shortcut_attendance, + MainView.Section.ATTENDANCE + ), + Triple( + getString(R.string.exam_title), + R.drawable.ic_shortcut_exam, + MainView.Section.EXAM + ), + Triple( + getString(R.string.timetable_title), + R.drawable.ic_shortcut_timetable, + MainView.Section.TIMETABLE + ), + Triple( + getString(R.string.message_title), + R.drawable.ic_shortcut_message, + MainView.Section.MESSAGE + ) ).forEach { (title, icon, enum) -> - shortcutsList.add(ShortcutInfo.Builder(applicationContext, title) - .setShortLabel(title) - .setLongLabel(title) - .setIcon(Icon.createWithResource(applicationContext, icon)) - .setIntents(arrayOf( - Intent(applicationContext, MainActivity::class.java).setAction(Intent.ACTION_VIEW), - Intent(applicationContext, MainActivity::class.java).putExtra(EXTRA_START_MENU, enum.id) - .setAction(Intent.ACTION_VIEW).addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK))) - .build()) + shortcutsList.add( + ShortcutInfo.Builder(applicationContext, title) + .setShortLabel(title) + .setLongLabel(title) + .setIcon(Icon.createWithResource(applicationContext, icon)) + .setIntents( + arrayOf( + Intent(applicationContext, MainActivity::class.java) + .setAction(Intent.ACTION_VIEW), + Intent(applicationContext, MainActivity::class.java) + .putExtra(EXTRA_START_MENU, enum.id) + .setAction(Intent.ACTION_VIEW) + .addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK) + ) + ) + .build() + ) } getSystemService<ShortcutManager>()?.dynamicShortcuts = shortcutsList @@ -160,20 +197,33 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie override fun initView() { with(binding.mainToolbar) { if (SDK_INT >= LOLLIPOP) stateListAnimator = null - setBackgroundColor(overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(4f))) + setBackgroundColor( + overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(4f)) + ) } with(binding.mainBottomNav) { - addItems(listOf( - AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_main_grade, 0), - AHBottomNavigationItem(R.string.attendance_title, R.drawable.ic_main_attendance, 0), - AHBottomNavigationItem(R.string.exam_title, R.drawable.ic_main_exam, 0), - AHBottomNavigationItem(R.string.timetable_title, R.drawable.ic_main_timetable, 0), - AHBottomNavigationItem(R.string.more_title, R.drawable.ic_main_more, 0) - )) + addItems( + listOf( + AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_main_grade, 0), + AHBottomNavigationItem( + R.string.attendance_title, + R.drawable.ic_main_attendance, + 0 + ), + AHBottomNavigationItem(R.string.exam_title, R.drawable.ic_main_exam, 0), + AHBottomNavigationItem( + R.string.timetable_title, + R.drawable.ic_main_timetable, + 0 + ), + AHBottomNavigationItem(R.string.more_title, R.drawable.ic_main_more, 0) + ) + ) accentColor = getThemeAttrColor(R.attr.colorPrimary) inactiveColor = getThemeAttrColor(R.attr.colorOnSurface, 153) - defaultBackgroundColor = overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(8f)) + defaultBackgroundColor = + overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(8f)) titleState = ALWAYS_SHOW currentItem = startMenuIndex isBehaviorTranslationEnabled = false @@ -183,6 +233,13 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie with(navController) { setOnViewChangeListener { section, name -> + binding.mainBottomNav.visibility = + if (section == MainView.Section.ACCOUNT || section == MainView.Section.STUDENT_INFO) { + View.GONE + } else { + View.VISIBLE + } + analytics.setCurrentScreen(this@MainActivity, name) presenter.onViewChange(section) } @@ -224,7 +281,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie } override fun showAccountPicker() { - navController.showDialogFragment(AccountDialog.newInstance()) + navController.showDialogFragment(AccountQuickDialog.newInstance()) } override fun showActionBarElevation(show: Boolean) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt index 97b556e3..7f409814 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt @@ -64,6 +64,8 @@ interface MainView : BaseView { LUCKY_NUMBER(8), SETTINGS(9), ABOUT(10), - SCHOOL(11) + SCHOOL(11), + ACCOUNT(12), + STUDENT_INFO(13) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt index 491a19ec..202d4e5d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt @@ -81,10 +81,7 @@ class SchoolPresenter @Inject constructor( showEmpty(false) showErrorView(false) } - analytics.logEvent( - "load_item", - "type" to "school" - ) + analytics.logEvent("load_item", "type" to "school") } else view?.run { Timber.i("Loading school result: No school info found") showContent(!isViewEmpty) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoAdapter.kt new file mode 100644 index 00000000..602ec07a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoAdapter.kt @@ -0,0 +1,42 @@ +package io.github.wulkanowy.ui.modules.studentinfo + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import io.github.wulkanowy.databinding.ItemStudentInfoBinding +import javax.inject.Inject + +class StudentInfoAdapter @Inject constructor() : + RecyclerView.Adapter<StudentInfoAdapter.ViewHolder>() { + + var items = listOf<Pair<String, String>>() + + var onItemClickListener: (position: Int) -> Unit = {} + + var onItemLongClickListener: (text: String) -> Unit = {} + + override fun getItemCount() = items.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder( + ItemStudentInfoBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ) + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val item = items[position] + + with(holder.binding) { + studentInfoItemTitle.text = item.first + studentInfoItemSubtitle.text = item.second + + with(root) { + setOnClickListener { onItemClickListener(position) } + setOnLongClickListener { + onItemLongClickListener(studentInfoItemSubtitle.text.toString()) + true + } + } + } + } + + class ViewHolder(val binding: ItemStudentInfoBinding) : RecyclerView.ViewHolder(binding.root) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt new file mode 100644 index 00000000..0075d558 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt @@ -0,0 +1,228 @@ +package io.github.wulkanowy.ui.modules.studentinfo + +import android.annotation.SuppressLint +import android.content.ClipData +import android.content.ClipboardManager +import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.View +import android.widget.Toast +import androidx.core.content.getSystemService +import androidx.core.view.get +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import dagger.hilt.android.AndroidEntryPoint +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.StudentInfo +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.data.enums.Gender +import io.github.wulkanowy.databinding.FragmentStudentInfoBinding +import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.modules.main.MainActivity +import io.github.wulkanowy.ui.modules.main.MainView +import javax.inject.Inject + +@AndroidEntryPoint +class StudentInfoFragment : + BaseFragment<FragmentStudentInfoBinding>(R.layout.fragment_student_info), StudentInfoView, + MainView.TitledView { + + @Inject + lateinit var presenter: StudentInfoPresenter + + @Inject + lateinit var studentInfoAdapter: StudentInfoAdapter + + override val titleStringId: Int + get() = R.string.student_info_title + + override val isViewEmpty get() = studentInfoAdapter.items.isEmpty() + + companion object { + + private const val INFO_TYPE_ARGUMENT_KEY = "info_type" + + private const val STUDENT_ARGUMENT_KEY = "student_with_semesters" + + fun newInstance(type: StudentInfoView.Type, studentWithSemesters: StudentWithSemesters) = + StudentInfoFragment().apply { + arguments = Bundle().apply { + putSerializable(INFO_TYPE_ARGUMENT_KEY, type) + putSerializable(STUDENT_ARGUMENT_KEY, studentWithSemesters) + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setHasOptionsMenu(true) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentStudentInfoBinding.bind(view) + presenter.onAttachView( + this, + requireArguments().getSerializable(INFO_TYPE_ARGUMENT_KEY) as StudentInfoView.Type, + requireArguments().getSerializable(STUDENT_ARGUMENT_KEY) as StudentWithSemesters + ) + } + + override fun initView() { + with(binding) { + studentInfoSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + studentInfoErrorRetry.setOnClickListener { presenter.onRetry() } + studentInfoErrorDetails.setOnClickListener { presenter.onDetailsClick() } + } + + with(studentInfoAdapter) { + onItemClickListener = presenter::onItemSelected + onItemLongClickListener = presenter::onItemLongClick + } + + with(binding.studentInfoRecycler) { + layoutManager = LinearLayoutManager(context) + addItemDecoration(DividerItemDecoration(context, RecyclerView.VERTICAL)) + setHasFixedSize(true) + adapter = studentInfoAdapter + } + } + + override fun updateData(data: List<Pair<String, String>>) { + with(studentInfoAdapter) { + items = data + notifyDataSetChanged() + } + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + menu[0].isVisible = false + } + + override fun showPersonalTypeData(studentInfo: StudentInfo) { + updateData( + listOf( + getString(R.string.student_info_first_name) to studentInfo.firstName, + getString(R.string.student_info_second_name) to studentInfo.secondName, + getString(R.string.student_info_gender) to getString(if (studentInfo.gender == Gender.MALE) R.string.student_info_male else R.string.student_info_female), + getString(R.string.student_info_polish_citizenship) to getString(if (studentInfo.hasPolishCitizenship) R.string.all_yes else R.string.all_no), + getString(R.string.student_info_family_name) to studentInfo.familyName, + getString(R.string.student_info_parents_name) to studentInfo.parentsNames + ).map { + if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it + } + ) + } + + override fun showContactTypeData(studentInfo: StudentInfo) { + updateData( + listOf( + getString(R.string.student_info_phone) to studentInfo.phoneNumber, + getString(R.string.student_info_cellphone) to studentInfo.cellPhoneNumber, + getString(R.string.student_info_email) to studentInfo.email + ).map { + if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it + } + ) + } + + @SuppressLint("DefaultLocale") + override fun showFamilyTypeData(studentInfo: StudentInfo) { + updateData( + listOf( + studentInfo.firstGuardian.kinship.capitalize() to studentInfo.firstGuardian.fullName, + studentInfo.secondGuardian.kinship.capitalize() to studentInfo.secondGuardian.fullName + ).map { + if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it + } + ) + } + + override fun showAddressTypeData(studentInfo: StudentInfo) { + updateData( + listOf( + getString(R.string.student_info_address) to studentInfo.address, + getString(R.string.student_info_registered_address) to studentInfo.registeredAddress, + getString(R.string.student_info_correspondence_address) to studentInfo.correspondenceAddress + ).map { + if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it + } + ) + } + + override fun showFirstGuardianTypeData(studentInfo: StudentInfo) { + updateData( + listOf( + getString(R.string.student_info_full_name) to studentInfo.firstGuardian.fullName, + getString(R.string.student_info_kinship) to studentInfo.firstGuardian.kinship, + getString(R.string.student_info_guardian_address) to studentInfo.firstGuardian.address, + getString(R.string.student_info_phones) to studentInfo.firstGuardian.phones, + getString(R.string.student_info_email) to studentInfo.firstGuardian.email + ).map { + if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it + } + ) + } + + override fun showSecondGuardianTypeData(studentInfo: StudentInfo) { + updateData( + listOf( + getString(R.string.student_info_full_name) to studentInfo.secondGuardian.fullName, + getString(R.string.student_info_kinship) to studentInfo.secondGuardian.kinship, + getString(R.string.student_info_guardian_address) to studentInfo.secondGuardian.address, + getString(R.string.student_info_phones) to studentInfo.secondGuardian.phones, + getString(R.string.student_info_email) to studentInfo.secondGuardian.email + ).map { + if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it + } + ) + } + + override fun openStudentInfoView( + infoType: StudentInfoView.Type, + studentWithSemesters: StudentWithSemesters + ) { + (requireActivity() as MainActivity).pushView(newInstance(infoType, studentWithSemesters)) + } + + override fun showEmpty(show: Boolean) { + binding.studentInfoEmpty.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun showErrorView(show: Boolean) { + binding.studentInfoError.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun setErrorDetails(message: String) { + binding.studentInfoErrorMessage.text = message + } + + override fun showProgress(show: Boolean) { + binding.studentInfoProgress.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun enableSwipe(enable: Boolean) { + binding.studentInfoSwipe.isEnabled = enable + } + + override fun showContent(show: Boolean) { + binding.studentInfoRecycler.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun hideRefresh() { + binding.studentInfoSwipe.isRefreshing = false + } + + override fun copyToClipboard(text: String) { + val clipData = ClipData.newPlainText("student_info_wulkanowy", text) + requireActivity().getSystemService<ClipboardManager>()?.setPrimaryClip(clipData) + Toast.makeText(context, R.string.all_copied, Toast.LENGTH_SHORT).show() + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoPresenter.kt new file mode 100644 index 00000000..a1a48be1 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoPresenter.kt @@ -0,0 +1,142 @@ +package io.github.wulkanowy.ui.modules.studentinfo + +import io.github.wulkanowy.data.Status +import io.github.wulkanowy.data.db.entities.StudentInfo +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.data.repositories.StudentInfoRepository +import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.utils.AnalyticsHelper +import io.github.wulkanowy.utils.afterLoading +import io.github.wulkanowy.utils.flowWithResourceIn +import io.github.wulkanowy.utils.getCurrentOrLast +import kotlinx.coroutines.flow.onEach +import timber.log.Timber +import javax.inject.Inject + +class StudentInfoPresenter @Inject constructor( + errorHandler: ErrorHandler, + studentRepository: StudentRepository, + private val studentInfoRepository: StudentInfoRepository, + private val analytics: AnalyticsHelper +) : BasePresenter<StudentInfoView>(errorHandler, studentRepository) { + + private lateinit var infoType: StudentInfoView.Type + + private lateinit var studentWithSemesters: StudentWithSemesters + + private lateinit var lastError: Throwable + + fun onAttachView( + view: StudentInfoView, + type: StudentInfoView.Type, + studentWithSemesters: StudentWithSemesters + ) { + super.onAttachView(view) + infoType = type + this.studentWithSemesters = studentWithSemesters + view.initView() + Timber.i("Student info $infoType view was initialized") + errorHandler.showErrorMessage = ::showErrorViewOnError + loadData() + } + + fun onSwipeRefresh() { + loadData(true) + } + + fun onRetry() { + view?.run { + showErrorView(false) + showProgress(true) + } + loadData(true) + } + + fun onDetailsClick() { + view?.showErrorDetailsDialog(lastError) + } + + fun onItemSelected(position: Int) { + if (infoType != StudentInfoView.Type.FAMILY) return + + if (position == 0) { + view?.openStudentInfoView(StudentInfoView.Type.FIRST_GUARDIAN, studentWithSemesters) + } else { + view?.openStudentInfoView(StudentInfoView.Type.SECOND_GUARDIAN, studentWithSemesters) + } + } + + fun onItemLongClick(text: String) { + view?.copyToClipboard(text) + } + + private fun loadData(forceRefresh: Boolean = false) { + flowWithResourceIn { + val semester = studentWithSemesters.semesters.getCurrentOrLast() + studentInfoRepository.getStudentInfo( + studentWithSemesters.student, + semester, + forceRefresh + ) + }.onEach { + when (it.status) { + Status.LOADING -> Timber.i("Loading student info $infoType started") + Status.SUCCESS -> { + if (it.data != null) { + Timber.i("Loading student info $infoType result: Success") + showCorrectData(it.data) + view?.run { + showContent(true) + showEmpty(false) + showErrorView(false) + } + analytics.logEvent("load_item", "type" to "student_info") + } else { + Timber.i("Loading student info $infoType result: No school info found") + view?.run { + showContent(!isViewEmpty) + showEmpty(isViewEmpty) + showErrorView(false) + } + } + } + Status.ERROR -> { + Timber.i("Loading student info $infoType result: An exception occurred") + errorHandler.dispatch(it.error!!) + } + } + }.afterLoading { + view?.run { + hideRefresh() + showProgress(false) + enableSwipe(true) + } + }.launch() + } + + private fun showCorrectData(studentInfo: StudentInfo) { + when (infoType) { + StudentInfoView.Type.PERSONAL -> view?.showPersonalTypeData(studentInfo) + StudentInfoView.Type.CONTACT -> view?.showContactTypeData(studentInfo) + StudentInfoView.Type.ADDRESS -> view?.showAddressTypeData(studentInfo) + StudentInfoView.Type.FAMILY -> view?.showFamilyTypeData(studentInfo) + StudentInfoView.Type.SECOND_GUARDIAN -> view?.showSecondGuardianTypeData(studentInfo) + StudentInfoView.Type.FIRST_GUARDIAN -> view?.showFirstGuardianTypeData(studentInfo) + } + } + + private fun showErrorViewOnError(message: String, error: Throwable) { + view?.run { + if (isViewEmpty) { + lastError = error + setErrorDetails(message) + showErrorView(true) + showEmpty(false) + showContent(false) + showProgress(false) + } else showError(message, error) + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoView.kt new file mode 100644 index 00000000..70c3eb5e --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoView.kt @@ -0,0 +1,48 @@ +package io.github.wulkanowy.ui.modules.studentinfo + +import io.github.wulkanowy.data.db.entities.StudentInfo +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.ui.base.BaseView + +interface StudentInfoView : BaseView { + + enum class Type { + PERSONAL, ADDRESS, CONTACT, FAMILY, FIRST_GUARDIAN, SECOND_GUARDIAN + } + + val isViewEmpty: Boolean + + fun initView() + + fun updateData(data: List<Pair<String, String>>) + + fun showPersonalTypeData(studentInfo: StudentInfo) + + fun showContactTypeData(studentInfo: StudentInfo) + + fun showAddressTypeData(studentInfo: StudentInfo) + + fun showFamilyTypeData(studentInfo: StudentInfo) + + fun showFirstGuardianTypeData(studentInfo: StudentInfo) + + fun showSecondGuardianTypeData(studentInfo: StudentInfo) + + fun openStudentInfoView(infoType: Type, studentWithSemesters: StudentWithSemesters) + + fun showEmpty(show: Boolean) + + fun showErrorView(show: Boolean) + + fun setErrorDetails(message: String) + + fun showProgress(show: Boolean) + + fun enableSwipe(enable: Boolean) + + fun showContent(show: Boolean) + + fun hideRefresh() + + fun copyToClipboard(text: String) +} diff --git a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt index 1098a9a0..37a09e74 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt @@ -28,4 +28,9 @@ open class AppInfo @Inject constructor() { @Suppress("DEPRECATION") open val systemLanguage: String get() = Resources.getSystem().configuration.locale.language + + open val defaultColorsForAvatar = listOf( + 0xe57373, 0xf06292, 0xba68c8, 0x9575cd, 0x7986cb, 0x64b5f6, 0x4fc3f7, 0x4dd0e1, 0x4db6ac, + 0x81c784, 0xaed581, 0xff8a65, 0xd4e157, 0xffd54f, 0xffb74d, 0xa1887f, 0x90a4ae + ) } diff --git a/app/src/main/java/io/github/wulkanowy/utils/FlowUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/FlowUtils.kt index 2d074b22..049e1d42 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/FlowUtils.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/FlowUtils.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.utils import io.github.wulkanowy.data.Resource import io.github.wulkanowy.data.Status +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect @@ -71,24 +72,14 @@ inline fun <ResultType, RequestType, T> networkBoundResource( fun <T> flowWithResource(block: suspend () -> T) = flow { emit(Resource.loading()) - emit(try { - Resource.success(block()) - } catch (e: Throwable) { - Resource.error(e) - }) -} + emit(Resource.success(block())) +}.catch { emit(Resource.error(it)) } +@OptIn(FlowPreview::class) fun <T> flowWithResourceIn(block: suspend () -> Flow<Resource<T>>) = flow { emit(Resource.loading()) - - block() - .catch { emit(Resource.error(it)) } - .collect { - if (it.status != Status.LOADING || (it.status == Status.LOADING && it.data != null)) { // LOADING without data is already emitted - emit(it) - } - } -} + emitAll(block().filter { it.status != Status.LOADING || (it.status == Status.LOADING && it.data != null) }) +}.catch { emit(Resource.error(it)) } fun <T> Flow<Resource<T>>.afterLoading(callback: () -> Unit) = onEach { if (it.status != Status.LOADING) callback() @@ -96,4 +87,5 @@ fun <T> Flow<Resource<T>>.afterLoading(callback: () -> Unit) = onEach { suspend fun <T> Flow<Resource<T>>.toFirstResult() = filter { it.status != Status.LOADING }.first() -suspend fun <T> Flow<Resource<T>>.waitForResult() = takeWhile { it.status == Status.LOADING }.collect() +suspend fun <T> Flow<Resource<T>>.waitForResult() = + takeWhile { it.status == Status.LOADING }.collect() diff --git a/app/src/main/java/io/github/wulkanowy/utils/FragmentExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/FragmentExtension.kt index 0b71c964..a49360d7 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/FragmentExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/FragmentExtension.kt @@ -2,6 +2,8 @@ package io.github.wulkanowy.utils import androidx.fragment.app.Fragment import io.github.wulkanowy.ui.modules.about.AboutFragment +import io.github.wulkanowy.ui.modules.account.AccountFragment +import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment import io.github.wulkanowy.ui.modules.exam.ExamFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment @@ -13,6 +15,7 @@ import io.github.wulkanowy.ui.modules.more.MoreFragment import io.github.wulkanowy.ui.modules.note.NoteFragment import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment import io.github.wulkanowy.ui.modules.settings.SettingsFragment +import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment import io.github.wulkanowy.ui.modules.timetable.TimetableFragment fun Fragment.toSection(): MainView.Section? { @@ -29,6 +32,9 @@ fun Fragment.toSection(): MainView.Section? { is SettingsFragment -> MainView.Section.SETTINGS is AboutFragment -> MainView.Section.ABOUT is SchoolAndTeachersFragment -> MainView.Section.SCHOOL + is AccountFragment -> MainView.Section.ACCOUNT + is AccountDetailsFragment -> MainView.Section.ACCOUNT + is StudentInfoFragment -> MainView.Section.STUDENT_INFO else -> null } } diff --git a/app/src/main/res/drawable/ic_account_details_family.xml b/app/src/main/res/drawable/ic_account_details_family.xml new file mode 100644 index 00000000..363b4f58 --- /dev/null +++ b/app/src/main/res/drawable/ic_account_details_family.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M16,4c0,-1.11 0.89,-2 2,-2s2,0.89 2,2s-0.89,2 -2,2S16,5.11 16,4zM20,22v-6h2.5l-2.54,-7.63C19.68,7.55 18.92,7 18.06,7h-0.12c-0.86,0 -1.63,0.55 -1.9,1.37l-0.86,2.58C16.26,11.55 17,12.68 17,14v8H20zM12.5,11.5c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5S11,9.17 11,10S11.67,11.5 12.5,11.5zM5.5,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2s-2,0.89 -2,2S4.39,6 5.5,6zM7.5,22v-7H9V9c0,-1.1 -0.9,-2 -2,-2H4C2.9,7 2,7.9 2,9v6h1.5v7H7.5zM14,22v-4h1v-4c0,-0.82 -0.68,-1.5 -1.5,-1.5h-2c-0.82,0 -1.5,0.68 -1.5,1.5v4h1v4H14z" /> +</vector> diff --git a/app/src/main/res/drawable/ic_about_homepage.xml b/app/src/main/res/drawable/ic_all_home.xml similarity index 100% rename from app/src/main/res/drawable/ic_about_homepage.xml rename to app/src/main/res/drawable/ic_all_home.xml diff --git a/app/src/main/res/drawable/ic_school_phone.xml b/app/src/main/res/drawable/ic_all_phone.xml similarity index 100% rename from app/src/main/res/drawable/ic_school_phone.xml rename to app/src/main/res/drawable/ic_all_phone.xml diff --git a/app/src/main/res/layout/dialog_account_edit_details.xml b/app/src/main/res/layout/dialog_account_edit_details.xml new file mode 100644 index 00000000..0b13e042 --- /dev/null +++ b/app/src/main/res/layout/dialog_account_edit_details.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <View + android:layout_width="280dp" + android:layout_height="1dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/accountEditDetailsHeader" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="24dp" + android:layout_marginEnd="24dp" + android:text="Modify data" + android:textSize="21sp" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/accountEditDetailsNick" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="28dp" + android:layout_marginEnd="24dp" + android:hint="Nick" + app:errorEnabled="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/accountEditDetailsHeader"> + + <com.google.android.material.textfield.TextInputEditText + android:layout_width="match_parent" + android:layout_height="match_parent" + android:inputType="textPersonName" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.button.MaterialButton + android:id="@+id/accountEditDetailsSave" + style="@style/Widget.MaterialComponents.Button.TextButton.Dialog" + android:layout_width="88dp" + android:layout_height="36dp" + android:layout_marginTop="36dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="8dp" + android:insetLeft="0dp" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:text="Save" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/accountEditDetailsNick" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/accountEditDetailsCancel" + style="@style/Widget.MaterialComponents.Button.TextButton.Dialog" + android:layout_width="88dp" + android:layout_height="36dp" + android:layout_marginTop="36dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="8dp" + android:insetLeft="0dp" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:text="@android:string/cancel" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@id/accountEditDetailsSave" + app:layout_constraintTop_toBottomOf="@id/accountEditDetailsNick" /> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/dialog_account.xml b/app/src/main/res/layout/dialog_account_quick.xml similarity index 62% rename from app/src/main/res/layout/dialog_account.xml rename to app/src/main/res/layout/dialog_account_quick.xml index d56de3a2..da31d31d 100644 --- a/app/src/main/res/layout/dialog_account.xml +++ b/app/src/main/res/layout/dialog_account_quick.xml @@ -8,23 +8,24 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> + android:orientation="vertical" + tools:ignore="UselessParent"> <TextView - android:id="@+id/accountDialogTitle" + android:id="@+id/account_quick_dialog_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingStart="24dp" android:paddingLeft="24dp" android:paddingEnd="24dp" android:paddingRight="24dp" - android:text="@string/account_title" + android:text="@string/account_quick_title" android:textSize="20sp" android:textStyle="bold" app:firstBaselineToTopHeight="40dp" /> <androidx.recyclerview.widget.RecyclerView - android:id="@+id/accountDialogRecycler" + android:id="@+id/account_quick_dialog_recycler" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="8dp" @@ -39,26 +40,12 @@ android:orientation="horizontal"> <com.google.android.material.button.MaterialButton - android:id="@+id/accountDialogAdd" + android:id="@+id/account_quick_dialog_manger" style="@style/Widget.MaterialComponents.Button.TextButton" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp" - android:text="@string/account_add_new" - android:textColor="?android:textColorPrimary" /> - - <Space - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" /> - - <com.google.android.material.button.MaterialButton - android:id="@+id/accountDialogRemove" - style="@style/Widget.MaterialComponents.Button.TextButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:text="@string/account_logout" /> + android:text="@string/account_quick_manager" /> </LinearLayout> </LinearLayout> </RelativeLayout> diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml new file mode 100644 index 00000000..a2cf73cf --- /dev/null +++ b/app/src/main/res/layout/fragment_account.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <me.zhanghai.android.materialprogressbar.MaterialProgressBar + android:id="@+id/account_progress" + style="@style/Widget.MaterialProgressBar.ProgressBar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:indeterminate="true" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/accountRecycler" + android:layout_width="match_parent" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@id/accountAdd" + app:layout_constraintTop_toTopOf="parent" + tools:listitem="@layout/item_account" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/accountAdd" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginEnd="24dp" + android:layout_marginBottom="16dp" + android:insetLeft="0dp" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:text="@string/account_add_new" + app:layout_constraintBottom_toBottomOf="parent" /> + + <LinearLayout + android:id="@+id/account_error" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" + android:visibility="invisible" + tools:ignore="UseCompoundDrawables" + tools:visibility="visible"> + + <ImageView + android:layout_width="100dp" + android:layout_height="100dp" + app:srcCompat="@drawable/ic_all_account" + app:tint="?colorOnBackground" + tools:ignore="contentDescription" /> + + <TextView + android:id="@+id/account_error_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:gravity="center" + android:padding="8dp" + android:text="@string/error_unknown" + android:textSize="20sp" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:gravity="center" + android:orientation="horizontal"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/account_error_details" + style="@style/Widget.MaterialComponents.Button.OutlinedButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:text="@string/all_details" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/account_error_retry" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/all_retry" /> + </LinearLayout> + </LinearLayout> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_account_details.xml b/app/src/main/res/layout/fragment_account_details.xml new file mode 100644 index 00000000..f0e1bd9b --- /dev/null +++ b/app/src/main/res/layout/fragment_account_details.xml @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="0dp" + android:fillViewport="true" + app:layout_constraintBottom_toTopOf="@id/accountDetailsSelect" + app:layout_constraintTop_toTopOf="parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/accountDetailsAvatar" + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_marginTop="36dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_all_account" + app:tint="?colorPrimary" + tools:ignore="ContentDescription" /> + + <TextView + android:id="@+id/accountDetailsName" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:textSize="24sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/accountDetailsAvatar" + tools:text="Jan Kowalski" /> + + <TextView + android:id="@+id/accountDetailsSchool" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:textColor="?android:textColorSecondary" + android:textSize="14sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/accountDetailsName" + tools:text="Szkoła FakeLog" /> + + <LinearLayout + android:id="@+id/accountDetailsPersonalData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:layout_marginTop="16dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsSchool" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_all_account" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_personal_data" + android:textSize="16sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/accountDetailsAddressData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsPersonalData" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_all_home" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_address" + android:textSize="16sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/accountDetailsContactData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsAddressData" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_all_phone" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_contact" + android:textSize="16sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/accountDetailsFamilyData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsContactData" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_account_details_family" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_family" + android:textSize="16sp" /> + </LinearLayout> + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> + + <com.google.android.material.button.MaterialButton + android:id="@+id/accountDetailsSelect" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:insetLeft="0dp" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:text="@string/account_select_student" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintBottom_toTopOf="@id/accountDetailsLogout" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/accountDetailsLogout" + style="@style/Widget.MaterialComponents.Button.OutlinedButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:insetLeft="0dp" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:text="@string/account_logout" + app:layout_constraintBottom_toBottomOf="parent" /> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_school.xml b/app/src/main/res/layout/fragment_school.xml index a7e9a213..23126b08 100644 --- a/app/src/main/res/layout/fragment_school.xml +++ b/app/src/main/res/layout/fragment_school.xml @@ -140,7 +140,7 @@ android:id="@+id/schoolTelephoneButton" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:srcCompat="@drawable/ic_school_phone" + app:srcCompat="@drawable/ic_all_phone" android:contentDescription="@string/school_telephone_button" android:background="?attr/selectableItemBackgroundBorderless" android:tint="?colorPrimary" diff --git a/app/src/main/res/layout/fragment_student_info.xml b/app/src/main/res/layout/fragment_student_info.xml new file mode 100644 index 00000000..37145727 --- /dev/null +++ b/app/src/main/res/layout/fragment_student_info.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <me.zhanghai.android.materialprogressbar.MaterialProgressBar + android:id="@+id/student_info_progress" + style="@style/Widget.MaterialProgressBar.ProgressBar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:indeterminate="true" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.swiperefreshlayout.widget.SwipeRefreshLayout + android:layout_width="match_parent" + android:id="@+id/student_info_swipe" + android:layout_height="match_parent"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/student_info_recycler" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> + + <LinearLayout + android:id="@+id/student_info_empty" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" + android:padding="10dp" + android:visibility="gone" + tools:ignore="UseCompoundDrawables" + tools:visibility="gone"> + + <ImageView + android:layout_width="100dp" + android:layout_height="100dp" + app:srcCompat="@drawable/ic_all_about" + app:tint="?colorOnBackground" + tools:ignore="contentDescription" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:gravity="center" + android:text="@string/student_info_empty" + android:textSize="20sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/student_info_error" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" + android:visibility="invisible" + tools:ignore="UseCompoundDrawables" + tools:visibility="visible"> + + <ImageView + android:layout_width="100dp" + android:layout_height="100dp" + app:srcCompat="@drawable/ic_error" + app:tint="?colorOnBackground" + tools:ignore="contentDescription" /> + + <TextView + android:id="@+id/student_info_error_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:gravity="center" + android:padding="8dp" + android:text="@string/error_unknown" + android:textSize="20sp" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:gravity="center" + android:orientation="horizontal"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/student_info_error_details" + style="@style/Widget.MaterialComponents.Button.OutlinedButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:text="@string/all_details" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/student_info_error_retry" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/all_retry" /> + </LinearLayout> + </LinearLayout> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/header_account.xml b/app/src/main/res/layout/header_account.xml index 6219c26d..86252552 100644 --- a/app/src/main/res/layout/header_account.xml +++ b/app/src/main/res/layout/header_account.xml @@ -4,15 +4,22 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingHorizontal="24dp" - android:paddingTop="8dp" - android:paddingBottom="8dp" + android:paddingHorizontal="16dp" + android:paddingBottom="16dp" tools:context=".ui.modules.account.AccountAdapter"> + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:id="@+id/accountHeaderDivider" + android:layout_marginTop="16dp" + android:background="@color/colorDivider" /> + <TextView android:id="@+id/accountHeaderEmail" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="16dp" android:textColor="?android:textColorPrimary" android:textSize="14sp" tools:text="jan@fakelog.cf" /> @@ -21,7 +28,6 @@ android:id="@+id/accountHeaderType" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="2dp" android:textColor="?android:textColorSecondary" android:textSize="12sp" tools:text="Konto ucznia" /> diff --git a/app/src/main/res/layout/item_account.xml b/app/src/main/res/layout/item_account.xml index 9568b345..95fdb0e8 100644 --- a/app/src/main/res/layout/item_account.xml +++ b/app/src/main/res/layout/item_account.xml @@ -5,9 +5,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" android:orientation="horizontal" - android:paddingVertical="8dp" android:paddingHorizontal="16dp" + android:paddingVertical="8dp" tools:context=".ui.modules.account.AccountAdapter"> <ImageView @@ -49,7 +51,7 @@ tools:text="@tools:sample/lorem/random" /> <TextView - android:id="@+id/accountItemLoginMode" + android:id="@+id/accountItemAccountType" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" @@ -58,7 +60,6 @@ android:maxLines="1" android:textColor="?android:textColorSecondary" android:textSize="12sp" - android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/accountItemImage" app:layout_constraintTop_toBottomOf="@id/accountItemSchool" diff --git a/app/src/main/res/layout/item_student_info.xml b/app/src/main/res/layout/item_student_info.xml new file mode 100644 index 00000000..203ce86b --- /dev/null +++ b/app/src/main/res/layout/item_student_info.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="64dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true"> + + <TextView + android:id="@+id/student_info_item_title" + android:layout_width="match_parent" + android:layout_height="28dp" + android:layout_marginStart="16dp" + android:layout_marginTop="5dp" + android:layout_marginEnd="16dp" + android:gravity="bottom" + android:maxLines="1" + android:textColor="?android:textColorPrimary" + android:textSize="16sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="@tools:sample/lorem/random" /> + + <TextView + android:id="@+id/student_info_item_subtitle" + android:layout_width="match_parent" + android:layout_height="18dp" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" + android:gravity="bottom" + android:maxLines="1" + android:textColor="?android:textColorSecondary" + android:textSize="12sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/student_info_item_title" + tools:text="@tools:sample/lorem/random" /> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/menu/action_menu_account_details.xml b/app/src/main/res/menu/action_menu_account_details.xml new file mode 100644 index 00000000..9ddc1e55 --- /dev/null +++ b/app/src/main/res/menu/action_menu_account_details.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + <item + android:id="@+id/accountDetailsMenuEdit" + android:icon="@drawable/ic_menu_message_write" + android:orderInCategory="1" + android:title="@string/account_details_edit" + app:iconTint="@color/material_on_surface_emphasis_medium" + app:showAsAction="ifRoom" /> +</menu> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4364214c..f4817989 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,7 +17,10 @@ <string name="send_message_title">New message</string> <string name="note_title">Notes and achievements</string> <string name="homework_title">Homework</string> - <string name="account_title">Choose account</string> + <string name="account_title">Accounts manager</string> + <string name="account_quick_title">Select account</string> + <string name="account_details_title">Account details</string> + <string name="student_info_title">Student info</string> <!--Subtitles--> @@ -344,12 +347,19 @@ <!--Account--> <string name="account_add_new">Add account</string> <string name="account_logout">Logout</string> - <string name="account_confirm">Do you want to log out of an active student?</string> + <string name="account_confirm">Do you want to log out this student?</string> <string name="account_logout_student">Student logout</string> <string name="account_type_student">Student account</string> <string name="account_type_parent">Parent account</string> <string name="account_login_mobile_api">Mobile API mode</string> <string name="account_login_hybrid">Hybrid mode</string> + <string name="account_details_edit">Edit data</string> + <string name="account_quick_manager">Accounts manager</string> + <string name="account_select_student">Select student</string> + <string name="account_family">Family</string> + <string name="account_contact">Contact</string> + <string name="account_address">Residence details</string> + <string name="account_personal_data">Personal information</string> <!--About--> @@ -382,6 +392,28 @@ <string name="contributor_see_more">See more on GitHub</string> + <!--Student info--> + <string name="student_info_empty">No info about student</string> + <string name="student_info_first_name">Name</string> + <string name="student_info_second_name">Second name</string> + <string name="student_info_gender">Gender</string> + <string name="student_info_polish_citizenship">Polish citizenship</string> + <string name="student_info_family_name">Family name</string> + <string name="student_info_parents_name">Mother\'s and father\'s names</string> + <string name="student_info_phone">Phone</string> + <string name="student_info_cellphone">Cellphone</string> + <string name="student_info_email">E-mail</string> + <string name="student_info_address">Address of residence</string> + <string name="student_info_registered_address">Address of registration</string> + <string name="student_info_correspondence_address">Correspondence address</string> + <string name="student_info_full_name">Surname and first name</string> + <string name="student_info_kinship">Degree of kinship</string> + <string name="student_info_guardian_address">Address</string> + <string name="student_info_phones">Phones</string> + <string name="student_info_male">Male</string> + <string name="student_info_female">Female</string> + + <!--Log viewer--> <string name="logviewer_share">Share logs</string> <string name="logviewer_refresh">Refresh</string> @@ -410,6 +442,8 @@ <string name="all_next">Next</string> <string name="all_search">Search</string> <string name="all_search_hint">Search…</string> + <string name="all_yes">Yes</string> + <string name="all_no">No</string> <!--Timetable Widget--> @@ -508,4 +542,5 @@ <string name="error_unknown">An unexpected error occurred</string> <string name="error_feature_disabled">Feature disabled by your school</string> <string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string> + </resources> diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/StudentTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/StudentTest.kt index 22669323..415f6e0a 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/StudentTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/StudentTest.kt @@ -35,7 +35,9 @@ class StudentTest { @Test fun testRemoteAll() { - coEvery { mockSdk.getStudentsFromScrapper(any(), any(), any(), any()) } returns listOf(getStudent("test")) + coEvery { mockSdk.getStudentsFromScrapper(any(), any(), any(), any()) } returns listOf( + getStudent("test") + ) val students = runBlocking { studentRepository.getStudentsScrapper("", "", "http://fakelog.cf", "") } assertEquals(1, students.size) diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt index 4479965c..fed0093e 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt @@ -41,7 +41,29 @@ class GradeAverageProviderTest { private lateinit var gradeAverageProvider: GradeAverageProvider - private val student = Student("", "", "", "SCRAPPER", "", "", false, "", "", "", 101, 0, "", "", "", "", "", "", 1, true, LocalDateTime.now()) + private val student = Student( + scrapperBaseUrl = "", + mobileBaseUrl = "", + loginType = "", + loginMode = "SCRAPPER", + certificateKey = "", + privateKey = "", + isParent = false, + email = "", + password = "", + symbol = "", + studentId = 101, + userLoginId = 0, + userName = "", + studentName = "", + schoolSymbol = "", + schoolShortName = "", + schoolName = "", + className = "", + classId = 1, + isCurrent = true, + registrationDate = LocalDateTime.now() + ) private val semesters = mutableListOf( getSemesterEntity(10, 21, of(2019, 1, 31), of(2019, 6, 23)), diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt index b475584b..31e3e198 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt @@ -99,8 +99,32 @@ class LoginFormPresenterTest { @Test fun loginTest() { - val studentTest = Student(email = "test@", password = "123", scrapperBaseUrl = "https://fakelog.cf/", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "", mobileBaseUrl = "", privateKey = "", certificateKey = "", loginMode = "", userLoginId = 0, schoolShortName = "", isParent = false, userName = "") - coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(StudentWithSemesters(studentTest, emptyList())) + val studentTest = Student( + email = "test@", + password = "123", + scrapperBaseUrl = "https://fakelog.cf/", + loginType = "AUTO", + studentName = "", + schoolSymbol = "", + schoolName = "", + studentId = 0, + classId = 1, + isCurrent = false, + symbol = "", + registrationDate = now(), + className = "", + mobileBaseUrl = "", + privateKey = "", + certificateKey = "", + loginMode = "", + userLoginId = 0, + schoolShortName = "", + isParent = false, + userName = "" + ) + coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf( + StudentWithSemesters(studentTest, emptyList()) + ) every { loginFormView.formUsernameValue } returns "@" every { loginFormView.formPassValue } returns "123456" diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt index 4b977682..9e34235e 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt @@ -38,7 +38,31 @@ class LoginStudentSelectPresenterTest { private lateinit var presenter: LoginStudentSelectPresenter - private val testStudent by lazy { Student(email = "test", password = "test123", scrapperBaseUrl = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", classId = 1, studentName = "", registrationDate = now(), className = "", loginMode = "", certificateKey = "", privateKey = "", mobileBaseUrl = "", schoolShortName = "", userLoginId = 1, isParent = false, userName = "") } + private val testStudent by lazy { + Student( + email = "test", + password = "test123", + scrapperBaseUrl = "https://fakelog.cf", + loginType = "AUTO", + symbol = "", + isCurrent = false, + studentId = 0, + schoolName = "", + schoolSymbol = "", + classId = 1, + studentName = "", + registrationDate = now(), + className = "", + loginMode = "", + certificateKey = "", + privateKey = "", + mobileBaseUrl = "", + schoolShortName = "", + userLoginId = 1, + isParent = false, + userName = "" + ) + } private val testException by lazy { RuntimeException("Problem") } @@ -64,8 +88,24 @@ class LoginStudentSelectPresenterTest { @Test fun onSelectedStudentTest() { - coEvery { studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList()))) } returns listOf(1L) - coEvery { studentRepository.switchStudent(StudentWithSemesters(testStudent, emptyList())) } just Runs + coEvery { + studentRepository.saveStudents( + listOf( + StudentWithSemesters( + testStudent, + emptyList() + ) + ) + ) + } returns listOf(1L) + coEvery { + studentRepository.switchStudent( + StudentWithSemesters( + testStudent, + emptyList() + ) + ) + } just Runs every { loginStudentSelectView.openMainView() } just Runs presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false) presenter.onSignIn() @@ -77,7 +117,16 @@ class LoginStudentSelectPresenterTest { @Test fun onSelectedStudentErrorTest() { - coEvery { studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList()))) } throws testException + coEvery { + studentRepository.saveStudents( + listOf( + StudentWithSemesters( + testStudent, + emptyList() + ) + ) + ) + } throws testException coEvery { studentRepository.logoutStudent(testStudent) } just Runs presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false) presenter.onSignIn() diff --git a/gradle.properties b/gradle.properties index 5741ecfc..998e3195 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,10 +7,13 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m android.enableJetifier=true android.useAndroidX=true -org.gradle.jvmargs=-Xmx1536m +kotlin.code.style=official kapt.incremental.apt=true +kapt.use.worker.api=true +kapt.include.compile.classpath=false # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit From 6568c4abf8930bf9dd0a5afa252cdb281ba4088c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 29 Jan 2021 21:24:30 +0000 Subject: [PATCH 12/28] Bump hilt-work from 1.0.0-alpha02 to 1.0.0-alpha03 (#1099) --- app/build.gradle | 5 +-- .../wulkanowy/services/sync/SyncWorker.kt | 34 +++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 6e7bb42d..89062b9f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -131,6 +131,7 @@ play { ext { work_manager = "2.5.0" + work_hilt = "1.0.0-alpha03" room = "2.3.0-alpha04" chucker = "3.4.0" mockk = "1.10.5" @@ -175,8 +176,8 @@ dependencies { implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version" - implementation 'androidx.hilt:hilt-work:1.0.0-alpha02' - kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02' + implementation "androidx.hilt:hilt-work:$work_hilt" + kapt "androidx.hilt:hilt-compiler:$work_hilt" implementation "com.aurelhubert:ahbottomnavigation:2.3.4" implementation "com.ncapdevi:frag-nav:3.3.0" diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt index a428b702..8b6bc65d 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt @@ -5,11 +5,12 @@ import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat.BigTextStyle import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT import androidx.core.app.NotificationManagerCompat -import androidx.hilt.Assisted -import androidx.hilt.work.WorkerInject +import androidx.hilt.work.HiltWorker import androidx.work.CoroutineWorker import androidx.work.Data import androidx.work.WorkerParameters +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject import io.github.wulkanowy.R import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.SemesterRepository @@ -23,7 +24,8 @@ import kotlinx.coroutines.coroutineScope import timber.log.Timber import kotlin.random.Random -class SyncWorker @WorkerInject constructor( +@HiltWorker +class SyncWorker @AssistedInject constructor( @Assisted appContext: Context, @Assisted workerParameters: WorkerParameters, private val studentRepository: StudentRepository, @@ -58,9 +60,10 @@ class SyncWorker @WorkerInject constructor( } val result = when { exceptions.isNotEmpty() && inputData.getBoolean("one_time", false) -> { - Result.failure(Data.Builder() - .putString("error", exceptions.map { it.stackTraceToString() }.toString()) - .build() + Result.failure( + Data.Builder() + .putString("error", exceptions.map { it.stackTraceToString() }.toString()) + .build() ) } exceptions.isNotEmpty() -> Result.retry() @@ -74,13 +77,16 @@ class SyncWorker @WorkerInject constructor( } private fun notify(result: Result) { - notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID) - .setContentTitle("Debug notification") - .setSmallIcon(R.drawable.ic_stat_push) - .setAutoCancel(true) - .setColor(applicationContext.getCompatColor(R.color.colorPrimary)) - .setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result")) - .setPriority(PRIORITY_DEFAULT) - .build()) + notificationManager.notify( + Random.nextInt(Int.MAX_VALUE), + NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID) + .setContentTitle("Debug notification") + .setSmallIcon(R.drawable.ic_stat_push) + .setAutoCancel(true) + .setColor(applicationContext.getCompatColor(R.color.colorPrimary)) + .setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result")) + .setPriority(PRIORITY_DEFAULT) + .build() + ) } } From 82df5b951500b91b9807784a81db0a69ba629c2a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 Jan 2021 14:13:35 +0000 Subject: [PATCH 13/28] Bump agconnect-crash from 1.4.2.301 to 1.5.0.200 (#1110) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 89062b9f..f1e7a328 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -205,7 +205,7 @@ dependencies { playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' hmsImplementation 'com.huawei.hms:hianalytics:5.1.0.301' - hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.4.2.301' + hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.0.200' releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" From 70d42bb8645172cb36603e4142b83b119ae7c7f8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 Jan 2021 14:14:08 +0000 Subject: [PATCH 14/28] Bump agcp from 1.4.2.301 to 1.5.0.200 (#1109) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9bdfdd2d..f82df20e 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ buildscript { classpath 'com.android.tools.build:gradle:4.1.2' classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" classpath 'com.google.gms:google-services:4.3.5' - classpath 'com.huawei.agconnect:agcp:1.4.2.301' + classpath 'com.huawei.agconnect:agcp:1.5.0.200' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1' classpath "com.github.triplet.gradle:play-publisher:2.8.0" classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.1.1" From f5e4c63fedac9d757ec27f979ca2187af0fde244 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 Jan 2021 14:18:28 +0000 Subject: [PATCH 15/28] Bump about_libraries from 8.6.9 to 8.7.0 (#1111) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f82df20e..5ab0182b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { ext { kotlin_version = '1.4.21' - about_libraries = '8.6.9' + about_libraries = '8.7.0' hilt_version = "2.31.2-alpha" } repositories { From e5e95e7dec421ed9d874797ddc04c55dd87dbba5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 Jan 2021 14:22:08 +0000 Subject: [PATCH 16/28] Bump room from 2.3.0-alpha04 to 2.3.0-beta01 (#1112) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index f1e7a328..2c3aaa8c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -132,7 +132,7 @@ play { ext { work_manager = "2.5.0" work_hilt = "1.0.0-alpha03" - room = "2.3.0-alpha04" + room = "2.3.0-beta01" chucker = "3.4.0" mockk = "1.10.5" moshi = "1.11.0" From dd5ce752da647bf588ac8b6c174dbfd7a810ad8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= <RafalBO99@outlook.com> Date: Sat, 30 Jan 2021 15:26:31 +0100 Subject: [PATCH 17/28] Update gradle and build tools (#1108) --- app/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2c3aaa8c..e90852c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ apply from: 'hooks.gradle' android { compileSdkVersion 30 - buildToolsVersion '30.0.2' + buildToolsVersion '30.0.3' defaultConfig { applicationId "io.github.wulkanowy" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 33682bbb..1c4bcc29 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From d1cd497a23eaa983ecd4fc13f2f5a79de1c13e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= <RafalBO99@outlook.com> Date: Sat, 30 Jan 2021 16:07:37 +0100 Subject: [PATCH 18/28] Fix null data in Status.SUCCESS in emission from average provider (#1105) --- .../ui/modules/grade/GradeAverageProvider.kt | 218 ++++++++++++------ ...eDetailsWithAverage.kt => GradeSubject.kt} | 2 +- .../grade/details/GradeDetailsPresenter.kt | 9 +- .../grade/summary/GradeSummaryPresenter.kt | 6 +- .../github/wulkanowy/utils/GradeExtension.kt | 95 ++++---- .../modules/grade/GradeAverageProviderTest.kt | 46 ++++ 6 files changed, 250 insertions(+), 126 deletions(-) rename app/src/main/java/io/github/wulkanowy/ui/modules/grade/{GradeDetailsWithAverage.kt => GradeSubject.kt} (88%) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt index 0bd971ec..36c3c4f8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.modules.grade import io.github.wulkanowy.data.Resource +import io.github.wulkanowy.data.Status import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Semester @@ -33,81 +34,162 @@ class GradeAverageProvider @Inject constructor( private val minusModifier get() = preferencesRepository.gradeMinusModifier - fun getGradesDetailsWithAverage(student: Student, semesterId: Int, forceRefresh: Boolean) = flowWithResourceIn { - val semesters = semesterRepository.getSemesters(student) + fun getGradesDetailsWithAverage(student: Student, semesterId: Int, forceRefresh: Boolean) = + flowWithResourceIn { + val semesters = semesterRepository.getSemesters(student) - when (preferencesRepository.gradeAverageMode) { - ONE_SEMESTER -> getSemesterDetailsWithAverage(student, semesters.single { it.semesterId == semesterId }, forceRefresh) - BOTH_SEMESTERS -> calculateBothSemestersAverage(student, semesters, semesterId, forceRefresh) - ALL_YEAR -> calculateAllYearAverage(student, semesters, semesterId, forceRefresh) - } - }.distinctUntilChanged() - - private fun calculateBothSemestersAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Flow<Resource<List<GradeDetailsWithAverage>>> { - val selectedSemester = semesters.single { it.semesterId == semesterId } - val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 } - - val selectedSemesterDetailsWithAverage = getSemesterDetailsWithAverage(student, selectedSemester, forceRefresh) - - return if (selectedSemester == firstSemester) selectedSemesterDetailsWithAverage else { - val firstSemesterDetailsWithAverage = getSemesterDetailsWithAverage(student, firstSemester, forceRefresh) - selectedSemesterDetailsWithAverage.combine(firstSemesterDetailsWithAverage) { selectedDetails, secondDetails -> - val isAnyAverage = selectedDetails.data.orEmpty().any { it.average != .0 } - secondDetails.copy(data = selectedDetails.data?.map { selected -> - val second = secondDetails.data.orEmpty().singleOrNull { it.subject == selected.subject } - selected.copy(average = if (!isAnyAverage || preferencesRepository.gradeAverageForceCalc) { - val selectedGrades = selected.grades.updateModifiers(student).calcAverage() - (selectedGrades + (second?.grades?.updateModifiers(student)?.calcAverage() ?: selectedGrades)) / 2 - } else (selected.average + (second?.average ?: selected.average)) / 2) - }) - } - } - } - - private fun calculateAllYearAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Flow<Resource<List<GradeDetailsWithAverage>>> { - val selectedSemester = semesters.single { it.semesterId == semesterId } - val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 } - - val selectedSemesterDetailsWithAverage = getSemesterDetailsWithAverage(student, selectedSemester, forceRefresh) - - return if (selectedSemester == firstSemester) selectedSemesterDetailsWithAverage else { - val firstSemesterDetailsWithAverage = getSemesterDetailsWithAverage(student, firstSemester, forceRefresh) - selectedSemesterDetailsWithAverage.combine(firstSemesterDetailsWithAverage) { selectedDetails, secondDetails -> - val isAnyAverage = selectedDetails.data.orEmpty().any { it.average != .0 } - secondDetails.copy(data = selectedDetails.data?.map { selected -> - val second = secondDetails.data.orEmpty().singleOrNull { it.subject == selected.subject } - selected.copy(average = if (!isAnyAverage || preferencesRepository.gradeAverageForceCalc) { - (selected.grades.updateModifiers(student) + second?.grades?.updateModifiers(student).orEmpty()).calcAverage() - } else selected.average) - }) - } - } - } - - private fun getSemesterDetailsWithAverage(student: Student, semester: Semester, forceRefresh: Boolean): Flow<Resource<List<GradeDetailsWithAverage>>> { - return gradeRepository.getGrades(student, semester, forceRefresh = forceRefresh).map { res -> - val (details, summaries) = res.data ?: null to null - val isAnyAverage = summaries.orEmpty().any { it.average != .0 } - val allGrades = details.orEmpty().groupBy { it.subject } - - val items = summaries?.emulateEmptySummaries(student, semester, allGrades.toList(), isAnyAverage)?.map { summary -> - val grades = allGrades[summary.subject].orEmpty() - GradeDetailsWithAverage( - subject = summary.subject, - average = if (!isAnyAverage || preferencesRepository.gradeAverageForceCalc) { - grades.updateModifiers(student).calcAverage() - } else summary.average, - points = summary.pointsSum, - summary = summary, - grades = grades + when (preferencesRepository.gradeAverageMode) { + ONE_SEMESTER -> getGradeSubjects( + student = student, + semester = semesters.single { it.semesterId == semesterId }, + forceRefresh = forceRefresh + ) + BOTH_SEMESTERS -> calculateCombinedAverage( + student = student, + semesters = semesters, + semesterId = semesterId, + forceRefresh = forceRefresh, + averageMode = BOTH_SEMESTERS + ) + ALL_YEAR -> calculateCombinedAverage( + student = student, + semesters = semesters, + semesterId = semesterId, + forceRefresh = forceRefresh, + averageMode = ALL_YEAR ) } + }.distinctUntilChanged() - Resource(res.status, items, res.error) + private fun calculateCombinedAverage( + student: Student, + semesters: List<Semester>, + semesterId: Int, + forceRefresh: Boolean, + averageMode: GradeAverageMode + ): Flow<Resource<List<GradeSubject>>> { + val gradeAverageForceCalc = preferencesRepository.gradeAverageForceCalc + val selectedSemester = semesters.single { it.semesterId == semesterId } + val firstSemester = + semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 } + + val selectedSemesterGradeSubjects = + getGradeSubjects(student, selectedSemester, forceRefresh) + + if (selectedSemester == firstSemester) return selectedSemesterGradeSubjects + + val firstSemesterGradeSubjects = + getGradeSubjects(student, firstSemester, forceRefresh) + + return selectedSemesterGradeSubjects.combine(firstSemesterGradeSubjects) { secondSemesterGradeSubject, firstSemesterGradeSubject -> + if (firstSemesterGradeSubject.status == Status.ERROR) { + return@combine firstSemesterGradeSubject + } + + val isAnyAverage = secondSemesterGradeSubject.data.orEmpty().any { it.average != .0 } + val updatedData = secondSemesterGradeSubject.data?.map { secondSemesterSubject -> + val firstSemesterSubject = firstSemesterGradeSubject.data.orEmpty() + .singleOrNull { it.subject == secondSemesterSubject.subject } + + val updatedAverage = if (averageMode == ALL_YEAR) { + calculateAllYearAverage( + student = student, + isAnyAverage = isAnyAverage, + gradeAverageForceCalc = gradeAverageForceCalc, + secondSemesterSubject = secondSemesterSubject, + firstSemesterSubject = firstSemesterSubject + ) + } else { + calculateBothSemestersAverage( + student = student, + isAnyAverage = isAnyAverage, + gradeAverageForceCalc = gradeAverageForceCalc, + secondSemesterSubject = secondSemesterSubject, + firstSemesterSubject = firstSemesterSubject + ) + } + secondSemesterSubject.copy(average = updatedAverage) + } + secondSemesterGradeSubject.copy(data = updatedData) } } - private fun List<GradeSummary>.emulateEmptySummaries(student: Student, semester: Semester, grades: List<Pair<String, List<Grade>>>, calcAverage: Boolean): List<GradeSummary> { + private fun calculateAllYearAverage( + student: Student, + isAnyAverage: Boolean, + gradeAverageForceCalc: Boolean, + secondSemesterSubject: GradeSubject, + firstSemesterSubject: GradeSubject? + ) = if (!isAnyAverage || gradeAverageForceCalc) { + val updatedSecondSemesterGrades = + secondSemesterSubject.grades.updateModifiers(student) + val updatedFirstSemesterGrades = + firstSemesterSubject?.grades?.updateModifiers(student).orEmpty() + + (updatedSecondSemesterGrades + updatedFirstSemesterGrades).calcAverage() + } else { + secondSemesterSubject.average + } + + private fun calculateBothSemestersAverage( + student: Student, + isAnyAverage: Boolean, + gradeAverageForceCalc: Boolean, + secondSemesterSubject: GradeSubject, + firstSemesterSubject: GradeSubject? + ) = if (!isAnyAverage || gradeAverageForceCalc) { + val secondSemesterAverage = + secondSemesterSubject.grades.updateModifiers(student).calcAverage() + val firstSemesterAverage = firstSemesterSubject?.grades?.updateModifiers(student) + ?.calcAverage() ?: secondSemesterAverage + val divider = if (secondSemesterSubject.grades.any { it.weightValue > .0 }) 2 else 1 + + (secondSemesterAverage + firstSemesterAverage) / divider + } else { + (secondSemesterSubject.average + (firstSemesterSubject?.average ?: secondSemesterSubject.average)) / 2 + } + + private fun getGradeSubjects( + student: Student, + semester: Semester, + forceRefresh: Boolean + ): Flow<Resource<List<GradeSubject>>> { + val gradeAverageForceCalc = preferencesRepository.gradeAverageForceCalc + + return gradeRepository.getGrades(student, semester, forceRefresh = forceRefresh) + .map { res -> + val (details, summaries) = res.data ?: null to null + val isAnyAverage = summaries.orEmpty().any { it.average != .0 } + val allGrades = details.orEmpty().groupBy { it.subject } + + val items = summaries?.emulateEmptySummaries( + student, + semester, + allGrades.toList(), + isAnyAverage + )?.map { summary -> + val grades = allGrades[summary.subject].orEmpty() + GradeSubject( + subject = summary.subject, + average = if (!isAnyAverage || gradeAverageForceCalc) { + grades.updateModifiers(student).calcAverage() + } else summary.average, + points = summary.pointsSum, + summary = summary, + grades = grades + ) + } + + Resource(res.status, items, res.error) + } + } + + private fun List<GradeSummary>.emulateEmptySummaries( + student: Student, + semester: Semester, + grades: List<Pair<String, List<Grade>>>, + calcAverage: Boolean + ): List<GradeSummary> { if (isNotEmpty() && size > grades.size) return this return grades.mapIndexed { i, (subject, details) -> diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeDetailsWithAverage.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeSubject.kt similarity index 88% rename from app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeDetailsWithAverage.kt rename to app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeSubject.kt index 3f5d706b..ee4266c5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeDetailsWithAverage.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeSubject.kt @@ -3,7 +3,7 @@ package io.github.wulkanowy.ui.modules.grade import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.GradeSummary -data class GradeDetailsWithAverage( +data class GradeSubject( val subject: String, val average: Double, val points: String, diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt index afec6b5e..6d86c7bb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt @@ -10,9 +10,9 @@ import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider -import io.github.wulkanowy.ui.modules.grade.GradeDetailsWithAverage import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.ALPHABETIC import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.DATE +import io.github.wulkanowy.ui.modules.grade.GradeSubject import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.afterLoading import io.github.wulkanowy.utils.flowWithResource @@ -201,8 +201,9 @@ class GradeDetailsPresenter @Inject constructor( }.launch() } - private fun updateNewGradesAmount(grades: List<GradeDetailsWithAverage>) { - newGradesAmount = grades.sumBy { item -> item.grades.sumBy { grade -> if (!grade.isRead) 1 else 0 } } + private fun updateNewGradesAmount(grades: List<GradeSubject>) { + newGradesAmount = + grades.sumBy { item -> item.grades.sumBy { grade -> if (!grade.isRead) 1 else 0 } } } private fun showErrorViewOnError(message: String, error: Throwable) { @@ -217,7 +218,7 @@ class GradeDetailsPresenter @Inject constructor( } @SuppressLint("DefaultLocale") - private fun createGradeItems(items: List<GradeDetailsWithAverage>): List<GradeDetailsItem> { + private fun createGradeItems(items: List<GradeSubject>): List<GradeDetailsItem> { return items .let { gradesWithAverages -> if (!preferencesRepository.showSubjectsWithoutGrades) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt index 17c14b85..7adfd7e5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt @@ -6,7 +6,7 @@ import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider -import io.github.wulkanowy.ui.modules.grade.GradeDetailsWithAverage +import io.github.wulkanowy.ui.modules.grade.GradeSubject import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.afterLoading import io.github.wulkanowy.utils.flowWithResourceIn @@ -135,14 +135,14 @@ class GradeSummaryPresenter @Inject constructor( cancelJobs("load") } - private fun createGradeSummaryItems(items: List<GradeDetailsWithAverage>): List<GradeSummary> { + private fun createGradeSummaryItems(items: List<GradeSubject>): List<GradeSummary> { return items .filter { !checkEmpty(it) } .sortedBy { it.subject } .map { it.summary.copy(average = it.average) } } - private fun checkEmpty(gradeSummary: GradeDetailsWithAverage): Boolean { + private fun checkEmpty(gradeSummary: GradeSubject): Boolean { return gradeSummary.run { summary.finalGrade.isBlank() && summary.predictedGrade.isBlank() diff --git a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt index c57b6247..9aa4fcac 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt @@ -16,63 +16,58 @@ fun List<Grade>.calcAverage(): Double { } @JvmName("calcSummaryAverage") -fun List<GradeSummary>.calcAverage(): Double { - return asSequence().mapNotNull { - if (it.finalGrade.matches("[0-6]".toRegex())) it.finalGrade.toDouble() else null - }.average().let { if (it.isNaN()) 0.0 else it } -} - -fun Grade.getBackgroundColor(theme: String): Int { - return when (theme) { - "grade_color" -> getGradeColor() - "material" -> when (value.toInt()) { - 6 -> R.color.grade_material_six - 5 -> R.color.grade_material_five - 4 -> R.color.grade_material_four - 3 -> R.color.grade_material_three - 2 -> R.color.grade_material_two - 1 -> R.color.grade_material_one - else -> R.color.grade_material_default - } - else -> when (value.toInt()) { - 6 -> R.color.grade_vulcan_six - 5 -> R.color.grade_vulcan_five - 4 -> R.color.grade_vulcan_four - 3 -> R.color.grade_vulcan_three - 2 -> R.color.grade_vulcan_two - 1 -> R.color.grade_vulcan_one - else -> R.color.grade_vulcan_default - } +fun List<GradeSummary>.calcAverage() = asSequence() + .mapNotNull { + if (it.finalGrade.matches("[0-6]".toRegex())) { + it.finalGrade.toDouble() + } else null } -} + .average() + .let { if (it.isNaN()) 0.0 else it } -fun Grade.getGradeColor(): Int { - return when (color) { - "000000" -> R.color.grade_black - "F04C4C" -> R.color.grade_red - "20A4F7" -> R.color.grade_blue - "6ECD07" -> R.color.grade_green - "B16CF1" -> R.color.grade_purple +fun Grade.getBackgroundColor(theme: String) = when (theme) { + "grade_color" -> getGradeColor() + "material" -> when (value.toInt()) { + 6 -> R.color.grade_material_six + 5 -> R.color.grade_material_five + 4 -> R.color.grade_material_four + 3 -> R.color.grade_material_three + 2 -> R.color.grade_material_two + 1 -> R.color.grade_material_one else -> R.color.grade_material_default } + else -> when (value.toInt()) { + 6 -> R.color.grade_vulcan_six + 5 -> R.color.grade_vulcan_five + 4 -> R.color.grade_vulcan_four + 3 -> R.color.grade_vulcan_three + 2 -> R.color.grade_vulcan_two + 1 -> R.color.grade_vulcan_one + else -> R.color.grade_vulcan_default + } +} + +fun Grade.getGradeColor() = when (color) { + "000000" -> R.color.grade_black + "F04C4C" -> R.color.grade_red + "20A4F7" -> R.color.grade_blue + "6ECD07" -> R.color.grade_green + "B16CF1" -> R.color.grade_purple + else -> R.color.grade_material_default } inline val Grade.colorStringId: Int - get() { - return when (color) { - "000000" -> R.string.all_black - "F04C4C" -> R.string.all_red - "20A4F7" -> R.string.all_blue - "6ECD07" -> R.string.all_green - "B16CF1" -> R.string.all_purple - else -> R.string.all_empty_color - } + get() = when (color) { + "000000" -> R.string.all_black + "F04C4C" -> R.string.all_red + "20A4F7" -> R.string.all_blue + "6ECD07" -> R.string.all_green + "B16CF1" -> R.string.all_purple + else -> R.string.all_empty_color } -fun Grade.changeModifier(plusModifier: Double, minusModifier: Double): Grade { - return when { - modifier > 0 -> copy(modifier = plusModifier) - modifier < 0 -> copy(modifier = -minusModifier) - else -> this - } +fun Grade.changeModifier(plusModifier: Double, minusModifier: Double) = when { + modifier > 0 -> copy(modifier = plusModifier) + modifier < 0 -> copy(modifier = -minusModifier) + else -> this } diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt index fed0093e..0da02cf5 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt @@ -15,6 +15,7 @@ import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.toList @@ -152,6 +153,51 @@ class GradeAverageProviderTest { assertEquals(3.5, items[1].data?.single { it.subject == "Język polski" }!!.average, .0) // from details and after set custom plus/minus } + @Test + fun `calc all year semester average with delayed emit`(){ + every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR + + coEvery { semesterRepository.getSemesters(student) } returns semesters + coEvery { gradeRepository.getGrades(student, semesters[2], false) } returns flow { + emit(Resource.loading()) + delay(1000) + emit(Resource.success(secondGradeWithModifier to secondSummariesWithModifier)) + } + coEvery { gradeRepository.getGrades(student, semesters[1], false) } returns flow { + emit(Resource.loading()) + emit(Resource.success(secondGradeWithModifier to secondSummariesWithModifier)) + } + + val items = runBlocking { gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId, false).toList() } + + with(items[0]) { + assertEquals(Status.LOADING, status) + assertEquals(null, data) + } + with(items[1]) { + assertEquals(Status.SUCCESS, status) + assertEquals(1, data!!.size) + } + + assertEquals(3.5, items[1].data?.single { it.subject == "Język polski" }!!.average, .0) // from details and after set custom plus/minus + } + + @Test + fun `calc both semesters average with grade without grade in second semester`() { + every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS + + coEvery { gradeRepository.getGrades(student, semesters[1], false) } returns flowWithResource { secondGradeWithModifier to secondSummariesWithModifier } + coEvery { gradeRepository.getGrades(student, semesters[2], false) } returns flowWithResource { + listOf(getGrade(semesters[2].semesterId, "Język polski", .0, .0, .0)) to listOf(getSummary(semesters[2].semesterId, "Język polski", 2.5)) + } + + val items = runBlocking { gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId, false).getResult() } + + assertEquals(3.5, items.single { it.subject == "Język polski" }.average, .0) + } + @Test fun `force calc average on no grades`() { every { preferencesRepository.gradeAverageForceCalc } returns true From e2ba265048379c0848bcbf76176c61c4509dc8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= <m.pich@outlook.com> Date: Sun, 31 Jan 2021 17:12:38 +0100 Subject: [PATCH 19/28] Add build date to version info (#1114) --- app/build.gradle | 5 ++++- app/src/main/AndroidManifest.xml | 12 ++++++++++++ .../io/github/wulkanowy/ui/base/ErrorDialog.kt | 14 ++++++++++---- .../ui/modules/about/AboutFragment.kt | 18 ++++++++++++++---- .../java/io/github/wulkanowy/utils/AppInfo.kt | 6 ++++++ 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e90852c3..39930a73 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,9 +21,12 @@ android { versionCode 81 versionName "0.24.3" multiDexEnabled true - resValue "string", "app_name", "Wulkanowy" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true + + resValue "string", "app_name", "Wulkanowy" + buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis()) + manifestPlaceholders = [ firebase_enabled: project.hasProperty("enableFirebase") ] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index eaef4369..ac8d3be4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,6 +18,18 @@ <action android:name="android.intent.action.VIEW" /> <data android:scheme="https" /> </intent> + <intent> + <action android:name="android.intent.action.VIEW" /> + <data android:scheme="mailto" /> + </intent> + <intent> + <action android:name="android.intent.action.VIEW" /> + <data android:scheme="tel" /> + </intent> + <intent> + <action android:name="android.intent.action.VIEW" /> + <data android:scheme="geo" /> + </intent> </queries> <application diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt index 341ae459..f76614e1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt @@ -57,7 +57,7 @@ class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() { } } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return DialogErrorBinding.inflate(inflater).apply { binding = this }.root } @@ -114,11 +114,17 @@ class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() { chooserTitle = getString(R.string.about_feedback), email = "wulkanowyinc@gmail.com", subject = "Zgłoszenie błędu", - body = requireContext().getString(R.string.about_feedback_template, - "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), appInfo.versionName + body = requireContext().getString( + R.string.about_feedback_template, + "${appInfo.systemManufacturer} ${appInfo.systemModel}", + appInfo.systemVersion.toString(), + "${appInfo.versionName}-${appInfo.buildFlavor}" ) + "\n" + content, onActivityNotFound = { - requireContext().openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage) + requireContext().openInternetBrowser( + "https://github.com/wulkanowy/wulkanowy/issues", + ::showMessage + ) } ) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt index c616c31e..1c613800 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt @@ -18,6 +18,8 @@ import io.github.wulkanowy.utils.getCompatDrawable import io.github.wulkanowy.utils.openAppInMarket import io.github.wulkanowy.utils.openEmailClient import io.github.wulkanowy.utils.openInternetBrowser +import io.github.wulkanowy.utils.toFormattedString +import io.github.wulkanowy.utils.toLocalDateTime import javax.inject.Inject @AndroidEntryPoint @@ -35,7 +37,9 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about override val versionRes: Triple<String, String, Drawable?>? get() = context?.run { - Triple(getString(R.string.about_version), "${appInfo.versionName} (${appInfo.versionCode})", getCompatDrawable(R.drawable.ic_all_about)) + val buildTimestamp = appInfo.buildTimestamp.toLocalDateTime().toFormattedString("yyyy-MM-dd") + val versionSignature = "${appInfo.versionName}-${appInfo.buildFlavor} (${appInfo.versionCode}), $buildTimestamp" + Triple(getString(R.string.about_version), versionSignature, getCompatDrawable(R.drawable.ic_all_about)) } override val creatorsRes: Triple<String, String, Drawable?>? @@ -135,11 +139,17 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about chooserTitle = getString(R.string.about_feedback), email = "wulkanowyinc@gmail.com", subject = "Zgłoszenie błędu", - body = getString(R.string.about_feedback_template, - "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), appInfo.versionName + body = getString( + R.string.about_feedback_template, + "${appInfo.systemManufacturer} ${appInfo.systemModel}", + appInfo.systemVersion.toString(), + "${appInfo.versionName}-${appInfo.buildFlavor}" ), onActivityNotFound = { - requireContext().openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage) + requireContext().openInternetBrowser( + "https://github.com/wulkanowy/wulkanowy/issues", + ::showMessage + ) } ) } diff --git a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt index 37a09e74..82671a7f 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt @@ -4,7 +4,9 @@ import android.content.res.Resources import android.os.Build.MANUFACTURER import android.os.Build.MODEL import android.os.Build.VERSION.SDK_INT +import io.github.wulkanowy.BuildConfig.BUILD_TIMESTAMP import io.github.wulkanowy.BuildConfig.DEBUG +import io.github.wulkanowy.BuildConfig.FLAVOR import io.github.wulkanowy.BuildConfig.VERSION_CODE import io.github.wulkanowy.BuildConfig.VERSION_NAME import javax.inject.Inject @@ -17,6 +19,10 @@ open class AppInfo @Inject constructor() { open val versionCode get() = VERSION_CODE + open val buildTimestamp get() = BUILD_TIMESTAMP + + open val buildFlavor get() = FLAVOR + open val versionName get() = VERSION_NAME open val systemVersion get() = SDK_INT From 4984cb9b26284bc816b1cf1846c0878802ec1de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= <m.pich@outlook.com> Date: Sun, 31 Jan 2021 21:46:24 +0100 Subject: [PATCH 20/28] Update auto update priority policy (#1051) --- .../io/github/wulkanowy/utils/UpdateHelper.kt | 75 ++++++++++++++----- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/app/src/play/java/io/github/wulkanowy/utils/UpdateHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/UpdateHelper.kt index 7586a21a..1dd3bc68 100644 --- a/app/src/play/java/io/github/wulkanowy/utils/UpdateHelper.kt +++ b/app/src/play/java/io/github/wulkanowy/utils/UpdateHelper.kt @@ -17,6 +17,7 @@ import com.google.android.play.core.install.model.UpdateAvailability.DEVELOPER_T import com.google.android.play.core.install.model.UpdateAvailability.UPDATE_AVAILABLE import com.google.android.play.core.ktx.isFlexibleUpdateAllowed import com.google.android.play.core.ktx.isImmediateUpdateAllowed +import com.google.android.play.core.ktx.updatePriority import dagger.hilt.android.qualifiers.ApplicationContext import io.github.wulkanowy.R import timber.log.Timber @@ -24,40 +25,57 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class UpdateHelper @Inject constructor(@ApplicationContext private val context: Context) { +class UpdateHelper @Inject constructor( + @ApplicationContext private val context: Context, + private val analyticsHelper: AnalyticsHelper, +) { lateinit var messageContainer: View - companion object { - const val IN_APP_UPDATE_REQUEST_CODE = 1721 - - const val DAYS_FOR_FLEXIBLE_UPDATE = 7 - const val HIGH_PRIORITY_UPDATE = 4 - } - private val appUpdateManager by lazy { AppUpdateManagerFactory.create(context) } private val flexibleUpdateListener = InstallStateUpdatedListener { state -> when (state.installStatus()) { - PENDING -> Toast.makeText(context, R.string.update_download_started, Toast.LENGTH_SHORT).show() + PENDING -> Toast.makeText(context, R.string.update_download_started, Toast.LENGTH_SHORT) + .show() DOWNLOADED -> popupSnackBarForCompleteUpdate() else -> Timber.d("Update state: ${state.installStatus()}") } } private inline val AppUpdateInfo.isImmediateUpdateAvailable: Boolean - get() = updateAvailability() == UPDATE_AVAILABLE && isImmediateUpdateAllowed && - updatePriority() >= HIGH_PRIORITY_UPDATE + get() { + val days = clientVersionStalenessDays() ?: 0 + val isUpdatePriorityAllowUpdate = when (updatePriority) { + 5 -> true + 4 -> days > 7 + 3 -> days > 30 + else -> false + } + + return updateAvailability() == UPDATE_AVAILABLE && isImmediateUpdateAllowed && isUpdatePriorityAllowUpdate + } private inline val AppUpdateInfo.isFlexibleUpdateAvailable: Boolean - get() = updateAvailability() == UPDATE_AVAILABLE && isFlexibleUpdateAllowed && - clientVersionStalenessDays() ?: 0 >= DAYS_FOR_FLEXIBLE_UPDATE + get() { + val days = clientVersionStalenessDays() ?: 0 + val isUpdatePriorityAllowUpdate = when (updatePriority) { + 4, 3, 2 -> true + 1 -> days >= 7 + 0 -> false + else -> false + } + + return updateAvailability() == UPDATE_AVAILABLE && isFlexibleUpdateAllowed && isUpdatePriorityAllowUpdate + } fun checkAndInstallUpdates(activity: Activity) { Timber.d("Checking for updates...") appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo -> when { - appUpdateInfo.isImmediateUpdateAvailable -> startUpdate(activity, appUpdateInfo, IMMEDIATE) + appUpdateInfo.isImmediateUpdateAvailable -> { + startUpdate(activity, appUpdateInfo, IMMEDIATE) + } appUpdateInfo.isFlexibleUpdateAvailable -> { appUpdateManager.registerListener(flexibleUpdateListener) startUpdate(activity, appUpdateInfo, FLEXIBLE) @@ -68,15 +86,20 @@ class UpdateHelper @Inject constructor(@ApplicationContext private val context: } private fun startUpdate(activity: Activity, appUpdateInfo: AppUpdateInfo, updateType: Int) { + Timber.d("Start update ($updateType): $appUpdateInfo") appUpdateManager.startUpdateFlowForResult( appUpdateInfo, updateType, activity, IN_APP_UPDATE_REQUEST_CODE ) } fun onActivityResult(requestCode: Int, resultCode: Int) { - if (requestCode == IN_APP_UPDATE_REQUEST_CODE && resultCode != RESULT_OK) { - Timber.e("Update failed! Result code: $resultCode") - Toast.makeText(context, R.string.update_failed, Toast.LENGTH_LONG).show() + if (requestCode == IN_APP_UPDATE_REQUEST_CODE) { + if (resultCode != RESULT_OK) { + Timber.i("Update failed! Result code: $resultCode") + Toast.makeText(context, R.string.update_failed, Toast.LENGTH_LONG).show() + } + + analyticsHelper.logEvent("inapp_update", "code" to resultCode) } } @@ -87,14 +110,23 @@ class UpdateHelper @Inject constructor(@ApplicationContext private val context: when { DOWNLOADED == info.installStatus() -> popupSnackBarForCompleteUpdate() DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS == info.updateAvailability() -> { - startUpdate(activity, info, if (info.isImmediateUpdateAvailable) IMMEDIATE else FLEXIBLE) + startUpdate( + activity = activity, + appUpdateInfo = info, + updateType = if (info.isImmediateUpdateAvailable) IMMEDIATE else FLEXIBLE + ) } } } } private fun popupSnackBarForCompleteUpdate() { - Snackbar.make(messageContainer, R.string.update_download_success, Snackbar.LENGTH_INDEFINITE).apply { + Timber.d("Show snackbar with update complete") + Snackbar.make( + messageContainer, + R.string.update_download_success, + Snackbar.LENGTH_INDEFINITE + ).apply { setAction(R.string.update_download_success_button) { appUpdateManager.completeUpdate() appUpdateManager.unregisterListener(flexibleUpdateListener) @@ -102,4 +134,9 @@ class UpdateHelper @Inject constructor(@ApplicationContext private val context: show() } } + + private companion object { + + private const val IN_APP_UPDATE_REQUEST_CODE = 1721 + } } From 82b207b03aec2eb8c799cbfe13af53c66fc6f90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= <RafalBO99@outlook.com> Date: Sun, 31 Jan 2021 22:38:30 +0100 Subject: [PATCH 21/28] Fix follow system language setting (#1113) --- app/build.gradle | 2 +- .../java/io/github/wulkanowy/WulkanowyApp.kt | 40 +++++++++++-------- .../ui/modules/settings/SettingsFragment.kt | 4 ++ .../ui/modules/settings/SettingsPresenter.kt | 19 ++++++--- .../ui/modules/settings/SettingsView.kt | 2 + .../github/wulkanowy/utils/AnalyticsHelper.kt | 2 +- 6 files changed, 45 insertions(+), 24 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 39930a73..af3f4aef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -184,7 +184,7 @@ dependencies { implementation "com.aurelhubert:ahbottomnavigation:2.3.4" implementation "com.ncapdevi:frag-nav:3.3.0" - implementation "com.github.YarikSOffice:lingver:1.2.2" + implementation "com.github.YarikSOffice:lingver:1.3.0" implementation "com.squareup.moshi:moshi:$moshi" implementation "com.squareup.moshi:moshi-adapters:$moshi" diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt index f1c61e82..0e6055aa 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt @@ -5,6 +5,7 @@ import android.content.Context import android.util.Log.DEBUG import android.util.Log.INFO import android.util.Log.VERBOSE +import android.webkit.WebView import androidx.hilt.work.HiltWorkerFactory import androidx.multidex.MultiDex import androidx.work.Configuration @@ -47,22 +48,23 @@ class WulkanowyApp : Application(), Configuration.Provider { override fun onCreate() { super.onCreate() - Lingver.init(this) - themeManager.applyDefaultTheme() + initializeAppLanguage() + themeManager.applyDefaultTheme() initLogging() - logCurrentLanguage() + fixWebViewLocale() } private fun initLogging() { if (appInfo.isDebug) { Timber.plant(DebugLogTree()) - Timber.plant(FileLoggerTree.Builder() - .withFileName("wulkanowy.%g.log") - .withDirName(applicationContext.filesDir.absolutePath) - .withFileLimit(10) - .withMinPriority(DEBUG) - .build() + Timber.plant( + FileLoggerTree.Builder() + .withFileName("wulkanowy.%g.log") + .withDirName(applicationContext.filesDir.absolutePath) + .withFileLimit(10) + .withMinPriority(DEBUG) + .build() ) } else { Timber.plant(CrashLogExceptionTree()) @@ -71,14 +73,20 @@ class WulkanowyApp : Application(), Configuration.Provider { registerActivityLifecycleCallbacks(ActivityLifecycleLogger()) } - private fun logCurrentLanguage() { - val newLang = if (preferencesRepository.appLanguage == "system") { - appInfo.systemLanguage - } else { - preferencesRepository.appLanguage - } + private fun initializeAppLanguage() { + Lingver.init(this) - analyticsHelper.logEvent("language", "startup" to newLang) + if (preferencesRepository.appLanguage == "system") { + Lingver.getInstance().setFollowSystemLocale(this) + analyticsHelper.logEvent("language", "startup" to appInfo.systemLanguage) + } else { + analyticsHelper.logEvent("language", "startup" to preferencesRepository.appLanguage) + } + } + + private fun fixWebViewLocale() { + //https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above + WebView(this).destroy() } override fun getWorkManagerConfiguration() = Configuration.Builder() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt index bda07e34..ad4692b9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt @@ -79,6 +79,10 @@ class SettingsFragment : PreferenceFragmentCompat(), lingver.setLocale(requireContext(), langCode) } + override fun updateLanguageToFollowSystem() { + lingver.setFollowSystemLocale(requireContext()) + } + override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) { findPreference<Preference>(serviceEnablesKey)?.run { summary = if (isHolidays) getString(R.string.pref_services_suspended) else "" diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt index f9ad74a1..e3b2e232 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt @@ -42,14 +42,18 @@ class SettingsPresenter @Inject constructor( when (key) { serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startPeriodicSyncWorker() else stopSyncWorker() } servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startPeriodicSyncWorker(true) - isDebugNotificationEnableKey -> chuckerCollector.showNotification = isDebugNotificationEnable + isDebugNotificationEnableKey -> chuckerCollector.showNotification = + isDebugNotificationEnable appThemeKey -> view?.recreateView() isUpcomingLessonsNotificationsEnableKey -> if (!isUpcomingLessonsNotificationsEnable) timetableNotificationHelper.cancelNotification() appLanguageKey -> view?.run { - val newLang = if (appLanguage == "system") appInfo.systemLanguage else appLanguage - analytics.logEvent("language", "setting_changed" to newLang) - - updateLanguage(newLang) + if (appLanguage == "system") { + updateLanguageToFollowSystem() + analytics.logEvent("language", "setting_changed" to appInfo.systemLanguage) + } else { + updateLanguage(appLanguage) + analytics.logEvent("language", "setting_changed" to appLanguage) + } recreateView() } } @@ -71,7 +75,10 @@ class SettingsPresenter @Inject constructor( analytics.logEvent("sync_now", "status" to "success") } WorkInfo.State.FAILED -> { - showError(syncFailedString, Throwable(workInfo.outputData.getString("error"))) + showError( + syncFailedString, + Throwable(workInfo.outputData.getString("error")) + ) analytics.logEvent("sync_now", "status" to "failed") } else -> Timber.d("Sync now state: ${workInfo.state}") diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt index b647c0b7..80271741 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt @@ -14,6 +14,8 @@ interface SettingsView : BaseView { fun updateLanguage(langCode: String) + fun updateLanguageToFollowSystem() + fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) fun setSyncInProgress(inProgress: Boolean) diff --git a/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt index ba29e1cb..b6532579 100644 --- a/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt +++ b/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt @@ -20,7 +20,7 @@ class AnalyticsHelper @Inject constructor( params.forEach { if (it.second == null) return@forEach when (it.second) { - is String, is String? -> putString(it.first, it.second as String) + is String, is String? -> putString(it.first, it.second.toString()) is Int, is Int? -> putInt(it.first, it.second as Int) is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean) } From 28fd7460cb0da82dd1ecf34381629398eda6455e Mon Sep 17 00:00:00 2001 From: Mateusz Idziejczak <idziejczak3@gmail.com> Date: Mon, 1 Feb 2021 11:45:10 +0100 Subject: [PATCH 22/28] Replace progressBar with CircularProgressIndicator (#1117) --- app/build.gradle | 3 +-- app/src/main/res/layout/activity_send_message.xml | 3 +-- app/src/main/res/layout/dialog_mobile_device.xml | 3 +-- app/src/main/res/layout/fragment_account.xml | 3 +-- app/src/main/res/layout/fragment_attendance.xml | 3 +-- app/src/main/res/layout/fragment_attendance_summary.xml | 3 +-- app/src/main/res/layout/fragment_conference.xml | 3 +-- app/src/main/res/layout/fragment_contributor.xml | 3 +-- app/src/main/res/layout/fragment_exam.xml | 3 +-- app/src/main/res/layout/fragment_grade.xml | 3 +-- app/src/main/res/layout/fragment_grade_details.xml | 3 +-- app/src/main/res/layout/fragment_grade_statistics.xml | 3 +-- app/src/main/res/layout/fragment_grade_summary.xml | 3 +-- app/src/main/res/layout/fragment_homework.xml | 3 +-- app/src/main/res/layout/fragment_license.xml | 3 +-- app/src/main/res/layout/fragment_login_advanced.xml | 3 +-- app/src/main/res/layout/fragment_login_form.xml | 3 +-- app/src/main/res/layout/fragment_login_recover.xml | 3 +-- app/src/main/res/layout/fragment_login_student_select.xml | 3 +-- app/src/main/res/layout/fragment_login_symbol.xml | 3 +-- app/src/main/res/layout/fragment_lucky_number.xml | 3 +-- app/src/main/res/layout/fragment_message.xml | 3 +-- app/src/main/res/layout/fragment_message_preview.xml | 3 +-- app/src/main/res/layout/fragment_message_tab.xml | 3 +-- app/src/main/res/layout/fragment_mobile_device.xml | 3 +-- app/src/main/res/layout/fragment_note.xml | 3 +-- app/src/main/res/layout/fragment_school.xml | 3 +-- app/src/main/res/layout/fragment_schoolandteachers.xml | 3 +-- app/src/main/res/layout/fragment_student_info.xml | 3 +-- app/src/main/res/layout/fragment_teacher.xml | 3 +-- app/src/main/res/layout/fragment_timetable.xml | 3 +-- app/src/main/res/layout/fragment_timetable_additional.xml | 3 +-- app/src/main/res/layout/fragment_timetable_completed.xml | 3 +-- 33 files changed, 33 insertions(+), 66 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index af3f4aef..0d42ad71 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -163,10 +163,9 @@ dependencies { implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.constraintlayout:constraintlayout:2.0.4" implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0" - implementation "com.google.android.material:material:1.2.1" + implementation "com.google.android.material:material:1.3.0-rc01" implementation "com.github.wulkanowy:material-chips-input:2.1.1" implementation "com.github.PhilJay:MPAndroidChart:v3.1.0" - implementation "me.zhanghai.android.materialprogressbar:library:1.6.1" implementation "androidx.work:work-runtime-ktx:$work_manager" playImplementation "androidx.work:work-gcm:$work_manager" diff --git a/app/src/main/res/layout/activity_send_message.xml b/app/src/main/res/layout/activity_send_message.xml index e0ec52bb..10b581f7 100644 --- a/app/src/main/res/layout/activity_send_message.xml +++ b/app/src/main/res/layout/activity_send_message.xml @@ -194,9 +194,8 @@ tools:text="No messages" /> </LinearLayout> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/sendMessageProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" diff --git a/app/src/main/res/layout/dialog_mobile_device.xml b/app/src/main/res/layout/dialog_mobile_device.xml index 7b128605..680f5719 100644 --- a/app/src/main/res/layout/dialog_mobile_device.xml +++ b/app/src/main/res/layout/dialog_mobile_device.xml @@ -86,9 +86,8 @@ android:text="@string/all_close" /> </LinearLayout> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/mobileDeviceDialogProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml index a2cf73cf..306dc219 100644 --- a/app/src/main/res/layout/fragment_account.xml +++ b/app/src/main/res/layout/fragment_account.xml @@ -5,9 +5,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/account_progress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" diff --git a/app/src/main/res/layout/fragment_attendance.xml b/app/src/main/res/layout/fragment_attendance.xml index 39b00d30..8016081b 100644 --- a/app/src/main/res/layout/fragment_attendance.xml +++ b/app/src/main/res/layout/fragment_attendance.xml @@ -10,9 +10,8 @@ android:layout_height="match_parent" android:layout_marginBottom="50dp"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/attendanceProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_attendance_summary.xml b/app/src/main/res/layout/fragment_attendance_summary.xml index da0ce7f2..613ea506 100644 --- a/app/src/main/res/layout/fragment_attendance_summary.xml +++ b/app/src/main/res/layout/fragment_attendance_summary.xml @@ -49,9 +49,8 @@ </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </LinearLayout> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/attendanceSummaryProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_conference.xml b/app/src/main/res/layout/fragment_conference.xml index d7cac878..730b46d5 100644 --- a/app/src/main/res/layout/fragment_conference.xml +++ b/app/src/main/res/layout/fragment_conference.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" tools:context=".ui.modules.conference.ConferenceFragment"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/conferenceProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_contributor.xml b/app/src/main/res/layout/fragment_contributor.xml index d913c5a4..8b71ffed 100644 --- a/app/src/main/res/layout/fragment_contributor.xml +++ b/app/src/main/res/layout/fragment_contributor.xml @@ -4,9 +4,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/creatorProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_exam.xml b/app/src/main/res/layout/fragment_exam.xml index ed4094a5..ca88849c 100644 --- a/app/src/main/res/layout/fragment_exam.xml +++ b/app/src/main/res/layout/fragment_exam.xml @@ -10,9 +10,8 @@ android:layout_height="match_parent" android:layout_marginBottom="50dp"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/examProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_grade.xml b/app/src/main/res/layout/fragment_grade.xml index 0bc864b2..ed0447fb 100644 --- a/app/src/main/res/layout/fragment_grade.xml +++ b/app/src/main/res/layout/fragment_grade.xml @@ -25,9 +25,8 @@ android:visibility="invisible" tools:visibility="visible" /> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/gradeProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_grade_details.xml b/app/src/main/res/layout/fragment_grade_details.xml index a1faefe7..c1b88580 100644 --- a/app/src/main/res/layout/fragment_grade_details.xml +++ b/app/src/main/res/layout/fragment_grade_details.xml @@ -17,9 +17,8 @@ tools:listitem="@layout/item_grade_details" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/gradeDetailsProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_grade_statistics.xml b/app/src/main/res/layout/fragment_grade_statistics.xml index b3fcac44..ca512dac 100644 --- a/app/src/main/res/layout/fragment_grade_statistics.xml +++ b/app/src/main/res/layout/fragment_grade_statistics.xml @@ -95,9 +95,8 @@ android:layout_height="match_parent" tools:listitem="@layout/item_grade_statistics_pie" /> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/gradeStatisticsProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_grade_summary.xml b/app/src/main/res/layout/fragment_grade_summary.xml index 3f21e61c..a3425513 100644 --- a/app/src/main/res/layout/fragment_grade_summary.xml +++ b/app/src/main/res/layout/fragment_grade_summary.xml @@ -17,9 +17,8 @@ tools:listitem="@layout/item_grade_summary" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/gradeSummaryProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_homework.xml b/app/src/main/res/layout/fragment_homework.xml index 26381da6..c0b5698d 100644 --- a/app/src/main/res/layout/fragment_homework.xml +++ b/app/src/main/res/layout/fragment_homework.xml @@ -10,9 +10,8 @@ android:layout_height="match_parent" android:layout_marginBottom="50dp"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/homeworkProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_license.xml b/app/src/main/res/layout/fragment_license.xml index f4105355..5551d4f1 100644 --- a/app/src/main/res/layout/fragment_license.xml +++ b/app/src/main/res/layout/fragment_license.xml @@ -4,9 +4,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/licenseProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_login_advanced.xml b/app/src/main/res/layout/fragment_login_advanced.xml index 65af0b54..c7acaa70 100644 --- a/app/src/main/res/layout/fragment_login_advanced.xml +++ b/app/src/main/res/layout/fragment_login_advanced.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" tools:context=".ui.modules.login.advanced.LoginAdvancedFragment"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/loginFormProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml index d91d7b03..412502b5 100644 --- a/app/src/main/res/layout/fragment_login_form.xml +++ b/app/src/main/res/layout/fragment_login_form.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" tools:context=".ui.modules.login.form.LoginFormFragment"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/loginFormProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_login_recover.xml b/app/src/main/res/layout/fragment_login_recover.xml index 205a4bea..629ed54d 100644 --- a/app/src/main/res/layout/fragment_login_recover.xml +++ b/app/src/main/res/layout/fragment_login_recover.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" tools:context=".ui.modules.login.recover.LoginRecoverFragment"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/loginRecoverProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_login_student_select.xml b/app/src/main/res/layout/fragment_login_student_select.xml index f9c6c157..bf543116 100644 --- a/app/src/main/res/layout/fragment_login_student_select.xml +++ b/app/src/main/res/layout/fragment_login_student_select.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" android:orientation="vertical"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/loginStudentSelectProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_login_symbol.xml b/app/src/main/res/layout/fragment_login_symbol.xml index 77f44d21..f1c9be4a 100644 --- a/app/src/main/res/layout/fragment_login_symbol.xml +++ b/app/src/main/res/layout/fragment_login_symbol.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" tools:context=".ui.modules.login.symbol.LoginSymbolFragment"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/loginSymbolProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_lucky_number.xml b/app/src/main/res/layout/fragment_lucky_number.xml index a6b9b822..f6de01e6 100644 --- a/app/src/main/res/layout/fragment_lucky_number.xml +++ b/app/src/main/res/layout/fragment_lucky_number.xml @@ -5,9 +5,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/luckyNumberProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_message.xml b/app/src/main/res/layout/fragment_message.xml index b4cc0c2f..a61f3738 100644 --- a/app/src/main/res/layout/fragment_message.xml +++ b/app/src/main/res/layout/fragment_message.xml @@ -39,9 +39,8 @@ android:tint="?colorOnSecondary" app:icon="@drawable/ic_menu_message_write" /> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/messageProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_message_preview.xml b/app/src/main/res/layout/fragment_message_preview.xml index 0931990f..4b15cf10 100644 --- a/app/src/main/res/layout/fragment_message_preview.xml +++ b/app/src/main/res/layout/fragment_message_preview.xml @@ -62,9 +62,8 @@ </LinearLayout> </LinearLayout> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/messagePreviewProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_message_tab.xml b/app/src/main/res/layout/fragment_message_tab.xml index e83d913e..4a6948f0 100644 --- a/app/src/main/res/layout/fragment_message_tab.xml +++ b/app/src/main/res/layout/fragment_message_tab.xml @@ -16,9 +16,8 @@ tools:listitem="@layout/item_message" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/messageTabProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_mobile_device.xml b/app/src/main/res/layout/fragment_mobile_device.xml index cf11c283..afe1db8e 100644 --- a/app/src/main/res/layout/fragment_mobile_device.xml +++ b/app/src/main/res/layout/fragment_mobile_device.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" tools:context=".ui.modules.mobiledevice.MobileDeviceFragment"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/mobileDevicesProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_note.xml b/app/src/main/res/layout/fragment_note.xml index e55f0007..f62a11a6 100644 --- a/app/src/main/res/layout/fragment_note.xml +++ b/app/src/main/res/layout/fragment_note.xml @@ -4,9 +4,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/noteProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_school.xml b/app/src/main/res/layout/fragment_school.xml index 23126b08..32be61db 100644 --- a/app/src/main/res/layout/fragment_school.xml +++ b/app/src/main/res/layout/fragment_school.xml @@ -5,9 +5,8 @@ android:layout_height="match_parent" tools:context=".ui.modules.schoolandteachers.school.SchoolFragment"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/schoolProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_schoolandteachers.xml b/app/src/main/res/layout/fragment_schoolandteachers.xml index 6414abb9..f9fec1dd 100644 --- a/app/src/main/res/layout/fragment_schoolandteachers.xml +++ b/app/src/main/res/layout/fragment_schoolandteachers.xml @@ -27,9 +27,8 @@ android:layout_marginTop="48dp" android:visibility="invisible" /> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/schoolandteachersProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_student_info.xml b/app/src/main/res/layout/fragment_student_info.xml index 37145727..7943b2db 100644 --- a/app/src/main/res/layout/fragment_student_info.xml +++ b/app/src/main/res/layout/fragment_student_info.xml @@ -5,9 +5,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/student_info_progress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_teacher.xml b/app/src/main/res/layout/fragment_teacher.xml index 484bf065..ef27d2c4 100644 --- a/app/src/main/res/layout/fragment_teacher.xml +++ b/app/src/main/res/layout/fragment_teacher.xml @@ -4,9 +4,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/teacherProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_timetable.xml b/app/src/main/res/layout/fragment_timetable.xml index 533af2fa..df33b289 100644 --- a/app/src/main/res/layout/fragment_timetable.xml +++ b/app/src/main/res/layout/fragment_timetable.xml @@ -10,9 +10,8 @@ android:layout_height="match_parent" android:layout_marginBottom="50dp"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/timetableProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_timetable_additional.xml b/app/src/main/res/layout/fragment_timetable_additional.xml index d70306c9..61eb4445 100644 --- a/app/src/main/res/layout/fragment_timetable_additional.xml +++ b/app/src/main/res/layout/fragment_timetable_additional.xml @@ -10,9 +10,8 @@ android:layout_height="match_parent" android:layout_marginBottom="50dp"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/additionalLessonsProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/app/src/main/res/layout/fragment_timetable_completed.xml b/app/src/main/res/layout/fragment_timetable_completed.xml index 4934327c..1a890fe1 100644 --- a/app/src/main/res/layout/fragment_timetable_completed.xml +++ b/app/src/main/res/layout/fragment_timetable_completed.xml @@ -10,9 +10,8 @@ android:layout_height="match_parent" android:layout_marginBottom="50dp"> - <me.zhanghai.android.materialprogressbar.MaterialProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@+id/completedLessonsProgress" - style="@style/Widget.MaterialProgressBar.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" From e39b053d2dc1143ab65947053be9499242dc1cf5 Mon Sep 17 00:00:00 2001 From: Dominik Korsa <dominik.korsa@gmail.com> Date: Mon, 1 Feb 2021 13:15:36 +0100 Subject: [PATCH 23/28] Change timetable icon (#1115) --- .../drawable-anydpi-v24/ic_stat_timetable.xml | 19 ++++++++++++++++++ .../res/drawable-hdpi/ic_stat_timetable.png | Bin 0 -> 426 bytes .../res/drawable-mdpi/ic_stat_timetable.png | Bin 0 -> 335 bytes .../res/drawable-xhdpi/ic_stat_timetable.png | Bin 0 -> 519 bytes .../res/drawable-xxhdpi/ic_stat_timetable.png | Bin 0 -> 700 bytes .../drawable-anydpi-v24/ic_stat_timetable.xml | 16 +++++++++++++++ .../res/drawable-hdpi/ic_stat_timetable.png | Bin 312 -> 386 bytes .../res/drawable-mdpi/ic_stat_timetable.png | Bin 275 -> 315 bytes .../res/drawable-xhdpi/ic_stat_timetable.png | Bin 358 -> 499 bytes .../res/drawable-xxhdpi/ic_stat_timetable.png | Bin 459 -> 671 bytes .../main/res/drawable/ic_main_timetable.xml | 2 +- .../ic_menu_timetable_lessons_additional.xml | 2 +- 12 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 app/src/debug/res/drawable-anydpi-v24/ic_stat_timetable.xml create mode 100644 app/src/debug/res/drawable-hdpi/ic_stat_timetable.png create mode 100644 app/src/debug/res/drawable-mdpi/ic_stat_timetable.png create mode 100644 app/src/debug/res/drawable-xhdpi/ic_stat_timetable.png create mode 100644 app/src/debug/res/drawable-xxhdpi/ic_stat_timetable.png create mode 100644 app/src/main/res/drawable-anydpi-v24/ic_stat_timetable.xml diff --git a/app/src/debug/res/drawable-anydpi-v24/ic_stat_timetable.xml b/app/src/debug/res/drawable-anydpi-v24/ic_stat_timetable.xml new file mode 100644 index 00000000..ac99d4a8 --- /dev/null +++ b/app/src/debug/res/drawable-anydpi-v24/ic_stat_timetable.xml @@ -0,0 +1,19 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="#FFFFFF" + android:viewportWidth="24" + android:viewportHeight="24"> + <group + android:scaleX="0.92" + android:scaleY="0.92" + android:translateX="0.96" + android:translateY="0.96"> + <path + android:fillColor="#FFF" + android:pathData="M3.9512,2A2,2 0,0 0,2 4L2,18A2,2 0,0 0,4 20L10.0996,20C11.3596,21.24 13.09,22 15,22A7,7 0,0 0,15.7988 21.9551L15.7988,19.7832A4.85,4.85 0,0 1,15 19.8496C12.32,19.8496 10.1504,17.68 10.1504,15A4.85,4.85 0,0 1,15 10.1504C17.4677,10.1504 19.4978,11.9912 19.8047,14.375C20.566,14.3758 21.3108,14.5325 21.9922,14.834C21.9491,12.9905 21.2036,11.3226 20,10.0996L20,4A2,2 0,0 0,18 2L4,2A2,2 0,0 0,3.9512 2zM4,5L10,5L10,8L4,8L4,5zM12,5L18,5L18,8L12,8L12,5zM4,10L10.0996,10C9.2596,10.82 8.6291,11.85 8.2891,13L4,13L4,10zM14,12L14,15.6895L15.7988,16.7266L15.7988,14.9922L15.5,14.8203L15.5,12L14,12zM4,15L8,15C8,16.07 8.2399,17.09 8.6699,18L4,18L4,15z" /> + <path + android:fillColor="#FFF" + android:pathData="m17.298,24v-8.1249h2.5c0.7143,0 1.3523,0.1618 1.9141,0.4855 0.5655,0.3199 1.0063,0.7775 1.3225,1.3728 0.3162,0.5915 0.4743,1.2649 0.4743,2.0201v0.3739c0,0.7552 -0.1562,1.4267 -0.4687,2.0145 -0.3088,0.5878 -0.7459,1.0435 -1.3114,1.3672C21.1633,23.8326 20.5253,23.9963 19.8148,24ZM18.9721,17.2311v5.4241h0.8091c0.6548,0 1.1551,-0.2139 1.5011,-0.6417 0.346,-0.4278 0.5227,-1.0398 0.5301,-1.8359v-0.4297c0,-0.8259 -0.1711,-1.4509 -0.5134,-1.875 -0.3423,-0.4278 -0.8426,-0.6417 -1.5011,-0.6417z" /> + </group> +</vector> diff --git a/app/src/debug/res/drawable-hdpi/ic_stat_timetable.png b/app/src/debug/res/drawable-hdpi/ic_stat_timetable.png new file mode 100644 index 0000000000000000000000000000000000000000..10b27cee7d8e3a0018f9eed678f9624ad1314c7a GIT binary patch literal 426 zcmV;b0agBqP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ0004TNkl<Zc-rlk z;SItd5QRGeBRB#Z*b&@7HqZ_12;IPr;0AUByMb;{H$a*k$%Pc|z^g{nOWvQRr62I_ z4ytO6H5LeKZR2!ZKxZda0<&aXbAkGWf$U!a)r5wUcZ-3(_3jGvj)zW!?j`T8Y5%RX z-#LxJzn<`Y3l+a}ddx6saZ|(3a9m=2$~`v#>*LPuX&fL}AsmJ=t`4ADNg%wfmk4an zn23@}d+Zs-1)3S(NM~7U6=Fa~^nE7{)D{3K$k2x6BSzZe>}m*~)Dp+nq^Ti=Q!Av< zsk4S>ZE%#Ge7Kha(zu=^#@S3FY;YrsBs1+FnKj6d*};|?bYM#t$zV3I+XHSHBQ;Aj zW)p0!FO<iemcWTIW#Bm=<gI8%V)D|CKds*0X$w*WkT?HL>O!d_-P{IQMga|yw_Jsm zJ{PDXx9m+Y13&3OnlSaq?rFlX9_S3-I-oQ5kbU2mto}g^zIc8b$bf;d>gpHb1x7t0 UUF%U7EdT%j07*qoM6N<$f`#0?BLDyZ literal 0 HcmV?d00001 diff --git a/app/src/debug/res/drawable-mdpi/ic_stat_timetable.png b/app/src/debug/res/drawable-mdpi/ic_stat_timetable.png new file mode 100644 index 0000000000000000000000000000000000000000..db5747b0d5d396a78294aff9769f5af290234af1 GIT binary patch literal 335 zcmV-V0kHmwP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv0003NNkl<Zc-q}n z0S$vd3`7DFkbr}|gqMJW;edBA98ALIU^rk7zyUb;@ymVEG==AXELqm%0%=Q+Z@+Dp z{he5A%LS)MlzW5UZMqDh;D!BM)E0q))40G07-5%eT?|3DVt)r&v6-JDm=-()Ot4F~ zA%@`VMSkL)LX#jfQsQ(qyV`A14ahBV&pdE?6-7Ywvky*miul#OMyWM0f-fb=y<>=A zMk+jJ=(XUhg*jHasSuN*7W$fvl@7&r?+tJkg9ivI=x;0Yi;kF)r;{JgqG=j}3#o(N z_%XwZT}mY5j%I4M2%wWsK|YYsGNK;oiz5i^424d&WOVZs75q}9u2#j0e8u|gX;U7t h!+C>tyLa>v@&an^DdqdT(X{{o002ovPDHLkV1jaYl6C+9 literal 0 HcmV?d00001 diff --git a/app/src/debug/res/drawable-xhdpi/ic_stat_timetable.png b/app/src/debug/res/drawable-xhdpi/ic_stat_timetable.png new file mode 100644 index 0000000000000000000000000000000000000000..8d985829277738537f0b0ef8ecd72d40713bbcdc GIT binary patch literal 519 zcmV+i0{H!jP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm0005bNkl<Zc-rlm zjg5pL5QQnh5-foZ)(*}R?BMJ`JGkvYIygI6JJ1fi4sJW(++;Q(gr6A!H5Xno*~F|e zpUCh4#<H@q{;#Bz<rcRsx`X0l3mz-^W{Y2Wj)oX-{;cHRYC-@idA{x;0R063rVOB{ zBHTNvHxk>;02v?yBm(#ZOM!`5yZ1(jTt+j%RRLP?N0^v>iESa^cX9l0KD-LO445UE z(dP5P`HHB9ZV!OP!9KUBk!^BIk5oqitcK(ZV!MR_VoeSJt2bS>r<Zz1PlPRQc1&as z{hLR8W<6mnjYpSJ9tcqC4?GkAInaAg4$JPr90)K)0;nMm0R<rlK)^Lq=rvp*0cL82 zN>YUk^&i^<lBE(6fKx00KrAW%JmX=Buh*bXJrC$A5pA@@eW)%afC%w08o(2bp2_Up zQvuZ2xc~t$8D{w>shnC8qH4xg4i|vog$k@Ql#w8K1OQI1UJj4GN1bb6`v44uqQF8l z%IXOli>F7v0cZ#Ss8~ulR%S-ev;&}IsRf1LCkBA-PLDokYhX<r0?<d<t%v~g-nnSi z6`N-s;M#Fl!>%R`U{y{n2QB%LT~SCcG*UMSt^zP#^0UbT{Q;!e2T9p$Of&!h002ov JPDHLkV1hGH(31cF literal 0 HcmV?d00001 diff --git a/app/src/debug/res/drawable-xxhdpi/ic_stat_timetable.png b/app/src/debug/res/drawable-xxhdpi/ic_stat_timetable.png new file mode 100644 index 0000000000000000000000000000000000000000..232108e8769d0ba8b9ea4b0f62a6d53955fe7324 GIT binary patch literal 700 zcmV;t0z>_YP)<h;3K|Lk000e1NJLTq002k;002k`1^@s6RqeA!0007mNkl<Zc-rlo z?Qw%J42BsYBV+_Ns5eMP$Od79utB>)*r03>Z$LH(8^8t>-znD~7aM=bs!jCX>1VKb zkY(9&ih{*ru~;k?i?yn0ns&1tX1gSA=h;eXILFzBDKCAik4gn6S9KKAYMAm?&C&B; zQKaZ^0MNvM7*KwIWT5qw&m{-+ZqH>v42S_SAO^&M7!U*EN}2&NAO^&M@&Hr^nj~hl z%VwEZEg8#m?)z-js}>HNm8;|6X139$!;u9b%O-$|F5&ph+5%La1EAZ=OPm6py|<XU z$7BJimp3>*x<t*&IE`VPN6LU62FC@m-%X4tjRt5XdQOf$NXxvWJNF(^1k~vgvWE}S za!e6D7a8iH4+lGhOf6qP@Y_~1Zj(bLefRXi1(1k3%_0M;VgrKTkI@!}$bd>BKy8+Q z0(@`<Bmk0x?Tb?cZyu1Q;;vBYAp;=cVAz0gzJ4loP$WS0mH_Eik-fw5h%^C$X=AL% zQU)Y3s#!Sy={10CbEVo3UTi-O6`(K7Y8HH|5EhejDu8qsK?kg((16wUn#yK1>M5Vb z&&Ki`yiNg76Eli5ehN*|IHFb6hS0q@+SL$69TlKItKw3v@4yvNTjojy$Pm$cpMgul z-j(;CPdoq#wCdcj8;+sQCm(nK+My+Dc-Wn|6MA#0eq8}+R@N3H5mJL1Ai+PAz1lXM zmoJY5NEWFGqB3Oa)|&=|PyxROpck7^5<sx~U+Sw!S<qbUi2xm=c3dOpCYx(5p@1Yx zp_l-$5{kOz1uXAXOw$H$i!IAxvs!6xmh9gV(6fH}gu-)(e%m86K+egY0sX4SzLT^C iKqFM|r-H>|rJx`3<*bMohB1f$0000<MNUMnLSTYPAT+1| literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-anydpi-v24/ic_stat_timetable.xml b/app/src/main/res/drawable-anydpi-v24/ic_stat_timetable.xml new file mode 100644 index 00000000..9efc0348 --- /dev/null +++ b/app/src/main/res/drawable-anydpi-v24/ic_stat_timetable.xml @@ -0,0 +1,16 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="#FFFFFF" + android:viewportWidth="24" + android:viewportHeight="24"> + <group + android:scaleX="0.92" + android:scaleY="0.92" + android:translateX="0.96" + android:translateY="0.96"> + <path + android:fillColor="#FFF" + android:pathData="M14,12H15.5V14.82L17.94,16.23L17.19,17.53L14,15.69V12M4,2H18A2,2 0 0,1 20,4V10.1C21.24,11.36 22,13.09 22,15A7,7 0 0,1 15,22C13.09,22 11.36,21.24 10.1,20H4A2,2 0 0,1 2,18V4A2,2 0 0,1 4,2M4,15V18H8.67C8.24,17.09 8,16.07 8,15H4M4,8H10V5H4V8M18,8V5H12V8H18M4,13H8.29C8.63,11.85 9.26,10.82 10.1,10H4V13M15,10.15A4.85,4.85 0 0,0 10.15,15C10.15,17.68 12.32,19.85 15,19.85A4.85,4.85 0 0,0 19.85,15C19.85,12.32 17.68,10.15 15,10.15Z" /> + </group> +</vector> diff --git a/app/src/main/res/drawable-hdpi/ic_stat_timetable.png b/app/src/main/res/drawable-hdpi/ic_stat_timetable.png index 201419d5d48501c657d592ea41c27763c5e6eb7f..21095e296c90fbbfa5f40b29c7ed6c09036f30e1 100644 GIT binary patch delta 360 zcmV-u0hj)`0)hjOBYy!&Nkl<Zc-rlkiw%Py5QZJW5gdUH$_Q>yHfT4f8`KTz2yUPo z)D3h4-GD-JCWP=fDb%FlPcA0b!pCtBD2lAC1mc`G!iEI)5>|%5q||T}XiN;m{|bnD zYzp}{80f5TGtf6N^zhgm@@-E0v(mm6wrX>2@c$MnzI-kQCVvt=sKw8nHc4;mQ{p`X z*j+Qar(uA=L#h~JT%tj>F@e-=?Jck)Vj*R$v{z%M!~z+{XR)))<%Q7^PrJI<Ky3gJ zbuB0)?bYmRJQK=OVigSt;c}CQO2eu1xyPD#-dzg{0U~NWag0+zZIYTS^{bAR_6s&s zV2g-hF}RAY#bJ=`_Mo<m6*Dkw<!q~8M_K|#5{i1N^xIXxd@Bj<_|kh<VHdC)+{JX! zR2NEO>E<?V$zU{(wg{O1@U1lh7=sub!5TO>ks>SWNBRI5XS84U*13@Y0000<MNUMn GLSTZLqND== delta 286 zcmV+(0pb3F1GoZ^BYyz@Nkl<Zc-rllF$%&k6oy;$5cL8sF2O<QR-8OW@1O_hRUABm z4m$K6YU$Xqi%?K7{()EMBJ_nsOVS^{!QuUU!%Nc|1Y^ehC{juR5(RTEA%tn6TvC{G zZF0ASP%r^Yumu??JLMUJHYNSuffbl?h1TE>p3-bypiuo>p?{0Cn=@CapuwthQcO@$ zZ^0F6ccwIaIP`jlEMzP02sQLjG)3dw4h>g`Zv0FGVM{30T;S9jp-A((i2PXUA)d0n zJCt}UwCQ<02tRk|-$FMUtTnHTZ`9O#<q93Z+tRy`>fLjN7T^RPhGkUW5zM(lA((;K k@K;Anz2W$ei5C<305App0gj+)B>(^b07*qoM6N<$f*+KFGXMYp diff --git a/app/src/main/res/drawable-mdpi/ic_stat_timetable.png b/app/src/main/res/drawable-mdpi/ic_stat_timetable.png index dcfe95f26582f0cb2cee7b00e660fd2f50f7523e..9147c409006bd9a9975b2e249a1eee49c7500ca1 100644 GIT binary patch delta 289 zcmV++0p9+T0=oi`BYyz`Nkl<Zc-q}n3k`!n3`GJGCIJVlgp+^-9DswJlg$A*00-az z9Nf62O`1y!cMy_=OJ3O8(pUPsEW6!t&OKH<6H&xE|G494jEVg0fh__+qiIDWU_!m5 z>rx0hMgMc6=$gMGm{+s{X4Ff%F@@mrA`keR!!Rccro_vtpntXPp&GC*@y}e)o87O_ z2$*~!=S&7dq1&T1Xarjbd^oMs!bm%Y1?5JtEdw8enx>5uS(I17TA{kU{eP5GFnJ0= zNsfefN?akHu%K0=rHBmt(9{esRtK}ug+olMP7%XY3xV}CLos&(D6j!h&(;SGXmR$o n1C|QM*1NspY8nNxTW)v0+2+|+_@sfX00000NkvXXu0mjfEC+%# delta 248 zcmV<U00;lO0+RxeBYyzeNkl<Zc-muN7`EX5|No*utPR9`c+~Jg)rgW~LBoFt2*sl& z6so3y6oVyzH~@%OK{fY54Z?=|plVh@^+*yEEXRTP?|;$(NY4qp!3C7Gg(^G+4I)zT zDX3msd=@xBT{D%8IGYO9>p+YJcc9@)3cf>%1(X1yELa9j-*KeiWu#a@^EjA_rU@UI zN{IzEKzx+|t|8k3dIXUXjv~UH)^Tu^S{8WWC>FA)VgW7UzzT?eQBYKX^jhJwfFFq0 yLKTt<Kzdf=s{vt_@Bpy}8ASz156|#xJOBX9>$>$se^_(?0000<MNUMnLSTYB;%T-3 diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_timetable.png b/app/src/main/res/drawable-xhdpi/ic_stat_timetable.png index 7264bd92a947d264f2b576b17645a1346557cf53..96942b5a3ddf02c66f67b17bc0283c871aa9234f 100644 GIT binary patch delta 473 zcmV;~0Ve+D0`miqB!9X|L_t(|+U;43je{@@WdufG1U4ue93y0dV}r86b%V0Ou|e4& zYycbdHsFHfN>S>NF9F^8Nmi>W5WmE+pVKTO5D0%4%d!;0F2b&f>_b=?%Xud3xg3Lg zjFmsi`4?CSfoeG(w-5sD2?z{CKtkp4>>xkrI4=<(0z_aZ0)L+%DQt`@&t4pi(kKx) zD}e^|k&SVaW5PQ495=@C<XLDHU>aw7oz4g4dy6XQd<bY1?2oY8a?Vn-BXueQ6XJaC zIB$-Sn06-s-J5aclwE2!b|S2~@hD^uHRdhCtaX^bPn|}~KmvvO!lVQ&4|;3xVf58w zp#+9V1p1f+I)C^LvrZjrNq}!Th13SNOBO=%|KM0F?pV52WqIfhRE7d%EdhXp8sF<3 zRHKZ0CLw?{A}b1uIT|Q-Z)XC_LQX}|gFxq_VW9G^u|CTVBJn@$U5RVkTHvXvoGWo1 zLC<qfEu?Cy*=H5XNKFa1-3eIvDT*4^#B~U+x`Pb|_EIbQ1+SzsU)__fjfNfh28SPp zEBx-re|Bz%U9CqXQA2uk!R#ILI}%}tFvA*smYp5a%>|Rb=NW-O_`moCm}zszR72dr P00000NkvXXu0mjfdwkOF delta 331 zcmV-R0kr<}1LgvdB!4YQL_t(|+U=P!4go<Jg*8N?Z~+&PtuzuhKx?^!sJ5^wiBq_P zZ73BEK})%<XeqGXBvWiA8h$&IUGF7dqxj!^lgzNIRALzB|B@uhFhxf&r<0y#Qy`s4 zFege6qCg=9Ft-K<U<p=cDH7|?z9BX@LwBgI5vc!S@l$XFSAXzKvXAPxffJaiHAn>d z;9zOt??m>XClLts&bx~04kZE$W1wf@g7A#a1qF&E5EwrrvLMJ(z(pufD1qFc0bZjN z_?5t$B1t?7{G&ia@FZr^;31|!4zJN~&Ong&?}3N{6yPmHfscmG!NcJbnd+WP1Sa6( z@Ok(Q#u9-x*hGQ5gT<@PEoeyus`?G}M(>8L*Xycl4Z5HrJyaFY)FQrxGvMnk)mi3W dsti-`yZ|%rS?@H2>6HKg002ovPDHLkV1lvQmRbM+ diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_timetable.png b/app/src/main/res/drawable-xxhdpi/ic_stat_timetable.png index 1fb37b092c4c26e76a349ab679d42edf8797c551..510da8d5257b165a84300089e9b4b3050bee4a95 100644 GIT binary patch delta 648 zcmV;30(bq(1D^$uBYy&BNkl<Zc-rlo?QMfF5QZ6n5g36D!Ukc3vO(COY|w5HHYgi} z4Z;Rt1G0gOB}b|v@CTePcKW{3{Xy~v4`=)A!$|@`5ClOG1Q{iSNM}3F_8GXHX3M$Z zl(S7DF8#=l$^|D@T{(u;B;r;B?|GFMN&0U9NB|H3#RsV0X@4VUz3hPgTfG1TKmY_l z00ck)1VD(S0SJHq2!P@M)a<mLnNb?eGA~mymgn5VZ1qwKXMUEc<KT9-yG@283P6@g z0O?(YW1Wo!s3rzL7sE?bJK+z8`paMe$(Pr3{O;m4hIU#_JGYPl-83C9i2L37@KSGp z4Bk^Y_MzW7+<$Ils~RDo>)M38p%1-fn}zqeND~Jg9PGGfXl(_g%C5y*Z48n0u(1y= zfY!WdiUCmV8;~l$79ZuI1In2Iwcb`vpMZAsp(lEW27q1&sBkc9KtgR<GRyKMJ0Qn8 zd;ogr%M|pz#Dj=dk<_w$Za6=Zrvs-AfT~ac^%T*p8h<LI?pM2|VW(-o2nEnLWi+cf z`x&3TQtipsl!XGQ)C`SuW52S6_@;E&Bo7IN2sf)<PWjX-*{?1Anj@AvG(au27d?BF z<LZ}t1ti?>Pn>m=tB0fFT+?1h*-*`tmN^r{nY>QUmS2KeyDy(uz-bc??%FXzx^9h6 z)KJ!G^na2-v`nW^OYXG}mVNs$Bm^E=6Tf%J)P&6qYEl#YW3vByq3_~QPnpCd_2oH+ z?map<j3<_(;J%va36g0Ox<#$vxQ@vTsv-c@k;XZJ&P^`AwP=5nd3&kAuUPm2t5VOi i1cD$4f*=SY*DqJQQJ2+w9RL6T002ovPDHLkU;%=U1uIbi delta 434 zcmV;j0Zsm&1<M1FBYy#sNkl<Zc-rloze>YU7)JxzNwAaR;_Rx6uGz!~aPQ!xn`5Vl zk07{qa1}+U4qdYA3-|}A?jp9Jf*r2E3wP28mGXsq={a!bd_8G$Zy?Ds00000m>B0= zE{mTU9<Qh{k2#PZ@E3;1tD+zffe1vPsSTt7=H#+GmACTU#ea*R?M|M{71^|oGcPw~ zM?T3nIf^)tpKTzY<%!(#zrixlnmm+4mmb3~`>JK219{`p<=XTf6|Ut$!h!tkXO@9_ z75AL}A6xzy>{r~AdX|C8inCHiyzQuWUIGz_Km>{~P-+l}Km;PtR0T@uQG;ckeGq{N zL?8l<alo3l1b-!g2t*(P5$Jz`S~WgWv{>fZ2N8%s1R_wh%X~o~0uhKn1d8`jBWIas zA4DJm5r{w&AMi?kCj8>UhwNGgI+l+K2fCL>mVtJ|zi5<ToG*DHcPs<>&!G0@Yl4AZ z!U<lm3^Xg3<c7SI58=9w`JUrv?8<eyC}*r!hK6j)Z7aDa+Y!G&)ebZIS^c+ejSK() c0073~8@jaK?WG8(v;Y7A07*qoM6N<$g3{E<D*ylh diff --git a/app/src/main/res/drawable/ic_main_timetable.xml b/app/src/main/res/drawable/ic_main_timetable.xml index b8f5cb85..e33aae16 100644 --- a/app/src/main/res/drawable/ic_main_timetable.xml +++ b/app/src/main/res/drawable/ic_main_timetable.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> <path android:fillColor="#FFF" - android:pathData="M19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,9h14v10zM5,7L5,5h14v2L5,7zM7,11h10v2L7,13zM7,15h7v2L7,17z" /> + android:pathData="M14,12H15.5V14.82L17.94,16.23L17.19,17.53L14,15.69V12M4,2H18A2,2 0 0,1 20,4V10.1C21.24,11.36 22,13.09 22,15A7,7 0 0,1 15,22C13.09,22 11.36,21.24 10.1,20H4A2,2 0 0,1 2,18V4A2,2 0 0,1 4,2M4,15V18H8.67C8.24,17.09 8,16.07 8,15H4M4,8H10V5H4V8M18,8V5H12V8H18M4,13H8.29C8.63,11.85 9.26,10.82 10.1,10H4V13M15,10.15A4.85,4.85 0 0,0 10.15,15C10.15,17.68 12.32,19.85 15,19.85A4.85,4.85 0 0,0 19.85,15C19.85,12.32 17.68,10.15 15,10.15Z" /> </vector> diff --git a/app/src/main/res/drawable/ic_menu_timetable_lessons_additional.xml b/app/src/main/res/drawable/ic_menu_timetable_lessons_additional.xml index 169395e9..ddb6d2f5 100644 --- a/app/src/main/res/drawable/ic_menu_timetable_lessons_additional.xml +++ b/app/src/main/res/drawable/ic_menu_timetable_lessons_additional.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> <path android:fillColor="#FFF" - android:pathData="M19,19V8H5V19H19M16,1H18V3H19C20.11,3 21,3.9 21,5V19C21,20.11 20.11,21 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1M11,9.5H13V12.5H16V14.5H13V17.5H11V14.5H8V12.5H11V9.5Z" /> + android:pathData="M6,1L6,3L5,3C3.89,3 3,3.89 3,5v14c0,1.1 0.89,2 2,2h14c1.11,0 2,-0.89 2,-2L21,5C21,3.9 20.11,3 19,3L18,3L18,1L16,1L16,3L8,3L8,1ZM5,5L19,5L19,7L5,7ZM5,9L19,9L19,19L5,19ZM11,10v3L8,13v2h3v3h2v-3h3v-2h-3v-3z" /> </vector> From 39534aeda409e48f392f2a36904f0914d7f138d9 Mon Sep 17 00:00:00 2001 From: Mateusz Idziejczak <idziejczak3@gmail.com> Date: Mon, 1 Feb 2021 18:13:11 +0100 Subject: [PATCH 24/28] Add dark mode to swipe refresh layout (#1118) --- .../wulkanowy/ui/modules/attendance/AttendanceFragment.kt | 3 +++ .../modules/attendance/summary/AttendanceSummaryFragment.kt | 3 +++ .../wulkanowy/ui/modules/conference/ConferenceFragment.kt | 5 ++++- .../java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt | 3 +++ .../ui/modules/grade/details/GradeDetailsFragment.kt | 5 ++++- .../ui/modules/grade/statistics/GradeStatisticsFragment.kt | 3 +++ .../ui/modules/grade/summary/GradeSummaryFragment.kt | 5 ++++- .../github/wulkanowy/ui/modules/homework/HomeworkFragment.kt | 3 +++ .../wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt | 5 ++++- .../wulkanowy/ui/modules/message/tab/MessageTabFragment.kt | 5 ++++- .../ui/modules/mobiledevice/MobileDeviceFragment.kt | 5 ++++- .../java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt | 5 ++++- .../ui/modules/schoolandteachers/school/SchoolFragment.kt | 5 ++++- .../ui/modules/schoolandteachers/teacher/TeacherFragment.kt | 5 ++++- .../wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt | 5 ++++- .../wulkanowy/ui/modules/timetable/TimetableFragment.kt | 3 +++ .../timetable/additional/AdditionalLessonsFragment.kt | 3 +++ .../modules/timetable/completed/CompletedLessonsFragment.kt | 3 +++ app/src/main/res/values-night/styles.xml | 1 + app/src/main/res/values/attrs.xml | 1 + app/src/main/res/values/colors.xml | 3 +++ app/src/main/res/values/styles.xml | 1 + 22 files changed, 70 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt index 3bef3dc6..00d5aae8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt @@ -26,6 +26,7 @@ import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.widgets.DividerItemDecoration import io.github.wulkanowy.utils.SchooldaysRangeLimiter import io.github.wulkanowy.utils.dpToPx +import io.github.wulkanowy.utils.getThemeAttrColor import java.time.LocalDate import javax.inject.Inject @@ -112,6 +113,8 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag with(binding) { attendanceSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + attendanceSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + attendanceSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) attendanceErrorRetry.setOnClickListener { presenter.onRetry() } attendanceErrorDetails.setOnClickListener { presenter.onDetailsClick() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt index 6b971f26..118971e6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt @@ -15,6 +15,7 @@ import io.github.wulkanowy.databinding.FragmentAttendanceSummaryBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.dpToPx +import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.setOnItemSelectedListener import javax.inject.Inject @@ -56,6 +57,8 @@ class AttendanceSummaryFragment : with(binding) { attendanceSummarySwipe.setOnRefreshListener(presenter::onSwipeRefresh) + attendanceSummarySwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + attendanceSummarySwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) attendanceSummaryErrorRetry.setOnClickListener { presenter.onRetry() } attendanceSummaryErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceFragment.kt index 6173c15b..dd10a65e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceFragment.kt @@ -10,6 +10,7 @@ import io.github.wulkanowy.databinding.FragmentConferenceBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.widgets.DividerItemDecoration +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -47,7 +48,9 @@ class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.frag } with(binding) { - conferenceSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + conferenceSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + conferenceSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + conferenceSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) conferenceErrorRetry.setOnClickListener { presenter.onRetry() } conferenceErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt index 9cc1aeda..0940b0bd 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt @@ -15,6 +15,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.widgets.DividerItemDecoration import io.github.wulkanowy.utils.dpToPx +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -55,6 +56,8 @@ class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam), with(binding) { examSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + examSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + examSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) examErrorRetry.setOnClickListener { presenter.onRetry() } examErrorDetails.setOnClickListener { presenter.onDetailsClick() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt index ef9a932e..9d4da767 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt @@ -17,6 +17,7 @@ import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView import io.github.wulkanowy.ui.modules.main.MainActivity +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -65,7 +66,9 @@ class GradeDetailsFragment : layoutManager = LinearLayoutManager(context) adapter = gradeDetailsAdapter } - gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + gradeDetailsSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + gradeDetailsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + gradeDetailsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) gradeDetailsErrorRetry.setOnClickListener { presenter.onRetry() } gradeDetailsErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt index 75050249..1ce7a202 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt @@ -13,6 +13,7 @@ import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView import io.github.wulkanowy.utils.dpToPx +import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.setOnItemSelectedListener import javax.inject.Inject @@ -69,6 +70,8 @@ class GradeStatisticsFragment : gradeStatisticsSubjectsContainer.setElevationCompat(requireContext().dpToPx(1f)) gradeStatisticsSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + gradeStatisticsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + gradeStatisticsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) gradeStatisticsErrorRetry.setOnClickListener { presenter.onRetry() } gradeStatisticsErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt index 4d12dcd5..0ac16fb3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt @@ -13,6 +13,7 @@ import io.github.wulkanowy.databinding.FragmentGradeSummaryBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -52,7 +53,9 @@ class GradeSummaryFragment : adapter = gradeSummaryAdapter } with(binding) { - gradeSummarySwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + gradeSummarySwipe.setOnRefreshListener(presenter::onSwipeRefresh) + gradeSummarySwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + gradeSummarySwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) gradeSummaryErrorRetry.setOnClickListener { presenter.onRetry() } gradeSummaryErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt index 85173e91..1d9434dc 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt @@ -15,6 +15,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.widgets.DividerItemDecoration import io.github.wulkanowy.utils.dpToPx +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -55,6 +56,8 @@ class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment with(binding) { homeworkSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + homeworkSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + homeworkSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) homeworkErrorRetry.setOnClickListener { presenter.onRetry() } homeworkErrorDetails.setOnClickListener { presenter.onDetailsClick() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt index 0f1d836d..3de23585 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt @@ -10,6 +10,7 @@ import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.databinding.FragmentLuckyNumberBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainView +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -38,7 +39,9 @@ class LuckyNumberFragment : override fun initView() { with(binding) { - luckyNumberSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + luckyNumberSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + luckyNumberSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + luckyNumberSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) luckyNumberErrorRetry.setOnClickListener { presenter.onRetry() } luckyNumberErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt index 48a2cee2..f08059f2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt @@ -19,6 +19,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.message.MessageFragment import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment import io.github.wulkanowy.ui.widgets.DividerItemDecoration +import io.github.wulkanowy.utils.getThemeAttrColor import kotlinx.coroutines.FlowPreview import javax.inject.Inject @@ -74,7 +75,9 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag addItemDecoration(DividerItemDecoration(context)) } with(binding) { - messageTabSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + messageTabSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + messageTabSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + messageTabSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) messageTabErrorRetry.setOnClickListener { presenter.onRetry() } messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt index 48737d7b..f8e367c5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt @@ -16,6 +16,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.mobiledevice.token.MobileDeviceTokenDialog import io.github.wulkanowy.ui.widgets.DividerItemDecoration +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -56,7 +57,9 @@ class MobileDeviceFragment : } with(binding) { - mobileDevicesSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + mobileDevicesSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + mobileDevicesSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + mobileDevicesSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) mobileDevicesErrorRetry.setOnClickListener { presenter.onRetry() } mobileDevicesErrorDetails.setOnClickListener { presenter.onDetailsClick() } mobileDeviceAddButton.setOnClickListener { presenter.onRegisterDevice() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt index 40378265..dd622344 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt @@ -13,6 +13,7 @@ import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.widgets.DividerItemDecoration +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -50,7 +51,9 @@ class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note), addItemDecoration(DividerItemDecoration(context)) } with(binding) { - noteSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + noteSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + noteSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + noteSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) noteErrorRetry.setOnClickListener { presenter.onRetry() } noteErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt index d3f11007..03ad7ba0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt @@ -12,6 +12,7 @@ import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersChildView import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment +import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.openDialer import io.github.wulkanowy.utils.openNavigation import javax.inject.Inject @@ -39,7 +40,9 @@ class SchoolFragment : BaseFragment<FragmentSchoolBinding>(R.layout.fragment_sch override fun initView() { with(binding) { - schoolSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + schoolSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + schoolSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + schoolSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) schoolErrorRetry.setOnClickListener { presenter.onRetry() } schoolErrorDetails.setOnClickListener { presenter.onDetailsClick() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt index 5914945b..b052a383 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt @@ -14,6 +14,7 @@ import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersChildView import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment import io.github.wulkanowy.ui.widgets.DividerItemDecoration +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -51,7 +52,9 @@ class TeacherFragment : BaseFragment<FragmentTeacherBinding>(R.layout.fragment_t addItemDecoration(DividerItemDecoration(context)) } with(binding) { - teacherSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + teacherSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + teacherSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + teacherSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) teacherErrorRetry.setOnClickListener { presenter.onRetry() } teacherErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt index 0075d558..fb7f8d28 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt @@ -22,6 +22,7 @@ import io.github.wulkanowy.databinding.FragmentStudentInfoBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView +import io.github.wulkanowy.utils.getThemeAttrColor import javax.inject.Inject @AndroidEntryPoint @@ -72,7 +73,9 @@ class StudentInfoFragment : override fun initView() { with(binding) { - studentInfoSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + studentInfoSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + studentInfoSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + studentInfoSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) studentInfoErrorRetry.setOnClickListener { presenter.onRetry() } studentInfoErrorDetails.setOnClickListener { presenter.onDetailsClick() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt index 21585cc9..91f09ccc 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt @@ -21,6 +21,7 @@ import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragme import io.github.wulkanowy.ui.widgets.DividerItemDecoration import io.github.wulkanowy.utils.SchooldaysRangeLimiter import io.github.wulkanowy.utils.dpToPx +import io.github.wulkanowy.utils.getThemeAttrColor import java.time.LocalDate import javax.inject.Inject @@ -69,6 +70,8 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme with(binding) { timetableSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + timetableSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + timetableSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) timetableErrorRetry.setOnClickListener { presenter.onRetry() } timetableErrorDetails.setOnClickListener { presenter.onDetailsClick() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt index 559366a9..18551faa 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt @@ -13,6 +13,7 @@ import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.widgets.DividerItemDecoration import io.github.wulkanowy.utils.SchooldaysRangeLimiter import io.github.wulkanowy.utils.dpToPx +import io.github.wulkanowy.utils.getThemeAttrColor import java.time.LocalDate import javax.inject.Inject @@ -53,6 +54,8 @@ class AdditionalLessonsFragment : with(binding) { additionalLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + additionalLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + additionalLessonsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) additionalLessonsErrorRetry.setOnClickListener { presenter.onRetry() } additionalLessonsPreviousButton.setOnClickListener { presenter.onPreviousDay() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt index f8634a9b..b6041b8a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt @@ -18,6 +18,7 @@ import io.github.wulkanowy.ui.widgets.DividerItemDecoration import io.github.wulkanowy.utils.SchooldaysRangeLimiter import io.github.wulkanowy.utils.dpToPx import io.github.wulkanowy.utils.getCompatDrawable +import io.github.wulkanowy.utils.getThemeAttrColor import java.time.LocalDate import javax.inject.Inject @@ -60,6 +61,8 @@ class CompletedLessonsFragment : with(binding) { completedLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh) + completedLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary)) + completedLessonsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)) completedLessonErrorRetry.setOnClickListener { presenter.onRetry() } completedLessonErrorDetails.setOnClickListener { presenter.onDetailsClick() } diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml index 32f7cdf1..bf5cd769 100644 --- a/app/src/main/res/values-night/styles.xml +++ b/app/src/main/res/values-night/styles.xml @@ -7,6 +7,7 @@ <item name="colorTimetableChange">@color/timetable_change_light</item> <item name="colorError">@color/colorErrorLight</item> <item name="colorDivider">@color/colorDividerInverse</item> + <item name="colorSwipeRefresh">@color/colorSwipeRefreshDark</item> <item name="android:windowBackground">?colorSurface</item> <item name="android:textColor">?android:textColorPrimary</item> <item name="android:navigationBarColor" tools:targetApi="lollipop">@android:color/black diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 49cdd5b7..49ef39ab 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <attr name="colorDivider" format="color" /> + <attr name="colorSwipeRefresh" format="color" /> <attr name="colorTimetableChange" format="color" /> </resources> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 36dee181..99456744 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -12,6 +12,9 @@ <color name="colorDivider">#1f000000</color> <color name="colorDividerInverse">#1fffffff</color> + <color name="colorSwipeRefreshDark">#ff383838</color> + <color name="colorSwipeRefresh">#ffffffff</color> + <color name="note_positive">#a0c431</color> <color name="note_negative">#d43f3f</color> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 788f081e..cf587cbf 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -10,6 +10,7 @@ <item name="colorTimetableChange">@color/timetable_change_dark</item> <item name="colorError">@color/colorError</item> <item name="colorDivider">@color/colorDivider</item> + <item name="colorSwipeRefresh">@color/colorSwipeRefresh</item> <item name="android:textColor">?android:textColorPrimary</item> <item name="android:preferenceStyle">@style/PreferenceThemeOverlay</item> </style> From 3e3a080b701a93e19886d32c202a6c53d0753007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= <RafalBO99@outlook.com> Date: Mon, 1 Feb 2021 23:58:44 +0100 Subject: [PATCH 25/28] Add nick for student (#1119) --- .../31.json | 2 +- .../32.json | 2142 +++++++++++++++++ .../github/wulkanowy/data/db/AppDatabase.kt | 6 +- .../wulkanowy/data/db/dao/StudentDao.kt | 5 + .../wulkanowy/data/db/entities/Student.kt | 2 + .../wulkanowy/data/db/entities/StudentNick.kt | 16 + .../data/db/migrations/Migration32.kt | 12 + .../data/repositories/StudentRepository.kt | 76 +- .../TimetableNotificationSchedulerHelper.kt | 67 +- .../ui/base/WidgetConfigureAdapter.kt | 3 +- .../ui/modules/account/AccountAdapter.kt | 3 +- .../ui/modules/account/AccountPresenter.kt | 10 +- .../accountdetails/AccountDetailsFragment.kt | 49 +- .../accountdetails/AccountDetailsPresenter.kt | 82 +- .../accountdetails/AccountDetailsView.kt | 15 +- .../AccountEditDetailsDialog.kt | 38 - .../account/accountedit/AccountEditDialog.kt | 72 + .../accountedit/AccountEditPresenter.kt | 54 + .../account/accountedit/AccountEditView.kt | 14 + .../accountquick/AccountQuickPresenter.kt | 6 +- .../studentinfo/StudentInfoFragment.kt | 1 + .../TimetableWidgetProvider.kt | 11 +- .../wulkanowy/utils/StudentExtension.kt | 5 + ...it_details.xml => dialog_account_edit.xml} | 13 +- app/src/main/res/layout/fragment_account.xml | 2 +- .../res/layout/fragment_account_details.xml | 455 ++-- .../main/res/layout/fragment_login_form.xml | 2 - app/src/main/res/values/strings.xml | 7 + 28 files changed, 2857 insertions(+), 313 deletions(-) create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/32.json create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/StudentNick.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration32.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditView.kt create mode 100644 app/src/main/java/io/github/wulkanowy/utils/StudentExtension.kt rename app/src/main/res/layout/{dialog_account_edit_details.xml => dialog_account_edit.xml} (90%) diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json index 55a51e04..4935a901 100644 --- a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json @@ -2133,4 +2133,4 @@ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd642512ffa5fe81ae9308c9c55612539')" ] } -} \ No newline at end of file +} diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/32.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/32.json new file mode 100644 index 00000000..3621be48 --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/32.json @@ -0,0 +1,2142 @@ +{ + "formatVersion": 1, + "database": { + "version": 32, + "identityHash": "9531cdc8b3f0e62db5ab6ebe66837a28", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "nick", + "columnName": "nick", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "scrapperBaseUrl", + "columnName": "scrapper_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mobileBaseUrl", + "columnName": "mobile_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "login_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginMode", + "columnName": "login_mode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "certificateKey", + "columnName": "certificate_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "privateKey", + "columnName": "private_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isParent", + "columnName": "is_parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "user_login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userName", + "columnName": "user_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolShortName", + "columnName": "school_short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "current", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isStudentPlan", + "columnName": "student_plan", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timeId", + "columnName": "time_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excused", + "columnName": "excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excusable", + "columnName": "excusable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excuseStatus", + "columnName": "excuse_status", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPredictedGradeNotified", + "columnName": "is_predicted_grade_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isFinalGradeNotified", + "columnName": "is_final_grade_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "predictedGradeLastChange", + "columnName": "predicted_grade_last_change", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "finalGradeLastChange", + "columnName": "final_grade_last_change", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradePartialStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classAverage", + "columnName": "class_average", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentAverage", + "columnName": "student_average", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classAmounts", + "columnName": "class_amounts", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentAmounts", + "columnName": "student_amounts", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesPointsStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "others", + "columnName": "others", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "student", + "columnName": "student", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradeSemesterStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amounts", + "columnName": "amounts", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentGrade", + "columnName": "student_grade", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `content` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasAttachments", + "columnName": "has_attachments", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MessageAttachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))", + "fields": [ + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "oneDriveId", + "columnName": "one_drive_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filename", + "columnName": "filename", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "real_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "categoryType", + "columnName": "category_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPointsShow", + "columnName": "is_points_show", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDone", + "columnName": "is_done", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attachments", + "columnName": "attachments", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MobileDevices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "device_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "School", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contact", + "columnName": "contact", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "headmaster", + "columnName": "headmaster", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pedagogue", + "columnName": "pedagogue", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Conferences", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "agenda", + "columnName": "agenda", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presentOnConference", + "columnName": "present_on_conference", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "conferenceId", + "columnName": "conference_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "TimetableAdditional", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "StudentInfo", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `first_guardian_full_name` TEXT NOT NULL, `first_guardian_kinship` TEXT NOT NULL, `first_guardian_address` TEXT NOT NULL, `first_guardian_phones` TEXT NOT NULL, `first_guardian_email` TEXT NOT NULL, `second_guardian_full_name` TEXT NOT NULL, `second_guardian_kinship` TEXT NOT NULL, `second_guardian_address` TEXT NOT NULL, `second_guardian_phones` TEXT NOT NULL, `second_guardian_email` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "full_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "first_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondName", + "columnName": "second_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "surname", + "columnName": "surname", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "birthDate", + "columnName": "birth_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "birthPlace", + "columnName": "birth_place", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gender", + "columnName": "gender", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasPolishCitizenship", + "columnName": "has_polish_citizenship", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "familyName", + "columnName": "family_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentsNames", + "columnName": "parents_names", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "registeredAddress", + "columnName": "registered_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "correspondenceAddress", + "columnName": "correspondence_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phoneNumber", + "columnName": "phone_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cellPhoneNumber", + "columnName": "cell_phone_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.fullName", + "columnName": "first_guardian_full_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.kinship", + "columnName": "first_guardian_kinship", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.address", + "columnName": "first_guardian_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.phones", + "columnName": "first_guardian_phones", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstGuardian.email", + "columnName": "first_guardian_email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.fullName", + "columnName": "second_guardian_full_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.kinship", + "columnName": "second_guardian_kinship", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.address", + "columnName": "second_guardian_address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.phones", + "columnName": "second_guardian_phones", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "secondGuardian.email", + "columnName": "second_guardian_email", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9531cdc8b3f0e62db5ab6ebe66837a28')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index d1f99e3e..806f0c9d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -83,6 +83,7 @@ import io.github.wulkanowy.data.db.migrations.Migration29 import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration30 import io.github.wulkanowy.data.db.migrations.Migration31 +import io.github.wulkanowy.data.db.migrations.Migration32 import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration5 import io.github.wulkanowy.data.db.migrations.Migration6 @@ -128,7 +129,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 31 + const val VERSION_SCHEMA = 32 fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> { return arrayOf( @@ -161,7 +162,8 @@ abstract class AppDatabase : RoomDatabase() { Migration28(), Migration29(), Migration30(), - Migration31() + Migration31(), + Migration32() ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt index d7237ea8..e9c5f157 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt @@ -6,7 +6,9 @@ import androidx.room.Insert import androidx.room.OnConflictStrategy.ABORT import androidx.room.Query import androidx.room.Transaction +import androidx.room.Update import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.StudentNick import io.github.wulkanowy.data.db.entities.StudentWithSemesters import javax.inject.Singleton @@ -20,6 +22,9 @@ interface StudentDao { @Delete suspend fun delete(student: Student) + @Update(entity = Student::class) + suspend fun update(studentNick: StudentNick) + @Query("SELECT * FROM Students WHERE is_current = 1") suspend fun loadCurrent(): Student? diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt index 0b37b1e9..6b60c814 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt @@ -79,4 +79,6 @@ data class Student( @PrimaryKey(autoGenerate = true) var id: Long = 0 + + var nick = "" } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/StudentNick.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/StudentNick.kt new file mode 100644 index 00000000..71f48f7a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/StudentNick.kt @@ -0,0 +1,16 @@ +package io.github.wulkanowy.data.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey +import java.io.Serializable + +@Entity +data class StudentNick( + + val nick: String + +) : Serializable { + + @PrimaryKey + var id: Long = 0 +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration32.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration32.kt new file mode 100644 index 00000000..508485e0 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration32.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration32 : Migration(31, 32) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE Students ADD COLUMN nick TEXT NOT NULL DEFAULT \"\"") + } +} + diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt index 5b80035b..55821479 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt @@ -5,6 +5,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.StudentDao import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.StudentNick import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.exceptions.NoCurrentStudentException import io.github.wulkanowy.data.mappers.mapToEntities @@ -25,49 +26,70 @@ class StudentRepository @Inject constructor( private val sdk: Sdk ) { - suspend fun isStudentSaved(): Boolean = getSavedStudents(false).isNotEmpty() + suspend fun isStudentSaved() = getSavedStudents(false).isNotEmpty() - suspend fun isCurrentStudentSet(): Boolean = studentDb.loadCurrent()?.isCurrent ?: false + suspend fun isCurrentStudentSet() = studentDb.loadCurrent()?.isCurrent ?: false - suspend fun getStudentsApi(pin: String, symbol: String, token: String): List<StudentWithSemesters> { - return sdk.getStudentsFromMobileApi(token, pin, symbol, "").mapToEntities() - } + suspend fun getStudentsApi( + pin: String, + symbol: String, + token: String + ): List<StudentWithSemesters> = + sdk.getStudentsFromMobileApi(token, pin, symbol, "").mapToEntities() - suspend fun getStudentsScrapper(email: String, password: String, scrapperBaseUrl: String, symbol: String): List<StudentWithSemesters> { - return sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol).mapToEntities(password) - } + suspend fun getStudentsScrapper( + email: String, + password: String, + scrapperBaseUrl: String, + symbol: String + ): List<StudentWithSemesters> = + sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol) + .mapToEntities(password) - suspend fun getStudentsHybrid(email: String, password: String, scrapperBaseUrl: String, symbol: String): List<StudentWithSemesters> { - return sdk.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol).mapToEntities(password) - } + suspend fun getStudentsHybrid( + email: String, + password: String, + scrapperBaseUrl: String, + symbol: String + ): List<StudentWithSemesters> = + sdk.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol).mapToEntities(password) - suspend fun getSavedStudents(decryptPass: Boolean = true) = withContext(dispatchers.backgroundThread) { - studentDb.loadStudentsWithSemesters().map { - it.apply { - if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) student.password = decrypt(student.password) + suspend fun getSavedStudents(decryptPass: Boolean = true) = + withContext(dispatchers.backgroundThread) { + studentDb.loadStudentsWithSemesters().map { + it.apply { + if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) { + student.password = decrypt(student.password) + } + } } } - } suspend fun getStudentById(id: Int) = withContext(dispatchers.backgroundThread) { studentDb.loadById(id)?.apply { - if (Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password) + if (Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) { + password = decrypt(password) + } } } ?: throw NoCurrentStudentException() - suspend fun getCurrentStudent(decryptPass: Boolean = true) = withContext(dispatchers.backgroundThread) { - studentDb.loadCurrent()?.apply { - if (decryptPass && Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password) - } - } ?: throw NoCurrentStudentException() + suspend fun getCurrentStudent(decryptPass: Boolean = true) = + withContext(dispatchers.backgroundThread) { + studentDb.loadCurrent()?.apply { + if (decryptPass && Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) { + password = decrypt(password) + } + } + } ?: throw NoCurrentStudentException() suspend fun saveStudents(studentsWithSemesters: List<StudentWithSemesters>): List<Long> { semesterDb.insertSemesters(studentsWithSemesters.flatMap { it.semesters }) return withContext(dispatchers.backgroundThread) { studentDb.insertAll(studentsWithSemesters.map { it.student }.map { - if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.API) it.copy(password = encrypt(it.password, context)) - else it + if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.API) { + it.copy(password = encrypt(it.password, context)) + } else it }) } } @@ -79,7 +101,7 @@ class StudentRepository @Inject constructor( } } - suspend fun logoutStudent(student: Student) { - studentDb.delete(student) - } + suspend fun logoutStudent(student: Student) = studentDb.delete(student) + + suspend fun updateStudentNick(studentNick: StudentNick) = studentDb.update(studentNick) } diff --git a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt index c0eba2f9..c5a5590b 100644 --- a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt +++ b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt @@ -27,6 +27,7 @@ import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companio import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.STUDENT_NAME import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.DispatchersProvider +import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.toTimestamp import kotlinx.coroutines.withContext import timber.log.Timber @@ -41,17 +42,23 @@ class TimetableNotificationSchedulerHelper @Inject constructor( private val dispatchersProvider: DispatchersProvider, ) { - private fun getRequestCode(time: LocalDateTime, studentId: Int) = (time.toTimestamp() * studentId).toInt() + private fun getRequestCode(time: LocalDateTime, studentId: Int) = + (time.toTimestamp() * studentId).toInt() - private fun getUpcomingLessonTime(index: Int, day: List<Timetable>, lesson: Timetable): LocalDateTime { - return day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30) - } + private fun getUpcomingLessonTime( + index: Int, + day: List<Timetable>, + lesson: Timetable + ) = day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30) suspend fun cancelScheduled(lessons: List<Timetable>, studentId: Int = 1) { withContext(dispatchersProvider.backgroundThread) { lessons.sortedBy { it.start }.forEachIndexed { index, lesson -> val upcomingTime = getUpcomingLessonTime(index, lessons, lesson) - cancelScheduledTo(upcomingTime..lesson.start, getRequestCode(upcomingTime, studentId)) + cancelScheduledTo( + upcomingTime..lesson.start, + getRequestCode(upcomingTime, studentId) + ) cancelScheduledTo(lesson.start..lesson.end, getRequestCode(lesson.start, studentId)) Timber.d("TimetableNotification canceled: type 1 & 2, subject: ${lesson.subject}, start: ${lesson.start}, student: $studentId") @@ -61,13 +68,18 @@ class TimetableNotificationSchedulerHelper @Inject constructor( private fun cancelScheduledTo(range: ClosedRange<LocalDateTime>, requestCode: Int) { if (now() in range) cancelNotification() - alarmManager.cancel(PendingIntent.getBroadcast(context, requestCode, Intent(), FLAG_UPDATE_CURRENT)) + alarmManager.cancel( + PendingIntent.getBroadcast(context, requestCode, Intent(), FLAG_UPDATE_CURRENT) + ) } - fun cancelNotification() = NotificationManagerCompat.from(context).cancel(MainView.Section.TIMETABLE.id) + fun cancelNotification() = + NotificationManagerCompat.from(context).cancel(MainView.Section.TIMETABLE.id) suspend fun scheduleNotifications(lessons: List<Timetable>, student: Student) { - if (!preferencesRepository.isUpcomingLessonsNotificationsEnable) return cancelScheduled(lessons, student.studentId) + if (!preferencesRepository.isUpcomingLessonsNotificationsEnable) { + return cancelScheduled(lessons, student.studentId) + } withContext(dispatchersProvider.backgroundThread) { lessons.groupBy { it.date } @@ -82,13 +94,28 @@ class TimetableNotificationSchedulerHelper @Inject constructor( val intent = createIntent(student, lesson, active.getOrNull(index + 1)) if (lesson.start > now()) { - scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_UPCOMING, getUpcomingLessonTime(index, active, lesson)) + scheduleBroadcast( + intent, + student.studentId, + NOTIFICATION_TYPE_UPCOMING, + getUpcomingLessonTime(index, active, lesson) + ) } if (lesson.end > now()) { - scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_CURRENT, lesson.start) + scheduleBroadcast( + intent, + student.studentId, + NOTIFICATION_TYPE_CURRENT, + lesson.start + ) if (active.lastIndex == index) { - scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION, lesson.end) + scheduleBroadcast( + intent, + student.studentId, + NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION, + lesson.end + ) } } } @@ -99,7 +126,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor( private fun createIntent(student: Student, lesson: Timetable, nextLesson: Timetable?): Intent { return Intent(context, TimetableNotificationReceiver::class.java).apply { putExtra(STUDENT_ID, student.studentId) - putExtra(STUDENT_NAME, student.studentName) + putExtra(STUDENT_NAME, student.nickOrName) putExtra(LESSON_ROOM, lesson.room) putExtra(LESSON_START, lesson.start.toTimestamp()) putExtra(LESSON_END, lesson.end.toTimestamp()) @@ -109,13 +136,23 @@ class TimetableNotificationSchedulerHelper @Inject constructor( } } - private fun scheduleBroadcast(intent: Intent, studentId: Int, notificationType: Int, time: LocalDateTime) { - AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, RTC_WAKEUP, time.toTimestamp(), + private fun scheduleBroadcast( + intent: Intent, + studentId: Int, + notificationType: Int, + time: LocalDateTime + ) { + AlarmManagerCompat.setExactAndAllowWhileIdle( + alarmManager, RTC_WAKEUP, time.toTimestamp(), PendingIntent.getBroadcast(context, getRequestCode(time, studentId), intent.also { it.putExtra(NOTIFICATION_ID, MainView.Section.TIMETABLE.id) it.putExtra(LESSON_TYPE, notificationType) }, FLAG_UPDATE_CURRENT) ) - Timber.d("TimetableNotification scheduled: type: $notificationType, subject: ${intent.getStringExtra(LESSON_TITLE)}, start: $time, student: $studentId") + Timber.d( + "TimetableNotification scheduled: type: $notificationType, subject: ${ + intent.getStringExtra(LESSON_TITLE) + }, start: $time, student: $studentId" + ) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/WidgetConfigureAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/WidgetConfigureAdapter.kt index cefe6ed7..8e6130fb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/WidgetConfigureAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/WidgetConfigureAdapter.kt @@ -9,6 +9,7 @@ import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.databinding.ItemAccountBinding import io.github.wulkanowy.utils.getThemeAttrColor +import io.github.wulkanowy.utils.nickOrName import javax.inject.Inject class WidgetConfigureAdapter @Inject constructor() : RecyclerView.Adapter<WidgetConfigureAdapter.ItemViewHolder>() { @@ -28,7 +29,7 @@ class WidgetConfigureAdapter @Inject constructor() : RecyclerView.Adapter<Widget val (student, isCurrent) = items[position] with(holder.binding) { - accountItemName.text = "${student.studentName} ${student.className}" + accountItemName.text = "${student.nickOrName} ${student.className}" accountItemSchool.text = student.schoolName with(accountItemImage) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt index 4aa17073..342fd2d4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountAdapter.kt @@ -12,6 +12,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.HeaderAccountBinding import io.github.wulkanowy.databinding.ItemAccountBinding import io.github.wulkanowy.utils.getThemeAttrColor +import io.github.wulkanowy.utils.nickOrName import javax.inject.Inject class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() { @@ -84,7 +85,7 @@ class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.V }.size > 1 && isAccountQuickDialogMode with(binding) { - accountItemName.text = "${student.studentName} ${diary?.diaryName.orEmpty()}" + accountItemName.text = "${student.nickOrName} ${diary?.diaryName.orEmpty()}" accountItemSchool.text = studentWithSemesters.student.schoolName accountItemAccountType.setText(if (student.isParent) R.string.account_type_parent else R.string.account_type_student) accountItemAccountType.visibility = if (isDuplicatedStudent) VISIBLE else GONE diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt index 349561f8..366793b6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt @@ -62,10 +62,16 @@ class AccountPresenter @Inject constructor( } private fun loadData() { - flowWithResource { studentRepository.getSavedStudents() } + flowWithResource { studentRepository.getSavedStudents(false) } .onEach { when (it.status) { - Status.LOADING -> Timber.i("Loading account data started") + Status.LOADING -> { + Timber.i("Loading account data started") + view?.run { + showProgress(true) + showContent(false) + } + } Status.SUCCESS -> { Timber.i("Loading account result: Success") view?.updateData(createAccountItems(it.data!!)) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt index bdd4946a..f4b2c833 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt @@ -9,13 +9,16 @@ import androidx.appcompat.app.AlertDialog import androidx.core.view.get import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.FragmentAccountDetailsBinding import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.modules.account.accountedit.AccountEditDialog import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView +import io.github.wulkanowy.utils.nickOrName import javax.inject.Inject @AndroidEntryPoint @@ -43,22 +46,19 @@ class AccountDetailsFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) - arguments?.let { - presenter.studentWithSemesters = - it.getSerializable(ARGUMENT_KEY) as StudentWithSemesters - } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding = FragmentAccountDetailsBinding.bind(view) - presenter.onAttachView(this) + presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as StudentWithSemesters) } override fun initView() { + binding.accountDetailsErrorRetry.setOnClickListener { presenter.onRetry() } + binding.accountDetailsErrorDetails.setOnClickListener { presenter.onDetailsClick() } binding.accountDetailsLogout.setOnClickListener { presenter.onRemoveSelected() } binding.accountDetailsSelect.setOnClickListener { presenter.onStudentSelect() } - binding.accountDetailsSelect.isEnabled = !presenter.studentWithSemesters.student.isCurrent binding.accountDetailsPersonalData.setOnClickListener { presenter.onStudentInfoSelected(StudentInfoView.Type.PERSONAL) @@ -76,24 +76,31 @@ class AccountDetailsFragment : override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { menu[0].isVisible = false + inflater.inflate(R.menu.action_menu_account_details, menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean { return if (item.itemId == R.id.accountDetailsMenuEdit) { - showAccountEditDetailsDialog() - return true + presenter.onAccountEditSelected() + true } else false } - override fun showAccountData(studentWithSemesters: StudentWithSemesters) { + override fun showAccountData(student: Student) { with(binding) { - accountDetailsName.text = studentWithSemesters.student.studentName - accountDetailsSchool.text = studentWithSemesters.student.schoolName + accountDetailsName.text = student.nickOrName + accountDetailsSchool.text = student.schoolName } } - override fun showAccountEditDetailsDialog() { - (requireActivity() as MainActivity).showDialogFragment(AccountEditDetailsDialog.newInstance()) + override fun enableSelectStudentButton(enable: Boolean) { + binding.accountDetailsSelect.isEnabled = enable + } + + override fun showAccountEditDetailsDialog(student: Student) { + (requireActivity() as MainActivity).showDialogFragment( + AccountEditDialog.newInstance(student) + ) } override fun showLogoutConfirmDialog() { @@ -127,6 +134,22 @@ class AccountDetailsFragment : ) } + override fun showErrorView(show: Boolean) { + binding.accountDetailsError.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun setErrorDetails(message: String) { + binding.accountDetailsErrorMessage.text = message + } + + override fun showProgress(show: Boolean) { + binding.accountDetailsProgress.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun showContent(show: Boolean) { + binding.accountDetailsContent.visibility = if (show) View.VISIBLE else View.GONE + } + override fun onDestroyView() { presenter.onDetachView() super.onDestroyView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt index da437429..7b93d3d8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt @@ -1,5 +1,6 @@ package io.github.wulkanowy.ui.modules.account.accountdetails +import io.github.wulkanowy.data.Resource import io.github.wulkanowy.data.Status import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.repositories.StudentRepository @@ -9,6 +10,7 @@ import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView import io.github.wulkanowy.utils.afterLoading import io.github.wulkanowy.utils.flowWithResource +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import timber.log.Timber import javax.inject.Inject @@ -19,14 +21,74 @@ class AccountDetailsPresenter @Inject constructor( private val syncManager: SyncManager ) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) { - lateinit var studentWithSemesters: StudentWithSemesters + private lateinit var studentWithSemesters: StudentWithSemesters - override fun onAttachView(view: AccountDetailsView) { + private lateinit var lastError: Throwable + + private var studentId: Long? = null + + fun onAttachView(view: AccountDetailsView, studentWithSemesters: StudentWithSemesters) { super.onAttachView(view) - view.initView() - Timber.i("Account details view was initialized") + studentId = studentWithSemesters.student.id - view.showAccountData(studentWithSemesters) + view.initView() + errorHandler.showErrorMessage = ::showErrorViewOnError + Timber.i("Account details view was initialized") + loadData() + } + + fun onRetry() { + view?.run { + showErrorView(false) + showProgress(true) + } + loadData() + } + + fun onDetailsClick() { + view?.showErrorDetailsDialog(lastError) + } + + private fun loadData() { + flowWithResource { studentRepository.getSavedStudents() } + .map { studentWithSemesters -> + Resource( + data = studentWithSemesters.data?.single { it.student.id == studentId }, + status = studentWithSemesters.status, + error = studentWithSemesters.error + ) + } + .onEach { + when (it.status) { + Status.LOADING -> { + view?.run { + showProgress(true) + showContent(false) + } + Timber.i("Loading account details view started") + } + Status.SUCCESS -> { + Timber.i("Loading account details view result: Success") + studentWithSemesters = it.data!! + view?.run { + showAccountData(studentWithSemesters.student) + enableSelectStudentButton(!studentWithSemesters.student.isCurrent) + showContent(true) + showErrorView(false) + } + } + Status.ERROR -> { + Timber.i("Loading account details view result: An exception occurred") + errorHandler.dispatch(it.error!!) + } + } + } + .afterLoading { view?.showProgress(false) } + .launch() + } + + fun onAccountEditSelected() { + view?.showAccountEditDetailsDialog(studentWithSemesters.student) } fun onStudentInfoSelected(infoType: StudentInfoView.Type) { @@ -97,4 +159,14 @@ class AccountDetailsPresenter @Inject constructor( view?.popView() }.launch("logout") } + + private fun showErrorViewOnError(message: String, error: Throwable) { + view?.run { + lastError = error + setErrorDetails(message) + showErrorView(true) + showContent(false) + showProgress(false) + } + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt index f1001fd7..652f0c1a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsView.kt @@ -1,5 +1,6 @@ package io.github.wulkanowy.ui.modules.account.accountdetails +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView @@ -8,9 +9,9 @@ interface AccountDetailsView : BaseView { fun initView() - fun showAccountData(studentWithSemesters: StudentWithSemesters) + fun showAccountData(student: Student) - fun showAccountEditDetailsDialog() + fun showAccountEditDetailsDialog(student: Student) fun showLogoutConfirmDialog() @@ -18,8 +19,18 @@ interface AccountDetailsView : BaseView { fun recreateMainView() + fun enableSelectStudentButton(enable: Boolean) + fun openStudentInfoView( infoType: StudentInfoView.Type, studentWithSemesters: StudentWithSemesters ) + + fun showErrorView(show: Boolean) + + fun setErrorDetails(message: String) + + fun showProgress(show: Boolean) + + fun showContent(show: Boolean) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt deleted file mode 100644 index be0af7df..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountEditDetailsDialog.kt +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.wulkanowy.ui.modules.account.accountdetails - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.DialogFragment -import io.github.wulkanowy.databinding.DialogAccountEditDetailsBinding -import io.github.wulkanowy.utils.lifecycleAwareVariable - -class AccountEditDetailsDialog : DialogFragment() { - - private var binding: DialogAccountEditDetailsBinding by lifecycleAwareVariable() - - companion object { - - fun newInstance() = AccountEditDetailsDialog() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setStyle(STYLE_NO_TITLE, 0) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return DialogAccountEditDetailsBinding.inflate(inflater).apply { binding = this }.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - binding.accountEditDetailsCancel.setOnClickListener { dismiss() } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt new file mode 100644 index 00000000..89f23e29 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt @@ -0,0 +1,72 @@ +package io.github.wulkanowy.ui.modules.account.accountedit + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.databinding.DialogAccountEditBinding +import io.github.wulkanowy.ui.base.BaseDialogFragment +import javax.inject.Inject + +@AndroidEntryPoint +class AccountEditDialog : BaseDialogFragment<DialogAccountEditBinding>(), AccountEditView { + + @Inject + lateinit var presenter: AccountEditPresenter + + companion object { + + private const val ARGUMENT_KEY = "student_with_semesters" + + fun newInstance(student: Student) = + AccountEditDialog().apply { + arguments = Bundle().apply { + putSerializable(ARGUMENT_KEY, student) + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, 0) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View = DialogAccountEditBinding.inflate(inflater).apply { binding = this }.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as Student) + } + + override fun initView() { + with(binding) { + accountEditDetailsCancel.setOnClickListener { dismiss() } + accountEditDetailsSave.setOnClickListener { + presenter.changeStudentNick(binding.accountEditDetailsNickText.text.toString()) + } + } + } + + override fun showCurrentNick(nick: String) { + binding.accountEditDetailsNickText.setText(nick) + } + + override fun popView() { + dismiss() + } + + override fun recreateMainView() { + activity?.recreate() + } + + override fun onDestroyView() { + super.onDestroyView() + presenter.onDetachView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditPresenter.kt new file mode 100644 index 00000000..7830605c --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditPresenter.kt @@ -0,0 +1,54 @@ +package io.github.wulkanowy.ui.modules.account.accountedit + +import io.github.wulkanowy.data.Status +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.StudentNick +import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.utils.afterLoading +import io.github.wulkanowy.utils.flowWithResource +import kotlinx.coroutines.flow.onEach +import timber.log.Timber +import javax.inject.Inject + +class AccountEditPresenter @Inject constructor( + errorHandler: ErrorHandler, + studentRepository: StudentRepository +) : BasePresenter<AccountEditView>(errorHandler, studentRepository) { + + lateinit var student: Student + + fun onAttachView(view: AccountEditView, student: Student) { + super.onAttachView(view) + this.student = student + + with(view) { + initView() + showCurrentNick(student.nick.trim()) + } + Timber.i("Account edit dialog view was initialized") + } + + fun changeStudentNick(nick: String) { + flowWithResource { + val studentNick = + StudentNick(nick = nick.trim()).apply { id = student.id } + studentRepository.updateStudentNick(studentNick) + }.onEach { + when (it.status) { + Status.LOADING -> Timber.i("Attempt to change a student nick") + Status.SUCCESS -> { + Timber.i("Change a student nick result: Success") + view?.recreateMainView() + } + Status.ERROR -> { + Timber.i("Change a student result: An exception occurred") + errorHandler.dispatch(it.error!!) + } + } + } + .afterLoading { view?.popView() } + .launch() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditView.kt new file mode 100644 index 00000000..b25eec6c --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditView.kt @@ -0,0 +1,14 @@ +package io.github.wulkanowy.ui.modules.account.accountedit + +import io.github.wulkanowy.ui.base.BaseView + +interface AccountEditView : BaseView { + + fun initView() + + fun popView() + + fun recreateMainView() + + fun showCurrentNick(nick: String) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt index 87b14c53..43cc8bc7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt @@ -52,9 +52,9 @@ class AccountQuickPresenter @Inject constructor( errorHandler.dispatch(it.error!!) } } - }.afterLoading { - view?.popView() - }.launch("switch") + } + .afterLoading { view?.popView() } + .launch("switch") } private fun loadData() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt index fb7f8d28..767d31a4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt @@ -109,6 +109,7 @@ class StudentInfoFragment : listOf( getString(R.string.student_info_first_name) to studentInfo.firstName, getString(R.string.student_info_second_name) to studentInfo.secondName, + getString(R.string.student_info_last_name) to studentInfo.surname, getString(R.string.student_info_gender) to getString(if (studentInfo.gender == Gender.MALE) R.string.student_info_male else R.string.student_info_female), getString(R.string.student_info_polish_citizenship) to getString(if (studentInfo.hasPolishCitizenship) R.string.all_yes else R.string.all_no), getString(R.string.student_info_family_name) to studentInfo.familyName, diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt index 938be98d..1d63f094 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt @@ -27,6 +27,7 @@ import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.nextOrSameSchoolDay import io.github.wulkanowy.utils.nextSchoolDay +import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.previousSchoolDay import io.github.wulkanowy.utils.toFormattedString import kotlinx.coroutines.GlobalScope @@ -151,8 +152,14 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() { val remoteView = RemoteViews(context.packageName, layoutId).apply { setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty) - setTextViewText(R.id.timetableWidgetDate, date.toFormattedString("EEEE, dd.MM").capitalize()) - setTextViewText(R.id.timetableWidgetName, student?.studentName ?: context.getString(R.string.all_no_data)) + setTextViewText( + R.id.timetableWidgetDate, + date.toFormattedString("EEEE, dd.MM").capitalize() + ) + setTextViewText( + R.id.timetableWidgetName, + student?.nickOrName ?: context.getString(R.string.all_no_data) + ) setRemoteAdapter(R.id.timetableWidgetList, adapterIntent) setOnClickPendingIntent(R.id.timetableWidgetNext, nextNavIntent) setOnClickPendingIntent(R.id.timetableWidgetPrev, prevNavIntent) diff --git a/app/src/main/java/io/github/wulkanowy/utils/StudentExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/StudentExtension.kt new file mode 100644 index 00000000..fdd0610a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/StudentExtension.kt @@ -0,0 +1,5 @@ +package io.github.wulkanowy.utils + +import io.github.wulkanowy.data.db.entities.Student + +inline val Student.nickOrName get() = if (nick.isBlank()) studentName else nick diff --git a/app/src/main/res/layout/dialog_account_edit_details.xml b/app/src/main/res/layout/dialog_account_edit.xml similarity index 90% rename from app/src/main/res/layout/dialog_account_edit_details.xml rename to app/src/main/res/layout/dialog_account_edit.xml index 0b13e042..b65f85ac 100644 --- a/app/src/main/res/layout/dialog_account_edit_details.xml +++ b/app/src/main/res/layout/dialog_account_edit.xml @@ -18,7 +18,7 @@ android:layout_marginStart="24dp" android:layout_marginTop="24dp" android:layout_marginEnd="24dp" - android:text="Modify data" + android:text="@string/account_edit_header" android:textSize="21sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" @@ -34,16 +34,21 @@ android:layout_marginStart="24dp" android:layout_marginTop="28dp" android:layout_marginEnd="24dp" - android:hint="Nick" + android:hint="@string/account_edit_nick_hint" + app:endIconMode="clear_text" app:errorEnabled="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/accountEditDetailsHeader"> + <requestFocus /> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/accountEditDetailsNickText" android:layout_width="match_parent" android:layout_height="match_parent" - android:inputType="textPersonName" /> + android:inputType="textPersonName" + android:maxLength="20" /> </com.google.android.material.textfield.TextInputLayout> <com.google.android.material.button.MaterialButton @@ -58,7 +63,7 @@ android:insetTop="0dp" android:insetRight="0dp" android:insetBottom="0dp" - android:text="Save" + android:text="@string/all_save" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/accountEditDetailsNick" /> diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml index 306dc219..5d3d81e2 100644 --- a/app/src/main/res/layout/fragment_account.xml +++ b/app/src/main/res/layout/fragment_account.xml @@ -45,7 +45,7 @@ android:orientation="vertical" android:visibility="invisible" tools:ignore="UseCompoundDrawables" - tools:visibility="visible"> + tools:visibility="gone"> <ImageView android:layout_width="100dp" diff --git a/app/src/main/res/layout/fragment_account_details.xml b/app/src/main/res/layout/fragment_account_details.xml index f0e1bd9b..1a0de147 100644 --- a/app/src/main/res/layout/fragment_account_details.xml +++ b/app/src/main/res/layout/fragment_account_details.xml @@ -5,202 +5,269 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <ScrollView - android:layout_width="match_parent" - android:layout_height="0dp" - android:fillViewport="true" - app:layout_constraintBottom_toTopOf="@id/accountDetailsSelect" - app:layout_constraintTop_toTopOf="parent"> - - <androidx.constraintlayout.widget.ConstraintLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <ImageView - android:id="@+id/accountDetailsAvatar" - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_marginTop="36dp" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:srcCompat="@drawable/ic_all_account" - app:tint="?colorPrimary" - tools:ignore="ContentDescription" /> - - <TextView - android:id="@+id/accountDetailsName" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:textSize="24sp" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/accountDetailsAvatar" - tools:text="Jan Kowalski" /> - - <TextView - android:id="@+id/accountDetailsSchool" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="5dp" - android:textColor="?android:textColorSecondary" - android:textSize="14sp" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/accountDetailsName" - tools:text="Szkoła FakeLog" /> - - <LinearLayout - android:id="@+id/accountDetailsPersonalData" - android:layout_width="match_parent" - android:layout_height="56dp" - android:layout_marginTop="16dp" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" - android:orientation="horizontal" - app:layout_constraintTop_toBottomOf="@id/accountDetailsSchool" - tools:ignore="UseCompoundDrawables"> - - <ImageView - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginStart="16dp" - android:layout_marginTop="16dp" - app:srcCompat="@drawable/ic_all_account" - app:tint="?colorOnBackground" - tools:ignore="ContentDescription" /> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginStart="32dp" - android:layout_marginEnd="16dp" - android:gravity="center_vertical" - android:text="@string/account_personal_data" - android:textSize="16sp" /> - </LinearLayout> - - <LinearLayout - android:id="@+id/accountDetailsAddressData" - android:layout_width="match_parent" - android:layout_height="56dp" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" - android:orientation="horizontal" - app:layout_constraintTop_toBottomOf="@id/accountDetailsPersonalData" - tools:ignore="UseCompoundDrawables"> - - <ImageView - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginStart="16dp" - android:layout_marginTop="16dp" - app:srcCompat="@drawable/ic_all_home" - app:tint="?colorOnBackground" - tools:ignore="ContentDescription" /> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginStart="32dp" - android:layout_marginEnd="16dp" - android:gravity="center_vertical" - android:text="@string/account_address" - android:textSize="16sp" /> - </LinearLayout> - - <LinearLayout - android:id="@+id/accountDetailsContactData" - android:layout_width="match_parent" - android:layout_height="56dp" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" - android:orientation="horizontal" - app:layout_constraintTop_toBottomOf="@id/accountDetailsAddressData" - tools:ignore="UseCompoundDrawables"> - - <ImageView - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginStart="16dp" - android:layout_marginTop="16dp" - app:srcCompat="@drawable/ic_all_phone" - app:tint="?colorOnBackground" - tools:ignore="ContentDescription" /> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginStart="32dp" - android:layout_marginEnd="16dp" - android:gravity="center_vertical" - android:text="@string/account_contact" - android:textSize="16sp" /> - </LinearLayout> - - <LinearLayout - android:id="@+id/accountDetailsFamilyData" - android:layout_width="match_parent" - android:layout_height="56dp" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" - android:orientation="horizontal" - app:layout_constraintTop_toBottomOf="@id/accountDetailsContactData" - tools:ignore="UseCompoundDrawables"> - - <ImageView - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginStart="16dp" - android:layout_marginTop="16dp" - app:srcCompat="@drawable/ic_account_details_family" - app:tint="?colorOnBackground" - tools:ignore="ContentDescription" /> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginStart="32dp" - android:layout_marginEnd="16dp" - android:gravity="center_vertical" - android:text="@string/account_family" - android:textSize="16sp" /> - </LinearLayout> - </androidx.constraintlayout.widget.ConstraintLayout> - </ScrollView> - - <com.google.android.material.button.MaterialButton - android:id="@+id/accountDetailsSelect" - android:layout_width="match_parent" + <com.google.android.material.progressindicator.CircularProgressIndicator + android:id="@+id/account_details_progress" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_margin="10dp" - android:insetLeft="0dp" - android:insetTop="0dp" - android:insetRight="0dp" - android:insetBottom="0dp" - android:text="@string/account_select_student" + android:indeterminate="true" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintBottom_toTopOf="@id/accountDetailsLogout" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - <com.google.android.material.button.MaterialButton - android:id="@+id/accountDetailsLogout" - style="@style/Widget.MaterialComponents.Button.OutlinedButton" + <LinearLayout + android:id="@+id/account_details_error" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_margin="10dp" - android:insetLeft="0dp" - android:insetTop="0dp" - android:insetRight="0dp" - android:insetBottom="0dp" - android:text="@string/account_logout" - app:layout_constraintBottom_toBottomOf="parent" /> + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" + android:visibility="invisible" + tools:ignore="UseCompoundDrawables" + tools:visibility="visible"> + + <ImageView + android:layout_width="100dp" + android:layout_height="100dp" + app:srcCompat="@drawable/ic_all_account" + app:tint="?colorOnBackground" + tools:ignore="contentDescription" /> + + <TextView + android:id="@+id/account_details_error_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:gravity="center" + android:padding="8dp" + android:text="@string/error_unknown" + android:textSize="20sp" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:gravity="center" + android:orientation="horizontal"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/account_details_error_details" + style="@style/Widget.MaterialComponents.Button.OutlinedButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:text="@string/all_details" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/account_details_error_retry" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/all_retry" /> + </LinearLayout> + </LinearLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/account_details_content" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="0dp" + android:fillViewport="true" + app:layout_constraintBottom_toTopOf="@id/accountDetailsSelect" + app:layout_constraintTop_toTopOf="parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/accountDetailsAvatar" + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_marginTop="36dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_all_account" + app:tint="?colorPrimary" + tools:ignore="ContentDescription" /> + + <TextView + android:id="@+id/accountDetailsName" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:textSize="24sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/accountDetailsAvatar" + tools:text="Jan Kowalski" /> + + <TextView + android:id="@+id/accountDetailsSchool" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:textColor="?android:textColorSecondary" + android:textSize="14sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/accountDetailsName" + tools:text="Szkoła FakeLog" /> + + <LinearLayout + android:id="@+id/accountDetailsPersonalData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:layout_marginTop="16dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsSchool" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_all_account" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_personal_data" + android:textSize="16sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/accountDetailsAddressData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsPersonalData" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_all_home" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_address" + android:textSize="16sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/accountDetailsContactData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsAddressData" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_all_phone" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_contact" + android:textSize="16sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/accountDetailsFamilyData" + android:layout_width="match_parent" + android:layout_height="56dp" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@id/accountDetailsContactData" + tools:ignore="UseCompoundDrawables"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:srcCompat="@drawable/ic_account_details_family" + app:tint="?colorOnBackground" + tools:ignore="ContentDescription" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="32dp" + android:layout_marginEnd="16dp" + android:gravity="center_vertical" + android:text="@string/account_family" + android:textSize="16sp" /> + </LinearLayout> + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> + + <com.google.android.material.button.MaterialButton + android:id="@+id/accountDetailsSelect" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:insetLeft="0dp" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:text="@string/account_select_student" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintBottom_toTopOf="@id/accountDetailsLogout" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/accountDetailsLogout" + style="@style/Widget.MaterialComponents.Button.OutlinedButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:insetLeft="0dp" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:text="@string/account_logout" + app:layout_constraintBottom_toBottomOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml index 412502b5..fb0e138e 100644 --- a/app/src/main/res/layout/fragment_login_form.xml +++ b/app/src/main/res/layout/fragment_login_form.xml @@ -237,9 +237,7 @@ android:layout_gravity="center_vertical" android:layout_marginTop="48dp" android:layout_marginEnd="24dp" - android:layout_marginBottom="16dp" android:text="@string/login_sign_in" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f4817989..e41f2f28 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -412,6 +412,12 @@ <string name="student_info_phones">Phones</string> <string name="student_info_male">Male</string> <string name="student_info_female">Female</string> + <string name="student_info_last_name">Last name</string> + + + <!--Account edit--> + <string name="account_edit_nick_hint">Nick</string> + <string name="account_edit_header">Add nick</string> <!--Log viewer--> @@ -444,6 +450,7 @@ <string name="all_search_hint">Search…</string> <string name="all_yes">Yes</string> <string name="all_no">No</string> + <string name="all_save">Save</string> <!--Timetable Widget--> From 42f95942101617fae8610f903c5f4c3d3e13ae0d Mon Sep 17 00:00:00 2001 From: Mateusz Idziejczak <idziejczak3@gmail.com> Date: Tue, 2 Feb 2021 00:11:34 +0100 Subject: [PATCH 26/28] Fix empty message bug (#1122) --- .../ui/modules/message/preview/MessagePreviewPresenter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 55b9631a..702e5467 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -70,6 +70,7 @@ class MessagePreviewPresenter @Inject constructor( this@MessagePreviewPresenter.attachments = it.data.attachments view?.apply { setMessageWithAttachment(it.data) + showContent(true) initOptions() } analytics.logEvent( From aff40df707f06fab9f35fd4164d508dbddfe508d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= <RafalBO99@outlook.com> Date: Tue, 2 Feb 2021 00:25:27 +0100 Subject: [PATCH 27/28] New Crowdin updates (#1095) --- app/src/main/res/values-cs-rCZ/strings.xml | 71 ++++++++++++---- app/src/main/res/values-de/strings.xml | 53 ++++++++++-- app/src/main/res/values-pl/strings.xml | 45 +++++++++- app/src/main/res/values-ru/strings.xml | 95 ++++++++++++++++------ app/src/main/res/values-sk-rSK/strings.xml | 91 +++++++++++++++------ app/src/main/res/values-uk/strings.xml | 67 ++++++++++++--- 6 files changed, 334 insertions(+), 88 deletions(-) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index e2e7bdac..fc01584b 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -17,7 +17,10 @@ <string name="send_message_title">Nová zpráva</string> <string name="note_title">Poznámky a úspěchy</string> <string name="homework_title">Domácí úkoly</string> - <string name="account_title">Vyberte účet</string> + <string name="account_title">Manažer účtů</string> + <string name="account_quick_title">Vyberte účet</string> + <string name="account_details_title">Manažer účtů</string> + <string name="student_info_title">Informace o žáku</string> <!--Subtitles--> <string name="grade_subtitle">Semestr %1$d, %2$d/%3$d</string> <!--Login--> @@ -44,11 +47,11 @@ <string name="login_invalid_email">Neplatný e-mail</string> <string name="login_invalid_login">Místo e-mailu použijte přiřazené přihlašovací údaje</string> <string name="login_invalid_symbol">Neplatný symbol</string> - <string name="login_incorrect_symbol">Student nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string> + <string name="login_incorrect_symbol">Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string> <string name="login_field_required">Toto pole je povinné</string> - <string name="login_duplicate_student">Vybraný student je již přihlášen</string> + <string name="login_duplicate_student">Vybraný žák je již přihlášen</string> <string name="login_symbol_helper">Symbol najdete na stránce deníku v  <b>Uczeń</b> →  <b>Dostęp Mobilny</b> →  <b>Zarejestruj urządzenie mobilne</b>.\n\nUjistěte se, že jste na předchozí obrazovce nastavili správnou variantu deníku do pole <b>Variace deníku UONET+</b>. Wulkanowy v tuto chvíli nezjistí předškolní studenty</string> - <string name="login_select_student">Vyberte studenty, kteří se mají do aplikace přihlásit</string> + <string name="login_select_student">Vyberte žáky, kteří se mají do aplikace přihlásit</string> <string name="login_advanced">Jiné možnosti</string> <string name="login_advanced_warning_mobile_api">V tomto režimu nefungují následující: šťastné číslo, statistiky třídy, shrnutí docházky, ospravedlnění nepřítomnosti, absolvované lekce, informace o škole a prohlížení seznamu registrovaných zařízení</string> <string name="login_advanced_warning_scraper">Tento režim zobrazuje stejná data, která se zobrazují na webových stránkách deníka</string> @@ -63,7 +66,7 @@ <string name="login_recover_button">Zapomněl jsem své heslo</string> <string name="login_recover_title">Obnovte svůj účet</string> <string name="login_recover">Obnovit</string> - <string name="login_signed_in">Student je již přihlášen</string> + <string name="login_signed_in">Žák je již přihlášen</string> <!--Main--> <string name="main_account_picker">Manažer účtů</string> <string name="main_log_in">Přihlásit se</string> @@ -84,17 +87,21 @@ <string name="grade_no_average">Bez průměru</string> <string name="grade_predicted">Předpovězeno: %1$s</string> <string name="grade_final">Konečná: %1$s</string> - <string name="grade_summary_points">Celkem bodů</string> + <string name="grade_summary_points">Součet bodů</string> <string name="grade_summary_final_grade">Konečná známka</string> <string name="grade_summary_predicted_grade">Předpokládaná známka</string> <string name="grade_summary_calculated_average">Vypočítaný průměr</string> <string name="grade_summary_final_average">Konečný průměr</string> - <string name="grade_menu_summary">Souhrn</string> + <string name="grade_menu_summary">Shrnutí</string> <string name="grade_menu_statistics">Třída</string> <string name="grade_menu_read">Označit jako přečtené</string> <string name="grade_statistics_partial">Částečně</string> <string name="grade_statistics_semester">Semestr</string> <string name="grade_statistics_points">Body</string> + <string name="grade_statistics_legend">Vysvětlivky</string> + <string name="grade_statistics_average">Průměr: %1$s</string> + <string name="grade_statistics_average_class">Třída</string> + <string name="grade_statistics_average_student">Žák</string> <plurals name="grade_number_item"> <item quantity="one">%d známka</item> <item quantity="few">%d známky</item> @@ -139,7 +146,7 @@ </plurals> <!--Timetable--> <string name="timetable_lesson">Lekce</string> - <string name="timetable_room">Pokoj</string> + <string name="timetable_room">Učebna</string> <string name="timetable_group">Skupina</string> <string name="timetable_time">Hodiny</string> <string name="timetable_changes">Změny</string> @@ -164,10 +171,10 @@ <string name="additional_lessons_button">Zobrazit další lekce</string> <string name="additional_lessons_no_items">Žádné informace o dalších lekcích</string> <!--Attendance--> - <string name="attendance_summary_button">Souhrn docházky</string> + <string name="attendance_summary_button">Shrnutí docházky</string> <string name="attendance_absence_school">Nepřítomen ze školních důvodů</string> <string name="attendance_absence_excused">Omluvená nepřítomnost</string> - <string name="attendance_absence_unexcused">Neomluvená absence</string> + <string name="attendance_absence_unexcused">Neomluvená nepřítomnost</string> <string name="attendance_exemption">Osvobození</string> <string name="attendance_excused_lateness">Omluvené zpoždění</string> <string name="attendance_unexcused_lateness">Neomluvené zpoždění</string> @@ -189,7 +196,7 @@ <string name="attendance_excuse_title">Ospravedlnit</string> <!--Attendance summary--> <string name="attendance_summary_final">Účast</string> - <string name="attendance_summary_total">Celkový</string> + <string name="attendance_summary_total">Společně</string> <!--Exam--> <string name="exam_no_items">Tento týden žádné testy</string> <string name="exam_type">Typ</string> @@ -215,7 +222,7 @@ <string name="message_subject">Téma</string> <string name="message_content">Obsah</string> <string name="message_send_successful">Zpráva úspěšně odeslána</string> - <string name="message_not_exists">Message does not exist</string> + <string name="message_not_exists">Zpráva neexistuje</string> <string name="message_required_recipients">Musíte vybrat alespoň 1 příjemce</string> <string name="message_content_min_length">Obsah zprávy musí mít alespoň 3 znaky</string> <plurals name="message_number_item"> @@ -337,12 +344,19 @@ <!--Account--> <string name="account_add_new">Přidat účet</string> <string name="account_logout">Odhlásit se</string> - <string name="account_confirm">Chcete se odhlásit z aktivního studenta?</string> - <string name="account_logout_student">Odhlášení studentů</string> - <string name="account_type_student">Studentský účet</string> + <string name="account_confirm">Chcete se odhlásit z aktivního žáka?</string> + <string name="account_logout_student">Odhlášení žáků</string> + <string name="account_type_student">Žákův účet</string> <string name="account_type_parent">Rodičovský účet</string> <string name="account_login_mobile_api">Režim Mobilního API</string> <string name="account_login_hybrid">Hybridní režim</string> + <string name="account_details_edit">Upravit data</string> + <string name="account_quick_manager">Manažer účtů</string> + <string name="account_select_student">Vyberte žáka</string> + <string name="account_family">Rodina</string> + <string name="account_contact">Kontakt</string> + <string name="account_address">Údaje o adresách</string> + <string name="account_personal_data">Osobní údaje</string> <!--About--> <string name="about_version">Verze aplikace</string> <string name="about_contributor">Tvůrci</string> @@ -366,6 +380,30 @@ <!--Contributor--> <string name="contributor_avatar_description">Avatar</string> <string name="contributor_see_more">Zobrazit více na GitHub</string> + <!--Student info--> + <string name="student_info_empty">Žádné informace o žácích</string> + <string name="student_info_first_name">Jméno</string> + <string name="student_info_second_name">Druhé jméno</string> + <string name="student_info_gender">Pohlaví</string> + <string name="student_info_polish_citizenship">Polské občanství</string> + <string name="student_info_family_name">Rodinné jméno</string> + <string name="student_info_parents_name">Jména matky a otce</string> + <string name="student_info_phone">Telefon</string> + <string name="student_info_cellphone">Mobilní telefon</string> + <string name="student_info_email">E-mail</string> + <string name="student_info_address">Adresa bydliště</string> + <string name="student_info_registered_address">Registrovaná adresa</string> + <string name="student_info_correspondence_address">Korespondenční adresa</string> + <string name="student_info_full_name">Příjmení a jméno</string> + <string name="student_info_kinship">Stupeň příbuznosti</string> + <string name="student_info_guardian_address">Adresa</string> + <string name="student_info_phones">Telefony</string> + <string name="student_info_male">Muž</string> + <string name="student_info_female">Žena</string> + <string name="student_info_last_name">Příjmení</string> + <!--Account edit--> + <string name="account_edit_nick_hint">Přezdívka</string> + <string name="account_edit_header">Přidat přezdívku</string> <!--Log viewer--> <string name="logviewer_share">Sdílejte protokoly</string> <string name="logviewer_refresh">Obnovit</string> @@ -390,6 +428,9 @@ <string name="all_next">Další</string> <string name="all_search">Hledat</string> <string name="all_search_hint">Hledat…</string> + <string name="all_yes">Ano</string> + <string name="all_no">Ne</string> + <string name="all_save">Uložit</string> <!--Timetable Widget--> <string name="widget_timetable_no_items">Žádné lekce</string> <string name="widget_timetable_theme_title">Vybrat motiv</string> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7ba35734..8d0bf3e9 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -17,7 +17,10 @@ <string name="send_message_title">neue Nachricht</string> <string name="note_title">Eintragen und Erfolgen</string> <string name="homework_title">Hausaufgaben</string> - <string name="account_title">Wählen Sie ein Konto</string> + <string name="account_title">Konten-Manager</string> + <string name="account_quick_title">Konto auswählen</string> + <string name="account_details_title">Kontodetails</string> + <string name="student_info_title">Schülerinfo</string> <!--Subtitles--> <string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string> <!--Login--> @@ -95,6 +98,10 @@ <string name="grade_statistics_partial">Partiell</string> <string name="grade_statistics_semester">Semester</string> <string name="grade_statistics_points">Punkte</string> + <string name="grade_statistics_legend">Legende</string> + <string name="grade_statistics_average">Durchschnitt: %1$s</string> + <string name="grade_statistics_average_class">Klasse</string> + <string name="grade_statistics_average_student">Schüler</string> <plurals name="grade_number_item"> <item quantity="one">%d Note</item> <item quantity="other">%d Noten</item> @@ -146,9 +153,9 @@ <string name="completed_lessons_absence">Abwesenheit</string> <string name="completed_lessons_resources">Ressourcen</string> <!--Additional lessons--> - <string name="additional_lessons_title">Additional lessons</string> - <string name="additional_lessons_button">Show additional lessons</string> - <string name="additional_lessons_no_items">No info about additional lessons</string> + <string name="additional_lessons_title">Zusätzliche Lektionen</string> + <string name="additional_lessons_button">Zusätzliche Lektionen anzeigen</string> + <string name="additional_lessons_no_items">Keine Infos zu zusätzlichen Lektionen</string> <!--Attendance--> <string name="attendance_summary_button">Übersicht über die Schulbesuch</string> <string name="attendance_absence_school">Aus schulischen Gründen abwesend</string> @@ -199,7 +206,7 @@ <string name="message_subject">Thema</string> <string name="message_content">Inhalt</string> <string name="message_send_successful">Nachricht erfolgreich gesendet</string> - <string name="message_not_exists">Message does not exist</string> + <string name="message_not_exists">Nachricht existiert nicht</string> <string name="message_required_recipients">Sie müssen mindestens 1 Empfänger auswählen.</string> <string name="message_content_min_length">Der Inhalt der Nachricht muss mindestens 3 Zeichen lang sein.</string> <plurals name="message_number_item"> @@ -297,12 +304,19 @@ <!--Account--> <string name="account_add_new">Konto hinzufügen</string> <string name="account_logout">Abmelden</string> - <string name="account_confirm">Wollen Sie sich von einem aktiven Studenten abmelden?</string> + <string name="account_confirm">Wollen Sie diesen Schüler abmelden?</string> <string name="account_logout_student">Abmeldung von Student</string> <string name="account_type_student">Studentenkonto</string> <string name="account_type_parent">Elternkonto</string> <string name="account_login_mobile_api">Mobiler API Modus</string> <string name="account_login_hybrid">Hybrid Modus</string> + <string name="account_details_edit">Daten bearbeiten</string> + <string name="account_quick_manager">Konten-Manager</string> + <string name="account_select_student">Schüler auswählen</string> + <string name="account_family">Familie</string> + <string name="account_contact">Kontakt</string> + <string name="account_address">Wohnungsdetails</string> + <string name="account_personal_data">Persönliche Information</string> <!--About--> <string name="about_version">Version der App</string> <string name="about_contributor">Mitarbeiter</string> @@ -326,6 +340,30 @@ <!--Contributor--> <string name="contributor_avatar_description">Benutzerbild</string> <string name="contributor_see_more">Sehen Sie mehr auf GitHub</string> + <!--Student info--> + <string name="student_info_empty">Keine Informationen über Schüler</string> + <string name="student_info_first_name">Name</string> + <string name="student_info_second_name">Zweite Name</string> + <string name="student_info_gender">Geschlecht</string> + <string name="student_info_polish_citizenship">Polnische Staatsbürgerschaft</string> + <string name="student_info_family_name">Familienname</string> + <string name="student_info_parents_name">Namen von Mutter und Vater</string> + <string name="student_info_phone">Telefonnummer</string> + <string name="student_info_cellphone">Mobiltelefonnummer</string> + <string name="student_info_email">E-Mail</string> + <string name="student_info_address">Wohnadresse</string> + <string name="student_info_registered_address">Adresse der Registrierung</string> + <string name="student_info_correspondence_address">Korrespondenzadresse</string> + <string name="student_info_full_name">Nachname und Vorname</string> + <string name="student_info_kinship">Verwandtschaftsgrad</string> + <string name="student_info_guardian_address">Adresse</string> + <string name="student_info_phones">Telefonnummern</string> + <string name="student_info_male">Mann</string> + <string name="student_info_female">Frau</string> + <string name="student_info_last_name">Nachname</string> + <!--Account edit--> + <string name="account_edit_nick_hint">Nick</string> + <string name="account_edit_header">Nick hinzufügen</string> <!--Log viewer--> <string name="logviewer_share">Logs teilen</string> <string name="logviewer_refresh">Aktualisieren</string> @@ -350,6 +388,9 @@ <string name="all_next">Nächste</string> <string name="all_search">Suchen</string> <string name="all_search_hint">Suchen…</string> + <string name="all_yes">Ja</string> + <string name="all_no">Nein</string> + <string name="all_save">Speichern</string> <!--Timetable Widget--> <string name="widget_timetable_no_items">Keine Lektionen</string> <string name="widget_timetable_theme_title">Thema wählen</string> diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 19e312ba..2f849bc1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -17,7 +17,10 @@ <string name="send_message_title">Nowa wiadomość</string> <string name="note_title">Uwagi i osiągnięcia</string> <string name="homework_title">Zadania domowe</string> - <string name="account_title">Wybierz konto</string> + <string name="account_title">Menadżer kont</string> + <string name="account_quick_title">Wybierz konto</string> + <string name="account_details_title">Szczegóły konta</string> + <string name="student_info_title">Informacje o uczniu</string> <!--Subtitles--> <string name="grade_subtitle">Semestr %1$d, %2$d/%3$d</string> <!--Login--> @@ -95,6 +98,10 @@ <string name="grade_statistics_partial">Cząstkowe</string> <string name="grade_statistics_semester">Semestralne</string> <string name="grade_statistics_points">Punkty</string> + <string name="grade_statistics_legend">Legenda</string> + <string name="grade_statistics_average">Średnia: %1$s</string> + <string name="grade_statistics_average_class">Klasa</string> + <string name="grade_statistics_average_student">Uczeń</string> <plurals name="grade_number_item"> <item quantity="one">%d ocena</item> <item quantity="few">%d oceny</item> @@ -337,12 +344,19 @@ <!--Account--> <string name="account_add_new">Dodaj konto</string> <string name="account_logout">Wyloguj</string> - <string name="account_confirm">Czy chcesz wylogować aktualnego ucznia?</string> + <string name="account_confirm">Czy chcesz wylogować tego ucznia?</string> <string name="account_logout_student">Wylogowanie ucznia</string> <string name="account_type_student">Konto ucznia</string> <string name="account_type_parent">Konto rodzica</string> <string name="account_login_mobile_api">Tryb API mobilne</string> <string name="account_login_hybrid">Tryb hybrydowy</string> + <string name="account_details_edit">Edytuj dane</string> + <string name="account_quick_manager">Menadżer kont</string> + <string name="account_select_student">Wybierz ucznia</string> + <string name="account_family">Rodzina</string> + <string name="account_contact">Kontakt</string> + <string name="account_address">Dane adresowe</string> + <string name="account_personal_data">Dane osobowe</string> <!--About--> <string name="about_version">Wersja aplikacji</string> <string name="about_contributor">Twórcy</string> @@ -366,6 +380,30 @@ <!--Contributor--> <string name="contributor_avatar_description">Awatar</string> <string name="contributor_see_more">Zobacz więcej na GitHub</string> + <!--Student info--> + <string name="student_info_empty">Brak informacji o uczniu</string> + <string name="student_info_first_name">Imię</string> + <string name="student_info_second_name">Drugie imię</string> + <string name="student_info_gender">Płeć</string> + <string name="student_info_polish_citizenship">Obywatelstwo polskie</string> + <string name="student_info_family_name">Nazwisko rodowe</string> + <string name="student_info_parents_name">Imiona matki i ojca</string> + <string name="student_info_phone">Telefon</string> + <string name="student_info_cellphone">Telefon komórkowy</string> + <string name="student_info_email">E-mail</string> + <string name="student_info_address">Adres zamieszkania</string> + <string name="student_info_registered_address">Adres zameldowania</string> + <string name="student_info_correspondence_address">Adres korespondencyjny</string> + <string name="student_info_full_name">Nazwisko i imię</string> + <string name="student_info_kinship">Stopień pokrewieństwa</string> + <string name="student_info_guardian_address">Adres</string> + <string name="student_info_phones">Telefony</string> + <string name="student_info_male">Mężczyzna</string> + <string name="student_info_female">Kobieta</string> + <string name="student_info_last_name">Nazwisko</string> + <!--Account edit--> + <string name="account_edit_nick_hint">Pseudonim</string> + <string name="account_edit_header">Dodaj pseudonim</string> <!--Log viewer--> <string name="logviewer_share">Udostępnij logi</string> <string name="logviewer_refresh">Odśwież</string> @@ -390,6 +428,9 @@ <string name="all_next">Następny</string> <string name="all_search">Szukaj</string> <string name="all_search_hint">Szukaj…</string> + <string name="all_yes">Tak</string> + <string name="all_no">Nie</string> + <string name="all_save">Zapisz</string> <!--Timetable Widget--> <string name="widget_timetable_no_items">Brak lekcji</string> <string name="widget_timetable_theme_title">Wybierz motyw</string> diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9c4efa45..158c91bc 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -8,7 +8,7 @@ <string name="exam_title">Тесты</string> <string name="timetable_title">Расписание</string> <string name="settings_title">Настройки</string> - <string name="more_title">Другое</string> + <string name="more_title">Ещё</string> <string name="about_title">О приложении</string> <string name="logviewer_title">Просмотр журнала</string> <string name="contributors_title">Разработчики</string> @@ -17,7 +17,10 @@ <string name="send_message_title">Новое сообщение</string> <string name="note_title">Предупреждения и свершения</string> <string name="homework_title">Домашние задания</string> - <string name="account_title">Выберите аккаунт</string> + <string name="account_title">Менеджер аккаунтов</string> + <string name="account_quick_title">Выбор учетной записи</string> + <string name="account_details_title">Данные аккаунта</string> + <string name="student_info_title">Информация о студенте</string> <!--Subtitles--> <string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string> <!--Login--> @@ -27,10 +30,10 @@ <string name="login_email_hint">Электронная почта</string> <string name="login_login_pesel_email_hint">Логин, PESEL или электронная почта</string> <string name="login_password_hint">Пароль</string> - <string name="login_host_hint">Разновидностью бревна UONET+</string> - <string name="login_type_api">Mobile API</string> + <string name="login_host_hint">UONET + вариант регистрации</string> + <string name="login_type_api">Мобильный API</string> <string name="login_type_scrapper">Scraper</string> - <string name="login_type_hybrid">Hybrid</string> + <string name="login_type_hybrid">Гибрид</string> <string name="login_token_hint">Token</string> <string name="login_pin_hint">PIN</string> <string name="login_api_key_hint">Ключ API</string> @@ -39,15 +42,15 @@ <string name="login_invalid_password">Слишком короткий пароль</string> <string name="login_incorrect_password">Данные для входа неверны. Убедитесь, что в поле ниже выбран правильный вариант регистра UONET+</string> <string name="login_invalid_pin">Неправильный PIN</string> - <string name="login_invalid_token">Неправильный token</string> - <string name="login_expired_token">Токен просрочен</string> + <string name="login_invalid_token">Неверный token</string> + <string name="login_expired_token">Token просрочен</string> <string name="login_invalid_email">Неверный адрес электронной почты</string> <string name="login_invalid_login">Используйте назначенный логин вместо электронной почты</string> - <string name="login_invalid_symbol">Неправильный symbol</string> + <string name="login_invalid_symbol">Неправильный символ</string> <string name="login_incorrect_symbol">Студент не найден. Подтвердите символ и выбранный вариант регистра UONET+</string> - <string name="login_field_required">Обязательное поле</string> + <string name="login_field_required">Это обязательное поле</string> <string name="login_duplicate_student">Данный ученик уже авторизован</string> - <string name="login_symbol_helper">Этот символ можно найти на странице регистрации в  <b>Uczeń</b> →  <b>Dostęp Mobilny</b> →  <b>Zarejestruj urządzenie mobilne</b>.\n\nУбедитесь, что вы установили соответствующий вариант регистра в поле <b>Разновидностью бревна UONET+</b> на предыдущем экране. Wulkanowy на данный момент не обнаруживает дошкольников</string> + <string name="login_symbol_helper">Этот символ можно найти на странице регистрации в  <b>Ученик</b> →  <b>Телефонный доступ</b> →  <b> Зарегистрируйте мобильное устройство</b>.\n\nУбедитесь, что вы установили соответствующий вариант регистра в поле <b>Разновидностью бревна UONET+</b> на предыдущем экране. Вулкановый на данный момент не обнаруживает дошкольников</string> <string name="login_select_student">Выберите учеников для авторизации в приложении</string> <string name="login_advanced">Другие варианты</string> <string name="login_advanced_warning_mobile_api">В этом режиме не работают: счастливый номер, статистика класса по оценкам, статистика посещаемости и уроков, информация о школе и список зарегистрированных устройств</string> @@ -60,7 +63,7 @@ <string name="login_email_intent_title">Отправить письмо</string> <string name="login_email_details">Опишите детали проблемы:</string> <string name="login_recover_warning">Убедитесь, что вы выбрали правильный вариант регистра UONET+!</string> - <string name="login_recover_button">Забыли пароль?</string> + <string name="login_recover_button">Я забыл свой пароль</string> <string name="login_recover_title">Восстановите свой аккаунт</string> <string name="login_recover">Восстановить</string> <string name="login_signed_in">Студент уже вошел в систему</string> @@ -68,7 +71,7 @@ <string name="main_account_picker">Менеджер аккаунтов</string> <string name="main_log_in">Войти</string> <string name="main_session_expired">Сеанс истёк</string> - <string name="main_session_relogin">Сеанс истёк, пожалуйста, авторизируйтесь ещё раз</string> + <string name="main_session_relogin">Сеанс истёк, пожалуйста, войдите ещё раз</string> <!--Grade--> <string name="grade_header">Оценка</string> <string name="grade_semester">Семестр %d</string> @@ -95,6 +98,10 @@ <string name="grade_statistics_partial">Частичные</string> <string name="grade_statistics_semester">За семестр</string> <string name="grade_statistics_points">Баллы</string> + <string name="grade_statistics_legend">Легенда</string> + <string name="grade_statistics_average">Средняя: %1$s</string> + <string name="grade_statistics_average_class">Класс</string> + <string name="grade_statistics_average_student">Студент</string> <plurals name="grade_number_item"> <item quantity="one">%d оценка</item> <item quantity="few">%d оценки</item> @@ -132,7 +139,7 @@ <item quantity="other">Вы получили %1$d ожидаемых оценок</item> </plurals> <plurals name="grade_notify_new_items_final"> - <item quantity="one">Вы получили %1$d финальную оценку</item> + <item quantity="one">Вы получили %1$d итоговою оценку</item> <item quantity="few">Вы получили %1$d итоговых оценки</item> <item quantity="many">Вы получили %1$d итоговых оценок</item> <item quantity="other">Вы получили %1$d финальные оценки</item> @@ -143,7 +150,7 @@ <string name="timetable_group">Группа</string> <string name="timetable_time">Часы</string> <string name="timetable_changes">Изменения</string> - <string name="timetable_no_items">Нет уроков в данный день</string> + <string name="timetable_no_items">Нету уроков в данный день</string> <string name="timetable_minutes">%s мин</string> <string name="timetable_seconds">%s сек</string> <string name="timetable_time_left">%1$s осталось</string> @@ -160,9 +167,9 @@ <string name="completed_lessons_absence">Отсутствие</string> <string name="completed_lessons_resources">Ресурсы</string> <!--Additional lessons--> - <string name="additional_lessons_title">Additional lessons</string> - <string name="additional_lessons_button">Show additional lessons</string> - <string name="additional_lessons_no_items">No info about additional lessons</string> + <string name="additional_lessons_title">Дополнительные уроки</string> + <string name="additional_lessons_button">Показать дополнительные уроки</string> + <string name="additional_lessons_no_items">Нет информации о дополнительных уроках</string> <!--Attendance--> <string name="attendance_summary_button">Итоговая посещаемость</string> <string name="attendance_absence_school">Отсутствие по школьным причинам</string> @@ -215,7 +222,7 @@ <string name="message_subject">Тема</string> <string name="message_content">Текст</string> <string name="message_send_successful">Сообщение успешно отправлено</string> - <string name="message_not_exists">Message does not exist</string> + <string name="message_not_exists">Сообщения не существует</string> <string name="message_required_recipients">Вы должны выбрать как минимум одного получателя</string> <string name="message_content_min_length">Текст сообщения должен содержать как минимум 3 знака</string> <plurals name="message_number_item"> @@ -237,7 +244,7 @@ <item quantity="other">Вы получили %1$d новых сообщений</item> </plurals> <!--Note--> - <string name="note_no_items">Нет данных о предупреждениях</string> + <string name="note_no_items">Нет информации о заметках</string> <string name="note_points">Баллы</string> <plurals name="note_number_item"> <item quantity="one">%d предупреждение</item> @@ -297,19 +304,19 @@ </plurals> <!--Homework--> <string name="homework_no_items">Нет домашних заданий</string> - <string name="homework_mark_as_done">сделанный</string> - <string name="homework_mark_as_undone">Не сделано</string> + <string name="homework_mark_as_done">Отметить как выполненное</string> + <string name="homework_mark_as_undone">Отметить как невыполненное</string> <string name="homework_attachments">Вложения</string> <!--Lucky number--> <string name="lucky_number_title">Счастливый номер</string> - <string name="lucky_number_header">Сегодняшний счастливый номер</string> + <string name="lucky_number_header">Сегодняшний счастливый номер это</string> <string name="lucky_number_empty">Нет данных о счастливом номере</string> <string name="lucky_number_notify_new_item_title">Сегодняшний счастливый номер</string> - <string name="lucky_number_notify_new_item">Сегодняшний счастливый номер: %d</string> + <string name="lucky_number_notify_new_item">Сегодняшний счастливый номер это: %d</string> <!--Mobile devices--> <string name="mobile_devices_title">Мобильные устройства</string> <string name="mobile_devices_no_items">Нет устройств</string> - <string name="mobile_devices_unregister">Удалить</string> + <string name="mobile_devices_unregister">Отменить регистрацию</string> <string name="mobile_device_removed">Устройство удалено</string> <string name="mobile_device_qr">QR-код</string> <string name="mobile_device_token">Token</string> @@ -323,8 +330,8 @@ <string name="school_name">Название школы</string> <string name="school_address">Адрес школы</string> <string name="school_telephone">Телефон</string> - <string name="school_headmaster">Директор</string> - <string name="school_pedagogue">Педагог</string> + <string name="school_headmaster">Имя директора</string> + <string name="school_pedagogue">Имя педагога</string> <string name="school_address_button">Показать на карте</string> <string name="school_telephone_button">Позвонить</string> <!--Teacher--> @@ -343,10 +350,17 @@ <string name="account_type_parent">Профиль родителя</string> <string name="account_login_mobile_api">Режим Mobile API</string> <string name="account_login_hybrid">Гибридный режим</string> + <string name="account_details_edit">Изменить данные</string> + <string name="account_quick_manager">Менеджер аккаунтов</string> + <string name="account_select_student">Выберите Студента</string> + <string name="account_family">Семья</string> + <string name="account_contact">Контакт</string> + <string name="account_address">Детали проживания</string> + <string name="account_personal_data">Персональные данные</string> <!--About--> <string name="about_version">Версия приложения</string> <string name="about_contributor">Разработчики</string> - <string name="about_contributor_summary">Список разработчиков \"Wulkanowy\"</string> + <string name="about_contributor_summary">Список разработчиков \"Вулкановый\"</string> <string name="about_feedback">Возникла ошибка?</string> <string name="about_feedback_summary">Сообщить о ошибке</string> <string name="about_faq">FAQ</string> @@ -366,6 +380,30 @@ <!--Contributor--> <string name="contributor_avatar_description">Aватар</string> <string name="contributor_see_more">Страница проекта на GitHub</string> + <!--Student info--> + <string name="student_info_empty">Нет информации о студенте</string> + <string name="student_info_first_name">Имя</string> + <string name="student_info_second_name">Фамилия</string> + <string name="student_info_gender">Пол</string> + <string name="student_info_polish_citizenship">Польское гражданство</string> + <string name="student_info_family_name">Фамилия</string> + <string name="student_info_parents_name">Имена матери и отца</string> + <string name="student_info_phone">Телефон</string> + <string name="student_info_cellphone">Сотовый телефон</string> + <string name="student_info_email">Эл. почта</string> + <string name="student_info_address">Адрес проживания</string> + <string name="student_info_registered_address">Адрес регистрации</string> + <string name="student_info_correspondence_address">Адрес переписки</string> + <string name="student_info_full_name">Фамилия и имя</string> + <string name="student_info_kinship">Степень родства</string> + <string name="student_info_guardian_address">Адрес</string> + <string name="student_info_phones">Телефоны</string> + <string name="student_info_male">Муж</string> + <string name="student_info_female">Женская</string> + <string name="student_info_last_name">Фамилия</string> + <!--Account edit--> + <string name="account_edit_nick_hint">Ник</string> + <string name="account_edit_header">Добавить ник</string> <!--Log viewer--> <string name="logviewer_share">Поделиться логами</string> <string name="logviewer_refresh">Обновить</string> @@ -390,6 +428,9 @@ <string name="all_next">Следующий</string> <string name="all_search">Поиск</string> <string name="all_search_hint">Поиск…</string> + <string name="all_yes">Да</string> + <string name="all_no">Нет</string> + <string name="all_save">Сохранить</string> <!--Timetable Widget--> <string name="widget_timetable_no_items">Нет уроков</string> <string name="widget_timetable_theme_title">Выбрать тему</string> diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 54012b1f..b5c0116e 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -17,7 +17,10 @@ <string name="send_message_title">Nová správa</string> <string name="note_title">Poznámky a úspechy</string> <string name="homework_title">Domáce úlohy</string> - <string name="account_title">Vyberte účet</string> + <string name="account_title">Accounts manager</string> + <string name="account_quick_title">Select account</string> + <string name="account_details_title">Account details</string> + <string name="student_info_title">Student info</string> <!--Subtitles--> <string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string> <!--Login--> @@ -44,11 +47,11 @@ <string name="login_invalid_email">Neplatný e-mail</string> <string name="login_invalid_login">Namiesto e-mailu použite priradené prihlasovacie údaje</string> <string name="login_invalid_symbol">Neplatný symbol</string> - <string name="login_incorrect_symbol">Študent nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+</string> + <string name="login_incorrect_symbol">Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+</string> <string name="login_field_required">Toto pole je povinné</string> - <string name="login_duplicate_student">Vybraný študent je už prihlásený</string> + <string name="login_duplicate_student">Vybraný žiak už je prihlásený</string> <string name="login_symbol_helper">The symbol can be found on the register page in <b>Uczeń</b> → <b>Dostęp Mobilny</b> → <b>Zarejestruj urządzenie mobilne</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the previous screen. Wulkanowy does not detect pre-school students at the moment</string> - <string name="login_select_student">Vyberte studenty, kteří se mají do aplikace přihlásit</string> + <string name="login_select_student">Vyberte žiakov, ktorí sa majú do aplikácie prihlásiť</string> <string name="login_advanced">Iné možnosti</string> <string name="login_advanced_warning_mobile_api">In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices</string> <string name="login_advanced_warning_scraper">This mode displays the same data as it appears on the register website</string> @@ -84,17 +87,21 @@ <string name="grade_no_average">Bez priemeru</string> <string name="grade_predicted">Predpovedané: %1$s</string> <string name="grade_final">Konečná: %1$s</string> - <string name="grade_summary_points">Celkom bodov</string> + <string name="grade_summary_points">Súčet bodov</string> <string name="grade_summary_final_grade">Konečná známka</string> <string name="grade_summary_predicted_grade">Predpokladaná známka</string> <string name="grade_summary_calculated_average">Vypočítaný priemer</string> <string name="grade_summary_final_average">Konečný priemer</string> - <string name="grade_menu_summary">Súhrn</string> + <string name="grade_menu_summary">Zhrnutie</string> <string name="grade_menu_statistics">Trieda</string> <string name="grade_menu_read">Označiť ako prečítané</string> - <string name="grade_statistics_partial">Čiastočne</string> + <string name="grade_statistics_partial">Čiastočné</string> <string name="grade_statistics_semester">Semester</string> <string name="grade_statistics_points">Body</string> + <string name="grade_statistics_legend">Legenda</string> + <string name="grade_statistics_average">Average: %1$s</string> + <string name="grade_statistics_average_class">Trieda</string> + <string name="grade_statistics_average_student">Žiák</string> <plurals name="grade_number_item"> <item quantity="one">%d známka</item> <item quantity="few">%d známky</item> @@ -109,27 +116,27 @@ </plurals> <plurals name="grade_new_items_predicted"> <item quantity="one">Nová predpokladaná známka</item> - <item quantity="few">Nové predpovedanej známky</item> - <item quantity="many">Nové predpovedanej známky</item> - <item quantity="other">Nové predpovedanej známky</item> + <item quantity="few">Nové predpokladané známky</item> + <item quantity="many">Nové predpokladané známky</item> + <item quantity="other">Nové predpokladané známky</item> </plurals> <plurals name="grade_new_items_final"> <item quantity="one">Nová konečná známka</item> - <item quantity="few">Nové konečnej známky</item> - <item quantity="many">Nové konečnej známky</item> - <item quantity="other">Nové konečnej známky</item> + <item quantity="few">Nové konečné známky</item> + <item quantity="many">Nové konečné známky</item> + <item quantity="other">Nové konečné známky</item> </plurals> <plurals name="grade_notify_new_items"> <item quantity="one">Máte %1$d novú známku</item> <item quantity="few">Máte %1$d nové známky</item> - <item quantity="many">Máte %1$d nové známky</item> - <item quantity="other">Máte %1$d nové známky</item> + <item quantity="many">Máte %1$d nových známok</item> + <item quantity="other">Máte %1$d nových známok</item> </plurals> <plurals name="grade_notify_new_items_predicted"> <item quantity="one">Máte %1$d novú predpokladanú známku</item> <item quantity="few">Máte %1$d nové predpokladané známky</item> - <item quantity="many">Máte %1$d nové predpokladané známky</item> - <item quantity="other">Máte %1$d nové predpokladané známky</item> + <item quantity="many">Máte %1$d nových predpokladaných známok</item> + <item quantity="other">Máte %1$d nových predpokladaných známok</item> </plurals> <plurals name="grade_notify_new_items_final"> <item quantity="one">Máte %1$d novú konečnú známku</item> @@ -139,7 +146,7 @@ </plurals> <!--Timetable--> <string name="timetable_lesson">Lekcia</string> - <string name="timetable_room">Room</string> + <string name="timetable_room">Učebňa</string> <string name="timetable_group">Skupina</string> <string name="timetable_time">Hodiny</string> <string name="timetable_changes">Zmeny</string> @@ -158,9 +165,9 @@ <string name="completed_lessons_no_items">No info about completed lessons</string> <string name="completed_lessons_topic">Téma</string> <string name="completed_lessons_absence">Neprítomnosť</string> - <string name="completed_lessons_resources">Resources</string> + <string name="completed_lessons_resources">Zdroje</string> <!--Additional lessons--> - <string name="additional_lessons_title">Additional lessons</string> + <string name="additional_lessons_title">Ďalší lekcie</string> <string name="additional_lessons_button">Show additional lessons</string> <string name="additional_lessons_no_items">No info about additional lessons</string> <!--Attendance--> @@ -171,11 +178,11 @@ <string name="attendance_exemption">Exemption</string> <string name="attendance_excused_lateness">Excused lateness</string> <string name="attendance_unexcused_lateness">Unexcused lateness</string> - <string name="attendance_present">Present</string> + <string name="attendance_present">Prítomnosť</string> <string name="attendance_deleted">Deleted</string> - <string name="attendance_unknown">Unknown</string> + <string name="attendance_unknown">Neznámy</string> <string name="attendance_number">Number of lesson</string> - <string name="attendance_no_items">No entries</string> + <string name="attendance_no_items">Žiadne položky</string> <plurals name="attendance_number_absences"> <item quantity="one">%1$d absence</item> <item quantity="few">%1$d absences</item> @@ -183,7 +190,7 @@ <item quantity="other">%1$d absences</item> </plurals> <string name="attendance_excuse_dialog_reason">Absence reason (optional)</string> - <string name="attendance_excuse_dialog_submit">Send</string> + <string name="attendance_excuse_dialog_submit">Poslať</string> <string name="attendance_excuse_success">Absence excused successfully!</string> <string name="attendance_excuse_no_selection">You must select at least one absence!</string> <string name="attendance_excuse_title">Excuse</string> @@ -337,12 +344,19 @@ <!--Account--> <string name="account_add_new">Add account</string> <string name="account_logout">Logout</string> - <string name="account_confirm">Do you want to log out of an active student?</string> + <string name="account_confirm">Do you want to log out this student?</string> <string name="account_logout_student">Student logout</string> <string name="account_type_student">Student account</string> <string name="account_type_parent">Parent account</string> <string name="account_login_mobile_api">Mobile API mode</string> <string name="account_login_hybrid">Hybrid mode</string> + <string name="account_details_edit">Edit data</string> + <string name="account_quick_manager">Accounts manager</string> + <string name="account_select_student">Select student</string> + <string name="account_family">Family</string> + <string name="account_contact">Contact</string> + <string name="account_address">Residence details</string> + <string name="account_personal_data">Personal information</string> <!--About--> <string name="about_version">App version</string> <string name="about_contributor">Contributors</string> @@ -366,6 +380,30 @@ <!--Contributor--> <string name="contributor_avatar_description">Avatar</string> <string name="contributor_see_more">See more on GitHub</string> + <!--Student info--> + <string name="student_info_empty">No info about student</string> + <string name="student_info_first_name">Name</string> + <string name="student_info_second_name">Second name</string> + <string name="student_info_gender">Gender</string> + <string name="student_info_polish_citizenship">Polish citizenship</string> + <string name="student_info_family_name">Family name</string> + <string name="student_info_parents_name">Mother\'s and father\'s names</string> + <string name="student_info_phone">Phone</string> + <string name="student_info_cellphone">Cellphone</string> + <string name="student_info_email">E-mail</string> + <string name="student_info_address">Address of residence</string> + <string name="student_info_registered_address">Address of registration</string> + <string name="student_info_correspondence_address">Correspondence address</string> + <string name="student_info_full_name">Surname and first name</string> + <string name="student_info_kinship">Degree of kinship</string> + <string name="student_info_guardian_address">Address</string> + <string name="student_info_phones">Phones</string> + <string name="student_info_male">Male</string> + <string name="student_info_female">Female</string> + <string name="student_info_last_name">Last name</string> + <!--Account edit--> + <string name="account_edit_nick_hint">Nick</string> + <string name="account_edit_header">Add nick</string> <!--Log viewer--> <string name="logviewer_share">Share logs</string> <string name="logviewer_refresh">Refresh</string> @@ -390,6 +428,9 @@ <string name="all_next">Next</string> <string name="all_search">Search</string> <string name="all_search_hint">Search…</string> + <string name="all_yes">Yes</string> + <string name="all_no">No</string> + <string name="all_save">Save</string> <!--Timetable Widget--> <string name="widget_timetable_no_items">No lessons</string> <string name="widget_timetable_theme_title">Choose theme</string> diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index a1511d9f..3c4b4436 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -17,11 +17,14 @@ <string name="send_message_title">Нове повідомлення</string> <string name="note_title">Нотатки та досягнення</string> <string name="homework_title">Домашні завдання</string> - <string name="account_title">Оберіть аккаунт</string> + <string name="account_title">Менеджер аккаунтів</string> + <string name="account_quick_title">Виберіть обліковий запис</string> + <string name="account_details_title">Деталі облікового запису</string> + <string name="student_info_title">Інформація про учня</string> <!--Subtitles--> <string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string> <!--Login--> - <string name="login_header_default">Авторизуйтеся за допомогою аккаунта учня або батька</string> + <string name="login_header_default">Авторизуйтеся за допомогою аккаунта учня або батьків</string> <string name="login_header_symbol">Введіть символ зі сторінки реєстру</string> <string name="login_nickname_hint">Ім\'я користувача</string> <string name="login_email_hint">Електронна пошта</string> @@ -43,11 +46,11 @@ <string name="login_expired_token">Минув термін дії токену</string> <string name="login_invalid_email">Недійсна адреса електронної пошти</string> <string name="login_invalid_login">Використовуйте призначений логін замість електронної пошти</string> - <string name="login_invalid_symbol">Неправильний symbol</string> + <string name="login_invalid_symbol">Неправильний симбвол</string> <string name="login_incorrect_symbol">Студента не знайдено Перевірте символ та обраний варіант реєстру UONET+</string> <string name="login_field_required">Обов\'язкове поле</string> <string name="login_duplicate_student">Даного учня вже авторизовано</string> - <string name="login_symbol_helper">Символ можна знайти на сторінці реєстру в   <b> Uczeń </b> →   <b> Dostęp Mobilny </b> →   <b> Zarejestruj urządzenie mobilne </b>.\n\nПереконайтесь, що ви встановили відповідний варіант реєстру в полі <b> UONET + варіант реєстрації </b> на попередньому екрані. На даний момент Wulkanowy не виявляє учнів дошкільних закладів</string> + <string name="login_symbol_helper">Символ можна знайти на сторінці реєстру в   <b> Учень </b> →   <b> Мобільний доступ </b> →   <b> Додайте мобільне приладдя </b>.\n\nПереконайтесь, що ви встановили відповідний варіант реєстру в полі <b> UONET + варіант реєстрації </b> на попередньому екрані. На даний момент Wulkanowy не виявляє учнів дошкільних закладів</string> <string name="login_select_student">Виберіть учнів для авторизації в додатку</string> <string name="login_advanced">Інші варіанти</string> <string name="login_advanced_warning_mobile_api">У цьому режимі не працюють: щасливий номер, статистика класу по оцінкам, статистика відвідуваності і уроків, інформація про школу і список зареєстрованних пристроїв</string> @@ -61,7 +64,7 @@ <string name="login_email_details">Опишіть деталі помилки:</string> <string name="login_recover_warning">Переконайтеся, що ви вибрали правильний варіант реєстрації UONET+!</string> <string name="login_recover_button">Забули пароль?</string> - <string name="login_recover_title">Відновіть свій аккаунт</string> + <string name="login_recover_title">Відновіть свій обліковий запис</string> <string name="login_recover">Відновити</string> <string name="login_signed_in">Учень вже увійшов до системи</string> <!--Main--> @@ -73,15 +76,15 @@ <string name="grade_header">Оцінка</string> <string name="grade_semester">%d семестр</string> <string name="grade_switch_semester">Змінити семестр</string> - <string name="grade_no_items">Брак оцінок</string> + <string name="grade_no_items">Оцінки відсутні</string> <string name="grade_weight">Вартість</string> <string name="grade_weight_value">Вартість: %s</string> <string name="grade_comment">Коментар</string> - <string name="grade_no_new_items">Брак нових оцінок</string> + <string name="grade_no_new_items">Нові оцінки відсутні</string> <string name="grade_number_new_items">Кількість нових оцінок: %1$d</string> <string name="grade_average">Середня оцінка: %1$.2f</string> - <string name="grade_points_sum">точок: %s</string> - <string name="grade_no_average">Брак середньої оцінки</string> + <string name="grade_points_sum">Балів: %s</string> + <string name="grade_no_average">Відсутність середньої оцінки</string> <string name="grade_predicted">Очікувана оцінка: %1$s</string> <string name="grade_final">Підсумкова оцінка: %1$s</string> <string name="grade_summary_points">Сума балів</string> @@ -95,6 +98,10 @@ <string name="grade_statistics_partial">Поточні</string> <string name="grade_statistics_semester">Семестрові</string> <string name="grade_statistics_points">Бали</string> + <string name="grade_statistics_legend">Умовні позначення</string> + <string name="grade_statistics_average">Середня оцінка: %1$s</string> + <string name="grade_statistics_average_class">Клас</string> + <string name="grade_statistics_average_student">Учень</string> <plurals name="grade_number_item"> <item quantity="one">%d оцінка</item> <item quantity="few">%d оцінки</item> @@ -160,9 +167,9 @@ <string name="completed_lessons_absence">Відсутність</string> <string name="completed_lessons_resources">Ресурси</string> <!--Additional lessons--> - <string name="additional_lessons_title">Additional lessons</string> - <string name="additional_lessons_button">Show additional lessons</string> - <string name="additional_lessons_no_items">No info about additional lessons</string> + <string name="additional_lessons_title">Додаткові уроки</string> + <string name="additional_lessons_button">Показати додаткові уроки</string> + <string name="additional_lessons_no_items">Немає інформації про додаткових уроків</string> <!--Attendance--> <string name="attendance_summary_button">Підсумок відвідуваності</string> <string name="attendance_absence_school">Відсутність зі шкільних причин</string> @@ -215,7 +222,7 @@ <string name="message_subject">Тема</string> <string name="message_content">Зміст</string> <string name="message_send_successful">Повідомлення було успішно відправлено</string> - <string name="message_not_exists">Message does not exist</string> + <string name="message_not_exists">Такого повідомлення не існує</string> <string name="message_required_recipients">Необхідно обрати принаймні 1 адресата</string> <string name="message_content_min_length">Зміст повідомлення мусить складатися принаймні з 3 знаків</string> <plurals name="message_number_item"> @@ -343,6 +350,13 @@ <string name="account_type_parent">Головний рахунок</string> <string name="account_login_mobile_api">Режим мобільного API</string> <string name="account_login_hybrid">Гібридний режим</string> + <string name="account_details_edit">Редагувати дані</string> + <string name="account_quick_manager">Менеджер аккаунтів</string> + <string name="account_select_student">Виберіть учня</string> + <string name="account_family">Сім\'я</string> + <string name="account_contact">Контакт</string> + <string name="account_address">Деталі проживання</string> + <string name="account_personal_data">Особиста інформація</string> <!--About--> <string name="about_version">Версія додатка</string> <string name="about_contributor">Розробники</string> @@ -366,6 +380,30 @@ <!--Contributor--> <string name="contributor_avatar_description">Аватар</string> <string name="contributor_see_more">Сторінка проекту на GitHub</string> + <!--Student info--> + <string name="student_info_empty">Брак інформації про учня</string> + <string name="student_info_first_name">Ім\'я</string> + <string name="student_info_second_name">Друге ім\'я</string> + <string name="student_info_gender">Стать</string> + <string name="student_info_polish_citizenship">Польське громадянство</string> + <string name="student_info_family_name">Прізвище</string> + <string name="student_info_parents_name">Імена батька і матері</string> + <string name="student_info_phone">Номер телефону</string> + <string name="student_info_cellphone">Мобільний телефон</string> + <string name="student_info_email">Електронна пошта</string> + <string name="student_info_address">Місця проживання</string> + <string name="student_info_registered_address">Адреса реєстрації</string> + <string name="student_info_correspondence_address">Адреса для кореспонденції</string> + <string name="student_info_full_name">Прізвище та ім\'я</string> + <string name="student_info_kinship">Ступінь спорідненості</string> + <string name="student_info_guardian_address">Адреса</string> + <string name="student_info_phones">Телефони</string> + <string name="student_info_male">Чоловіча</string> + <string name="student_info_female">Жінка</string> + <string name="student_info_last_name">Прізвище</string> + <!--Account edit--> + <string name="account_edit_nick_hint">Псевдонім</string> + <string name="account_edit_header">Додати псевдонім</string> <!--Log viewer--> <string name="logviewer_share">Поділитися логами</string> <string name="logviewer_refresh">Оновити</string> @@ -390,6 +428,9 @@ <string name="all_next">Наступний</string> <string name="all_search">Пошук</string> <string name="all_search_hint">Пошук…</string> + <string name="all_yes">Так</string> + <string name="all_no">Ні</string> + <string name="all_save">Зберегти</string> <!--Timetable Widget--> <string name="widget_timetable_no_items">Брак уроків</string> <string name="widget_timetable_theme_title">Увібрати тему</string> From dfa10883d32958f4b6b7f9db2f3de210e67bd1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= <m.pich@outlook.com> Date: Tue, 2 Feb 2021 00:47:30 +0100 Subject: [PATCH 28/28] Version 0.25.0 --- app/build.gradle | 8 ++++---- app/src/main/play/release-notes/pl-PL/default.txt | 12 +++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0d42ad71..f2efb421 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 17 targetSdkVersion 30 - versionCode 81 - versionName "0.24.3" + versionCode 82 + versionName "0.25.0" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -129,7 +129,7 @@ play { serviceAccountCredentials = file('key.p12') defaultToAppBundles = false track = 'alpha' - updatePriority = 5 + updatePriority = 3 } ext { @@ -142,7 +142,7 @@ ext { } dependencies { - implementation "io.github.wulkanowy:sdk:b7576e86" + implementation "io.github.wulkanowy:sdk:0.25.0" coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt index 1af17e0e..e33059d8 100644 --- a/app/src/main/play/release-notes/pl-PL/default.txt +++ b/app/src/main/play/release-notes/pl-PL/default.txt @@ -1,9 +1,7 @@ -Wersja 0.24.3 -- naprawiliśmy odczytywanie wiadomości -- naprawiliśmy niekończące się ładowanie w ocenach na drugim semestrze -- naprawiliśmy ciemny motyw na MIUI 12 -- dodaliśmy automatyczne odświeżanie danych w aplikacji -- naprawiliśmy wysyłanie wiadomości kiedy uczeń zalogowany był/jest przez konto ucznia i rodzica -- dodaliśmy zakładkę lekcji dodatkowych (na górnym pasku w planie lekcji) +Wersja 0.25.0 +- naprawiliśmy przełączanie semestrów przy przełączaniu uczniów +- naprawiliśmy błąd przy odświeżaniu ocen gdy włączony był inny niż domyślny tryb liczenia średniej +- dodaliśmy menadżer kont, gdzie można podejrzeć informacje o uczniu oraz zmienić pseudonim +- zmieniliśmy ikonę planu lekcji oraz kolor animacji odświeżania w ciemnym motywie Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases