Xamarin UI Test Android Date Picker (On Hold) - xamarin

I'm working with Xamarin UI Test (1.0.0). I'm trying to write an extension method that will update the selected date.
Here is what I wrote so far. It works with iOS and Android 4.x. it does not work with Android 5.x.
public static void EnterDate(this IApp app, string datePickerStyleId, DateTime date)
{
var array = app.Query(datePickerStyleId);
if (array.Length == 0)
return;
foreach (var picker in array)
{
var newMonth = date.ToString("MMM");
var newDay = date.Day.ToString();
var newYear = date.Year.ToString();
if (app.IsAndroid())
{
app.Tap(picker.Label);
//if device OS > 5 try scrolll up
app.Repl();
app.Screenshot("Date Picker");
app.Tap("month");
app.EnterText(newMonth);
app.PressEnter();
app.Tap("day");
app.EnterText(newDay);
app.PressEnter();
app.Tap("year");
app.EnterText(newYear);
app.PressEnter();
app.ClickDone();
app.Screenshot("Page After Changing Date");
app.ClickButton("Ok");
}
else if (app.IsIOS())
{
app.Tap(picker.Id);
app.Screenshot("Date Picker");
var currentDate = picker.Text;
var split = currentDate.Split(' ');
var currentMonth = split[0];
var currentDay = split[1].Remove(split[1].Length - 1);
var currentYear = split[2];
if (!newMonth.Equals(currentMonth))
{
app.Tap(newMonth);
}
if (!newDay.Equals(currentDay))
{
app.Tap(newDay);
}
if (!newYear.Equals(currentYear))
{
app.Tap(newYear);
}
app.ClickButton("Done");
}
}
}
The problem that I'm running into is that I can't figure out how to select a certain date. App.ScrollUp()/.ScrollDown() do work to navigate to different months. Although, I haven't found to determine the current month and then pick a day. Here is the output from the tree command of the Repl() tool.
tree [[object CalabashRootView] > ... > FrameLayout] [FrameLayout] id: "content" [LinearLayout] id: "parentPanel" [FrameLayout] id: "customPanel" [FrameLayout] id: "custom" [DatePicker > LinearLayout] id: "datePicker" [LinearLayout] id: "day_picker_selector_layout"
[TextView] id: "date_picker_header" text: "Thursday"
[LinearLayout] id: "date_picker_month_day_year_layout"
[LinearLayout] id: "date_picker_month_and_day_layout", label: "August 6"
[TextView] id: "date_picker_month" text: "AUG"
[TextView] id: "date_picker_day" text: "6"
[TextView] id: "date_picker_year" text: "2015"
[AccessibleDateAnimator > ... > SimpleMonthView] id: "animator", label: "Month grid of days: August 6"
[LinearLayout] id: "buttonPanel"
[Button] id: "button2" text: "Cancel"
[Button] id: "button1" text: "OK"
Does anybody know or have a method to select the date for Xamarin UI test that will work on iOS and Android (4.x and 5.x)?

Related

Compare Times to get active time from data

Simulator Screenshot
In the example above, I have a data model that contains various times for an Itinerary that will be displayed. I would like to highlight the current time with a filled circle:
struct SampleModel: Identifiable {
let id = UUID()
let title: String
let description: String
let time: Date
let icon: String
}
let timeInterval = 1652619600
class Sample: ObservableObject {
#Published var sample2 = [SampleModel(title: "Coffee", description: "Get coffee", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)), icon: "house"),
SampleModel(title: "Coffee", description: "Get coffee", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 30), icon: "house"),
SampleModel(title: "Dinner", description: "Outback Steakhouse", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 60), icon: "person"),
SampleModel(title: "Check Weather", description: "Use app to check weather", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 120), icon: "cloud.sun.fill"),
SampleModel(title: "Go To Work", description: "Leave for work", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 180), icon: "car.fill"),
SampleModel(title: "YouTube", description: "Watch youtube video", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 240), icon: "video.fill"),
SampleModel(title: "Cut Grass", description: "Work in yard", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 300), icon: "speedometer"),
SampleModel(title: "Ride Bike", description: "Go to the trace", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 360), icon: "bicycle"),
SampleModel(title: "Take Pictures", description: "Photograph the moon", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 420), icon: "camera.fill"),
SampleModel(title: "Boat Ride", description: "Go boating", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 480), icon: "ferry.fill"),
SampleModel(title: "Colorado trip", description: "Fly to Erie", time: Date(timeIntervalSince1970: TimeInterval(timeInterval)).adding(minutes: 540), icon: "airplane")]
func isCurrent(date1: Date) -> Bool {
var currentItem: Bool = false
for cTime in sample2 {
if date1 <= cTime.time && date1 <= Date() {
} else {
currentItem = false
}
}
return currentItem
}
}
The data above is just a sample mock data so I can get the UI and the functioning working properly. In my content view I have. foreach loop on the sample data, and I want to highlight the current item with a filled circle. In the isCurrent() function, I can get all items that already have occurred before, but I want to return the most recent.
ForEach(sampleVM.sample2, id: \.id) { index in
Divider()
ItemRowView(isCurrent: sampleVM.isCurrent(date1: index.time), isLastRow: lastRow(item: index.id), time: Date(), sample: index)
}
ItemRowView() is what I am using to display the data.
As the array is sorted you simply need to find the first item/index whose date is greater than the current date
If the index is not found (current date is later than the date of the last item) the item is the last item
If the index is 0 (current date is sooner than the date of the first item) the item is nil
Otherwise the item is the item at index - 1
let currentItem : SampleModel?
if let nextIndex = sample2.firstIndex(where: {$0.time > Date()}) {
currentItem = nextIndex > 0 ? sample2[nextIndex - 1] : nil
} else {
currentItem = sample2.last!
}
Or if the result is the index
let currentIndex: Int?
if let nextIndex = sample2.firstIndex(where: {$0.time > Date()}) {
currentIndex = nextIndex > 0 ? nextIndex - 1 : nil
} else {
currentIndex = sample2.endIndex - 1
}

