Skip to content

Commit 5b6bfcf

Browse files
Vetle444Vetle Finstad
andauthored
[CP] Fix iOS Touch gestures behind overlays (#908)
Co-authored-by: Vetle Finstad <finstad@Vetles-MacBook-Pro-2.local>
1 parent 62f47ea commit 5b6bfcf

9 files changed

Lines changed: 594 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## [60.2.17]
2+
- [Touch][iOS] Fixed scroll gestures on tappable rows getting stuck after dismissing context menus or picker popovers, and prevented taps behind open overlays from activating touch commands.
3+
14
## [60.2.16]
25
- [ImageCapture][iOS] Fixed intermittent black images in full-screen gallery previews by refreshing stream-backed sources for current and neighboring carousel items during position updates.
36

src/app/Playground/MainPage.xaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
Tapped="GoToCollectionViewTests" />
2828
<dui:NavigationListItem Title="ItemPicker Refresh Repro"
2929
Tapped="GoToItemPickerRefreshRepro" />
30+
<dui:NavigationListItem Title="Patient List Menu Fling Repro"
31+
Tapped="GoToPatientListMenuFlingRepro" />
32+
<dui:NavigationListItem Title="DatePicker Fling Repro"
33+
Tapped="GoToDatePickerFlingRepro" />
3034
<dui:NavigationListItem Title="Barcode Resume Repro (#1415)"
3135
Tapped="GoToBarcodeScanResumeRepro" />
3236
<dui:NavigationListItem Title="Barcode Resume Repro (Modal)"

src/app/Playground/MainPage.xaml.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ private void GoToItemPickerRefreshRepro(object sender, EventArgs e)
9393
Shell.Current.Navigation.PushAsync(new ItemPickerRefreshRepro());
9494
}
9595

