Skip to content

Commit f95dd6d

Browse files
authored
Live Activity improvements (#110)
* Send notifciation for important events next to Live Activity * Add cancel notification
1 parent 6ea3892 commit f95dd6d

File tree

2 files changed

+49
-40
lines changed

2 files changed

+49
-40
lines changed

octoapp/appsstorage.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ def __init__(
3535
self.ExpireAt = expireAt
3636
self.ExcludeNotifications = excludeNotifications
3737

38+
def WithToken(self, fcmToken: str):
39+
return AppInstance(
40+
fcmToken=fcmToken,
41+
fcmFallbackToken=self.FcmFallbackToken,
42+
activityAutoStartToken=self.ActivityAutoStartToken,
43+
instanceId=self.InstanceId,
44+
displayName=self.DisplayName,
45+
displayDescription=self.DisplayDescription,
46+
model=self.Model,
47+
appVersion=self.AppVersion,
48+
appBuild=self.AppBuild,
49+
appLanguage=self.AppLanguage,
50+
lastSeenAt=self.LastSeenAt,
51+
expireAt=self.ExpireAt,
52+
excludeNotifications=self.ExcludeNotifications,
53+
)
3854

3955
def ToDict(self):
4056
return dict(

octoapp/notificationsender.py

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,15 @@ def SendNotification(self, event, state=None):
6666

6767
self.LastPrintState = state
6868
Sentry.Info("SENDER", "Preparing notification for %s" % event)
69-
eventFilter = self._filterEvents(event=event, state=state)
69+
priority = self._determinePriority(event=event, state=state)
7070

7171
# Skip this event
72-
if eventFilter == -1:
72+
if priority == -1:
7373
return
7474

75-
onlyActivities = eventFilter == 1
76-
targets = self._getPushTargets(
77-
preferActivity=self._shouldPreferActivity(event),
78-
canUseNonActivity=self._canUseNonActivity(event) and not onlyActivities
79-
)
75+
targets = self._getPushTargets(event = event)
8076

77+
onlyActivities = priority == 1
8178
if onlyActivities:
8279
Sentry.Debug("SENDER", "Only activities allowed, filtering")
8380
targets = helper.GetActivities(targets)
@@ -92,11 +89,7 @@ def SendNotification(self, event, state=None):
9289
activity_targets = helper.GetActivities(targets)
9390
activity_auto_start_targets = helper.GetActivityAutoStarts(targets) if (event == self.EVENT_STARTED) else []
9491
android_targets = helper.GetAndroidApps(targets)
95-
apnsData = self._createActivityStartData(event, state, activity_auto_start_targets[0]) if event == self.EVENT_STARTED and len(activity_auto_start_targets) > 0 else (self._createApnsPushData(event, state) if len(ios_targets) or len(activity_targets) else None)
96-
97-
# Remove all ios_targets that also will get a LiveActivity as they will already receive the alert from the LiveActivity
98-
auto_start_instance_ids = list(map(lambda target: target.InstanceId, activity_auto_start_targets))
99-
ios_targets = list(filter(lambda target: target.InstanceId not in auto_start_instance_ids, ios_targets))
92+
apnsData = self._createActivityStartData(event, state) if event == self.EVENT_STARTED and len(activity_auto_start_targets) > 0 else (self._createApnsPushData(event, state) if len(ios_targets) or len(activity_targets) else None)
10093

10194
# Some clients might have user interaction disbaled. First send pause so all live activities etc
10295
if event == self.EVENT_USER_INTERACTION_NEEDED and target_count_before_filter != len(targets):
@@ -124,7 +117,7 @@ def SendNotification(self, event, state=None):
124117
if event in [self.EVENT_DONE, self.EVENT_CANCELLED, self.EVENT_ERROR]:
125118
helper.RemoveTemporaryApps()
126119

127-
def _filterEvents(self, event, state):
120+
def _determinePriority(self, event, state):
128121
if event == self.EVENT_STARTED:
129122
self.LastProgressUpdate = time.time()
130123
return 0
@@ -192,7 +185,7 @@ def _doSendNotification(self, targets, highProiroty, apnsData, androidData):
192185
# priority status update
193186
body = dict(
194187
targets=list(map(lambda x: {
195-
"fcmToken": x.ActivityAutoStartToken if x.ActivityAutoStartToken is not None and apnsData is not None and apnsData.get("event", None) == "start" else x.FcmToken,
188+
"fcmToken": x.FcmToken,
196189
"fcmTokenFallback": x.FcmFallbackToken,
197190
"instanceId": x.InstanceId
198191
}, targets)),
@@ -353,6 +346,13 @@ def _createApnsPushData(self, event, state):
353346

354347
elif event == self.EVENT_CANCELLED:
355348
liveActivityState = "cancelled"
349+
notificationTitle = "Print on %s cancelled" % self.PrinterName
350+
notificationTitleKey = "print_notification___cancelled_title"
351+
notificationTitleArgs = [self.PrinterName]
352+
notificationBody = state.get(NotificationSender.STATE_FILE_NAME, None)
353+
notificationBodyKey = state.get(NotificationSender.STATE_FILE_NAME, None)
354+
notificationBodyArgs = []
355+
notificationSound = "notification_filament_change.wav"
356356

357357
elif event == self.EVENT_DONE:
358358
notificationTitle = "%s is done!" % self.PrinterName
@@ -449,7 +449,7 @@ def _createApnsPushData(self, event, state):
449449
"loc-key": notificationBodyKey,
450450
"loc-args": notificationBodyArgs,
451451
},
452-
"sound": notificationSound
452+
# "sound": notificationSound -> We send a notification alongside because iOS doesn't play this sound reliably, especially with Apple Watch connected
453453
}
454454

455455
# Delete None values, causes issues with APNS
@@ -460,7 +460,7 @@ def _createApnsPushData(self, event, state):
460460
return data
461461

462462

463-
def _createActivityStartData(self, event, state, firstTarget):
463+
def _createActivityStartData(self, event, state):
464464
# Base: Activity state
465465
data = self._createActivityContentState(
466466
isEnd=False,
@@ -500,17 +500,8 @@ def _createActivityContentState(self, isEnd, state, liveActivityState):
500500
}
501501
}
502502

503-
504-
def _shouldPreferActivity(self, event):
505-
return event != self.EVENT_BEEP and event != self.EVENT_FIRST_LAYER_DONE and event != self.EVENT_THIRD_LAYER_DONE and event != self.EVENT_CUSTOM
506-
507-
508-
def _canUseNonActivity(self, event):
509-
return event != self.EVENT_PROGRESS and event != self.EVENT_PROGRESS and event != self.EVENT_RESUME and event != self.EVENT_TIME_PROGRESS
510-
511-
512-
def _getPushTargets(self, preferActivity, canUseNonActivity):
513-
Sentry.Info("SENDER", "Finding targets preferActivity=%s canUseNonActivity=%s" % (preferActivity, canUseNonActivity))
503+
def _getPushTargets(self, event):
504+
Sentry.Info("SENDER", "Finding targets for event=%s" % event)
514505
helper = AppStorageHelper.Get()
515506
apps = helper.GetAllApps()
516507
phones = {}
@@ -528,22 +519,24 @@ def pick_best_app(apps):
528519
ios = helper.GetIosApps(apps)
529520
android = helper.GetAndroidApps(apps)
530521

531-
# If we have an activity and we should prefer it, use it
532-
if len(activities) and preferActivity:
533-
return activities[0:1]
534-
535-
# If we have an iOS app and we can use non-activity targets, use it
536-
# This means iOS might not be picked at all if we only can use activity but no activity is available!
537-
elif len(ios) and canUseNonActivity:
538-
return ios[0:1]
522+
# For start events we can generate LiveActivity instances on the fly which will start a LiveActivity
523+
if event == self.EVENT_STARTED:
524+
for ios_app in ios:
525+
if ios_app.ActivityAutoStartToken:
526+
activities.append(ios_app.WithToken(ios_app.ActivityAutoStartToken))
539527

540-
# If we have any android devices, use all of them (might be watch + phone)
541-
elif len(android):
528+
if len(android):
529+
# If we have android...return any way. Handled all the same.
542530
return android
543-
544-
# Oh no!
531+
elif event in [self.EVENT_CUSTOM, self.EVENT_BEEP, self.EVENT_FIRST_LAYER_DONE, self.EVENT_THIRD_LAYER_DONE]:
532+
# If we have an event Live Activities can't handle send via notification
533+
return ios
534+
elif event in [self.EVENT_STARTED, self.EVENT_FILAMENT_REQUIRED, self.EVENT_USER_INTERACTION_NEEDED, self.EVENT_CANCELLED, self.EVENT_DONE, self.EVENT_ERROR]:
535+
# If we have a important event, send to all targets
536+
return activities + ios
545537
else:
546-
return []
538+
# Send only to activities, might be empty
539+
return activities
547540

548541
# Get apps per phone and flatten
549542
apps = list(map(lambda phone: pick_best_app(phone), phones.values()))

0 commit comments

Comments
 (0)