2020-07-22 21:32:42 +02:00
|
|
|
package org.mian.gitnex.notifications;
|
|
|
|
|
2020-11-03 20:14:24 +01:00
|
|
|
import android.app.Notification;
|
2020-07-22 21:32:42 +02:00
|
|
|
import android.app.PendingIntent;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.graphics.Color;
|
|
|
|
import android.media.RingtoneManager;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.core.app.NotificationCompat;
|
2020-11-03 20:14:24 +01:00
|
|
|
import androidx.core.app.NotificationManagerCompat;
|
2020-07-22 21:32:42 +02:00
|
|
|
import androidx.work.Worker;
|
|
|
|
import androidx.work.WorkerParameters;
|
2022-04-18 09:10:54 +02:00
|
|
|
import org.gitnex.tea4j.v2.models.NotificationThread;
|
2020-07-22 21:32:42 +02:00
|
|
|
import org.mian.gitnex.R;
|
|
|
|
import org.mian.gitnex.activities.MainActivity;
|
|
|
|
import org.mian.gitnex.clients.RetrofitClient;
|
2021-04-13 20:56:50 +02:00
|
|
|
import org.mian.gitnex.database.api.BaseApi;
|
|
|
|
import org.mian.gitnex.database.api.UserAccountsApi;
|
|
|
|
import org.mian.gitnex.database.models.UserAccount;
|
2020-07-22 21:32:42 +02:00
|
|
|
import org.mian.gitnex.helpers.AppUtil;
|
2021-03-21 16:56:54 +01:00
|
|
|
import org.mian.gitnex.helpers.Constants;
|
2020-07-22 21:32:42 +02:00
|
|
|
import org.mian.gitnex.helpers.TinyDB;
|
2021-04-13 20:56:50 +02:00
|
|
|
import org.mian.gitnex.helpers.Version;
|
2020-07-22 21:32:42 +02:00
|
|
|
import java.util.Date;
|
2021-04-13 20:56:50 +02:00
|
|
|
import java.util.HashMap;
|
2020-07-22 21:32:42 +02:00
|
|
|
import java.util.List;
|
2021-04-13 20:56:50 +02:00
|
|
|
import java.util.Map;
|
2020-07-22 21:32:42 +02:00
|
|
|
import retrofit2.Call;
|
|
|
|
import retrofit2.Response;
|
|
|
|
|
|
|
|
/**
|
2022-04-30 18:55:20 +02:00
|
|
|
* @author opyale
|
2020-07-22 21:32:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
public class NotificationsWorker extends Worker {
|
|
|
|
|
2021-02-13 20:31:38 +01:00
|
|
|
private final Context context;
|
|
|
|
private final TinyDB tinyDB;
|
2021-04-13 20:56:50 +02:00
|
|
|
private final Map<UserAccount, Map<String, String>> userAccounts;
|
2020-07-22 21:32:42 +02:00
|
|
|
|
|
|
|
public NotificationsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
|
|
|
|
|
|
super(context, workerParams);
|
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
UserAccountsApi userAccountsApi = BaseApi.getInstance(context, UserAccountsApi.class);
|
|
|
|
|
2020-07-22 21:32:42 +02:00
|
|
|
this.context = context;
|
2020-11-02 16:17:00 +01:00
|
|
|
this.tinyDB = TinyDB.getInstance(context);
|
2021-04-13 20:56:50 +02:00
|
|
|
this.userAccounts = new HashMap<>(userAccountsApi.getCount());
|
|
|
|
|
Don't use TinyDB as cache (#1034)
Do not use TinyDB as a cache or a way to send data between activities.
### How is this working
Instead of saving everything into the TinyDB, I created three `Context`s (a `RepositoryContext`, an `IssueContext` and an `AccountContext`). All are used to store things like API or database values/models and additional data, e.g. the `RepositoryContext` also contains information about the current filter state of a repository (issues, pull requests, releases/tags and milestones). These are sent using `Intent`s and `Bundle`s between activities and fragments. Changing a field (e.g. filter state) in any fragment changes it also for the whole repository (or at least it should do so).
Due to the size of the changes (after https://codeberg.org/gitnex/GitNex/commit/c9172f85efafd9f25739fdd8385e1904b711ea41, Git says `154 files changed, 3318 insertions(+), 3835 deletions(-)`) **I highly recommend you to create a beta/pre release before releasing a stable version**.
Additional changes:
* after logging out, the account remains in the account list (with a note) and you can log in again (you can't switch to this account)
* repositories and organizations are clickable on user profiles
* deleted two unused classes
Once finished, hopefully
* closes #354
* replaces #897
* fixes #947
* closes #1001
* closes #1015
* marks #876 and #578 as `Wontfix` since they are not necessary at this point
* and all the other TinyDB issues
Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1034
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2022-03-13 03:59:13 +01:00
|
|
|
for(UserAccount userAccount : userAccountsApi.loggedInUserAccounts()) {
|
2021-04-13 20:56:50 +02:00
|
|
|
|
|
|
|
// We do also accept empty values, since the server version was not saved properly in the beginning.
|
2022-08-15 16:26:02 +02:00
|
|
|
if(userAccount.getServerVersion() == null || userAccount.getServerVersion().isEmpty() || new Version(userAccount.getServerVersion()).higherOrEqual("1.12.3")) {
|
2021-04-13 20:56:50 +02:00
|
|
|
|
|
|
|
Map<String, String> userAccountParameters = new HashMap<>();
|
|
|
|
userAccountParameters.put("previousTimestamp", AppUtil.getTimestampFromDate(context, new Date()));
|
2021-03-21 16:56:54 +01:00
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
userAccounts.put(userAccount, userAccountParameters);
|
|
|
|
}
|
|
|
|
}
|
2020-07-22 21:32:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
@Override
|
|
|
|
public Result doWork() {
|
2021-04-13 20:56:50 +02:00
|
|
|
pollingLoops();
|
|
|
|
return Result.success();
|
|
|
|
}
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
/**
|
|
|
|
* Used to bypass the 15-minute limit of {@code WorkManager}.
|
|
|
|
*/
|
|
|
|
private void pollingLoops() {
|
2022-08-15 16:26:02 +02:00
|
|
|
int notificationLoops = tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay) < 15 ? Math.min(15 - tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay), 10) : 1;
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2021-03-21 16:56:54 +01:00
|
|
|
for(int i = 0; i < notificationLoops; i++) {
|
2020-07-22 21:32:42 +02:00
|
|
|
long startPollingTime = System.currentTimeMillis();
|
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
startPolling();
|
|
|
|
|
2020-07-22 21:32:42 +02:00
|
|
|
try {
|
2021-04-13 20:56:50 +02:00
|
|
|
if(notificationLoops > 1 && i < (notificationLoops - 1)) {
|
|
|
|
Thread.sleep(60000 - (System.currentTimeMillis() - startPollingTime));
|
|
|
|
}
|
2022-08-15 16:26:02 +02:00
|
|
|
}
|
|
|
|
catch(InterruptedException ignored) {
|
|
|
|
}
|
2021-04-13 20:56:50 +02:00
|
|
|
}
|
|
|
|
}
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
private void startPolling() {
|
|
|
|
for(UserAccount userAccount : userAccounts.keySet()) {
|
|
|
|
Map<String, String> userAccountParameters = userAccounts.get(userAccount);
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
try {
|
Don't use TinyDB as cache (#1034)
Do not use TinyDB as a cache or a way to send data between activities.
### How is this working
Instead of saving everything into the TinyDB, I created three `Context`s (a `RepositoryContext`, an `IssueContext` and an `AccountContext`). All are used to store things like API or database values/models and additional data, e.g. the `RepositoryContext` also contains information about the current filter state of a repository (issues, pull requests, releases/tags and milestones). These are sent using `Intent`s and `Bundle`s between activities and fragments. Changing a field (e.g. filter state) in any fragment changes it also for the whole repository (or at least it should do so).
Due to the size of the changes (after https://codeberg.org/gitnex/GitNex/commit/c9172f85efafd9f25739fdd8385e1904b711ea41, Git says `154 files changed, 3318 insertions(+), 3835 deletions(-)`) **I highly recommend you to create a beta/pre release before releasing a stable version**.
Additional changes:
* after logging out, the account remains in the account list (with a note) and you can log in again (you can't switch to this account)
* repositories and organizations are clickable on user profiles
* deleted two unused classes
Once finished, hopefully
* closes #354
* replaces #897
* fixes #947
* closes #1001
* closes #1015
* marks #876 and #578 as `Wontfix` since they are not necessary at this point
* and all the other TinyDB issues
Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1034
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2022-03-13 03:59:13 +01:00
|
|
|
assert userAccountParameters != null;
|
2022-08-15 16:26:02 +02:00
|
|
|
Call<List<NotificationThread>> call = RetrofitClient.getApiInterface(context, userAccount.getInstanceUrl(), userAccount.getToken(), null)
|
|
|
|
.notifyGetList(false, List.of("unread"), null, new Date(userAccountParameters.get("previousTimestamp")), null, null, 1);
|
2020-07-22 21:32:42 +02:00
|
|
|
|
|
|
|
Response<List<NotificationThread>> response = call.execute();
|
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
if(response.code() == 200 && response.body() != null) {
|
2020-07-22 21:32:42 +02:00
|
|
|
List<NotificationThread> notificationThreads = response.body();
|
2021-04-13 20:56:50 +02:00
|
|
|
if(!notificationThreads.isEmpty()) {
|
|
|
|
sendNotifications(userAccount, notificationThreads);
|
|
|
|
}
|
|
|
|
userAccountParameters.put("previousTimestamp", AppUtil.getTimestampFromDate(context, new Date()));
|
2020-11-03 20:14:24 +01:00
|
|
|
}
|
2022-08-15 16:26:02 +02:00
|
|
|
}
|
|
|
|
catch(Exception ignored) {
|
|
|
|
}
|
2020-07-22 21:32:42 +02:00
|
|
|
}
|
2020-11-03 20:14:24 +01:00
|
|
|
}
|
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
private void sendNotifications(@NonNull UserAccount userAccount, @NonNull List<NotificationThread> notificationThreads) {
|
2020-11-03 20:14:24 +01:00
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
PendingIntent pendingIntent = getPendingIntent(userAccount);
|
2020-11-03 20:14:24 +01:00
|
|
|
|
|
|
|
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
|
|
|
|
|
2022-08-15 16:26:02 +02:00
|
|
|
Notification summaryNotification = new NotificationCompat.Builder(context, Constants.mainNotificationChannelId).setContentTitle(context.getString(R.string.newMessages, userAccount.getUserName()))
|
|
|
|
.setContentText(String.format(context.getString(R.string.youHaveGotNewNotifications), notificationThreads.size())).setSmallIcon(R.drawable.gitnex_transparent).setGroup(userAccount.getUserName())
|
|
|
|
.setGroupSummary(true).setAutoCancel(true).setContentIntent(pendingIntent).build();
|
2020-11-03 20:14:24 +01:00
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
notificationManagerCompat.notify(userAccount.getAccountId(), summaryNotification);
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2020-11-03 20:14:24 +01:00
|
|
|
for(NotificationThread notificationThread : notificationThreads) {
|
|
|
|
|
|
|
|
String subjectUrl = notificationThread.getSubject().getUrl();
|
|
|
|
String issueId = context.getResources().getString(R.string.hash) + subjectUrl.substring(subjectUrl.lastIndexOf("/") + 1);
|
2022-08-15 16:26:02 +02:00
|
|
|
String notificationHeader = issueId + " " + notificationThread.getSubject().getTitle() + " " + String.format(context.getResources().getString(R.string.notificationExtraInfo),
|
|
|
|
notificationThread.getRepository().getFullName(), notificationThread.getSubject().getType());
|
2020-11-03 20:14:24 +01:00
|
|
|
|
2022-08-15 16:26:02 +02:00
|
|
|
NotificationCompat.Builder builder1 = getBaseNotificationBuilder().setContentTitle(notificationHeader).setGroup(userAccount.getUserName()).setContentIntent(pendingIntent);
|
2020-11-03 20:14:24 +01:00
|
|
|
|
2021-03-21 16:56:54 +01:00
|
|
|
notificationManagerCompat.notify(Notifications.uniqueNotificationId(context), builder1.build());
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2020-11-03 20:14:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private NotificationCompat.Builder getBaseNotificationBuilder() {
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2022-08-15 16:26:02 +02:00
|
|
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, Constants.mainNotificationChannelId).setSmallIcon(R.drawable.gitnex_transparent)
|
|
|
|
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)).setCategory(NotificationCompat.CATEGORY_MESSAGE).setPriority(NotificationCompat.PRIORITY_DEFAULT).setAutoCancel(true);
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2020-11-03 20:14:24 +01:00
|
|
|
if(tinyDB.getBoolean("notificationsEnableLights", true)) {
|
|
|
|
builder.setLights(tinyDB.getInt("notificationsLightColor", Color.GREEN), 1500, 1500);
|
|
|
|
}
|
2020-07-22 21:32:42 +02:00
|
|
|
|
2020-11-03 20:14:24 +01:00
|
|
|
if(tinyDB.getBoolean("notificationsEnableVibration", true)) {
|
2021-04-13 20:56:50 +02:00
|
|
|
builder.setVibrate(Constants.defaultVibrationPattern);
|
2022-08-15 16:26:02 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-11-03 20:14:24 +01:00
|
|
|
builder.setVibrate(null);
|
2020-07-22 21:32:42 +02:00
|
|
|
}
|
2020-11-03 20:14:24 +01:00
|
|
|
|
|
|
|
return builder;
|
2020-07-22 21:32:42 +02:00
|
|
|
}
|
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
private PendingIntent getPendingIntent(@NonNull UserAccount userAccount) {
|
2020-11-03 20:14:24 +01:00
|
|
|
|
|
|
|
Intent intent = new Intent(context, MainActivity.class);
|
2021-04-13 20:56:50 +02:00
|
|
|
|
2020-11-03 20:14:24 +01:00
|
|
|
intent.putExtra("launchFragment", "notifications");
|
2021-04-13 20:56:50 +02:00
|
|
|
intent.putExtra("switchAccountId", userAccount.getAccountId());
|
2020-11-03 20:14:24 +01:00
|
|
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
|
|
|
|
2021-04-13 20:56:50 +02:00
|
|
|
return PendingIntent.getActivity(context, userAccount.getAccountId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
2021-03-21 16:56:54 +01:00
|
|
|
|
2020-11-03 20:14:24 +01:00
|
|
|
}
|
2021-04-13 20:56:50 +02:00
|
|
|
|
2020-07-22 21:32:42 +02:00
|
|
|
}
|