From 82b232d0e5e5f2c2b85a5af6c4d6d8eccb6890cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 15 Feb 2020 14:36:36 +0100 Subject: [PATCH] [Messages/Compose] Add dropdown icon to show all recipient categories. Add before-send confirmation dialog. --- .../messages/MessagesComposeFragment.kt | 196 ++++++++++-------- .../MessagesComposeSuggestionAdapter.kt | 7 +- .../res/layout/messages_compose_fragment.xml | 4 +- app/src/main/res/values/strings.xml | 2 + .../com/hootsuite/nachos/NachoTextView.java | 16 ++ 5 files changed, 140 insertions(+), 85 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeFragment.kt index b0956257..784b95a1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeFragment.kt @@ -17,6 +17,7 @@ import android.text.style.StyleSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.AutoCompleteTextView import android.widget.Toast import androidx.core.text.HtmlCompat import androidx.core.widget.addTextChangedListener @@ -72,8 +73,6 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { 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 = MessagesComposeFragmentBinding.inflate(inflater) return b.root @@ -84,7 +83,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // TODO check if app, activity, b can be null - if (app.profile == null || !isAdded) + if (!isAdded) return EventBus.getDefault().register(this) @@ -190,80 +189,94 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { override fun createChip(context: Context, text: CharSequence, data: Any?): ChipSpan? { if (data == null || data !is Teacher) return null - if (data.id in -24L..0L) { - val type = (data.id * -1).toInt() - - val textColorPrimary = android.R.attr.textColorPrimary.resolveAttr(activity) - val textColorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity) - - val category = mutableListOf() - val categoryNames = mutableListOf() - val categoryCheckedItems = mutableListOf() - teachers.forEach { teacher -> - if (teacher.isType(type)) { - category += teacher - val name = teacher.fullName - val description = when (type) { - Teacher.TYPE_TEACHER -> null - Teacher.TYPE_PARENTS_COUNCIL -> teacher.typeDescription - Teacher.TYPE_SCHOOL_PARENTS_COUNCIL -> null - Teacher.TYPE_PEDAGOGUE -> null - Teacher.TYPE_LIBRARIAN -> null - Teacher.TYPE_SCHOOL_ADMIN -> null - Teacher.TYPE_SUPER_ADMIN -> null - Teacher.TYPE_SECRETARIAT -> null - Teacher.TYPE_PRINCIPAL -> null - Teacher.TYPE_EDUCATOR -> teacher.typeDescription - Teacher.TYPE_PARENT -> teacher.typeDescription - Teacher.TYPE_STUDENT -> teacher.typeDescription - Teacher.TYPE_SPECIALIST -> null - else -> teacher.typeDescription - } - categoryNames += listOfNotNull( - name.asSpannable( - ForegroundColorSpan(textColorPrimary) - ), - description?.asSpannable( - ForegroundColorSpan(textColorSecondary), - AbsoluteSizeSpan(14.dp) - ) - ).concat("\n") - categoryCheckedItems += b.recipients.allChips.firstOrNull { it.data == teacher } != null + if (data.id !in -24L..0L) { + b.recipients.allChips.forEach { + if (it.data == data) { + Toast.makeText(activity, R.string.messages_compose_recipient_exists, Toast.LENGTH_SHORT).show() + return null } } + val chipSpan = ChipSpan(context, data.fullName, BitmapDrawable(context.resources, data.image), data) + chipSpan.setIconBackgroundColor(Colors.stringToMaterialColor(data.fullName)) + return chipSpan + } - MaterialAlertDialogBuilder(activity) - .setTitle("Dodaj odbiorców - "+ Teacher.typeName(activity, type)) - //.setMessage(getString(R.string.messages_compose_recipients_text_format, Teacher.typeName(activity, type))) - .setPositiveButton("OK", null) - .setNeutralButton("Anuluj", null) - .setMultiChoiceItems(categoryNames.toTypedArray(), categoryCheckedItems.toBooleanArray()) { _, which, isChecked -> - val teacher = category[which] - if (isChecked) { - val chipInfoList = mutableListOf() - teacher.image = getProfileImage(48, 24, 16, 12, 1, teacher.fullName) - chipInfoList.add(ChipInfo(teacher.fullName, teacher)) - b.recipients.addTextWithChips(chipInfoList) - } - else { - b.recipients.allChips.forEach { - if (it.data == teacher) - b.recipients.chipTokenizer?.deleteChipAndPadding(it, b.recipients.text) - } + val type = (data.id * -1).toInt() + + val textColorPrimary = android.R.attr.textColorPrimary.resolveAttr(activity) + val textColorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity) + + val sortByCategory = type in listOf( + Teacher.TYPE_PARENTS_COUNCIL, + Teacher.TYPE_EDUCATOR, + Teacher.TYPE_STUDENT + ) + val teachers = if (sortByCategory) + teachers.sortedBy { it.typeDescription } + else + teachers + + val category = mutableListOf() + val categoryNames = mutableListOf() + val categoryCheckedItems = mutableListOf() + teachers.forEach { teacher -> + if (!teacher.isType(type)) + return@forEach + + category += teacher + val name = teacher.fullName + val description = when (type) { + Teacher.TYPE_TEACHER -> null + Teacher.TYPE_PARENTS_COUNCIL -> teacher.typeDescription + Teacher.TYPE_SCHOOL_PARENTS_COUNCIL -> null + Teacher.TYPE_PEDAGOGUE -> null + Teacher.TYPE_LIBRARIAN -> null + Teacher.TYPE_SCHOOL_ADMIN -> null + Teacher.TYPE_SUPER_ADMIN -> null + Teacher.TYPE_SECRETARIAT -> null + Teacher.TYPE_PRINCIPAL -> null + Teacher.TYPE_EDUCATOR -> teacher.typeDescription + Teacher.TYPE_PARENT -> teacher.typeDescription + Teacher.TYPE_STUDENT -> teacher.typeDescription + Teacher.TYPE_SPECIALIST -> null + else -> teacher.typeDescription + } + categoryNames += listOfNotNull( + name.asSpannable( + ForegroundColorSpan(textColorPrimary) + ), + description?.asSpannable( + ForegroundColorSpan(textColorSecondary), + AbsoluteSizeSpan(14.dp) + ) + ).concat("\n") + + // check the teacher if already added as a recipient + categoryCheckedItems += b.recipients.allChips.firstOrNull { it.data == teacher } != null + } + + MaterialAlertDialogBuilder(activity) + .setTitle("Dodaj odbiorców - "+ Teacher.typeName(activity, type)) + //.setMessage(getString(R.string.messages_compose_recipients_text_format, Teacher.typeName(activity, type))) + .setPositiveButton("OK", null) + .setNeutralButton("Anuluj", null) + .setMultiChoiceItems(categoryNames.toTypedArray(), categoryCheckedItems.toBooleanArray()) { _, which, isChecked -> + val teacher = category[which] + if (isChecked) { + val chipInfoList = mutableListOf() + teacher.image = getProfileImage(48, 24, 16, 12, 1, teacher.fullName) + chipInfoList.add(ChipInfo(teacher.fullName, teacher)) + b.recipients.addTextWithChips(chipInfoList) + } + else { + b.recipients.allChips.forEach { + if (it.data == teacher) + b.recipients.chipTokenizer?.deleteChipAndPadding(it, b.recipients.text) } } - .show() - return null - } - b.recipients.allChips.forEach { - if (it.data == data) { - Toast.makeText(activity, R.string.messages_compose_recipient_exists, Toast.LENGTH_SHORT).show() - return null - } - } - val chipSpan = ChipSpan(context, data.fullName, BitmapDrawable(context.resources, data.image), data) - chipSpan.setIconBackgroundColor(Colors.stringToMaterialColor(data.fullName)) - return chipSpan + } + .show() + return null } override fun configureChip(chip: ChipSpan, chipConfiguration: ChipConfiguration) { @@ -276,23 +289,33 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { b.recipients.setIllegalCharacterIdentifier { c -> c.toString().matches("[\\n;:_ ]".toRegex()) } - /*b.recipients.setOnChipClickListener { chip, _ -> - Toast.makeText(app, "onChipClick: " + chip.text, Toast.LENGTH_SHORT).show() - }*/ - b.recipients.setOnChipRemoveListener { chip -> + b.recipients.setOnChipRemoveListener { _ -> b.recipients.setSelection(b.recipients.text.length) } + b.recipients.addTextChangedListener( beforeTextChanged = { _, _, _, _ -> + b.recipients.ignoreThreshold = false + }) + b.recipients.onDismissListener = AutoCompleteTextView.OnDismissListener { + b.recipients.ignoreThreshold = false + } + b.recipientsLayout.setEndIconOnClickListener { + b.recipients.error = null + b.recipients.ignoreThreshold = true + b.recipients.showDropDown() + val adapter = b.recipients.adapter ?: return@setEndIconOnClickListener + if (adapter is MessagesComposeSuggestionAdapter) + adapter.filter.filter(null) + } + b.recipientsLayout.isEnabled = false b.subjectLayout.isEnabled = false b.textLayout.isEnabled = false - activity.navView.apply { - bottomBar.apply { - fabEnable = true - fabExtendedText = getString(R.string.messages_compose_send) - fabIcon = CommunityMaterial.Icon2.cmd_send - } + activity.navView.bottomBar.apply { + fabEnable = true + fabExtendedText = getString(R.string.messages_compose_send) + fabIcon = CommunityMaterial.Icon2.cmd_send setFabOnClickListener(View.OnClickListener { sendMessage() @@ -438,7 +461,14 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { activity.bottomSheet.hideKeyboard() - EdziennikTask.messageSend(App.profileId, recipients, subject.trim(), textHtml.trim()).enqueue(activity) + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.messages_compose_confirm_title) + .setMessage(R.string.messages_compose_confirm_text) + .setPositiveButton(R.string.send) { _, _ -> + EdziennikTask.messageSend(App.profileId, recipients, subject.trim(), textHtml.trim()).enqueue(activity) + } + .setNegativeButton(R.string.cancel, null) + .show() } @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeSuggestionAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeSuggestionAdapter.kt index 07946e80..935d2d34 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeSuggestionAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesComposeSuggestionAdapter.kt @@ -71,7 +71,12 @@ class MessagesComposeSuggestionAdapter( override fun performFiltering(prefix: CharSequence?): FilterResults { val results = FilterResults() - if (prefix.isNullOrEmpty()) { + if (prefix == null) { + originalList.filter { it.id in -24L..0L }.let { + results.values = it + results.count = it.size + } + } else if (prefix.isEmpty()) { results.values = originalList results.count = originalList.size } else { diff --git a/app/src/main/res/layout/messages_compose_fragment.xml b/app/src/main/res/layout/messages_compose_fragment.xml index 7f07881a..19055549 100644 --- a/app/src/main/res/layout/messages_compose_fragment.xml +++ b/app/src/main/res/layout/messages_compose_fragment.xml @@ -21,7 +21,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:boxBackgroundColor="@android:color/transparent" - app:boxBackgroundMode="filled"> + app:boxBackgroundMode="filled" + app:endIconMode="custom" + app:endIconDrawable="@drawable/dropdown_arrow"> Inne Ustawienia ocen Pokaż imiona i nazwiska nauczycieli + Potwierdź wysłanie wiadomości + Czy na pewno chcesz wysłać wiadomość do wybranych odbiorców? diff --git a/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java b/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java index 1a9e9be7..b2cb81ab 100644 --- a/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java +++ b/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java @@ -1078,6 +1078,22 @@ public class NachoTextView extends MultiAutoCompleteTextView implements TextWatc return chipAndTokenValues; } + public boolean ignoreThreshold = false; + + @Override + public boolean enoughToFilter() { + return ignoreThreshold || super.enoughToFilter(); + } + + public OnDismissListener onDismissListener = null; + + @Override + public void dismissDropDown() { + if (onDismissListener != null) + onDismissListener.onDismiss(); + super.dismissDropDown(); + } + @Override public String toString() { try {