mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-01-18 12:56:45 -06:00
Merge pull request #5 from szkolny-eu/feature/new-settings
Add new Settings UI
This commit is contained in:
commit
5c87ae2711
@ -115,7 +115,7 @@ dependencies {
|
||||
implementation "eu.szkolny:agendacalendarview:1799f8ef47"
|
||||
implementation "eu.szkolny:cafebar:5bf0c618de"
|
||||
implementation "eu.szkolny.fslogin:lib:2.0.0"
|
||||
implementation "eu.szkolny:material-about-library:0534abf316"
|
||||
implementation "eu.szkolny:material-about-library:fe4a5cd6f1"
|
||||
implementation "eu.szkolny:mhttp:af4b62e6e9"
|
||||
implementation "eu.szkolny:nachos:0e5dfcaceb"
|
||||
implementation "eu.szkolny.selective-dao:annotation:27f8f3f194"
|
||||
@ -129,7 +129,7 @@ dependencies {
|
||||
implementation "com.mikepenz:iconics-core:5.2.8"
|
||||
implementation "com.mikepenz:iconics-views:5.2.8"
|
||||
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
|
||||
implementation "eu.szkolny:szkolny-font:1dab7d64ed"
|
||||
implementation "eu.szkolny:szkolny-font:1.3"
|
||||
|
||||
// Other dependencies
|
||||
implementation "cat.ereza:customactivityoncrash:2.3.0"
|
||||
@ -139,6 +139,7 @@ dependencies {
|
||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2"
|
||||
implementation "com.github.bassaer:chatmessageview:2.0.1"
|
||||
implementation "com.github.CanHub:Android-Image-Cropper:2.2.2"
|
||||
implementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
|
||||
implementation "com.github.jetradarmobile:android-snowfall:1.2.0"
|
||||
implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31"
|
||||
@ -147,7 +148,6 @@ dependencies {
|
||||
implementation "com.jaredrummler:colorpicker:1.1.0"
|
||||
implementation "com.qifan.powerpermission:powerpermission-coroutines:1.3.0"
|
||||
implementation "com.qifan.powerpermission:powerpermission:1.3.0"
|
||||
implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0"
|
||||
implementation "com.wdullaer:materialdatetimepicker:4.2.3"
|
||||
implementation "com.yuyh.json:jsonviewer:1.0.6"
|
||||
implementation "io.coil-kt:coil:1.1.1"
|
||||
|
@ -143,8 +143,7 @@
|
||||
<activity android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".ui.modules.webpush.QrScannerActivity" />
|
||||
<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
||||
<activity android:name="com.canhub.cropper.CropImageActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/Base.Theme.AppCompat" />
|
||||
|
||||
|
@ -1,12 +1,9 @@
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
@ -29,7 +26,6 @@ import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.*
|
||||
import androidx.annotation.*
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.database.getIntOrNull
|
||||
import androidx.core.database.getLongOrNull
|
||||
import androidx.core.database.getStringOrNull
|
||||
@ -304,19 +300,6 @@ fun colorFromCssName(name: String): Int {
|
||||
|
||||
fun List<Profile>.filterOutArchived() = this.filter { !it.archived }
|
||||
|
||||
fun Activity.isStoragePermissionGranted(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
true
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun Response?.getUnixDate(): Long {
|
||||
val rfcDate = this?.headers()?.get("date") ?: return currentTimeUnix()
|
||||
val pattern = "EEE, dd MMM yyyy HH:mm:ss Z"
|
||||
@ -1278,3 +1261,41 @@ operator fun <K, V> Iterable<Pair<K, V>>.get(key: K): V? {
|
||||
}
|
||||
|
||||
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
|
||||
|
||||
fun <E> MutableList<E>.after(what: E, insert: E) {
|
||||
val index = indexOf(what)
|
||||
if (index != -1)
|
||||
add(index + 1, insert)
|
||||
}
|
||||
|
||||
fun <E> MutableList<E>.before(what: E, insert: E) {
|
||||
val index = indexOf(what)
|
||||
if (index != -1)
|
||||
add(index, insert)
|
||||
}
|
||||
|
||||
fun <E> MutableList<E>.after(what: E, insert: Collection<E>) {
|
||||
val index = indexOf(what)
|
||||
if (index != -1)
|
||||
addAll(index + 1, insert)
|
||||
}
|
||||
|
||||
fun <E> MutableList<E>.before(what: E, insert: Collection<E>) {
|
||||
val index = indexOf(what)
|
||||
if (index != -1)
|
||||
addAll(index, insert)
|
||||
}
|
||||
|
||||
fun Context.getSyncInterval(interval: Int): String {
|
||||
val hours = interval / 60 / 60
|
||||
val minutes = interval / 60 % 60
|
||||
val hoursText = if (hours > 0)
|
||||
plural(R.plurals.time_till_hours, hours)
|
||||
else
|
||||
null
|
||||
val minutesText = if (minutes > 0)
|
||||
plural(R.plurals.time_till_minutes, minutes)
|
||||
else
|
||||
""
|
||||
return hoursText?.plus(" $minutesText") ?: minutesText
|
||||
}
|
||||
|
@ -10,13 +10,11 @@ import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
@ -56,7 +54,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.UpdateAvailableDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||
@ -79,7 +77,7 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment
|
||||
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
|
||||
@ -97,7 +95,6 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
import pl.szczodrzynski.navlib.drawer.NavDrawer
|
||||
import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@ -110,8 +107,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
|
||||
const val TAG = "MainActivity"
|
||||
|
||||
const val REQUEST_LOGIN_ACTIVITY = 20222
|
||||
|
||||
const val DRAWER_PROFILE_ADD_NEW = 200
|
||||
const val DRAWER_PROFILE_SYNC_ALL = 201
|
||||
const val DRAWER_PROFILE_EXPORT_DATA = 202
|
||||
@ -199,7 +194,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
.isStatic(true)
|
||||
.isBelowSeparator(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
@ -257,6 +252,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
|
||||
val mainSnackbar: MainSnackbar by lazy { MainSnackbar(this) }
|
||||
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
|
||||
val requestHandler by lazy { MainActivityRequestHandler(this) }
|
||||
|
||||
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
||||
|
||||
@ -392,7 +388,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
drawerProfileLongClickListener = { _, profile, _, view ->
|
||||
if (view != null && profile is ProfileDrawerItem) {
|
||||
showProfileContextMenu(profile, view)
|
||||
launch {
|
||||
val appProfile = withContext(Dispatchers.IO) {
|
||||
App.db.profileDao().getByIdNow(profile.identifier.toInt())
|
||||
} ?: return@launch
|
||||
drawer.close()
|
||||
ProfileConfigDialog(this@MainActivity, appProfile)
|
||||
}
|
||||
true
|
||||
}
|
||||
else {
|
||||
@ -472,28 +474,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
|
||||
// APP BACKGROUND
|
||||
if (app.config.ui.appBackground != null) {
|
||||
try {
|
||||
app.config.ui.appBackground?.let {
|
||||
var bg = it
|
||||
val bgDir = File(Environment.getExternalStoragePublicDirectory("Szkolny.eu"), "bg")
|
||||
if (bgDir.exists()) {
|
||||
val files = bgDir.listFiles()
|
||||
val r = Random()
|
||||
val i = r.nextInt(files.size)
|
||||
bg = files[i].toString()
|
||||
}
|
||||
val linearLayout = b.root
|
||||
if (bg.endsWith(".gif")) {
|
||||
linearLayout.background = GifDrawable(bg)
|
||||
} else {
|
||||
linearLayout.background = BitmapDrawable.createFromPath(bg)
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
setAppBackground()
|
||||
|
||||
// IT'S WINTER MY DUDES
|
||||
val today = Date.getToday()
|
||||
@ -575,7 +556,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
if (App.devMode) {
|
||||
bottomSheet += BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_debug)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
||||
}
|
||||
}
|
||||
@ -583,7 +564,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
private var profileSettingClickListener = { id: Int, view: View? ->
|
||||
when (id) {
|
||||
DRAWER_PROFILE_ADD_NEW -> {
|
||||
startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY)
|
||||
requestHandler.requestLogin()
|
||||
}
|
||||
DRAWER_PROFILE_SYNC_ALL -> {
|
||||
EdziennikTask.sync().enqueue(this)
|
||||
@ -831,7 +812,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
handleIntent(intent?.extras)
|
||||
}
|
||||
}
|
||||
private fun handleIntent(extras: Bundle?) {
|
||||
fun handleIntent(extras: Bundle?) {
|
||||
|
||||
d(TAG, "handleIntent() {")
|
||||
extras?.keySet()?.forEach { key ->
|
||||
@ -989,13 +970,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == REQUEST_LOGIN_ACTIVITY) {
|
||||
if (!app.config.loginFinished)
|
||||
finish()
|
||||
else {
|
||||
handleIntent(data?.extras)
|
||||
}
|
||||
}
|
||||
requestHandler.handleResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
/* _ _ _ _ _
|
||||
@ -1221,6 +1196,19 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
fun setAppBackground() {
|
||||
try {
|
||||
b.root.background = app.config.ui.appBackground?.let {
|
||||
if (it.endsWith(".gif"))
|
||||
GifDrawable(it)
|
||||
else
|
||||
BitmapDrawable.createFromPath(it)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
/* _____ _ _
|
||||
| __ \ (_) |
|
||||
| | | |_ __ __ ___ _____ _ __ _| |_ ___ _ __ ___ ___
|
||||
@ -1296,26 +1284,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
drawer.addProfileSettings(*drawerProfiles.toTypedArray())
|
||||
}
|
||||
|
||||
private fun showProfileContextMenu(profile: IProfile, view: View) {
|
||||
val profileId = profile.identifier.toInt()
|
||||
val popupMenu = PopupMenu(this, view)
|
||||
popupMenu.menu.add(0, 1, 1, R.string.profile_menu_open_settings)
|
||||
popupMenu.menu.add(0, 2, 2, R.string.profile_menu_remove)
|
||||
popupMenu.setOnMenuItemClickListener { item ->
|
||||
if (item.itemId == 1) {
|
||||
if (profileId != app.profile.id) {
|
||||
loadProfile(profileId, DRAWER_ITEM_SETTINGS)
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
loadTarget(DRAWER_ITEM_SETTINGS, null)
|
||||
} else if (item.itemId == 2) {
|
||||
ProfileRemoveDialog(this, profileId, profile.name?.getText(this) ?: "?")
|
||||
}
|
||||
true
|
||||
}
|
||||
popupMenu.show()
|
||||
}
|
||||
|
||||
private val targetPopToHomeList = arrayListOf<Int>()
|
||||
private var targetHomeId: Int = -1
|
||||
override fun onBackPressed() {
|
||||
|
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-23.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import com.canhub.cropper.CropImage
|
||||
import com.canhub.cropper.CropImageView
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class MainActivityRequestHandler(val activity: MainActivity) {
|
||||
companion object {
|
||||
private const val REQUEST_LOGIN_ACTIVITY = 2000
|
||||
private const val REQUEST_FILE_HEADER_BACKGROUND = 3000
|
||||
private const val REQUEST_FILE_APP_BACKGROUND = 4000
|
||||
private const val REQUEST_FILE_PROFILE_IMAGE = 5000
|
||||
private const val REQUEST_CROP_HEADER_BACKGROUND = 3100
|
||||
private const val REQUEST_CROP_APP_BACKGROUND = 4100
|
||||
private const val REQUEST_CROP_PROFILE_IMAGE = 5100
|
||||
}
|
||||
|
||||
private val app = activity.app
|
||||
private val requestData = mutableMapOf<Int, Any?>()
|
||||
private val listeners = mutableMapOf<Int, (data: Any?) -> Unit>()
|
||||
|
||||
private val manager
|
||||
get() = app.permissionManager
|
||||
|
||||
fun requestLogin() = activity.startActivityForResult(
|
||||
Intent(activity, LoginActivity::class.java),
|
||||
REQUEST_LOGIN_ACTIVITY
|
||||
)
|
||||
|
||||
fun requestHeaderBackground(listener: (Any?) -> Unit) =
|
||||
manager.requestCameraPermission(
|
||||
activity, 0, isRequired = false
|
||||
) {
|
||||
listeners[REQUEST_FILE_HEADER_BACKGROUND] = listener
|
||||
activity.startActivityForResult(
|
||||
CropImage.getPickImageChooserIntent(
|
||||
activity,
|
||||
activity.getString(R.string.pick_image_intent_chooser_title),
|
||||
true,
|
||||
true
|
||||
),
|
||||
REQUEST_FILE_HEADER_BACKGROUND
|
||||
)
|
||||
}
|
||||
|
||||
fun requestAppBackground(listener: (Any?) -> Unit) =
|
||||
manager.requestCameraPermission(
|
||||
activity, 0, isRequired = false
|
||||
) {
|
||||
listeners[REQUEST_FILE_APP_BACKGROUND] = listener
|
||||
activity.startActivityForResult(
|
||||
CropImage.getPickImageChooserIntent(
|
||||
activity,
|
||||
activity.getString(R.string.pick_image_intent_chooser_title),
|
||||
true,
|
||||
true
|
||||
),
|
||||
REQUEST_FILE_APP_BACKGROUND
|
||||
)
|
||||
}
|
||||
|
||||
fun requestProfileImage(profile: Profile, listener: (Any?) -> Unit) =
|
||||
manager.requestCameraPermission(
|
||||
activity, 0, isRequired = false
|
||||
) {
|
||||
listeners[REQUEST_FILE_PROFILE_IMAGE] = listener
|
||||
requestData[REQUEST_FILE_PROFILE_IMAGE] = profile
|
||||
activity.startActivityForResult(
|
||||
CropImage.getPickImageChooserIntent(
|
||||
activity,
|
||||
activity.getString(R.string.pick_image_intent_chooser_title),
|
||||
true,
|
||||
true
|
||||
),
|
||||
REQUEST_FILE_PROFILE_IMAGE
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFileInfo(uri: Uri): Pair<String, String?> {
|
||||
if (uri.scheme == "file") {
|
||||
return (uri.lastPathSegment ?: "unknown") to null
|
||||
}
|
||||
val cursor = activity.contentResolver.query(
|
||||
uri,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
return cursor?.use {
|
||||
if (it.moveToFirst()) {
|
||||
val name = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
|
||||
val mimeIndex = it.getColumnIndex("mime_type")
|
||||
val mimeType = if (mimeIndex != -1) it.getString(mimeIndex) else null
|
||||
|
||||
name to mimeType
|
||||
} else
|
||||
null
|
||||
} ?: "unknown" to null
|
||||
}
|
||||
|
||||
private fun shouldCrop(uri: Uri): Boolean {
|
||||
val (filename, mimeType) = getFileInfo(uri)
|
||||
return !filename.endsWith(".gif") && mimeType?.endsWith("/gif") != true
|
||||
}
|
||||
|
||||
private fun saveFile(uri: Uri, name: String): String {
|
||||
val (filename, _) = getFileInfo(uri)
|
||||
val extension = filename.substringAfterLast('.')
|
||||
val file = File(activity.filesDir, "$name.$extension")
|
||||
activity.contentResolver.openInputStream(uri)?.use { input ->
|
||||
FileOutputStream(file).use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
return file.absolutePath
|
||||
}
|
||||
|
||||
fun handleResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode != Activity.RESULT_OK)
|
||||
return
|
||||
var uri = CropImage.getPickImageResultUri(activity, data)
|
||||
when (requestCode) {
|
||||
REQUEST_LOGIN_ACTIVITY -> {
|
||||
if (!app.config.loginFinished)
|
||||
activity.finish()
|
||||
else {
|
||||
activity.handleIntent(data?.extras)
|
||||
}
|
||||
}
|
||||
REQUEST_FILE_HEADER_BACKGROUND -> {
|
||||
if (uri == null)
|
||||
return // TODO: 2021-03-24 if the app returns no data
|
||||
if (shouldCrop(uri)) {
|
||||
val intent = CropImage.activity(uri)
|
||||
.setAspectRatio(512, 288)
|
||||
.setGuidelines(CropImageView.Guidelines.ON_TOUCH)
|
||||
.setAllowFlipping(true)
|
||||
.setAllowRotation(true)
|
||||
.setRequestedSize(512, 288)
|
||||
.getIntent(activity)
|
||||
activity.startActivityForResult(intent, REQUEST_CROP_HEADER_BACKGROUND)
|
||||
} else {
|
||||
val path = saveFile(uri, "header")
|
||||
app.config.ui.headerBackground = path
|
||||
listeners.remove(REQUEST_FILE_HEADER_BACKGROUND)?.invoke(path)
|
||||
}
|
||||
}
|
||||
REQUEST_FILE_APP_BACKGROUND -> {
|
||||
if (uri == null)
|
||||
return
|
||||
if (shouldCrop(uri)) {
|
||||
val intent = CropImage.activity(uri)
|
||||
.setGuidelines(CropImageView.Guidelines.ON_TOUCH)
|
||||
.setAllowFlipping(true)
|
||||
.setAllowRotation(true)
|
||||
.getIntent(activity)
|
||||
activity.startActivityForResult(intent, REQUEST_CROP_APP_BACKGROUND)
|
||||
} else {
|
||||
val path = saveFile(uri, "background")
|
||||
app.config.ui.appBackground = path
|
||||
listeners.remove(REQUEST_FILE_APP_BACKGROUND)?.invoke(path)
|
||||
}
|
||||
}
|
||||
REQUEST_FILE_PROFILE_IMAGE -> {
|
||||
if (uri == null)
|
||||
return
|
||||
if (shouldCrop(uri)) {
|
||||
val intent = CropImage.activity(uri)
|
||||
.setAspectRatio(1, 1)
|
||||
.setCropShape(CropImageView.CropShape.OVAL)
|
||||
.setGuidelines(CropImageView.Guidelines.ON_TOUCH)
|
||||
.setAllowFlipping(true)
|
||||
.setAllowRotation(true)
|
||||
.setRequestedSize(512, 512)
|
||||
.getIntent(activity)
|
||||
activity.startActivityForResult(intent, REQUEST_CROP_PROFILE_IMAGE)
|
||||
} else {
|
||||
val profile =
|
||||
requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return
|
||||
val path = saveFile(uri, "profile${profile.id}")
|
||||
profile.image = path
|
||||
listeners.remove(REQUEST_FILE_PROFILE_IMAGE)?.invoke(profile)
|
||||
}
|
||||
}
|
||||
REQUEST_CROP_HEADER_BACKGROUND -> {
|
||||
uri = CropImage.getActivityResult(data)?.uri ?: return
|
||||
val path = saveFile(uri, "header")
|
||||
app.config.ui.headerBackground = path
|
||||
listeners.remove(REQUEST_FILE_HEADER_BACKGROUND)?.invoke(path)
|
||||
}
|
||||
REQUEST_CROP_APP_BACKGROUND -> {
|
||||
uri = CropImage.getActivityResult(data)?.uri ?: return
|
||||
val path = saveFile(uri, "background")
|
||||
app.config.ui.appBackground = path
|
||||
listeners.remove(REQUEST_FILE_APP_BACKGROUND)?.invoke(path)
|
||||
}
|
||||
REQUEST_CROP_PROFILE_IMAGE -> {
|
||||
uri = CropImage.getActivityResult(data)?.uri ?: return
|
||||
val profile = requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return
|
||||
val path = saveFile(uri, "profile${profile.id}")
|
||||
profile.image = path
|
||||
listeners.remove(REQUEST_FILE_PROFILE_IMAGE)?.invoke(profile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.bell
|
||||
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class BellSyncConfigDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val onChangeListener: (() -> Unit)? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "BellSyncConfigDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
|
||||
private fun parse(input: String): Pair<Time, Int>? {
|
||||
if (input.length < 8) {
|
||||
return null
|
||||
}
|
||||
if (input[2] != ':' || input[5] != ':') {
|
||||
return null
|
||||
}
|
||||
val multiplier = when {
|
||||
input[0] == '+' -> 1
|
||||
input[0] == '-' -> -1
|
||||
else -> return null
|
||||
}
|
||||
val time = Time.fromH_m_s("0" + input.substring(1))
|
||||
|
||||
return time to multiplier
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
app = activity.applicationContext as App
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.bell_sync_title)
|
||||
.setView(R.layout.dialog_edit_text)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setNeutralButton(R.string.reset) { _, _ ->
|
||||
app.config.timetable.bellSyncDiff = null
|
||||
app.config.timetable.bellSyncMultiplier = 0
|
||||
onChangeListener?.invoke()
|
||||
}
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
|
||||
val message = dialog.findViewById<TextView>(android.R.id.title)
|
||||
val editText = dialog.findViewById<TextInputEditText>(android.R.id.text1)
|
||||
val textLayout = dialog.findViewById<TextInputLayout>(R.id.text_input_layout)
|
||||
|
||||
message?.setText(R.string.bell_sync_adjust_content)
|
||||
editText?.hint = "±H:MM:SS"
|
||||
editText?.setText(app.config.timetable.bellSyncDiff?.let {
|
||||
(if (app.config.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS
|
||||
} ?: "+0:00:00")
|
||||
editText?.addTextChangedListener { text ->
|
||||
val input = text?.toString()
|
||||
textLayout?.error =
|
||||
if (input != null && parse(input) == null)
|
||||
activity.getString(R.string.bell_sync_adjust_error)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.onClick {
|
||||
val input = editText?.text?.toString() ?: return@onClick
|
||||
val parsed = parse(input)
|
||||
if (parsed == null) {
|
||||
Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show()
|
||||
return@onClick
|
||||
}
|
||||
|
||||
val (time, multiplier) = parsed
|
||||
app.config.timetable.bellSyncDiff =
|
||||
if (time.value == 0)
|
||||
null
|
||||
else
|
||||
time
|
||||
app.config.timetable.bellSyncMultiplier = multiplier
|
||||
|
||||
onChangeListener?.invoke()
|
||||
dialog.dismiss()
|
||||
}
|
||||
}}
|
||||
}
|
@ -33,7 +33,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationEnableDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.views.TimeDropdown.Companion.DISPLAY_LESSONS
|
||||
import pl.szczodrzynski.edziennik.utils.Anim
|
||||
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
@ -64,7 +64,7 @@ class EventManualDialog(
|
||||
private val app by lazy { activity.application as App }
|
||||
private lateinit var b: DialogEventManualV2Binding
|
||||
private lateinit var dialog: AlertDialog
|
||||
private var profile: Profile? = null
|
||||
private lateinit var profile: Profile
|
||||
|
||||
private var customColor: Int? = null
|
||||
private val editingShared = editingEvent?.sharedBy != null
|
||||
@ -80,11 +80,11 @@ class EventManualDialog(
|
||||
|
||||
private var progressDialog: AlertDialog? = null
|
||||
|
||||
init { run {
|
||||
init { launch {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
return@launch
|
||||
onShowListener?.invoke(TAG)
|
||||
EventBus.getDefault().register(this)
|
||||
EventBus.getDefault().register(this@EventManualDialog)
|
||||
b = DialogEventManualV2Binding.inflate(activity.layoutInflater)
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.dialog_event_manual_title)
|
||||
@ -236,8 +236,15 @@ class EventManualDialog(
|
||||
progressDialog?.dismiss()
|
||||
}
|
||||
|
||||
private fun loadLists() { launch {
|
||||
profile = withContext(Dispatchers.Default) { app.db.profileDao().getByIdNow(profileId) }
|
||||
private fun loadLists() = launch {
|
||||
val profile = withContext(Dispatchers.Default) {
|
||||
app.db.profileDao().getByIdNow(profileId)
|
||||
}
|
||||
if (profile == null) {
|
||||
Toast.makeText(activity, R.string.event_manual_no_profile, Toast.LENGTH_SHORT).show()
|
||||
return@launch
|
||||
}
|
||||
this@EventManualDialog.profile = profile
|
||||
|
||||
with (b.dateDropdown) {
|
||||
db = app.db
|
||||
@ -380,7 +387,7 @@ class EventManualDialog(
|
||||
})
|
||||
colorPickerDialog.show(activity.supportFragmentManager, "color-picker-dialog")
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
private fun showRemoveEventDialog() {
|
||||
val shareNotice = when {
|
||||
@ -417,12 +424,11 @@ class EventManualDialog(
|
||||
|
||||
val share = b.shareSwitch.isChecked
|
||||
|
||||
if (share && profile?.registration != Profile.REGISTRATION_ENABLED) {
|
||||
RegistrationEnableDialog(activity, profileId).showEventShareDialog {
|
||||
if (it != null)
|
||||
profile = it
|
||||
saveEvent()
|
||||
}
|
||||
if (share && profile.registration != Profile.REGISTRATION_ENABLED) {
|
||||
RegistrationConfigDialog(activity, profile, onChangeListener = { enabled ->
|
||||
if (enabled)
|
||||
saveEvent()
|
||||
}).showEventShareDialog()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ import pl.szczodrzynski.edziennik.data.db.full.GradeFull
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogGradeDetailsBinding
|
||||
import pl.szczodrzynski.edziennik.onClick
|
||||
import pl.szczodrzynski.edziennik.setTintColor
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-16
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.grade
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.appcompat.app.AlertDialog
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-23.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.profile
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogProfileConfigBinding
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileConfigDialog(
|
||||
val activity: MainActivity,
|
||||
val profile: Profile,
|
||||
val onProfileSaved: ((profile: Profile) -> Unit)? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "ProfileConfigDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var b: DialogProfileConfigBinding
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
private var profileChanged = false
|
||||
private var profileRemoved = false
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
app = activity.applicationContext as App
|
||||
b = DialogProfileConfigBinding.inflate(activity.layoutInflater)
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setView(b.root)
|
||||
.setPositiveButton(R.string.close, null)
|
||||
.setOnDismissListener {
|
||||
if (!profileRemoved && profileChanged) {
|
||||
app.profileSave(profile)
|
||||
onProfileSaved?.invoke(profile)
|
||||
}
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
|
||||
b.profile = profile
|
||||
profile.applyImageTo(b.image)
|
||||
|
||||
// I can't believe how simple it is to get the dialog's background color !!
|
||||
val shape = MaterialShapeDrawable(activity, null, R.attr.alertDialogStyle, R.style.MaterialAlertDialog_MaterialComponents)
|
||||
val surface = MaterialColors.getColor(activity, R.attr.colorSurface, TAG)
|
||||
shape.setCornerSize(18.dp.toFloat())
|
||||
shape.initializeElevationOverlay(activity)
|
||||
shape.fillColor = ColorStateList.valueOf(surface)
|
||||
shape.elevation = 16.dp.toFloat()
|
||||
b.circleView.background = shape
|
||||
|
||||
b.nameEdit.addTextChangedListener {
|
||||
profileChanged = true
|
||||
}
|
||||
|
||||
b.syncSwitch.onChange { _, _ ->
|
||||
profileChanged = true
|
||||
}
|
||||
|
||||
b.imageButton.onClick {
|
||||
activity.requestHandler.requestProfileImage(profile) {
|
||||
val profile = it as? Profile ?: return@requestProfileImage
|
||||
if (this@ProfileConfigDialog.profile == profile) {
|
||||
profileChanged = true
|
||||
b.profile = profile
|
||||
b.image.setImageDrawable(profile.getImageDrawable(activity))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.logoutButton.onClick {
|
||||
ProfileRemoveDialog(activity, profile.id, profile.name) {
|
||||
profileRemoved = true
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.profile
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
@ -18,7 +18,8 @@ class ProfileRemoveDialog(
|
||||
val activity: MainActivity,
|
||||
val profileId: Int,
|
||||
val profileName: String,
|
||||
val noProfileRemoval: Boolean = false
|
||||
val noProfileRemoval: Boolean = false,
|
||||
val onRemove: (() -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "ProfileRemoveDialog"
|
||||
@ -95,5 +96,6 @@ class ProfileRemoveDialog(
|
||||
dialog.dismiss()
|
||||
activity.reloadTarget()
|
||||
Toast.makeText(activity, R.string.dialog_profile_remove_success, Toast.LENGTH_LONG).show()
|
||||
onRemove?.invoke()
|
||||
}}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-19.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class AppLanguageDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "AppLanguageDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
app = activity.applicationContext as App
|
||||
|
||||
val languages = mapOf(
|
||||
null to R.string.language_system,
|
||||
"pl" to R.string.language_polish,
|
||||
"en" to R.string.language_english,
|
||||
"de" to R.string.language_german
|
||||
)
|
||||
val languageIds = languages.map { it.key }
|
||||
val languageNames = languages.map {
|
||||
activity.getString(it.value)
|
||||
}
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.app_language_dialog_title)
|
||||
//.setMessage(R.string.settings_about_language_dialog_text)
|
||||
.setSingleChoiceItems(
|
||||
languageNames.toTypedArray(),
|
||||
languageIds.indexOf(app.config.ui.language),
|
||||
null
|
||||
)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
val which = dialog.listView.checkedItemPosition
|
||||
|
||||
app.config.ui.language = languageIds[which]
|
||||
activity.recreate()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_NOTIFICATIONS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_SETTINGS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class MiniMenuConfigDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "MiniMenuConfigDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
app = activity.applicationContext as App
|
||||
|
||||
val buttons = mapOf(
|
||||
DRAWER_ITEM_HOME to R.string.menu_home_page,
|
||||
DRAWER_ITEM_TIMETABLE to R.string.menu_timetable,
|
||||
DRAWER_ITEM_AGENDA to R.string.menu_agenda,
|
||||
DRAWER_ITEM_GRADES to R.string.menu_grades,
|
||||
DRAWER_ITEM_MESSAGES to R.string.menu_messages,
|
||||
DRAWER_ITEM_HOMEWORK to R.string.menu_homework,
|
||||
DRAWER_ITEM_BEHAVIOUR to R.string.menu_notices,
|
||||
DRAWER_ITEM_ATTENDANCE to R.string.menu_attendance,
|
||||
DRAWER_ITEM_ANNOUNCEMENTS to R.string.menu_announcements,
|
||||
DRAWER_ITEM_NOTIFICATIONS to R.string.menu_notifications,
|
||||
DRAWER_ITEM_SETTINGS to R.string.menu_settings
|
||||
)
|
||||
val miniMenuButtons = app.config.ui.miniMenuButtons
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.settings_theme_mini_drawer_buttons_dialog_title)
|
||||
//.setMessage(R.string.settings_theme_mini_drawer_buttons_dialog_text)
|
||||
.setMultiChoiceItems(
|
||||
buttons.map { activity.getString(it.value) }.toTypedArray(),
|
||||
buttons.map { it.key in miniMenuButtons }.toBooleanArray(),
|
||||
null
|
||||
)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
app.config.ui.miniMenuButtons =
|
||||
buttons.keys.mapIndexedNotNull { index, id ->
|
||||
if (dialog.listView.checkedItemPositions[index])
|
||||
id
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
if (activity is MainActivity) {
|
||||
activity.setDrawerItems()
|
||||
activity.drawer.updateBadges()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ThemeChooserDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "ThemeChooserDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
app = activity.applicationContext as App
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.settings_theme_theme_text)
|
||||
.setSingleChoiceItems(
|
||||
Themes.getThemeNames(activity).toTypedArray(),
|
||||
Themes.themeIndex,
|
||||
null
|
||||
)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
val which = dialog.listView.checkedItemPosition
|
||||
|
||||
val theme = Themes.themeList[which]
|
||||
if (app.config.ui.theme == theme.id)
|
||||
return@setPositiveButton
|
||||
app.config.ui.theme = theme.id
|
||||
Themes.themeIndex = which
|
||||
activity.recreate()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
import com.google.android.material.timepicker.TimeFormat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class QuietHoursConfigDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val onChangeListener: (() -> Unit)? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "QuietHoursConfigDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
app = activity.applicationContext as App
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.settings_sync_quiet_hours_dialog_title)
|
||||
.setItems(arrayOf(
|
||||
activity.getString(R.string.settings_sync_quiet_hours_set_beginning),
|
||||
activity.getString(R.string.settings_sync_quiet_hours_set_end)
|
||||
)) { dialog, which ->
|
||||
when (which) {
|
||||
0 -> configStartTime()
|
||||
1 -> configEndTime()
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
|
||||
private fun configStartTime() {
|
||||
onShowListener?.invoke(TAG + "Start")
|
||||
|
||||
val time = app.config.sync.quietHoursStart ?: return
|
||||
val picker = MaterialTimePicker.Builder()
|
||||
.setTitleText(R.string.settings_sync_quiet_hours_set_beginning)
|
||||
.setTimeFormat(TimeFormat.CLOCK_24H)
|
||||
.setHour(time.hour)
|
||||
.setMinute(time.minute)
|
||||
.build()
|
||||
|
||||
picker.show(activity.supportFragmentManager, TAG)
|
||||
picker.addOnPositiveButtonClickListener {
|
||||
app.config.sync.quietHoursEnabled = true
|
||||
app.config.sync.quietHoursStart = Time(picker.hour, picker.minute, 0)
|
||||
onChangeListener?.invoke()
|
||||
}
|
||||
picker.addOnDismissListener {
|
||||
onDismissListener?.invoke(TAG + "Start")
|
||||
}
|
||||
}
|
||||
|
||||
private fun configEndTime() {
|
||||
onShowListener?.invoke(TAG + "End")
|
||||
|
||||
val time = app.config.sync.quietHoursEnd ?: return
|
||||
val picker = MaterialTimePicker.Builder()
|
||||
.setTitleText(R.string.settings_sync_quiet_hours_set_end)
|
||||
.setTimeFormat(TimeFormat.CLOCK_24H)
|
||||
.setHour(time.hour)
|
||||
.setMinute(time.minute)
|
||||
.build()
|
||||
|
||||
picker.show(activity.supportFragmentManager, TAG)
|
||||
picker.addOnPositiveButtonClickListener {
|
||||
app.config.sync.quietHoursEnabled = true
|
||||
app.config.sync.quietHoursEnd = Time(picker.hour, picker.minute, 0)
|
||||
onChangeListener?.invoke()
|
||||
}
|
||||
picker.addOnDismissListener {
|
||||
onDismissListener?.invoke(TAG + "End")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-15.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||
|
||||
import android.text.Html
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.data.api.task.AppSync
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class RegistrationConfigDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val profile: Profile,
|
||||
val onChangeListener: ((enabled: Boolean) -> Unit)? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "RegistrationEnableDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
app = activity.applicationContext as App
|
||||
}}
|
||||
|
||||
fun showEventShareDialog() {
|
||||
onShowListener?.invoke(TAG + "EventShare")
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.registration_config_event_sharing_title)
|
||||
.setMessage(R.string.registration_config_event_sharing_text)
|
||||
.setPositiveButton(R.string.i_agree) { _, _ ->
|
||||
enableRegistration()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG + "EventShare")
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
fun showEnableDialog() {
|
||||
onShowListener?.invoke(TAG + "Enable")
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.registration_config_title)
|
||||
.setMessage(Html.fromHtml(app.getString(R.string.registration_config_enable_text)))
|
||||
.setPositiveButton(R.string.i_agree) { _, _ ->
|
||||
enableRegistration()
|
||||
}
|
||||
.setNegativeButton(R.string.i_disagree, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG + "Enable")
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
fun showDisableDialog() {
|
||||
onShowListener?.invoke(TAG + "Disable")
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.registration_config_title)
|
||||
.setMessage(Html.fromHtml(app.getString(R.string.registration_config_disable_text)))
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
disableRegistration()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG + "Disable")
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun enableRegistration() = launch {
|
||||
onShowListener?.invoke(TAG + "Enabling")
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.please_wait)
|
||||
.setMessage(R.string.registration_config_enable_progress_text)
|
||||
.setCancelable(false)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG + "Enabling")
|
||||
}
|
||||
.show()
|
||||
|
||||
withContext(Dispatchers.Default) {
|
||||
profile.registration = Profile.REGISTRATION_ENABLED
|
||||
|
||||
// force full registration of the user
|
||||
App.config.getFor(profile.id).hash = ""
|
||||
|
||||
SzkolnyApi(app).runCatching(activity) {
|
||||
AppSync(app, mutableListOf(), listOf(profile), this).run(
|
||||
0L,
|
||||
markAsSeen = true
|
||||
)
|
||||
}
|
||||
app.db.profileDao().add(profile)
|
||||
if (profile.id == App.profileId) {
|
||||
App.profile.registration = profile.registration
|
||||
}
|
||||
}
|
||||
|
||||
dialog.dismiss()
|
||||
onChangeListener?.invoke(true)
|
||||
}
|
||||
|
||||
private fun disableRegistration() = launch {
|
||||
onShowListener?.invoke(TAG + "Disabling")
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.please_wait)
|
||||
.setMessage(R.string.registration_config_disable_progress_text)
|
||||
.setCancelable(false)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG + "Disabling")
|
||||
}
|
||||
.show()
|
||||
|
||||
withContext(Dispatchers.Default) {
|
||||
profile.registration = Profile.REGISTRATION_DISABLED
|
||||
|
||||
SzkolnyApi(app).runCatching(activity) {
|
||||
unregisterAppUser(profile.userCode)
|
||||
}
|
||||
app.db.profileDao().add(profile)
|
||||
if (profile.id == App.profileId) {
|
||||
App.profile.registration = profile.registration
|
||||
}
|
||||
}
|
||||
|
||||
dialog.dismiss()
|
||||
onChangeListener?.invoke(false)
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-15.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||
|
||||
import android.text.Html
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.data.api.task.AppSync
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class RegistrationEnableDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val profileId: Int
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "RegistrationEnableDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
private var progressDialog: AlertDialog? = null
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
app = activity.applicationContext as App
|
||||
}}
|
||||
|
||||
fun showEventShareDialog(onSuccess: (profile: Profile?) -> Unit) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.event_manual_need_registration_title)
|
||||
.setMessage(R.string.event_manual_need_registration_text)
|
||||
.setPositiveButton(R.string.ok) { dialog, which ->
|
||||
enableRegistration(onSuccess)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
fun showEnableDialog(onSuccess: (profile: Profile?) -> Unit) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.registration_enable_dialog_title)
|
||||
.setMessage(Html.fromHtml(app.getString(R.string.registration_enable_dialog_text)))
|
||||
.setPositiveButton(R.string.ok) { dialog, which ->
|
||||
enableRegistration(onSuccess)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun enableRegistration(onSuccess: (profile: Profile?) -> Unit) { launch {
|
||||
progressDialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.please_wait)
|
||||
.setMessage(R.string.registration_enable_progress_text)
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
|
||||
val profile = withContext(Dispatchers.Default) {
|
||||
val profile = app.db.profileDao().getByIdNow(profileId) ?: return@withContext null
|
||||
profile.registration = Profile.REGISTRATION_ENABLED
|
||||
|
||||
// force full registration of the user
|
||||
App.config.getFor(profile.id).hash = ""
|
||||
|
||||
AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run(0L, markAsSeen = true)
|
||||
app.db.profileDao().add(profile)
|
||||
if (profile.id == App.profileId) {
|
||||
App.profile.registration = profile.registration
|
||||
}
|
||||
return@withContext profile
|
||||
}
|
||||
|
||||
progressDialog?.dismiss()
|
||||
onSuccess(profile)
|
||||
}}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class SyncIntervalDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val onChangeListener: (() -> Unit)? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "SyncIntervalDialog"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local variables go here
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
app = activity.applicationContext as App
|
||||
|
||||
val intervals = listOf(
|
||||
30 * MINUTE,
|
||||
45 * MINUTE,
|
||||
60 * MINUTE,
|
||||
90 * MINUTE,
|
||||
2 * HOUR,
|
||||
3 * HOUR,
|
||||
4 * HOUR,
|
||||
6 * HOUR,
|
||||
10 * HOUR
|
||||
)
|
||||
val intervalNames = intervals.map {
|
||||
activity.getSyncInterval(it.toInt())
|
||||
}
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.settings_sync_sync_interval_dialog_title)
|
||||
//.setMessage(R.string.settings_sync_sync_interval_dialog_text)
|
||||
.setSingleChoiceItems(
|
||||
intervalNames.toTypedArray(),
|
||||
intervals.indexOf(app.config.sync.interval.toLong()),
|
||||
null
|
||||
)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
val which = dialog.listView.checkedItemPosition
|
||||
|
||||
val interval = intervals[which]
|
||||
app.config.sync.interval = interval.toInt()
|
||||
onChangeListener?.invoke()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
@ -16,7 +16,7 @@ import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
|
||||
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
import pl.szczodrzynski.fslogin.decode
|
||||
|
@ -23,7 +23,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull
|
||||
import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSemester
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats
|
||||
|
@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.GradesItemStatsBinding
|
||||
import pl.szczodrzynski.edziennik.onClick
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats
|
||||
import java.text.DecimalFormat
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-17.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder
|
||||
import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem
|
||||
|
||||
class MaterialAboutProfileItem(item: MaterialAboutTitleItem) : MaterialAboutTitleItem(item) {
|
||||
companion object {
|
||||
fun getViewHolder(view: View): MaterialAboutItemViewHolder =
|
||||
MaterialAboutTitleItem.getViewHolder(view)
|
||||
|
||||
fun setupItem(
|
||||
holder: MaterialAboutTitleItemViewHolder,
|
||||
item: MaterialAboutProfileItem,
|
||||
context: Context
|
||||
) = MaterialAboutTitleItem.setupItem(holder, item, context)
|
||||
}
|
||||
|
||||
override fun getType(): Int {
|
||||
return SettingsViewTypeManager.ItemType.PROFILE_ITEM
|
||||
}
|
||||
|
||||
override fun getDetailString() = "MaterialAboutProfileItem{" +
|
||||
"text=" + text +
|
||||
", textRes=" + textRes +
|
||||
", desc=" + desc +
|
||||
", descRes=" + descRes +
|
||||
", icon=" + icon +
|
||||
", iconRes=" + iconRes +
|
||||
", onClickAction=" + onClickAction +
|
||||
", onLongClickAction=" + onLongClickAction +
|
||||
'}'
|
||||
|
||||
override fun clone() = MaterialAboutProfileItem(this)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-17.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
|
||||
import com.danielstone.materialaboutlibrary.items.MaterialAboutItem
|
||||
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
|
||||
abstract class SettingsCard(
|
||||
protected val util: SettingsUtil,
|
||||
) {
|
||||
protected val app: App = util.activity.application as App
|
||||
protected val activity: MainActivity = util.activity
|
||||
|
||||
protected val configGlobal by lazy { app.config }
|
||||
protected val configProfile by lazy { app.config.forProfile() }
|
||||
|
||||
val card by lazy {
|
||||
buildCard()
|
||||
}
|
||||
|
||||
protected abstract fun buildCard(): MaterialAboutCard
|
||||
protected abstract fun getItems(): List<MaterialAboutItem>
|
||||
protected open fun getItemsMore(): List<MaterialAboutItem> = listOf()
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-16.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.danielstone.materialaboutlibrary.MaterialAboutFragment
|
||||
import com.danielstone.materialaboutlibrary.model.MaterialAboutList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.cards.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class SettingsFragment : MaterialAboutFragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "SettingsFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private val util by lazy {
|
||||
SettingsUtil(activity) {
|
||||
refreshMaterialAboutList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
app = activity.application as App
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun getViewTypeManager() =
|
||||
SettingsViewTypeManager()
|
||||
|
||||
override fun getMaterialAboutList(activityContext: Context?): MaterialAboutList {
|
||||
return MaterialAboutList(
|
||||
SettingsProfileCard(util).card,
|
||||
SettingsThemeCard(util).card,
|
||||
SettingsSyncCard(util).card,
|
||||
SettingsRegisterCard(util).card,
|
||||
SettingsAboutCard(util).card,
|
||||
)
|
||||
}
|
||||
}
|
@ -3,8 +3,8 @@ package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
|
||||
import com.danielstone.materialaboutlibrary.ConvenienceBuilder
|
||||
import com.danielstone.materialaboutlibrary.ConvenienceBuilder.createLicenseCard
|
||||
import com.danielstone.materialaboutlibrary.MaterialAboutActivity
|
||||
import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem
|
||||
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
|
||||
@ -14,169 +14,374 @@ import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.resolveColor
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class SettingsLicenseActivity : MaterialAboutActivity() {
|
||||
|
||||
var foregroundColor: Int = 0
|
||||
|
||||
private val icon
|
||||
get() = IconicsDrawable(this).apply {
|
||||
icon = CommunityMaterial.Icon.cmd_book_outline
|
||||
colorInt = foregroundColor
|
||||
sizeDp = 18
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val app = application as App
|
||||
setTheme(Themes.appTheme)
|
||||
foregroundColor = Themes.getPrimaryTextColor(this)
|
||||
setTheme(
|
||||
if (Themes.isDark)
|
||||
R.style.Theme_MaterialComponents
|
||||
else
|
||||
R.style.Theme_MaterialComponents_Light
|
||||
)
|
||||
foregroundColor = if (Themes.isDark)
|
||||
R.color.primaryTextDark.resolveColor(this)
|
||||
else
|
||||
R.color.primaryTextLight.resolveColor(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun createLicenseCard(
|
||||
context: Context,
|
||||
libraryTitle: CharSequence,
|
||||
copyrightYear: CharSequence,
|
||||
copyrightName: CharSequence,
|
||||
license: OpenSourceLicense,
|
||||
libraryUrl: String): MaterialAboutCard {
|
||||
val licenseItem = MaterialAboutActionItem.Builder()
|
||||
.icon(IconicsDrawable(this).apply {
|
||||
icon = CommunityMaterial.Icon.cmd_book_outline
|
||||
colorInt = foregroundColor
|
||||
sizeDp = 18
|
||||
})
|
||||
.setIconGravity(MaterialAboutActionItem.GRAVITY_TOP)
|
||||
.text(libraryTitle)
|
||||
.subText(String.format(getString(license.resourceId), copyrightYear, copyrightName))
|
||||
.setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(context, Uri.parse(libraryUrl)))
|
||||
.build()
|
||||
|
||||
return MaterialAboutCard.Builder().addItem(licenseItem).build()
|
||||
private fun license(
|
||||
title: String,
|
||||
year: String,
|
||||
copyright: String,
|
||||
license: OpenSourceLicense,
|
||||
url: String
|
||||
): MaterialAboutCard {
|
||||
return createLicenseCard(this, icon, title, year, copyright, license).also {
|
||||
(it.items[0] as MaterialAboutActionItem).onClickAction =
|
||||
ConvenienceBuilder.createWebsiteOnClickAction(
|
||||
this,
|
||||
Uri.parse(url)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMaterialAboutList(context: Context): MaterialAboutList {
|
||||
override fun getMaterialAboutList(context: Context) = MaterialAboutList(
|
||||
license(
|
||||
"Kotlin",
|
||||
"2000-2020",
|
||||
"JetBrains s.r.o. and Kotlin Programming Language contributors.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/JetBrains/kotlin"
|
||||
),
|
||||
|
||||
return MaterialAboutList(
|
||||
createLicenseCard(this,
|
||||
"OkHttp",
|
||||
"",
|
||||
"square",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/square/okhttp/"),
|
||||
createLicenseCard(this,
|
||||
"MHttp",
|
||||
"2018",
|
||||
"Mot.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/motcwang/MHttp/"),
|
||||
createLicenseCard(this,
|
||||
"AgendaCalendarView",
|
||||
"2015",
|
||||
"Thibault Guégan",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Tibolte/AgendaCalendarView/"),
|
||||
createLicenseCard(this,
|
||||
"Material Calendar View",
|
||||
"2017",
|
||||
"Applandeo sp. z o.o.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Applandeo/Material-Calendar-View/"),
|
||||
createLicenseCard(this,
|
||||
"Custom Activity On Crash",
|
||||
"",
|
||||
"Eduard Ereza MartĂnez (Ereza)",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Ereza/CustomActivityOnCrash/"),
|
||||
createLicenseCard(this,
|
||||
"Android-Iconics",
|
||||
"2018",
|
||||
"Mike Penz",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/mikepenz/Android-Iconics/"),
|
||||
createLicenseCard(this,
|
||||
"MaterialDrawer",
|
||||
"2016",
|
||||
"Mike Penz",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/mikepenz/MaterialDrawer/"),
|
||||
createLicenseCard(this,
|
||||
"Material Dialogs",
|
||||
"2014-2016",
|
||||
"Aidan Michael Follestad",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/afollestad/material-dialogs/"),
|
||||
createLicenseCard(this,
|
||||
"MaterialDateTimePicker",
|
||||
"2014",
|
||||
"Wouter Dullaert",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/wdullaer/MaterialDateTimePicker/"),
|
||||
createLicenseCard(this,
|
||||
"ColorPicker",
|
||||
"2016",
|
||||
"Jared Rummler, 2015 Daniel Nilsson",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/jaredrummler/ColorPicker/"),
|
||||
createLicenseCard(this,
|
||||
"material-about-library",
|
||||
"2016-2018",
|
||||
"Daniel Stone",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/daniel-stoneuk/material-about-library/"),
|
||||
createLicenseCard(this,
|
||||
"material-intro",
|
||||
"2017",
|
||||
"Jan Heinrich Reimer",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/heinrichreimer/material-intro/"),
|
||||
createLicenseCard(this,
|
||||
"JsonViewer",
|
||||
"2017",
|
||||
"smuyyh",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/smuyyh/JsonViewer/"),
|
||||
createLicenseCard(this,
|
||||
"ShortcutBadger",
|
||||
"2014",
|
||||
"Leo Lin",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/leolin310148/ShortcutBadger/"),
|
||||
createLicenseCard(this,
|
||||
"Android Image Cropper",
|
||||
"2016",
|
||||
"Arthur Teplitzki, 2013 Edmodo, Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/ArthurHub/Android-Image-Cropper/"),
|
||||
createLicenseCard(this,
|
||||
"Android Swipe Layout",
|
||||
"2014",
|
||||
"代码家 (daimajia)",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/daimajia/AndroidSwipeLayout/"),
|
||||
createLicenseCard(this,
|
||||
"barcodescanner (ZXing)",
|
||||
"2014",
|
||||
"Dushyanth Maguluru",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/dm77/barcodescanner/"),
|
||||
createLicenseCard(this,
|
||||
"CircularProgressIndicator",
|
||||
"2018",
|
||||
"Anton Kozyriatskyi",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/antonKozyriatskyi/CircularProgressIndicator/")
|
||||
license(
|
||||
"Android Jetpack",
|
||||
"",
|
||||
"The Android Open Source Project",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/androidx/androidx"
|
||||
),
|
||||
|
||||
license(
|
||||
"Material Components for Android",
|
||||
"2014-2020",
|
||||
"Google, Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/material-components/material-components-android"
|
||||
),
|
||||
|
||||
/*createLicenseCard(this,
|
||||
"NoNonsense-FilePicker",
|
||||
"",
|
||||
"Jonas Kalderstam (spacecowboy)",
|
||||
OpenSourceLicense.GNU_GPL_3,
|
||||
"https://github.com/spacecowboy/NoNonsense-FilePicker/")*/
|
||||
license(
|
||||
"OkHttp",
|
||||
"2019",
|
||||
"Square, Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/square/okhttp"
|
||||
),
|
||||
|
||||
license(
|
||||
"Retrofit",
|
||||
"2013",
|
||||
"Square, Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/square/retrofit"
|
||||
),
|
||||
|
||||
license(
|
||||
"Gson",
|
||||
"2008",
|
||||
"Google Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/google/gson"
|
||||
),
|
||||
|
||||
license(
|
||||
"jsoup",
|
||||
"2009-2021",
|
||||
"Jonathan Hedley",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/jhy/jsoup"
|
||||
),
|
||||
|
||||
license(
|
||||
"jspoon",
|
||||
"2017",
|
||||
"Droids On Roids",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/DroidsOnRoids/jspoon"
|
||||
),
|
||||
|
||||
license(
|
||||
"AgendaCalendarView",
|
||||
"2015",
|
||||
"Thibault Guégan",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/szkolny-eu/agendacalendarview"
|
||||
),
|
||||
|
||||
license(
|
||||
"CafeBar",
|
||||
"2017",
|
||||
"Dani Mahardhika",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/szkolny-eu/cafebar"
|
||||
),
|
||||
|
||||
license(
|
||||
"FSLogin",
|
||||
"2021",
|
||||
"kuba2k2",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/szkolny-eu/FSLogin"
|
||||
),
|
||||
|
||||
license(
|
||||
"material-about-library",
|
||||
"2016-2020",
|
||||
"Daniel Stone",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/szkolny-eu/material-about-library"
|
||||
),
|
||||
|
||||
license(
|
||||
"MHttp",
|
||||
"2018",
|
||||
"Mot.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/szkolny-eu/mhttp"
|
||||
),
|
||||
|
||||
license(
|
||||
"Nachos for Android",
|
||||
"2016",
|
||||
"Hootsuite Media, Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/szkolny-eu/nachos"
|
||||
),
|
||||
|
||||
license(
|
||||
"Material Number Sliding Picker",
|
||||
"2019",
|
||||
"Alessandro Crugnola",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/kuba2k2/NumberSlidingPicker"
|
||||
),
|
||||
|
||||
license(
|
||||
"RecyclerTabLayout",
|
||||
"2017",
|
||||
"nshmura",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/kuba2k2/RecyclerTabLayout"
|
||||
),
|
||||
|
||||
license(
|
||||
"Tachyon",
|
||||
"2019",
|
||||
"LinkedIn Corporation",
|
||||
OpenSourceLicense.BSD,
|
||||
"https://github.com/kuba2k2/Tachyon"
|
||||
),
|
||||
|
||||
license(
|
||||
"Android-Iconics",
|
||||
"2021",
|
||||
"Mike Penz",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/mikepenz/Android-Iconics"
|
||||
),
|
||||
|
||||
license(
|
||||
"Custom Activity On Crash library",
|
||||
"2020",
|
||||
"Eduard Ereza Martínez",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Ereza/CustomActivityOnCrash"
|
||||
),
|
||||
|
||||
license(
|
||||
"Material-Calendar-View",
|
||||
"2017",
|
||||
"Applandeo sp. z o.o.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Applandeo/Material-Calendar-View"
|
||||
),
|
||||
|
||||
license(
|
||||
"Android Swipe Layout",
|
||||
"2014",
|
||||
"代码家",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/daimajia/AndroidSwipeLayout"
|
||||
),
|
||||
|
||||
license(
|
||||
"CircularProgressIndicator",
|
||||
"2018",
|
||||
"Anton Kozyriatskyi",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/antonKozyriatskyi/CircularProgressIndicator"
|
||||
),
|
||||
|
||||
license(
|
||||
"ChatMessageView",
|
||||
"2019",
|
||||
"Tsubasa Nakayama",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/bassaer/ChatMessageView"
|
||||
),
|
||||
|
||||
license(
|
||||
"Android Image Cropper",
|
||||
"2016 Arthur Teplitzki,",
|
||||
"2013 Edmodo, Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/CanHub/Android-Image-Cropper"
|
||||
),
|
||||
|
||||
license(
|
||||
"Chucker",
|
||||
"2018-2020 Chucker Team,",
|
||||
"2017 Jeff Gilfelt",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/ChuckerTeam/chucker"
|
||||
),
|
||||
|
||||
license(
|
||||
"Android-Snowfall",
|
||||
"2016",
|
||||
"JetRadar",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/JetradarMobile/android-snowfall"
|
||||
),
|
||||
|
||||
license(
|
||||
"UONET+ Request Signer",
|
||||
"2019",
|
||||
"Wulkanowy",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/wulkanowy/uonet-request-signer"
|
||||
),
|
||||
|
||||
license(
|
||||
"material-intro",
|
||||
"2017",
|
||||
"Jan Heinrich Reimer",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/heinrichreimer/material-intro"
|
||||
),
|
||||
|
||||
license(
|
||||
"HyperLog Android",
|
||||
"2018",
|
||||
"HyperTrack",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/hypertrack/hyperlog-android"
|
||||
),
|
||||
|
||||
license(
|
||||
"Color Picker",
|
||||
"2016 Jared Rummler,",
|
||||
"2015 Daniel Nilsson",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/jaredrummler/ColorPicker"
|
||||
),
|
||||
|
||||
license(
|
||||
"PowerPermission",
|
||||
"2020",
|
||||
"Qifan Yang",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/underwindfall/PowerPermission"
|
||||
),
|
||||
|
||||
license(
|
||||
"Material DateTime Picker",
|
||||
"2015",
|
||||
"Wouter Dullaert",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/wdullaer/MaterialDateTimePicker"
|
||||
),
|
||||
|
||||
license(
|
||||
"JsonViewer",
|
||||
"2017",
|
||||
"smuyyh",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/smuyyh/JsonViewer"
|
||||
),
|
||||
|
||||
license(
|
||||
"Coil",
|
||||
"2021",
|
||||
"Coil Contributors",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/coil-kt/coil"
|
||||
),
|
||||
|
||||
license(
|
||||
"Barcode Scanner (ZXing)",
|
||||
"2014",
|
||||
"Dushyanth Maguluru",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/dm77/barcodescanner"
|
||||
),
|
||||
|
||||
license(
|
||||
"AutoFitTextView",
|
||||
"2014",
|
||||
"Grantland Chew",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/grantland/android-autofittextview"
|
||||
),
|
||||
|
||||
license(
|
||||
"ShortcutBadger",
|
||||
"2014",
|
||||
"Leo Lin",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/leolin310148/ShortcutBadger"
|
||||
),
|
||||
|
||||
license(
|
||||
"EventBus",
|
||||
"2012-2020",
|
||||
"Markus Junginger, greenrobot",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/greenrobot/EventBus"
|
||||
),
|
||||
|
||||
license(
|
||||
"android-gif-drawable",
|
||||
"2013 - present,",
|
||||
"Karol Wrótniak, Droids on Roids LLC\n",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/koral--/android-gif-drawable"
|
||||
),
|
||||
|
||||
license(
|
||||
"Android Debug Database",
|
||||
"2019 Amit Shekhar,",
|
||||
"2011 Android Open Source Project",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/amitshekhariitbhu/Android-Debug-Database"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
override fun getActivityTitle(): CharSequence? {
|
||||
override fun getActivityTitle(): CharSequence {
|
||||
return getString(R.string.settings_about_licenses_text)
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-17.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
|
||||
import com.danielstone.materialaboutlibrary.items.*
|
||||
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.IIcon
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.after
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Colors
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class SettingsUtil(
|
||||
val activity: MainActivity,
|
||||
private val onRefresh: () -> Unit
|
||||
) {
|
||||
|
||||
fun refresh() = onRefresh()
|
||||
|
||||
private fun IIcon.asDrawable(color: Int? = null, size: Int = 20) =
|
||||
IconicsDrawable(activity).apply {
|
||||
icon = this@asDrawable
|
||||
sizeDp = size
|
||||
colorInt = color ?: Themes.getPrimaryTextColor(activity)
|
||||
}
|
||||
|
||||
fun createCard(
|
||||
titleRes: Int?,
|
||||
items: List<MaterialAboutItem>,
|
||||
itemsMore: List<MaterialAboutItem>,
|
||||
backgroundColor: Int? = null,
|
||||
theme: Int? = null
|
||||
): MaterialAboutCard {
|
||||
val card = MaterialAboutCard.Builder()
|
||||
.title(titleRes ?: 0)
|
||||
.cardColor(backgroundColor ?: 0)
|
||||
.theme(theme ?: 0)
|
||||
.build()
|
||||
card.items.addAll(items)
|
||||
|
||||
if (itemsMore.isNotEmpty()) {
|
||||
card.items.add(createMoreItem(card, itemsMore))
|
||||
}
|
||||
|
||||
return card
|
||||
}
|
||||
|
||||
fun createMoreItem(
|
||||
card: MaterialAboutCard,
|
||||
items: List<MaterialAboutItem>
|
||||
): MaterialAboutActionItem {
|
||||
val iconColor = card.cardColor.let {
|
||||
if (it == 0)
|
||||
null
|
||||
else
|
||||
Colors.legibleTextColor(it)
|
||||
}
|
||||
|
||||
val moreItem = MaterialAboutActionItem.Builder()
|
||||
.text(R.string.settings_more_text)
|
||||
.icon(CommunityMaterial.Icon.cmd_chevron_down.asDrawable(iconColor, size = 14))
|
||||
.build()
|
||||
|
||||
moreItem.setOnClickAction {
|
||||
card.items.after(moreItem, items)
|
||||
card.items.remove(moreItem)
|
||||
onRefresh()
|
||||
}
|
||||
|
||||
return moreItem
|
||||
}
|
||||
|
||||
fun createSectionItem(text: Int) = MaterialAboutSectionItem(text)
|
||||
|
||||
fun createActionItem(
|
||||
text: Int,
|
||||
subText: Int? = null,
|
||||
icon: IIcon,
|
||||
backgroundColor: Int? = null,
|
||||
onClick: (item: MaterialAboutActionItem) -> Unit
|
||||
): MaterialAboutActionItem {
|
||||
val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) }
|
||||
|
||||
val item = MaterialAboutActionItem.Builder()
|
||||
.text(text)
|
||||
.subText(subText ?: 0)
|
||||
.icon(icon.asDrawable(iconColor))
|
||||
.build()
|
||||
|
||||
item.setOnClickAction {
|
||||
onClick(item)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
fun createPropertyItem(
|
||||
text: Int,
|
||||
subText: Int? = null,
|
||||
subTextChecked: Int? = null,
|
||||
icon: IIcon,
|
||||
backgroundColor: Int? = null,
|
||||
value: Boolean,
|
||||
beforeChange: ((item: MaterialAboutSwitchItem, value: Boolean) -> Boolean)? = null,
|
||||
onChange: (item: MaterialAboutSwitchItem, value: Boolean) -> Unit
|
||||
): MaterialAboutSwitchItem {
|
||||
val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) }
|
||||
|
||||
val item = MaterialAboutSwitchItem.Builder()
|
||||
.text(text)
|
||||
.subText(subText ?: 0)
|
||||
.subTextChecked(subTextChecked ?: 0)
|
||||
.icon(icon.asDrawable(iconColor))
|
||||
.setChecked(value)
|
||||
.build()
|
||||
|
||||
item.setOnCheckedChangedAction { item, isChecked ->
|
||||
if (beforeChange?.invoke(item as MaterialAboutSwitchItem, isChecked) == false)
|
||||
return@setOnCheckedChangedAction false
|
||||
onChange(item as MaterialAboutSwitchItem, isChecked)
|
||||
true
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
fun createPropertyActionItem(
|
||||
text: Int,
|
||||
subText: Int? = null,
|
||||
subTextChecked: Int? = null,
|
||||
icon: IIcon,
|
||||
backgroundColor: Int? = null,
|
||||
value: Boolean,
|
||||
onChange: (item: MaterialAboutActionSwitchItem, value: Boolean) -> Unit,
|
||||
onClick: (item: MaterialAboutActionSwitchItem) -> Unit
|
||||
): MaterialAboutSwitchItem {
|
||||
val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) }
|
||||
|
||||
val item = MaterialAboutActionSwitchItem.Builder()
|
||||
.text(text)
|
||||
.subText(subText ?: 0)
|
||||
.subTextChecked(subTextChecked ?: 0)
|
||||
.icon(icon.asDrawable(iconColor))
|
||||
.setChecked(value)
|
||||
.build()
|
||||
|
||||
item.setOnClickAction {
|
||||
onClick(item)
|
||||
}
|
||||
item.setOnCheckedChangedAction { item, isChecked ->
|
||||
onChange(item as MaterialAboutActionSwitchItem, isChecked)
|
||||
true
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
fun createTitleItem(): MaterialAboutTitleItem =
|
||||
MaterialAboutTitleItem.Builder()
|
||||
.text(R.string.app_name)
|
||||
.desc(R.string.settings_about_title_subtext)
|
||||
.icon(R.mipmap.ic_splash)
|
||||
.build()
|
||||
|
||||
fun createProfileItem(
|
||||
profile: Profile,
|
||||
onClick: (item: MaterialAboutProfileItem, profile: Profile) -> Unit
|
||||
): MaterialAboutProfileItem {
|
||||
val item = MaterialAboutProfileItem(
|
||||
MaterialAboutTitleItem.Builder()
|
||||
.text(profile.name)
|
||||
.desc(profile.subname)
|
||||
.icon(profile.getImageDrawable(activity))
|
||||
.build()
|
||||
)
|
||||
item.setOnClickAction {
|
||||
onClick(item, profile)
|
||||
}
|
||||
return item
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-17.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder
|
||||
import com.danielstone.materialaboutlibrary.items.MaterialAboutItem
|
||||
import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder
|
||||
import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsViewTypeManager.ItemType.Companion.PROFILE_ITEM
|
||||
|
||||
class SettingsViewTypeManager : DefaultViewTypeManager() {
|
||||
class ItemType {
|
||||
companion object {
|
||||
const val PROFILE_ITEM = 10
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLayout(itemType: Int) = when (itemType) {
|
||||
PROFILE_ITEM -> R.layout.mal_material_about_profile_item
|
||||
else -> super.getLayout(itemType)
|
||||
}
|
||||
|
||||
override fun getViewHolder(itemType: Int, view: View): MaterialAboutItemViewHolder =
|
||||
when (itemType) {
|
||||
PROFILE_ITEM -> MaterialAboutProfileItem.getViewHolder(view)
|
||||
else -> super.getViewHolder(itemType, view)
|
||||
}
|
||||
|
||||
override fun setupItem(
|
||||
itemType: Int,
|
||||
holder: MaterialAboutItemViewHolder,
|
||||
item: MaterialAboutItem,
|
||||
context: Context
|
||||
) = when (itemType) {
|
||||
PROFILE_ITEM -> MaterialAboutProfileItem.setupItem(
|
||||
holder as MaterialAboutTitleItemViewHolder,
|
||||
item as MaterialAboutProfileItem, context
|
||||
)
|
||||
else -> super.setupItem(itemType, holder, item, context)
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings.cards
|
||||
|
||||
import android.content.Intent
|
||||
import android.media.MediaPlayer
|
||||
import android.widget.Toast
|
||||
import com.danielstone.materialaboutlibrary.items.MaterialAboutItem
|
||||
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import eu.szkolny.font.SzkolnyFont
|
||||
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.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsLicenseActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class SettingsAboutCard(util: SettingsUtil) : SettingsCard(util), CoroutineScope {
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private var clickCounter = 0
|
||||
private val mediaPlayer by lazy {
|
||||
MediaPlayer.create(activity, R.raw.ogarnij_sie)
|
||||
}
|
||||
|
||||
override fun buildCard(): MaterialAboutCard =
|
||||
util.createCard(
|
||||
null,
|
||||
items = listOf(),
|
||||
itemsMore = listOf(),
|
||||
backgroundColor = 0xff1976d2.toInt(),
|
||||
theme = R.style.AppTheme_Dark
|
||||
).also {
|
||||
it.items.addAll(getItems(it))
|
||||
}
|
||||
|
||||
override fun getItems() = listOf<MaterialAboutItem>()
|
||||
override fun getItemsMore() = listOf<MaterialAboutItem>()
|
||||
|
||||
private fun getItems(card: MaterialAboutCard) = listOf(
|
||||
util.createTitleItem(),
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_version_text,
|
||||
icon = CommunityMaterial.Icon2.cmd_information_outline,
|
||||
onClick = { item ->
|
||||
clickCounter++
|
||||
if (clickCounter < 7)
|
||||
Toast.makeText(activity, "\uD83D\uDE02", Toast.LENGTH_SHORT).show()
|
||||
item.subText =
|
||||
BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + " \uD83D\uDCA3"
|
||||
util.refresh()
|
||||
if (clickCounter >= 7) {
|
||||
mediaPlayer.start()
|
||||
clickCounter = 0
|
||||
}
|
||||
}
|
||||
).also {
|
||||
it.subText = BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE
|
||||
},
|
||||
|
||||
util.createMoreItem(card, items = listOf(
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_changelog_text,
|
||||
icon = CommunityMaterial.Icon3.cmd_radar
|
||||
) {
|
||||
ChangelogDialog(activity)
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_update_text,
|
||||
subText = R.string.settings_about_update_subtext,
|
||||
icon = CommunityMaterial.Icon3.cmd_update
|
||||
) {
|
||||
launch {
|
||||
UpdateWorker.runNow(app)
|
||||
}
|
||||
}
|
||||
)),
|
||||
|
||||
util.createSectionItem(
|
||||
text = R.string.see_also
|
||||
),
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_privacy_policy_text,
|
||||
icon = CommunityMaterial.Icon3.cmd_shield_outline
|
||||
) {
|
||||
Utils.openUrl(activity, "https://szkolny.eu/privacy-policy")
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_discord_text,
|
||||
subText = R.string.settings_about_discord_subtext,
|
||||
icon = SzkolnyFont.Icon.szf_discord_outline
|
||||
) {
|
||||
Utils.openUrl(activity, "https://szkolny.eu/discord")
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_github_text,
|
||||
subText = R.string.settings_about_github_subtext,
|
||||
icon = SzkolnyFont.Icon.szf_github_face
|
||||
) {
|
||||
Utils.openUrl(activity, "https://szkolny.eu/github/android")
|
||||
},
|
||||
|
||||
util.createMoreItem(card, items = listOfNotNull(
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_homepage_text,
|
||||
subText = R.string.settings_about_homepage_subtext,
|
||||
icon = CommunityMaterial.Icon.cmd_earth
|
||||
) {
|
||||
Utils.openUrl(activity, "https://szkolny.eu/")
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_licenses_text,
|
||||
icon = CommunityMaterial.Icon.cmd_code_braces
|
||||
) {
|
||||
activity.startActivity(Intent(activity, SettingsLicenseActivity::class.java))
|
||||
},
|
||||
|
||||
if (App.devMode)
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_crash_text,
|
||||
subText = R.string.settings_about_crash_subtext,
|
||||
icon = CommunityMaterial.Icon.cmd_bug_outline
|
||||
) {
|
||||
throw RuntimeException("MANUAL CRASH")
|
||||
}
|
||||
else
|
||||
null
|
||||
))
|
||||
)
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings.cards
|
||||
|
||||
import android.content.Intent
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.MaterialAboutProfileItem
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
|
||||
|
||||
class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) {
|
||||
|
||||
override fun buildCard() = util.createCard(
|
||||
null,
|
||||
items = getItems(),
|
||||
itemsMore = listOf()
|
||||
)
|
||||
|
||||
private fun getProfileItem(): MaterialAboutProfileItem = util.createProfileItem(
|
||||
profile = app.profile
|
||||
) { item, profile ->
|
||||
ProfileConfigDialog(activity, profile, onProfileSaved = {
|
||||
val index = card.items.indexOf(item)
|
||||
if (index == -1)
|
||||
return@ProfileConfigDialog
|
||||
card.items.remove(item)
|
||||
card.items.add(index, getProfileItem())
|
||||
util.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
override fun getItems() = listOf(
|
||||
getProfileItem(),
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_add_student_text,
|
||||
subText = R.string.settings_add_student_subtext,
|
||||
icon = CommunityMaterial.Icon.cmd_account_plus_outline
|
||||
) {
|
||||
activity.startActivity(Intent(activity, LoginActivity::class.java))
|
||||
}
|
||||
)
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings.cards
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import eu.szkolny.font.SzkolnyFont
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.after
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.bell.BellSyncConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
|
||||
|
||||
class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
|
||||
|
||||
override fun buildCard() = util.createCard(
|
||||
R.string.settings_card_register_title,
|
||||
items = getItems(),
|
||||
itemsMore = getItemsMore()
|
||||
)
|
||||
|
||||
private fun getBellSync() =
|
||||
configGlobal.timetable.bellSyncDiff?.let {
|
||||
activity.getString(
|
||||
R.string.settings_register_bell_sync_subtext_format,
|
||||
(if (configGlobal.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS
|
||||
)
|
||||
} ?: activity.getString(R.string.settings_register_bell_sync_subtext_disabled)
|
||||
|
||||
private val sharedEventsItem by lazy {
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_register_shared_events_text,
|
||||
subText = R.string.settings_register_shared_events_subtext,
|
||||
icon = CommunityMaterial.Icon3.cmd_share_outline,
|
||||
value = app.profile.enableSharedEvents
|
||||
) { _, value ->
|
||||
app.profile.enableSharedEvents = value
|
||||
app.profileSave()
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.event_sharing)
|
||||
.setMessage(
|
||||
if (value)
|
||||
R.string.settings_register_shared_events_dialog_enabled_text
|
||||
else
|
||||
R.string.settings_register_shared_events_dialog_disabled_text
|
||||
)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItems() = listOfNotNull(
|
||||
util.createActionItem(
|
||||
text = R.string.menu_grades_config,
|
||||
icon = CommunityMaterial.Icon3.cmd_numeric_5_box_outline
|
||||
) {
|
||||
GradesConfigDialog(activity, reloadOnDismiss = false)
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.menu_attendance_config,
|
||||
icon = CommunityMaterial.Icon.cmd_calendar_remove_outline
|
||||
) {
|
||||
AttendanceConfigDialog(activity, reloadOnDismiss = false)
|
||||
},
|
||||
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_register_allow_registration_text,
|
||||
subText = R.string.settings_register_allow_registration_subtext,
|
||||
icon = CommunityMaterial.Icon.cmd_account_circle_outline,
|
||||
value = app.profile.registration == REGISTRATION_ENABLED,
|
||||
beforeChange = { item, value ->
|
||||
if (app.profile.registration == REGISTRATION_ENABLED == value)
|
||||
// allow the switch to change - needed for util.refresh() to change the visual state
|
||||
return@createPropertyItem true
|
||||
val dialog =
|
||||
RegistrationConfigDialog(activity, app.profile, onChangeListener = { enabled ->
|
||||
if (item.isChecked == enabled)
|
||||
return@RegistrationConfigDialog
|
||||
item.isChecked = enabled
|
||||
if (value) {
|
||||
card.items.after(item, sharedEventsItem)
|
||||
} else {
|
||||
card.items.remove(sharedEventsItem)
|
||||
}
|
||||
util.refresh()
|
||||
})
|
||||
if (value)
|
||||
dialog.showEnableDialog()
|
||||
else
|
||||
dialog.showDisableDialog()
|
||||
false
|
||||
}
|
||||
) { _, _ -> },
|
||||
|
||||
if (app.profile.registration == REGISTRATION_ENABLED)
|
||||
sharedEventsItem
|
||||
else
|
||||
null
|
||||
)
|
||||
|
||||
override fun getItemsMore() = listOfNotNull(
|
||||
util.createActionItem(
|
||||
text = R.string.settings_register_bell_sync_text,
|
||||
icon = SzkolnyFont.Icon.szf_alarm_bell_outline,
|
||||
onClick = {
|
||||
BellSyncConfigDialog(activity, onChangeListener = {
|
||||
it.subText = getBellSync()
|
||||
util.refresh()
|
||||
})
|
||||
}
|
||||
).also {
|
||||
it.subText = getBellSync()
|
||||
},
|
||||
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_register_count_in_seconds_text,
|
||||
subText = R.string.settings_register_count_in_seconds_subtext,
|
||||
icon = CommunityMaterial.Icon3.cmd_timer_outline,
|
||||
value = configGlobal.timetable.countInSeconds
|
||||
) { _, it ->
|
||||
configGlobal.timetable.countInSeconds = it
|
||||
},
|
||||
|
||||
if (app.profile.loginStoreType == LOGIN_TYPE_LIBRUS)
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_register_show_teacher_absences_text,
|
||||
icon = CommunityMaterial.Icon.cmd_account_arrow_right_outline,
|
||||
value = app.profile.getStudentData("showTeacherAbsences", true)
|
||||
) { _, it ->
|
||||
app.profile.putStudentData("showTeacherAbsences", it)
|
||||
app.profileSave()
|
||||
}
|
||||
else
|
||||
null,
|
||||
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_register_hide_sticks_from_old,
|
||||
icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline,
|
||||
value = configProfile.grades.hideSticksFromOld
|
||||
) { _, it ->
|
||||
configProfile.grades.hideSticksFromOld = it
|
||||
}
|
||||
)
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings.cards
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.provider.Settings
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.after
|
||||
import pl.szczodrzynski.edziennik.getSyncInterval
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.QuietHoursConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncIntervalDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) {
|
||||
|
||||
override fun buildCard() = util.createCard(
|
||||
R.string.settings_card_sync_title,
|
||||
items = getItems(),
|
||||
itemsMore = getItemsMore()
|
||||
)
|
||||
|
||||
private fun getQuietHours(): String {
|
||||
if (configGlobal.sync.quietHoursStart == null) {
|
||||
configGlobal.sync.quietHoursStart = Time(22, 30, 0)
|
||||
}
|
||||
if (configGlobal.sync.quietHoursEnd == null) {
|
||||
configGlobal.sync.quietHoursEnd = Time(6, 30, 0)
|
||||
}
|
||||
|
||||
return activity.getString(
|
||||
if (configGlobal.sync.quietHoursStart!! > configGlobal.sync.quietHoursEnd!!)
|
||||
R.string.settings_sync_quiet_hours_subtext_next_day_format
|
||||
else
|
||||
R.string.settings_sync_quiet_hours_subtext_format,
|
||||
configGlobal.sync.quietHoursStart?.stringHM,
|
||||
configGlobal.sync.quietHoursEnd?.stringHM
|
||||
)
|
||||
}
|
||||
|
||||
private val syncWifiItem by lazy {
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_sync_wifi_text,
|
||||
subText = R.string.settings_sync_wifi_subtext,
|
||||
icon = CommunityMaterial.Icon3.cmd_wifi_strength_2,
|
||||
value = configGlobal.sync.onlyWifi
|
||||
) { _, it ->
|
||||
configGlobal.sync.onlyWifi = it
|
||||
SyncWorker.rescheduleNext(app)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItems() = listOfNotNull(
|
||||
util.createPropertyActionItem(
|
||||
text = R.string.settings_sync_sync_interval_text,
|
||||
subText = R.string.settings_sync_sync_interval_subtext_disabled,
|
||||
icon = CommunityMaterial.Icon.cmd_download_outline,
|
||||
value = configGlobal.sync.enabled,
|
||||
onChange = { item, value ->
|
||||
// When calling onChange from the onClick listener below
|
||||
// a list refresh is requested, the adapter refreshes
|
||||
// all view holders, changing the state of the switch
|
||||
// view, thus calling onChange again, causing it to
|
||||
// try to recursively refresh the list, therefore
|
||||
// crashing the app. To avoid this, the method will
|
||||
// continue only if the checked state is different
|
||||
// from the saved value, which should only happen
|
||||
// when clicking the switch manually or when called
|
||||
// by onClick, **once** (because onClick doesn't
|
||||
// update the config value - we let the switch
|
||||
// listener do it). Then there comes a different problem,
|
||||
// when onClick changes the subText and the onChange
|
||||
// listener returns because the boolean value
|
||||
// is unchanged, leaving the list not refreshed.
|
||||
// To solve this, a list refresh is also requested
|
||||
// in onClick, when the config value is the same
|
||||
// as the new switch value, which would normally
|
||||
// cause the onChange method to exit here.
|
||||
if (value == configGlobal.sync.enabled)
|
||||
return@createPropertyActionItem
|
||||
|
||||
if (value) {
|
||||
card.items.after(item, syncWifiItem)
|
||||
} else {
|
||||
card.items.remove(syncWifiItem)
|
||||
}
|
||||
util.refresh()
|
||||
|
||||
configGlobal.sync.enabled = value
|
||||
SyncWorker.rescheduleNext(app)
|
||||
},
|
||||
onClick = { item ->
|
||||
SyncIntervalDialog(activity, onChangeListener = {
|
||||
item.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval)
|
||||
item.isChecked = true
|
||||
item.onCheckedChangedAction.onCheckedChanged(item, true)
|
||||
if (configGlobal.sync.enabled)
|
||||
util.refresh()
|
||||
})
|
||||
}
|
||||
).also {
|
||||
it.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval)
|
||||
},
|
||||
|
||||
if (configGlobal.sync.enabled)
|
||||
syncWifiItem
|
||||
else
|
||||
null,
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_profile_notifications_text,
|
||||
subText = R.string.settings_profile_notifications_subtext,
|
||||
icon = CommunityMaterial.Icon2.cmd_filter_outline
|
||||
) {
|
||||
NotificationFilterDialog(activity)
|
||||
},
|
||||
|
||||
util.createPropertyActionItem(
|
||||
text = R.string.settings_sync_quiet_hours_text,
|
||||
subText = R.string.settings_sync_quiet_hours_subtext_disabled,
|
||||
icon = CommunityMaterial.Icon.cmd_bell_sleep_outline,
|
||||
value = configGlobal.sync.quietHoursEnabled,
|
||||
onChange = { _, value ->
|
||||
configGlobal.sync.quietHoursEnabled = value
|
||||
},
|
||||
onClick = { item ->
|
||||
QuietHoursConfigDialog(activity, onChangeListener = {
|
||||
item.subTextChecked = getQuietHours()
|
||||
item.isChecked = configGlobal.sync.quietHoursEnabled
|
||||
util.refresh()
|
||||
})
|
||||
}
|
||||
).also {
|
||||
it.subTextChecked = getQuietHours()
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_sync_web_push_text,
|
||||
subText = R.string.settings_sync_web_push_subtext,
|
||||
icon = CommunityMaterial.Icon2.cmd_laptop
|
||||
) {
|
||||
activity.loadTarget(MainActivity.TARGET_WEB_PUSH)
|
||||
}
|
||||
)
|
||||
|
||||
override fun getItemsMore() = listOfNotNull(
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_sync_updates_text,
|
||||
icon = CommunityMaterial.Icon.cmd_cellphone_arrow_down,
|
||||
value = configGlobal.sync.notifyAboutUpdates
|
||||
) { _, it ->
|
||||
configGlobal.sync.notifyAboutUpdates = it
|
||||
UpdateWorker.rescheduleNext(app)
|
||||
},
|
||||
|
||||
if (SDK_INT >= VERSION_CODES.KITKAT)
|
||||
util.createActionItem(
|
||||
text = R.string.settings_sync_notifications_settings_text,
|
||||
subText = R.string.settings_sync_notifications_settings_subtext,
|
||||
icon = CommunityMaterial.Icon.cmd_cog_outline
|
||||
) {
|
||||
val channel = app.notificationChannelsManager.data.key
|
||||
val intent = Intent().apply {
|
||||
when {
|
||||
SDK_INT >= VERSION_CODES.O -> {
|
||||
action = Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS
|
||||
putExtra(Settings.EXTRA_APP_PACKAGE, app.packageName)
|
||||
putExtra(Settings.EXTRA_CHANNEL_ID, channel)
|
||||
addFlags(FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
SDK_INT >= VERSION_CODES.LOLLIPOP -> {
|
||||
action = "android.settings.APP_NOTIFICATION_SETTINGS"
|
||||
putExtra("app_package", app.packageName)
|
||||
putExtra("app_uid", app.applicationInfo.uid)
|
||||
}
|
||||
else -> {
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
addCategory(Intent.CATEGORY_DEFAULT)
|
||||
data = Uri.parse("package:" + app.packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
else
|
||||
null
|
||||
)
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2021-3-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings.cards
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.AppLanguageDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.MiniMenuConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ThemeChooserDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
|
||||
|
||||
override fun buildCard() = util.createCard(
|
||||
R.string.settings_card_theme_title,
|
||||
items = getItems(),
|
||||
itemsMore = getItemsMore()
|
||||
)
|
||||
|
||||
override fun getItems() = listOfNotNull(
|
||||
if (Date.getToday().month % 11 == 1) // cool math games
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_theme_snowfall_text,
|
||||
subText = R.string.settings_theme_snowfall_subtext,
|
||||
icon = CommunityMaterial.Icon3.cmd_snowflake,
|
||||
value = configGlobal.ui.snowfall
|
||||
) { _, it ->
|
||||
configGlobal.ui.snowfall = it
|
||||
activity.recreate()
|
||||
}
|
||||
else null,
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_theme_theme_text,
|
||||
subText = Themes.getThemeNameRes(),
|
||||
icon = CommunityMaterial.Icon3.cmd_palette_outline
|
||||
) {
|
||||
ThemeChooserDialog(activity)
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_about_language_text,
|
||||
subText = R.string.settings_about_language_subtext,
|
||||
icon = CommunityMaterial.Icon3.cmd_translate
|
||||
) {
|
||||
AppLanguageDialog(activity)
|
||||
},
|
||||
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_theme_mini_drawer_text,
|
||||
subText = R.string.settings_theme_mini_drawer_subtext,
|
||||
icon = CommunityMaterial.Icon.cmd_dots_vertical,
|
||||
value = configGlobal.ui.miniMenuVisible
|
||||
) { _, it ->
|
||||
configGlobal.ui.miniMenuVisible = it
|
||||
activity.navView.drawer.miniDrawerVisiblePortrait = it
|
||||
}
|
||||
)
|
||||
|
||||
override fun getItemsMore() = listOf(
|
||||
util.createActionItem(
|
||||
text = R.string.settings_theme_mini_drawer_buttons_text,
|
||||
icon = CommunityMaterial.Icon2.cmd_format_list_checks
|
||||
) {
|
||||
MiniMenuConfigDialog(activity)
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_theme_drawer_header_text,
|
||||
icon = CommunityMaterial.Icon2.cmd_image_outline
|
||||
) {
|
||||
if (app.config.ui.appBackground == null) {
|
||||
setHeaderBackground()
|
||||
return@createActionItem
|
||||
}
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setItems(
|
||||
arrayOf(
|
||||
activity.getString(R.string.settings_theme_drawer_header_dialog_set),
|
||||
activity.getString(R.string.settings_theme_drawer_header_dialog_restore)
|
||||
)
|
||||
) { _, which ->
|
||||
when (which) {
|
||||
0 -> setHeaderBackground()
|
||||
1 -> {
|
||||
app.config.ui.headerBackground = null
|
||||
activity.drawer.setAccountHeaderBackground(null)
|
||||
activity.drawer.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
},
|
||||
|
||||
util.createActionItem(
|
||||
text = R.string.settings_theme_app_background_text,
|
||||
subText = R.string.settings_theme_app_background_subtext,
|
||||
icon = CommunityMaterial.Icon2.cmd_image_filter_hdr
|
||||
) {
|
||||
if (app.config.ui.appBackground == null) {
|
||||
setAppBackground()
|
||||
return@createActionItem
|
||||
}
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setItems(
|
||||
arrayOf(
|
||||
activity.getString(R.string.settings_theme_app_background_dialog_set),
|
||||
activity.getString(R.string.settings_theme_app_background_dialog_restore)
|
||||
)
|
||||
) { _, which ->
|
||||
when (which) {
|
||||
0 -> setAppBackground()
|
||||
1 -> {
|
||||
app.config.ui.appBackground = null
|
||||
activity.setAppBackground()
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
},
|
||||
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_theme_open_drawer_on_back_pressed_text,
|
||||
icon = CommunityMaterial.Icon3.cmd_menu_open,
|
||||
value = configGlobal.ui.openDrawerOnBackPressed
|
||||
) { _, it ->
|
||||
configGlobal.ui.openDrawerOnBackPressed = it
|
||||
}
|
||||
)
|
||||
|
||||
private fun setHeaderBackground() = activity.requestHandler.requestHeaderBackground {
|
||||
activity.drawer.setAccountHeaderBackground(null)
|
||||
activity.drawer.setAccountHeaderBackground(app.config.ui.headerBackground)
|
||||
activity.drawer.open()
|
||||
}
|
||||
|
||||
private fun setAppBackground() = activity.requestHandler.requestAppBackground {
|
||||
activity.setAppBackground()
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.webpush;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.zxing.Result;
|
||||
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
|
||||
public class QrScannerActivity extends AppCompatActivity implements ZXingScannerView.ResultHandler {
|
||||
private ZXingScannerView mScannerView;
|
||||
public static ZXingScannerView.ResultHandler resultHandler;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mScannerView = new ZXingScannerView(this); // Programmatically initialize the scanner view
|
||||
setContentView(mScannerView);
|
||||
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
|
||||
mScannerView.startCamera(); // Start camera on resume
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
|
||||
mScannerView.startCamera(); // Start camera on resume
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mScannerView.stopCamera(); // Stop camera on pause
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case 1: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
mScannerView.startCamera();
|
||||
} else {
|
||||
// permission denied, boo! Disable the
|
||||
// functionality that depends on this permission.
|
||||
Toast.makeText(this, R.string.no_permissions, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
// other 'case' lines to check for other
|
||||
// permissions this app might request
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
if (resultHandler != null) {
|
||||
resultHandler.handleResult(rawResult);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
@ -4,15 +4,11 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.webpush
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -25,7 +21,6 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
|
||||
import pl.szczodrzynski.edziennik.databinding.WebPushFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.QrScannerDialog
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class WebPushFragment : Fragment(), CoroutineScope {
|
||||
@ -46,13 +41,13 @@ class WebPushFragment : Fragment(), CoroutineScope {
|
||||
SzkolnyApi(app)
|
||||
}
|
||||
|
||||
private val manager
|
||||
get() = app.permissionManager
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
context!!.theme.applyStyle(Themes.appTheme, true)
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false)
|
||||
// activity, context and profile is valid
|
||||
b = WebPushFragmentBinding.inflate(inflater)
|
||||
return b.root
|
||||
@ -60,19 +55,15 @@ class WebPushFragment : Fragment(), CoroutineScope {
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
if (!isAdded)
|
||||
return
|
||||
|
||||
b.scanQrCode.onClick {
|
||||
val result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
manager.requestCameraPermission(activity, R.string.permissions_qr_scanner) {
|
||||
QrScannerDialog(activity, {
|
||||
b.tokenEditText.setText(it.crc32().toString(36).toUpperCase())
|
||||
pairBrowser(browserId = it)
|
||||
})
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
|
||||
public class SnackbarHelper {
|
||||
|
||||
public static void configSnackbar(Context context, Snackbar snack) {
|
||||
addMargins(snack);
|
||||
setRoundBordersBg(context, snack);
|
||||
ViewCompat.setElevation(snack.getView(), 6f);
|
||||
}
|
||||
|
||||
private static void addMargins(Snackbar snack) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) snack.getView().getLayoutParams();
|
||||
params.setMargins(12, 12, 12, 12);
|
||||
snack.getView().setLayoutParams(params);
|
||||
}
|
||||
|
||||
private static void setRoundBordersBg(Context context, Snackbar snackbar) {
|
||||
snackbar.getView().setBackground(context.getResources().getDrawable(R.drawable.bg_snackbar));
|
||||
}
|
||||
}
|
@ -42,6 +42,12 @@ object Themes {
|
||||
theme = themeList[value]
|
||||
}
|
||||
|
||||
var themeIndex
|
||||
get() = themeList.indexOf(theme)
|
||||
set(value) {
|
||||
theme = themeList[value]
|
||||
}
|
||||
|
||||
|
||||
val appThemeNoDisplay: Int
|
||||
get() = if (theme.isDark) R.style.AppTheme_Dark_NoDisplay else R.style.AppTheme_Light_NoDisplay
|
||||
@ -61,38 +67,15 @@ object Themes {
|
||||
return getColorFromAttr(context, android.R.attr.textColorSecondary)
|
||||
}
|
||||
|
||||
/*public static int getChipColorRes() {
|
||||
switch (themeInt) {
|
||||
case THEME_LIGHT:
|
||||
return R.color.chipBackgroundLight;
|
||||
default:
|
||||
case THEME_DARK:
|
||||
return R.color.chipBackgroundDark;
|
||||
case THEME_BLACK:
|
||||
return R.color.chipBackgroundBlack;
|
||||
case THEME_CHOCOLATE:
|
||||
return R.color.chipBackgroundChocolate;
|
||||
case THEME_BLUE:
|
||||
return R.color.chipBackgroundBlue;
|
||||
case THEME_PURPLE:
|
||||
return R.color.chipBackgroundPurple;
|
||||
case THEME_GREEN:
|
||||
return R.color.chipBackgroundGreen;
|
||||
case THEME_AMBER:
|
||||
return R.color.chipBackgroundAmber;
|
||||
case THEME_RED:
|
||||
return R.color.chipBackgroundRed;
|
||||
}
|
||||
}*/
|
||||
fun getThemeName(context: Context): String {
|
||||
return context.getString(theme.name)
|
||||
}
|
||||
|
||||
fun getThemeNames(context: Context): List<String> {
|
||||
val list = mutableListOf<String>()
|
||||
for (theme in themeList) {
|
||||
list += context.getString(theme.name)
|
||||
@StringRes
|
||||
fun getThemeNameRes() = theme.name
|
||||
|
||||
fun getThemeNames(context: Context) =
|
||||
themeList.map {
|
||||
context.getString(it.name)
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
@ -31,49 +31,91 @@ class PermissionManager(val app: App) : CoroutineScope {
|
||||
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
|
||||
private fun isPermissionGranted(name: String) =
|
||||
if (Build.VERSION.SDK_INT >= 23)
|
||||
app.checkSelfPermission(name) == PackageManager.PERMISSION_GRANTED
|
||||
else
|
||||
true
|
||||
|
||||
private fun openPermissionSettings(activity: AppCompatActivity) {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
val uri = Uri.fromParts("package", app.packageName, null)
|
||||
intent.data = uri
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
|
||||
fun requestStoragePermission(
|
||||
activity: AppCompatActivity,
|
||||
@StringRes permissionMessage: Int,
|
||||
onSuccess: suspend CoroutineScope.() -> Unit
|
||||
private fun requestPermission(
|
||||
activity: AppCompatActivity,
|
||||
@StringRes permissionMessage: Int,
|
||||
isRequired: Boolean = true,
|
||||
permissionName: String,
|
||||
onSuccess: suspend CoroutineScope.() -> Unit
|
||||
) {
|
||||
launch {
|
||||
if (isStoragePermissionGranted()) {
|
||||
if (isPermissionGranted(permissionName)) {
|
||||
onSuccess()
|
||||
return@launch
|
||||
}
|
||||
val result = activity.awaitAskPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
val result = activity.awaitAskPermissions(permissionName)
|
||||
when {
|
||||
result.hasAllGranted() -> onSuccess()
|
||||
result.hasRational() -> {
|
||||
if (!isRequired) {
|
||||
onSuccess()
|
||||
return@launch
|
||||
}
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.permissions_required)
|
||||
.setMessage(permissionMessage)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
requestStoragePermission(activity, permissionMessage, onSuccess)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
.setTitle(R.string.permissions_required)
|
||||
.setMessage(permissionMessage)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
requestPermission(
|
||||
activity,
|
||||
permissionMessage,
|
||||
isRequired,
|
||||
permissionName,
|
||||
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()
|
||||
.setTitle(R.string.permissions_required)
|
||||
.setMessage(R.string.permissions_denied)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
openPermissionSettings(activity)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun requestStoragePermission(
|
||||
activity: AppCompatActivity,
|
||||
@StringRes permissionMessage: Int,
|
||||
isRequired: Boolean = true,
|
||||
onSuccess: suspend CoroutineScope.() -> Unit
|
||||
) = requestPermission(
|
||||
activity,
|
||||
permissionMessage,
|
||||
isRequired,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
onSuccess
|
||||
)
|
||||
|
||||
fun requestCameraPermission(
|
||||
activity: AppCompatActivity,
|
||||
@StringRes permissionMessage: Int,
|
||||
isRequired: Boolean = true,
|
||||
onSuccess: suspend CoroutineScope.() -> Unit
|
||||
) = requestPermission(
|
||||
activity,
|
||||
permissionMessage,
|
||||
isRequired,
|
||||
Manifest.permission.CAMERA,
|
||||
onSuccess
|
||||
)
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="4dp" />
|
||||
<stroke android:color="@color/dividerColor" android:width="1dp" />
|
||||
<solid android:color="#DCDCDC" />
|
||||
</shape>
|
@ -1,5 +0,0 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#323232" />
|
||||
<corners android:radius="4dp" />
|
||||
</shape>
|
32
app/src/main/res/layout/dialog_edit_text.xml
Normal file
32
app/src/main/res/layout/dialog_edit_text.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2021-3-19.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="4dp"
|
||||
tools:text="This is a custom message of the dialog." />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/text_input_layout"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
113
app/src/main/res/layout/dialog_profile_config.xml
Normal file
113
app/src/main/res/layout/dialog_profile_config.xml
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2021-3-22.
|
||||
-->
|
||||
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
<import type="pl.szczodrzynski.edziennik.data.db.entity.Profile" />
|
||||
|
||||
<variable
|
||||
name="profile"
|
||||
type="Profile" />
|
||||
</data>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingTop="24dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<com.mikepenz.materialdrawer.view.BezelImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@drawable/face_1" />
|
||||
|
||||
<View
|
||||
android:id="@+id/circleView"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
tools:background="?colorSurface" />
|
||||
|
||||
<com.mikepenz.iconics.view.IconicsImageView
|
||||
android:id="@+id/imageButtonIcon"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
app:iiv_color="?colorOnBackground"
|
||||
app:iiv_icon="szf-image-plus-outline"
|
||||
app:iiv_padding="5dp"
|
||||
tools:background="@color/colorSurface_16dp" />
|
||||
|
||||
<View
|
||||
android:id="@+id/imageButton"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:background="?selectableItemBackgroundBorderless" />
|
||||
</FrameLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/nameLayout"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/nameEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/profile_config_name_hint"
|
||||
android:text="@={profile.name}"
|
||||
tools:text="Paweł Informatyczny" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:textAppearance="@style/NavView.TextView.Subtitle"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:text="@{profile.subname}"
|
||||
tools:text="3b3t - 2020/2021" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/syncSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/profile_config_sync_enabled"
|
||||
android:checked="@={profile.syncEnabled}" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/logoutButton"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/profile_config_logout"
|
||||
android:textColor="@color/md_red_500"
|
||||
app:rippleColor="@color/md_red_300"
|
||||
app:strokeColor="@color/md_red_500" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</layout>
|
48
app/src/main/res/layout/mal_material_about_profile_item.xml
Normal file
48
app/src/main/res/layout/mal_material_about_profile_item.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="@dimen/mal_baseline_half">
|
||||
|
||||
<com.mikepenz.materialdrawer.view.BezelImageView
|
||||
android:id="@+id/mal_item_image"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_margin="@dimen/mal_baseline"
|
||||
android:adjustViewBounds="false"
|
||||
android:contentDescription="@null"
|
||||
android:cropToPadding="false"
|
||||
android:scaleType="centerCrop"
|
||||
tools:background="@tools:sample/backgrounds/scenic" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginVertical="@dimen/mal_baseline"
|
||||
android:layout_marginEnd="@dimen/mal_baseline"
|
||||
android:layout_marginRight="@dimen/mal_baseline"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mal_item_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="24sp"
|
||||
tools:text="Władca Androida" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mal_item_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
tools:text="kubasz" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
@ -351,8 +351,6 @@
|
||||
<string name="event_list_added_by_unknown_format">Hinzugefügt %1$s%3$s</string>
|
||||
<string name="event_list_shared_by_format">{cmd-share-variant} %1$s von %2$s%3$s</string>
|
||||
<string name="event_list_shared_by_self_format">{cmd-share-variant} %1$s von Ihnen%3$s</string>
|
||||
<string name="event_manual_need_registration_text">Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren.</string>
|
||||
<string name="event_manual_need_registration_title">Ereignisse teilen</string>
|
||||
<string name="event_manual_remove">Ereignis entfernen…</string>
|
||||
<string name="event_manual_saving">Ereignis speichern…</string>
|
||||
<string name="event_manual_share">Ereignis teilen…</string>
|
||||
@ -830,9 +828,13 @@
|
||||
<string name="rate_snackbar_positive">etzt bewerten</string>
|
||||
<string name="rate_snackbar_text">Zeigen Sie, dass Ihnen Szkolny.eu gefällt - bewerten Sie die App und machen Sie sie noch besser!</string>
|
||||
<string name="refresh">Aktualisieren</string>
|
||||
<string name="registration_enable_dialog_text">Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der <a href="http://szkolny.eu/privacy-policy"> Datenschutzrichtlinie </a> lesen und die Bestimmungen akzeptieren.</string>
|
||||
<string name="registration_enable_dialog_title">Server-Registrierung</string>
|
||||
<string name="registration_enable_progress_text">Gemeinsame Ereignisse herunterladen…</string>
|
||||
<string name="registration_config_disable_progress_text">Benutzerregistrierung aufheben…</string>
|
||||
<string name="registration_config_disable_text">Einige Funktionen wie Ereignisfreigabe oder Benachrichtigungsweiterleitung können nicht mehr verwendet werden.\n\nDie Funktion kann je nach ausgewähltem Profil aktiviert / deaktiviert werden.</string>
|
||||
<string name="registration_config_enable_progress_text">Gemeinsame Ereignisse herunterladen…</string>
|
||||
<string name="registration_config_enable_text">Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der <a href="http://szkolny.eu/privacy-policy"> Datenschutzrichtlinie </a> lesen und die Bestimmungen akzeptieren.</string>
|
||||
<string name="registration_config_event_sharing_text">Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren.</string>
|
||||
<string name="registration_config_event_sharing_title">Ereignisse teilen</string>
|
||||
<string name="registration_config_title">Szkolny.eu Server-Registrierung</string>
|
||||
<string name="remove">Löschen</string>
|
||||
<string name="removed">gelöschtet</string>
|
||||
<string name="report">Melden</string>
|
||||
@ -847,13 +849,13 @@
|
||||
<string name="settings_about_crash_text">Klicken Sie hier, um eine unerwartete Ausnahme auszulösen</string>
|
||||
<string name="settings_about_discord_subtext">Treten Sie unserem Discord-Server bei!</string>
|
||||
<string name="settings_about_discord_text">Discord Server</string>
|
||||
<string name="settings_about_language_dialog_text">Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht.</string>
|
||||
<string name="settings_about_language_dialog_title">App-Sprache ändern</string>
|
||||
<string name="app_language_dialog_text">Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht.</string>
|
||||
<string name="app_language_dialog_title">App-Sprache ändern</string>
|
||||
<string name="settings_about_language_subtext">Deutsch</string>
|
||||
<string name="settings_about_language_text">Sprache der App</string>
|
||||
<string name="settings_about_licenses_text">Open-Source-Lizenzen</string>
|
||||
<string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string>
|
||||
<string name="settings_about_register_title_text">E-Klassenbuch</string>
|
||||
<string name="settings_card_register_title">E-Klassenbuch</string>
|
||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - Februar 2021</string>
|
||||
<string name="settings_about_update_subtext">Klicken Sie hier, um nach Aktualisierungen zu suchen</string>
|
||||
<string name="settings_about_update_text">Aktualisierung</string>
|
||||
@ -944,7 +946,7 @@
|
||||
<string name="settings_sync_sync_interval_subtext_disabled">Deaktiviert</string>
|
||||
<string name="settings_sync_sync_interval_subtext_format">Daten alle %s herunterladen</string>
|
||||
<string name="settings_sync_sync_interval_text">Automatische Synchronisierung</string>
|
||||
<string name="settings_sync_title_text">Synchronisation und Benachrichtigungen</string>
|
||||
<string name="settings_card_sync_title">Synchronisation und Benachrichtigungen</string>
|
||||
<string name="settings_sync_updates_text">Über App-Aktualisierungen benachrichtigen</string>
|
||||
<string name="settings_sync_web_push_subtext">Benachrichtigungen auf Ihrem PC anzeigen</string>
|
||||
<string name="settings_sync_web_push_text">Benachrichtigungsweiterleitung</string>
|
||||
@ -968,7 +970,7 @@
|
||||
<string name="settings_theme_theme_pink">Rosa</string>
|
||||
<string name="settings_theme_theme_system">System</string>
|
||||
<string name="settings_theme_theme_text">Thema</string>
|
||||
<string name="settings_theme_title_text">Aussehen</string>
|
||||
<string name="settings_card_theme_title">Aussehen</string>
|
||||
<string name="share">Teilen</string>
|
||||
<string name="share_intent">Teilen über…</string>
|
||||
<string name="sharing_event">Daten Teilen…</string>
|
||||
|
@ -351,8 +351,6 @@
|
||||
<string name="event_list_added_by_unknown_format">Adde %1$s%3$s</string>
|
||||
<string name="event_list_shared_by_format">{cmd-share-variant} %1$s by %2$s%3$s</string>
|
||||
<string name="event_list_shared_by_self_format">{cmd-share-variant} %1$s by you%3$s</string>
|
||||
<string name="event_manual_need_registration_text">You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nBefore turning it on, make sure you\'ve read the terms and accept them</string>
|
||||
<string name="event_manual_need_registration_title">Sharing events</string>
|
||||
<string name="event_manual_remove">Removing event…</string>
|
||||
<string name="event_manual_saving">Saving event…</string>
|
||||
<string name="event_manual_share">Sharing event…</string>
|
||||
@ -832,9 +830,13 @@
|
||||
<string name="rate_snackbar_positive">Rate now</string>
|
||||
<string name="rate_snackbar_text">Show that you like Szkolny.eu - rate the app and make it even better!</string>
|
||||
<string name="refresh">Refresh</string>
|
||||
<string name="registration_enable_dialog_text">Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nMake sure you read the terms and accept them.</string>
|
||||
<string name="registration_enable_dialog_title">Server registration</string>
|
||||
<string name="registration_enable_progress_text">Syncing shared events…</string>
|
||||
<string name="registration_config_disable_progress_text">Unregistering the user…</string>
|
||||
<string name="registration_config_disable_text">You won\'t be able to use some functions anymore, like Event sharing and Notification forwarding.\n\nThis feature may be enabled/disabled depending on the active profile.</string>
|
||||
<string name="registration_config_enable_progress_text">Syncing shared events…</string>
|
||||
<string name="registration_config_enable_text">Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nContinuing means reading and accepting the <a href="https://szkolny.eu/privacy-policy">Privacy policy</a>.</string>
|
||||
<string name="registration_config_event_sharing_text">You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nContinuing means reading and accepting the <a href="https://szkolny.eu/privacy-policy">Privacy policy</a>.</string>
|
||||
<string name="registration_config_event_sharing_title">Sharing events</string>
|
||||
<string name="registration_config_title">Szkolny.eu server registration</string>
|
||||
<string name="remove">Remove</string>
|
||||
<string name="removed">Removed</string>
|
||||
<string name="report">Report</string>
|
||||
@ -849,13 +851,13 @@
|
||||
<string name="settings_about_crash_text">Click to throw an unexpected exception</string>
|
||||
<string name="settings_about_discord_subtext">Join our Discord community!</string>
|
||||
<string name="settings_about_discord_text">Discord server</string>
|
||||
<string name="settings_about_language_dialog_text">Notice. This feature may not work on some devices or in some parts of the app.</string>
|
||||
<string name="settings_about_language_dialog_title">Change app language</string>
|
||||
<string name="settings_about_language_subtext">"English "</string>
|
||||
<string name="app_language_dialog_text">Notice. This feature may not work on some devices or in some parts of the app.</string>
|
||||
<string name="app_language_dialog_title">Change app language</string>
|
||||
<string name="settings_about_language_subtext">English</string>
|
||||
<string name="settings_about_language_text">App language</string>
|
||||
<string name="settings_about_licenses_text">Open-source licenses</string>
|
||||
<string name="settings_about_privacy_policy_text">Privacy policy</string>
|
||||
<string name="settings_about_register_title_text">E-register</string>
|
||||
<string name="settings_card_register_title">E-register</string>
|
||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - February 2021</string>
|
||||
<string name="settings_about_update_subtext">Click to check for updates</string>
|
||||
<string name="settings_about_update_text">Update</string>
|
||||
@ -946,7 +948,7 @@
|
||||
<string name="settings_sync_sync_interval_subtext_disabled">Disabled</string>
|
||||
<string name="settings_sync_sync_interval_subtext_format">Download data every %s</string>
|
||||
<string name="settings_sync_sync_interval_text">Automatic sync</string>
|
||||
<string name="settings_sync_title_text">Sync & notifications</string>
|
||||
<string name="settings_card_sync_title">Sync & notifications</string>
|
||||
<string name="settings_sync_updates_text">Notify about app updates</string>
|
||||
<string name="settings_sync_web_push_subtext">Show notifications on your PC</string>
|
||||
<string name="settings_sync_web_push_text">Notification forwarding</string>
|
||||
@ -970,7 +972,7 @@
|
||||
<string name="settings_theme_theme_pink">Pink</string>
|
||||
<string name="settings_theme_theme_system">System</string>
|
||||
<string name="settings_theme_theme_text">Theme</string>
|
||||
<string name="settings_theme_title_text">Appearance</string>
|
||||
<string name="settings_card_theme_title">Appearance</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="share_intent">Share…</string>
|
||||
<string name="sharing_event">Sharing events…</string>
|
||||
|
@ -386,8 +386,6 @@
|
||||
<string name="event_list_added_by_unknown_format">Dodano %1$s%3$s</string>
|
||||
<string name="event_list_shared_by_format">{cmd-share-variant} %1$s przez %2$s%3$s</string>
|
||||
<string name="event_list_shared_by_self_format">{cmd-share-variant} %1$s przez Ciebie%3$s</string>
|
||||
<string name="event_manual_need_registration_text">Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nUpewnij się, że zapoznałeś się z warunkami i akceptujesz jej postanowienia.</string>
|
||||
<string name="event_manual_need_registration_title">Udostępnianie wydarzeń</string>
|
||||
<string name="event_manual_remove">Usuwam wydarzenie…</string>
|
||||
<string name="event_manual_saving">Zapisuję wydarzenie…</string>
|
||||
<string name="event_manual_share">Udostępniam wydarzenie…</string>
|
||||
@ -895,9 +893,13 @@
|
||||
<string name="rate_snackbar_positive">Oceń teraz</string>
|
||||
<string name="rate_snackbar_text">Pokaż, że podoba ci się Szkolny.eu - oceń aplikację i spraw, by była jeszcze lepsza!</string>
|
||||
<string name="refresh">Odśwież</string>
|
||||
<string name="registration_enable_dialog_text">Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nUpewnij się, że zapoznałeś się z warunkami <a href="http://szkolny.eu/privacy-policy">Polityki prywatności</a> i akceptujesz jej postanowienia.</string>
|
||||
<string name="registration_enable_dialog_title">Rejestracja na serwerze</string>
|
||||
<string name="registration_enable_progress_text">Pobieranie udostępnionych wydarzeń…</string>
|
||||
<string name="registration_config_disable_progress_text">Trwa wyrejestrowywanie użytkownika…</string>
|
||||
<string name="registration_config_disable_text">Stracisz możliwość korzystania z niektórych funkcji, takich jak Udostępnianie wydarzeń czy Przekazywanie powiadomień.\n\nFunkcja może być włączona/wyłączona w zależności od wybranego profilu.</string>
|
||||
<string name="registration_config_enable_progress_text">Pobieranie udostępnionych wydarzeń…</string>
|
||||
<string name="registration_config_enable_text">Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień <a href="https://szkolny.eu/privacy-policy">Polityki prywatności</a>.</string>
|
||||
<string name="registration_config_event_sharing_text">Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień <a href="https://szkolny.eu/privacy-policy">Polityki prywatności</a>.</string>
|
||||
<string name="registration_config_event_sharing_title">Udostępnianie wydarzeń</string>
|
||||
<string name="registration_config_title">Rejestracja aplikacji Szkolny.eu</string>
|
||||
<string name="remove">Usuń</string>
|
||||
<string name="removed">Usunięto</string>
|
||||
<string name="report">Zgłoś</string>
|
||||
@ -912,13 +914,13 @@
|
||||
<string name="settings_about_crash_text">Kliknij, aby wywołać nieoczekiwany wyjątek</string>
|
||||
<string name="settings_about_discord_subtext">Dołącz do naszego serwera Discord!</string>
|
||||
<string name="settings_about_discord_text">Serwer Discord</string>
|
||||
<string name="settings_about_language_dialog_text">Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji.</string>
|
||||
<string name="settings_about_language_dialog_title">Zmień język aplikacji</string>
|
||||
<string name="app_language_dialog_text">Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji.</string>
|
||||
<string name="app_language_dialog_title">Zmień język aplikacji</string>
|
||||
<string name="settings_about_language_subtext">Polski</string>
|
||||
<string name="settings_about_language_text">Język aplikacji</string>
|
||||
<string name="settings_about_licenses_text">Licencje open-source</string>
|
||||
<string name="settings_about_privacy_policy_text">Polityka prywatności</string>
|
||||
<string name="settings_about_register_title_text">E-dziennik</string>
|
||||
<string name="settings_card_register_title">E-dziennik</string>
|
||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - luty 2021</string>
|
||||
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
|
||||
<string name="settings_about_update_text">Aktualizacja</string>
|
||||
@ -1011,7 +1013,7 @@
|
||||
<string name="settings_sync_sync_interval_subtext_disabled">Wyłączona</string>
|
||||
<string name="settings_sync_sync_interval_subtext_format">Pobieraj dane co %s</string>
|
||||
<string name="settings_sync_sync_interval_text">Synchronizacja automatyczna</string>
|
||||
<string name="settings_sync_title_text">Synchronizacja i powiadomienia</string>
|
||||
<string name="settings_card_sync_title">Synchronizacja i powiadomienia</string>
|
||||
<string name="settings_sync_updates_text">Powiadamiaj o aktualizacjach aplikacji</string>
|
||||
<string name="settings_sync_web_push_subtext">Pokazuj powiadomienia na swoim komputerze</string>
|
||||
<string name="settings_sync_web_push_text">Przekazywanie powiadomień</string>
|
||||
@ -1035,7 +1037,7 @@
|
||||
<string name="settings_theme_theme_pink">Różowy</string>
|
||||
<string name="settings_theme_theme_system">Systemowy</string>
|
||||
<string name="settings_theme_theme_text">Motyw</string>
|
||||
<string name="settings_theme_title_text">Wygląd</string>
|
||||
<string name="settings_card_theme_title">Wygląd</string>
|
||||
<string name="share">Udostępnij</string>
|
||||
<string name="share_intent">Udostępnij przez…</string>
|
||||
<string name="sharing_event">Udostępnianie danych…</string>
|
||||
@ -1387,4 +1389,14 @@
|
||||
<string name="login_chooser_mode_dev_only">{cmd-android-studio} Wersja deweloperska</string>
|
||||
<string name="eggs">\???</string>
|
||||
<string name="rate_snackbar_negative_message">Szkoda, opinie innych pomagają mi rozwijać aplikację.</string>
|
||||
<string name="event_manual_no_profile">Nie znaleziono profilu ucznia.</string>
|
||||
<string name="see_also">Zobacz także</string>
|
||||
<string name="settings_about_homepage_text">Wejdź na stronę aplikacji</string>
|
||||
<string name="settings_about_homepage_subtext">Uzyskaj pomoc lub wesprzyj autorów</string>
|
||||
<string name="settings_about_github_text">Kod źródłowy</string>
|
||||
<string name="settings_about_github_subtext">Pomóż w rozwoju aplikacji na GitHubie</string>
|
||||
<string name="profile_config_name_hint">Nazwa profilu</string>
|
||||
<string name="profile_config_sync_enabled">Synchronizuj ten profil</string>
|
||||
<string name="profile_config_logout">Wyloguj się</string>
|
||||
<string name="permissions_qr_scanner">Aby móc zeskanować kod QR musisz przyznać uprawnienia dostępu do kamery.\n\nKliknij OK, aby przyznać uprawnienia.</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user