mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-18 08:12:44 +02:00
[API] Add Vulcan OneDrive attachment downloading. Add asking for permissions on demand.
This commit is contained in:
@ -65,6 +65,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
val gradesManager by lazy { GradesManager(this) }
|
||||
val timetableManager by lazy { TimetableManager(this) }
|
||||
val eventManager by lazy { EventManager(this) }
|
||||
val permissionManager by lazy { PermissionManager(this) }
|
||||
|
||||
val db
|
||||
get() = App.db
|
||||
|
@ -414,8 +414,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
R.color.md_green_500
|
||||
)
|
||||
|
||||
isStoragePermissionGranted()
|
||||
|
||||
SyncWorker.scheduleNext(app)
|
||||
UpdateWorker.scheduleNext(app)
|
||||
|
||||
|
@ -158,6 +158,7 @@ const val ERROR_LOGIN_VULCAN_NO_PUPILS = 331
|
||||
const val ERROR_VULCAN_API_MAINTENANCE = 340
|
||||
const val ERROR_VULCAN_API_BAD_REQUEST = 341
|
||||
const val ERROR_VULCAN_API_OTHER = 342
|
||||
const val ERROR_VULCAN_ATTACHMENT_DOWNLOAD = 343
|
||||
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402
|
||||
@ -207,5 +208,6 @@ const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
||||
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
||||
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
|
||||
const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921
|
||||
const val ERROR_ONEDRIVE_DOWNLOAD = 930
|
||||
|
||||
const val LOGIN_NO_ARGUMENTS = 1201
|
||||
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-4-7.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.helper
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_ONEDRIVE_DOWNLOAD
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
|
||||
import pl.szczodrzynski.edziennik.data.api.SYSTEM_USER_AGENT
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
class OneDriveDownloadAttachment(
|
||||
app: App,
|
||||
fileUrl: String,
|
||||
val onSuccess: (file: File) -> 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()
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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 }
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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<Int>("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 -> {
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user