package app.fedilab.android.helper; /* Copyright 2021 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 . */ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.text.Html; import android.text.SpannableString; 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.CustomTarget; import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.transition.Transition; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import app.fedilab.android.R; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.API; import app.fedilab.android.client.APIResponse; import app.fedilab.android.client.Entities.Account; import app.fedilab.android.client.Entities.Notification; import app.fedilab.android.client.GNUAPI; import app.fedilab.android.fragments.DisplayNotificationsFragment; import static android.text.Html.FROM_HTML_MODE_LEGACY; import static app.fedilab.android.helper.BaseHelper.INTENT_ACTION; import static app.fedilab.android.helper.BaseHelper.INTENT_TARGETED_ACCOUNT; import static app.fedilab.android.helper.BaseHelper.NOTIFICATION_INTENT; import static app.fedilab.android.helper.BaseHelper.PREF_INSTANCE; import static app.fedilab.android.helper.BaseHelper.PREF_KEY_ID; import static app.fedilab.android.helper.BaseHelper.getMainLogo; import static app.fedilab.android.helper.BaseHelper.notify_user; public class NotificationsHelper { public static HashMap since_ids = new HashMap<>(); public static void task(Context context, Account account) { APIResponse apiResponse; String key = account.getUsername() + "@" + account.getInstance(); String last_notifid = null; if (since_ids.containsKey(key)) { last_notifid = since_ids.get(key); } final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); //Check which notifications the user wants to see boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true); boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true); boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); boolean notif_poll = sharedpreferences.getBoolean(Helper.SET_NOTIF_POLL, true); //User disagree with all notifications if (!notif_follow && !notif_add && !notif_mention && !notif_share && !notif_poll) return; //Nothing is done //No account connected, the service is stopped if (!Helper.isLoggedIn(context)) return; //If WIFI only and on WIFI OR user defined any connections to use the service. if (!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(context)) { if (account.getSocial().compareTo("FRIENDICA") != 0 && account.getSocial().compareTo("GNU") != 0) { API api = new API(context, account.getInstance(), account.getToken()); apiResponse = api.getNotificationsSince(DisplayNotificationsFragment.Type.ALL, last_notifid, false); } else { GNUAPI gnuApi = new GNUAPI(context, account.getInstance(), account.getToken()); apiResponse = gnuApi.getNotificationsSince(DisplayNotificationsFragment.Type.ALL, last_notifid); } onRetrieveNotifications(context, apiResponse, account); } } public static void onRetrieveNotifications(Context context, APIResponse apiResponse, final Account account) { List notificationsReceived = apiResponse.getNotifications(); if (apiResponse.getError() != null || notificationsReceived == null || notificationsReceived.size() == 0 || account == null) return; String key = account.getUsername() + "@" + account.getInstance(); since_ids.put(key, apiResponse.getNotifications().get(0).getId()); final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true); boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true); boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); boolean notif_poll = sharedpreferences.getBoolean(Helper.SET_NOTIF_POLL, true); boolean notif_status = sharedpreferences.getBoolean(Helper.SET_NOTIF_STATUS, true); final String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null); final List notifications = new ArrayList<>(); int pos = 0; for (Notification notif : notificationsReceived) { if (max_id == null || notif.getId().compareTo(max_id) > 0) { notifications.add(pos, notif); pos++; } } if (notifications.size() == 0) return; //No previous notifications in cache, so no notification will be sent int newFollows = 0; int newAdds = 0; int newMentions = 0; int newShare = 0; int newPolls = 0; int newStatus = 0; String notificationUrl = null; String title = null; String message = null; String targeted_account = null; Helper.NotifType notifType = Helper.NotifType.MENTION; String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); for (Notification notification : notifications) { switch (notification.getType()) { case "mention": notifType = Helper.NotifType.MENTION; if (notif_mention) { if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0) message = String.format("%s %s", notification.getAccount().getDisplay_name(), context.getString(R.string.notif_mention)); else message = String.format("@%s %s", notification.getAccount().getAcct(), context.getString(R.string.notif_mention)); if (notification.getStatus() != null) { if (notification.getStatus().getSpoiler_text() != null && notification.getStatus().getSpoiler_text().length() > 0) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getSpoiler_text(), FROM_HTML_MODE_LEGACY)); else message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getSpoiler_text())); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getContent(), FROM_HTML_MODE_LEGACY)); else message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getContent())); } } newFollows++; } break; case "status": notifType = Helper.NotifType.STATUS; if (notif_status) { if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0) message = String.format("%s %s", notification.getAccount().getDisplay_name(), context.getString(R.string.notif_status)); else message = String.format("@%s %s", notification.getAccount().getAcct(), context.getString(R.string.notif_status)); if (notification.getStatus() != null) { if (notification.getStatus().getSpoiler_text() != null && notification.getStatus().getSpoiler_text().length() > 0) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getSpoiler_text(), FROM_HTML_MODE_LEGACY)); else message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getSpoiler_text())); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getContent(), FROM_HTML_MODE_LEGACY)); else message = "\n" + new SpannableString(Html.fromHtml(notification.getStatus().getContent())); } } newStatus++; } break; case "reblog": notifType = Helper.NotifType.BOOST; if (notif_share) { if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0) message = String.format("%s %s", notification.getAccount().getDisplay_name(), context.getString(R.string.notif_reblog)); else message = String.format("@%s %s", notification.getAccount().getAcct(), context.getString(R.string.notif_reblog)); newShare++; } break; case "favourite": notifType = Helper.NotifType.FAV; if (notif_add) { if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0) message = String.format("%s %s", notification.getAccount().getDisplay_name(), context.getString(R.string.notif_favourite)); else message = String.format("@%s %s", notification.getAccount().getAcct(), context.getString(R.string.notif_favourite)); newAdds++; } break; case "follow_request": notifType = Helper.NotifType.FOLLLOW; if (notif_follow) { if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0) message = String.format("%s %s", notification.getAccount().getDisplay_name(), context.getString(R.string.notif_follow_request)); else message = String.format("@%s %s", notification.getAccount().getAcct(), context.getString(R.string.notif_follow_request)); targeted_account = notification.getAccount().getId(); newFollows++; } break; case "follow": notifType = Helper.NotifType.FOLLLOW; if (notif_follow) { if (notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0) message = String.format("%s %s", notification.getAccount().getDisplay_name(), context.getString(R.string.notif_follow)); else message = String.format("@%s %s", notification.getAccount().getAcct(), context.getString(R.string.notif_follow)); targeted_account = notification.getAccount().getId(); newFollows++; } break; case "poll": notifType = Helper.NotifType.POLL; if (notif_poll) { if (notification.getAccount().getId() != null && notification.getAccount().getId().equals(userId)) message = context.getString(R.string.notif_poll_self); else message = context.getString(R.string.notif_poll); newPolls++; } break; default: } } int allNotifCount = newFollows + newAdds + newMentions + newShare + newPolls + newStatus; if (allNotifCount > 0) { //Some others notification final Intent intent = new Intent(context, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(INTENT_ACTION, NOTIFICATION_INTENT); intent.putExtra(PREF_KEY_ID, account.getId()); if (targeted_account != null && notifType == Helper.NotifType.FOLLLOW) intent.putExtra(INTENT_TARGETED_ACCOUNT, targeted_account); intent.putExtra(PREF_INSTANCE, account.getInstance()); notificationUrl = notifications.get(0).getAccount().getAvatar(); if (notificationUrl != null) { Handler mainHandler = new Handler(Looper.getMainLooper()); final String finalNotificationUrl = notificationUrl; Helper.NotifType finalNotifType = notifType; String finalMessage = message; String finalMessage1 = message; Runnable myRunnable = () -> Glide.with(context) .asBitmap() .load(finalNotificationUrl) .listener(new RequestListener() { @Override public boolean onResourceReady(Bitmap resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; } @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { notify_user(context, account, intent, BitmapFactory.decodeResource(context.getResources(), getMainLogo(context)), finalNotifType, context.getString(R.string.top_notification), finalMessage1); String lastNotif = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null); if (lastNotif == null || notifications.get(0).getId().compareTo(lastNotif) > 0) { SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), notifications.get(0).getId()); editor.apply(); } return false; } }) .into(new CustomTarget() { @Override public void onResourceReady(@NonNull Bitmap resource, Transition transition) { notify_user(context, account, intent, resource, finalNotifType, context.getString(R.string.top_notification), finalMessage); String lastNotif = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null); if (lastNotif == null || notifications.get(0).getId().compareTo(lastNotif) > 0) { SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), notifications.get(0).getId()); editor.apply(); } } @Override public void onLoadCleared(@Nullable Drawable placeholder) { } }); mainHandler.post(myRunnable); } } } }