Skip to content
This repository has been archived by the owner on Dec 28, 2023. It is now read-only.

Add ContentPopup #276

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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 src/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static void Init()
{
if (IsInitialized) return;
IsInitialized = true;
ContentPopup.RendererFunc = () => new ContentPopupRenderer();
Copy link
Contributor

Choose a reason for hiding this comment

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

where this technique come from?

Copy link
Collaborator

Choose a reason for hiding this comment

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

come from me 😉

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
ContentPopup.RendererFunc = () => new ContentPopupRenderer();
ContentPopup.CreateRenderer = () => new ContentPopupRenderer();

}

public static void Init(string apiKey)
Expand Down
141 changes: 141 additions & 0 deletions src/Tizen.Wearable.CircularUI.Forms.Renderer/ContentPopupRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Flora License, Version 1.1 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://floralicense.org/license/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using System.ComponentModel;
using Tizen.Wearable.CircularUI.Forms;
using Tizen.Wearable.CircularUI.Forms.Renderer;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Tizen;
using XForms = Xamarin.Forms.Forms;

[assembly: ExportRenderer(typeof(ContentPopup), typeof(ContentPopupRenderer))]

namespace Tizen.Wearable.CircularUI.Forms.Renderer
{
public class ContentPopupRenderer : IContentPopupRenderer
{
ElmSharp.Popup _popup;
ContentPopup _element;

public void SetElement(Element element)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
public void SetElement(Element element)
public void SetElement(ContentPopup element)

Because it is ContentPopupRenderer

{
if (element.Parent == null)
element.Parent = Application.Current;
element.PropertyChanged += OnElementPropertyChanged;
_element = element as ContentPopup;

UpdateContent();
UpdateIsShow();
}

public ContentPopupRenderer()
{
_popup = new ElmSharp.Popup(XForms.NativeParent);
_popup.Style = "circle";

_popup.BackButtonPressed += OnBackButtonPressed;
_popup.Dismissed += OnDismissed;
}

~ContentPopupRenderer()
{
Dispose(false);
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

public void Dismiss()
{
_popup?.Hide();
}

public void Show()
{
_popup?.Show();
}

protected void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == ContentPopup.ContentProperty.PropertyName)
{
UpdateContent();
}
if (e.PropertyName == ContentPopup.IsShowProperty.PropertyName)
{
UpdateIsShow();
}
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_popup != null)
{
_popup.BackButtonPressed -= OnBackButtonPressed;
_popup.Dismissed -= OnDismissed;
_popup.Unrealize();
_popup = null;
}
if (_element != null)
{
_element.PropertyChanged -= OnElementPropertyChanged;
_element = null;
}
}
}

void OnBackButtonPressed(object sender, EventArgs e)
{
_element.SendBackButtonPressed();
}

void OnDismissed(object sender, EventArgs e)
{
_element.SendDismissed();
Dispose();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do you dispose it?

}

void UpdateContent()
{
if (_element.Content != null)
{
var renderer = Platform.GetOrCreateRenderer(_element.Content);
(renderer as LayoutRenderer)?.RegisterOnLayoutUpdated();
var native = renderer.NativeView;
native.MinimumHeight = 360;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do not use static value 360
How about use align and weight?

native.AlignmentX= -1;
native.AlignmentY= -1;
native.WeightX = 1;
native.WeightY = 1;

_popup.SetContent(native, false);
}
else
{
_popup.SetContent(null, false);
}
}

