Skip to content

Conversation

Odonno
Copy link
Contributor

@Odonno Odonno commented Jul 25, 2017

Linked to #1080

First version of the In App Notification control. The control is very flexible : devs can update Background color, Border, Padding, Margin. By default, the control looks like the Microsoft Edge in-app notification.

Need more things before merging :

  • Animations
  • Add ability to use DataTemplate
  • Add some default DataTemplates (just Text, Yes/No buttons, ...) and should be responsive (Adaptative design) EDIT : cannot make default DataTemplate because they require code-behind variables (text value, click event or command button)
  • Documentation
  • Dismiss button should be optional (DependencyProperty)
  • Add more examples (with DropShadow, vscode-like notification)
  • Add duration
@skendrot
Copy link
Contributor

Should this follow the ContentDialog pattern and have PrimaryButton* and SecondaryButton*?

@skendrot
Copy link
Contributor

Should this be a type of Flyout? eg: NotificationFlyout

@skendrot
Copy link
Contributor

I would expect a control like this to be similar to Toastr

@Odonno
Copy link
Contributor Author

Odonno commented Jul 26, 2017

@skendrot I don't know. It could have one button, two buttons, three buttons, no button, images, whatever. I suppose we are replicating the behavior of Toast notification in some sort of way.

@Odonno
Copy link
Contributor Author

Odonno commented Jul 26, 2017

Yes, looks pretty much like a Flyout but not sure we can inherit from it.

@skendrot
Copy link
Contributor

Flyout is not sealed and has a public ctor, so shouldn't be a problem

@Odonno
Copy link
Contributor Author

Odonno commented Jul 26, 2017

You can perfectly create almost anything that you see in toastr. Like I said, my implementation came from Microsoft Edge in-app notification.

@skendrot
Copy link
Contributor

What do you mean? I don't see a way to say it's a warning message or to set the duration of the notification or many other features

@Odonno
Copy link
Contributor Author

Odonno commented Jul 26, 2017

@skendrot You can update properties the way you want :

  • Background color for warning or error message
  • Vertical and Horizontal alignment to set the position
  • Call Dismiss using a Timer for notification duration

Of course, these features are not natives and devs have to deal with it. Unless someone have a different opinion. :)

@skendrot
Copy link
Contributor

Not exactly what I was referring too 😆

@Odonno
Copy link
Contributor Author

Odonno commented Jul 26, 2017

One question: Can we add DropShadow on a Flyout? Or ContentDialog?

@skendrot
Copy link
Contributor

For a flyout you define the flyout presenter. I'm sure you could do it in there.

@tibitoth
Copy link
Contributor

repost my question here:

Can the design of in-app notification be like in the Visual Studio Code?

image

@Odonno
Copy link
Contributor Author

Odonno commented Aug 12, 2017

@nmetulev It should work now.

@Vijay-Nirmal
Copy link
Contributor

@Odonno I found two issues

  1. Doesn't work properly in StackPanel. I understand the reason for that. Maybe you should recommend the dev to use Grid instead of StackPanel in the Doc
  2. How to set the InAppNotification to Pop from Top to Bottom instead of Bottom to Top?
@Odonno
Copy link
Contributor Author

Odonno commented Aug 12, 2017

@Vijay-Nirmal

  1. Yes. I work with the Grid because it is the the main UI container in Windows XAML application. The thing is that devs can put the control everywhere so if they want to put it in a StackPanel of 700px Width and 200px height, they can. It may not be the most efficient way to use this control it is one of the many potential uses of the control. Not sure if adding a word on this is useful.
  2. If you want to change the animation, you'll have to change the RenderTransformOrigin property. By default, it is Bottom to Top but you can invert Y value so it goes in the opposite direction. Check the vscode-like example.
@Vijay-Nirmal
Copy link
Contributor

@Odonno I think you can add RenderTransformOrigin method to change Pop Up direction in the Doc (OR) Dedicated property would be nice

@Odonno
Copy link
Contributor Author

Odonno commented Aug 12, 2017

@Vijay-Nirmal I would like a Property but not sure how to do it. The RenderTransformOrigin allows me to set animation the way I want. But it may not be the best option.

I can add a description on how to change the animation using RenderTransformOrigin in the docs.

Copy link
Contributor

@nmetulev nmetulev left a comment

