365 lines
18 KiB
Java
365 lines
18 KiB
Java
/* Copyright 2017 Thomas Schneider
|
|
*
|
|
* This file is a part of Fedilab
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
* Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
|
* see <http://www.gnu.org/licenses>. */
|
|
package app.fedilab.android.client.Entities;
|
|
|
|
|
|
import android.app.Activity;
|
|
import android.content.Context;
|
|
import android.content.SharedPreferences;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.text.Spannable;
|
|
import android.text.SpannableString;
|
|
import android.text.style.ImageSpan;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.bumptech.glide.Glide;
|
|
import com.bumptech.glide.load.DataSource;
|
|
import com.bumptech.glide.load.engine.GlideException;
|
|
import com.bumptech.glide.request.RequestListener;
|
|
import com.bumptech.glide.request.target.SimpleTarget;
|
|
import com.bumptech.glide.request.target.Target;
|
|
import com.bumptech.glide.request.transition.Transition;
|
|
import com.github.penfeizhou.animation.apng.APNGDrawable;
|
|
import com.github.penfeizhou.animation.apng.decode.APNGParser;
|
|
import com.github.penfeizhou.animation.gif.GifDrawable;
|
|
import com.github.penfeizhou.animation.gif.decode.GifParser;
|
|
|
|
import java.io.File;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
|
|
import app.fedilab.android.R;
|
|
import app.fedilab.android.helper.Helper;
|
|
import app.fedilab.android.interfaces.OnRetrieveEmojiInterface;
|
|
|
|
import static app.fedilab.android.helper.Helper.drawableToBitmap;
|
|
|
|
/**
|
|
* Created by Thomas on 23/04/2017.
|
|
*/
|
|
|
|
public class Notification implements Parcelable {
|
|
|
|
public static final Creator<Notification> CREATOR = new Creator<Notification>() {
|
|
@Override
|
|
public Notification createFromParcel(Parcel in) {
|
|
return new Notification(in);
|
|
}
|
|
|
|
@Override
|
|
public Notification[] newArray(int size) {
|
|
return new Notification[size];
|
|
}
|
|
};
|
|
private String id;
|
|
private String type;
|
|
private Date created_at;
|
|
private Account account;
|
|
private Status status;
|
|
private boolean notificationAnimated = false;
|
|
private boolean isEmojiFound = false;
|
|
|
|
protected Notification(Parcel in) {
|
|
id = in.readString();
|
|
type = in.readString();
|
|
account = in.readParcelable(Account.class.getClassLoader());
|
|
status = in.readParcelable(Status.class.getClassLoader());
|
|
}
|
|
|
|
public Notification() {
|
|
}
|
|
|
|
public static void makeEmojis(final Context context, final OnRetrieveEmojiInterface listener, Notification notification) {
|
|
|
|
if (((Activity) context).isFinishing())
|
|
return;
|
|
Status status = notification.getStatus();
|
|
|
|
java.util.List<Emojis> emojis = null;
|
|
if (status != null) {
|
|
emojis = status.getEmojis();
|
|
}
|
|
List<Emojis> emojisAccounts = notification.getAccount().getEmojis();
|
|
|
|
String typeString = "";
|
|
switch (notification.getType()) {
|
|
case "mention":
|
|
if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0)
|
|
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true), context.getString(R.string.notif_mention));
|
|
else
|
|
typeString = String.format("@%s %s", notification.getAccount().getUsername(), context.getString(R.string.notif_mention));
|
|
break;
|
|
case "poll":
|
|
typeString = context.getString(R.string.notif_poll);
|
|
break;
|
|
case "reblog":
|
|
if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0)
|
|
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true), context.getString(R.string.notif_reblog));
|
|
else
|
|
typeString = String.format("@%s %s", notification.getAccount().getUsername(), context.getString(R.string.notif_reblog));
|
|
break;
|
|
case "favourite":
|
|
if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0)
|
|
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true), context.getString(R.string.notif_favourite));
|
|
else
|
|
typeString = String.format("@%s %s", notification.getAccount().getUsername(), context.getString(R.string.notif_favourite));
|
|
break;
|
|
case "follow":
|
|
if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0)
|
|
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true), context.getString(R.string.notif_follow));
|
|
else
|
|
typeString = String.format("@%s %s", notification.getAccount().getUsername(), context.getString(R.string.notif_follow));
|
|
break;
|
|
case "follow_request":
|
|
if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0)
|
|
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true), context.getString(R.string.notif_follow_request));
|
|
else
|
|
typeString = String.format("@%s %s", notification.getAccount().getUsername(), context.getString(R.string.notif_follow_request));
|
|
break;
|
|
}
|
|
SpannableString displayNameSpan = new SpannableString(typeString);
|
|
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
|
boolean disableAnimatedEmoji = sharedpreferences.getBoolean(Helper.SET_DISABLE_ANIMATED_EMOJI, false);
|
|
|
|
if (emojisAccounts != null && emojisAccounts.size() > 0) {
|
|
final int[] j = {0};
|
|
for (final Emojis emoji : emojisAccounts) {
|
|
Glide.with(context)
|
|
.asDrawable()
|
|
.load(emoji.getUrl())
|
|
.listener(new RequestListener<Drawable>() {
|
|
@Override
|
|
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
|
|
j[0]++;
|
|
if (j[0] == (emojisAccounts.size())) {
|
|
listener.onRetrieveEmoji(notification);
|
|
}
|
|
return false;
|
|
}
|
|
})
|
|
.into(new SimpleTarget<Drawable>() {
|
|
@Override
|
|
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
|
|
final String targetedEmoji = ":" + emoji.getShortcode() + ":";
|
|
if (displayNameSpan.toString().contains(targetedEmoji)) {
|
|
//emojis can be used several times so we have to loop
|
|
for (int startPosition = -1; (startPosition = displayNameSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
|
|
final int endPosition = startPosition + targetedEmoji.length();
|
|
if (endPosition <= displayNameSpan.toString().length() && endPosition >= startPosition) {
|
|
resource.setBounds(0, 0, (int) Helper.convertDpToPixel(20, context), (int) Helper.convertDpToPixel(20, context));
|
|
resource.setVisible(true, true);
|
|
ImageSpan imageSpan = new ImageSpan(resource);
|
|
displayNameSpan.setSpan(
|
|
imageSpan, startPosition,
|
|
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
}
|
|
}
|
|
}
|
|
j[0]++;
|
|
if (j[0] == (emojisAccounts.size())) {
|
|
notification.getAccount().setdisplayNameSpan(displayNameSpan);
|
|
listener.onRetrieveEmoji(notification);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (status != null && emojis != null && emojis.size() > 0) {
|
|
SpannableString contentSpan = status.getContentSpan();
|
|
SpannableString contentSpanCW = status.getContentSpanCW();
|
|
final int[] i = {0};
|
|
for (final Emojis emoji : emojis) {
|
|
List<Emojis> finalEmojis = emojis;
|
|
Glide.with(context)
|
|
.asFile()
|
|
.load(emoji.getUrl())
|
|
.listener(new RequestListener<File>() {
|
|
@Override
|
|
public boolean onResourceReady(File resource, Object model, Target<File> 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] == (finalEmojis.size())) {
|
|
listener.onRetrieveEmoji(status, false);
|
|
}
|
|
return false;
|
|
}
|
|
})
|
|
.into(new SimpleTarget<File>() {
|
|
@Override
|
|
public void onResourceReady(@NonNull File resourceFile, @Nullable Transition<? super File> 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 (contentSpan != null && contentSpan.toString().contains(targetedEmoji)) {
|
|
//emojis can be used several times so we have to loop
|
|
for (int startPosition = -1; (startPosition = contentSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
|
|
final int endPosition = startPosition + targetedEmoji.length();
|
|
if (endPosition <= contentSpan.toString().length() && endPosition >= startPosition) {
|
|
try {
|
|
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);
|
|
imageSpan = new ImageSpan(context,
|
|
Bitmap.createScaledBitmap(bitmap, (int) Helper.convertDpToPixel(20, context),
|
|
(int) Helper.convertDpToPixel(20, context), false));
|
|
}
|
|
contentSpan.setSpan(
|
|
imageSpan, startPosition,
|
|
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
} catch (Exception ignored) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (contentSpanCW != null && contentSpanCW.toString().contains(targetedEmoji)) {
|
|
//emojis can be used several times so we have to loop
|
|
for (int startPosition = -1; (startPosition = contentSpanCW.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
|
|
final int endPosition = startPosition + targetedEmoji.length();
|
|
if (endPosition <= contentSpanCW.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 {
|
|
resource.setVisible(true, true);
|
|
Bitmap bitmap = drawableToBitmap(resource);
|
|
imageSpan = new ImageSpan(context,
|
|
Bitmap.createScaledBitmap(bitmap, (int) Helper.convertDpToPixel(20, context),
|
|
(int) Helper.convertDpToPixel(20, context), false));
|
|
}
|
|
contentSpanCW.setSpan(
|
|
imageSpan, startPosition,
|
|
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
}
|
|
}
|
|
}
|
|
i[0]++;
|
|
if (i[0] == (finalEmojis.size())) {
|
|
status.setContentSpan(contentSpan);
|
|
status.setContentSpanCW(contentSpanCW);
|
|
status.setEmojiFound(true);
|
|
listener.onRetrieveEmoji(notification);
|
|
}
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public String getId() {
|
|
return id;
|
|
}
|
|
|
|
public void setId(String id) {
|
|
this.id = id;
|
|
}
|
|
|
|
public String getType() {
|
|
return type;
|
|
}
|
|
|
|
public void setType(String type) {
|
|
this.type = type;
|
|
}
|
|
|
|
public Date getCreated_at() {
|
|
return created_at;
|
|
}
|
|
|
|
public void setCreated_at(Date created_at) {
|
|
this.created_at = created_at;
|
|
}
|
|
|
|
public Account getAccount() {
|
|
return account;
|
|
}
|
|
|
|
public void setAccount(Account account) {
|
|
this.account = account;
|
|
}
|
|
|
|
public Status getStatus() {
|
|
return status;
|
|
}
|
|
|
|
public void setStatus(Status status) {
|
|
this.status = status;
|
|
}
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel(Parcel dest, int flags) {
|
|
dest.writeString(id);
|
|
dest.writeString(type);
|
|
dest.writeParcelable(account, flags);
|
|
dest.writeParcelable(status, flags);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object otherNotifications) {
|
|
return otherNotifications != null && (otherNotifications == this || otherNotifications instanceof Notification && this.getId().equals(((Notification) otherNotifications).getId()));
|
|
}
|
|
|
|
public boolean isNotificationAnimated() {
|
|
return notificationAnimated;
|
|
}
|
|
|
|
public void setNotificationAnimated(boolean notificationAnimated) {
|
|
this.notificationAnimated = notificationAnimated;
|
|
}
|
|
|
|
public boolean isEmojiFound() {
|
|
return isEmojiFound;
|
|
}
|
|
|
|
public void setEmojiFound(boolean emojiFound) {
|
|
isEmojiFound = emojiFound;
|
|
}
|
|
}
|