Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Remember last recording settings (which camera was used and geotagging checkbox)
- Automatically retry geotagging when it fails for the first time
- Added Catalan localization
- Cancel notification if video is recorded for that day

## v1.5.2 - 09/2023
- Added quick trim shortcuts in save video page for a more precise editing
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Harry Schiller (@waitingwittykitty)
- David Coker (@daoxve)
- Adrasteon (@AdrasteonDev)
- Ishan Vaghani (@ishanvaghani)

## Testing & Feedback
- Augusto Vesco
Expand Down
4 changes: 4 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ android {
ndkVersion "25.1.8937393"

compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Expand Down Expand Up @@ -91,4 +92,7 @@ flutter {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.window:window:1.0.0'
implementation 'androidx.window:window-java:1.0.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ishanvaghani why are these needed?
Then, shouldn't we also add coreLibraryDesugaringEnabled true as it says here: https://www.geeksforgeeks.org/desugaring-in-android/

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have missed it. Adding

}
17 changes: 12 additions & 5 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />

<application
android:name="${applicationName}"
Expand Down Expand Up @@ -55,11 +58,15 @@
android:name="flutterEmbedding"
android:value="2" />

<service
android:name="com.dexterous.flutterlocalnotifications.ForegroundService"
android:exported="false"
android:stopWithTask="false"
tools:targetApi="ice_cream_sandwich" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>

</application>

Expand Down
13 changes: 7 additions & 6 deletions lib/controllers/daily_entry_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ class DailyEntryController extends GetxController {
SharedPrefsUtil.putBool('dailyEntry', value);
dailyEntry.value = value;
dailyEntry.refresh();

// Remove the existing notification and schedule it again
notificationService.rescheduleNotification(DateTime.now());
if (value) {
notificationService.cancelTodayNotification();
} else {
notificationService.scheduleTodayNotification();
}
}

void _checkTodayEntry() {
Expand All @@ -34,8 +36,7 @@ class DailyEntryController extends GetxController {
dailyEntry.refresh();
}

// Remove the existing notification and schedule it again if there is a daily entry
if(dailyEntry.value)
notificationService.rescheduleNotification(DateTime.now());
// schedule future notification
notificationService.scheduleFutureNotifications();
}
}
3 changes: 3 additions & 0 deletions lib/lang/en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,7 @@ const Map<String, String> en = {
'useAlternativeCalendarColors': 'Use alternative calendar colors',
'useAlternativeCalendarColorsDescription':
'Changes green and red in calendar to blue and yellow. Useful for colorblind people.',
'permissionDenied': 'Permission Denied',
'allPermissionDenied': 'You have denied all the requested permissions but these are required to perform the required functionality. Would you like to accept them?',
'noThanks': 'No Thanks',
};
52 changes: 52 additions & 0 deletions lib/models/osd_date_time.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'package:flutter/foundation.dart';

@immutable
class OSDDateTime {
final int year;
final int month;
final int day;
final int hour;
final int minute;
final int notificationId;

OSDDateTime({
required this.year,
required this.month,
required this.day,
required this.hour,
required this.minute,
required this.notificationId,
});

Map<String, int> toMap() => {
'year': year,
'month': month,
'day': day,
'hour': hour,
'minute': minute,
'notificationId': notificationId,
};

factory OSDDateTime.fromJson(Map<String, dynamic> json) {
return OSDDateTime(
year: json['year'],
month: json['month'],
day: json['day'],
hour: json['hour'],
minute: json['minute'],
notificationId: json['notificationId'],
);
}

@override
String toString() {
return {
'year': year,
'month': month,
'day': day,
'hour': hour,
'minute': minute,
'notificationId': notificationId,
}.toString();
}
}
125 changes: 87 additions & 38 deletions lib/pages/home/notification/widgets/switch_notifications.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';

import '../../../../routes/app_pages.dart';
import '../../../../utils/constants.dart';
import '../../../../utils/custom_dialog.dart';
import '../../../../utils/notification_service.dart';
import '../../../../utils/theme.dart';

