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 + +