mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-31 02:21:35 +00:00
Notifications working with the app off
This commit is contained in:
parent
26a2b7101c
commit
a4e1ddb255
@ -13,6 +13,7 @@ const Routes: React.FC = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener('navigateToPage', (event) => {
|
window.addEventListener('navigateToPage', (event) => {
|
||||||
|
console.log('navigateToPage', JSON.stringify(event));
|
||||||
const orderId = event?.detail?.order_id;
|
const orderId = event?.detail?.order_id;
|
||||||
const coordinator = event?.detail?.coordinator;
|
const coordinator = event?.detail?.coordinator;
|
||||||
if (orderId && coordinator) {
|
if (orderId && coordinator) {
|
||||||
|
@ -99,6 +99,7 @@ class Garage {
|
|||||||
const slot = this.getSlot(token);
|
const slot = this.getSlot(token);
|
||||||
if (attributes) {
|
if (attributes) {
|
||||||
if (attributes.copiedToken !== undefined) slot?.setCopiedToken(attributes.copiedToken);
|
if (attributes.copiedToken !== undefined) slot?.setCopiedToken(attributes.copiedToken);
|
||||||
|
this.save();
|
||||||
this.triggerHook('onRobotUpdate');
|
this.triggerHook('onRobotUpdate');
|
||||||
}
|
}
|
||||||
return slot;
|
return slot;
|
||||||
@ -106,6 +107,7 @@ class Garage {
|
|||||||
|
|
||||||
setCurrentSlot: (currentSlot: string) => void = (currentSlot) => {
|
setCurrentSlot: (currentSlot: string) => void = (currentSlot) => {
|
||||||
this.currentSlot = currentSlot;
|
this.currentSlot = currentSlot;
|
||||||
|
this.save();
|
||||||
this.triggerHook('onRobotUpdate');
|
this.triggerHook('onRobotUpdate');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,6 +183,7 @@ class Garage {
|
|||||||
Object.values(this.slots).forEach((slot) => {
|
Object.values(this.slots).forEach((slot) => {
|
||||||
slot.syncCoordinator(coordinator, this);
|
slot.syncCoordinator(coordinator, this);
|
||||||
});
|
});
|
||||||
|
this.save();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ const App = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
TorModule.start();
|
TorModule.start();
|
||||||
DeviceEventEmitter.addListener('navigateToPage', (payload) => {
|
DeviceEventEmitter.addListener('navigateToPage', (payload) => {
|
||||||
|
window.navigateToPage = payload;
|
||||||
injectMessage({
|
injectMessage({
|
||||||
category: 'system',
|
category: 'system',
|
||||||
type: 'navigateToPage',
|
type: 'navigateToPage',
|
||||||
@ -63,6 +64,17 @@ const App = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onLoadEnd = () => {
|
||||||
|
if (window.navigateToPage) {
|
||||||
|
injectMessage({
|
||||||
|
category: 'system',
|
||||||
|
type: 'navigateToPage',
|
||||||
|
detail: window.navigateToPage,
|
||||||
|
});
|
||||||
|
window.navigateToPage = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const init = (responseId: string) => {
|
const init = (responseId: string) => {
|
||||||
const loadCookie = async (key: string) => {
|
const loadCookie = async (key: string) => {
|
||||||
return await EncryptedStorage.getItem(key).then((value) => {
|
return await EncryptedStorage.getItem(key).then((value) => {
|
||||||
@ -207,6 +219,7 @@ const App = () => {
|
|||||||
allowsLinkPreview={false}
|
allowsLinkPreview={false}
|
||||||
renderLoading={() => <Text></Text>}
|
renderLoading={() => <Text></Text>}
|
||||||
onError={(syntheticEvent) => <Text>{syntheticEvent.type}</Text>}
|
onError={(syntheticEvent) => <Text>{syntheticEvent.type}</Text>}
|
||||||
|
onLoadEnd={() => setTimeout(onLoadEnd, 3000)}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
|
@ -300,8 +300,6 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime:2.7.1"
|
|
||||||
|
|
||||||
if (enableHermes) {
|
if (enableHermes) {
|
||||||
//noinspection GradleDynamicVersion
|
//noinspection GradleDynamicVersion
|
||||||
implementation("com.facebook.react:hermes-engine:+") { // From node_modules
|
implementation("com.facebook.react:hermes-engine:+") { // From node_modules
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MainApplication"
|
android:name=".MainApplication"
|
||||||
@ -15,6 +16,7 @@
|
|||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:extractNativeLibs="true"
|
android:extractNativeLibs="true"
|
||||||
>
|
>
|
||||||
|
<service android:name=".NotificationsService" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
@ -4,26 +4,17 @@ import android.Manifest;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy;
|
|
||||||
import androidx.work.OneTimeWorkRequest;
|
|
||||||
import androidx.work.PeriodicWorkRequest;
|
|
||||||
import androidx.work.WorkManager;
|
|
||||||
|
|
||||||
import com.facebook.react.ReactActivity;
|
import com.facebook.react.ReactActivity;
|
||||||
import com.facebook.react.ReactActivityDelegate;
|
import com.facebook.react.ReactActivityDelegate;
|
||||||
import com.facebook.react.ReactInstanceManager;
|
|
||||||
import com.facebook.react.ReactRootView;
|
import com.facebook.react.ReactRootView;
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||||
import com.robosats.workers.NotificationWorker;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class MainActivity extends ReactActivity {
|
public class MainActivity extends ReactActivity {
|
||||||
private static final int REQUEST_CODE_POST_NOTIFICATIONS = 1;
|
private static final int REQUEST_CODE_POST_NOTIFICATIONS = 1;
|
||||||
@ -31,22 +22,20 @@ public class MainActivity extends ReactActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
Bundle extras = getIntent().getExtras();
|
|
||||||
if (extras != null) {
|
|
||||||
String coordinator = extras.getString("coordinator");
|
|
||||||
String token = extras.getString("token");
|
|
||||||
int order_id = extras.getInt("order_id", 0);
|
|
||||||
if (order_id > 0) {
|
|
||||||
navigateToPage(coordinator, order_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_CODE_POST_NOTIFICATIONS);
|
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_CODE_POST_NOTIFICATIONS);
|
||||||
} else {
|
} else {
|
||||||
// Permission already granted, schedule your work
|
Intent serviceIntent = new Intent(getApplicationContext(), NotificationsService.class);
|
||||||
scheduleFirstNotificationTask();
|
getApplicationContext().startService(serviceIntent);
|
||||||
schedulePeriodicNotificationTask();
|
}
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
if (intent != null) {
|
||||||
|
String coordinator = intent.getStringExtra("coordinator");
|
||||||
|
int order_id = intent.getIntExtra("order_id", 0);
|
||||||
|
if (order_id > 0) {
|
||||||
|
navigateToPage(coordinator, order_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +75,8 @@ public class MainActivity extends ReactActivity {
|
|||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
if (requestCode == REQUEST_CODE_POST_NOTIFICATIONS) {
|
if (requestCode == REQUEST_CODE_POST_NOTIFICATIONS) {
|
||||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
scheduleFirstNotificationTask();
|
Intent serviceIntent = new Intent(getApplicationContext(), NotificationsService.class);
|
||||||
schedulePeriodicNotificationTask();
|
getApplicationContext().startService(serviceIntent);
|
||||||
} else {
|
} else {
|
||||||
// Permission denied, handle accordingly
|
// Permission denied, handle accordingly
|
||||||
// Maybe show a message to the user explaining why the permission is necessary
|
// Maybe show a message to the user explaining why the permission is necessary
|
||||||
@ -106,37 +95,6 @@ public class MainActivity extends ReactActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleFirstNotificationTask() {
|
|
||||||
OneTimeWorkRequest workRequest =
|
|
||||||
new OneTimeWorkRequest.Builder(NotificationWorker.class)
|
|
||||||
.setInitialDelay(20, TimeUnit.SECONDS)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
WorkManager.getInstance(getApplicationContext())
|
|
||||||
.enqueue(workRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void schedulePeriodicNotificationTask() {
|
|
||||||
// Trigger the WorkManager setup and enqueueing here
|
|
||||||
PeriodicWorkRequest periodicWorkRequest =
|
|
||||||
new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
WorkManager.getInstance(getApplicationContext())
|
|
||||||
.enqueueUniquePeriodicWork("RobosatsNotificationsWork",
|
|
||||||
ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scheduleInitialTask() {
|
|
||||||
OneTimeWorkRequest workRequest =
|
|
||||||
new OneTimeWorkRequest.Builder(NotificationWorker.class)
|
|
||||||
.setInitialDelay(25, TimeUnit.SECONDS)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
WorkManager.getInstance(getApplicationContext())
|
|
||||||
.enqueue(workRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MainActivityDelegate extends ReactActivityDelegate {
|
public static class MainActivityDelegate extends ReactActivityDelegate {
|
||||||
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
|
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
|
||||||
super(activity, mainComponentName);
|
super(activity, mainComponentName);
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
package com.robosats.workers;
|
package com.robosats;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.work.Worker;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.robosats.MainActivity;
|
|
||||||
import com.robosats.R;
|
|
||||||
import com.robosats.tor.TorKmp;
|
import com.robosats.tor.TorKmp;
|
||||||
import com.robosats.tor.TorKmpManager;
|
import com.robosats.tor.TorKmpManager;
|
||||||
|
|
||||||
@ -26,10 +26,16 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Proxy;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import kotlin.UninitializedPropertyAccessException;
|
import kotlin.UninitializedPropertyAccessException;
|
||||||
@ -39,21 +45,82 @@ import okhttp3.OkHttpClient;
|
|||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
public class NotificationWorker extends Worker {
|
public class NotificationsService extends Service {
|
||||||
|
private Handler handler;
|
||||||
|
private Runnable periodicTask;
|
||||||
private static final String CHANNEL_ID = "robosats_notifications";
|
private static final String CHANNEL_ID = "robosats_notifications";
|
||||||
|
private static final int NOTIFICATION_ID = 76453;
|
||||||
|
private static final long INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
||||||
private static final String PREFS_NAME_NOTIFICATION = "Notifications";
|
private static final String PREFS_NAME_NOTIFICATION = "Notifications";
|
||||||
private static final String PREFS_NAME_SYSTEM = "System";
|
private static final String PREFS_NAME_SYSTEM = "System";
|
||||||
private static final String KEY_DATA_SLOTS = "Slots";
|
private static final String KEY_DATA_SLOTS = "Slots";
|
||||||
private static final String KEY_DATA_PROXY = "UsePoxy";
|
private static final String KEY_DATA_PROXY = "UsePoxy";
|
||||||
private static final String KEY_DATA_FEDERATION = "Federation";
|
private static final String KEY_DATA_FEDERATION = "Federation";
|
||||||
|
|
||||||
public NotificationWorker(Context context, WorkerParameters params) {
|
@Nullable
|
||||||
super(context, params);
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result doWork() {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
createNotificationChannel();
|
||||||
|
startForeground(NOTIFICATION_ID, buildServiceNotification());
|
||||||
|
|
||||||
|
handler = new Handler();
|
||||||
|
periodicTask = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Log.d("NotificationsService", "Running periodic task");
|
||||||
|
executeBackgroundTask();
|
||||||
|
handler.postDelayed(periodicTask, INTERVAL_MS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.d("NotificationsService", "Squeduling periodic task");
|
||||||
|
handler.postDelayed(periodicTask, 5000);
|
||||||
|
return START_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (handler != null && periodicTask != null) {
|
||||||
|
handler.removeCallbacks(periodicTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopForeground(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createNotificationChannel() {
|
||||||
|
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||||
|
NotificationChannel channel = new NotificationChannel(
|
||||||
|
CHANNEL_ID,
|
||||||
|
"Robosats",
|
||||||
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
|
);
|
||||||
|
manager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeBackgroundTask() {
|
||||||
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
executor.submit(this::checkNotifications);
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification buildServiceNotification() {
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
|
.setContentTitle("Tor Notifications")
|
||||||
|
.setContentText("The app will run on the background to send you notifications about your orders.")
|
||||||
|
.setSmallIcon(R.mipmap.ic_icon)
|
||||||
|
.setTicker("Robosats");
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkNotifications() {
|
||||||
|
Log.d("NotificationsService", "checkNotifications");
|
||||||
SharedPreferences sharedPreferences =
|
SharedPreferences sharedPreferences =
|
||||||
getApplicationContext()
|
getApplicationContext()
|
||||||
.getSharedPreferences(PREFS_NAME_NOTIFICATION, ReactApplicationContext.MODE_PRIVATE);
|
.getSharedPreferences(PREFS_NAME_NOTIFICATION, ReactApplicationContext.MODE_PRIVATE);
|
||||||
@ -69,19 +136,13 @@ public class NotificationWorker extends Worker {
|
|||||||
JSONObject slot = (JSONObject) slots.get(robotToken);
|
JSONObject slot = (JSONObject) slots.get(robotToken);
|
||||||
JSONObject robots = slot.getJSONObject("robots");
|
JSONObject robots = slot.getJSONObject("robots");
|
||||||
JSONObject coordinatorRobot;
|
JSONObject coordinatorRobot;
|
||||||
String activeShortAlias;
|
String shortAlias = slot.getString("activeShortAlias");
|
||||||
try {
|
coordinatorRobot = robots.getJSONObject(shortAlias);
|
||||||
activeShortAlias = slot.getString("activeShortAlias");
|
fetchNotifications(coordinatorRobot, shortAlias);
|
||||||
coordinatorRobot = robots.getJSONObject(activeShortAlias);
|
|
||||||
fetchNotifications(coordinatorRobot, activeShortAlias);
|
|
||||||
} catch (JSONException | InterruptedException e) {
|
|
||||||
Log.d("JSON error", String.valueOf(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException | InterruptedException e) {
|
||||||
Log.d("JSON error", String.valueOf(e));
|
Log.d("NotificationsService", "Error reading garage: " + e);
|
||||||
}
|
}
|
||||||
return Result.success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchNotifications(JSONObject robot, String coordinator) throws JSONException, InterruptedException {
|
private void fetchNotifications(JSONObject robot, String coordinator) throws JSONException, InterruptedException {
|
||||||
@ -93,11 +154,11 @@ public class NotificationWorker extends Worker {
|
|||||||
JSONObject federation = new JSONObject(sharedPreferences.getString(KEY_DATA_FEDERATION, "{}"));
|
JSONObject federation = new JSONObject(sharedPreferences.getString(KEY_DATA_FEDERATION, "{}"));
|
||||||
long unix_time_millis = sharedPreferences.getLong(token, 0);
|
long unix_time_millis = sharedPreferences.getLong(token, 0);
|
||||||
String url = federation.getString(coordinator) + "/api/notifications";
|
String url = federation.getString(coordinator) + "/api/notifications";
|
||||||
// if (unix_time_millis > 0) {
|
if (unix_time_millis > 0) {
|
||||||
// String last_created_at = String
|
String last_created_at = String
|
||||||
// .valueOf(LocalDateTime.ofInstant(Instant.ofEpochMilli(unix_time_millis), ZoneId.of("UTC")));
|
.valueOf(LocalDateTime.ofInstant(Instant.ofEpochMilli(unix_time_millis), ZoneId.of("UTC")));
|
||||||
// url += "?created_at=" + last_created_at;
|
url += "?created_at=" + last_created_at;
|
||||||
// }
|
}
|
||||||
|
|
||||||
OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
||||||
.connectTimeout(60, TimeUnit.SECONDS) // Set connection timeout
|
.connectTimeout(60, TimeUnit.SECONDS) // Set connection timeout
|
||||||
@ -120,7 +181,7 @@ public class NotificationWorker extends Worker {
|
|||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||||
displayErrorNotification();
|
displayErrorNotification();
|
||||||
Log.d("RobosatsError", e.toString());
|
Log.d("NotificationsService", "Error fetching coordinator: " + e.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -142,8 +203,17 @@ public class NotificationWorker extends Worker {
|
|||||||
|
|
||||||
displayOrderNotification(order_id, notification.getString("title"), coordinator);
|
displayOrderNotification(order_id, notification.getString("title"), coordinator);
|
||||||
|
|
||||||
|
long milliseconds;
|
||||||
|
try {
|
||||||
|
String created_at = notification.getString("created_at");
|
||||||
|
LocalDateTime datetime = LocalDateTime.parse(created_at, DateTimeFormatter.ISO_DATE_TIME);
|
||||||
|
milliseconds = datetime.toInstant(ZoneOffset.UTC).toEpochMilli() + 1000;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
milliseconds = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
editor.putLong(token, System.currentTimeMillis());
|
editor.putLong(token, milliseconds);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
@ -158,11 +228,6 @@ public class NotificationWorker extends Worker {
|
|||||||
NotificationManager notificationManager = (NotificationManager)
|
NotificationManager notificationManager = (NotificationManager)
|
||||||
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
|
|
||||||
order_id.toString(),
|
|
||||||
NotificationManager.IMPORTANCE_HIGH);
|
|
||||||
notificationManager.createNotificationChannel(channel);
|
|
||||||
|
|
||||||
Intent intent = new Intent(this.getApplicationContext(), MainActivity.class);
|
Intent intent = new Intent(this.getApplicationContext(), MainActivity.class);
|
||||||
intent.putExtra("coordinator", coordinator);
|
intent.putExtra("coordinator", coordinator);
|
||||||
intent.putExtra("order_id", order_id);
|
intent.putExtra("order_id", order_id);
|
||||||
@ -173,7 +238,7 @@ public class NotificationWorker extends Worker {
|
|||||||
new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
|
new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
|
||||||
.setContentTitle("Order #" + order_id)
|
.setContentTitle("Order #" + order_id)
|
||||||
.setContentText(message)
|
.setContentText(message)
|
||||||
.setSmallIcon(R.mipmap.ic_launcher_round)
|
.setSmallIcon(R.mipmap.ic_icon)
|
||||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.setAutoCancel(true);
|
.setAutoCancel(true);
|
||||||
@ -185,16 +250,11 @@ public class NotificationWorker extends Worker {
|
|||||||
NotificationManager notificationManager = (NotificationManager)
|
NotificationManager notificationManager = (NotificationManager)
|
||||||
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
|
|
||||||
"robosats_error",
|
|
||||||
NotificationManager.IMPORTANCE_HIGH);
|
|
||||||
notificationManager.createNotificationChannel(channel);
|
|
||||||
|
|
||||||
NotificationCompat.Builder builder =
|
NotificationCompat.Builder builder =
|
||||||
new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
|
new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
|
||||||
.setContentTitle("Connection Error")
|
.setContentTitle("Connection Error")
|
||||||
.setContentText("There was an error while connecting to the Tor network.")
|
.setContentText("There was an error while connecting to the Tor network.")
|
||||||
.setSmallIcon(R.mipmap.ic_launcher_round)
|
.setSmallIcon(R.mipmap.ic_icon)
|
||||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
.setAutoCancel(true);
|
.setAutoCancel(true);
|
||||||
|
|
||||||
@ -225,4 +285,3 @@ public class NotificationWorker extends Worker {
|
|||||||
return torKmp;
|
return torKmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
mobile/android/app/src/main/res/mipmap-hdpi/ic_icon.png
Normal file
BIN
mobile/android/app/src/main/res/mipmap-hdpi/ic_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Loading…
Reference in New Issue
Block a user