void UpdateIsShow()
{
if (_element.IsShow)
Show();
else
Dismiss();
}
}
}
158 changes: 158 additions & 0 deletions src/Tizen.Wearable.CircularUI.Forms/ContentPopup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Flora License, Version 1.1 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://floralicense.org/license/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace Tizen.Wearable.CircularUI.Forms
{
/// <summary>
/// The ContentPopup is a Popup, which allows you to customize the View to be displayed.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public class ContentPopup : Element, IDisposable
{
IContentPopupRenderer _renderer;

/// <summary>
/// For internal use.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static Func<IContentPopupRenderer> RendererFunc { get; set; } = null;

/// <summary>
/// BindableProperty. Identifies the Content bindable property.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public static readonly BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(View), typeof(ContentPopup), null, propertyChanged: (b, o, n) => ((ContentPopup)b).UpdateContent());

/// <summary>
/// BindableProperty. Identifies the IsShow bindable property.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public static readonly BindableProperty IsShowProperty = BindableProperty.Create(nameof(IsShow), typeof(bool), typeof(ContentPopup), false, propertyChanged:(b, o, n) => ((ContentPopup)b).UpdateRenderer());

/// <summary>
/// Occurs when the device's back button is pressed.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public event EventHandler BackButtonPressed;

/// <summary>
/// Occurs when the popup is dismissed.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public event EventHandler Dismissed;

/// <summary>
/// Gets or sets content view of the Popup.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public View Content
{
get { return (View)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}

/// <summary>
/// Gets or sets the popup is shown.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public bool IsShow
{
get { return (bool)GetValue(IsShowProperty); }
set { SetValue(IsShowProperty, value); }
}

/// <summary>
/// Shows the popup.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public void Show()
Copy link
Collaborator

@myroot myroot Apr 26, 2020

Choose a reason for hiding this comment

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

How about rename to Open?
and How about return Task that indicate closing timing

        TaskCompletionSource<bool> _tcsForDismiss;
        public Task Open()
        {
            IsShow = true;
            _tcsForDismiss = new TaskCompletionSource<bool>();
            return _tcsForDismiss.Task;
        }

        public void SendDismissed()
        {
            Dismissed?.Invoke(this, EventArgs.Empty);
            _tcsForDismiss?.TrySetResult(true);
        }

If you provide Task we can easily use

  using (var popup = new ContentPopup()) {
     poup.Content = new StackLayout { ... };
     _ = await popup.Open();
  }

{
IsShow = true;
}

/// <summary>
/// Dismisses the popup.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public void Dismiss()
{
IsShow = false;
}

/// <summary>
/// For internal use.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public void SendDismissed()
{
Dismissed?.Invoke(this, EventArgs.Empty);
}

/// <summary>
/// For internal use.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public void SendBackButtonPressed()
{
BackButtonPressed?.Invoke(this, EventArgs.Empty);
}

/// <summary>
/// Dispose the popup.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public void Dispose()
{
Dispose(true);
}

protected virtual void Dispose(bool disposing)
{
if (disposing && _renderer != null)
{
_renderer.Dispose();
_renderer = null;
}
}

protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (Content != null)
SetInheritedBindingContext(Content, BindingContext);
}

void UpdateContent()
{
if (Content != null)
OnChildAdded(Content);
}

void UpdateRenderer()
{
if (_renderer == null)
{
_renderer = RendererFunc();
_renderer.SetElement(this);
}
}

}
}
34 changes: 34 additions & 0 deletions src/Tizen.Wearable.CircularUI.Forms/IContentPopupRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Flora License, Version 1.1 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://floralicense.org/license/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using Xamarin.Forms;

namespace Tizen.Wearable.CircularUI.Forms
{
/// <summary>
/// Base interface for ContentPopup renderer.
/// </summary>
/// <since_tizen> 4 </since_tizen>
public interface IContentPopupRenderer : IDisposable
{
/// <summary>
/// Sets the Element associated with this renderer.
/// </summary>
/// <param name="element">New element.</param>
void SetElement(Element element);
}
}
2 changes: 1 addition & 1 deletion src/Tizen.Wearable.CircularUI.Forms/ITwoButtonPopup.cs
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ internal interface ITwoButtonPopup
/// <since_tizen> 4 </since_tizen>
void Dismiss();
}
}
}
43 changes: 43 additions & 0 deletions test/WearableUIGallery/WearableUIGallery/TC/TCContentPopup.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="WearableUIGallery.TC.TCContentPopupTest"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WearableUIGallery"
xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=Tizen.Wearable.CircularUI.Forms"
w:CircleSurfaceEffectBehavior.RotaryFocusObject="{x:Reference myscroller}">
<ContentPage.Behaviors>
<w:CircleSurfaceEffectBehavior/>
</ContentPage.Behaviors>
<ContentPage.Content>
<w:CircleScrollView x:Name="myscroller" Orientation="Vertical">
<StackLayout Padding="0,50,0,50">
<Label
x:Name="label1"
HorizontalOptions="CenterAndExpand"
Text="ContentPopup test"
VerticalOptions="Start" />
<Button
AutomationId="dismisstest1"
x:Name="button1"
Clicked="OnContentPopupDismissBackKeyClicked"
FontSize="Small"
HeightRequest="50"
HorizontalOptions="Center"
Text="Dismiss test 1"
VerticalOptions="CenterAndExpand"
WidthRequest="300" />
<Button
AutomationId="dismisstest2"
x:Name="button2"
Clicked="OnContentPopupDismissButtonClicked"
FontSize="Small"
HeightRequest="50"
HorizontalOptions="Center"
Text="Dismiss test 2"
VerticalOptions="CenterAndExpand"
WidthRequest="300" />
</StackLayout>
</w:CircleScrollView>
</ContentPage.Content>
</ContentPage>
Loading