Merge branch 'release/1.2.2'

This commit is contained in:
Mikołaj Pich 2021-09-13 14:53:32 +02:00
commit 6a00e75816
27 changed files with 154 additions and 110 deletions

View File

@ -71,4 +71,4 @@ jobs:
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }} PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }} PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }} PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
run: ./gradlew assembleHmsRelease --stacktrace && ./gradlew publishHuaweiAppGalleryHmsRelease --stacktrace run: ./gradlew bundleHmsRelease --stacktrace && ./gradlew publishHuaweiAppGalleryHmsRelease --stacktrace

View File

@ -21,8 +21,8 @@ android {
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 30
versionCode 94 versionCode 95
versionName "1.2.1" versionName "1.2.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
@ -141,14 +141,14 @@ huaweiPublish {
instances { instances {
hmsRelease { hmsRelease {
credentialsPath = "$rootDir/app/src/release/agconnect-credentials.json" credentialsPath = "$rootDir/app/src/release/agconnect-credentials.json"
buildFormat = "apk" buildFormat = "aab"
deployType = "draft" deployType = "draft"
} }
} }
} }
ext { ext {
work_manager = "2.5.0" work_manager = "2.6.0"
android_hilt = "1.0.0" android_hilt = "1.0.0"
room = "2.3.0" room = "2.3.0"
chucker = "3.5.2" chucker = "3.5.2"
@ -157,7 +157,7 @@ ext {
} }
dependencies { dependencies {
implementation "io.github.wulkanowy:sdk:1.2.1" implementation "io.github.wulkanowy:sdk:1.2.2"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
@ -177,7 +177,7 @@ dependencies {
implementation "androidx.constraintlayout:constraintlayout:2.1.0" implementation "androidx.constraintlayout:constraintlayout:2.1.0"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0" implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.4.0" implementation "com.google.android.material:material:1.4.0"
implementation "com.github.wulkanowy:material-chips-input:2.2.0" implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0" implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.github.lopspower:CircularImageView:4.2.0' implementation 'com.github.lopspower:CircularImageView:4.2.0'

View File

@ -119,11 +119,9 @@
<receiver android:name=".services.alarm.TimetableNotificationReceiver" /> <receiver android:name=".services.alarm.TimetableNotificationReceiver" />
<provider <provider
android:name="androidx.work.impl.WorkManagerInitializer" android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.workmanager-init" android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="remove" /> tools:node="remove" />
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider" android:authorities="${applicationId}.fileprovider"

View File

@ -14,33 +14,39 @@ import javax.inject.Singleton
@Singleton @Singleton
@Dao @Dao
interface StudentDao { abstract class StudentDao {
@Insert(onConflict = ABORT) @Insert(onConflict = ABORT)
suspend fun insertAll(student: List<Student>): List<Long> abstract suspend fun insertAll(student: List<Student>): List<Long>
@Delete @Delete
suspend fun delete(student: Student) abstract suspend fun delete(student: Student)
@Update(entity = Student::class) @Update(entity = Student::class)
suspend fun update(studentNickAndAvatar: StudentNickAndAvatar) abstract suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
@Query("SELECT * FROM Students WHERE is_current = 1") @Query("SELECT * FROM Students WHERE is_current = 1")
suspend fun loadCurrent(): Student? abstract suspend fun loadCurrent(): Student?
@Query("SELECT * FROM Students WHERE id = :id") @Query("SELECT * FROM Students WHERE id = :id")
suspend fun loadById(id: Long): Student? abstract suspend fun loadById(id: Long): Student?
@Query("SELECT * FROM Students") @Query("SELECT * FROM Students")
suspend fun loadAll(): List<Student> abstract suspend fun loadAll(): List<Student>
@Transaction @Transaction
@Query("SELECT * FROM Students") @Query("SELECT * FROM Students")
suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters> abstract suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
@Query("UPDATE Students SET is_current = 1 WHERE id = :id") @Query("UPDATE Students SET is_current = 1 WHERE id = :id")
suspend fun updateCurrent(id: Long) abstract suspend fun updateCurrent(id: Long)
@Query("UPDATE Students SET is_current = 0") @Query("UPDATE Students SET is_current = 0")
suspend fun resetCurrent() abstract suspend fun resetCurrent()
@Transaction
open suspend fun switchCurrent(id: Long) {
resetCurrent()
updateCurrent(id)
}
} }

View File

@ -1,7 +1,9 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import android.content.Context import android.content.Context
import androidx.room.withTransaction
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
@ -25,7 +27,8 @@ class StudentRepository @Inject constructor(
private val studentDb: StudentDao, private val studentDb: StudentDao,
private val semesterDb: SemesterDao, private val semesterDb: SemesterDao,
private val sdk: Sdk, private val sdk: Sdk,
private val appInfo: AppInfo private val appInfo: AppInfo,
private val appDatabase: AppDatabase
) { ) {
suspend fun isStudentSaved() = getSavedStudents(false).isNotEmpty() suspend fun isStudentSaved() = getSavedStudents(false).isNotEmpty()
@ -92,7 +95,7 @@ class StudentRepository @Inject constructor(
return student return student
} }
suspend fun saveStudents(studentsWithSemesters: List<StudentWithSemesters>): List<Long> { suspend fun saveStudents(studentsWithSemesters: List<StudentWithSemesters>) {
val semesters = studentsWithSemesters.flatMap { it.semesters } val semesters = studentsWithSemesters.flatMap { it.semesters }
val students = studentsWithSemesters.map { it.student } val students = studentsWithSemesters.map { it.student }
.map { .map {
@ -104,16 +107,21 @@ class StudentRepository @Inject constructor(
} }
} }
} }
.mapIndexed { index, student ->
if (index == 0) {
student.copy(isCurrent = true).apply { avatarColor = student.avatarColor }
} else student
}
appDatabase.withTransaction {
studentDb.resetCurrent()
semesterDb.insertSemesters(semesters) semesterDb.insertSemesters(semesters)
return studentDb.insertAll(students) studentDb.insertAll(students)
}
} }
suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) { suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) {
with(studentDb) { studentDb.switchCurrent(studentWithSemesters.student.id)
resetCurrent()
updateCurrent(studentWithSemesters.student.id)
}
} }
suspend fun logoutStudent(student: Student) = studentDb.delete(student) suspend fun logoutStudent(student: Student) = studentDb.delete(student)

