Added back support for alarms
@ -5,6 +5,12 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- RN-NOTIFICATION -->
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<!-- /RN-NOTIFICATION -->
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:label="@string/app_name"
|
||||
@ -12,6 +18,37 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:allowBackup="false"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<!-- RN-NOTIFICATION -->
|
||||
<receiver
|
||||
android:name="com.emekalites.react.alarm.notification.AlarmReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="ACTION_DISMISS" />
|
||||
<action android:name="ACTION_SNOOZE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="com.emekalites.react.alarm.notification.AlarmDismissReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
|
||||
<receiver
|
||||
android:name="com.emekalites.react.alarm.notification.AlarmBootReceiver"
|
||||
android:directBootAware="true"
|
||||
android:enabled="false"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- /RN-NOTIFICATION -->
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 548 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 921 B |
After Width: | Height: | Size: 725 B |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB |
@ -1,3 +1,4 @@
|
||||
<resources>
|
||||
<string name="app_name">Joplin</string>
|
||||
<string name="default_notification_channel_id">net.cozic.joplin.notification</string>
|
||||
</resources>
|
||||
|
@ -264,7 +264,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
|
||||
const renderUndoButton = () => {
|
||||
return renderTopButton({
|
||||
iconName: 'md-undo',
|
||||
iconName: 'arrow-undo-circle-sharp',
|
||||
onPress: this.props.onUndoButtonPress,
|
||||
visible: this.props.showUndoButton,
|
||||
disabled: this.props.undoButtonDisabled,
|
||||
@ -273,7 +273,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
|
||||
const renderRedoButton = () => {
|
||||
return renderTopButton({
|
||||
iconName: 'md-redo',
|
||||
iconName: 'arrow-redo-circle-sharp',
|
||||
onPress: this.props.onRedoButtonPress,
|
||||
visible: this.props.showRedoButton,
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ const BaseModel = require('lib/BaseModel.js');
|
||||
const Note = require('lib/models/Note.js');
|
||||
|
||||
export interface Notification {
|
||||
id: string,
|
||||
id: number,
|
||||
noteId: string,
|
||||
date: Date,
|
||||
title: string,
|
||||
|
@ -1,48 +1,67 @@
|
||||
import Logger from 'lib/Logger';
|
||||
import { Notification } from 'lib/models/Alarm';
|
||||
|
||||
const PushNotification = require('react-native-push-notification');
|
||||
const ReactNativeAN = require('react-native-alarm-notification').default;
|
||||
|
||||
export default class AlarmServiceDriver {
|
||||
|
||||
private PushNotification_:any = null;
|
||||
private logger_:Logger;
|
||||
|
||||
PushNotificationHandler_() {
|
||||
if (!this.PushNotification_) {
|
||||
PushNotification.configure({
|
||||
// (required) Called when a remote or local notification is opened or received
|
||||
onNotification: function(notification:any) {
|
||||
console.info('Notification was opened: ', notification);
|
||||
// process the notification
|
||||
},
|
||||
popInitialNotification: true,
|
||||
requestPermissions: true,
|
||||
});
|
||||
|
||||
this.PushNotification_ = PushNotification;
|
||||
}
|
||||
|
||||
return this.PushNotification_;
|
||||
constructor(logger:Logger) {
|
||||
this.logger_ = logger;
|
||||
}
|
||||
|
||||
hasPersistentNotifications() {
|
||||
public hasPersistentNotifications() {
|
||||
return true;
|
||||
}
|
||||
|
||||
notificationIsSet() {
|
||||
public notificationIsSet() {
|
||||
throw new Error('Available only for non-persistent alarms');
|
||||
}
|
||||
|
||||
async clearNotification(id:any) {
|
||||
return this.PushNotificationHandler_().cancelLocalNotifications({ id: `${id}` });
|
||||
public async clearNotification(id:number) {
|
||||
const alarm = await this.alarmByJoplinNotificationId(id);
|
||||
if (!alarm) return;
|
||||
|
||||
this.logger_.info('AlarmServiceDriver: Deleting alarm:', alarm);
|
||||
|
||||
await ReactNativeAN.deleteAlarm(alarm.id);
|
||||
}
|
||||
|
||||
async scheduleNotification(notification:Notification) {
|
||||
const config = {
|
||||
id: `${notification.id}`,
|
||||
message: notification.title,
|
||||
date: notification.date,
|
||||
// Returns -1 if could not be found
|
||||
private alarmJoplinAlarmId(alarm:any):number {
|
||||
if (!alarm.data) return -1;
|
||||
const m = alarm.data.match(/joplinNotificationId==>(\d+)/)
|
||||
return m ? Number(m[1]) : -1;
|
||||
}
|
||||
|
||||
private async alarmByJoplinNotificationId(joplinNotificationId:number) {
|
||||
const alarms:any[] = await ReactNativeAN.getScheduledAlarms();
|
||||
for (const alarm of alarms) {
|
||||
const id = this.alarmJoplinAlarmId(alarm);
|
||||
if (id === joplinNotificationId) return alarm;
|
||||
}
|
||||
|
||||
this.logger_.warn('AlarmServiceDriver: Could not find alarm that matches Joplin notification ID. It could be because it has already been triggered:', joplinNotificationId);
|
||||
return null;
|
||||
}
|
||||
|
||||
public async scheduleNotification(notification:Notification) {
|
||||
const alarmNotifData = {
|
||||
title: notification.title,
|
||||
message: notification.body ? notification.body : '-', // Required
|
||||
channel: "net.cozic.joplin.notification",
|
||||
small_icon: "ic_launcher",
|
||||
color: 'white',
|
||||
data: { joplinNotificationId: notification.id + '' },
|
||||
};
|
||||
|
||||
this.PushNotificationHandler_().localNotificationSchedule(config);
|
||||
// ReactNativeAN expects a string as a date and it seems this utility
|
||||
// function converts it to the right format.
|
||||
const fireDate = ReactNativeAN.parseDate(notification.date);
|
||||
|
||||
const alarm = await ReactNativeAN.scheduleAlarm({ ...alarmNotifData, fire_date: fireDate });
|
||||
|
||||
this.logger_.info('AlarmServiceDriver: Created new alarm:', alarm);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// import { Notification } from 'lib/models/Alarm';
|
||||
// import Logger from 'lib/Logger';
|
||||
// const PushNotificationIOS = require('@react-native-community/push-notification-ios').default;
|
||||
|
||||
// export default class AlarmServiceDriver {
|
||||
@ -6,7 +7,8 @@
|
||||
// private hasPermission_:boolean = null;
|
||||
// private inAppNotificationHandler_:any = null;
|
||||
|
||||
// constructor() {
|
||||
// constructor(logger:Logger) {
|
||||
// this.logger_ = logger;
|
||||
// PushNotificationIOS.addEventListener('localNotification', (instance:any) => {
|
||||
// if (!this.inAppNotificationHandler_) return;
|
||||
|
||||
|
@ -33,11 +33,11 @@ export default class AlarmServiceDriverNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
notificationIsSet(id:string) {
|
||||
notificationIsSet(id:number) {
|
||||
return id in this.notifications_;
|
||||
}
|
||||
|
||||
async clearNotification(id:string) {
|
||||
async clearNotification(id:number) {
|
||||
if (!this.notificationIsSet(id)) return;
|
||||
shim.clearTimeout(this.notifications_[id].timeoutId);
|
||||
delete this.notifications_[id];
|
||||
|
5
ReactNativeClient/package-lock.json
generated
@ -10770,6 +10770,11 @@
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"react-native-alarm-notification": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-alarm-notification/-/react-native-alarm-notification-1.7.1.tgz",
|
||||
"integrity": "sha512-cvfSqCCfw48NyeFTEL5WOF/tkeWLNI7X1mVoEQ/9aY+2fuBtkCfZUoJ7vvOOHeryPbDJrlDNpRWTi3erLphZ+w=="
|
||||
},
|
||||
"react-native-camera": {
|
||||
"version": "3.40.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.40.0.tgz",
|
||||
|
@ -57,6 +57,7 @@
|
||||
"react-async": "^10.0.0",
|
||||
"react-native": "0.63.3",
|
||||
"react-native-action-button": "^2.8.5",
|
||||
"react-native-alarm-notification": "^1.7.1",
|
||||
"react-native-camera": "^3.40.0",
|
||||
"react-native-device-info": "^6.2.0",
|
||||
"react-native-dialogbox": "^0.6.10",
|
||||
|
@ -8,7 +8,7 @@ const { connect, Provider } = require('react-redux');
|
||||
const { BackButtonService } = require('lib/services/back-button.js');
|
||||
const NavService = require('lib/services/NavService.js');
|
||||
const AlarmService = require('lib/services/AlarmService.js').default;
|
||||
// const AlarmServiceDriver = require('lib/services/AlarmServiceDriver').default;
|
||||
const AlarmServiceDriver = require('lib/services/AlarmServiceDriver').default;
|
||||
const Alarm = require('lib/models/Alarm').default;
|
||||
const { createStore, applyMiddleware } = require('redux');
|
||||
const reduxSharedMiddleware = require('lib/components/shared/reduxSharedMiddleware');
|
||||
@ -442,7 +442,7 @@ async function initialize(dispatch) {
|
||||
Resource.fsDriver_ = fsDriver;
|
||||
FileApiDriverLocal.fsDriver_ = fsDriver;
|
||||
|
||||
// AlarmService.setDriver(new AlarmServiceDriver());
|
||||
AlarmService.setDriver(new AlarmServiceDriver(mainLogger));
|
||||
AlarmService.setLogger(mainLogger);
|
||||
|
||||
try {
|
||||
|
@ -709,8 +709,7 @@
|
||||
],
|
||||
"spellright.documentTypes": [
|
||||
"markdown",
|
||||
"latex",
|
||||
"plaintext"
|
||||
"latex"
|
||||
]
|
||||
},
|
||||
}
|