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 &#160;<b>Uczeń</b> → &#160;<b>Dostęp Mobilny</b> → &#160;<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">Этот символ можно найти на странице регистрации в &#160;<b>Uczeń</b> → &#160;<b>Dostęp Mobilny</b> → &#160;<b>Zarejestruj urządzenie mobilne</b>.\n\nУбедитесь, что вы установили соответствующий вариант регистра в поле <b>Разновидностью бревна UONET+</b> на предыдущем экране. Wulkanowy на данный момент не обнаруживает дошкольников</string>
+    <string name="login_symbol_helper">Этот символ можно найти на странице регистрации в &#160;<b>Ученик</b> → &#160;<b>Телефонный доступ</b> → &#160;<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&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b> →&#160;<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">Символ можна знайти на сторінці реєстру в &#160; <b> Uczeń </b> → &#160; <b> Dostęp Mobilny </b> → &#160; <b> Zarejestruj urządzenie mobilne </b>.\n\nПереконайтесь, що ви встановили відповідний варіант реєстру в полі <b> UONET + варіант реєстрації </b> на попередньому екрані. На даний момент Wulkanowy не виявляє учнів дошкільних закладів</string>
+    <string name="login_symbol_helper">Символ можна знайти на сторінці реєстру в &#160; <b> Учень </b> → &#160; <b> Мобільний доступ </b> → &#160; <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