96+
private void GoToPatientListMenuFlingRepro(object sender, EventArgs e)
97+
{
98+
Shell.Current.Navigation.PushAsync(new PatientListMenuFlingReproPage());
99+
}
100+
101+
private void GoToDatePickerFlingRepro(object sender, EventArgs e)
102+
{
103+
Shell.Current.Navigation.PushAsync(new DatePickerFlingReproPage());
104+
}
105+
96106
private void GoToCollectionViewTests(object sender, EventArgs e)
97107
{
98108
Shell.Current.Navigation.PushAsync(new CollectionViewTests());
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
using System.Collections.ObjectModel;
2+
using DIPS.Mobile.UI.Effects.Touch;
3+
using DIPS.Mobile.UI.Resources.Colors;
4+
using DIPS.Mobile.UI.Resources.Sizes;
5+
using DIPS.Mobile.UI.Resources.Styles;
6+
using DIPS.Mobile.UI.Resources.Styles.Label;
7+
using Colors = DIPS.Mobile.UI.Resources.Colors.Colors;
8+
using DuiDateAndTimePicker = DIPS.Mobile.UI.Components.Pickers.DateAndTimePicker.DateAndTimePicker;
9+
using DuiCollectionView = DIPS.Mobile.UI.Components.Lists.CollectionView;
10+
using DuiContentPage = DIPS.Mobile.UI.Components.Pages.ContentPage;
11+
using DuiDatePicker = DIPS.Mobile.UI.Components.Pickers.DatePicker.DatePicker;
12+
using DuiLabel = DIPS.Mobile.UI.Components.Labels.Label;
13+
using DuiRefreshView = DIPS.Mobile.UI.Components.Loading.RefreshView;
14+
using DuiTimePicker = DIPS.Mobile.UI.Components.Pickers.TimePicker.TimePicker;
15+
16+
namespace Playground.VetleSamples;
17+
18+
public class DatePickerFlingReproPage : DuiContentPage
19+
{
20+
private readonly ObservableCollection<DatePickerReproItem> m_items = new(
21+
Enumerable.Range(1, 80).Select(index => new DatePickerReproItem(index)));
22+
23+
private readonly DuiLabel m_statusLabel = new()
24+
{
25+
Style = Styles.GetLabelStyle(LabelStyle.UI200),
26+
Text = "No selection yet"
27+
};
28+
29+
public DatePickerFlingReproPage()
30+
{
31+
Title = "DatePicker Fling Repro";
32+
33+
var header = new Grid
34+
{
35+
Padding = new Thickness(
36+
Sizes.GetSize(SizeName.size_5),
37+
Sizes.GetSize(SizeName.size_4),
38+
Sizes.GetSize(SizeName.size_5),
39+
Sizes.GetSize(SizeName.size_2))
40+
};
41+
42+
header.Add(new DuiLabel
43+
{
44+
Text = "Picker rows (80)",
45+
Style = Styles.GetLabelStyle(LabelStyle.SectionHeader),
46+
VerticalTextAlignment = TextAlignment.Center
47+
});
48+
49+
var collectionView = new DuiCollectionView
50+
{
51+
ItemSpacing = Sizes.GetSize(SizeName.size_2),
52+
ShouldBounce = true,
53+
HasAdditionalSpaceAtTheEnd = true,
54+
ItemsSource = m_items,
55+
ItemTemplate = new DataTemplate(CreateDatePickerCell),
56+
EmptyView = m_statusLabel
57+
};
58+
59+
var refreshView = new DuiRefreshView
60+
{
61+
Content = collectionView,
62+
Command = new Command(() => SetStatus("Refresh completed"))
63+
};
64+
65+
refreshView.PropertyChanged += (_, args) =>
66+
{
67+
if (args.PropertyName == DuiRefreshView.IsRefreshingProperty.PropertyName && refreshView.IsRefreshing)
68+
{
69+
refreshView.IsRefreshing = false;
70+
}
71+
};
72+
73+
Grid.SetRow(refreshView, 1);
74+
75+
Content = new Grid
76+
{
77+
RowDefinitions =
78+
[
79+
new RowDefinition(GridLength.Auto),
80+
new RowDefinition(GridLength.Star)
81+
],
82+
Children =
83+
{
84+
header,
85+
refreshView
86+
}
87+
};
88+
}
89+
90+
private View CreateDatePickerCell()
91+
{
92+
var root = new Grid
93+
{
94+
ColumnDefinitions =
95+
[
96+
new ColumnDefinition(GridLength.Star),
97+
new ColumnDefinition(GridLength.Auto)
98+
],
99+
ColumnSpacing = Sizes.GetSize(SizeName.size_3),
100+
Padding = new Thickness(Sizes.GetSize(SizeName.size_3), Sizes.GetSize(SizeName.size_2)),
101+
BackgroundColor = Colors.GetColor(ColorName.color_surface_default)
102+
};
103+
104+
Touch.SetCommand(root, new Command(() => SetStatus("Date row tapped")));
105+
SemanticProperties.SetDescription(root, "Date row");
106+
107+
var textGrid = new Grid
108+
{
109+
RowDefinitions =
110+
[
111+
new RowDefinition(GridLength.Auto),
112+
new RowDefinition(GridLength.Auto)
113+
]
114+
};
115+
116+
var titleLabel = new DuiLabel
117+
{
118+
Style = Styles.GetLabelStyle(LabelStyle.UI300),
119+
MaxLines = 1,
120+
LineBreakMode = LineBreakMode.TailTruncation
121+
};
122+
titleLabel.SetBinding(Label.TextProperty, nameof(DatePickerReproItem.Title));
123+
124+
var subtitleLabel = new DuiLabel
125+
{
126+
Style = Styles.GetLabelStyle(LabelStyle.UI200),
127+
TextColor = Colors.GetColor(ColorName.color_text_subtle)
128+
};
129+
subtitleLabel.SetBinding(Label.TextProperty, nameof(DatePickerReproItem.Subtitle));
130+
131+
textGrid.Add(titleLabel);
132+
textGrid.Add(subtitleLabel, 0, 1);
133+
134+
var picker = CreatePicker();
135+
136+
root.Add(textGrid);
137+
root.Add(picker, 1);
138+
139+
return root;
140+
}
141+
142+
private View CreatePicker()
143+
{
144+
var datePicker = new DuiDatePicker
145+
{
146+
IgnoreLocalTime = true,
147+
HorizontalOptions = LayoutOptions.End,
148+
VerticalOptions = LayoutOptions.Center
149+
};
150+
datePicker.SetBinding(DuiDatePicker.SelectedDateProperty, nameof(DatePickerReproItem.Date));
151+
datePicker.SelectedDateCommand = new Command<DateTime?>(date =>
152+
SetStatus(date.HasValue ? $"Date selected: {date.Value:yyyy-MM-dd}" : "Date cleared"));
153+
154+
var timePicker = new DuiTimePicker
155+
{
156+
HorizontalOptions = LayoutOptions.End,
157+
VerticalOptions = LayoutOptions.Center
158+
};
159+
timePicker.SetBinding(DuiTimePicker.SelectedTimeProperty, nameof(DatePickerReproItem.Time));
160+
timePicker.SelectedTimeCommand = new Command<TimeSpan?>(time =>
161+
SetStatus(time.HasValue ? $"Time selected: {time.Value:hh\\:mm}" : "Time cleared"));
162+
163+
var dateAndTimePicker = new DuiDateAndTimePicker
164+
{
165+
IgnoreLocalTime = true,
166+
HorizontalOptions = LayoutOptions.End,
167+
VerticalOptions = LayoutOptions.Center
168+
};
169+
dateAndTimePicker.SetBinding(DuiDateAndTimePicker.SelectedDateTimeProperty, nameof(DatePickerReproItem.DateAndTime));
170+
dateAndTimePicker.SelectedDateTimeCommand = new Command<DateTime?>(dateTime =>
171+
SetStatus(dateTime.HasValue ? $"Date and time selected: {dateTime.Value:yyyy-MM-dd HH:mm}" : "Date and time cleared"));
172+
173+
datePicker.SetBinding(IsVisibleProperty, nameof(DatePickerReproItem.IsDatePicker));
174+
timePicker.SetBinding(IsVisibleProperty, nameof(DatePickerReproItem.IsTimePicker));
175+
dateAndTimePicker.SetBinding(IsVisibleProperty, nameof(DatePickerReproItem.IsDateAndTimePicker));
176+
177+
return new Grid
178+
{
179+
Children =
180+
{
181+
datePicker,
182+
timePicker,
183+
dateAndTimePicker
184+
}
185+
};
186+
}
187+
188+
private void SetStatus(string status)
189+
{
190+
m_statusLabel.Text = status;
191+
Console.WriteLine(status);
192+
}
193+
194+
private sealed class DatePickerReproItem(int index)
195+
{
196+
public string Title { get; } = $"Picker row {index:00}";
197+
public string Subtitle { get; } = GetSubtitle(index);
198+
public DateTime Date { get; set; } = DateTime.Today.AddDays(index);
199+
public TimeSpan Time { get; set; } = new(8 + index % 10, index % 60, 0);
200+
public DateTime DateAndTime { get; set; } = DateTime.Today.AddDays(index).AddHours(8 + index % 10).AddMinutes(index % 60);
201+
public bool IsDatePicker => index % 3 == 1;
202+
public bool IsTimePicker => index % 3 == 2;
203+
public bool IsDateAndTimePicker => index % 3 == 0;
204+
205+
private static string GetSubtitle(int index) => (index % 3) switch
206+
{
207+
1 => "DatePicker - open, dismiss, then scroll",
208+
2 => "TimePicker - open, dismiss, then scroll",
209+
_ => "DateAndTimePicker - open, dismiss, then scroll"
210+
};
211+
}
212+
}

0 commit comments

Comments
 (0)