Choose a reason for hiding this comment

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

I noticed the animation does not run the first time the control is shown, it just becomes visible, could you take a look?

I tried the sample code (with template) from the code bind file in a blank new app and the app crashed. I generated the nugets and used them in the app to test.

}

_dismissButton = (Button)GetTemplateChild(DismissButtonPart);
_dismissButton.Visibility = ShowDismissButton ? Visibility.Visible : Visibility.Collapsed;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this move in the null check block below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That might be better. :)

</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<Grid x:Name="RootGrid" SizeChanged="RootGrid_SizeChanged">
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the SizeChanged event?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do not remember, I think this is a old version. Will update it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok. I remember. I made it that way to be able to detect the change of the Grid Width (not the App Width) so I can create a StateTrigger based on the container Size, not the App Size.

I do not know if there is a better option because it will crash if you do not have this code in your code-behind:

public bool IsRootGridActualWidthLargerThan700 { get; set; } private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e) { // When the root part size of the In App Notification template changed, we should apply VisualState bool newValue = e.NewSize.Width > 700; if (IsRootGridActualWidthLargerThan700 != newValue) { IsRootGridActualWidthLargerThan700 = newValue; OnPropertyChanged(nameof(IsRootGridActualWidthLargerThan700)); } } 
Copy link
Contributor

Choose a reason for hiding this comment

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

Is that required for an example? Should it work without it?

Copy link
Contributor Author

@Odonno Odonno Aug 19, 2017

Choose a reason for hiding this comment

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

To be clear, the DataTemplate available in the bind code file is a specific template that handle responsive design based on the container Width. And to make it work, I need a property that tell what StateTrigger I should use, in this case I used a boolean in the code behind.

Of course, it is not the default behavior and you can perfectly use the control without extra code :

<controls:InAppNotification x:Name="ExampleInAppNotification" /> 

And then use .ShowAsync() method.

My objective with the DataTemplate was to provide a more complete example that mimic MS Edge notification with buttons (Horizontal Orientation when Width > 700px, Vertical Orientation otherwise).

Should I remove this template from the code file?

Copy link
Contributor

Choose a reason for hiding this comment

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

My thoughts on this are to have a simple template that doesn't complicate the mechanics of the control and shows the minimum needed to try the control. We could always have both?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nmetulev I can leave the complete Templates in the page (with buttons, with DropShadow, etc..) and add a simple template in the code file. I'll update it.

@Odonno
Copy link
Contributor Author

Odonno commented Aug 17, 2017

@nmetulev Another question: Is it interesting and how can we integrate Styles (like the vscode-like notification template) so developers can reuse them without copying the code everytime in their apps? My long-term goal would be to gather some styles devs are used to work with (like MS Edge-like, vscode-like and some more to come).

@nmetulev
Copy link
Contributor

@Odonno, I agree, it would be interesting to provide common style after the control is available to see what requests devs have


## Syntax

The control should be placed where you want your notification to be displayed in the page, generally in the root grid.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should tell the dev to put this control in the Bottom of the grid because If they put at the top other controls will overlay this control.

Copy link
Contributor

Choose a reason for hiding this comment

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

Or use the ol' Canvas.ZIndex="99999"

Copy link
Contributor

@Vijay-Nirmal Vijay-Nirmal Aug 19, 2017

Choose a reason for hiding this comment

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

or int.MaxValue

Copy link
Contributor

Choose a reason for hiding this comment

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

I think Canvas.ZIndex has a limit below Int.MaxValue, possibly 16 Bit, I remember, because once I entered a few too many 9s. Unless I added 11 9s.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Vijay-Nirmal By default, the position is set to Bottom because I mimic the original component from MS Edge. But of course, you can place it at the Top or at the Center, it depends on the dev intention.

Copy link
Contributor

@Vijay-Nirmal Vijay-Nirmal Aug 19, 2017

Choose a reason for hiding this comment

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

@Odonno What do you mean by "By default, the position is set to Bottom"?
I think we can set Canvas.ZIndex by default because Notification will always be displayed about all controls. If devs want to change it they can easily change it by setting Canvas.ZIndex to 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Vijay-Nirmal If you put the control at the last position of the parent container, it will be have priority over other controls, if you do not use Canvas.ZIndex. I can add this to the description of the control if you think it is relevant.

Copy link
Contributor

@Vijay-Nirmal Vijay-Nirmal Aug 19, 2017

Choose a reason for hiding this comment

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

@Odonno I think we should either say it in Doc or set a default Canvas.ZIndex value

Copy link
Contributor

Choose a reason for hiding this comment

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

We can always add a note in the docs if that will make things easier. How about:

Note: Since the control is part of the page visual tree, it will render in the order it was added in the parent control, and might be hidden by other elements. For the control to render on top of other elements, add it as the last child of the parent control or set the Canvas.ZIndex to a high number.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@IbraheemOsama
Copy link
Member

Will review this

DefaultStyleKey = typeof(InAppNotification);
}

