diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 989f592..e87e005 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,29 +1,33 @@ + package="com.massive"> - - + + + - - - - - - - + android:roundIcon="@mipmap/ic_launcher_round" + android:theme="@style/AppTheme" + android:dataExtractionRules="@xml/data_extraction_rules"> + + + + + + + + diff --git a/android/app/src/main/java/com/massive/AlarmModule.java b/android/app/src/main/java/com/massive/AlarmModule.java index d65765b..600168d 100644 --- a/android/app/src/main/java/com/massive/AlarmModule.java +++ b/android/app/src/main/java/com/massive/AlarmModule.java @@ -1,12 +1,19 @@ package com.massive; // replace com.your-app-name with your app’s name +import static android.content.Context.ALARM_SERVICE; + +import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.Context; import android.content.Intent; +import android.media.MediaPlayer; import android.os.Build; +import android.os.SystemClock; import android.util.Log; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; @@ -24,6 +31,8 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import java.time.Duration; +import java.util.Calendar; +import java.util.Date; import java.util.Map; import java.util.HashMap; import java.util.concurrent.TimeUnit; @@ -42,12 +51,15 @@ public class AlarmModule extends ReactContextBaseJavaModule { @RequiresApi(api = Build.VERSION_CODES.O) @ReactMethod(isBlockingSynchronousMethod = true) public void timer(int milliseconds) { - WorkRequest request = new PeriodicWorkRequest.Builder( - AlarmWorker.class, milliseconds, TimeUnit.MILLISECONDS - ) - .build(); Log.d("AlarmModule", "Queue alarm for " + milliseconds + " delay"); - WorkManager.getInstance(getReactApplicationContext()) - .enqueue(request); + Intent intent = new Intent(getReactApplicationContext(), MyBroadcastReceiver.class); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + getReactApplicationContext(), 69, intent, PendingIntent.FLAG_IMMUTABLE); + AlarmManager alarmManager = (AlarmManager) getReactApplicationContext().getSystemService(ALARM_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + Log.d("AlarmModule", "Can schedule: " + alarmManager.canScheduleExactAlarms()); + } + AlarmManager.AlarmClockInfo info = new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + milliseconds, pendingIntent); + alarmManager.setAlarmClock(info, pendingIntent); } } diff --git a/android/app/src/main/java/com/massive/AlarmWorker.java b/android/app/src/main/java/com/massive/AlarmWorker.java deleted file mode 100644 index b6c47da..0000000 --- a/android/app/src/main/java/com/massive/AlarmWorker.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.massive; - -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.media.MediaPlayer; -import android.os.Build; -import android.os.Vibrator; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; -import androidx.work.Worker; -import androidx.work.WorkerParameters; - -public class AlarmWorker extends Worker { - private static final String CHANNEL_ID = "MassiveAlarms"; - - public AlarmWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - } - - @NonNull - @Override - public Result doWork() { - Log.d("AlarmWorker", "Doing work..."); - createNotificationChannel(); - Intent intent = new Intent(getApplicationContext(), AlarmModule.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE); - NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID) - .setSmallIcon(R.drawable.autofill_inline_suggestion_chip_background) - .setContentTitle("Rest complete.") - .setContentText("Break time is over!") - .setContentIntent(pendingIntent) - .setAutoCancel(true) - .setPriority(NotificationCompat.PRIORITY_DEFAULT); - NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext()); - notificationManager.notify(1, builder.build()); - MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.argon); - mediaPlayer.start(); // no need to call prepare(); create() does that for you - Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE); - vibrator.vibrate(400); - return Result.success(); - } - - private void createNotificationChannel() { - Log.d("AlarmWorker", "Creating notification channel..."); - // Create the NotificationChannel, but only on API 26+ because - // the NotificationChannel class is new and not in the support library - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - int importance = NotificationManager.IMPORTANCE_DEFAULT; - NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "MassiveAlarms", importance); - channel.setDescription("Alarms for the Massive application"); - // Register the channel with the system; you can't change the importance - // or other notification behaviors after this - NotificationManager notificationManager = getApplicationContext().getSystemService(NotificationManager.class); - notificationManager.createNotificationChannel(channel); - } - } -} diff --git a/android/app/src/main/java/com/massive/MyBroadcastReceiver.java b/android/app/src/main/java/com/massive/MyBroadcastReceiver.java new file mode 100644 index 0000000..33cc1f8 --- /dev/null +++ b/android/app/src/main/java/com/massive/MyBroadcastReceiver.java @@ -0,0 +1,67 @@ +package com.massive; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.media.MediaPlayer; +import android.os.Build; +import android.os.VibrationEffect; +import android.os.Vibrator; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.RequiresApi; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + +public class MyBroadcastReceiver extends BroadcastReceiver { + private static final String CHANNEL_ID = "MassiveAlarm"; + private static final int ALARM_ID = 59; + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onReceive(Context context, Intent intent) { + Log.d("MyBroadcastReceiver", "Received intent for BroadcastReceiver."); + long[] pattern = {0, 300, 200, 300, 200}; + int[] amplitudes = {VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE}; + Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + vibrator.vibrate(VibrationEffect.createWaveform(pattern, amplitudes, 0)); + } else { + //deprecated in API 26 + vibrator.vibrate(500); + } + createNotificationChannel(context); + + Intent contentIntent = new Intent(context.getApplicationContext(), MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, PendingIntent.FLAG_IMMUTABLE); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID) + .setSmallIcon(R.drawable.rn_edit_text_material) + .setContentTitle("Rest") + .setContentText("Break times over!") + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .setCategory(NotificationCompat.CATEGORY_ALARM) + .setPriority(NotificationCompat.PRIORITY_HIGH); + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + notificationManager.notify(ALARM_ID, builder.build()); + MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.argon); + mediaPlayer.start(); + } + + private void createNotificationChannel(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + int importance = NotificationManager.IMPORTANCE_HIGH; + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, importance); + channel.setDescription("Alarms for rest timings."); + NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(channel); + } + } +} + + diff --git a/android/app/src/main/res/xml/data_extraction_rules.xml b/android/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..8b570f1 --- /dev/null +++ b/android/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,36 @@ + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index 60538c7..30acc9f 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@react-native-async-storage/async-storage": "^1.17.7", "@react-native-community/push-notification-ios": "^1.10.1", "@react-navigation/bottom-tabs": "^6.3.1", + "@react-navigation/material-top-tabs": "^6.2.1", "@react-navigation/native": "^6.0.10", "@react-navigation/native-stack": "^6.6.2", "@types/react-native-background-timer": "^2.0.0", @@ -25,6 +26,7 @@ "react-native": "0.69.1", "react-native-background-timer": "^2.4.1", "react-native-gesture-handler": "^2.5.0", + "react-native-pager-view": "^5.4.24", "react-native-paper": "^4.12.2", "react-native-push-notification": "^8.1.1", "react-native-reanimated": "^2.9.0", @@ -32,6 +34,7 @@ "react-native-screens": "^3.14.0", "react-native-sound": "^0.11.2", "react-native-sqlite-storage": "^6.0.1", + "react-native-tab-view": "^3.1.1", "react-native-vector-icons": "^9.2.0" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 24baeae..3a66bf1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1650,6 +1650,14 @@ resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.3.tgz#9f56b650a9a1a8263a271628be7342c8121d1788" integrity sha512-Lv2lR7si5gNME8dRsqz57d54m4FJtrwHRjNQLOyQO546ZxO+g864cSvoLC6hQedQU0+IJnPTsZiEI2hHqfpEpw== +"@react-navigation/material-top-tabs@^6.2.1": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@react-navigation/material-top-tabs/-/material-top-tabs-6.2.1.tgz#747d17bd0138a7d50c791e9cce1adc350904f67d" + integrity sha512-fGy2+/7cUAyrZUPUhzKUttA4avK5Z2FrNk0LRI04hRlAVqs5DYpnaQGkegGeOGwKmnxaVCjCVPr+KoEroyqduw== + dependencies: + color "^3.1.3" + warn-once "^0.1.0" + "@react-navigation/native-stack@^6.6.2": version "6.6.2" resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.6.2.tgz#09e696ad72299872f4c5c1e5b1ad309869853628" @@ -6676,6 +6684,11 @@ react-native-iphone-x-helper@^1.3.1: resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010" integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg== +react-native-pager-view@^5.4.24: + version "5.4.24" + resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-5.4.24.tgz#8626e757ddc55e41eca66d2f8a8a75aec54591ee" + integrity sha512-dRMB7i3B+mu4NCeIN6gqbR/kC/rr2wzqO0gisXDdJwJr78G24sWoTNpLEDFo3G8TFHY9nTMutVl5CUvkN2dp6g== + react-native-paper@^4.12.2: version "4.12.2" resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-4.12.2.tgz#31ed8011afd994d54dd403ed0099295fc1616d26" @@ -6727,6 +6740,11 @@ react-native-sqlite-storage@^6.0.1: resolved "https://registry.yarnpkg.com/react-native-sqlite-storage/-/react-native-sqlite-storage-6.0.1.tgz#ce6a6b852f07abbea68658d5363818c8bef45dfb" integrity sha512-1tDFjrint6X6qSYKf3gDyz+XB+X79jfiL6xTugKHPRtF0WvqMtVgdLuNqZunIXjNEvNtNVEbXaeZ6MsguFu00A== +react-native-tab-view@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.1.1.tgz#1f8d7a835ab4f5b1b1407ec8dddc1053b53fa3c6" + integrity sha512-M5pRN6utQfytKWoKlKVzg5NbkYu308qNoW1khGTtEOTs1k14p2dHJ/BWOJoJYHKbPVUyZldbG9MFT7gUl4YHnw== + react-native-vector-icons@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz#3c0c82e95defd274d56363cbe8fead8d53167ebd"