SwiftUI Table (macOS 12) and CoreData

I have a problem with the sortOrder in Tables with FetchedResults as datasource. Currently I'm using XCode 13 beta, Deployment Target macOS 12.0. Here is my code:
struct MyTable: View {
#FetchRequest(fetchRequest: Person.fetchRequest(), animation: .default)
var people: FetchedResults<Person>
#State private var sortOrder = [KeyPathComparator(\Person.familyName)]
#State private var selectedPersonID: Person.ID?
var body: some View {
Table(people, selection: $selectedPersonID, sortOrder: $sortOrder) {
TableColumn("Nachname", value: \.familyName)
TableColumn("Vorname", value: \.givenName)
TableColumn("Adresse", value:\.address)
TableColumn("Telefon 1", value:\.phone1)
TableColumn("Telefon 2", value:\.phone2)
}
.onChange(of: sortOrder) {
// --> PROBLEM: how can I implement the sortOrder with NSSortDescriptor ? <--
}
}
}
My question is: How can I implement the sort functionality in the .onChange-Method? The first attempt using people.sort(using: $0) failed. I also tried to parse the fetchedResults<Person> people into an Array:
var peopleArray: [Person] {
Array(people)
}
But then I get an immutable value peopleArray on which I cannot sort with the .sort(using:)-Method.
Thanks for any help!
Nico
I know, the question is old, but perhaps there's someone looking for the answer.
#FetchRequest(
fetchRequest: Person.fetchRequest(),
sortDescriptors: [SortDescriptor(\. familyName, order: .forward)],
animation: .default
)
var people: FetchedResults<Person>
var body: some View {
Table(people, selection: $selectedPersonID, sortOrder: $people.sortDescriptors) {
TableColumn("Nachname", value: \.familyName)
TableColumn("Vorname", value: \.givenName)
TableColumn("Adresse", value:\.address)
TableColumn("Telefon 1", value:\.phone1)
TableColumn("Telefon 2", value:\.phone2)
}
}

swiftUi : 2 Pickers on one screen - app crash with "Index out of range"

When I try to put 2 pikers with a different number of rows on-screen with different observers.
if I select in one number of the row that not exists in the second,
when I move to the second picker app crash with this message:
"Fatal error: Index out of range"
public enum kTrackType {
case audio
case text
}
class kTrack: NSObject, Identifiable {
public var id = UUID()
public var trakcId: String
public var title: String
public var type: kTrackType
public init(id: String, title: String, type: kTrackType) {
self.trakcId = id
self.title = title
self.type = type
}
}
and this is the main struct:
struct SelectedAudioAndSubtileView: View {
let geometry: GeometryProxy
#State var subtitlesList = [kTrack(id: "t0", title: "None", type: kTrackType.text),
kTrack(id: "t1", title: "En", type: kTrackType.text),
kTrack(id: "t2", title: "Rus", type: kTrackType.text),
kTrack(id: "t3", title: "Spn", type: kTrackType.text)]
#State var multiAudioList = [kTrack(id: "s0", title: "En", type: kTrackType.audio),
kTrack(id: "s1", title: "Rus", type: kTrackType.audio)]
#Binding var showSubtitlesPicker: Bool
#State private var selectedAudioPicker: Int = 0
#State private var selectedSubtitlePicker: Int = 0
#State private var selectedType = 0
var body: some View {
VStack {
Picker(selection: $selectedType, label: EmptyView()) {
Text("Audio").tag(0)
Text("Subtitle").tag(1)
}
.pickerStyle(SegmentedPickerStyle())
Text(self.selectedType == 0 ? "Select Audio" : "Select Subtitle")
Divider()
if selectedType == 0 {
Picker(selection: self.$selectedAudioPicker, label: Text("")) {
ForEach(self.multiAudioList, id: \.id){ name in
Text(name.title)
}
}
} else {
Picker(selection: self.$selectedSubtitlePicker, label: Text("")) {
ForEach(self.subtitlesList, id: \.id){ name in
Text(name.title)
}
}
}
Divider()
}
.background(Color(#colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1)))
.offset(y: geometry.size.height - 330)
}
After recheck, the crash happened also if you have same rows in 2 pickers!
Here is the situation :
a) the selectedValue should match the tag value, therefore in ForEach, it's better to use index not the id so that you can add tag for each items.
b) the ForEach structure is a complex one and usually to be reused for performance. So in order to force it refresh, id() modifier can be added to extra ForEach structures. There must be one ForEach without id which provides the real underlying data layer.
if selectedType == 0 {
Picker (selection: self.$selectedAudioPicker, label: Text("")) {
ForEach(0..<self.multiAudioList.count){ index in
Text(self.multiAudioList[index].title).tag(index)
}
}
} else if selectedType == 1 {
Picker(selection: self.$selectedSubtitlePicker, label: Text("")) {
ForEach(0..<self.subtitlesList.count){ index in
Text(self.subtitlesList[index].title).tag(index)
}.id(0)
}
}