Expand All @@ -15,7 +18,7 @@ class SwitchNotificationsComponent extends StatefulWidget {
class _SwitchNotificationsComponentState
extends State<SwitchNotificationsComponent> {
late bool isNotificationSwitchToggled;
TimeOfDay scheduledTimeOfDay = const TimeOfDay(hour: 20, minute: 00);
late TimeOfDay scheduledTimeOfDay;
late bool isPersistentSwitchToggled;
final NotificationService notificationService = Get.find();

Expand Down Expand Up @@ -55,21 +58,30 @@ class _SwitchNotificationsComponentState
value: isNotificationSwitchToggled,
onChanged: (value) async {
if (value) {
await notificationService.turnOnNotifications();
// show custom permission dialog
if (await Permission.notification.isPermanentlyDenied) {
await showNotificationDialog();
return;
}

await notificationService.scheduleNotification(
// show system permission dialog
await notificationService.turnOnNotifications();
if (notificationService.isNotificationActivated()) {
setState(() {
isNotificationSwitchToggled = true;
});
notificationService
.rescheduleNotifications(
scheduledTimeOfDay.hour,
scheduledTimeOfDay.minute,
DateTime.now()
);
);
}
} else {
await notificationService.turnOffNotifications();
setState(() {
isNotificationSwitchToggled = false;
});
}

/// Update switch value
setState(() {
isNotificationSwitchToggled = !isNotificationSwitchToggled;
});
},
activeTrackColor: AppColors.mainColor.withOpacity(0.4),
activeColor: AppColors.mainColor,
Expand Down Expand Up @@ -133,23 +145,29 @@ class _SwitchNotificationsComponentState

// Enable notification if it's disabled
if (!isNotificationSwitchToggled) {
// show custom permission dialog
if (await Permission.notification.isPermanentlyDenied) {
await showNotificationDialog();
return;
}

// show system permission dialog
await notificationService.turnOnNotifications();
setState(() {
isNotificationSwitchToggled = true;
});
if (notificationService.isNotificationActivated()) {
setState(() {
isNotificationSwitchToggled = true;
});
}
}

notificationService.setScheduledTime(newTimeOfDay.hour,
newTimeOfDay.minute);

notificationService.setScheduledTime(newTimeOfDay.hour, newTimeOfDay.minute);
setState(() {
scheduledTimeOfDay = newTimeOfDay;
});

await notificationService.scheduleNotification(
scheduledTimeOfDay.hour,
scheduledTimeOfDay.minute,
DateTime.now()
notificationService.rescheduleNotifications(
scheduledTimeOfDay.hour,
scheduledTimeOfDay.minute,
);
},
child: Container(
Expand Down Expand Up @@ -194,27 +212,16 @@ class _SwitchNotificationsComponentState
} else {
notificationService.deactivatePersistentNotifications();
}
setState(() {
isPersistentSwitchToggled = value;
});

/// Schedule notification if switch in ON
if(isNotificationSwitchToggled && !isNotificationSwitchToggled){
await notificationService.turnOnNotifications();
setState(() {
isNotificationSwitchToggled = true;
});
}

if(isNotificationSwitchToggled){
await notificationService.scheduleNotification(
scheduledTimeOfDay.hour,
scheduledTimeOfDay.minute,
DateTime.now()
if (isNotificationSwitchToggled) {
notificationService.rescheduleNotifications(
scheduledTimeOfDay.hour,
scheduledTimeOfDay.minute,
);
}

/// Update switch value
setState(() {
isPersistentSwitchToggled = !isPersistentSwitchToggled;
});
},
activeTrackColor: AppColors.mainColor.withOpacity(0.4),
activeColor: AppColors.mainColor,
Expand All @@ -226,4 +233,46 @@ class _SwitchNotificationsComponentState
],
);
}

Future<void> showNotificationDialog() async {
await showDialog(
barrierDismissible: false,
context: Get.context!,
builder: (context) =>
CustomDialog(
isDoubleAction: true,
title: 'permissionDenied'.tr,
content: 'allPermissionDenied'.tr,
actionText: 'noThanks'.tr,
actionColor: Colors.red,
action: () => Get.back(),
action2Text: 'settings'.tr,
action2Color: Colors.green,
action2: () async {
Get.back();
await openAppSettings();
const lifecycleChannel = SystemChannels.lifecycle;
lifecycleChannel.setMessageHandler((msg) async {
if (msg?.endsWith('resumed') == true) {
lifecycleChannel.setMessageHandler(null);
if (await Permission.notification.isGranted) {
// schedule notifications
notificationService.switchNotification();
setState(() {
isNotificationSwitchToggled = true;
});
notificationService
.rescheduleNotifications(
scheduledTimeOfDay.hour,
scheduledTimeOfDay.minute,
);
}
}
return null;
});
},
sendLogs: false,
),
);
}
}
1 change: 1 addition & 0 deletions lib/utils/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Constants {
static const String backupTutorialUrl = 'https://youtu.be/1Kf3ysnNNNE';
static const String email = 'mailto:kylekundev@gmail.com';
static const String githubUrl = 'https://github.com/KyleKun/one_second_diary';
static const int scheduleNotificationForDays = 14;

static const enMonths = [
'January',
Expand Down
Loading