From c29a2bd07b5ef838e81cebd95a770b1ef938348b Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 14 Feb 2023 16:21:04 +0100 Subject: [PATCH] some changes for chat --- app/build.gradle | 2 + .../mastodon/ui/drawer/ComposeAdapter.java | 1 - .../ui/drawer/ConversationAdapter.java | 2 +- .../ui/drawer/StatusDirectMessageAdapter.java | 223 ++++++++++++-- .../FragmentMastodonDirectMessage.java | 271 +++++++++++++++++- .../mastodon/drawable/bubble_left_tail.xml | 4 +- .../mastodon/drawable/bubble_right_tail.xml | 4 +- .../layout/activity_direct_message.xml | 64 ++--- .../mastodon/layout/drawer_status_chat.xml | 11 + .../layouts/mastodon/layout/layout_poll.xml | 1 + app/src/main/res/values/colors.xml | 4 + 11 files changed, 511 insertions(+), 76 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8f7cea495..1a208594f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -77,6 +77,8 @@ android { 'src/main/res/menus/peertube', 'src/main/res/menus', + 'src/main/res/values', + 'src/main/res' ] } diff --git a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ComposeAdapter.java index 5cec5fac5..8ebadf0cd 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ComposeAdapter.java @@ -1648,7 +1648,6 @@ public class ComposeAdapter extends RecyclerView.Adapter displayPollPopup(holder, statusDraft, position)); - holder.binding.buttonPoll.setOnClickListener(v -> displayPollPopup(holder, statusDraft, position)); if (instanceInfo == null) { return; } diff --git a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ConversationAdapter.java b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ConversationAdapter.java index 29cb0df8f..3192d2863 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ConversationAdapter.java +++ b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ConversationAdapter.java @@ -211,7 +211,7 @@ public class ConversationAdapter extends RecyclerView.Adapter { Intent intent; if (chatMode) { diff --git a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusDirectMessageAdapter.java b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusDirectMessageAdapter.java index 1659e6e3b..36f3b9db3 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusDirectMessageAdapter.java +++ b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusDirectMessageAdapter.java @@ -21,20 +21,29 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.graphics.PorterDuff; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.CountDownTimer; +import android.text.SpannableString; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.RadioButton; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.widget.LinearLayoutCompat; import androidx.core.app.ActivityOptionsCompat; +import androidx.core.content.ContextCompat; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelStoreOwner; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; @@ -44,20 +53,25 @@ import org.jetbrains.annotations.NotNull; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.databinding.DrawerStatusChatBinding; import app.fedilab.android.databinding.LayoutMediaBinding; +import app.fedilab.android.databinding.LayoutPollItemBinding; import app.fedilab.android.mastodon.activities.MediaActivity; import app.fedilab.android.mastodon.client.entities.api.Attachment; +import app.fedilab.android.mastodon.client.entities.api.Poll; import app.fedilab.android.mastodon.client.entities.api.Status; import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.LongClickLinkMovementMethod; import app.fedilab.android.mastodon.helper.MastodonHelper; import app.fedilab.android.mastodon.helper.MediaHelper; import app.fedilab.android.mastodon.helper.ThemeHelper; +import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM; public class StatusDirectMessageAdapter extends RecyclerView.Adapter { @@ -81,7 +95,7 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter adapter, int mediaPosition, float mediaW, float mediaH, float ratio, - Status statusToDeal, Attachment attachment) { + Status status, Attachment attachment) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); final int timeout = sharedpreferences.getInt(context.getString(R.string.SET_NSFW_TIMEOUT), 5); boolean long_press_media = sharedpreferences.getBoolean(context.getString(R.string.SET_LONG_PRESS_STORE_MEDIA), false); @@ -96,9 +110,9 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter 0) { layoutMediaBinding.media.setContentDescription(attachment.description.trim()); @@ -132,22 +146,22 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter requestBuilder = prepareRequestBuilder(context, attachment, mediaW * ratio, mediaH * ratio, focusX, focusY, statusToDeal.sensitive, false); - if (!statusToDeal.sensitive || expand_media) { + RequestBuilder requestBuilder = prepareRequestBuilder(context, attachment, mediaW * ratio, mediaH * ratio, focusX, focusY, status.sensitive, false); + if (!status.sensitive || expand_media) { layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_24); } else { layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_off_24); } requestBuilder.load(attachment.preview_url).into(layoutMediaBinding.media); - if (statusToDeal.sensitive) { + if (status.sensitive) { Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, ThemeHelper.getAttColor(context, R.attr.colorError)); } else { Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, R.color.white); } layoutMediaBinding.media.setOnClickListener(v -> { - if (statusToDeal.sensitive && !expand_media) { - statusToDeal.sensitive = false; + if (status.sensitive && !expand_media) { + status.sensitive = false; int position = holder.getBindingAdapterPosition(); adapter.notifyItemChanged(position); @@ -157,7 +171,7 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter(statusToDeal.media_attachments)); + b.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(status.media_attachments)); mediaIntent.putExtras(b); ActivityOptionsCompat options = ActivityOptionsCompat - .makeSceneTransitionAnimation((Activity) context, layoutMediaBinding.media, statusToDeal.media_attachments.get(0).url); + .makeSceneTransitionAnimation((Activity) context, layoutMediaBinding.media, status.media_attachments.get(0).url); // start the new activity context.startActivity(mediaIntent, options.toBundle()); }); layoutMediaBinding.viewHide.setOnClickListener(v -> { - statusToDeal.sensitive = !statusToDeal.sensitive; + status.sensitive = !status.sensitive; adapter.notifyItemChanged(holder.getBindingAdapterPosition()); }); @@ -208,7 +222,7 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter(holder.binding.messageContent), @@ -228,23 +242,190 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter greaterValue) + greaterValue = pollItem.votes_count; + } + holder.binding.poll.rated.removeAllViews(); + List ownvotes = status.poll.own_votes; + int j = 0; + if (status.poll.voters_count == 0 && status.poll.votes_count > 0) { + status.poll.voters_count = status.poll.votes_count; + } + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + for (Poll.PollItem pollItem : status.poll.options) { + @NonNull LayoutPollItemBinding pollItemBinding = LayoutPollItemBinding.inflate(inflater, holder.binding.poll.rated, true); + double value = ((double) (pollItem.votes_count * 100) / (double) status.poll.voters_count); + pollItemBinding.pollItemPercent.setText(String.format("%s %%", (int) value)); + pollItemBinding.pollItemText.setText( + pollItem.getSpanTitle(context, status, + new WeakReference<>(pollItemBinding.pollItemText)), + TextView.BufferType.SPANNABLE); + pollItemBinding.pollItemPercent.setTextColor(ThemeHelper.getAttColor(context, R.attr.colorOnSecondary)); + pollItemBinding.pollItemText.setTextColor(ThemeHelper.getAttColor(context, R.attr.colorOnSecondary)); + pollItemBinding.pollItemValue.setProgress((int) value); + if (pollItem.votes_count == greaterValue) { + pollItemBinding.pollItemPercent.setTypeface(null, Typeface.BOLD); + pollItemBinding.pollItemText.setTypeface(null, Typeface.BOLD); + } + if (ownvotes != null && ownvotes.contains(j)) { + Drawable img = ContextCompat.getDrawable(context, R.drawable.ic_baseline_check_24); + assert img != null; + img.setColorFilter(ThemeHelper.getAttColor(context, R.attr.colorPrimary), PorterDuff.Mode.SRC_IN); + img.setBounds(0, 0, (int) (20 * scale + 0.5f), (int) (20 * scale + 0.5f)); + pollItemBinding.pollItemText.setCompoundDrawables(null, null, img, null); + } + j++; + } + } else { + + if (status.poll.voters_count == 0 && status.poll.votes_count > 0) { + status.poll.voters_count = status.poll.votes_count; + } + holder.binding.poll.rated.setVisibility(View.GONE); + holder.binding.poll.submitVote.setVisibility(View.VISIBLE); + if (status.poll.multiple) { + if ((holder.binding.poll.multipleChoice).getChildCount() > 0) + (holder.binding.poll.multipleChoice).removeAllViews(); + for (Poll.PollItem pollOption : status.poll.options) { + CheckBox cb = new CheckBox(context); + cb.setText( + pollOption.getSpanTitle(context, status, + new WeakReference<>(cb)), + TextView.BufferType.SPANNABLE); + holder.binding.poll.multipleChoice.addView(cb); + cb.setTextColor(ThemeHelper.getAttColor(context, R.attr.colorOnSecondary)); + } + holder.binding.poll.multipleChoice.setVisibility(View.VISIBLE); + holder.binding.poll.singleChoiceRadioGroup.setVisibility(View.GONE); + } else { + if ((holder.binding.poll.singleChoiceRadioGroup).getChildCount() > 0) + (holder.binding.poll.singleChoiceRadioGroup).removeAllViews(); + for (Poll.PollItem pollOption : status.poll.options) { + RadioButton rb = new RadioButton(context); + rb.setText( + pollOption.getSpanTitle(context, status, + new WeakReference<>(rb)), + TextView.BufferType.SPANNABLE); + rb.setTextColor(ThemeHelper.getAttColor(context, R.attr.colorOnSecondary)); + holder.binding.poll.singleChoiceRadioGroup.addView(rb); + } + holder.binding.poll.singleChoiceRadioGroup.setVisibility(View.VISIBLE); + holder.binding.poll.multipleChoice.setVisibility(View.GONE); + } + holder.binding.poll.submitVote.setVisibility(View.VISIBLE); + holder.binding.poll.submitVote.setOnClickListener(v -> { + int[] choice; + if (status.poll.multiple) { + ArrayList choices = new ArrayList<>(); + int choicesCount = holder.binding.poll.multipleChoice.getChildCount(); + for (int i1 = 0; i1 < choicesCount; i1++) { + if (holder.binding.poll.multipleChoice.getChildAt(i1) != null && holder.binding.poll.multipleChoice.getChildAt(i1) instanceof CheckBox) { + if (((CheckBox) holder.binding.poll.multipleChoice.getChildAt(i1)).isChecked()) { + choices.add(i1); + } + } + } + choice = new int[choices.size()]; + Iterator iterator = choices.iterator(); + for (int i1 = 0; i1 < choice.length; i1++) { + choice[i1] = iterator.next(); + } + if (choice.length == 0) + return; + } else { + choice = new int[1]; + choice[0] = -1; + int choicesCount = holder.binding.poll.singleChoiceRadioGroup.getChildCount(); + for (int i1 = 0; i1 < choicesCount; i1++) { + if (holder.binding.poll.singleChoiceRadioGroup.getChildAt(i1) != null && holder.binding.poll.singleChoiceRadioGroup.getChildAt(i1) instanceof RadioButton) { + if (((RadioButton) holder.binding.poll.singleChoiceRadioGroup.getChildAt(i1)).isChecked()) { + choice[0] = i1; + } + } + } + if (choice[0] == -1) + return; + } + //Vote on the poll + + statusesVM.votePoll(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, status.poll.id, choice) + .observe((LifecycleOwner) context, poll -> { + if (poll != null) { + int i = 0; + for (Poll.PollItem item : status.poll.options) { + if (item.span_title != null) { + poll.options.get(i).span_title = item.span_title; + } else { + poll.options.get(i).span_title = new SpannableString(item.title); + } + i++; + } + status.poll = poll; + notifyItemChanged(holder.getBindingAdapterPosition()); + } + }); + + }); + } + holder.binding.poll.refreshPoll.setOnClickListener(v -> statusesVM.getPoll(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, status.poll.id) + .observe((LifecycleOwner) context, poll -> { + if (poll != null) { + //Store span elements + int i = 0; + for (Poll.PollItem item : status.poll.options) { + if (item.span_title != null) { + poll.options.get(i).span_title = item.span_title; + } else { + poll.options.get(i).span_title = new SpannableString(item.title); + } + i++; + } + status.poll = poll; + notifyItemChanged(holder.getBindingAdapterPosition()); + } + })); + holder.binding.poll.pollContainer.setVisibility(View.VISIBLE); + String pollInfo = context.getResources().getQuantityString(R.plurals.number_of_voters, status.poll.voters_count, status.poll.voters_count); + if (status.poll.expired) { + pollInfo += " - " + context.getString(R.string.poll_finish_at, MastodonHelper.dateToStringPoll(status.poll.expires_at)); + } else { + pollInfo += " - " + context.getString(R.string.poll_finish_in, MastodonHelper.dateDiffPoll(context, status.poll.expires_at)); + } + holder.binding.poll.pollInfo.setText(pollInfo); + } else { + holder.binding.poll.pollContainer.setVisibility(View.GONE); + } holder.binding.userName.setText( status.account.getSpanDisplayName(context, new WeakReference<>(holder.binding.userName)), diff --git a/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonDirectMessage.java b/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonDirectMessage.java index 1d0345e78..ff2ab9ddc 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonDirectMessage.java +++ b/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonDirectMessage.java @@ -37,10 +37,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.AppCompatEditText; +import androidx.appcompat.widget.LinearLayoutCompat; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; @@ -68,12 +73,15 @@ import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.databinding.ComposeAttachmentItemBinding; +import app.fedilab.android.databinding.ComposePollBinding; +import app.fedilab.android.databinding.ComposePollItemBinding; import app.fedilab.android.databinding.FragmentDirectMessageBinding; import app.fedilab.android.databinding.PopupMediaDescriptionBinding; import app.fedilab.android.mastodon.activities.ComposeActivity; import app.fedilab.android.mastodon.client.entities.api.Attachment; import app.fedilab.android.mastodon.client.entities.api.Context; import app.fedilab.android.mastodon.client.entities.api.Mention; +import app.fedilab.android.mastodon.client.entities.api.Poll; import app.fedilab.android.mastodon.client.entities.api.Status; import app.fedilab.android.mastodon.client.entities.app.StatusDraft; import app.fedilab.android.mastodon.exception.DBException; @@ -84,6 +92,7 @@ import app.fedilab.android.mastodon.jobs.ComposeWorker; import app.fedilab.android.mastodon.services.ThreadMessageService; import app.fedilab.android.mastodon.ui.drawer.StatusDirectMessageAdapter; import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM; +import es.dmoral.toasty.Toasty; public class FragmentMastodonDirectMessage extends Fragment { @@ -155,7 +164,7 @@ public class FragmentMastodonDirectMessage extends Fragment { statusesVM.getContext(user_instance, user_token, focusedStatus.id) .observe(getViewLifecycleOwner(), this::initializeContextView); } - + binding.buttonCloseAttachmentPanel.setOnClickListener(v -> binding.attachmentChoicesPanel.setVisibility(View.GONE)); statusCompose = new Status(); binding.buttonAttach.setOnClickListener(v -> { @@ -176,6 +185,7 @@ public class FragmentMastodonDirectMessage extends Fragment { binding.attachmentChoicesPanel.setVisibility(View.VISIBLE); binding.buttonAttach.setChecked(false); }); + binding.buttonPoll.setOnClickListener(v -> displayPollPopup()); binding.buttonAttachAudio.setOnClickListener(v -> { binding.attachmentChoicesPanel.setVisibility(View.GONE); pickupMedia(ComposeActivity.mediaType.AUDIO); @@ -195,6 +205,7 @@ public class FragmentMastodonDirectMessage extends Fragment { binding.sendButton.setOnClickListener(v -> { statusCompose.submitted = true; + statusCompose.text = binding.text.getText().toString(); onSubmit(prepareDraft(statusCompose, MainActivity.currentInstance, MainActivity.currentUserID)); }); LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(broadcast_data, new IntentFilter(Helper.BROADCAST_DATA)); @@ -300,30 +311,266 @@ public class FragmentMastodonDirectMessage extends Fragment { return statusDraftDB; } - private Status initiliazeStatus() { - Status status = new Status(); + /** + * Display the popup to attach a poll to message + */ + private void displayPollPopup() { + AlertDialog.Builder alertPoll = new MaterialAlertDialogBuilder(requireActivity()); + alertPoll.setTitle(R.string.create_poll); + ComposePollBinding composePollBinding = ComposePollBinding.inflate(LayoutInflater.from(requireActivity()), new LinearLayout(requireActivity()), false); + alertPoll.setView(composePollBinding.getRoot()); + int max_entry = 4; + int max_length = 25; + final int[] pollCountItem = {2}; + + if (instanceInfo != null && instanceInfo.configuration != null && instanceInfo.configuration.pollsConf != null) { + max_entry = instanceInfo.configuration.pollsConf.max_options; + max_length = instanceInfo.configuration.pollsConf.max_option_chars; + } else if (instanceInfo != null && instanceInfo.poll_limits != null) { + max_entry = instanceInfo.poll_limits.max_options; + max_length = instanceInfo.poll_limits.max_option_chars; + } + InputFilter[] fArray = new InputFilter[1]; + fArray[0] = new InputFilter.LengthFilter(max_length); + composePollBinding.option1.text.setFilters(fArray); + composePollBinding.option1.textLayout.setHint(getString(R.string.poll_choice_s, 1)); + composePollBinding.option2.text.setFilters(fArray); + composePollBinding.option2.textLayout.setHint(getString(R.string.poll_choice_s, 2)); + composePollBinding.option1.buttonRemove.setVisibility(View.GONE); + composePollBinding.option2.buttonRemove.setVisibility(View.GONE); + int finalMax_entry = max_entry; + composePollBinding.buttonAddOption.setOnClickListener(v -> { + if (pollCountItem[0] < finalMax_entry) { + ComposePollItemBinding composePollItemBinding = ComposePollItemBinding.inflate(LayoutInflater.from(composePollBinding.optionsList.getContext()), composePollBinding.optionsList, false); + if (composePollBinding.pollType.getCheckedButtonId() == R.id.poll_type_multiple) + composePollItemBinding.typeIndicator.setImageResource(R.drawable.ic_compose_poll_option_mark_multiple); + composePollItemBinding.text.setFilters(fArray); + composePollItemBinding.textLayout.setHint(getString(R.string.poll_choice_s, (pollCountItem[0] + 1))); + LinearLayoutCompat viewItem = composePollItemBinding.getRoot(); + composePollBinding.optionsList.addView(composePollItemBinding.getRoot()); + composePollItemBinding.buttonRemove.setOnClickListener(view -> { + composePollBinding.optionsList.removeView(viewItem); + pollCountItem[0]--; + if (pollCountItem[0] >= finalMax_entry) { + composePollBinding.buttonAddOption.setVisibility(View.GONE); + } else { + composePollBinding.buttonAddOption.setVisibility(View.VISIBLE); + } + int childCount = composePollBinding.optionsList.getChildCount(); + for (int i = 0; i < childCount; i++) { + AppCompatEditText title = (composePollBinding.optionsList.getChildAt(i)).findViewById(R.id.text); + title.setHint(getString(R.string.poll_choice_s, i + 1)); + } + + }); + } + pollCountItem[0]++; + if (pollCountItem[0] >= finalMax_entry) { + composePollBinding.buttonAddOption.setVisibility(View.GONE); + } else { + composePollBinding.buttonAddOption.setVisibility(View.VISIBLE); + } + + }); + + + ArrayAdapter pollduration = ArrayAdapter.createFromResource(requireActivity(), + R.array.poll_duration, android.R.layout.simple_spinner_dropdown_item); + composePollBinding.pollDuration.setAdapter(pollduration); + composePollBinding.pollDuration.setSelection(4); + if (statusCompose != null && statusCompose.poll != null && statusCompose.poll.options != null) { + int i = 1; + for (Poll.PollItem pollItem : statusCompose.poll.options) { + if (i == 1) { + if (statusCompose.poll.multiple) + composePollBinding.option1.typeIndicator.setImageResource(R.drawable.ic_compose_poll_option_mark_multiple); + if (pollItem.title != null) + composePollBinding.option1.text.setText(pollItem.title); + } else if (i == 2) { + if (statusCompose.poll.multiple) + composePollBinding.option2.typeIndicator.setImageResource(R.drawable.ic_compose_poll_option_mark_multiple); + if (pollItem.title != null) + composePollBinding.option2.text.setText(pollItem.title); + } else { + + ComposePollItemBinding composePollItemBinding = ComposePollItemBinding.inflate(LayoutInflater.from(requireActivity()), new LinearLayout(requireActivity()), false); + if (composePollBinding.pollType.getCheckedButtonId() == R.id.poll_type_multiple) + composePollItemBinding.typeIndicator.setImageResource(R.drawable.ic_compose_poll_option_mark_multiple); + else + composePollItemBinding.typeIndicator.setImageResource(R.drawable.ic_compose_poll_option_mark_single); + + composePollItemBinding.text.setFilters(fArray); + composePollItemBinding.textLayout.setHint(getString(R.string.poll_choice_s, (pollCountItem[0] + 1))); + composePollItemBinding.text.setText(pollItem.title); + composePollBinding.optionsList.addView(composePollItemBinding.getRoot()); + composePollItemBinding.buttonRemove.setOnClickListener(view -> { + composePollBinding.optionsList.removeView(view); + pollCountItem[0]--; + }); + pollCountItem[0]++; + } + i++; + } + if (statusCompose.poll.options.size() >= max_entry) { + composePollBinding.buttonAddOption.setVisibility(View.GONE); + } + switch (statusCompose.poll.expire_in) { + case 300: + composePollBinding.pollDuration.setSelection(0); + break; + case 1800: + composePollBinding.pollDuration.setSelection(1); + break; + case 3600: + composePollBinding.pollDuration.setSelection(2); + break; + case 21600: + composePollBinding.pollDuration.setSelection(3); + break; + case 86400: + composePollBinding.pollDuration.setSelection(4); + break; + case 259200: + composePollBinding.pollDuration.setSelection(5); + break; + case 604800: + composePollBinding.pollDuration.setSelection(6); + break; + } + if (statusCompose.poll.multiple) + composePollBinding.pollType.check(R.id.poll_type_multiple); + else + composePollBinding.pollType.check(R.id.poll_type_single); + + + } + alertPoll.setNegativeButton(R.string.delete, (dialog, whichButton) -> { + if (statusCompose != null && statusCompose.poll != null) statusCompose.poll = null; + buttonState(); + dialog.dismiss(); + }); + alertPoll.setPositiveButton(R.string.save, null); + final AlertDialog alertPollDiaslog = alertPoll.create(); + alertPollDiaslog.setOnShowListener(dialog -> { + composePollBinding.pollType.addOnButtonCheckedListener((group, checkedId, isChecked) -> { + if (isChecked) { + if (checkedId == R.id.poll_type_single) { + if (statusCompose != null && statusCompose.poll != null) + statusCompose.poll.multiple = false; + for (int i = 0; i < composePollBinding.optionsList.getChildCount(); i++) { + ComposePollItemBinding child = ComposePollItemBinding.bind(composePollBinding.optionsList.getChildAt(i)); + child.typeIndicator.setImageResource(R.drawable.ic_compose_poll_option_mark_single); + } + } else if (checkedId == R.id.poll_type_multiple) { + if (statusCompose != null && statusCompose.poll != null) + statusCompose.poll.multiple = true; + for (int i = 0; i < composePollBinding.optionsList.getChildCount(); i++) { + ComposePollItemBinding child = ComposePollItemBinding.bind(composePollBinding.optionsList.getChildAt(i)); + child.typeIndicator.setImageResource(R.drawable.ic_compose_poll_option_mark_multiple); + } + } + } + }); + Button b = alertPollDiaslog.getButton(AlertDialog.BUTTON_POSITIVE); + b.setOnClickListener(view1 -> { + int poll_duration_pos = composePollBinding.pollDuration.getSelectedItemPosition(); + + int selected_poll_type_id = composePollBinding.pollType.getCheckedButtonId(); + String choice1 = composePollBinding.option1.text.getText().toString().trim(); + String choice2 = composePollBinding.option2.text.getText().toString().trim(); + + if (choice1.isEmpty() && choice2.isEmpty()) { + Toasty.error(requireActivity(), getString(R.string.poll_invalid_choices), Toasty.LENGTH_SHORT).show(); + } else if (statusCompose != null) { + statusCompose.poll = new Poll(); + statusCompose.poll.multiple = selected_poll_type_id == R.id.poll_type_multiple; + int expire; + switch (poll_duration_pos) { + case 0: + expire = 300; + break; + case 1: + expire = 1800; + break; + case 2: + expire = 3600; + break; + case 3: + expire = 21600; + break; + case 4: + expire = 86400; + break; + case 5: + expire = 259200; + break; + case 6: + expire = 604800; + break; + default: + expire = 864000; + } + statusCompose.poll.expire_in = expire; + List pollItems = new ArrayList<>(); + int childCount = composePollBinding.optionsList.getChildCount(); + for (int i = 0; i < childCount; i++) { + Poll.PollItem pollItem = new Poll.PollItem(); + AppCompatEditText title = (composePollBinding.optionsList.getChildAt(i)).findViewById(R.id.text); + pollItem.title = title.getText().toString(); + pollItems.add(pollItem); + } + List options = new ArrayList<>(); + boolean doubleTitle = false; + for (Poll.PollItem po : pollItems) { + if (!options.contains(po.title.trim())) { + options.add(po.title.trim()); + } else { + doubleTitle = true; + } + } + if (!doubleTitle) { + statusCompose.poll.options = pollItems; + dialog.dismiss(); + } else { + Toasty.error(requireActivity(), getString(R.string.poll_duplicated_entry), Toasty.LENGTH_SHORT).show(); + } + } + binding.buttonPoll.setVisibility(View.VISIBLE); + buttonState(); + }); + }); + + alertPollDiaslog.show(); + } + + + private void initiliazeStatus() { + statusCompose = new Status(); + binding.text.setText(""); + binding.attachmentsListContainer.removeAllViews(); if (statuses != null && statuses.size() > 0) { + binding.recyclerView.scrollToPosition(statuses.size() - 1); Status lastStatus = statuses.get(statuses.size() - 1); - status.in_reply_to_id = lastStatus.id; - status.visibility = "direct"; - status.mentions = new ArrayList<>(); + statusCompose.in_reply_to_id = lastStatus.id; + statusCompose.visibility = "direct"; + statusCompose.mentions = new ArrayList<>(); if (lastStatus.account.acct != null && currentAccount.mastodon_account != null && !lastStatus.account.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) { Mention mention = new Mention(); mention.acct = "@" + lastStatus.account.acct; mention.url = lastStatus.account.url; mention.username = lastStatus.account.username; - status.mentions.add(mention); + statusCompose.mentions.add(mention); } //There are other mentions to if (lastStatus.mentions != null && lastStatus.mentions.size() > 0) { for (Mention mentionTmp : lastStatus.mentions) { if (currentAccount.mastodon_account != null && !mentionTmp.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) { - status.mentions.add(mentionTmp); + statusCompose.mentions.add(mentionTmp); } } } } - return status; + manageMentions(statusCompose); } /** @@ -353,7 +600,6 @@ public class FragmentMastodonDirectMessage extends Fragment { } } binding.text.setText(statusCompose.text); - statusCompose.cursorPosition = statusCompose.text.length(); if (statusCompose.mentions.size() > 1) { if (!mentionsAtTop) { statusCompose.text += "\n"; @@ -366,7 +612,7 @@ public class FragmentMastodonDirectMessage extends Fragment { binding.text.setText(statusCompose.text); binding.text.requestFocus(); binding.text.post(() -> { - binding.text.setSelection(statusCompose.cursorPosition); //Put cursor at the end + binding.text.setSelection(statusCompose.text.length()); //Put cursor at the end }); } else { binding.text.requestFocus(); @@ -685,10 +931,9 @@ public class FragmentMastodonDirectMessage extends Fragment { statuses.addAll(0, context.ancestors); statusDirectMessageAdapter.notifyItemRangeInserted(0, statusPosition); statuses.addAll(statusPosition + 1, context.descendants); - initiliazeStatus(); statusDirectMessageAdapter.notifyItemRangeInserted(statusPosition + 1, context.descendants.size()); binding.swipeContainer.setRefreshing(false); - binding.recyclerView.scrollToPosition(statusPosition); + initiliazeStatus(); } public interface FirstMessage { diff --git a/app/src/main/res/drawables/mastodon/drawable/bubble_left_tail.xml b/app/src/main/res/drawables/mastodon/drawable/bubble_left_tail.xml index 7f93abfd1..3cec78039 100644 --- a/app/src/main/res/drawables/mastodon/drawable/bubble_left_tail.xml +++ b/app/src/main/res/drawables/mastodon/drawable/bubble_left_tail.xml @@ -6,13 +6,13 @@ android:pivotY="100%" android:toDegrees="0"> - + - + diff --git a/app/src/main/res/drawables/mastodon/drawable/bubble_right_tail.xml b/app/src/main/res/drawables/mastodon/drawable/bubble_right_tail.xml index fa68f846a..b87980d6e 100644 --- a/app/src/main/res/drawables/mastodon/drawable/bubble_right_tail.xml +++ b/app/src/main/res/drawables/mastodon/drawable/bubble_right_tail.xml @@ -6,13 +6,13 @@ android:pivotY="100%" android:toDegrees="0"> - + - + diff --git a/app/src/main/res/layouts/mastodon/layout/activity_direct_message.xml b/app/src/main/res/layouts/mastodon/layout/activity_direct_message.xml index e6638f085..bf6a59338 100644 --- a/app/src/main/res/layouts/mastodon/layout/activity_direct_message.xml +++ b/app/src/main/res/layouts/mastodon/layout/activity_direct_message.xml @@ -14,49 +14,40 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:orientation="vertical"> - + android:layout_height="?attr/actionBarSize" + android:fitsSystemWindows="true"> - + - + + - - - - - - + - - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/layouts/mastodon/layout/drawer_status_chat.xml b/app/src/main/res/layouts/mastodon/layout/drawer_status_chat.xml index f0cfe6726..072a345fc 100644 --- a/app/src/main/res/layouts/mastodon/layout/drawer_status_chat.xml +++ b/app/src/main/res/layouts/mastodon/layout/drawer_status_chat.xml @@ -64,7 +64,18 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@id/message_content"> + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 7821d5dde..89f739b8c 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -206,4 +206,8 @@ #BBD144 #46483B #000000 + + + #E0E0E0 +