protected override void OnApplyTemplate()
Copy link
Member

Choose a reason for hiding this comment

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

missing documentations /// <inheritdoc />

/// <param name="text">Text used as the content of the notification</param>
/// <param name="duration">Displayed duration of the notification in ms (less or equal 0 means infinite duration)</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task ShowAsync(string text, int duration = 0)
Copy link
Member

Choose a reason for hiding this comment

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

This function could be done this way
public Task ShowAsync(string text, int duration = 0) { ContentTemplate = null; Content = text; return ShowAsync(duration); }
It's better because you're giving more control to the caller when to await instead of forcing the await in your function.
also this is applied to the rest of ShowAsync

Copy link
Member

Choose a reason for hiding this comment

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

except of the first ShowAsync :) you can't do that to it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems fair.

Copy link
Member

@IbraheemOsama IbraheemOsama left a comment

Choose a reason for hiding this comment

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

The on applyTemplate is missing the documentations.
regarding the async functions feel free to do it or not :) but it's just a better approach.

Copy link
Member

@michael-hawker michael-hawker left a comment

Choose a reason for hiding this comment

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

Excited to see this first version go in. I think if we want the new sample app to work we'll need the opened event though.

<TextBlock Text="*if duration is less or equal 0, the notification will never be dismissed" />
</StackPanel>

<Button x:Name="ShowNotificationWithRandomTextButton"
Copy link
Member

Choose a reason for hiding this comment

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

These types of buttons in the sample should instead be registered as commands with Shell.Current.RegisterNewCommand.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know how to do this. From what sample control should I take inspiration?

Copy link
Contributor

Choose a reason for hiding this comment

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

Take a look at this. It simply adds a button in the shell instead of having to add one in your sample.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I'm on it.

ExampleVSCodeInAppNotification.Dismiss();
SetDefaultControlTemplate();

var grid = new Grid();
Copy link
Member

Choose a reason for hiding this comment

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

Can you add this as a template like the other examples?

This is a large example and templates work a lot better in the new live XAML world.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to show different examples : so there is one with XAML DataTemplate and another one using C#.

Copy link
Member

Choose a reason for hiding this comment

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

People using the app won't see this code though, should it be in the .bind Code File instead?


<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Content="Action 1"
Click="Action1Button_Click"
Copy link
Member

Choose a reason for hiding this comment

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

Trying to think how this click event will work in the new sample app...

Since these are more geared to individual notifications vs a central service, I'd like to see an Opened/Opening event like FlyoutBase has. Then we can grab the buttons in that event and register handlers for the sample app.

/// <summary>
/// In App Notification defines a control to show local notification in the app.
/// </summary>
public partial class InAppNotification
Copy link
Member

Choose a reason for hiding this comment

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

Could we also have events for Opened/Opening/Closed/Closing like ContentDialog / FlyoutBase?

I would see closed/closing fire whenever it disappears (including dismiss or timeout) vs. the Dismiss event which fires when the user explicitly dismisses the notification.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to figure out how to inherits from Flyout/FlyoutPresenter. For the dismiss event, I can easily add an argument whether the user clicked on a button or if timeout.

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think there is a need to inherit from Flyout. You can add custom events. PullToRefeshListView events come to mind as an example.

@Odonno
Copy link
Contributor Author

Odonno commented Aug 23, 2017

@nmetulev I leave it to you.

@IbraheemOsama IbraheemOsama merged commit 2fa5a16 into CommunityToolkit:dev Aug 23, 2017
@Odonno Odonno deleted the inAppNotifications branch August 24, 2017 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment