[UI/Settings] Add new profile config dialog. Implement choosing background images.

This commit is contained in:
Kuba Szczodrzyński 2021-03-25 15:50:14 +01:00
parent ea7b4438e8
commit 0f84732f80
14 changed files with 525 additions and 71 deletions

View File

@ -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:1.2"
implementation "eu.szkolny:szkolny-font:1.3"
// Other dependencies
implementation "cat.ereza:customactivityoncrash:2.3.0"

View File

@ -10,7 +10,6 @@ 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
@ -56,7 +55,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.ProfileRemoveDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
@ -98,7 +97,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
@ -111,8 +109,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
@ -264,6 +260,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 }
@ -479,28 +476,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()
@ -590,7 +566,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)
@ -838,7 +814,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
handleIntent(intent?.extras)
}
}
private fun handleIntent(extras: Bundle?) {
fun handleIntent(extras: Bundle?) {
d(TAG, "handleIntent() {")
extras?.keySet()?.forEach { key ->
@ -996,13 +972,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)
}
/* _ _ _ _ _
@ -1228,6 +1198,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()
}
}
/* _____ _ _
| __ \ (_) |
| | | |_ __ __ ___ _____ _ __ _| |_ ___ _ __ ___ ___

View File

@ -0,0 +1,205 @@
/*
* 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.theartofdev.edmodo.cropper.CropImage
import com.theartofdev.edmodo.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>()
fun requestLogin() = activity.startActivityForResult(
Intent(activity, LoginActivity::class.java),
REQUEST_LOGIN_ACTIVITY
)
fun requestHeaderBackground(listener: (Any?) -> Unit) {
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) {
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) {
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?> {
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 = data?.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)
}
}
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-3-23.
*/
package pl.szczodrzynski.edziennik.ui.dialogs.profile
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.addTextChangedListener
import com.google.android.material.dialog.MaterialAlertDialogBuilder
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)
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
profile.applyImageTo(b.image)
}
}
}
b.logoutButton.onClick {
ProfileRemoveDialog(activity, profile.id, profile.name) {
profileRemoved = true
dialog.dismiss()
}
}
}}
}

View File

@ -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()
}}
}

View File

@ -104,10 +104,12 @@ class RegistrationConfigDialog(
// force full registration of the user
App.config.getFor(profile.id).hash = ""
AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run(
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

View File

@ -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

View File

@ -54,8 +54,8 @@ import pl.szczodrzynski.edziennik.sync.SyncWorker;
import pl.szczodrzynski.edziennik.sync.UpdateWorker;
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog;
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity;
import pl.szczodrzynski.edziennik.utils.Themes;
@ -253,7 +253,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
icon(SzkolnyFont.Icon.szf_delete_empty_outline, iconSizeDp, iconColor)
)
.setOnClickAction(() -> {
new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName(), false);
new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName(), false, null);
})
);

View File

@ -4,8 +4,6 @@
package pl.szczodrzynski.edziennik.ui.modules.settings
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.core.graphics.drawable.toBitmap
import com.danielstone.materialaboutlibrary.items.*
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
import com.mikepenz.iconics.IconicsDrawable
@ -27,7 +25,8 @@ class SettingsUtil(
fun refresh() = onRefresh()
private fun IIcon.asDrawable(color: Int? = null, size: Int = 20) = IconicsDrawable(activity).apply {
private fun IIcon.asDrawable(color: Int? = null, size: Int = 20) =
IconicsDrawable(activity).apply {
icon = this@asDrawable
sizeDp = size
colorInt = color ?: Themes.getPrimaryTextColor(activity)
@ -171,18 +170,20 @@ class SettingsUtil(
.icon(R.mipmap.ic_splash)
.build()
fun createProfileItem(profile: Profile, onClick: (profile: Profile) -> Unit) =
MaterialAboutProfileItem(
fun createProfileItem(
profile: Profile,
onClick: (item: MaterialAboutProfileItem, profile: Profile) -> Unit
): MaterialAboutProfileItem {
val item = MaterialAboutProfileItem(
MaterialAboutTitleItem.Builder()
.text(profile.name)
.desc(profile.subname)
.icon(RoundedBitmapDrawableFactory.create(
activity.resources,
profile.getImageDrawable(activity).toBitmap()
).also {
it.isCircular = true
})
.setOnClickAction { onClick(profile) }
.icon(profile.getImageDrawable(activity))
.build()
)
item.setOnClickAction {
onClick(item, profile)
}
return item
}
}

View File

@ -8,8 +8,10 @@ import android.content.Intent
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import eu.szkolny.font.SzkolnyFont
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog
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
@ -21,12 +23,21 @@ class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) {
itemsMore = getItemsMore()
)
override fun getItems() = listOf(
util.createProfileItem(
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,

View File

@ -4,6 +4,7 @@
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
@ -74,7 +75,28 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
text = R.string.settings_theme_drawer_header_text,
icon = CommunityMaterial.Icon2.cmd_image_outline
) {
// TODO: 2021-03-17
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(
@ -82,7 +104,27 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
subText = R.string.settings_theme_app_background_subtext,
icon = CommunityMaterial.Icon2.cmd_image_filter_hdr
) {
// TODO: 2021-03-17
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(
@ -93,4 +135,14 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
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()
}
}

View File

@ -0,0 +1,107 @@
<?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" />
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/imageButtonIcon"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="bottom|end"
app:iiv_background_color="?android:colorBackground"
app:iiv_color="?colorOnBackground"
app:iiv_corner_radius="18dp"
app:iiv_icon="szf-image-plus-outline"
app:iiv_padding="5dp" />
<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>

View File

@ -6,7 +6,7 @@
android:orientation="horizontal"
android:paddingHorizontal="@dimen/mal_baseline_half">
<ImageView
<com.mikepenz.materialdrawer.view.BezelImageView
android:id="@+id/mal_item_image"
android:layout_width="80dp"
android:layout_height="80dp"

View File

@ -1395,4 +1395,7 @@
<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>
</resources>