diff --git a/app/build.gradle b/app/build.gradle index 8adbdf5a9..450b2ca2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -100,7 +100,7 @@ dependencies { implementation 'com.github.mabbas007:TagsEditText:1.0.5' implementation 'com.jaredrummler:material-spinner:1.3.1' implementation "com.tonyodev.fetch2:fetch2:2.3.6" - implementation 'com.github.stom79:horizontalbargraph:1.5' + implementation 'com.github.stom79:horizontalbargraph:1.6' implementation 'jp.wasabeef:glide-transformations:4.0.0' playstoreImplementation "io.github.kobakei:ratethisapp:$ratethisappLibraryVersion" implementation 'ja.burhanrashid52:photoeditor:0.4.0' diff --git a/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java index 5906a4214..398584f6f 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java @@ -59,7 +59,6 @@ import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; -import android.util.Log; import android.util.Patterns; import android.view.LayoutInflater; import android.view.Menu; diff --git a/app/src/main/java/app/fedilab/android/client/Entities/PollOptions.java b/app/src/main/java/app/fedilab/android/client/Entities/PollOptions.java index 0b7498459..d7ce151e8 100644 --- a/app/src/main/java/app/fedilab/android/client/Entities/PollOptions.java +++ b/app/src/main/java/app/fedilab/android/client/Entities/PollOptions.java @@ -16,6 +16,8 @@ package app.fedilab.android.client.Entities; import android.os.Parcel; import android.os.Parcelable; +import android.text.SpannableString; +import android.text.TextUtils; public class PollOptions implements Parcelable { @@ -36,6 +38,7 @@ public class PollOptions implements Parcelable { } private String title; + private SpannableString titleSpan; private int votes_count; @@ -48,6 +51,7 @@ public class PollOptions implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.title); dest.writeInt(this.votes_count); + TextUtils.writeToParcel(this.titleSpan, dest, flags); } public PollOptions() { @@ -56,6 +60,7 @@ public class PollOptions implements Parcelable { protected PollOptions(Parcel in) { this.title = in.readString(); this.votes_count = in.readInt(); + this.titleSpan = (SpannableString) TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); } public static final Creator CREATOR = new Creator() { @@ -69,4 +74,12 @@ public class PollOptions implements Parcelable { return new PollOptions[size]; } }; + + public SpannableString getTitleSpan() { + return titleSpan; + } + + public void setTitleSpan(SpannableString titleSpan) { + this.titleSpan = titleSpan; + } } diff --git a/app/src/main/java/app/fedilab/android/client/Entities/Status.java b/app/src/main/java/app/fedilab/android/client/Entities/Status.java index 40e1446e7..83427bb66 100644 --- a/app/src/main/java/app/fedilab/android/client/Entities/Status.java +++ b/app/src/main/java/app/fedilab/android/client/Entities/Status.java @@ -132,6 +132,7 @@ public class Status implements Parcelable { private String language; private boolean isTranslated = false; private boolean isEmojiFound = false; + private boolean isPollEmojiFound = false; private boolean isImageFound = false; private boolean isEmojiTranslateFound = false; private boolean isClickable = false; @@ -1343,6 +1344,105 @@ public class Status implements Parcelable { } + public static void makeEmojiPoll(final Context context, final OnRetrieveEmojiInterface listener, Status status){ + if (((Activity) context).isFinishing()) + return; + if (status.getReblog() != null && status.getReblog().getEmojis() == null) { + status.setPollEmojiFound(true); + return; + } + if (status.getReblog() == null && status.getEmojis() == null) { + status.setPollEmojiFound(true); + return; + } + final List emojis = status.getReblog() != null ? status.getReblog().getEmojis() : status.getEmojis(); + + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean disableAnimatedEmoji = sharedpreferences.getBoolean(Helper.SET_DISABLE_ANIMATED_EMOJI, false); + Poll poll = status.getReblog()==null?status.getPoll():status.getReblog().getPoll(); + if (poll == null) { + status.setPollEmojiFound(true); + return; + } + int inc = 0; + for(PollOptions pollOption : poll.getOptionsList()){ + inc++; + SpannableString titleSpan = new SpannableString(pollOption.getTitle()); + if (emojis != null && emojis.size() > 0) { + final int[] i = {0}; + for (final Emojis emoji : emojis) { + int finalInc = inc; + Glide.with(context) + .asFile() + .load(emoji.getUrl()) + .listener(new RequestListener() { + @Override + public boolean onResourceReady(File resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + return false; + } + + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + i[0]++; + if (i[0] == (emojis.size())) { + listener.onRetrieveEmoji(status, false); + } + return false; + } + }) + .into(new SimpleTarget() { + @Override + public void onResourceReady(@NonNull File resourceFile, @Nullable Transition transition) { + Drawable resource; + if (GifParser.isGif(resourceFile.getAbsolutePath())) { + resource = GifDrawable.fromFile(resourceFile.getAbsolutePath()); + } else if (APNGParser.isAPNG(resourceFile.getAbsolutePath())) { + resource = APNGDrawable.fromFile(resourceFile.getAbsolutePath()); + } else { + resource = Drawable.createFromPath(resourceFile.getAbsolutePath()); + } + if (resource == null) { + return; + } + final String targetedEmoji = ":" + emoji.getShortcode() + ":"; + if ( titleSpan.toString().contains(targetedEmoji)) { + //emojis can be used several times so we have to loop + for (int startPosition = -1; (startPosition = titleSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) { + final int endPosition = startPosition + targetedEmoji.length(); + if (endPosition <= titleSpan.toString().length() && endPosition >= startPosition) { + ImageSpan imageSpan; + if (!disableAnimatedEmoji) { + resource.setBounds(0, 0, (int) Helper.convertDpToPixel(20, context), (int) Helper.convertDpToPixel(20, context)); + resource.setVisible(true, true); + imageSpan = new ImageSpan(resource); + + } else { + Bitmap bitmap = drawableToBitmap(resource.getCurrent()); + imageSpan = new ImageSpan(context, + Bitmap.createScaledBitmap(bitmap, (int) Helper.convertDpToPixel(20, context), + (int) Helper.convertDpToPixel(20, context), false)); + } + titleSpan.setSpan( + imageSpan, startPosition, + endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + pollOption.setTitleSpan(titleSpan); + } + } + } + i[0]++; + + if (i[0] == (emojis.size()) && finalInc == poll.getOptionsList().size()) { + status.setPollEmojiFound(true); + listener.onRetrieveEmoji(status, false); + } + } + }); + + } + } + } + } + public static void makeImage(final Context context, final OnRetrieveImageInterface listener, Status status) { if (((Activity) context).isFinishing()) @@ -1851,4 +1951,12 @@ public class Status implements Parcelable { public void setShowTopLine(boolean showTopLine) { this.showTopLine = showTopLine; } + + public boolean isPollEmojiFound() { + return isPollEmojiFound; + } + + public void setPollEmojiFound(boolean pollEmojiFound) { + isPollEmojiFound = pollEmojiFound; + } } diff --git a/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java index 525bc7bfa..9b931f58b 100644 --- a/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java +++ b/app/src/main/java/app/fedilab/android/drawers/StatusListAdapter.java @@ -343,6 +343,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct } else { status.setPoll(poll); } + Status.makeEmojiPoll(context, this, status); notifyStatusChanged(status); } @@ -1045,6 +1046,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct double value = ((double) (pollOption.getVotes_count() * 100) / (double) poll.getVotes_count()); if (pollOption.getVotes_count() == greaterValue) { BarItem bar = new BarItem(pollOption.getTitle(), value, "%", ContextCompat.getColor(context, R.color.mastodonC4), Color.WHITE); + bar.setDescriptionSpan(pollOption.getTitleSpan()); bar.setRounded(true); bar.setHeight1(30); items.add(bar); @@ -1054,6 +1056,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct bar = new BarItem(pollOption.getTitle(), value, "%", ContextCompat.getColor(context, R.color.mastodonC2), Color.BLACK); else bar = new BarItem(pollOption.getTitle(), value, "%", ContextCompat.getColor(context, R.color.mastodonC2), Color.WHITE); + bar.setDescriptionSpan(pollOption.getTitleSpan()); bar.setRounded(true); bar.setHeight1(30); items.add(bar); @@ -1070,7 +1073,12 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct (holder.multiple_choice).removeAllViews(); for (PollOptions pollOption : poll.getOptionsList()) { CheckBox cb = new CheckBox(context); - cb.setText(pollOption.getTitle()); + if( pollOption.getTitleSpan() != null){ + cb.setText(pollOption.getTitleSpan(), TextView.BufferType.SPANNABLE); + }else { + cb.setText(pollOption.getTitle()); + } + holder.multiple_choice.addView(cb); } holder.multiple_choice.setVisibility(View.VISIBLE); @@ -1080,7 +1088,11 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct (holder.radio_group).removeAllViews(); for (PollOptions pollOption : poll.getOptionsList()) { RadioButton rb = new RadioButton(context); - rb.setText(pollOption.getTitle()); + if( pollOption.getTitleSpan() != null){ + rb.setText(pollOption.getTitleSpan(), TextView.BufferType.SPANNABLE); + }else { + rb.setText(pollOption.getTitle()); + } holder.radio_group.addView(rb); } holder.single_choice.setVisibility(View.VISIBLE); @@ -1611,6 +1623,11 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct status.setEmojiFound(true); Status.makeEmojis(context, this, status); } + Poll poll = (status.getReblog() == null)?status.getPoll():status.getReblog().getPoll(); + if (poll != null && !status.isPollEmojiFound()) { + status.setPollEmojiFound(true); + Status.makeEmojiPoll(context, this, status); + } if (!status.isImageFound()) { status.setImageFound(true); Status.makeImage(context, this, status);