View File

@ -245,7 +245,9 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
} }
datePicker.show(this@AttendanceFragment.parentFragmentManager, null) if (!parentFragmentManager.isStateSaved) {
datePicker.show(parentFragmentManager, null)
}
} }
override fun showExcuseDialog() { override fun showExcuseDialog() {

View File

@ -152,6 +152,8 @@ class AttendancePresenter @Inject constructor(
fun onExcuseDialogSubmit(reason: String) { fun onExcuseDialogSubmit(reason: String) {
view?.finishActionMode() view?.finishActionMode()
if (attendanceToExcuseList.isEmpty()) return
if (isVulcanExcusedFunctionEnabled) { if (isVulcanExcusedFunctionEnabled) {
excuseAbsence( excuseAbsence(
reason = reason.takeIf { it.isNotBlank() }, reason = reason.takeIf { it.isNotBlank() },
@ -234,6 +236,7 @@ class AttendancePresenter @Inject constructor(
enableSwipe(true) enableSwipe(true)
showRefresh(true) showRefresh(true)
showProgress(false) showProgress(false)
showErrorView(false)
showEmpty(filteredAttendance.isEmpty()) showEmpty(filteredAttendance.isEmpty())
showContent(filteredAttendance.isNotEmpty()) showContent(filteredAttendance.isNotEmpty())
updateData(filteredAttendance.sortedBy { item -> item.number }) updateData(filteredAttendance.sortedBy { item -> item.number })

View File

@ -82,7 +82,13 @@ class AttendanceSummaryPresenter @Inject constructor(
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
attendanceSummaryRepository.getAttendanceSummary(student, semester, subjectId, forceRefresh)
attendanceSummaryRepository.getAttendanceSummary(
student = student,
semester = semester,
subjectId = subjectId,
forceRefresh = forceRefresh
)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> { Status.LOADING -> {
@ -92,6 +98,7 @@ class AttendanceSummaryPresenter @Inject constructor(
showRefresh(true) showRefresh(true)
showProgress(false) showProgress(false)
showContent(true) showContent(true)
showErrorView(false)
updateDataSet(sortItems(it.data)) updateDataSet(sortItems(it.data))
} }
} }
@ -99,6 +106,7 @@ class AttendanceSummaryPresenter @Inject constructor(
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading attendance summary result: Success") Timber.i("Loading attendance summary result: Success")
view?.apply { view?.apply {
showErrorView(false)
showEmpty(it.data!!.isEmpty()) showEmpty(it.data!!.isEmpty())
showContent(it.data.isNotEmpty()) showContent(it.data.isNotEmpty())
updateDataSet(sortItems(it.data)) updateDataSet(sortItems(it.data))

View File

@ -31,6 +31,7 @@ import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.left import io.github.wulkanowy.utils.left
import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.nickOrName
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import timber.log.Timber
import java.time.Duration import java.time.Duration
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
@ -170,6 +171,8 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
val isLoading = item.isLoading val isLoading = item.isLoading
val binding = horizontalGroupViewHolder.binding val binding = horizontalGroupViewHolder.binding
val context = binding.root.context val context = binding.root.context
val isLoadingVisible =
(isLoading && !item.isDataLoaded) || (isLoading && !item.isFullDataLoaded)
val attendanceColor = when { val attendanceColor = when {
attendancePercentage == null || attendancePercentage == .0 -> { attendancePercentage == null || attendancePercentage == .0 -> {
context.getThemeAttrColor(R.attr.colorOnSurface) context.getThemeAttrColor(R.attr.colorOnSurface)
@ -199,13 +202,12 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
context.getString(R.string.dashboard_horizontal_group_no_data) context.getString(R.string.dashboard_horizontal_group_no_data)
} else luckyNumber?.toString() } else luckyNumber?.toString()
dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoading dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoadingVisible
dashboardHorizontalGroupItemInfoProgress.isVisible = dashboardHorizontalGroupItemInfoProgress.isVisible = isLoadingVisible
(isLoading && !item.isDataLoaded) || (isLoading && !item.isFullDataLoaded)
dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null
with(dashboardHorizontalGroupItemLuckyContainer) { with(dashboardHorizontalGroupItemLuckyContainer) {
isVisible = luckyNumber != null && luckyNumber != -1 isVisible = luckyNumber != null && luckyNumber != -1 && !isLoadingVisible
setOnClickListener { onLuckyNumberTileClickListener() } setOnClickListener { onLuckyNumberTileClickListener() }
updateLayoutParams<ViewGroup.MarginLayoutParams> { updateLayoutParams<ViewGroup.MarginLayoutParams> {
@ -220,7 +222,8 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
} }
with(dashboardHorizontalGroupItemAttendanceContainer) { with(dashboardHorizontalGroupItemAttendanceContainer) {
isVisible = attendancePercentage != null && attendancePercentage != -1.0 isVisible =
attendancePercentage != null && attendancePercentage != -1.0 && !isLoadingVisible
updateLayoutParams<ConstraintLayout.LayoutParams> { updateLayoutParams<ConstraintLayout.LayoutParams> {
matchConstraintPercentWidth = when { matchConstraintPercentWidth = when {
luckyNumber == null && unreadMessagesCount == null -> 1.0f luckyNumber == null && unreadMessagesCount == null -> 1.0f
@ -232,7 +235,8 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
} }
with(dashboardHorizontalGroupItemMessageContainer) { with(dashboardHorizontalGroupItemMessageContainer) {
isVisible = unreadMessagesCount != null && unreadMessagesCount != -1 isVisible =
unreadMessagesCount != null && unreadMessagesCount != -1 && !isLoadingVisible
setOnClickListener { onMessageTileClickListener() } setOnClickListener { onMessageTileClickListener() }
} }
} }
@ -426,7 +430,10 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
} }
} }
} else { } else {
val minutesToEndLesson = firstLesson.left!!.toMinutes() + 1 val minutesToEndLesson = firstLesson.left?.toMinutes()?.plus(1) ?: run {
Timber.e(IllegalArgumentException("Lesson left is null. START ${firstLesson.start} ; END ${firstLesson.end} ; CURRENT ${LocalDateTime.now()}"))
0
}
firstTimeText = context.resources.getQuantityString( firstTimeText = context.resources.getQuantityString(
R.plurals.dashboard_timetable_first_lesson_time_more_minutes, R.plurals.dashboard_timetable_first_lesson_time_more_minutes,

View File

@ -90,10 +90,10 @@ class LoginFormPresenter @Inject constructor(
flowWithResource { flowWithResource {
studentRepository.getStudentsScrapper( studentRepository.getStudentsScrapper(
email, email = email,
password, password = password,
host, scrapperBaseUrl = host,
symbol symbol = symbol
) )
}.onEach { }.onEach {
when (it.status) { when (it.status) {

View File

@ -78,7 +78,9 @@ class LoginStudentSelectPresenter @Inject constructor(
when (it.status) { when (it.status) {
Status.LOADING -> Timber.d("Login student select students load started") Status.LOADING -> Timber.d("Login student select students load started")
Status.SUCCESS -> view?.updateData(studentsWithSemesters.map { studentWithSemesters -> Status.SUCCESS -> view?.updateData(studentsWithSemesters.map { studentWithSemesters ->
studentWithSemesters to it.data!!.any { item -> compareStudents(studentWithSemesters.student, item.student) } studentWithSemesters to it.data!!.any { item ->
compareStudents(studentWithSemesters.student, item.student)
}
}) })
Status.ERROR -> { Status.ERROR -> {
errorHandler.dispatch(it.error!!) errorHandler.dispatch(it.error!!)
@ -95,11 +97,8 @@ class LoginStudentSelectPresenter @Inject constructor(
} }
private fun registerStudents(studentsWithSemesters: List<StudentWithSemesters>) { private fun registerStudents(studentsWithSemesters: List<StudentWithSemesters>) {
flowWithResource { flowWithResource { studentRepository.saveStudents(studentsWithSemesters) }
val savedStudents = studentRepository.saveStudents(studentsWithSemesters) .onEach {
val firstRegistered = studentsWithSemesters.first().apply { student.id = savedStudents.first() }
studentRepository.switchStudent(firstRegistered)
}.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> view?.run { Status.LOADING -> view?.run {
Timber.i("Registration started") Timber.i("Registration started")
@ -134,7 +133,10 @@ class LoginStudentSelectPresenter @Inject constructor(
view?.openEmail(lastError?.message.ifNullOrBlank { "empty" }) view?.openEmail(lastError?.message.ifNullOrBlank { "empty" })
} }
private fun logRegisterEvent(studentsWithSemesters: List<StudentWithSemesters>, error: Throwable? = null) { private fun logRegisterEvent(
studentsWithSemesters: List<StudentWithSemesters>,
error: Throwable? = null
) {
studentsWithSemesters.forEach { student -> studentsWithSemesters.forEach { student ->
analytics.logEvent( analytics.logEvent(
"registration_student_select", "registration_student_select",

View File

@ -131,7 +131,9 @@ class LuckyNumberHistoryFragment :
presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
} }
datePicker.show(this@LuckyNumberHistoryFragment.parentFragmentManager, null) if (!parentFragmentManager.isStateSaved) {
datePicker.show(parentFragmentManager, null)
}
} }
override fun showContent(show: Boolean) { override fun showContent(show: Boolean) {

View File

@ -117,6 +117,7 @@ class MessageTabPresenter @Inject constructor(
if (!it.data.isNullOrEmpty()) { if (!it.data.isNullOrEmpty()) {
view?.run { view?.run {
enableSwipe(true) enableSwipe(true)
showErrorView(false)
showRefresh(true) showRefresh(true)
showProgress(false) showProgress(false)
showContent(true) showContent(true)

View File

@ -11,6 +11,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
import io.github.wulkanowy.ui.modules.exam.ExamFragment import io.github.wulkanowy.ui.modules.exam.ExamFragment
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.message.MessageFragment import io.github.wulkanowy.ui.modules.message.MessageFragment
@ -66,6 +67,9 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
override val examRes: Pair<String, Drawable?>? override val examRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.exam_title) to getCompatDrawable(R.drawable.ic_main_exam) } get() = context?.run { getString(R.string.exam_title) to getCompatDrawable(R.drawable.ic_main_exam) }
override val luckyNumberRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.lucky_number_title) to getCompatDrawable(R.drawable.ic_more_lucky_number) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding = FragmentMoreBinding.bind(view) binding = FragmentMoreBinding.bind(view)
@ -128,6 +132,10 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
(activity as? MainActivity)?.pushView(ExamFragment.newInstance()) (activity as? MainActivity)?.pushView(ExamFragment.newInstance())
} }
override fun openLuckyNumberView() {
(activity as? MainActivity)?.pushView(LuckyNumberFragment.newInstance())
}
override fun popView(depth: Int) { override fun popView(depth: Int) {
(activity as? MainActivity)?.popView(depth) (activity as? MainActivity)?.popView(depth)
} }

View File

@ -31,6 +31,7 @@ class MorePresenter @Inject constructor(
schoolAndTeachersRes?.first -> openSchoolAndTeachersView() schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
mobileDevicesRes?.first -> openMobileDevicesView() mobileDevicesRes?.first -> openMobileDevicesView()
settingsRes?.first -> openSettingsView() settingsRes?.first -> openSettingsView()
luckyNumberRes?.first -> openLuckyNumberView()
} }
} }
} }
@ -48,6 +49,7 @@ class MorePresenter @Inject constructor(
examRes, examRes,
homeworkRes, homeworkRes,
noteRes, noteRes,
luckyNumberRes,
conferencesRes, conferencesRes,
schoolAnnouncementRes, schoolAnnouncementRes,
schoolAndTeachersRes, schoolAndTeachersRes,

View File

@ -23,6 +23,8 @@ interface MoreView : BaseView {
val examRes: Pair<String, Drawable?>? val examRes: Pair<String, Drawable?>?
val luckyNumberRes: Pair<String, Drawable?>?
fun initView() fun initView()
fun updateData(data: List<Pair<String, Drawable?>>) fun updateData(data: List<Pair<String, Drawable?>>)
@ -46,4 +48,6 @@ interface MoreView : BaseView {
fun openMobileDevicesView() fun openMobileDevicesView()
fun openExamView() fun openExamView()
fun openLuckyNumberView()
} }

View File

@ -64,6 +64,7 @@ class SchoolAnnouncementPresenter @Inject constructor(
view?.run { view?.run {
enableSwipe(true) enableSwipe(true)
showRefresh(true) showRefresh(true)
showErrorView(false)
showProgress(false) showProgress(false)
showContent(true) showContent(true)
updateData(it.data) updateData(it.data)

View File

@ -202,7 +202,9 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
} }
datePicker.show(this@TimetableFragment.parentFragmentManager, null) if (!parentFragmentManager.isStateSaved) {
datePicker.show(parentFragmentManager, null)
}
} }
override fun openAdditionalLessonsView() { override fun openAdditionalLessonsView() {

View File

@ -149,6 +149,7 @@ class TimetablePresenter @Inject constructor(
view?.run { view?.run {
enableSwipe(true) enableSwipe(true)
showRefresh(true) showRefresh(true)
showErrorView(false)
showProgress(false) showProgress(false)
showContent(true) showContent(true)
updateData(it.data!!.lessons) updateData(it.data!!.lessons)

View File

@ -152,7 +152,9 @@ class AdditionalLessonsFragment :
presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
} }
datePicker.show(this@AdditionalLessonsFragment.parentFragmentManager, null) if (!parentFragmentManager.isStateSaved) {
datePicker.show(parentFragmentManager, null)
}
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {

View File

@ -173,7 +173,9 @@ class CompletedLessonsFragment :
presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
} }
datePicker.show(this@CompletedLessonsFragment.parentFragmentManager, null) if (!parentFragmentManager.isStateSaved) {
datePicker.show(parentFragmentManager, null)
}
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {

View File

@ -102,8 +102,10 @@ fun Context.openNavigation(location: String) {
fun Context.openDialer(phone: String) { fun Context.openDialer(phone: String) {
val intentUri = Uri.parse("tel:$phone") val intentUri = Uri.parse("tel:$phone")
val intent = Intent(Intent.ACTION_DIAL, intentUri) val intent = Intent(Intent.ACTION_DIAL, intentUri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent) startActivity(intent)
} }
}
fun Context.shareText(text: String, subject: String?) { fun Context.shareText(text: String, subject: String?) {
val sendIntent: Intent = Intent().apply { val sendIntent: Intent = Intent().apply {

View File

@ -2,7 +2,6 @@ package io.github.wulkanowy.utils
import com.google.android.material.datepicker.CalendarConstraints import com.google.android.material.datepicker.CalendarConstraints
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import java.time.DayOfWeek
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
@Parcelize @Parcelize
@ -12,7 +11,6 @@ class SchoolDaysValidator(val start: Long, val end: Long) : CalendarConstraints.
val date = dateLong.toLocalDateTime() val date = dateLong.toLocalDateTime()
return date.until(end.toLocalDateTime(), ChronoUnit.DAYS) >= 0 && return date.until(end.toLocalDateTime(), ChronoUnit.DAYS) >= 0 &&
date.until(start.toLocalDateTime(), ChronoUnit.DAYS) <= 0 && date.until(start.toLocalDateTime(), ChronoUnit.DAYS) <= 0
date.dayOfWeek != DayOfWeek.SUNDAY
} }
} }

View File

@ -1,7 +1,8 @@
Wersja 1.2.1 Wersja 1.2.2
- dodaliśmy brakujące okienka z podglądem szczegółów ogłoszeń szkolnych - naprawiliśmy problem z widocznością zadań w aplikacji gdy widoczne są one na stronie www dziennika (nadal pozostaje błąd z zadaniami widocznymi tylko w oficjalnej aplikacji - czekamy na poprawkę po stronie VULCANa)
- naprawiliśmy rzucające się w oczy błędy na ekranie startowym - odblokowaliśmy niedzielę w wyborze daty w planie lekcji i innych zakładkach
- naprawiliśmy też inne drobne błędy w wyglądzie i stabilności aplikacji - przywróciliśmy odnośnik do szczęśliwego numerka w menu Więcej
- naprawiliśmy drobne błędy ze stabilnością i wyglądem
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -69,7 +69,7 @@
<string name="login_contact_discord">Discord</string> <string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Send email</string> <string name="login_email_intent_title">Send email</string>
<string name="login_email_subject" translatable="false">Zgłoszenie: Problemy z logowaniem</string> <string name="login_email_subject" translatable="false">Zgłoszenie: Problemy z logowaniem</string>
<string name="login_email_text" translatable="false">Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nOpis problemu: </string> <string name="login_email_text" translatable="false">Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nOpis problemu (pełna nazwa szkoły, klasa ucznia): </string>
<string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string> <string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string>
<string name="login_recover_button">I forgot my password</string> <string name="login_recover_button">I forgot my password</string>
<string name="login_recover_title">Recover your account</string> <string name="login_recover_title">Recover your account</string>

View File

@ -37,7 +37,8 @@ class StudentTest {
studentDb, studentDb,
semesterDb, semesterDb,
mockSdk, mockSdk,
AppInfo() AppInfo(),
mockk()
) )
} }

View File

@ -89,24 +89,11 @@ class LoginStudentSelectPresenterTest {
@Test @Test
fun onSelectedStudentTest() { fun onSelectedStudentTest() {
coEvery { coEvery {
studentRepository.saveStudents( studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList())))
listOf(
StudentWithSemesters(
testStudent,
emptyList()
)
)
)
} returns listOf(1L)
coEvery {
studentRepository.switchStudent(
StudentWithSemesters(
testStudent,
emptyList()
)
)
} just Runs } just Runs
every { loginStudentSelectView.openMainView() } just Runs every { loginStudentSelectView.openMainView() } just Runs
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false) presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
presenter.onSignIn() presenter.onSignIn()
@ -118,18 +105,14 @@ class LoginStudentSelectPresenterTest {
@Test @Test
fun onSelectedStudentErrorTest() { fun onSelectedStudentErrorTest() {
coEvery { coEvery {
studentRepository.saveStudents( studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList())))
listOf(
StudentWithSemesters(
testStudent,
emptyList()
)
)
)
} throws testException } throws testException
coEvery { studentRepository.logoutStudent(testStudent) } just Runs coEvery { studentRepository.logoutStudent(testStudent) } just Runs
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false) presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
presenter.onSignIn() presenter.onSignIn()
verify { loginStudentSelectView.showContent(false) } verify { loginStudentSelectView.showContent(false) }
verify { loginStudentSelectView.showProgress(true) } verify { loginStudentSelectView.showProgress(true) }
verify { errorHandler.dispatch(match { testException.message == it.message }) } verify { errorHandler.dispatch(match { testException.message == it.message }) }