")
.replace(Regex("[\\n\\r]"), " ")
val jobName = buildString {
@@ -171,9 +167,7 @@ class MessagePreviewPresenter @Inject constructor(
}
view?.apply {
- val html = printHTML
- .replace("%SUBJECT%", subject)
- .replace("%CONTENT%", messageContent)
+ val html = printHTML.replace("%SUBJECT%", subject).replace("%CONTENT%", messageContent)
.replace("%INFO%", infoContent)
printDocument(html, jobName)
}
@@ -181,34 +175,69 @@ class MessagePreviewPresenter @Inject constructor(
return true
}
- private fun deleteMessage() {
- message ?: return
+ private fun restoreMessage() {
+ val message = messageWithAttachments?.message ?: return
view?.run {
showContent(false)
showProgress(true)
- showOptions(show = false, isReplayable = false)
+ showOptions(
+ show = false,
+ isReplayable = false,
+ isRestorable = false,
+ )
showErrorView(false)
}
-
- Timber.i("Delete message ${message?.messageGlobalKey}")
-
+ Timber.i("Restore message ${message.messageGlobalKey}")
presenterScope.launch {
runCatching {
val student = studentRepository.getCurrentStudent(decryptPass = true)
val mailbox = messageRepository.getMailboxByStudent(student)
- messageRepository.deleteMessage(student, mailbox, message!!)
+ messageRepository.restoreMessages(student, mailbox, listOfNotNull(message))
}
.onFailure {
- retryCallback = { onMessageDelete() }
+ retryCallback = { onMessageRestore() }
errorHandler.dispatch(it)
}
.onSuccess {
view?.run {
- showMessage(deleteMessageSuccessString)
+ showMessage(restoreMessageSuccessString)
popView()
}
}
+ view?.showProgress(false)
+ }
+ }
+
+ private fun deleteMessage() {
+ messageWithAttachments?.message ?: return
+
+ view?.run {
+ showContent(false)
+ showProgress(true)
+ showOptions(
+ show = false,
+ isReplayable = false,
+ isRestorable = false,
+ )
+ showErrorView(false)
+ }
+
+ Timber.i("Delete message ${messageWithAttachments?.message?.messageGlobalKey}")
+
+ presenterScope.launch {
+ runCatching {
+ val student = studentRepository.getCurrentStudent(decryptPass = true)
+ messageRepository.deleteMessage(student, messageWithAttachments?.message!!)
+ }.onFailure {
+ retryCallback = { onMessageDelete() }
+ errorHandler.dispatch(it)
+ }.onSuccess {
+ view?.run {
+ showMessage(deleteMessageSuccessString)
+ popView()
+ }
+ }
view?.showProgress(false)
}
@@ -224,6 +253,11 @@ class MessagePreviewPresenter @Inject constructor(
}
}
+ fun onMessageRestore(): Boolean {
+ restoreMessage()
+ return true
+ }
+
fun onMessageDelete(): Boolean {
deleteMessage()
return true
@@ -232,20 +266,39 @@ class MessagePreviewPresenter @Inject constructor(
private fun initOptions() {
view?.apply {
showOptions(
- show = message != null,
- isReplayable = message?.folderId != MessageFolder.SENT.id,
+ show = messageWithAttachments?.message != null,
+ isReplayable = messageWithAttachments?.message?.folderId == MessageFolder.RECEIVED.id,
+ isRestorable = messageWithAttachments?.message?.folderId == MessageFolder.TRASHED.id,
)
- message?.let {
- when (it.folderId == MessageFolder.TRASHED.id) {
- true -> setDeletedOptionsLabels()
- false -> setNotDeletedOptionsLabels()
- }
- }
-
}
}
fun onCreateOptionsMenu() {
initOptions()
}
+
+ fun onMute(): Boolean {
+ val message = messageWithAttachments?.message ?: return false
+ val isMuted = messageWithAttachments?.mutedMessageSender != null
+
+ presenterScope.launch {
+ runCatching {
+ when (isMuted) {
+ true -> {
+ messageRepository.unmuteMessage(message.correspondents)
+ view?.run { showMessage(unmuteMessageSuccessString) }
+ }
+
+ false -> {
+ messageRepository.muteMessage(message.correspondents)
+ view?.run { showMessage(muteMessageSuccessString) }
+ }
+ }
+ }.onFailure {
+ errorHandler.dispatch(it)
+ }
+ }
+ view?.updateMuteToggleButton(isMuted)
+ return true
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
index 7f5f140b2..ee0b6ce0a 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
@@ -9,6 +9,12 @@ interface MessagePreviewView : BaseView {
val deleteMessageSuccessString: String
+ val muteMessageSuccessString: String
+
+ val unmuteMessageSuccessString: String
+
+ val restoreMessageSuccessString: String
+
val messageNoSubjectString: String
val printHTML: String
@@ -19,6 +25,8 @@ interface MessagePreviewView : BaseView {
fun setMessageWithAttachment(item: MessageWithAttachment)
+ fun updateMuteToggleButton(isMuted: Boolean)
+
fun showProgress(show: Boolean)
fun showContent(show: Boolean)
@@ -29,11 +37,7 @@ interface MessagePreviewView : BaseView {
fun setErrorRetryCallback(callback: () -> Unit)
- fun showOptions(show: Boolean, isReplayable: Boolean)
-
- fun setDeletedOptionsLabels()
-
- fun setNotDeletedOptionsLabels()
+ fun showOptions(show: Boolean, isReplayable: Boolean, isRestorable: Boolean)
fun openMessageReply(message: Message?)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
index e776e9941..6155baea3 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
@@ -203,7 +203,7 @@ class SendMessagePresenter @Inject constructor(
subject = subject,
content = content,
recipients = recipients,
- mailboxId = mailbox.globalKey,
+ mailbox = mailbox,
)
}.logResourceStatus("sending message").onEach {
when (it) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
index 9792c7085..fadc77e6d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
@@ -18,8 +18,7 @@ import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.toFormattedString
import javax.inject.Inject
-class MessageTabAdapter @Inject constructor() :
- RecyclerView.Adapter() {
+class MessageTabAdapter @Inject constructor() : RecyclerView.Adapter() {
lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit
@@ -52,10 +51,11 @@ class MessageTabAdapter @Inject constructor() :
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
- return when (MessageItemViewType.values()[viewType]) {
+ return when (MessageItemViewType.entries[viewType]) {
MessageItemViewType.FILTERS -> HeaderViewHolder(
ItemMessageChipsBinding.inflate(inflater, parent, false)
)
+
MessageItemViewType.MESSAGE -> ItemViewHolder(
ItemMessageBinding.inflate(inflater, parent, false)
)
@@ -137,7 +137,12 @@ class MessageTabAdapter @Inject constructor() :
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(currentTextColor))
isVisible = message.hasAttachments
}
- messageItemUnreadIndicator.isVisible = message.unread
+ messageItemUnreadIndicator.isVisible = message.unread || item.isMuted
+
+ when (item.isMuted) {
+ true -> messageItemUnreadIndicator.setImageResource(R.drawable.ic_notifications_off)
+ else -> messageItemUnreadIndicator.setImageResource(R.drawable.ic_circle_notification)
+ }
root.setOnClickListener {
holder.bindingAdapterPosition.let {
@@ -165,8 +170,7 @@ class MessageTabAdapter @Inject constructor() :
RecyclerView.ViewHolder(binding.root)
private class MessageTabDiffUtil(
- private val old: List,
- private val new: List
+ private val old: List, private val new: List
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = old.size
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt
index c0bd4170e..ef640e040 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt
@@ -6,6 +6,7 @@ sealed class MessageTabDataItem(val viewType: MessageItemViewType) {
data class MessageItem(
val message: Message,
+ val isMuted: Boolean,
val isSelected: Boolean,
val isActionMode: Boolean
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
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 4364e8681..12f9d3234 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
@@ -5,7 +5,9 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
-import android.view.View.*
+import android.view.View.GONE
+import android.view.View.INVISIBLE
+import android.view.View.VISIBLE
import android.widget.CompoundButton
import androidx.annotation.StringRes
import androidx.appcompat.view.ActionMode
@@ -64,10 +66,12 @@ class MessageTabFragment : BaseFragment(R.layout.frag
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
- if (presenter.folder == MessageFolder.TRASHED) {
- val menuItem = menu.findItem(R.id.messageTabContextMenuDelete)
- menuItem.setTitle(R.string.message_delete_forever)
- }
+ val isTrashFolder = presenter.folder == MessageFolder.TRASHED
+
+ menu.findItem(R.id.messageTabContextMenuDelete).setVisible(!isTrashFolder)
+ menu.findItem(R.id.messageTabContextMenuDeleteForever).setVisible(isTrashFolder)
+ menu.findItem(R.id.messageTabContextMenuRestore).setVisible(isTrashFolder)
+
return presenter.onPrepareActionMode()
}
@@ -79,6 +83,8 @@ class MessageTabFragment : BaseFragment(R.layout.frag
override fun onActionItemClicked(mode: ActionMode, menu: MenuItem): Boolean {
when (menu.itemId) {
R.id.messageTabContextMenuDelete -> presenter.onActionModeSelectDelete()
+ R.id.messageTabContextMenuRestore -> presenter.onActionModeSelectRestore()
+ R.id.messageTabContextMenuDeleteForever -> presenter.onActionModeSelectDelete()
R.id.messageTabContextMenuSelectAll -> presenter.onActionModeSelectCheckAll()
}
return true
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
index 90f93b145..cda0b32bd 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
@@ -4,6 +4,7 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message
+import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.StudentRepository
@@ -39,7 +40,7 @@ class MessageTabPresenter @Inject constructor(
private var mailboxes: List = emptyList()
private var selectedMailbox: Mailbox? = null
- private var messages = emptyList()
+ private var messages = emptyList()
private val searchChannel = Channel()
@@ -120,8 +121,27 @@ class MessageTabPresenter @Inject constructor(
return true
}
+ fun onActionModeSelectRestore() {
+ Timber.i("Restore ${messagesToDelete.size} messages")
+ val messageList = messagesToDelete.toList()
+
+ presenterScope.launch {
+ view?.run {
+ showProgress(true)
+ showContent(false)
+ showActionMode(false)
+ }
+ runCatching {
+ val student = studentRepository.getCurrentStudent(true)
+ messageRepository.restoreMessages(student, selectedMailbox, messageList)
+ }
+ .onFailure(errorHandler::dispatch)
+ .onSuccess { view?.showMessage(R.string.message_messages_restored) }
+ }
+ }
+
fun onActionModeSelectDelete() {
- Timber.i("Delete ${messagesToDelete.size} messages)")
+ Timber.i("Delete ${messagesToDelete.size} messages")
val messageList = messagesToDelete.toList()
presenterScope.launch {
@@ -133,7 +153,7 @@ class MessageTabPresenter @Inject constructor(
runCatching {
val student = studentRepository.getCurrentStudent(true)
- messageRepository.deleteMessages(student, selectedMailbox, messageList)
+ messageRepository.deleteMessages(student, messageList)
}
.onFailure(errorHandler::dispatch)
.onSuccess { view?.showMessage(R.string.message_messages_deleted) }
@@ -141,7 +161,7 @@ class MessageTabPresenter @Inject constructor(
}
fun onActionModeSelectCheckAll() {
- val messagesToSelect = getFilteredData()
+ val messagesToSelect = getFilteredData().map { it.message }
val isAllSelected = messagesToDelete.containsAll(messagesToSelect)
if (isAllSelected) {
@@ -188,7 +208,7 @@ class MessageTabPresenter @Inject constructor(
view?.showActionMode(false)
}
- val filteredData = getFilteredData()
+ val filteredData = getFilteredData().map { it.message }
view?.run {
updateActionModeTitle(messagesToDelete.size)
@@ -320,25 +340,31 @@ class MessageTabPresenter @Inject constructor(
}
}
- private fun getFilteredData(): List {
+ private fun getFilteredData(): List {
if (lastSearchQuery.trim().isEmpty()) {
- val sortedMessages = messages.sortedByDescending { it.date }
+ val sortedMessages = messages.sortedByDescending { it.message.date }
return when {
- (onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter { it.unread == onlyUnread && it.hasAttachments == onlyWithAttachments }
- (onlyUnread == true) -> sortedMessages.filter { it.unread == onlyUnread }
- onlyWithAttachments -> sortedMessages.filter { it.hasAttachments == onlyWithAttachments }
+ (onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter {
+ it.message.unread == onlyUnread && it.message.hasAttachments == onlyWithAttachments
+ }
+
+ (onlyUnread == true) -> sortedMessages.filter { it.message.unread == onlyUnread }
+ onlyWithAttachments -> sortedMessages.filter { it.message.hasAttachments == onlyWithAttachments }
else -> sortedMessages
}
} else {
val sortedMessages = messages
- .map { it to calculateMatchRatio(it, lastSearchQuery) }
- .sortedWith(compareBy> { -it.second }.thenByDescending { it.first.date })
+ .map { it to calculateMatchRatio(it.message, lastSearchQuery) }
+ .sortedWith(compareBy> { -it.second }.thenByDescending { it.first.message.date })
.filter { it.second > 6000 }
.map { it.first }
return when {
- (onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter { it.unread == onlyUnread && it.hasAttachments == onlyWithAttachments }
- (onlyUnread == true) -> sortedMessages.filter { it.unread == onlyUnread }
- onlyWithAttachments -> sortedMessages.filter { it.hasAttachments == onlyWithAttachments }
+ (onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter {
+ it.message.unread == onlyUnread && it.message.hasAttachments == onlyWithAttachments
+ }
+
+ (onlyUnread == true) -> sortedMessages.filter { it.message.unread == onlyUnread }
+ onlyWithAttachments -> sortedMessages.filter { it.message.hasAttachments == onlyWithAttachments }
else -> sortedMessages
}
}
@@ -367,8 +393,9 @@ class MessageTabPresenter @Inject constructor(
addAll(data.map { message ->
MessageTabDataItem.MessageItem(
- message = message,
- isSelected = messagesToDelete.any { it.messageGlobalKey == message.messageGlobalKey },
+ message = message.message,
+ isMuted = message.mutedMessageSender != null,
+ isSelected = messagesToDelete.any { it.messageGlobalKey == message.message.messageGlobalKey },
isActionMode = isActionMode
)
})
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 19c4ef6b7..f8d1323c6 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
@@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.settings
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import io.github.wulkanowy.R
+import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.modules.main.MainView
import timber.log.Timber
@@ -26,6 +27,8 @@ class SettingsFragment : PreferenceFragmentCompat(), MainView.TitledView, Settin
override fun showExpiredCredentialsDialog() {}
+ override fun onCaptchaVerificationRequired(url: String?) = Unit
+
override fun showDecryptionFailedDialog() {}
override fun openClearLoginView() {}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt
index 256b13375..3ef1a80a3 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt
@@ -8,7 +8,6 @@ import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
-import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Inject
@@ -51,6 +50,10 @@ class AdvancedFragment : PreferenceFragmentCompat(),
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
}
+ override fun onCaptchaVerificationRequired(url: String?) {
+ (activity as? BaseActivity<*, *>)?.onCaptchaVerificationRequired(url)
+ }
+
override fun showDecryptionFailedDialog() {
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
}
@@ -68,7 +71,7 @@ class AdvancedFragment : PreferenceFragmentCompat(),
}
override fun showAuthDialog() {
- AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
+ (activity as? BaseActivity<*, *>)?.showAuthDialog()
}
override fun onResume() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt
index 20423eb91..3d0c8052b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt
@@ -9,7 +9,6 @@ import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
-import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Inject
@@ -67,6 +66,10 @@ class AppearanceFragment : PreferenceFragmentCompat(),
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
}
+ override fun onCaptchaVerificationRequired(url: String?) {
+ (activity as? BaseActivity<*, *>)?.onCaptchaVerificationRequired(url)
+ }
+
override fun showDecryptionFailedDialog() {
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
}
@@ -84,7 +87,7 @@ class AppearanceFragment : PreferenceFragmentCompat(),
}
override fun showAuthDialog() {
- AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
+ (activity as? BaseActivity<*, *>)?.showAuthDialog()
}
override fun onResume() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt
index 2ae983c26..0bf9ddadd 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt
@@ -21,7 +21,6 @@ import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
-import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.openInternetBrowser
@@ -137,6 +136,10 @@ class NotificationsFragment : PreferenceFragmentCompat(),
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
}
+ override fun onCaptchaVerificationRequired(url: String?) {
+ (activity as? BaseActivity<*, *>)?.onCaptchaVerificationRequired(url)
+ }
+
override fun showDecryptionFailedDialog() {
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
}
@@ -154,7 +157,7 @@ class NotificationsFragment : PreferenceFragmentCompat(),
}
override fun showAuthDialog() {
- AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
+ (activity as? BaseActivity<*, *>)?.showAuthDialog()
}
override fun showFixSyncDialog() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt
index 133b1ff44..d57144832 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt
@@ -10,7 +10,6 @@ import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
-import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.ui.modules.main.MainView
import javax.inject.Inject
@@ -88,6 +87,10 @@ class SyncFragment : PreferenceFragmentCompat(),
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
}
+ override fun onCaptchaVerificationRequired(url: String?) {
+ (activity as? BaseActivity<*, *>)?.onCaptchaVerificationRequired(url)
+ }
+
override fun showDecryptionFailedDialog() {
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
}
@@ -105,7 +108,7 @@ class SyncFragment : PreferenceFragmentCompat(),
}
override fun showAuthDialog() {
- AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
+ (activity as? BaseActivity<*, *>)?.showAuthDialog()
}
override fun onResume() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
index 6b442d1c2..e83f25176 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
@@ -2,9 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable
import android.os.Handler
import android.os.Looper
-import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
@@ -20,8 +18,8 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.TimetableRepository
-import io.github.wulkanowy.data.toFirstResult
-import io.github.wulkanowy.data.waitForResult
+import io.github.wulkanowy.domain.timetable.IsStudentHasLessonsOnWeekendUseCase
+import io.github.wulkanowy.domain.timetable.IsWeekendHasLessonsUseCase
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
@@ -31,16 +29,12 @@ import io.github.wulkanowy.utils.isHolidays
import io.github.wulkanowy.utils.isJustFinished
import io.github.wulkanowy.utils.isShowTimeUntil
import io.github.wulkanowy.utils.left
-import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.nextOrSameSchoolDay
import io.github.wulkanowy.utils.nextSchoolDay
import io.github.wulkanowy.utils.previousSchoolDay
-import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.toFormattedString
import io.github.wulkanowy.utils.until
-import kotlinx.coroutines.flow.firstOrNull
import timber.log.Timber
-import java.time.DayOfWeek
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDate.now
@@ -54,6 +48,8 @@ class TimetablePresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val timetableRepository: TimetableRepository,
+ private val isStudentHasLessonsOnWeekendUseCase: IsStudentHasLessonsOnWeekendUseCase,
+ private val isWeekendHasLessonsUseCase: IsWeekendHasLessonsUseCase,
private val semesterRepository: SemesterRepository,
private val prefRepository: PreferencesRepository,
private val analytics: AnalyticsHelper,
@@ -153,7 +149,7 @@ class TimetablePresenter @Inject constructor(
val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student)
- checkInitialAndCurrentDate(student, semester)
+ checkInitialAndCurrentDate(semester)
timetableRepository.getTimetable(
student = student,
semester = semester,
@@ -165,7 +161,7 @@ class TimetablePresenter @Inject constructor(
}
.logResourceStatus("load timetable data")
.onResourceData {
- isWeekendHasLessons = isWeekendHasLessons || isWeekendHasLessons(it.lessons)
+ isWeekendHasLessons = isWeekendHasLessons || isWeekendHasLessonsUseCase(it.lessons)
view?.run {
enableSwipe(true)
@@ -197,17 +193,9 @@ class TimetablePresenter @Inject constructor(
.launch()
}
- private suspend fun checkInitialAndCurrentDate(student: Student, semester: Semester) {
+ private suspend fun checkInitialAndCurrentDate(semester: Semester) {
if (initialDate == null) {
- val lessons = timetableRepository.getTimetable(
- student = student,
- semester = semester,
- start = now().monday,
- end = now().sunday,
- forceRefresh = false,
- timetableType = TimetableRepository.TimetableType.NORMAL
- ).toFirstResult().dataOrNull?.lessons.orEmpty()
- isWeekendHasLessons = isWeekendHasLessons(lessons)
+ isWeekendHasLessons = isStudentHasLessonsOnWeekendUseCase(semester)
initialDate = getInitialDate(semester)
}
@@ -216,15 +204,6 @@ class TimetablePresenter @Inject constructor(
}
}
- private fun isWeekendHasLessons(
- lessons: List,
- ): Boolean = lessons.any {
- it.date.dayOfWeek in listOf(
- DayOfWeek.SATURDAY,
- DayOfWeek.SUNDAY,
- )
- }
-
private fun getInitialDate(semester: Semester): LocalDate {
val now = now()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt
index 4e0578e2b..4cfc03229 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt
@@ -11,7 +11,7 @@ import android.view.View.VISIBLE
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import io.github.wulkanowy.R
-import io.github.wulkanowy.data.dataOrNull
+import io.github.wulkanowy.data.dataOrThrow
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
@@ -27,6 +27,7 @@ import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Co
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
import io.github.wulkanowy.utils.getCompatColor
+import io.github.wulkanowy.utils.getErrorString
import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString
import kotlinx.coroutines.runBlocking
@@ -67,25 +68,31 @@ class TimetableWidgetFactory(
override fun onDestroy() {}
override fun onDataSetChanged() {
- intent?.extras?.getInt(EXTRA_APPWIDGET_ID)?.let { appWidgetId ->
- val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
- val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
+ val appWidgetId = intent?.extras?.getInt(EXTRA_APPWIDGET_ID) ?: return
+ val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
+ val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
+ items = emptyList()
+
+ runBlocking {
runCatching {
- runBlocking {
- val student = getStudent(studentId) ?: return@runBlocking
- val semester = semesterRepository.getCurrentSemester(student)
- items = createItems(
- lessons = getLessons(student, semester, date),
- lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
- )
+ val student = getStudent(studentId) ?: return@runBlocking
+ val semester = semesterRepository.getCurrentSemester(student)
+ val lessons = getLessons(student, semester, date)
+ val lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
+
+ createItems(lessons, lastSync)
+ }
+ .onFailure {
+ items = listOf(TimetableWidgetItem.Error(it))
+ Timber.e(it, "An error has occurred in timetable widget factory")
+ }
+ .onSuccess {
+ items = it
if (date == LocalDate.now()) {
updateTodayLastLessonEnd(appWidgetId)
}
}
- }.onFailure {
- Timber.e(it, "An error has occurred in timetable widget factory")
- }
}
}
@@ -98,7 +105,7 @@ class TimetableWidgetFactory(
student: Student, semester: Semester, date: LocalDate
): List {
val timetable = timetableRepository.getTimetable(student, semester, date, date, false)
- val lessons = timetable.toFirstResult().dataOrNull?.lessons.orEmpty()
+ val lessons = timetable.toFirstResult().dataOrThrow.lessons
return lessons.sortedBy { it.number }
}
@@ -110,6 +117,7 @@ class TimetableWidgetFactory(
BETWEEN_AND_BEFORE_LESSONS -> 0
else -> null
}
+
return buildList {
lessons.forEach {
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
@@ -133,15 +141,12 @@ class TimetableWidgetFactory(
sharedPref.putLong(key, todayLastLessonEnd.epochSecond, true)
}
- companion object {
- const val TIME_FORMAT_STYLE = "HH:mm"
- }
-
override fun getViewAt(position: Int): RemoteViews? {
return when (val item = items.getOrNull(position) ?: return null) {
is TimetableWidgetItem.Normal -> getNormalItemRemoteView(item)
is TimetableWidgetItem.Empty -> getEmptyItemRemoteView(item)
is TimetableWidgetItem.Synchronized -> getSynchronizedItemRemoteView(item)
+ is TimetableWidgetItem.Error -> getErrorItemRemoteView(item)
}
}
@@ -213,6 +218,18 @@ class TimetableWidgetFactory(
}
}
+ private fun getErrorItemRemoteView(item: TimetableWidgetItem.Error): RemoteViews {
+ return RemoteViews(
+ context.packageName,
+ R.layout.item_widget_timetable_error
+ ).apply {
+ setTextViewText(
+ R.id.timetable_widget_item_error_message,
+ context.resources.getErrorString(item.error)
+ )
+ }
+ }
+
private fun updateTheme() {
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> {
@@ -300,4 +317,8 @@ class TimetableWidgetFactory(
synchronizationTime,
)
}
+
+ private companion object {
+ private const val TIME_FORMAT_STYLE = "HH:mm"
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetItem.kt
index 166b1a8fb..fb02f8919 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetItem.kt
@@ -17,10 +17,15 @@ sealed class TimetableWidgetItem(val type: TimetableWidgetItemType) {
data class Synchronized(
val timestamp: Instant,
) : TimetableWidgetItem(TimetableWidgetItemType.SYNCHRONIZED)
+
+ data class Error(
+ val error: Throwable
+ ) : TimetableWidgetItem(TimetableWidgetItemType.ERROR)
}
enum class TimetableWidgetItemType {
NORMAL,
EMPTY,
SYNCHRONIZED,
+ ERROR,
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/AttendanceExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/AttendanceExtension.kt
index 397c95953..19d0929db 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/AttendanceExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/AttendanceExtension.kt
@@ -19,6 +19,9 @@ private inline val AttendanceSummary.allAbsences: Double
inline val Attendance.isExcusableOrNotExcused: Boolean
get() = (excusable || ((absence || lateness) && !excused)) && excuseStatus == null
+inline val Attendance.isAbsenceExcusable: Boolean
+ get() = (excusable && absence && !excused) && excuseStatus == null
+
fun AttendanceSummary.calculatePercentage() = calculatePercentage(allPresences, allAbsences)
fun List.calculatePercentage(): Double {
diff --git a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
index a4c2537ac..1c2290510 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
@@ -3,6 +3,8 @@ package io.github.wulkanowy.utils
import android.content.res.Resources
import io.github.wulkanowy.R
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
+import io.github.wulkanowy.sdk.scrapper.exception.AccountInactiveException
+import io.github.wulkanowy.sdk.scrapper.exception.CloudflareVerificationException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
@@ -32,8 +34,10 @@ fun Resources.getErrorString(error: Throwable): String = when (error) {
is ServiceUnavailableException -> R.string.error_service_unavailable
is FeatureDisabledException -> R.string.error_feature_disabled
is FeatureNotAvailableException -> R.string.error_feature_not_available
+ is AccountInactiveException -> R.string.error_account_inactive
is VulcanException -> R.string.error_unknown_uonet
is ScrapperException -> R.string.error_unknown_app
+ is CloudflareVerificationException -> R.string.error_cloudflare_captcha
is SSLHandshakeException -> when {
error.isCausedByCertificateNotValidNow() -> R.string.error_invalid_device_datetime
else -> R.string.error_timeout
diff --git a/app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt
index df99be98b..9b6ca7060 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt
@@ -1,5 +1,6 @@
package io.github.wulkanowy.utils
+import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import timber.log.Timber
@@ -30,3 +31,12 @@ fun Sdk.init(student: Student): Sdk {
return this
}
+
+fun Sdk.switchSemester(semester: Semester): Sdk {
+ return switchDiary(
+ diaryId = semester.diaryId,
+ kindergartenDiaryId = semester.kindergartenDiaryId,
+ schoolYear = semester.schoolYear,
+ unitId = semester.unitId,
+ )
+}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/WebkitCookieManagerProxy.kt b/app/src/main/java/io/github/wulkanowy/utils/WebkitCookieManagerProxy.kt
new file mode 100644
index 000000000..3d41c711c
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/utils/WebkitCookieManagerProxy.kt
@@ -0,0 +1,70 @@
+package io.github.wulkanowy.utils
+
+import android.util.AndroidRuntimeException
+import java.net.CookiePolicy
+import java.net.CookieStore
+import java.net.HttpCookie
+import java.net.URI
+import android.webkit.CookieManager as WebkitCookieManager
+import java.net.CookieManager as JavaCookieManager
+
+class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL) {
+
+ private val webkitCookieManager: WebkitCookieManager? = getWebkitCookieManager()
+
+ /**
+ * @see [https://stackoverflow.com/a/70354583/6695449]
+ */
+ private fun getWebkitCookieManager(): WebkitCookieManager? {
+ return try {
+ WebkitCookieManager.getInstance()
+ } catch (e: AndroidRuntimeException) {
+ null
+ }
+ }
+
+ override fun put(uri: URI?, responseHeaders: Map>?) {
+ if (uri == null || responseHeaders == null) return
+ val url = uri.toString()
+ for (headerKey in responseHeaders.keys) {
+ if (headerKey == null || !(
+ headerKey.equals("Set-Cookie2", ignoreCase = true) ||
+ headerKey.equals("Set-Cookie", ignoreCase = true)
+ )
+ ) continue
+
+ // process each of the headers
+ for (headerValue in responseHeaders[headerKey].orEmpty()) {
+ webkitCookieManager?.setCookie(url, headerValue)
+ }
+ }
+ }
+
+ override operator fun get(
+ uri: URI?,
+ requestHeaders: Map?>?
+ ): Map> {
+ require(!(uri == null || requestHeaders == null)) { "Argument is null" }
+ val res = mutableMapOf>()
+ val cookie = webkitCookieManager?.getCookie(uri.toString())
+ if (cookie != null) res["Cookie"] = listOf(cookie)
+ return res
+ }
+
+ override fun getCookieStore(): CookieStore {
+ val cookies = super.getCookieStore()
+ return object : CookieStore {
+ override fun add(uri: URI?, cookie: HttpCookie?) = cookies.add(uri, cookie)
+ override fun get(uri: URI?): List = cookies.get(uri)
+ override fun getCookies(): List = cookies.cookies
+ override fun getURIs(): List = cookies.urIs
+ override fun remove(uri: URI?, cookie: HttpCookie?): Boolean =
+ cookies.remove(uri, cookie)
+
+ override fun removeAll(): Boolean {
+ webkitCookieManager?.removeAllCookies(null) ?: return false
+ return true
+ }
+ }
+ }
+}
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 0a2eb68f4..ef6308b6c 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,5 +1,7 @@
-Wersja 2.3.3
+Wersja 2.4.2
-— poprawiliśmy kolejne usterki przy odświeżaniu danych (teraz to powinno działać już dużo lepiej)
+- naprawiliśmy crash przy przełączaniu uczniów, motywów i języków
+- naprawiliśmy crash przy dodawaniu dodatkowych lekcji
+- naprawiliśmy obsługę błędów widżetach
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
diff --git a/app/src/main/res/drawable/ic_circle_notification.xml b/app/src/main/res/drawable/ic_circle_notification.xml
new file mode 100644
index 000000000..6059212cb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_circle_notification.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml
new file mode 100644
index 000000000..1d6c00461
--- /dev/null
+++ b/app/src/main/res/drawable/ic_close.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_message_delete_forever.xml b/app/src/main/res/drawable/ic_menu_message_delete_forever.xml
new file mode 100644
index 000000000..a7b5ac53b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_message_delete_forever.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_message_restore.xml b/app/src/main/res/drawable/ic_menu_message_restore.xml
new file mode 100644
index 000000000..5c8544f28
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_message_restore.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_notifications_off.xml b/app/src/main/res/drawable/ic_notifications_off.xml
new file mode 100644
index 000000000..094ed75fa
--- /dev/null
+++ b/app/src/main/res/drawable/ic_notifications_off.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index d14de50a1..a9284234e 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -16,7 +16,7 @@
+ android:layout_height="wrap_content" />
@@ -67,7 +67,7 @@
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
- android:inputType="text"
+ android:inputType="none"
tools:ignore="Deprecated" />
@@ -87,7 +87,7 @@
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
- android:inputType="text"
+ android:inputType="none"
tools:ignore="Deprecated" />
@@ -113,7 +113,7 @@
android:id="@+id/additionalLessonDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="24dp"
android:layout_marginEnd="8dp"
@@ -122,6 +122,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/additionalLessonDialogAdd"
@@ -131,7 +132,7 @@
android:id="@+id/additionalLessonDialogAdd"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
@@ -139,6 +140,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_attendance.xml b/app/src/main/res/layout/dialog_attendance.xml
index d832490a7..b9c63539c 100644
--- a/app/src/main/res/layout/dialog_attendance.xml
+++ b/app/src/main/res/layout/dialog_attendance.xml
@@ -150,7 +150,7 @@
android:id="@+id/attendanceDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
@@ -158,6 +158,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_captcha.xml b/app/src/main/res/layout/dialog_captcha.xml
new file mode 100644
index 000000000..539aa0cc9
--- /dev/null
+++ b/app/src/main/res/layout/dialog_captcha.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_conference.xml b/app/src/main/res/layout/dialog_conference.xml
index 72837b819..3d33fd568 100644
--- a/app/src/main/res/layout/dialog_conference.xml
+++ b/app/src/main/res/layout/dialog_conference.xml
@@ -181,7 +181,7 @@
android:id="@+id/conferenceDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
@@ -189,6 +189,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_exam.xml b/app/src/main/res/layout/dialog_exam.xml
index 519d1531f..e2f77e1f2 100644
--- a/app/src/main/res/layout/dialog_exam.xml
+++ b/app/src/main/res/layout/dialog_exam.xml
@@ -220,7 +220,7 @@
android:id="@+id/examDialogAddToCalendar"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginBottom="24dp"
android:contentDescription="@string/all_add_to_calendar"
@@ -228,6 +228,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_add"
app:icon="@drawable/ic_calendar_all"
app:layout_constraintBottom_toBottomOf="parent"
@@ -237,7 +238,7 @@
android:id="@+id/examDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
@@ -245,6 +246,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_grade.xml b/app/src/main/res/layout/dialog_grade.xml
index f47f61088..8606a5ce5 100644
--- a/app/src/main/res/layout/dialog_grade.xml
+++ b/app/src/main/res/layout/dialog_grade.xml
@@ -212,7 +212,7 @@
android:id="@+id/gradeDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_below="@+id/gradeDialogColorValue"
android:layout_alignParentRight="true"
android:layout_marginTop="24dp"
@@ -222,6 +222,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close" />
diff --git a/app/src/main/res/layout/dialog_homework.xml b/app/src/main/res/layout/dialog_homework.xml
index 8c6cf0a76..10b719077 100644
--- a/app/src/main/res/layout/dialog_homework.xml
+++ b/app/src/main/res/layout/dialog_homework.xml
@@ -27,7 +27,7 @@
android:id="@+id/homeworkDialogRead"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp"
android:layout_marginBottom="24dp"
@@ -35,6 +35,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/homework_mark_as_done"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/homeworkDialogClose" />
@@ -43,13 +44,14 @@
android:id="@+id/homeworkDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
diff --git a/app/src/main/res/layout/dialog_homework_add.xml b/app/src/main/res/layout/dialog_homework_add.xml
index e0ff5b749..dc7ae32d5 100644
--- a/app/src/main/res/layout/dialog_homework_add.xml
+++ b/app/src/main/res/layout/dialog_homework_add.xml
@@ -94,7 +94,7 @@
android:id="@+id/homeworkDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="24dp"
android:layout_marginEnd="8dp"
@@ -103,6 +103,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/homeworkDialogAdd"
@@ -112,13 +113,14 @@
android:id="@+id/homeworkDialogAdd"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_lesson_completed.xml b/app/src/main/res/layout/dialog_lesson_completed.xml
index 3a1d3fd00..fc32a252a 100644
--- a/app/src/main/res/layout/dialog_lesson_completed.xml
+++ b/app/src/main/res/layout/dialog_lesson_completed.xml
@@ -212,7 +212,7 @@
android:id="@+id/completedLessonDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
@@ -220,6 +220,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_mobile_device.xml b/app/src/main/res/layout/dialog_mobile_device.xml
index 9b81737fb..c526ed74c 100644
--- a/app/src/main/res/layout/dialog_mobile_device.xml
+++ b/app/src/main/res/layout/dialog_mobile_device.xml
@@ -18,10 +18,10 @@
android:layout_marginTop="24dp"
android:adjustViewBounds="true"
android:contentDescription="@string/mobile_device_qr"
- tools:src="@tools:sample/avatars"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"
+ tools:src="@tools:sample/avatars" />
+
+ app:constraint_referenced_ids="mobileDeviceQr,mobileDeviceDialogTokenTitle,mobileDeviceDialogTokenValue,mobileDeviceDialogSymbolTitle,mobileDeviceDialogSymbolValue,mobileDeviceDialogPinTitle,mobileDeviceDialogPinValue,mobileDeviceDialogClose"
+ tools:visibility="visible" />
+ tools:visibility="invisible" />
diff --git a/app/src/main/res/layout/dialog_note.xml b/app/src/main/res/layout/dialog_note.xml
index 9c8b18b32..3b88ea5f8 100644
--- a/app/src/main/res/layout/dialog_note.xml
+++ b/app/src/main/res/layout/dialog_note.xml
@@ -180,7 +180,7 @@
android:id="@+id/noteDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
@@ -188,6 +188,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_school_announcement.xml b/app/src/main/res/layout/dialog_school_announcement.xml
index 4e0ef556f..a771b772f 100644
--- a/app/src/main/res/layout/dialog_school_announcement.xml
+++ b/app/src/main/res/layout/dialog_school_announcement.xml
@@ -122,7 +122,7 @@
android:id="@+id/announcementDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
@@ -130,6 +130,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/dialog_timetable.xml b/app/src/main/res/layout/dialog_timetable.xml
index aeb01b3ba..de2696482 100644
--- a/app/src/main/res/layout/dialog_timetable.xml
+++ b/app/src/main/res/layout/dialog_timetable.xml
@@ -263,7 +263,7 @@
android:id="@+id/timetableDialogClose"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
@@ -271,6 +271,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minHeight="36dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml
index 348602d77..9de44a70d 100644
--- a/app/src/main/res/layout/fragment_dashboard.xml
+++ b/app/src/main/res/layout/fragment_dashboard.xml
@@ -18,7 +18,8 @@
+ android:layout_height="match_parent"
+ tools:visibility="gone">
-
+
+
@@ -55,14 +70,21 @@
android:gravity="center"
android:padding="8dp"
android:text="@string/error_unknown"
- android:textSize="20sp" />
+ android:textSize="20sp"
+ app:layout_constraintBottom_toTopOf="@id/dashboard_error_buttons"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/dashboard_error_image" />
+ android:orientation="horizontal"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/dashboard_error_message">
-
+
diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml
index fc5e5f35e..10864e640 100644
--- a/app/src/main/res/layout/fragment_login_form.xml
+++ b/app/src/main/res/layout/fragment_login_form.xml
@@ -261,6 +261,7 @@
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:hint="@string/login_domain_suffix_hint"
+ app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout"
diff --git a/app/src/main/res/layout/header_grade_details.xml b/app/src/main/res/layout/header_grade_details.xml
index f2ba9a8c9..e43e8993f 100644
--- a/app/src/main/res/layout/header_grade_details.xml
+++ b/app/src/main/res/layout/header_grade_details.xml
@@ -45,6 +45,9 @@
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/gradeHeaderPointsSum"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="@id/gradeHeaderSubject"
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
tools:text="Average: 6,00" />
@@ -55,8 +58,12 @@
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
+ android:ellipsize="end"
+ android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toStartOf="@id/gradeHeaderNumber"
app:layout_constraintStart_toEndOf="@+id/gradeHeaderAverage"
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
tools:text="Points: 123/200 (61,5%)" />
@@ -67,8 +74,13 @@
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
+ android:layout_marginEnd="8dp"
+ android:ellipsize="end"
+ android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/gradeHeaderPointsSum"
app:layout_constraintTop_toBottomOf="@id/gradeHeaderSubject"
tools:text="12 grades" />
@@ -85,6 +97,9 @@
android:paddingRight="5dp"
android:textColor="?colorOnPrimary"
android:textSize="14sp"
+ app:autoSizeMaxTextSize="16dp"
+ app:autoSizeMinTextSize="10dp"
+ app:autoSizeTextType="uniform"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
diff --git a/app/src/main/res/layout/item_dashboard_admin_message.xml b/app/src/main/res/layout/item_dashboard_admin_message.xml
index e12241df5..407e12921 100644
--- a/app/src/main/res/layout/item_dashboard_admin_message.xml
+++ b/app/src/main/res/layout/item_dashboard_admin_message.xml
@@ -34,11 +34,24 @@
android:layout_marginEnd="16dp"
android:textSize="18sp"
android:textStyle="bold"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/dashboard_admin_message_item_close"
app:layout_constraintStart_toEndOf="@id/dashboard_admin_message_item_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" />
+
+
+ android:layout_height="1dp"
+ android:id="@+id/gradeSummaryItemPointsDivider"
+ android:background="@drawable/ic_all_divider" />
+ android:id="@+id/gradeSummaryItemPredictedDivider"
+ android:layout_height="1dp"
+ android:background="@drawable/ic_all_divider" />
+ android:layout_height="1dp"
+ android:id="@+id/gradeSummaryItemFinalDivider"
+ android:background="@drawable/ic_all_divider" />
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_message.xml b/app/src/main/res/layout/item_message.xml
index 39fbaad01..1346c3f05 100644
--- a/app/src/main/res/layout/item_message.xml
+++ b/app/src/main/res/layout/item_message.xml
@@ -81,9 +81,9 @@
@@ -83,13 +94,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
- android:layout_marginTop="0dp"
- android:layout_marginEnd="5dp"
+ android:layout_marginEnd="0dp"
+ android:ellipsize="end"
+ android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="13sp"
app:layout_constraintEnd_toStartOf="@+id/timetableItemTeacher"
app:layout_constraintStart_toEndOf="@+id/timetableItemRoom"
- app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
+ app:layout_constraintTop_toTopOf="@id/timetableItemTimeFinish"
tools:text="(2/2)"
tools:visibility="visible" />
@@ -98,13 +110,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
- android:layout_marginEnd="16dp"
+ android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="13sp"
- app:layout_constraintBottom_toBottomOf="@+id/timetableItemNumber"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/timetableItemGroup"
+ app:layout_constraintTop_toTopOf="@id/timetableItemTimeFinish"
tools:text="Agata Kowalska - Błaszczyk"
tools:visibility="visible" />
@@ -118,8 +132,8 @@
android:textColor="?colorTimetableChange"
android:textSize="13sp"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@+id/timetableItemTeacher"
- app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
+ app:layout_constraintStart_toEndOf="@id/timetableItemTimeFinish"
+ app:layout_constraintTop_toTopOf="@id/timetableItemTimeFinish"
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
tools:visibility="gone" />
@@ -168,7 +182,7 @@
android:visibility="gone"
app:backgroundTint="?colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintTop_toTopOf="@id/timetableItemTimeStart"
tools:text="jeszcze 15 min"
tools:visibility="visible" />
diff --git a/app/src/main/res/layout/item_widget_timetable_error.xml b/app/src/main/res/layout/item_widget_timetable_error.xml
new file mode 100644
index 000000000..6f9ab067a
--- /dev/null
+++ b/app/src/main/res/layout/item_widget_timetable_error.xml
@@ -0,0 +1,12 @@
+
+
diff --git a/app/src/main/res/layout/subitem_dashboard_small_grade.xml b/app/src/main/res/layout/subitem_dashboard_small_grade.xml
index 6800b72e9..5d48313a3 100644
--- a/app/src/main/res/layout/subitem_dashboard_small_grade.xml
+++ b/app/src/main/res/layout/subitem_dashboard_small_grade.xml
@@ -1,5 +1,6 @@
diff --git a/app/src/main/res/layout/widget_timetable.xml b/app/src/main/res/layout/widget_timetable.xml
index b07cc78f6..b438da6c3 100644
--- a/app/src/main/res/layout/widget_timetable.xml
+++ b/app/src/main/res/layout/widget_timetable.xml
@@ -114,7 +114,5 @@
android:text="@string/widget_timetable_no_items"
android:textAppearance="?attr/textAppearanceBody1"
android:visibility="gone" />
-
-
diff --git a/app/src/main/res/menu/action_menu_message_preview.xml b/app/src/main/res/menu/action_menu_message_preview.xml
index 57cf05ddb..04af86713 100644
--- a/app/src/main/res/menu/action_menu_message_preview.xml
+++ b/app/src/main/res/menu/action_menu_message_preview.xml
@@ -29,6 +29,13 @@
android:title="@string/message_forward"
app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
+
+
+
diff --git a/app/src/main/res/menu/context_menu_attendance.xml b/app/src/main/res/menu/context_menu_attendance.xml
index 4eff14e3f..45377a76f 100644
--- a/app/src/main/res/menu/context_menu_attendance.xml
+++ b/app/src/main/res/menu/context_menu_attendance.xml
@@ -2,6 +2,13 @@
LaděníLadění oznámení
+ Vymazat soubory cookie webviewTvůrciLicenceZprávy
@@ -55,6 +56,7 @@
Neplatný e-mailMísto e-mailu použijte přiřazené přihlašovací údajePoužijte přiřazené přihlašovací nebo e-mail v @%1$s
+ Invalid domain suffixNeplatný symbol. Pokud jej nemůžete najít, kontaktujte školuNevymýšlejte si! Pokud symbol nemůžete najít, kontaktujte školuŽák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+
@@ -116,6 +118,7 @@
Součet bodůKonečná známkaPředpokládaná známka
+ Popisná známkaVypočítaný průměrJak funguje vypočítaný průměr?Vypočítaný průměr je aritmetický průměr vypočítaný z průměrů předmětů. Umožňuje vám to znát přibližný konečný průměr. Vypočítává se způsobem zvoleným uživatelem v nastavení aplikaci. Doporučuje se vybrat příslušnou možnost. Důvodem je rozdílný výpočet školních průměrů. Pokud vaše škola navíc uvádí průměr předmětů na stránce deníku Vulcan, aplikace si je stáhne a tyto průměry nepočítá. To lze změnit vynucením výpočtu průměru v nastavení aplikaci.\n\nPrůměr známek pouze z vybraného semestru:\n1. Výpočet váženého průměru pro každý předmět v daném semestru\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů\n\nPrůměr průměrů z obou semestrů:\n1. Výpočet váženého průměru pro každý předmět v semestru 1 a 2\n2. Výpočet aritmetického průměru vypočítaných průměrů za semestry 1 a 2 pro každý předmět.\n3. Sčítání vypočítaných průměrů\n4. Výpočet aritmetického průměru sečtených průměrů\n\nPrůměr známek z celého roku:\n1. Výpočet váženého průměru za rok pro každý předmět. Konečný průměr v 1. semestru je nepodstatný.\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů
@@ -159,6 +162,12 @@
Nové konečné známkyNové konečné známky
+
+ Nová popisná známka
+ Nové popisné známky
+ Nové popisné známky
+ Nové popisné známky
+ Máte %1$d novou známkuMáte %1$d nové známky
@@ -177,6 +186,12 @@
Máte %1$d nových konečných známekMáte %1$d nových konečných známek
+
+ Máte %1$d novou popisnou známku
+ Máte %1$d nové popisné známky
+ Máte %1$d nových popisných známek
+ Máte %1$d nových popisných známek
+ LekceUčebna
@@ -833,17 +848,27 @@
AutorizacePro provoz aplikace potřebujeme potvrdit vaši identitu. Zadejte PESEL žáka <b>%1$s</b> v níže uvedeném poliZatím přeskočit
+
+ Probíhá ověřování. Počkejte…
+ Úspěšně ověřenoŽádné internetové připojeníVyskytla se chyba. Zkontrolujte hodiny svého zařízení
+ This account is inactive. Try logging in againNelze se připojit ke deníku. Servery mohou být přetíženy. Prosím zkuste to znovu pozdějiNačítání dat se nezdařilo. Prosím zkuste to znovu pozdějiJe vyžadována změna hesla pro deníkProbíhá údržba deníku UONET+. Zkuste to později znovuNeznámá chyba deniku UONET+. Prosím zkuste to znovu pozdějiNeznámá chyba aplikace. Prosím zkuste to znovu později
+ Vyžadováno ověření CaptchaVyskytla se neočekávaná chybaFunkce je deaktivována přes vaší školouFunkce není k dispozici. Přihlaste se v jiném režimu než Mobile APIToto pole je povinné
+
+ Mute
+ Unmute
+ You have muted this user
+ You have unmuted this user
diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml
deleted file mode 100644
index 013066629..000000000
--- a/app/src/main/res/values-da-rDK/strings.xml
+++ /dev/null
@@ -1,759 +0,0 @@
-
-
-
- Login
- Wulkanowy
- Grades
- Attendance
- Exams
- Timetable
- Settings
- More
- About
- Log viewer
- Debug
- Notification debug
- Contributors
- Licenses
- Messages
- New message
- New homework
- Notes and achievements
- Homework
- Accounts manager
- Select account
- Account details
- Student info
- Dashboard
- Notifications center
- Menu configuartion
-
- Semester %1$d, %2$d/%3$d
-
- Sign in with the student or parent account
- Enter the symbol from the register page for account: <b>%1$s</b>
- Username
- Email
- Login, PESEL or e-mail
- Password
- UONET+ register variant
- Custom domain suffix
- Mobile API
- Scraper
- Hybrid
- Token
- PIN
- Symbol
- E.g. \"lodz\" or \"powiatjaroslawski\"
- Sign in
- Password too short
- Login details are incorrect
- %1$s. Make sure the correct UONET+ register variation is selected below
- Invalid PIN
- Invalid token
- Token expired
- Invalid email
- Use the assigned login instead of email
- Use the assigned login or email in @%1$s
- Invalid symbol. If you cannot find it, please contact the school
- Don\'t make this up! If you cannot find it, please contact the school
- Student not found. Validate the symbol and the chosen variation of the UONET+ register
- Selected student is already logged in
- The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen
- Select students to log in to the application
- Other options
- 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
- This mode displays the same data as it appears on the register website
- The combination of the best features of the other two modes. It works faster than scraper and provides features not available in the Mobile API mode. It is in the experimental phase
- Privacy policy
- Trouble signing in? Contact us!
- Email
- Discord
- Send email
- Make sure you select the correct UONET+ register variation!
- Reset password
- Recover your account
- Recover
- Student is already signed in
- Standard
- Other search locations
- No active students found
- Enter a different symbol
- Get help
- Full school name with the town (required)
- Np. ZSTiO Jarosław lub SP nr 99 w Łodzi
- Enter correct name of the school
- Additional information in Polish (optional)
- Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"
- Submit
-
- Enable notifications
- Enable notifications so you don\'t miss message from teacher or new grade
- Skip
- Enable
-
- Account manager
- Log in
- Session expired
- Session expired, log in again
- Your account password has been changed. You need to log in to Wulkanowy again
- Password changed
- Application support
- Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
- Enable ads
-
- Grade
- Semester %d
- Change semester
- No grades
- Weight
- Weight: %s
- Comment
- Number of new ratings: %1$d
- Average: %1$.2f
- Points: %s
- No average
- Total points
- Final grade
- Predicted grade
- Calculated average
- How does Calculated Average work?
- The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
- How does the Final Average work?
- The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded
- Final average
- from %1$d of %2$d subjects
- Summary
- Class
- Mark as read
- Partial
- Semester
- Points
- Legend
- Class average: %1$s
- Your average: %1$s
- Your grade: %1$s
- Class
- Student
-
- %d grade
- %d grades
-
-
- New grade
- New grades
-
-
- New predicted grade
- New predicted grades
-
-
- New final grade
- New final grades
-
-
- You received %1$d grade
- You received %1$d grades
-
-
- You received %1$d predicted grade
- You received %1$d predicted grades
-
-
- You received %1$d final grade
- You received %1$d final grades
-
-
- Lesson
- Room
- Group
- Hours
- Changes
- No lessons this day
- %s min
- %s sec
- %1$s left
- in %1$s
- Finished
- Now: %s
- Next: %s
- Later: %s
- %1$s lesson %2$d - %3$s
- Change of room from %1$s to %2$s
- Change of teacher from %1$s to %2$s
- Change of subject from %1$s to %2$s
-
- No lesson
- No lessons
-
-
- Timetable change
- Timetable changes
-
-
- %1$s - %2$d change in timetable
- %1$s - %2$d changes in timetable
-
-
- %1$d change in timetable
- %1$d changes in timetable
-
-
- %d change
- %d changes
-
-
- Completed lessons
- Show completed lessons
- No info about completed lessons
- Topic
- Absence
- Resources
-
- Additional lessons
- Show additional lessons
- No info about additional lessons
- New lesson
- New additional lesson
- Additional lesson added successfully
- Additional lesson deleted successfully
- Repeat weekly
- Delete additional lesson
- Just this lesson
- All in the series
- Start time
- End time
- End time must be greater than start time
-
- Attendance summary
- Absent for school reasons
- Excused absence
- Unexcused absence
- Exemption
- Excused lateness
- Unexcused lateness
- Present
- Deleted
- Unknown
- Number of lesson
- No entries
- Absence reason (optional)
- Send
- Absence excuse request sent successfully!
- You must select at least one absence!
- Excuse
-
- New attendance
- New attendance
-
-
- %1$d new attendance
- %1$d attendance
-
-
- %d attendance
- %d attendance
-
-
- Total
-
- No exams this week
- Type
- Entry date
-
- New exam
- New exams
-
-
- %d new exam
- %d new exams
-
-
- %d exam
- %d exams
-
-
- Inbox
- Sent
- Trash
- (no subject)
- No messages
- From:
- To:
- Date: %1$s
- Reply
- Forward
- Select all
- Unselect all
- Move to trash
- Delete permanently
- Message deleted successfully
- student
- parent
- guardian
- employee
- Share
- Print
- Subject
- Content
- Message sent successfully
- Message does not exist
- You need to choose at least 1 recipient
- The message content must be at least 3 characters
- All mailboxes
- Only unread
- Only with attachments
- Read: %s
- Read by: %1$d of %2$d people
-
- %1$d message
- %1$d messages
-
-
- New message
- New messages
-
- Do you want to restore draft message?
- Do you want to restore draft message with recipients: %s?
-
- You received %1$d message
- You received %1$d messages
-
-
- %1$d selected
- %1$d selected
-
- Messages deleted
- Choose mailbox
- Incognito mode is on
- Thanks to incognito mode sender is not notified when you read the message
-
- No info about notes
- Points
-
- %d note
- %d notes
-
-
- New note
- New notes
-
-
- You received %1$d note
- You received %1$d notes
-
-
-
- %d praise
- %d praises
-
-
- New praise
- New praises
-
-
- You received %1$d praise
- You received %1$d praises
-
-
-
- %d neutral note
- %d neutral notes
-
-
- New neutral note
- New neutral notes
-
-
- You received %1$d neutral note
- You received %1$d neutral notes
-
-
- No info about homework
- Mark as done
- Mark as undone
- Add homework
- Homework added successfully
- Homework deleted successfully
- Attachments
-
- New homework
- New homework
-
-
- You received %d new homework
- You received %d new homework
-
-
- %d homework
- %d homework
-
-
- Lucky number
- Today\'s lucky number is
- No info about the lucky number
- Lucky number for today
- Today\'s lucky number is: %s
- Show history
-
- Lucky number history
- No info about lucky numbers
-
- Mobile devices
- No devices
- Deregister
- Device removed
- QR code
- Token
- Symbol
- PIN
-
- School and teachers
-
- School
- No info about school
- School name
- School address
- Telephone
- Name of headmaster
- Name of pedagogue
- Show on map
- Call
-
- Teachers
- No info about teachers
- No subject
-
- Conferences
- No info about conferences
-
- %d conference
- %d conferences
-
-
- New conference
- New conferences
-
-
- You have %1$d new conference
- You have %1$d new conferences
-
- Present at conference
- Agenda
- Place
- Topic
-
- School announcements
- No school announcements
-
- %d school announcement
- %d school announcements
-
-
- New school announcement
- New school announcements
-
-
- You have %1$d new school announcement
- You have %1$d new school announcements
-
-
- Add account
- Logout
- Do you want to log out this student?
- Student logout
- Student account
- Parent account
- Edit data
- Accounts manager
- Select student
- Family
- Contact
- Residence details
- Personal information
-
- App version
- Contributors
- List of Wulkanowy developers
- Report a bug
- Send a bug report via e-mail
- FAQ
- Read Frequently Asked Questions
- Discord server
- Join the Wulkanowy community
- Facebook fanpage
- Twitter page
- Follow us on twitter
- Like our facebook fanpage
- Privacy policy
- Rules for collecting personal data
- System settings
- Open system settings
- Homepage
- Visit the website and help develop the application
- Licenses
- Licenses of libraries used in the application
-
- License
-
- Avatar
- See more on GitHub
-
- No info about student or student family
- Name
- Second name
- Gender
- Polish citizenship
- Family name
- Mother\'s and father\'s names
- Phone
- Cellphone
- E-mail
- Address of residence
- Address of registration
- Correspondence address
- Surname and first name
- Degree of kinship
- Address
- Phones
- Male
- Female
- Last name
- Guardian
-
- Nick
- Add nick
- Choose avatar color
-
- Share logs
- Refresh
-
- Lessons
- (Tomorrow)
- (Today and tomorrow)
- In a moment:
- Soon:
- First:
- Now:
- End of lessons
- Next:
- Later:
-
- %1$d more lesson
- %1$d more lessons
-
- until %1$s
- No upcoming lessons
- An error occurred while loading the lessons
- Homework
- No homework to do
- An error occurred while loading the homework
-
- %1$d more homework
- %1$d more homework
-
- due %1$s
- Last grades
- No new grades
- An error occurred while loading the grades
- School announcements
- No current announcements
- An error occurred while loading the announcements
-
- %1$d more announcement
- %1$d more announcements
-
- Exams
- No upcoming exams
- An error occurred while loading the exams
-
- %1$d more exam
- %1$d more exams
-
- Conferences
- No upcoming conferences
- An error occurred while loading the conferences
-
- %1$d more conference
- %1$d more conferences
-
- An error occurred while loading data
- None
-
- Check for updates
- Before reporting a bug, check first if an update with the bug fix is available
-
- Content
- Retry
- Description
- No description
- Teacher
- Date
- Entry date
- Color
- Details
- Category
- Close
- No data
- Subject
- Prev
- Next
- Search
- Search…
- Yes
- No
- Save
- Title
- Add
- Copied
- Undo
- Change
- Add to calendar
- Cancel
-
- No lessons
- Synchronized on %1$s at %2$s
- Choose theme
- Light
- Dark
- System Theme
-
- App
- Default view
- Calculated average options
- Force average calculation by app
- Show presence
- Theme
- Grades expanding
- Show groups next to subjects
- Show empty tiles where there\'s no lesson
- Show chart list in class grades
- Show subjects without grades
- Grades color scheme
- Subjects sorting
- Language
- Menu configuration
- Set the order of functions in the menu
- Notifications
- Other
- Show notifications
- Show upcoming lesson notifications
- Make upcoming lesson notification persistent
- Turn off when notification is not showing in your watch/band
- Open system notification settings
- Fix synchronization & notifications issues
- Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.
- Show debug notifications
- Synchronization is disabled
- Official app notifications
- Capture official app notifications
- Remove official app notifications after capture
- Capture notifications
- With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY
- Upcoming lesson notifications
- You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
- Go to settings
- Synchronization
- Automatic update
- Suspended on holidays
- Updates interval
- Wi-Fi only
- Sync now
- Synced!
- Sync failed
- Sync in progress
- Last full sync: %s
- Value of the plus
- Value of the minus
- Reply with message history
- Show arithmetic average when no weights provided
- Incognito mode
- Do not inform about reading the message
- Support
- Privacy Policy
- Agreements
- Show consent to data processing
- Show ads in app
- Watch single ad to support project
- Consent to data processing
- To view an advertisement you must agree to the data processing terms of our Privacy Policy
- Agree
- Privacy policy
- Ad is loading
- Thank you for your support, come back later for more ads
- Advanced
- Appearance & Behavior
- Notifications
- Synchronization
- Advertisements
- Grades
- Dashboard
- Tiles visibility
- Attendance
- Timetable
- Grades
- Calculated average
- Messages
- Appearance & Behavior
- Languages, themes, subjects sorting
- App notifications, fix problems
- Notifications
- Synchronization
- Automatic update, synchronization interval
- Plus and minus values, average calculation
- Advanced
- App version, contributors, social portals
- Displaying advertisements, project support
-
- New grades
- New homework
- New conferences
- New exams
- Lucky number
- New messages
- New notes
- New school announcements
- Push notifications
- Upcoming lessons
- Debug
- Timetable change
- New attendance
-
- Black
- Red
- Blue
- Green
- Purple
- No color
-
- Download of updates has started…
- An update has just been downloaded.
- Restart
- Update failed! Wulkanowy may not function properly. Consider updating
-
- Application restart
- The application must restart for the changes to be saved
- Restart
-
- Authorization has been rejected. The data provided does not match the records in the secretary\'s office.
- Invalid PESEL
- PESEL
- Authorize
- Authorization completed successfully
- Authorization
- To operate the application, we need to confirm your identity. Please enter the student\'s PESEL <b>%1$s</b> in the field below
- Skip for now
-
- No internet connection
- An error occurred. Check your device clock
- Connection to register failed. Servers can be overloaded. Please try again later
- Loading data failed. Please try again later
- Register password change required
- Maintenance underway UONET + register. Try again later
- Unknown UONET + register error. Try again later
- Unknown application error. Please try again later
- An unexpected error occurred
- Feature disabled by your school
- Feature not available. Login in a mode other than Mobile API
- This field is required
-
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 09173d38b..a346bbd2f 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -10,9 +10,10 @@
EinstellungenMehrÜber die Applikation
- Log Viewer
+ Log viewerDebuggenBenachrichtigungen debuggen
+ Clear webview cookiesMitarbeiterLizenzenNachrichten
@@ -55,6 +56,7 @@
Ungültige emailDen zugewiesenen Login anstelle von email verwendenBenutze den zugewiesenen Login oder E-Mail in @%1$s
+ Invalid domain suffixInvalid symbol. If you cannot find it, please contact the schoolDon\'t make this up! If you cannot find it, please contact the schoolSchüler nicht gefunden. Überprüfen Sie das Symbol und die gewählte Variation des UONET+ Registers
@@ -116,6 +118,7 @@
GesamtpunkteFinaler NoteVorhergesagte Note
+ Descriptive gradeBerechnender DurchschnittWie funktioniert der berechnete Durchschnitt?Der berechnete Mittelwert ist das arithmetische Mittel, das aus den Durchschnittswerten der Probanden errechnet wird. Es erlaubt Ihnen, den ungefähre endgültigen Durchschnitt zu kennen. Sie wird auf eine vom Anwender in den Anwendungseinstellungen gewählte Weise berechnet. Es wird empfohlen, die entsprechende Option zu wählen. Das liegt daran, dass die Berechnung der Schuldurchschnitte unterschiedlich ist. Wenn Ihre Schule den Durchschnitt der Fächer auf der Vulcan-Seite angibt, lädt die Anwendung diese Fächer herunter und berechnet nicht den Durchschnitt. Dies kann geändert werden, indem die Berechnung des Durchschnitts in den Anwendungseinstellungen erzwungen wird. \n\nDurchschnitt der Noten nur aus dem ausgewählten Semester :\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in einem bestimmten Semester\n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Durchschnitte\nDurchschnitt der Durchschnitte aus beiden Semestern:\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in Semester 1 und 2\n2. Berechnung des arithmetischen Mittels der berechneten Durchschnitte für Semester 1 und 2 für jedes Fach. \n3. Hinzufügen von berechneten Durchschnittswerten\n4. Berechnung des arithmetischen Mittels der summierten Durchschnitte\nDurchschnitt der Noten aus dem ganzen Jahr:\n1. Berechnung des gewichteten Jahresdurchschnitts für jedes Fach. Der Abschlussdurchschnitt im 1. Semester ist irrelevant. \n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Mittelwerte
@@ -151,6 +154,10 @@
Neue AbschlussnoteNeue Abschlussnoten
+
+ New descriptive grade
+ New descriptive grades
+ Du hast %1$d Note bekommenDu hast %1$d Noten bekommen
@@ -163,6 +170,10 @@
Sie haben %1$d Abschlussnote bekommenSie haben %1$d Abschlussnoten bekommen
+
+ You received %1$d descriptive grade
+ You received %1$d descriptive grades
+ LektionKlassenzimmer
@@ -743,17 +754,27 @@
AuthorizationTo operate the application, we need to confirm your identity. Please enter the student\'s PESEL <b>%1$s</b> in the field belowSkip for now
+
+ Verification is in progress. Wait…
+ Verified successfullyKeine InternetverbindungEs ist ein Fehler aufgetreten. Überprüfen Sie Ihre Geräteuhr
+ This account is inactive. Try logging in againRegistrierungsverbindung fehlgeschlagen. Server können überlastet sein. Bitte versuchen Sie es später noch einmalDas Laden der Daten ist fehlgeschlagen. Bitte versuchen Sie es später noch einmalPasswortänderung für Registrierung erforderlichWartung im Gange UONET + Klassenbuch. Versuchen Sie es später noch einmalUnbekannter UONET + Registerfehler. Versuchen Sie es später erneutUnbekannter Anwendungsfehler. Bitte versuchen Sie es später noch einmal
+ Captcha verification requiredEin unerwarteter Fehler ist aufgetretenFunktion, die von Ihrer Schule deaktiviert wurdeFeature in diesem Modus nicht verfügbarDieses Feld ist erforderlich
+
+ Mute
+ Unmute
+ You have muted this user
+ You have unmuted this user
diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml
deleted file mode 100644
index 013066629..000000000
--- a/app/src/main/res/values-es-rES/strings.xml
+++ /dev/null
@@ -1,759 +0,0 @@
-
-
-
- Login
- Wulkanowy
- Grades
- Attendance
- Exams
- Timetable
- Settings
- More
- About
- Log viewer
- Debug
- Notification debug
- Contributors
- Licenses
- Messages
- New message
- New homework
- Notes and achievements
- Homework
- Accounts manager
- Select account
- Account details
- Student info
- Dashboard
- Notifications center
- Menu configuartion
-
- Semester %1$d, %2$d/%3$d
-
- Sign in with the student or parent account
- Enter the symbol from the register page for account: <b>%1$s</b>
- Username
- Email
- Login, PESEL or e-mail
- Password
- UONET+ register variant
- Custom domain suffix
- Mobile API
- Scraper
- Hybrid
- Token
- PIN
- Symbol
- E.g. \"lodz\" or \"powiatjaroslawski\"
- Sign in
- Password too short
- Login details are incorrect
- %1$s. Make sure the correct UONET+ register variation is selected below
- Invalid PIN
- Invalid token
- Token expired
- Invalid email
- Use the assigned login instead of email
- Use the assigned login or email in @%1$s
- Invalid symbol. If you cannot find it, please contact the school
- Don\'t make this up! If you cannot find it, please contact the school
- Student not found. Validate the symbol and the chosen variation of the UONET+ register
- Selected student is already logged in
- The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen
- Select students to log in to the application
- Other options
- 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
- This mode displays the same data as it appears on the register website
- The combination of the best features of the other two modes. It works faster than scraper and provides features not available in the Mobile API mode. It is in the experimental phase
- Privacy policy
- Trouble signing in? Contact us!
- Email
- Discord
- Send email
- Make sure you select the correct UONET+ register variation!
- Reset password
- Recover your account
- Recover
- Student is already signed in
- Standard
- Other search locations
- No active students found
- Enter a different symbol
- Get help
- Full school name with the town (required)
- Np. ZSTiO Jarosław lub SP nr 99 w Łodzi
- Enter correct name of the school
- Additional information in Polish (optional)
- Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"
- Submit
-
- Enable notifications
- Enable notifications so you don\'t miss message from teacher or new grade
- Skip
- Enable
-
- Account manager
- Log in
- Session expired
- Session expired, log in again
- Your account password has been changed. You need to log in to Wulkanowy again
- Password changed
- Application support
- Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
- Enable ads
-
- Grade
- Semester %d
- Change semester
- No grades
- Weight
- Weight: %s
- Comment
- Number of new ratings: %1$d
- Average: %1$.2f
- Points: %s
- No average
- Total points
- Final grade
- Predicted grade
- Calculated average
- How does Calculated Average work?
- The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
- How does the Final Average work?
- The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded
- Final average
- from %1$d of %2$d subjects
- Summary
- Class
- Mark as read
- Partial
- Semester
- Points
- Legend
- Class average: %1$s
- Your average: %1$s
- Your grade: %1$s
- Class
- Student
-
- %d grade
- %d grades
-
-
- New grade
- New grades
-
-
- New predicted grade
- New predicted grades
-
-
- New final grade
- New final grades
-
-
- You received %1$d grade
- You received %1$d grades
-
-
- You received %1$d predicted grade
- You received %1$d predicted grades
-
-
- You received %1$d final grade
- You received %1$d final grades
-
-
- Lesson
- Room
- Group
- Hours
- Changes
- No lessons this day
- %s min
- %s sec
- %1$s left
- in %1$s
- Finished
- Now: %s
- Next: %s
- Later: %s
- %1$s lesson %2$d - %3$s
- Change of room from %1$s to %2$s
- Change of teacher from %1$s to %2$s
- Change of subject from %1$s to %2$s
-
- No lesson
- No lessons
-
-
- Timetable change
- Timetable changes
-
-
- %1$s - %2$d change in timetable
- %1$s - %2$d changes in timetable
-
-
- %1$d change in timetable
- %1$d changes in timetable
-
-
- %d change
- %d changes
-
-
- Completed lessons
- Show completed lessons
- No info about completed lessons
- Topic
- Absence
- Resources
-
- Additional lessons
- Show additional lessons
- No info about additional lessons
- New lesson
- New additional lesson
- Additional lesson added successfully
- Additional lesson deleted successfully
- Repeat weekly
- Delete additional lesson
- Just this lesson
- All in the series
- Start time
- End time
- End time must be greater than start time
-
- Attendance summary
- Absent for school reasons
- Excused absence
- Unexcused absence
- Exemption
- Excused lateness
- Unexcused lateness
- Present
- Deleted
- Unknown
- Number of lesson
- No entries
- Absence reason (optional)
- Send
- Absence excuse request sent successfully!
- You must select at least one absence!
- Excuse
-
- New attendance
- New attendance
-
-
- %1$d new attendance
- %1$d attendance
-
-
- %d attendance
- %d attendance
-
-
- Total
-
- No exams this week
- Type
- Entry date
-
- New exam
- New exams
-
-
- %d new exam
- %d new exams
-
-
- %d exam
- %d exams
-
-
- Inbox
- Sent
- Trash
- (no subject)
- No messages
- From:
- To:
- Date: %1$s
- Reply
- Forward
- Select all
- Unselect all
- Move to trash
- Delete permanently
- Message deleted successfully
- student
- parent
- guardian
- employee
- Share
- Print
- Subject
- Content
- Message sent successfully
- Message does not exist
- You need to choose at least 1 recipient
- The message content must be at least 3 characters
- All mailboxes
- Only unread
- Only with attachments
- Read: %s
- Read by: %1$d of %2$d people
-
- %1$d message
- %1$d messages
-
-
- New message
- New messages
-
- Do you want to restore draft message?
- Do you want to restore draft message with recipients: %s?
-
- You received %1$d message
- You received %1$d messages
-
-
- %1$d selected
- %1$d selected
-
- Messages deleted
- Choose mailbox
- Incognito mode is on
- Thanks to incognito mode sender is not notified when you read the message
-
- No info about notes
- Points
-
- %d note
- %d notes
-
-
- New note
- New notes
-
-
- You received %1$d note
- You received %1$d notes
-
-
-
- %d praise
- %d praises
-
-
- New praise
- New praises
-
-
- You received %1$d praise
- You received %1$d praises
-
-
-
- %d neutral note
- %d neutral notes
-
-
- New neutral note
- New neutral notes
-
-
- You received %1$d neutral note
- You received %1$d neutral notes
-
-
- No info about homework
- Mark as done
- Mark as undone
- Add homework
- Homework added successfully
- Homework deleted successfully
- Attachments
-
- New homework
- New homework
-
-
- You received %d new homework
- You received %d new homework
-
-
- %d homework
- %d homework
-
-
- Lucky number
- Today\'s lucky number is
- No info about the lucky number
- Lucky number for today
- Today\'s lucky number is: %s
- Show history
-
- Lucky number history
- No info about lucky numbers
-
- Mobile devices
- No devices
- Deregister
- Device removed
- QR code
- Token
- Symbol
- PIN
-
- School and teachers
-
- School
- No info about school
- School name
- School address
- Telephone
- Name of headmaster
- Name of pedagogue
- Show on map
- Call
-
- Teachers
- No info about teachers
- No subject
-
- Conferences
- No info about conferences
-
- %d conference
- %d conferences
-
-
- New conference
- New conferences
-
-
- You have %1$d new conference
- You have %1$d new conferences
-
- Present at conference
- Agenda
- Place
- Topic
-
- School announcements
- No school announcements
-
- %d school announcement
- %d school announcements
-
-
- New school announcement
- New school announcements
-
-
- You have %1$d new school announcement
- You have %1$d new school announcements
-
-
- Add account
- Logout
- Do you want to log out this student?
- Student logout
- Student account
- Parent account
- Edit data
- Accounts manager
- Select student
- Family
- Contact
- Residence details
- Personal information
-
- App version
- Contributors
- List of Wulkanowy developers
- Report a bug
- Send a bug report via e-mail
- FAQ
- Read Frequently Asked Questions
- Discord server
- Join the Wulkanowy community
- Facebook fanpage
- Twitter page
- Follow us on twitter
- Like our facebook fanpage
- Privacy policy
- Rules for collecting personal data
- System settings
- Open system settings
- Homepage
- Visit the website and help develop the application
- Licenses
- Licenses of libraries used in the application
-
- License
-
- Avatar
- See more on GitHub
-
- No info about student or student family
- Name
- Second name
- Gender
- Polish citizenship
- Family name
- Mother\'s and father\'s names
- Phone
- Cellphone
- E-mail
- Address of residence
- Address of registration
- Correspondence address
- Surname and first name
- Degree of kinship
- Address
- Phones
- Male
- Female
- Last name
- Guardian
-
- Nick
- Add nick
- Choose avatar color
-
- Share logs
- Refresh
-
- Lessons
- (Tomorrow)
- (Today and tomorrow)
- In a moment:
- Soon:
- First:
- Now:
- End of lessons
- Next:
- Later:
-
- %1$d more lesson
- %1$d more lessons
-
- until %1$s
- No upcoming lessons
- An error occurred while loading the lessons
- Homework
- No homework to do
- An error occurred while loading the homework
-
- %1$d more homework
- %1$d more homework
-
- due %1$s
- Last grades
- No new grades
- An error occurred while loading the grades
- School announcements
- No current announcements
- An error occurred while loading the announcements
-
- %1$d more announcement
- %1$d more announcements
-
- Exams
- No upcoming exams
- An error occurred while loading the exams
-
- %1$d more exam
- %1$d more exams
-
- Conferences
- No upcoming conferences
- An error occurred while loading the conferences
-
- %1$d more conference
- %1$d more conferences
-
- An error occurred while loading data
- None
-
- Check for updates
- Before reporting a bug, check first if an update with the bug fix is available
-
- Content
- Retry
- Description
- No description
- Teacher
- Date
- Entry date
- Color
- Details
- Category
- Close
- No data
- Subject
- Prev
- Next
- Search
- Search…
- Yes
- No
- Save
- Title
- Add
- Copied
- Undo
- Change
- Add to calendar
- Cancel
-
- No lessons
- Synchronized on %1$s at %2$s
- Choose theme
- Light
- Dark
- System Theme
-
- App
- Default view
- Calculated average options
- Force average calculation by app
- Show presence
- Theme
- Grades expanding
- Show groups next to subjects
- Show empty tiles where there\'s no lesson
- Show chart list in class grades
- Show subjects without grades
- Grades color scheme
- Subjects sorting
- Language
- Menu configuration
- Set the order of functions in the menu
- Notifications
- Other
- Show notifications
- Show upcoming lesson notifications
- Make upcoming lesson notification persistent
- Turn off when notification is not showing in your watch/band
- Open system notification settings
- Fix synchronization & notifications issues
- Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.
- Show debug notifications
- Synchronization is disabled
- Official app notifications
- Capture official app notifications
- Remove official app notifications after capture
- Capture notifications
- With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY
- Upcoming lesson notifications
- You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
- Go to settings
- Synchronization
- Automatic update
- Suspended on holidays
- Updates interval
- Wi-Fi only
- Sync now
- Synced!
- Sync failed
- Sync in progress
- Last full sync: %s
- Value of the plus
- Value of the minus
- Reply with message history
- Show arithmetic average when no weights provided
- Incognito mode
- Do not inform about reading the message
- Support
- Privacy Policy
- Agreements
- Show consent to data processing
- Show ads in app
- Watch single ad to support project
- Consent to data processing
- To view an advertisement you must agree to the data processing terms of our Privacy Policy
- Agree
- Privacy policy
- Ad is loading
- Thank you for your support, come back later for more ads
- Advanced
- Appearance & Behavior
- Notifications
- Synchronization
- Advertisements
- Grades
- Dashboard
- Tiles visibility
- Attendance
- Timetable
- Grades
- Calculated average
- Messages
- Appearance & Behavior
- Languages, themes, subjects sorting
- App notifications, fix problems
- Notifications
- Synchronization
- Automatic update, synchronization interval
- Plus and minus values, average calculation
- Advanced
- App version, contributors, social portals
- Displaying advertisements, project support
-
- New grades
- New homework
- New conferences
- New exams
- Lucky number
- New messages
- New notes
- New school announcements
- Push notifications
- Upcoming lessons
- Debug
- Timetable change
- New attendance
-
- Black
- Red
- Blue
- Green
- Purple
- No color
-
- Download of updates has started…
- An update has just been downloaded.
- Restart
- Update failed! Wulkanowy may not function properly. Consider updating
-
- Application restart
- The application must restart for the changes to be saved
- Restart
-
- Authorization has been rejected. The data provided does not match the records in the secretary\'s office.
- Invalid PESEL
- PESEL
- Authorize
- Authorization completed successfully
- Authorization
- To operate the application, we need to confirm your identity. Please enter the student\'s PESEL <b>%1$s</b> in the field below
- Skip for now
-
- No internet connection
- An error occurred. Check your device clock
- Connection to register failed. Servers can be overloaded. Please try again later
- Loading data failed. Please try again later
- Register password change required
- Maintenance underway UONET + register. Try again later
- Unknown UONET + register error. Try again later
- Unknown application error. Please try again later
- An unexpected error occurred
- Feature disabled by your school
- Feature not available. Login in a mode other than Mobile API
- This field is required
-
diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml
deleted file mode 100644
index 013066629..000000000
--- a/app/src/main/res/values-it-rIT/strings.xml
+++ /dev/null
@@ -1,759 +0,0 @@
-
-
-
- Login
- Wulkanowy
- Grades
- Attendance
- Exams
- Timetable
- Settings
- More
- About
- Log viewer
- Debug
- Notification debug
- Contributors
- Licenses
- Messages
- New message
- New homework
- Notes and achievements
- Homework
- Accounts manager
- Select account
- Account details
- Student info
- Dashboard
- Notifications center
- Menu configuartion
-
- Semester %1$d, %2$d/%3$d
-
- Sign in with the student or parent account
- Enter the symbol from the register page for account: <b>%1$s</b>
- Username
- Email
- Login, PESEL or e-mail
- Password
- UONET+ register variant
- Custom domain suffix
- Mobile API
- Scraper
- Hybrid
- Token
- PIN
- Symbol
- E.g. \"lodz\" or \"powiatjaroslawski\"
- Sign in
- Password too short
- Login details are incorrect
- %1$s. Make sure the correct UONET+ register variation is selected below
- Invalid PIN
- Invalid token
- Token expired
- Invalid email
- Use the assigned login instead of email
- Use the assigned login or email in @%1$s
- Invalid symbol. If you cannot find it, please contact the school
- Don\'t make this up! If you cannot find it, please contact the school
- Student not found. Validate the symbol and the chosen variation of the UONET+ register
- Selected student is already logged in
- The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen
- Select students to log in to the application
- Other options
- 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
- This mode displays the same data as it appears on the register website
- The combination of the best features of the other two modes. It works faster than scraper and provides features not available in the Mobile API mode. It is in the experimental phase
- Privacy policy
- Trouble signing in? Contact us!
- Email
- Discord
- Send email
- Make sure you select the correct UONET+ register variation!
- Reset password
- Recover your account
- Recover
- Student is already signed in
- Standard
- Other search locations
- No active students found
- Enter a different symbol
- Get help
- Full school name with the town (required)
- Np. ZSTiO Jarosław lub SP nr 99 w Łodzi
- Enter correct name of the school
- Additional information in Polish (optional)
- Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"
- Submit
-
- Enable notifications
- Enable notifications so you don\'t miss message from teacher or new grade
- Skip
- Enable
-
- Account manager
- Log in
- Session expired
- Session expired, log in again
- Your account password has been changed. You need to log in to Wulkanowy again
- Password changed
- Application support
- Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
- Enable ads
-
- Grade
- Semester %d
- Change semester
- No grades
- Weight
- Weight: %s
- Comment
- Number of new ratings: %1$d
- Average: %1$.2f
- Points: %s
- No average
- Total points
- Final grade
- Predicted grade
- Calculated average
- How does Calculated Average work?
- The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
- How does the Final Average work?
- The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded
- Final average
- from %1$d of %2$d subjects
- Summary
- Class
- Mark as read
- Partial
- Semester
- Points
- Legend
- Class average: %1$s
- Your average: %1$s
- Your grade: %1$s
- Class
- Student
-
- %d grade
- %d grades
-
-
- New grade
- New grades
-
-
- New predicted grade
- New predicted grades
-
-
- New final grade
- New final grades
-
-
- You received %1$d grade
- You received %1$d grades
-
-
- You received %1$d predicted grade
- You received %1$d predicted grades
-
-
- You received %1$d final grade
- You received %1$d final grades
-
-
- Lesson
- Room
- Group
- Hours
- Changes
- No lessons this day
- %s min
- %s sec
- %1$s left
- in %1$s
- Finished
- Now: %s
- Next: %s
- Later: %s
- %1$s lesson %2$d - %3$s
- Change of room from %1$s to %2$s
- Change of teacher from %1$s to %2$s
- Change of subject from %1$s to %2$s
-
- No lesson
- No lessons
-
-
- Timetable change
- Timetable changes
-
-
- %1$s - %2$d change in timetable
- %1$s - %2$d changes in timetable
-
-
- %1$d change in timetable
- %1$d changes in timetable
-
-
- %d change
- %d changes
-
-
- Completed lessons
- Show completed lessons
- No info about completed lessons
- Topic
- Absence
- Resources
-
- Additional lessons
- Show additional lessons
- No info about additional lessons
- New lesson
- New additional lesson
- Additional lesson added successfully
- Additional lesson deleted successfully
- Repeat weekly
- Delete additional lesson
- Just this lesson
- All in the series
- Start time
- End time
- End time must be greater than start time
-
- Attendance summary
- Absent for school reasons
- Excused absence
- Unexcused absence
- Exemption
- Excused lateness
- Unexcused lateness
- Present
- Deleted
- Unknown
- Number of lesson
- No entries
- Absence reason (optional)
- Send
- Absence excuse request sent successfully!
- You must select at least one absence!
- Excuse
-
- New attendance
- New attendance
-
-
- %1$d new attendance
- %1$d attendance
-
-
- %d attendance
- %d attendance
-
-
- Total
-
- No exams this week
- Type
- Entry date
-
- New exam
- New exams
-
-
- %d new exam
- %d new exams
-
-
- %d exam
- %d exams
-
-
- Inbox
- Sent
- Trash
- (no subject)
- No messages
- From:
- To:
- Date: %1$s
- Reply
- Forward
- Select all
- Unselect all
- Move to trash
- Delete permanently
- Message deleted successfully
- student
- parent
- guardian
- employee
- Share
- Print
- Subject
- Content
- Message sent successfully
- Message does not exist
- You need to choose at least 1 recipient
- The message content must be at least 3 characters
- All mailboxes
- Only unread
- Only with attachments
- Read: %s
- Read by: %1$d of %2$d people
-
- %1$d message
- %1$d messages
-
-
- New message
- New messages
-
- Do you want to restore draft message?
- Do you want to restore draft message with recipients: %s?
-
- You received %1$d message
- You received %1$d messages
-
-
- %1$d selected
- %1$d selected
-
- Messages deleted
- Choose mailbox
- Incognito mode is on
- Thanks to incognito mode sender is not notified when you read the message
-
- No info about notes
- Points
-
- %d note
- %d notes
-
-
- New note
- New notes
-
-
- You received %1$d note
- You received %1$d notes
-
-
-
- %d praise
- %d praises
-
-
- New praise
- New praises
-
-
- You received %1$d praise
- You received %1$d praises
-
-
-
- %d neutral note
- %d neutral notes
-
-
- New neutral note
- New neutral notes
-
-
- You received %1$d neutral note
- You received %1$d neutral notes
-
-
- No info about homework
- Mark as done
- Mark as undone
- Add homework
- Homework added successfully
- Homework deleted successfully
- Attachments
-
- New homework
- New homework
-
-
- You received %d new homework
- You received %d new homework
-
-
- %d homework
- %d homework
-
-
- Lucky number
- Today\'s lucky number is
- No info about the lucky number
- Lucky number for today
- Today\'s lucky number is: %s
- Show history
-
- Lucky number history
- No info about lucky numbers
-
- Mobile devices
- No devices
- Deregister
- Device removed
- QR code
- Token
- Symbol
- PIN
-
- School and teachers
-
- School
- No info about school
- School name
- School address
- Telephone
- Name of headmaster
- Name of pedagogue
- Show on map
- Call
-
- Teachers
- No info about teachers
- No subject
-
- Conferences
- No info about conferences
-
- %d conference
- %d conferences
-
-
- New conference
- New conferences
-
-
- You have %1$d new conference
- You have %1$d new conferences
-
- Present at conference
- Agenda
- Place
- Topic
-
- School announcements
- No school announcements
-
- %d school announcement
- %d school announcements
-
-
- New school announcement
- New school announcements
-
-
- You have %1$d new school announcement
- You have %1$d new school announcements
-
-
- Add account
- Logout
- Do you want to log out this student?
- Student logout
- Student account
- Parent account
- Edit data
- Accounts manager
- Select student
- Family
- Contact
- Residence details
- Personal information
-
- App version
- Contributors
- List of Wulkanowy developers
- Report a bug
- Send a bug report via e-mail
- FAQ
- Read Frequently Asked Questions
- Discord server
- Join the Wulkanowy community
- Facebook fanpage
- Twitter page
- Follow us on twitter
- Like our facebook fanpage
- Privacy policy
- Rules for collecting personal data
- System settings
- Open system settings
- Homepage
- Visit the website and help develop the application
- Licenses
- Licenses of libraries used in the application
-
- License
-
- Avatar
- See more on GitHub
-
- No info about student or student family
- Name
- Second name
- Gender
- Polish citizenship
- Family name
- Mother\'s and father\'s names
- Phone
- Cellphone
- E-mail
- Address of residence
- Address of registration
- Correspondence address
- Surname and first name
- Degree of kinship
- Address
- Phones
- Male
- Female
- Last name
- Guardian
-
- Nick
- Add nick
- Choose avatar color
-
- Share logs
- Refresh
-
- Lessons
- (Tomorrow)
- (Today and tomorrow)
- In a moment:
- Soon:
- First:
- Now:
- End of lessons
- Next:
- Later:
-
- %1$d more lesson
- %1$d more lessons
-
- until %1$s
- No upcoming lessons
- An error occurred while loading the lessons
- Homework
- No homework to do
- An error occurred while loading the homework
-
- %1$d more homework
- %1$d more homework
-
- due %1$s
- Last grades
- No new grades
- An error occurred while loading the grades
- School announcements
- No current announcements
- An error occurred while loading the announcements
-
- %1$d more announcement
- %1$d more announcements
-
- Exams
- No upcoming exams
- An error occurred while loading the exams
-
- %1$d more exam
- %1$d more exams
-
- Conferences
- No upcoming conferences
- An error occurred while loading the conferences
-
- %1$d more conference
- %1$d more conferences
-
- An error occurred while loading data
- None
-
- Check for updates
- Before reporting a bug, check first if an update with the bug fix is available
-
- Content
- Retry
- Description
- No description
- Teacher
- Date
- Entry date
- Color
- Details
- Category
- Close
- No data
- Subject
- Prev
- Next
- Search
- Search…
- Yes
- No
- Save
- Title
- Add
- Copied
- Undo
- Change
- Add to calendar
- Cancel
-
- No lessons
- Synchronized on %1$s at %2$s
- Choose theme
- Light
- Dark
- System Theme
-
- App
- Default view
- Calculated average options
- Force average calculation by app
- Show presence
- Theme
- Grades expanding
- Show groups next to subjects
- Show empty tiles where there\'s no lesson
- Show chart list in class grades
- Show subjects without grades
- Grades color scheme
- Subjects sorting
- Language
- Menu configuration
- Set the order of functions in the menu
- Notifications
- Other
- Show notifications
- Show upcoming lesson notifications
- Make upcoming lesson notification persistent
- Turn off when notification is not showing in your watch/band
- Open system notification settings
- Fix synchronization & notifications issues
- Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.
- Show debug notifications
- Synchronization is disabled
- Official app notifications
- Capture official app notifications
- Remove official app notifications after capture
- Capture notifications
- With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY
- Upcoming lesson notifications
- You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
- Go to settings
- Synchronization
- Automatic update
- Suspended on holidays
- Updates interval
- Wi-Fi only
- Sync now
- Synced!
- Sync failed
- Sync in progress
- Last full sync: %s
- Value of the plus
- Value of the minus
- Reply with message history
- Show arithmetic average when no weights provided
- Incognito mode
- Do not inform about reading the message
- Support
- Privacy Policy
- Agreements
- Show consent to data processing
- Show ads in app
- Watch single ad to support project
- Consent to data processing
- To view an advertisement you must agree to the data processing terms of our Privacy Policy
- Agree
- Privacy policy
- Ad is loading
- Thank you for your support, come back later for more ads
- Advanced
- Appearance & Behavior
- Notifications
- Synchronization
- Advertisements
- Grades
- Dashboard
- Tiles visibility
- Attendance
- Timetable
- Grades
- Calculated average
- Messages
- Appearance & Behavior
- Languages, themes, subjects sorting
- App notifications, fix problems
- Notifications
- Synchronization
- Automatic update, synchronization interval
- Plus and minus values, average calculation
- Advanced
- App version, contributors, social portals
- Displaying advertisements, project support
-
- New grades
- New homework
- New conferences
- New exams
- Lucky number
- New messages
- New notes
- New school announcements
- Push notifications
- Upcoming lessons
- Debug
- Timetable change
- New attendance
-
- Black
- Red
- Blue
- Green
- Purple
- No color
-
- Download of updates has started…
- An update has just been downloaded.
- Restart
- Update failed! Wulkanowy may not function properly. Consider updating
-
- Application restart
- The application must restart for the changes to be saved
- Restart
-
- Authorization has been rejected. The data provided does not match the records in the secretary\'s office.
- Invalid PESEL
- PESEL
- Authorize
- Authorization completed successfully
- Authorization
- To operate the application, we need to confirm your identity. Please enter the student\'s PESEL <b>%1$s</b> in the field below
- Skip for now
-
- No internet connection
- An error occurred. Check your device clock
- Connection to register failed. Servers can be overloaded. Please try again later
- Loading data failed. Please try again later
- Register password change required
- Maintenance underway UONET + register. Try again later
- Unknown UONET + register error. Try again later
- Unknown application error. Please try again later
- An unexpected error occurred
- Feature disabled by your school
- Feature not available. Login in a mode other than Mobile API
- This field is required
-
diff --git a/app/src/main/res/values-night-v31/styles.xml b/app/src/main/res/values-night-v31/styles.xml
index 6e6c4d79c..808bc714d 100644
--- a/app/src/main/res/values-night-v31/styles.xml
+++ b/app/src/main/res/values-night-v31/styles.xml
@@ -32,6 +32,9 @@
@color/material_dynamic_primary40@color/timetable_canceled_dark@color/timetable_change_dark
+ @color/attendance_absence_dark
+ @color/attendance_lateness_dark
+
@color/colorErrorLight@color/colorDividerInverse@color/material_dynamic_secondary20
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
index 5d9aa22a6..5840a051e 100644
--- a/app/src/main/res/values-night/styles.xml
+++ b/app/src/main/res/values-night/styles.xml
@@ -21,6 +21,8 @@
@color/colorSurfaceDark@color/timetable_canceled_dark@color/timetable_change_dark
+ @color/attendance_absence_dark
+ @color/attendance_lateness_dark@color/colorErrorLight@color/colorDividerInverse@color/colorSwipeRefreshDark
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index fb9d170a3..56a85ea2a 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -13,6 +13,7 @@
Przeglądarka logówDebugowanieDebugowanie powiadomień
+ Wyczyść ciasteczka webviewTwórcyLicencjeWiadomości
@@ -55,6 +56,7 @@
Nieprawidłowy adres e-mailUżyj loginu zamiast adresu e-mailUżyj loginu lub adresu e-mail w @%1$s
+ Nieprawidłowy sufiks domenyNieprawidłowy symbol. Jeśli nie możesz go znaleźć, skontaktuj się ze szkołąNie zmyślaj! Jeśli nie możesz znaleźć symbolu, skontaktuj się ze szkołąNie znaleziono ucznia. Sprawdź poprawność symbolu i wybranej odmiany dziennika UONET+
@@ -116,6 +118,7 @@
Suma punktówOcena końcowaPrzewidywana ocena
+ Ocena opisowaObliczona średniaJak działa obliczona średnia?Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\nŚrednia ocen tylko z wybranego semestru:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia ze średnich z obu semestrów:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semestrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia wszystkich ocen z całego roku:\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej z zsumowanych średnich
@@ -159,6 +162,12 @@
Nowe oceny końcoweNowe oceny końcowe
+
+ Nowa ocena opisowa
+ Nowe oceny opisowe
+ Nowe oceny opisowe
+ Nowe oceny opisowe
+ Masz %1$d nową ocenęMasz %1$d nowe oceny
@@ -177,6 +186,12 @@
Masz %1$d nowych końcowych ocenMasz %1$d nowych końcowych ocen
+
+ Masz %1$d nową ocenę opisową
+ Masz %1$d nowe oceny opisowe
+ Masz %1$d nowych ocen opisowych
+ Masz %1$d nowych ocen opisowych
+ LekcjaSala
@@ -833,17 +848,27 @@
AutoryzacjaRodzicu, musimy mieć pewność, że Twój adres e-mail został powiązany z prawidłowym kontem ucznia. W celu autoryzacji konta podaj numer PESEL ucznia <b>%1$s</b> w polu poniżejNa razie pomiń
+
+ Trwa weryfikacja. Czekaj…
+ Pomyślnie zweryfikowanoBrak połączenia z internetemWystąpił błąd. Sprawdź poprawność daty w urządzeniu
+ Konto jest nieaktywne. Spróbuj zalogować się ponownieNie udało się połączyć z dziennikiem. Serwery mogą być przeciążone. Spróbuj ponownie późniejŁadowanie danych nie powiodło się. Spróbuj ponownie późniejWymagana zmiana hasła do dziennikaTrwa przerwa techniczna dziennika UONET+. Spróbuj ponownie późniejNieznany błąd dziennika UONET+. Spróbuj ponownie późniejNieznany błąd aplikacji. Spróbuj ponownie później
+ Wymagana weryfikacja captchaWystąpił nieoczekiwany błądFunkcja wyłączona przez szkołęFunkcja niedostępna. Zaloguj się w trybie innym niż Mobilne APITo pole jest wymagane
+
+ Wycisz
+ Wyłącz wyciszenie
+ Wyciszyleś tego użytkownika
+ Wyłączyłeś wyciszenie tego użytkownika
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index c604cd8b3..f7469675e 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -13,6 +13,7 @@
Просмотр журналаОтладкаОтладка уведомлений
+ Clear webview cookiesРазработчикиЛицензииСообщения
@@ -55,6 +56,7 @@
Неверный e-mailИспользуйте назначенный логин вместо e-mailИспользуйте назначенный логин или email в @%1$s
+ Invalid domain suffixInvalid symbol. If you cannot find it, please contact the schoolDon\'t make this up! If you cannot find it, please contact the schoolУченик не найден. Проверьте symbol и выбранный тип дненика UONET+
@@ -116,6 +118,7 @@
Сумма балловИтоговая оценкаОжидаемая оценка
+ Descriptive gradeРассчитанная средняя оценкаКак работает \"Рассчитанная средняя оценка\"?Рассчитанная средняя оценка - это среднее арифметическое, рассчитанное на основе средних оценок по предметам. Это позволяет узнать приблизительную итоговую среднюю оценку. Она рассчитывается способом, выбранным пользователем в настройках приложения. Рекомендуется выбрать подходящий вариант, так как каждая школа по разному считает среднюю оценку. Кроме того, если ваша школа выставляет средние оценки по предметам на странице Vulcan, приложение просто загрузит их. Это можно изменить, заставив приложение считать среднюю оценку в настройках.\n\nСредняя из оценок выбранного семестра:\n1. Вычисление средневзвешенного значения по каждому предмету за семестр\n2.Суммирование вычисленных значений\n3. Вычисление среднего арифметического суммированных значений\n\nСредняя из средних оценок семестров:\n1.Расчет средневзвешенного значения для каждого предмета в семестрах. \n2. Вычисление среднего арифметического из средневзвешенных значений для каждого предмета в семестрах.\n3. Суммирование средних арифметических\n4. Вычисление среднего арифматического из суммированных значений\n\nСредняя из оценок со всего года:\n1. Расчет средневзвешенного значения по каждому предмету за год. Итоговое среднее значение за 1 семестр не имеет значения.\n2. Суммирование вычисленных средних\n3. Расчет среднего арифметического суммированных чисел
@@ -159,6 +162,12 @@
Новые итоговые оценкиНовые итоговые оценки
+
+ New descriptive grade
+ New descriptive grades
+ New descriptive grades
+ New descriptive grades
+ Вы получили %1$d новую оценкуВы получили %1$d новые оценки
@@ -177,6 +186,12 @@
Вы получили %1$d новых итоговых оценокВы получили %1$d новых итоговые оценки
+
+ You received %1$d descriptive grade
+ You received %1$d descriptive grades
+ You received %1$d descriptive grades
+ You received %1$d descriptive grades
+ УрокАудитория
@@ -828,22 +843,32 @@
Авторизация отклонена. Предоставленные данные не соответствуют записям в кабинете секретаря.Неправильный номер PESELНомер PESEL
- Authorize
+ АвторизоватьАвторизация прошла успешноАвторизацияДля работы приложения нам необходимо подтвердить вашу личность. Введите PESEL учащегося <b>%1$s</b> в поле нижеПропустить сейчас
+
+ Verification is in progress. Wait…
+ Verified successfullyИнтернет-соединение отсутствуетПроизошла ошибка. Проверьте время на вашем устройстве
+ This account is inactive. Try logging in againНе удалось подключиться к дневнику. Возможно, сервера перегружены, повторите попытку позжеНе удалось загрузить данные, повторите попытку позжеНеобходимо изменить пароль дневникаUONET+ проводит техническое обслуживание, повторите попытку позжеНеизвестная ошибка дневника UONET+, повторите попытку позжеНеизвестная ошибка приложения, повторите попытку позже
+ Captcha verification requiredПроизошла непредвиденная ошибкаФункция отключена вашей школойФункция недоступна в режиме Mobile API. Воспользуйтесь другим режимомЭто поле обязательно
+
+ Mute
+ Unmute
+ You have muted this user
+ You have unmuted this user
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index e02b1542a..56238c10a 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -13,6 +13,7 @@
Prehliadač protokolovLadenieLadenie oznámení
+ Vymazať súbory cookie webviewTvorcoviaLicencieSprávy
@@ -55,6 +56,7 @@
Neplatný e-mailNamiesto e-mailu použite priradené prihlasovacie údajePoužite priradené prihlasovacie alebo e-mail v @%1$s
+ Invalid domain suffixNeplatný symbol. Pokiaľ ho nemôžete nájsť, kontaktujte školuNevymýšľajte si! Pokiaľ symbol nemôžete nájsť, kontaktujte školuŽiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+
@@ -116,6 +118,7 @@
Súčet bodovKonečná známkaPredpokladaná známka
+ Popisná známkaVypočítaný priemerAko funguje vypočítaný priemer?Vypočítaný priemer je aritmetický priemer vypočítaný z priemerov predmetov. Umožňuje vám to poznať približný konečný priemer. Vypočítava sa spôsobom zvoleným užívateľom v nastaveniach aplikácii. Odporúča sa vybrať príslušnú možnosť. Dôvodom je rozdielny výpočet školských priemerov. Ak vaša škola navyše uvádza priemer predmetov na stránke denníka Vulcan, aplikácia si ich stiahne a tieto priemery nepočíta. To možno zmeniť vynútením výpočtu priemeru v nastavení aplikácii.\n\nPriemer známok iba z vybraného semestra:\n1. Výpočet váženého priemeru pre každý predmet v danom semestri\n2. Sčítanie vypočítaných priemerov\n3. Výpočet aritmetického priemeru součtených priemerov\n\nPriemer priemerov z oboch semestrov:\n1. Výpočet váženého priemeru pre každý predmet v semestri 1 a 2\n2. Výpočet aritmetického priemeru vypočítaných priemerov za semestre 1 a 2 pre každý predmet.\n3. Sčítanie vypočítaných priemerov\n4. Výpočet aritmetického priemeru součtených priemerov\n\nPriemer známok z celého roka:\n1. Výpočet váženého priemeru za rok pre každý predmet. Konečný priemer v 1. semestri je nepodstatný.\n2. Sčítanie vypočítaných priemerov\n3. Výpočet aritmetického priemeru součtených priemerov
@@ -159,6 +162,12 @@
Nové konečné známkyNové konečné známky
+
+ Nová popisná známka
+ Nové popisné známky
+ Nové popisné známky
+ Nové popisné známky
+ Máte %1$d novú známkuMáte %1$d nové známky
@@ -177,6 +186,12 @@
Máte %1$d nových konečných známokMáte %1$d nových konečných známok
+
+ Máte %1$d novú popisnú známku
+ Máte %1$d nové popisné známky
+ Máte %1$d nových popisných známok
+ Máte %1$d nových popisných známok
+ LekciaUčebňa
@@ -833,17 +848,27 @@
AutorizáciaNa prevádzku aplikácie potrebujeme potvrdiť vašu identitu. Zadajte PESEL žiaka <b>%1$s</b> v nižšie uvedenom poliZatiaľ preskočiť
+
+ Overovanie prebieha. Počkajte…
+ Úspešne overenéŽiadne internetové pripojenieVyskytla sa chyba. Skontrolujte hodiny svojho zariadenia
+ This account is inactive. Try logging in againNedá sa pripojiť ku denníku. Servery môžu byť preťažené. Prosím skúste to znova neskôrNačítanie údajov zlyhalo. Skúste neskôr prosímJe vyžadovaná zmena hesla pre denníkPrebieha údržba denníka UONET+. Skúste to neskôr znovaNeznáma chyba dennika UONET+. Prosím skúste to znova neskôrNeznáma chyba aplikácie. Prosím skúste to znova neskôr
+ Vyžaduje sa overenie CaptchaVyskytla sa neočakávaná chybaFunkcia je deaktivovaná cez vašou školouFunkcia nie je k dispozícii. Prihláste sa v inom režime než Mobile APIToto pole je povinné
+
+ Mute
+ Unmute
+ You have muted this user
+ You have unmuted this user
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 32617f429..a82027479 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -13,6 +13,7 @@
Переглядач логівВідладкаВідладка сповіщень
+ Очистити кукі веб - переглядуРозробникиЛіцензіїЛисти
@@ -55,6 +56,7 @@
Недійсна адреса e-mailВикористовуйте призначений логін замість адреси e-mailВикористовуйте призначений логін або адресу e-mail в @%1$s
+ Invalid domain suffixНекоректний символ. Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школоюНе вигадуйте! Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школоюСтудента не знайдено. Перевірте symbol та обраний тип щоденника UONET+
@@ -96,8 +98,8 @@
УвійтиМинув термін дії сесіїМинув термін дії сесії, авторизуйтеся знову
- Your account password has been changed. You need to log in to Wulkanowy again
- Password changed
+ Пароль вашого облікового запису був змінений. Ви повинні увійти в Wulkanowy знову
+ Пароль зміненоПідтримка додаткуВам подобається цей додаток? Підтримайте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете відключити в будь-який часУвімкнути рекламу
@@ -116,6 +118,7 @@
Всього балівПідсумкова оцінкаПередбачувана оцінка
+ Описова оцінкаРозрахована середня оцінкаЯк працює \"Розрахована середня оцінка\"?Розрахована середня оцінка - це середнє арифметичне, обчислене з середніх оцінок з предметів. Це дозволяє дізнатися приблизну кінцеву середню оцінку. Вона розраховується спосібом, обраним користувачем у налаштуваннях програми. Рекомендується вибрати відповідний варіант, тому що кожна школа по різному розраховує середню оцінку. Крім того, якщо у вашій школі повідомляється середня оцінка з предметів на сторінці Vulcan, програма тільки завантажує ці оцінки і не розраховує їх самостійно. Це можна змінити шляхом примусового розрахунку середньоЇ оцінки в налаштуваннях програми.\n\nСередні оцінки тільки за обраний семестр:\n1. Розрахунок середньозваженого числа для кожного предмета в даному семестрі\n2. Сумування розрахованих числ\n3. Розрахунок середнього арифметичного з сумованих чисел\n\nСереднє значення з обох семестрів:\n1. Обчислення середньозваженого числа для кожного предмета у 1 та 2 семестрі\n2. Обчислення середнього арифметичного з розрахованих середньозважених числ за 1 та 2 семестри для кожного предмета.\n3. Додавання розрахованих середніх\n4. Розрахунок середнього арифметичного підсумованих середніх значень\n\nСереднє значення оцінок за весь рік: \n1. Розрахунок середньозваженого числа за рік для кожного предмета. Підсумковий середній показник у 1-му семестрі не має значення.\n2. Сумування розрахованих середніх\n3. Обчислення середнього арифметичного з суммованих середніх
@@ -159,6 +162,12 @@
Нові підсумкові оцінкиНові підсумкові оцінки
+
+ Нова описова оцінка
+ Нових описових оцінок
+ Описових оцінок
+ Нові описові оцінки
+ Ви отримали %1$d нову оцінкуВи отримали %1$d нові оцінки
@@ -177,6 +186,12 @@
Ви отримали %1$d нових підсумкових оцінокВи отримали %1$d нових підсумкових оцінок
+
+ Ви отримали %1$d описову оцінку
+ Ви отримали %1$d нові описові оцінки
+ Ви отримали %1$d нових описових оцінок
+ Ви отримали %1$d нових описових оцінок
+ УрокАудиторія
@@ -833,17 +848,27 @@
АвторизуватиДля роботи програми нам потрібно підтвердити вашу особу. Будь ласка, введіть число PESEL <b>%1$s</b> студента в поле нижчеПоки що пропустити
+
+ Верифікація в процесі. Чекайте…
+ Верифікація завершенаНемає з\'єднання з інтернетомСталася помилка. Перевірте годинник пристрою
+ This account is inactive. Try logging in againПомилка підключення до щоденнику. Сервери можуть бути перевантажені, спробуйте пізнішеПомилка завантаження даних, спробуйте пізнішеНеобхідна зміна пароля щоденникаUONET+ проводить технічне осблуговування, спробуйте пізнішеНевідома помилка щоденника UONET+, спробуйте пізнішеНевідома помилка програми, спробуйте пізніше
+ Необхідна перевірка CaptchaВідбулася несподівана помилкаФункція вимкнена вашою школоюФункція недоступна в режимі Mobile API. Увійдіть в інший режимЦе поле обовʼязкове
+
+ Mute
+ Unmute
+ You have muted this user
+ You have unmuted this user
diff --git a/app/src/main/res/values-v31/styles.xml b/app/src/main/res/values-v31/styles.xml
index bb47b22ed..358806681 100644
--- a/app/src/main/res/values-v31/styles.xml
+++ b/app/src/main/res/values-v31/styles.xml
@@ -34,6 +34,9 @@
@color/material_dynamic_primary80@color/timetable_canceled_light@color/timetable_change_light
+ @color/attendance_absence_light
+ @color/attendance_lateness_light
+
@color/colorError@color/colorDivider@color/material_dynamic_secondary90
diff --git a/app/src/main/res/values/api_hosts.xml b/app/src/main/res/values/api_hosts.xml
index 522b6e116..9768329d0 100644
--- a/app/src/main/res/values/api_hosts.xml
+++ b/app/src/main/res/values/api_hosts.xml
@@ -44,10 +44,10 @@
https://vulcan.net.pl/?loginhttps://vulcan.net.pl/?loginhttps://vulcan.net.pl/?email&customSuffix
- https://fakelog.cf/?email
+ https://wulkanowy.net.pl/?email
- Default
+ warszawaopolegdansklublin
@@ -66,7 +66,7 @@
gminaulanmajoratgminaozorkowgminalopiennikgorny
- Default
+ saas1powiatwulkanowy
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index aa58fa09e..3c3fdb8e9 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -7,4 +7,6 @@
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 87057c61d..8ad27ad88 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -49,6 +49,12 @@
#ff8f00#ffd54f
+ #d32f2f
+ #e57373
+
+ #cd2a01
+ #f05d0e
+
#1f000000#1fffffff
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 72910b85c..b509b2710 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -14,6 +14,7 @@
Log viewerDebugNotification debug
+ Clear webview cookiesContributorsLicensesMessages
@@ -60,6 +61,7 @@
Invalid emailUse the assigned login instead of emailUse the assigned login or email in @%1$s
+ Invalid domain suffixInvalid symbol. If you cannot find it, please contact the schoolDon\'t make this up! If you cannot find it, please contact the schoolStudent not found. Validate the symbol and the chosen variation of the UONET+ register
@@ -129,6 +131,7 @@
Total pointsFinal gradePredicted grade
+ Descriptive gradeCalculated averageHow does Calculated Average work?The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
@@ -164,6 +167,10 @@
New final gradeNew final grades
+
+ New descriptive grade
+ New descriptive grades
+ You received %1$d gradeYou received %1$d grades
@@ -176,6 +183,10 @@
You received %1$d final gradeYou received %1$d final grades
+
+ You received %1$d descriptive grade
+ You received %1$d descriptive grades
+
@@ -263,8 +274,10 @@
Absence excuse request sent successfully!You must select at least one absence!Excuse
+ Excuse entire dayz powodu
- Dzień dobry,\nProszę o usprawiedliwienie mojego dziecka w dniu %s z lekcji %s%s%s.\n\nPozdrawiam.
+ Dzień dobry,\nProszę o usprawiedliwienie mojego dziecka w dniu %s z lekcji %s%s%s.\n\nPozdrawiam.
+ Dzień dobry,\nProszę o usprawiedliwienie mojego dziecka w dniu %s%s%s.\n\nPozdrawiam.New attendanceNew attendance
@@ -314,8 +327,10 @@
ForwardSelect allUnselect all
+ Restore from trashMove to trashDelete permanently
+ Message restored successfullyMessage deleted successfullystudentparent
@@ -353,6 +368,7 @@
%1$d selectedMessages deleted
+ Messages restoredChoose mailboxIncognito mode is onThanks to incognito mode sender is not notified when you read the message
@@ -833,17 +849,30 @@
Skip for now
+
+ Verification is in progress. Wait…
+ Verified successfully
+
+
No internet connectionAn error occurred. Check your device clock
+ This account is inactive. Try logging in againConnection to register failed. Servers can be overloaded. Please try again laterLoading data failed. Please try again laterRegister password change requiredMaintenance underway UONET + register. Try again laterUnknown UONET + register error. Try again laterUnknown application error. Please try again later
+ Captcha verification requiredAn unexpected error occurredFeature disabled by your schoolFeature not available. Login in a mode other than Mobile APIThis field is required
+
+
+ Mute
+ Unmute
+ You have muted this user
+ You have unmuted this user
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index a0023dda1..b5b029501 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -19,6 +19,8 @@
@color/colorSurface@color/timetable_canceled_light@color/timetable_change_light
+ @color/attendance_absence_light
+ @color/attendance_lateness_light@color/colorError@color/colorDivider@color/colorSwipeRefresh
diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
index d7d83e6c9..30b9e6b77 100644
--- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
+++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
@@ -105,6 +105,10 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
}
+ override fun onCaptchaVerificationRequired(url: String?) {
+ (activity as? BaseActivity<*, *>)?.onCaptchaVerificationRequired(url)
+ }
+
override fun showDecryptionFailedDialog() {
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
}
diff --git a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
index eac1389f4..9f5d731b6 100644
--- a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
+++ b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
@@ -42,6 +42,7 @@ fun getSemesterPojo(diaryId: Int, semesterId: Int, start: LocalDate, end: LocalD
diaryName = "$semesterId",
schoolYear = 1970,
classId = 0,
+ className = "Ti",
semesterNumber = semesterName,
unitId = 1,
start = start,
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt
index 5a1877cc0..515b0d66d 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt
@@ -2,6 +2,7 @@ package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.GradeDao
+import io.github.wulkanowy.data.db.dao.GradeDescriptiveDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.errorOrNull
import io.github.wulkanowy.data.mappers.mapToEntities
@@ -42,6 +43,9 @@ class GradeRepositoryTest {
@MockK
private lateinit var gradeSummaryDb: GradeSummaryDao
+ @MockK
+ private lateinit var gradeDescriptiveDb: GradeDescriptiveDao
+
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
@@ -56,7 +60,8 @@ class GradeRepositoryTest {
MockKAnnotations.init(this)
every { refreshHelper.shouldBeRefreshed(any()) } returns false
- gradeRepository = GradeRepository(gradeDb, gradeSummaryDb, sdk, refreshHelper)
+ gradeRepository =
+ GradeRepository(gradeDb, gradeSummaryDb, gradeDescriptiveDb, sdk, refreshHelper)
coEvery { gradeDb.deleteAll(any()) } just Runs
coEvery { gradeDb.insertAll(any()) } returns listOf()
@@ -68,6 +73,13 @@ class GradeRepositoryTest {
)
coEvery { gradeSummaryDb.deleteAll(any()) } just Runs
coEvery { gradeSummaryDb.insertAll(any()) } returns listOf()
+
+ coEvery { gradeDescriptiveDb.loadAll(any(), any()) } returnsMany listOf(
+ flowOf(listOf()),
+ )
+
+ coEvery { gradeDescriptiveDb.deleteAll(any()) } just Runs
+ coEvery { gradeDescriptiveDb.insertAll(any()) } returns listOf()
}
@Test
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
index 3a18ee979..58937e776 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
@@ -6,8 +6,10 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao
+import io.github.wulkanowy.data.db.dao.MutedMessageSendersDao
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
+import io.github.wulkanowy.data.db.entities.MutedMessageSender
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.errorOrNull
import io.github.wulkanowy.data.toFirstResult
@@ -19,9 +21,16 @@ import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.Status
import io.github.wulkanowy.utils.status
-import io.mockk.*
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.checkEquals
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
+import io.mockk.just
+import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
@@ -45,6 +54,9 @@ class MessageRepositoryTest {
@MockK
private lateinit var messageDb: MessagesDao
+ @MockK
+ private lateinit var mutesDb: MutedMessageSendersDao
+
@MockK
private lateinit var messageAttachmentDao: MessageAttachmentDao
@@ -73,9 +85,22 @@ class MessageRepositoryTest {
fun setUp() {
MockKAnnotations.init(this)
every { refreshHelper.shouldBeRefreshed(any()) } returns false
-
+ coEvery { mutesDb.checkMute(any()) } returns false
+ coEvery {
+ messageDb.loadMessagesWithMutedAuthor(
+ mailboxKey = any(),
+ folder = any()
+ )
+ } returns flowOf(emptyList())
+ coEvery {
+ messageDb.loadMessagesWithMutedAuthor(
+ folder = any(),
+ email = any()
+ )
+ } returns flowOf(emptyList())
repository = MessageRepository(
messagesDb = messageDb,
+ mutedMessageSendersDao = mutesDb,
messageAttachmentDao = messageAttachmentDao,
sdk = sdk,
context = context,
@@ -131,7 +156,11 @@ class MessageRepositoryTest {
@Test
fun `get message when content already in db`() {
val testMessage = getMessageEntity(123, "Test", false)
- val messageWithAttachment = MessageWithAttachment(testMessage, emptyList())
+ val messageWithAttachment = MessageWithAttachment(
+ testMessage,
+ emptyList(),
+ MutedMessageSender("Jan Kowalski - P - (WULKANOWY)")
+ )
coEvery { messageDb.loadMessageWithAttachment("v4") } returns flowOf(
messageWithAttachment
@@ -149,8 +178,16 @@ class MessageRepositoryTest {
val testMessage = getMessageEntity(123, "", true)
val testMessageWithContent = testMessage.copy().apply { content = "Test" }
- val mWa = MessageWithAttachment(testMessage, emptyList())
- val mWaWithContent = MessageWithAttachment(testMessageWithContent, emptyList())
+ val mWa = MessageWithAttachment(
+ testMessage,
+ emptyList(),
+ MutedMessageSender("Jan Kowalski - P - (WULKANOWY)")
+ )
+ val mWaWithContent = MessageWithAttachment(
+ testMessageWithContent,
+ emptyList(),
+ MutedMessageSender("Jan Kowalski - P - (WULKANOWY)")
+ )
coEvery {
messageDb.loadMessageWithAttachment("v4")
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 31ea3322b..6a717f6f6 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
@@ -1,12 +1,16 @@
package io.github.wulkanowy.ui.modules.grade
-import io.github.wulkanowy.data.*
+import io.github.wulkanowy.data.Resource
+import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.errorOrNull
import io.github.wulkanowy.data.repositories.GradeRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
+import io.github.wulkanowy.data.resourceFlow
+import io.github.wulkanowy.data.toFirstResult
import io.github.wulkanowy.getSemesterEntity
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.Status
@@ -158,7 +162,9 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { noWeightGrades to noWeightGradesSummary }
+ } returns resourceFlow {
+ Triple(noWeightGrades, noWeightGradesSummary, emptyList())
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -186,7 +192,9 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { noWeightGrades to noWeightGradesArithmeticSummary }
+ } returns resourceFlow {
+ Triple(noWeightGrades, noWeightGradesArithmeticSummary, emptyList())
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -211,8 +219,24 @@ class GradeAverageProviderTest {
coEvery { semesterRepository.getSemesters(student) } returns semesters
coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns flow {
emit(Resource.Loading())
- emit(Resource.Intermediate(secondGradeWithModifier to secondSummariesWithModifier))
- emit(Resource.Success(secondGradeWithModifier to secondSummariesWithModifier))
+ emit(
+ Resource.Intermediate(
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ )
+ )
+ emit(
+ Resource.Success(
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ )
+ )
}
val items = runBlocking {
@@ -253,11 +277,27 @@ class GradeAverageProviderTest {
coEvery { gradeRepository.getGrades(student, semesters[2], false) } returns flow {
emit(Resource.Loading())
delay(1000)
- emit(Resource.Success(secondGradeWithModifier to secondSummariesWithModifier))
+ emit(
+ Resource.Success(
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ )
+ )
}
coEvery { gradeRepository.getGrades(student, semesters[1], false) } returns flow {
emit(Resource.Loading())
- emit(Resource.Success(secondGradeWithModifier to secondSummariesWithModifier))
+ emit(
+ Resource.Success(
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ )
+ )
}
val items = runBlocking {
@@ -296,7 +336,13 @@ class GradeAverageProviderTest {
semesters[1],
false
)
- } returns resourceFlow { secondGradeWithModifier to secondSummariesWithModifier }
+ } returns resourceFlow {
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ }
coEvery {
gradeRepository.getGrades(
student,
@@ -304,8 +350,10 @@ class GradeAverageProviderTest {
false
)
} returns resourceFlow {
- listOf(getGrade(semesters[2].semesterId, "Język polski", .0, .0, .0)) to listOf(
- getSummary(semesters[2].semesterId, "Język polski", 2.5)
+ Triple(
+ listOf(getGrade(semesters[2].semesterId, "Język polski", .0, .0, .0)),
+ listOf(getSummary(semesters[2].semesterId, "Język polski", 2.5)),
+ emptyList()
)
}
@@ -332,7 +380,13 @@ class GradeAverageProviderTest {
semesters[1],
false
)
- } returns resourceFlow { secondGradeWithModifier to secondSummariesWithModifier }
+ } returns resourceFlow {
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ }
coEvery {
gradeRepository.getGrades(
student,
@@ -340,12 +394,14 @@ class GradeAverageProviderTest {
false
)
} returns resourceFlow {
- emptyList() to listOf(
- getSummary(
- 24,
- "Język polski",
- .0
- )
+ Triple(
+ emptyList(), listOf(
+ getSummary(
+ 24,
+ "Język polski",
+ .0
+ )
+ ), emptyList()
)
}
@@ -372,14 +428,22 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { emptyList() to emptyList() }
+ } returns resourceFlow {
+ Triple(
+ emptyList(),
+ emptyList(),
+ emptyList()
+ )
+ }
coEvery {
gradeRepository.getGrades(
student,
semesters[2],
true
)
- } returns resourceFlow { emptyList() to emptyList() }
+ } returns resourceFlow {
+ Triple(emptyList(), emptyList(), emptyList())
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -404,7 +468,13 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { secondGradeWithModifier to secondSummariesWithModifier }
+ } returns resourceFlow {
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -438,7 +508,13 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { secondGradeWithModifier to secondSummariesWithModifier }
+ } returns resourceFlow {
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -472,7 +548,13 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { secondGradeWithModifier to secondSummariesWithModifier }
+ } returns resourceFlow {
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -506,7 +588,13 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { secondGradeWithModifier to secondSummariesWithModifier }
+ } returns resourceFlow {
+ Triple(
+ secondGradeWithModifier,
+ secondSummariesWithModifier,
+ emptyList()
+ )
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -534,7 +622,7 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { secondGrades to secondSummaries }
+ } returns resourceFlow { Triple(secondGrades, secondSummaries, emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -564,7 +652,7 @@ class GradeAverageProviderTest {
semesters[2],
true
)
- } returns resourceFlow { secondGrades to secondSummaries }
+ } returns resourceFlow { Triple(secondGrades, secondSummaries, emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -594,7 +682,7 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { firstGrades to firstSummaries }
+ } returns resourceFlow { Triple(firstGrades, firstSummaries, emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -625,8 +713,8 @@ class GradeAverageProviderTest {
coEvery { semesterRepository.getSemesters(student) } returns semesters
coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flow {
emit(Resource.Loading())
- emit(Resource.Intermediate(firstGrades to firstSummaries))
- emit(Resource.Success(firstGrades to firstSummaries))
+ emit(Resource.Intermediate(Triple(firstGrades, firstSummaries, emptyList())))
+ emit(Resource.Success(Triple(firstGrades, firstSummaries, emptyList())))
}
val items = runBlocking {
@@ -675,9 +763,11 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- firstGrades to listOf(
- getSummary(22, "Matematyka", 3.0),
- getSummary(22, "Fizyka", 3.5)
+ Triple(
+ firstGrades, listOf(
+ getSummary(22, "Matematyka", 3.0),
+ getSummary(22, "Fizyka", 3.5)
+ ), emptyList()
)
}
coEvery {
@@ -687,9 +777,13 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- secondGrades to listOf(
- getSummary(22, "Matematyka", 3.5),
- getSummary(22, "Fizyka", 4.0)
+ Triple(
+ secondGrades,
+ listOf(
+ getSummary(22, "Matematyka", 3.5),
+ getSummary(22, "Fizyka", 4.0)
+ ),
+ emptyList()
)
}
@@ -723,17 +817,21 @@ class GradeAverageProviderTest {
emit(Resource.Loading())
emit(
Resource.Intermediate(
- firstGrades to listOf(
- getSummary(22, "Matematyka", 3.0),
- getSummary(22, "Fizyka", 3.5)
+ Triple(
+ firstGrades, listOf(
+ getSummary(22, "Matematyka", 3.0),
+ getSummary(22, "Fizyka", 3.5)
+ ), emptyList()
)
)
)
emit(
Resource.Success(
- firstGrades to listOf(
- getSummary(22, "Matematyka", 3.0),
- getSummary(22, "Fizyka", 3.5)
+ Triple(
+ firstGrades, listOf(
+ getSummary(22, "Matematyka", 3.0),
+ getSummary(22, "Fizyka", 3.5)
+ ), emptyList()
)
)
)
@@ -742,17 +840,21 @@ class GradeAverageProviderTest {
emit(Resource.Loading())
emit(
Resource.Intermediate(
- secondGrades to listOf(
- getSummary(22, "Matematyka", 3.5),
- getSummary(22, "Fizyka", 4.0)
+ Triple(
+ secondGrades, listOf(
+ getSummary(22, "Matematyka", 3.5),
+ getSummary(22, "Fizyka", 4.0)
+ ), emptyList()
)
)
)
emit(
Resource.Success(
- secondGrades to listOf(
- getSummary(22, "Matematyka", 3.5),
- getSummary(22, "Fizyka", 4.0)
+ Triple(
+ secondGrades, listOf(
+ getSummary(22, "Matematyka", 3.5),
+ getSummary(22, "Fizyka", 4.0)
+ ), emptyList()
)
)
)
@@ -803,7 +905,7 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { firstGrades to firstSummaries }
+ } returns resourceFlow { Triple(firstGrades, firstSummaries, emptyList()) }
coEvery {
gradeRepository.getGrades(
student,
@@ -811,9 +913,11 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- secondGrades to listOf(
- getSummary(22, "Matematyka", 1.1),
- getSummary(22, "Fizyka", 7.26)
+ Triple(
+ secondGrades, listOf(
+ getSummary(22, "Matematyka", 1.1),
+ getSummary(22, "Fizyka", 7.26)
+ ), emptyList()
)
}
@@ -850,9 +954,11 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- firstGrades to listOf(
- getSummary(22, "Matematyka", .0),
- getSummary(22, "Fizyka", .0)
+ Triple(
+ firstGrades, listOf(
+ getSummary(22, "Matematyka", .0),
+ getSummary(22, "Fizyka", .0)
+ ), emptyList()
)
}
coEvery {
@@ -862,9 +968,11 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- secondGrades to listOf(
- getSummary(22, "Matematyka", .0),
- getSummary(22, "Fizyka", .0)
+ Triple(
+ secondGrades, listOf(
+ getSummary(22, "Matematyka", .0),
+ getSummary(22, "Fizyka", .0)
+ ), emptyList()
)
}
@@ -889,24 +997,28 @@ class GradeAverageProviderTest {
coEvery { semesterRepository.getSemesters(student) } returns semesters
coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flow {
emit(Resource.Loading())
- emit(Resource.Intermediate(firstGrades to firstSummaries))
- emit(Resource.Success(firstGrades to firstSummaries))
+ emit(Resource.Intermediate(Triple(firstGrades, firstSummaries, emptyList())))
+ emit(Resource.Success(Triple(firstGrades, firstSummaries, emptyList())))
}
coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns flow {
emit(Resource.Loading())
emit(
Resource.Intermediate(
- secondGrades to listOf(
- getSummary(22, "Matematyka", 1.1),
- getSummary(22, "Fizyka", 7.26)
+ Triple(
+ secondGrades, listOf(
+ getSummary(22, "Matematyka", 1.1),
+ getSummary(22, "Fizyka", 7.26)
+ ), emptyList()
)
)
)
emit(
Resource.Success(
- secondGrades to listOf(
- getSummary(22, "Matematyka", 1.1),
- getSummary(22, "Fizyka", 7.26)
+ Triple(
+ secondGrades, listOf(
+ getSummary(22, "Matematyka", 1.1),
+ getSummary(22, "Fizyka", 7.26)
+ ), emptyList()
)
)
)
@@ -958,14 +1070,14 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { firstGrades to emptyList() }
+ } returns resourceFlow { Triple(firstGrades, emptyList(), emptyList()) }
coEvery {
gradeRepository.getGrades(
student,
semesters[2],
true
)
- } returns resourceFlow { secondGrades to emptyList() }
+ } returns resourceFlow { Triple(secondGrades, emptyList(), emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -1000,14 +1112,14 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { firstGrades to emptyList() }
+ } returns resourceFlow { Triple(firstGrades, emptyList(), emptyList()) }
coEvery {
gradeRepository.getGrades(
student,
semesters[2],
true
)
- } returns resourceFlow { secondGrades to emptyList() }
+ } returns resourceFlow { Triple(secondGrades, emptyList(), emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -1043,8 +1155,10 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- firstGrades to listOf(
- getSummary(22, "Matematyka", 4.0)
+ Triple(
+ firstGrades, listOf(
+ getSummary(22, "Matematyka", 4.0)
+ ), emptyList()
)
}
coEvery {
@@ -1054,8 +1168,10 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- secondGrades to listOf(
- getSummary(23, "Matematyka", 3.0)
+ Triple(
+ secondGrades, listOf(
+ getSummary(23, "Matematyka", 3.0)
+ ), emptyList()
)
}
@@ -1092,14 +1208,20 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { firstGrades to firstSummaries }
+ } returns resourceFlow { Triple(firstGrades, firstSummaries, emptyList()) }
coEvery {
gradeRepository.getGrades(
student,
semesters[2],
true
)
- } returns resourceFlow { secondGrades to secondSummaries.dropLast(1) }
+ } returns resourceFlow {
+ Triple(
+ secondGrades,
+ secondSummaries.dropLast(1),
+ emptyList()
+ )
+ }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -1134,14 +1256,20 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { firstGrades to firstSummaries.dropLast(1) }
+ } returns resourceFlow {
+ Triple(
+ firstGrades,
+ firstSummaries.dropLast(1),
+ emptyList()
+ )
+ }
coEvery {
gradeRepository.getGrades(
student,
semesters[2],
true
)
- } returns resourceFlow { secondGrades to secondSummaries }
+ } returns resourceFlow { Triple(secondGrades, secondSummaries, emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -1176,14 +1304,20 @@ class GradeAverageProviderTest {
semesters[1],
true
)
- } returns resourceFlow { firstGrades to firstSummaries.dropLast(1) }
+ } returns resourceFlow {
+ Triple(
+ firstGrades,
+ firstSummaries.dropLast(1),
+ emptyList()
+ )
+ }
coEvery {
gradeRepository.getGrades(
student,
semesters[2],
true
)
- } returns resourceFlow { secondGrades to secondSummaries }
+ } returns resourceFlow { Triple(secondGrades, secondSummaries, emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
@@ -1219,16 +1353,20 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- listOf(
- getGrade(22, "Fizyka", 5.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 5.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0)
- ) to listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(22, "Fizyka", 5.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 5.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
coEvery {
gradeRepository.getGrades(
@@ -1237,11 +1375,15 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- listOf(
- getGrade(23, "Fizyka", 5.0, weight = 1.0),
- getGrade(23, "Fizyka", 5.0, weight = 2.0),
- getGrade(23, "Fizyka", 4.0, modifier = 0.3, weight = 2.0)
- ) to listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(23, "Fizyka", 5.0, weight = 1.0),
+ getGrade(23, "Fizyka", 5.0, weight = 2.0),
+ getGrade(23, "Fizyka", 4.0, modifier = 0.3, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
val items = runBlocking {
@@ -1266,23 +1408,31 @@ class GradeAverageProviderTest {
every { preferencesRepository.gradeAverageModeFlow } returns flowOf(GradeAverageMode.ALL_YEAR)
coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns resourceFlow {
- listOf(
- getGrade(22, "Fizyka", 5.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 5.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0)
- ) to listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(22, "Fizyka", 5.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 5.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns resourceFlow {
- listOf(
- getGrade(23, "Fizyka", 5.0, weight = 1.0),
- getGrade(23, "Fizyka", 5.0, weight = 2.0),
- getGrade(23, "Fizyka", 4.0, modifier = 0.3, weight = 2.0)
- ) to listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(23, "Fizyka", 5.0, weight = 1.0),
+ getGrade(23, "Fizyka", 5.0, weight = 2.0),
+ getGrade(23, "Fizyka", 4.0, modifier = 0.3, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
val items = runBlocking {
@@ -1313,23 +1463,31 @@ class GradeAverageProviderTest {
coEvery { semesterRepository.getSemesters(student) } returns semesters
coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns resourceFlow {
- listOf(
- getGrade(22, "Fizyka", 5.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 5.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0)
- ) to listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(22, "Fizyka", 5.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 5.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns resourceFlow {
- listOf(
- getGrade(23, "Fizyka", 5.0, weight = 1.0),
- getGrade(23, "Fizyka", 5.0, weight = 2.0),
- getGrade(23, "Fizyka", 4.0, modifier = 0.33, weight = 2.0)
- ) to listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(23, "Fizyka", 5.0, weight = 1.0),
+ getGrade(23, "Fizyka", 5.0, weight = 2.0),
+ getGrade(23, "Fizyka", 4.0, modifier = 0.33, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
val items = runBlocking {
@@ -1366,16 +1524,20 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- listOf(
- getGrade(22, "Fizyka", 5.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 5.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 4.0),
- getGrade(22, "Fizyka", 6.0, weight = 2.0)
- ) to listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(22, "Fizyka", 5.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 5.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 4.0),
+ getGrade(22, "Fizyka", 6.0, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 22, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
coEvery {
gradeRepository.getGrades(
@@ -1384,11 +1546,15 @@ class GradeAverageProviderTest {
true
)
} returns resourceFlow {
- listOf(
- getGrade(23, "Fizyka", 5.0, weight = 1.0),
- getGrade(23, "Fizyka", 5.0, weight = 2.0),
- getGrade(23, "Fizyka", 4.0, modifier = 0.33, weight = 2.0)
- ) to listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0))
+ Triple(
+ listOf(
+ getGrade(23, "Fizyka", 5.0, weight = 1.0),
+ getGrade(23, "Fizyka", 5.0, weight = 2.0),
+ getGrade(23, "Fizyka", 4.0, modifier = 0.33, weight = 2.0)
+ ),
+ listOf(getSummary(semesterId = 23, subject = "Fizyka", average = .0)),
+ emptyList()
+ )
}
val items = runBlocking {
@@ -1413,9 +1579,9 @@ class GradeAverageProviderTest {
every { preferencesRepository.isOptionalArithmeticAverageFlow } returns flowOf(false)
coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns
- resourceFlow { firstGrades to firstSummaries }
+ resourceFlow { Triple(firstGrades, firstSummaries, emptyList()) }
coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns
- resourceFlow { listOf() to firstSummaries }
+ resourceFlow { Triple(listOf(), firstSummaries, emptyList()) }
val items = runBlocking {
gradeAverageProvider.getGradesDetailsWithAverage(
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 fad6436d8..34965f00d 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
@@ -58,7 +58,7 @@ class LoginStudentSelectPresenterTest {
login = "",
password = "",
baseUrl = "",
- symbol = null,
+ defaultSymbol = "warszawa",
domainSuffix = "",
)
diff --git a/build.gradle b/build.gradle
index 095d1b72f..f7f3d209e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,9 +14,9 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.16"
- classpath 'com.android.tools.build:gradle:8.2.1'
+ classpath 'com.android.tools.build:gradle:8.2.2'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
- classpath 'com.google.gms:google-services:4.4.0'
+ classpath 'com.google.gms:google-services:4.4.1'
classpath 'com.huawei.agconnect:agcp:1.9.1.303'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
classpath "com.github.triplet.gradle:play-publisher:3.8.4"