diff --git a/qController.Standard/Pages/App.xaml.cs b/qController.Standard/Pages/App.xaml.cs
index 01eddb6..f0cd93b 100644
--- a/qController.Standard/Pages/App.xaml.cs
+++ b/qController.Standard/Pages/App.xaml.cs
@@ -2,7 +2,8 @@
using Xamarin.Forms;
using Xamarin.Essentials;
using qController.Communication;
-
+using qController.Pages;
+
namespace qController
{
public partial class App : Application
@@ -54,7 +55,7 @@ namespace qController
var menuPage = new MenuPage();
rootPage = new RootPage();
- NavigationPage = new NavigationPage(new QConnectionPage());
+ NavigationPage = new NavigationPage(new QBrowserPage());
rootPage.Master = menuPage;
rootPage.Detail = NavigationPage;
MainPage = rootPage;
diff --git a/qController.Standard/Pages/QBrowserPage.xaml b/qController.Standard/Pages/QBrowserPage.xaml
new file mode 100644
index 0000000..41b933d
--- /dev/null
+++ b/qController.Standard/Pages/QBrowserPage.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qController.Standard/Pages/QBrowserPage.xaml.cs b/qController.Standard/Pages/QBrowserPage.xaml.cs
new file mode 100644
index 0000000..af60141
--- /dev/null
+++ b/qController.Standard/Pages/QBrowserPage.xaml.cs
@@ -0,0 +1,90 @@
+using QSharp;
+using System.Collections.Generic;
+using Xamarin.Forms;
+using Serilog;
+using System.Collections.ObjectModel;
+using qController.Cell;
+using Acr.UserDialogs;
+using qController.Dialogs;
+using Xamarin.Essentials;
+using System;
+
+namespace qController.Pages
+{
+ public partial class QBrowserPage : ContentPage
+ {
+ public ObservableCollection servers = new ObservableCollection();
+ public QBrowserPage()
+ {
+ InitializeComponent();
+ App.rootPage.MenuItemSelected += OnMenuItemSelected;
+
+ serverListView.ItemsSource = servers;
+ QBrowser browser = new QBrowser();
+ browser.ServerUpdatedWorkspaces += Browser_ServerUpdatedWorkspaces;
+ serverListView.ItemSelected += ServerListView_ItemSelected;
+
+ storageListView.ItemsSource = QStorage.qInstances;
+ storageListView.ItemTemplate = new DataTemplate(typeof(QInstanceCell));
+ storageListView.ItemTapped += (object sender, ItemTappedEventArgs e) =>
+ {
+ // don't do anything if we just de-selected the row
+ if (e.Item == null) return;
+ // do something with e.SelectedItem
+ ((ListView)sender).SelectedItem = null; // de-select the row
+ };
+
+ }
+
+ async void ServerListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
+ {
+ if (e.SelectedItem == null)
+ return;
+ QWorkspace selectedWorkspace = e.SelectedItem as QWorkspace;
+ Log.Debug($"[demo] workspace: {selectedWorkspace.nameWithoutPathExtension} has been selected");
+ ((ListView)sender).SelectedItem = null;
+ await Navigation.PushAsync(new WorkspacePage(selectedWorkspace));
+ }
+
+ private void Browser_ServerUpdatedWorkspaces(object source, QServerUpdatedArgs args)
+ {
+ ServerGroup serverGroup = new ServerGroup(args.server.name);
+ serverGroup.AddRange(args.server.workspaces);
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ servers.Add(serverGroup);
+ });
+ }
+
+
+ void AddWorkspace()
+ {
+ UserDialogs.Instance.Prompt(new AddInstancePrompt());
+ }
+
+ private void OnMenuItemSelected(object source, MenuEventArgs args)
+ {
+ if (args.Command == "add")
+ {
+ AddWorkspace();
+ }
+ else if (args.Command == "feedback")
+ {
+ Launcher.OpenAsync(new Uri("mailto:feedback@jwetzell.com?subject=qController%20feedback"));
+ }
+ else if (args.Command == "support")
+ {
+ UserDialogs.Instance.Confirm(new DonatePrompt());
+ }
+ }
+ }
+
+ public class ServerGroup : List
+ {
+ public string name { get; set; }
+ public ServerGroup(string name)
+ {
+ this.name = name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/qController.Standard/Pages/WorkspacePage.xaml b/qController.Standard/Pages/WorkspacePage.xaml
new file mode 100644
index 0000000..cec8aa5
--- /dev/null
+++ b/qController.Standard/Pages/WorkspacePage.xaml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qController.Standard/Pages/WorkspacePage.xaml.cs b/qController.Standard/Pages/WorkspacePage.xaml.cs
new file mode 100644
index 0000000..21c1b31
--- /dev/null
+++ b/qController.Standard/Pages/WorkspacePage.xaml.cs
@@ -0,0 +1,139 @@
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using QSharp;
+using qController.ViewModels;
+using Serilog;
+using Xamarin.Essentials;
+using Xamarin.Forms;
+
+namespace qController
+{
+ public partial class WorkspacePage : ContentPage
+ {
+ private QWorkspace connectedWorkspace;
+ private Dictionary cueGridDict = new Dictionary();
+ public WorkspacePage(QWorkspace workspace)
+ {
+ InitializeComponent();
+
+ connectedWorkspace = workspace;
+ connectedWorkspace.WorkspaceUpdated += Workspace_WorkspaceUpdated;
+ connectedWorkspace.connectWithPasscode("1234");
+ connectedWorkspace.defaultSendUpdatesOSC = true;
+ connectedWorkspace.CueListChangedPlaybackPosition += ConnectedWorkspace_CueListChangedPlaybackPosition;
+ }
+
+ void ConnectedWorkspace_CueListChangedPlaybackPosition(object source, QCueListChangedPlaybackPositionArgs args)
+ {
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ selectedCueGrid.BindingContext = new QCueViewModel(connectedWorkspace.cueWithID(args.cueID), false);
+
+ if (cueGridDict.ContainsKey(args.cueID))
+ {
+ var cueGrid = cueGridDict[args.cueID]; //element to scroll to
+ cueListScrollView.ScrollToAsync(cueGrid, ScrollToPosition.Center, true);
+ }
+ });
+ }
+
+ void Workspace_WorkspaceUpdated(object source, QWorkspaceUpdatedArgs args)
+ {
+ Log.Debug("[workspacepage] Workspace Updated");
+
+ foreach (var cue in connectedWorkspace.cueLists)
+ {
+ if (cue.cues.Count > 0)
+ {
+ List cueAddTasks = new List();
+ foreach (var aCue in cue.cues)
+ {
+ Grid cueGrid = cueToGrid(aCue);
+ cueGridDict.Add(aCue.uid, cueGrid);
+ MainThread.InvokeOnMainThreadAsync(() =>
+ {
+ cueListsGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
+ cueListsGrid.Children.Add(cueGrid, 0, aCue.sortIndex);
+ }).Wait();
+ }
+ connectedWorkspace.valueForKey(cue, QOSCKey.PlaybackPositionId); //fetch playback position for cueList once all cue loading is done.
+ break; //only load first cue list with cues.
+ }
+ }
+ }
+
+ protected override void OnDisappearing()
+ {
+ base.OnDisappearing();
+
+ //unsubscribe from events
+ connectedWorkspace.WorkspaceUpdated -= Workspace_WorkspaceUpdated;
+ connectedWorkspace.CueListChangedPlaybackPosition -= ConnectedWorkspace_CueListChangedPlaybackPosition;
+ //disconnect
+ connectedWorkspace.disconnect();
+
+ }
+
+ Grid cueToGrid(QCue cue)
+ {
+ Grid cueGrid = new Grid { RowSpacing = 0 };
+ QCueViewModel qCueViewModel = new QCueViewModel(cue, true);
+ cueGrid.RowDefinitions = new RowDefinitionCollection();
+ cueGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) });
+ var cueLabel = new Label
+ {
+ BindingContext = qCueViewModel,
+ HorizontalOptions = LayoutOptions.StartAndExpand,
+ VerticalTextAlignment = TextAlignment.Center,
+ };
+ cueLabel.SetBinding(Label.TextProperty, "name", BindingMode.OneWay);
+ var cueBackground = new Frame
+ {
+ BindingContext = qCueViewModel,
+ Opacity = 0.50,
+ HasShadow = false,
+ CornerRadius = 0,
+ BorderColor = Color.Black
+ };
+ cueBackground.SetBinding(BackgroundColorProperty, "color", BindingMode.OneWay);
+
+ var cueSelectedIndicator = new Frame
+ {
+ BindingContext = qCueViewModel,
+ BackgroundColor = Color.Blue,
+ HasShadow = false
+ };
+ cueSelectedIndicator.SetBinding(IsVisibleProperty, "IsSelected");
+
+ cueGrid.Children.Add(cueSelectedIndicator, 0, 0);
+ cueGrid.Children.Add(cueBackground, 0, 0);
+ cueGrid.Children.Add(cueLabel, 0, 0);
+
+ int rows = 1;
+ if (cue.cues.Count > 0)
+ {
+ foreach (var aCue in cue.cues)
+ {
+ cueGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
+ var aCueGrid = cueToGrid(aCue);
+ cueGridDict.Add(aCue.uid, aCueGrid);
+ aCueGrid.Margin = new Thickness(10, 0, 0, 0);
+ cueGrid.Children.Add(aCueGrid, 0, aCue.sortIndex + 1);
+ rows++;
+ }
+
+ var cueFrame = new Frame
+ {
+ BackgroundColor = Color.Transparent,
+ BorderColor = Color.Black
+ };
+
+ cueGrid.Children.Add(cueFrame);
+ Grid.SetRowSpan(cueFrame, rows);
+
+ }
+ return cueGrid;
+ }
+ }
+}
\ No newline at end of file
diff --git a/qController.Standard/ViewModels/QCueViewModel.cs b/qController.Standard/ViewModels/QCueViewModel.cs
new file mode 100644
index 0000000..b338bae
--- /dev/null
+++ b/qController.Standard/ViewModels/QCueViewModel.cs
@@ -0,0 +1,100 @@
+using QSharp;
+using Serilog;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using Xamarin.Forms;
+
+namespace qController.ViewModels
+{
+ public class QCueViewModel : INotifyPropertyChanged
+ {
+ QCue cue;
+ bool isSelected = false;
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public QCueViewModel(QCue cue, bool checkPlayback)
+ {
+ this.cue = cue;
+ if (checkPlayback)
+ this.cue.workspace.CueListChangedPlaybackPosition += Workspace_CueListChangedPlaybackPosition;
+ this.cue.CuePropertiesUpdated += OnCuePropertiesUpdated;
+ }
+
+ private void OnCuePropertiesUpdated(object source, QCuePropertiesUpdatedArgs args)
+ {
+ foreach (var property in args.properties)
+ {
+ Log.Debug($"[cueviewmodel] property <{property}> has been updated.");
+ if (property.Equals(QOSCKey.Name))
+ {
+ OnPropertyChanged("name");
+ }
+ else if (property.Equals(QOSCKey.ColorName))
+ {
+ OnPropertyChanged("color");
+ }
+ }
+ }
+
+ void OnPropertyChanged([CallerMemberName] string name = "")
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
+ }
+
+ private void Workspace_CueListChangedPlaybackPosition(object source, QCueListChangedPlaybackPositionArgs args)
+ {
+ IsSelected = args.cueID == cue.uid;
+ }
+
+ public string name
+ {
+ get
+ {
+ return cue.displayName;
+ }
+
+ set
+ {
+ cue.name = value;
+ }
+ }
+
+ public string number
+ {
+ get
+ {
+ return cue.number;
+ }
+
+ set
+ {
+ cue.number = value;
+ }
+ }
+
+ public Color color
+ {
+ get
+ {
+ return Color.FromHex(cue.color.Hex);
+ }
+ set
+ {
+ cue.color = new QColor("none");
+ }
+ }
+
+ public bool IsSelected
+ {
+ get
+ {
+ return isSelected;
+ }
+ set
+ {
+ isSelected = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+}
diff --git a/qController.Standard/qController.csproj b/qController.Standard/qController.csproj
index ba9b0c3..dc1ad72 100644
--- a/qController.Standard/qController.csproj
+++ b/qController.Standard/qController.csproj
@@ -40,7 +40,6 @@
-
@@ -50,12 +49,16 @@
*.xaml
+
+ QBrowserPage.xaml
+
*.xaml
+
@@ -83,7 +86,6 @@
-->
-
@@ -95,4 +97,12 @@
+
+
+ MSBuild:UpdateDesignTimeXaml
+
+
+ MSBuild:UpdateDesignTimeXaml
+
+