KendoUI Multiselect Remove Multiple

I am using Kendo UI Multiselect:
http://demos.kendoui.com/web/multiselect/events.html
I have this Data:
var data =
[
{ text: "Shirt-Black", value: "1" },
{ text: "Shirt-Brown", value: "2" },
{ text: "Shirt-Blue", value: "3" },
{ text: "Cap-Green", value: "4" },
{ text: "Cap-Red", value: "5" },
{ text: "Cap-White", value: "6" },
{ text: "Jacket-Denim", value: "7" }
];
Now I want that if I select "Shirt-Brown" then rest entries for shirt i.e. "Shirt-Black" and "Shirt-Blue" should not appear in the list which means that the user should not be able to choose the Shirt of two colors.
Similarly, If a "Cap" of any color has been chosen then user should not be able to choose the "Cap" of any other color.
Is there any way to achieve this?
This is not build-in functionality. You can't even use dataSource filter() method because it will remove selected items from list as well.
However, this code will do what you're asking:
$("#select").kendoMultiSelect({
...
change: function(e) {
var dataItems = e.sender.dataItems();
var categories = [];
for(var i = 0; i < dataItems.length; i++){
var category = dataItems[i].text.substring(0, dataItems[i].text.indexOf('-'));
categories.push(category);
}
e.sender.ul.find('li').each(function(index, value){
var $li = $(value);
var hidden = false;
for(var i = 0; i < categories.length; i++){
var category = categories[i];
if ($li.text().match("^" + category)){
$li.css('display', 'none');
hidden = true;
}
}
if(!hidden){
$li.css('display', 'list-item');
}
});
}
});
Working KendoUi Dojo: http://dojo.telerik.com/AGisi

Displaying a separator view in CollectionView

I've got a Collection that is sorted by model's datetime property. I need to display a 'separator view' whenever the day changes. I was thinking about using a CollectionView to display the data. Am I on the right track?
The end result would look something like this:
1st of September (separator view)
-----------------------------
Model1
Model2
2nd of September (separator view)
-----------------------------
Model3
The solution was to extend the CollectionView's appendHtml method.
appendHtml: (collectionView, itemView, index) ->
if #_isDayChanged index
itemView.separator = true
itemView.render()
super
I use a list of CompositeViews to divide collection items in groups by month. You can easily adapt it to group by days.
let ItemView = Marionette.ItemView.extend({
...
});
let ListView = Marionette.CompositeView.extend({
childView: ItemView,
template: template,
childViewContainer: '.items',
filter(child) {
return child.get('month') === this.model.get('month');
}
});
let MonthGroupedListView = Marionette.CollectionView.extend({
childView: ListView,
childViewOptions(item, index) {
return {
model: item,
collection: this.getOption('collection')
};
},
initialize() {
// Passed collection remains in this.options.collection
// this.collection will contain distinct months
this.collection = new Backbone.Collection();
this.reset();
this.listenTo(this.options.collection, 'sync update', this.reset);
},
reset() {
// Find distnct months and put them into the collection
let months = _.uniq(this.options.collection.map((model) => model.get('month')));
this.collection.reset(_.map(months, (month) => ({month})));
}
});
From the data below the result should be three groups of ListView:
let data = [
{ id: 1, month: '2015-01', title: "January item 1" },
{ id: 2, month: '2015-01', title: "January item 2" },
{ id: 3, month: '2015-02', title: "February item 1" },
{ id: 4, month: '2015-05', title: "May item 1" },
{ id: 5, month: '2015-05', title: "May item 2" },
{ id: 6, month: '2015-05', title: "May item 3" }
];
let view = new MonthGroupedListView({
collection: new Backbone.Collection(data)
});
The template for ListView looks like this:
<div class="month-header">
{{month}}
</div>
<ul class="items">
{{-- Here ItemView elements will be rendered --}}
</ul>

Resources