diff --git a/haxe/ui/animation/AnimationSequence.hx b/haxe/ui/animation/AnimationSequence.hx new file mode 100644 index 000000000..69a24288d --- /dev/null +++ b/haxe/ui/animation/AnimationSequence.hx @@ -0,0 +1,41 @@ +package haxe.ui.animation; + +class AnimationSequence { + public var onComplete:Void->Void = null; + public var builders:Array = []; + + private var _activeBuilders:Array; + + public function new() { + + } + + public function add(builder:AnimationBuilder) { + builders.push(builder); + } + + private function onAnimationComplete() { + _activeBuilders.pop(); + if (_activeBuilders.length == 0) { + if (onComplete != null) { + onComplete(); + } + } + } + + public function play() { + if (builders.length == 0) { + if (onComplete != null) { + onComplete(); + } + return; + } + _activeBuilders = builders.copy(); + for (builder in builders) { + builder.onComplete = onAnimationComplete; + } + for (builder in builders) { + builder.play(); + } + } +} \ No newline at end of file diff --git a/haxe/ui/events/NotificationEvent.hx b/haxe/ui/events/NotificationEvent.hx new file mode 100644 index 000000000..c31f3c835 --- /dev/null +++ b/haxe/ui/events/NotificationEvent.hx @@ -0,0 +1,23 @@ +package haxe.ui.events; + +import haxe.ui.notifications.Notification; + +class NotificationEvent extends UIEvent { + public static final SHOWN:EventType = EventType.name("notificationshown"); + public static final HIDDEN:EventType = EventType.name("notificationhidden"); + public static final ACTION:EventType = EventType.name("notificationaction"); + + public var notification:Notification = null; + + public override function clone():NotificationEvent { + var c:NotificationEvent = new NotificationEvent(this.type); + c.notification = this.notification; + c.type = this.type; + c.bubble = this.bubble; + c.target = this.target; + c.data = this.data; + c.canceled = this.canceled; + postClone(c); + return c; + } +} \ No newline at end of file diff --git a/haxe/ui/notifications/Notification.hx b/haxe/ui/notifications/Notification.hx index 5ad311614..c9955088d 100644 --- a/haxe/ui/notifications/Notification.hx +++ b/haxe/ui/notifications/Notification.hx @@ -2,6 +2,9 @@ package haxe.ui.notifications; import haxe.ui.components.Button; import haxe.ui.containers.VBox; +import haxe.ui.events.MouseEvent; +import haxe.ui.events.NotificationEvent; +import haxe.ui.notifications.NotificationData.NotificationActionData; @:xml(' @@ -70,13 +73,28 @@ class Notification extends VBox { actionsFooter.hide(); } else { actionsContainer.removeAllComponents(); - for (actionText in _notificationData.actions) { + for (actionData in _notificationData.actions) { var button = new Button(); - button.text = actionText; + button.text = actionData.text; + button.icon = actionData.icon; + button.userData = actionData; + button.registerEvent(MouseEvent.CLICK, onActionButton); actionsContainer.addComponent(button); } actionsFooter.show(); } return value; } + + private function onActionButton(event:MouseEvent) { + var event = new NotificationEvent(NotificationEvent.ACTION); + event.notification = this; + dispatch(event); + NotificationManager.instance.dispatch(event, this); + + var actionData:NotificationActionData = event.target.userData; + if (actionData.callback != null) { + actionData.callback(actionData); + } + } } \ No newline at end of file diff --git a/haxe/ui/notifications/NotificationData.hx b/haxe/ui/notifications/NotificationData.hx index 81e0a1bda..785c857d7 100644 --- a/haxe/ui/notifications/NotificationData.hx +++ b/haxe/ui/notifications/NotificationData.hx @@ -1,11 +1,19 @@ package haxe.ui.notifications; +import haxe.ui.util.Variant; + typedef NotificationData = { var body:String; @:optional var title:String; @:optional var icon:String; - @:optional var actions:Array; + @:optional var actions:Array; @:optional var expiryMs:Int; @:optional var type:NotificationType; @:optional var styleNames:String; +} + +typedef NotificationActionData = { + @:optional var text:String; + @:optional var icon:Variant; + @:optional var callback:NotificationActionData->Void; } \ No newline at end of file diff --git a/haxe/ui/notifications/NotificationManager.hx b/haxe/ui/notifications/NotificationManager.hx index 352ece1b4..1f4cd8f63 100644 --- a/haxe/ui/notifications/NotificationManager.hx +++ b/haxe/ui/notifications/NotificationManager.hx @@ -1,13 +1,17 @@ package haxe.ui.notifications; -import haxe.ui.util.Timer; import haxe.ui.Toolkit; import haxe.ui.animation.AnimationBuilder; +import haxe.ui.animation.AnimationSequence; import haxe.ui.core.Screen; +import haxe.ui.events.NotificationEvent; +import haxe.ui.events.UIEvent; +import haxe.ui.util.EventDispatcher; +import haxe.ui.util.Timer; using haxe.ui.animation.AnimationTools; -class NotificationManager { +class NotificationManager extends EventDispatcher { private static var _instance:NotificationManager; public static var instance(get, null):NotificationManager; private static function get_instance():NotificationManager { @@ -24,9 +28,7 @@ class NotificationManager { private static var DEFAULT_EXPIRY:Int = 3000; public var maxNotifications:Int = -1; - - private function new() { - } + public var animationFn:Array->Array = AnimateFromBottom; private var _timer:Timer = null; private function startTimer() { @@ -70,8 +72,8 @@ class NotificationManager { if (notificationData.expiryMs == null) { notificationData.expiryMs = DEFAULT_EXPIRY; } - } else { - notificationData.expiryMs = -1; // we'll assume if there are actions we dont want it to expire + } else if (notificationData.expiryMs == null) { + notificationData.expiryMs = -1; // we'll assume if there are actions we dont want it to expire by default } var notification = new Notification(); @@ -113,6 +115,11 @@ class NotificationManager { _isAnimating = true; notification.fadeOut(function () { + var event = new NotificationEvent(NotificationEvent.HIDDEN); + event.notification = notification; + notification.dispatch(event); + dispatch(event, notification); + _isAnimating = false; _currentNotifications.remove(notification); Screen.instance.removeComponent(notification); @@ -129,10 +136,9 @@ class NotificationManager { }); } } - _currentNotifications.insert(0, notification); + notification.opacity = 0; Screen.instance.addComponent(notification); - notification.validateNow(); Toolkit.callLater(function () { notification.validateNow(); var scx = Screen.instance.width; @@ -146,6 +152,12 @@ class NotificationManager { notification.left = scx - notification.width - GUTTER_SIZE; notification.top = baseline - notification.height; + var event = new NotificationEvent(NotificationEvent.SHOWN); + event.notification = notification; + notification.dispatch(event); + dispatch(event, notification); + + _currentNotifications.insert(0, notification); positionNotifications(); }); @@ -163,47 +175,44 @@ class NotificationManager { if (_isAnimating == true) { return; } + _isAnimating = true; + + var sequence = new AnimationSequence(); + var builders = animationFn(_currentNotifications); + for (builder in builders) { + sequence.add(builder); + } + + sequence.onComplete = function() { + _isAnimating = false; + if (_removeQueue.length > 0) { + popNotification(_removeQueue.shift()); + } else if (_addQueue.length > 0) { + pushNotification(_addQueue.shift()); + } + } + sequence.play(); + } + + public static function AnimateFromBottom(notifications:Array):Array { + var builders = []; + var scy = Screen.instance.height; - var baseline = scy - GUTTER_SIZE; + var baselineY = scy - GUTTER_SIZE; - var builder:AnimationBuilder = null; - var builders:Array = []; - for (notification in _currentNotifications) { - builder = new AnimationBuilder(notification); + for (notification in notifications) { + var builder = new AnimationBuilder(notification); builder.setPosition(0, "top", Std.int(notification.top), true); - builder.setPosition(100, "top", Std.int(baseline - notification.height), true); + builder.setPosition(100, "top", Std.int(baselineY - notification.height), true); if (notification.opacity == 0) { builder.setPosition(0, "opacity", 0, true); builder.setPosition(100, "opacity", 1, true); } builders.push(builder); - baseline -= (notification.height + SPACING); - } - - if (builders.length > 0) { - builder.onComplete = function () { - _isAnimating = false; - /* - if (_addQueue.length > 0) { - pushNotification(_addQueue.shift()); - } else if (_removeQueue.length > 0) { - popNotification(_removeQueue.shift()); - } - */ - if (_removeQueue.length > 0) { - popNotification(_removeQueue.shift()); - } - if (_addQueue.length > 0) { - pushNotification(_addQueue.shift()); - } - } - - for (builder in builders) { - builder.play(); - } - } else { - _isAnimating = false; + baselineY -= (notification.height + SPACING); } + + return builders; } } \ No newline at end of file