diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 6afdce41..276cd1ca 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -41,5 +41,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 06caeb83..ae884511 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -198,6 +198,9 @@ dependencies {
kapt project(":codegen")
implementation 'com.google.android:flexbox:2.0.1'
+
+ implementation 'com.qifan.powerpermission:powerpermission:1.0.0'
+ implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.0.0'
}
repositories {
mavenCentral()
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 21c13afb..cc82fed3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,6 +14,9 @@
+
+
+
Unit,
+ val onProgress: (written: Long, total: Long) -> Unit,
+ val onError: (apiError: ApiError) -> Unit
+) {
+ companion object {
+ private const val TAG = "OneDriveDownloadAttachment"
+ }
+
+ init {
+ Request.builder()
+ .url(fileUrl)
+ .userAgent(SYSTEM_USER_AGENT)
+ .withClient(app.httpLazy)
+ .callback(object : TextCallbackHandler() {
+ override fun onSuccess(text: String, response: Response) {
+ val location = response.headers().get("Location")
+ if (location?.contains("onedrive.live.com/redir?resid=") != true) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withApiResponse(text)
+ .withResponse(response))
+ return
+ }
+ val url = location
+ .replace("onedrive.live.com/redir?resid=", "storage.live.com/items/")
+ .replace("&", "?")
+ downloadFile(url)
+ }
+
+ override fun onFailure(response: Response, throwable: Throwable) {
+ onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ })
+ .build()
+ .enqueue()
+ }
+
+ private fun downloadFile(url: String) {
+ val targetFile = Utils.getStorageDir()
+
+ val callback = object : FileCallbackHandler(targetFile) {
+ override fun onSuccess(file: File?, response: Response?) {
+ if (file == null) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withResponse(response))
+ return
+ }
+
+ try {
+ onSuccess(file)
+ } catch (e: Exception) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withResponse(response)
+ .withThrowable(e))
+ }
+ }
+
+ override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
+ try {
+ this@OneDriveDownloadAttachment.onProgress(bytesWritten, bytesTotal)
+ } catch (e: Exception) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withThrowable(e))
+ }
+ }
+
+ override fun onFailure(response: Response?, throwable: Throwable?) {
+ onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ }
+
+ Request.builder()
+ .url(url)
+ .userAgent(SYSTEM_USER_AGENT)
+ .callback(callback)
+ .build()
+ .enqueue()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusSandboxDownloadAttachment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusSandboxDownloadAttachment.kt
index c6131bb2..567071aa 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusSandboxDownloadAttachment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusSandboxDownloadAttachment.kt
@@ -54,13 +54,13 @@ class LibrusSandboxDownloadAttachment(override val data: DataLibrus,
}
private fun getAttachmentCheckKey(attachmentKey: String, callback: () -> Unit) {
- sandboxGet(LibrusMessagesGetAttachment.TAG, "CSCheckKey",
+ sandboxGet(TAG, "CSCheckKey",
parameters = mapOf("singleUseKey" to attachmentKey)) { json ->
when (json.getString("status")) {
"not_downloaded_yet" -> {
if (getAttachmentCheckKeyTries++ > 5) {
- data.error(ApiError(LibrusMessagesGetAttachment.TAG, ERROR_FILE_DOWNLOAD)
+ data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
.withApiResponse(json))
return@sandboxGet
}
@@ -75,7 +75,7 @@ class LibrusSandboxDownloadAttachment(override val data: DataLibrus,
}
else -> {
- data.error(ApiError(LibrusMessagesGetAttachment.TAG, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
+ data.error(ApiError(TAG, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
.withApiResponse(json))
}
}
@@ -85,7 +85,7 @@ class LibrusSandboxDownloadAttachment(override val data: DataLibrus,
private fun downloadAttachment(url: String, method: Int = GET) {
val targetFile = File(Utils.getStorageDir(), attachmentName)
- sandboxGetFile(LibrusMessagesGetAttachment.TAG, url, targetFile, { file ->
+ sandboxGetFile(TAG, url, targetFile, { file ->
val event = AttachmentGetEvent(
profileId,
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt
index a3125b9d..89b60543 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt
@@ -7,28 +7,29 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan
import com.google.gson.JsonObject
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_API
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.helper.OneDriveDownloadAttachment
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiAttachments
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiMessagesChangeStatus
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiSendMessage
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin.VulcanFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin
+import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError
-import pl.szczodrzynski.edziennik.data.api.prepare
-import pl.szczodrzynski.edziennik.data.api.prepareFor
-import pl.szczodrzynski.edziennik.data.api.vulcanLoginMethods
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
+import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.Utils.d
+import java.io.File
class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
companion object {
@@ -128,8 +129,51 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
override fun markAllAnnouncementsAsRead() {}
override fun getAnnouncement(announcement: AnnouncementFull) {}
- override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {}
override fun getRecipientList() {}
+
+ override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
+ val fileUrl = attachmentName.substringAfter(":")
+ if (attachmentName == fileUrl) {
+ data.error(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD))
+ return
+ }
+
+ OneDriveDownloadAttachment(
+ app,
+ fileUrl,
+ onSuccess = { file ->
+ val event = AttachmentGetEvent(
+ data.profileId,
+ owner,
+ attachmentId,
+ AttachmentGetEvent.TYPE_FINISHED,
+ file.absolutePath
+ )
+
+ val attachmentDataFile = File(Utils.getStorageDir(), ".${data.profileId}_${event.ownerId}_${event.attachmentId}")
+ Utils.writeStringToFile(attachmentDataFile, event.fileName)
+
+ EventBus.getDefault().postSticky(event)
+
+ completed()
+ },
+ onProgress = { written, total ->
+ val event = AttachmentGetEvent(
+ data.profileId,
+ owner,
+ attachmentId,
+ AttachmentGetEvent.TYPE_PROGRESS,
+ bytesWritten = written
+ )
+
+ EventBus.getDefault().postSticky(event)
+ },
+ onError = { apiError ->
+ data.error(apiError)
+ }
+ )
+ }
+
override fun getEvent(eventFull: EventFull) {
login(LOGIN_METHOD_VULCAN_API) {
val list = data.app.db.eventDao().getAllNow(data.profileId).filter { !it.addedManually }
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt
index 61777a8d..1442f40c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt
@@ -17,6 +17,7 @@ import com.google.gson.JsonObject
import pl.droidsonroids.gif.GifDrawable
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_EDUDZIENNIK
+import pl.szczodrzynski.edziennik.utils.ProfileImageHolder
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.navlib.ImageHolder
import pl.szczodrzynski.navlib.R
@@ -128,7 +129,7 @@ open class Profile(
override fun getImageHolder(context: Context): ImageHolder {
return if (!image.isNullOrEmpty()) {
try {
- ImageHolder(image ?: "")
+ ProfileImageHolder(image ?: "")
} catch (_: Exception) {
ImageHolder(R.drawable.profile, colorFromName(name))
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt
index ee48a453..a522d427 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt
@@ -85,6 +85,7 @@ class LoginChooserFragment : Fragment() {
}
b.devMode.visibility = if (App.debugMode) View.VISIBLE else View.GONE
+ b.devMode.isChecked = app.config.debugMode
b.devMode.onChange { v, isChecked ->
if (isChecked) {
MaterialDialog.Builder(activity)
@@ -94,6 +95,7 @@ class LoginChooserFragment : Fragment() {
.negativeText(R.string.no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
app.config.debugMode = true
+ App.devMode = true
MaterialAlertDialogBuilder(activity)
.setTitle("Restart")
.setMessage("Wymagany restart aplikacji")
@@ -104,12 +106,10 @@ class LoginChooserFragment : Fragment() {
}
.setCancelable(false)
.show()
- /*if (b.devModeLayout.getVisibility() !== View.VISIBLE) {
- Anim.expand(b.devModeTitle, 500, null)
- Anim.expand(b.devModeLayout, 500, null)
- }*/
}
.onNegative { _: MaterialDialog?, _: DialogAction? ->
+ app.config.debugMode = false
+ App.devMode = false
b.devMode.isChecked = app.config.debugMode
b.devMode.jumpDrawablesToCurrentState()
Anim.collapse(b.devMode, 1000, null)
@@ -117,6 +117,7 @@ class LoginChooserFragment : Fragment() {
.show()
} else {
app.config.debugMode = false
+ App.devMode = false
/*if (b.devModeLayout.getVisibility() === View.VISIBLE) {
Anim.collapse(b.devModeTitle, 500, null)
Anim.collapse(b.devModeLayout, 500, null)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt
index cc638693..1975f39e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt
@@ -58,8 +58,9 @@ class AttachmentAdapter(
val item = items[position]
val b = holder.b
+ val fileName = item.name.substringBefore(":http")
// create an icon for the attachment
- val icon: IIcon = when (Utils.getExtensionFromFileName(item.name)) {
+ val icon: IIcon = when (Utils.getExtensionFromFileName(fileName)) {
"doc", "docx", "odt", "rtf" -> SzkolnyFont.Icon.szf_file_word_outline
"xls", "xlsx", "ods" -> SzkolnyFont.Icon.szf_file_excel_outline
"ppt", "pptx", "odp" -> SzkolnyFont.Icon.szf_file_powerpoint_outline
@@ -73,12 +74,12 @@ class AttachmentAdapter(
}
b.chip.text = if (item.isDownloading) {
- app.getString(R.string.messages_attachment_downloading_format, item.name, item.downloadProgress)
+ app.getString(R.string.messages_attachment_downloading_format, fileName, item.downloadProgress)
}
else {
item.size?.let {
- app.getString(R.string.messages_attachment_format, item.name, Utils.readableFileSize(it))
- } ?: item.name
+ app.getString(R.string.messages_attachment_format, fileName, Utils.readableFileSize(it))
+ } ?: fileName
}
b.chip.chipIcon = IconicsDrawable(context)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentsView.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentsView.kt
index 22c5cfa6..682a86a5 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentsView.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentsView.kt
@@ -8,12 +8,14 @@ import android.content.Context
import android.os.Bundle
import android.os.Environment
import android.util.AttributeSet
+import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
+import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
@@ -41,6 +43,8 @@ class AttachmentsView @JvmOverloads constructor(
}
fun init(arguments: Bundle, owner: Any) {
+ val app = context.applicationContext as App
+ val activity = context as? AppCompatActivity ?: return
val list = this as? RecyclerView ?: return
val profileId = arguments.get("profileId") ?: return
@@ -49,12 +53,16 @@ class AttachmentsView @JvmOverloads constructor(
val attachmentSizes = arguments.getLongArray("attachmentSizes")
val adapter = AttachmentAdapter(context, onAttachmentClick = { item ->
- downloadAttachment(item)
+ app.permissionManager.requestStoragePermission(activity, R.string.permissions_attachment) {
+ downloadAttachment(item)
+ }
}, onAttachmentLongClick = { chip, item ->
val popupMenu = PopupMenu(chip.context, chip)
popupMenu.menu.add(0, 1, 0, R.string.messages_attachment_download_again)
popupMenu.setOnMenuItemClickListener {
- downloadAttachment(item, forceDownload = true)
+ app.permissionManager.requestStoragePermission(activity, R.string.permissions_attachment) {
+ downloadAttachment(item, forceDownload = true)
+ }
true
}
popupMenu.show()
@@ -97,7 +105,8 @@ class AttachmentsView @JvmOverloads constructor(
private fun downloadAttachment(attachment: AttachmentAdapter.Item, forceDownload: Boolean = false) {
if (!forceDownload && attachment.isDownloaded) {
- Utils.openFile(context, File(Utils.getStorageDir(), attachment.name))
+ // open file by name, or first part before ':' (Vulcan OneDrive)
+ Utils.openFile(context, File(Utils.getStorageDir(), attachment.name.substringBefore(":")))
return
}
@@ -128,17 +137,19 @@ class AttachmentsView @JvmOverloads constructor(
when (event.eventType) {
AttachmentGetEvent.TYPE_FINISHED -> {
// save the downloaded file name
- attachment.downloadedName = event.fileName
attachment.isDownloading = false
attachment.isDownloaded = true
- // update file name for iDziennik which
- // does not provide the name before downloading
- if (!attachment.name.contains("."))
- attachment.name = File(attachment.downloadedName).name
+ // get the download url before updating file name
+ val fileUrl = attachment.name.substringBefore(":", missingDelimiterValue = "")
+ // update file name with the downloaded one
+ attachment.name = File(event.fileName).name
+ // save the download url back
+ if (fileUrl != "")
+ attachment.name += ":$fileUrl"
// open the file
- Utils.openFile(context, File(Utils.getStorageDir(), attachment.name))
+ Utils.openFile(context, File(event.fileName))
}
AttachmentGetEvent.TYPE_PROGRESS -> {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/ProfileImageHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/ProfileImageHolder.kt
new file mode 100644
index 00000000..acd07259
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/ProfileImageHolder.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2020-4-7.
+ */
+
+package pl.szczodrzynski.edziennik.utils
+
+import android.widget.ImageView
+import pl.szczodrzynski.navlib.ImageHolder
+
+class ProfileImageHolder(url: String) : ImageHolder(url) {
+
+ override fun applyTo(imageView: ImageView, tag: String?): Boolean {
+ return try {
+ super.applyTo(imageView, tag)
+ } catch (_: Exception) { false }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt
new file mode 100644
index 00000000..4b80f44b
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2020-4-7.
+ */
+
+package pl.szczodrzynski.edziennik.utils.managers
+
+import android.Manifest
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.provider.Settings
+import androidx.annotation.StringRes
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.qifan.powerpermission.coroutines.awaitAskPermissions
+import com.qifan.powerpermission.data.hasAllGranted
+import com.qifan.powerpermission.data.hasPermanentDenied
+import com.qifan.powerpermission.data.hasRational
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.R
+import kotlin.coroutines.CoroutineContext
+
+class PermissionManager(val app: App) : CoroutineScope {
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ private fun isStoragePermissionGranted() = if (Build.VERSION.SDK_INT >= 23) {
+ app.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
+ } else {
+ true
+ }
+
+ fun requestStoragePermission(
+ activity: AppCompatActivity,
+ @StringRes permissionMessage: Int,
+ onSuccess: suspend CoroutineScope.() -> Unit
+ ) {
+ launch {
+ if (isStoragePermissionGranted()) {
+ onSuccess()
+ return@launch
+ }
+ val result = activity.awaitAskPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ when {
+ result.hasAllGranted() -> onSuccess()
+ result.hasRational() -> {
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.permissions_required)
+ .setMessage(permissionMessage)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ requestStoragePermission(activity, permissionMessage, onSuccess)
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .show()
+ }
+ result.hasPermanentDenied() -> {
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.permissions_required)
+ .setMessage(R.string.permissions_denied)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ val uri = Uri.fromParts("package", app.packageName, null)
+ intent.data = uri
+ activity.startActivity(intent)
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .show()
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index aba40d03..7d81cf33 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -88,7 +88,7 @@
today (%s)
tomorrow (%s)
You shouldn\'t really care about what you see here.
- These settings are intended for this app\'s developers, not for normal users.\n\nThey are not described in any way, so using them may lead to breaking some functions in the app, damaging your system or losing data.\n\nBe careful and use them wisely.
+ These settings are intended for this app\'s developers, not for normal users.\n\nThey are not described in any way, so using them may lead to breaking some functions in the app, damaging your system, losing data or even installing a virus on the battery.\n\nBe careful and use them wisely.
Developer mode
Predicted semester %d average:\n%#.2f\n
Predicted yearly average:\n%#.2f\n
@@ -431,7 +431,7 @@
Hello blank fragment
Help
Notification forwarding allows you to pair a PC web browser to receive notifications on your desktop. This includes new grades, events, homework etc.\n\nClick \"Notification forwarding\" to begin.
- Registraton will run automatically on the first login.\n\nThere will be some data sent to the app server:\n- your school and class ID\n- your e-register username\n- your first and last name\n\nThe only data visible to others is your name (when sharing events). Any private data (like password, grades etc.) won\'t be sent anywhere. Learn more in the Privacy policy.
+ Registration will run automatically on the first login.\n\nThere will be some data sent to the app server:\n- your school and class ID\n- your e-register username\n- your first and last name\n\nThe only data visible to others is your name (when sharing events). Any private data (like password, grades etc.) won\'t be sent anywhere. Learn more in the Privacy policy.
Download again
Edit event
Go to timetable
@@ -683,9 +683,9 @@
Draft
You don\'t have any messages
Error getting the recipient list
- %s, read: %s, %s]]>
- %s, read: yes]]>
- %s, read: no]]>
+ %s, read: %s, %s]]>
+ %s, read: yes]]>
+ %s, read: no]]>
Reply
%s at %s
Search
diff --git a/app/src/main/res/values/errors.xml b/app/src/main/res/values/errors.xml
index 1ff266a3..8e9e043b 100644
--- a/app/src/main/res/values/errors.xml
+++ b/app/src/main/res/values/errors.xml
@@ -128,6 +128,7 @@
ERROR_VULCAN_API_MAINTENANCE
ERROR_VULCAN_API_BAD_REQUEST
ERROR_VULCAN_API_OTHER
+ ERROR_VULCAN_ATTACHMENT_DOWNLOAD
ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN
ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME
@@ -177,6 +178,7 @@
EXCEPTION_IDZIENNIK_API_REQUEST
EXCEPTION_EDUDZIENNIK_WEB_REQUEST
EXCEPTION_EDUDZIENNIK_FILE_REQUEST
+ ERROR_ONEDRIVE_DOWNLOAD
LOGIN_NO_ARGUMENTS
@@ -304,6 +306,7 @@
Vulcan: przerwa techniczna
Vulcan: błąd żądania, zgłoś błąd
Vulcan: inny błąd, wyślij zgłoszenie
+ Vulcan: nie znaleziono adresu załącznika
Nieprawidłowe dane logowania
Nieprawidłowa nazwa szkoły
@@ -353,6 +356,7 @@
EXCEPTION_IDZIENNIK_API_REQUEST
Wystąpił błąd
Wystąpił błąd podczas pobierania pliku
+ Nie udało się pobrać pliku z OneDrive
Nie podano parametrów
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e09f5d1a..98ed893a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -38,7 +38,7 @@
%s (%s)
%s
%s, %s
- %s]]>
+ %s]]>
Szkolny.eu: %s
pl.szczodrzynski.edziennik_preferences
pl.szczodrzynski.edziennik_profiles
@@ -736,9 +736,9 @@
Wersja robocza
Nie masz żadnych wiadomości.
Błąd pobierania listy odbiorców
- %s, przeczytano: %s, %s]]>
- %s, przeczytano: tak]]>
- %s, przeczytano: nie]]>
+ %s, przeczytano: %s, %s]]>
+ %s, przeczytano: tak]]>
+ %s, przeczytano: nie]]>
Odpowiedz
%s o %s
Szukaj
@@ -1281,4 +1281,7 @@
wczoraj
Jesteś offline. Spróbuj włączyć Wi-Fi lub dane komórkowe.
Połączenie sieciowe
+ Wymagane uprawnienia
+ Odmówiłeś aplikacji wymaganych uprawnień do wykonania tej czynności.\n\nAby przynać uprawnienia, otwórz sekcję Uprawnienia dla aplikacji Szkolny.eu w ustawieniach telefonu.\n\nKliknij OK, aby przejść do ustawień aplikacji.
+ Musisz przyznać uprawnienia do zapisu plików w pamięci telefonu, aby móc pobrać załącznik.\n\nKliknij OK, aby przyznać uprawnienia.
diff --git a/build.gradle b/build.gradle
index f6228cce..705a0c97 100644
--- a/build.gradle
+++ b/build.gradle
@@ -87,6 +87,7 @@ allprojects {
maven { url 'https://jitpack.io' }
maven { url "https://kotlin.bintray.com/kotlinx/" }
maven { url "https://dl.bintray.com/wulkanowy/wulkanowy" }
+ maven { url "https://dl.bintray.com/undervoid/PowerPermission" }
}
}