Skip to content

Commit

Permalink
Implement server outputs/local playback port on iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
Difegue committed Sep 8, 2024
1 parent de6fbc9 commit 337e83c
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 74 deletions.
3 changes: 3 additions & 0 deletions Sources/Stylophone.iOS/Stylophone.iOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
<Compile Update="Helpers\SymbolUIButton.designer.cs">
<DependentUpon>SymbolUIButton.cs</DependentUpon>
</Compile>
<Compile Condition=" '$(EnableDefaultCompileItems)' == 'true' " Update="ViewControllers\SubViews\ServerOutputCell.designer.cs">
<DependentUpon>ServerOutputCell.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Essentials" Version="1.8.1" />
Expand Down
98 changes: 92 additions & 6 deletions Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
using Stylophone.iOS.Helpers;
using Stylophone.Localization.Strings;
using UIKit;
using System.Collections.ObjectModel;
using Stylophone.Common.ViewModels.Items;
using System.Collections.Specialized;
using Stylophone.iOS.Views;

namespace Stylophone.iOS.ViewControllers
{
public partial class SettingsViewController : UITableViewController, IViewController<SettingsViewModel>
{

public SettingsViewController(IntPtr handle) : base(handle)
public SettingsViewController(ObjCRuntime.NativeHandle handle) : base(handle)
{
}

Expand All @@ -38,9 +42,10 @@ public override string TitleForHeader(UITableView tableView, nint section)
{
0 => Resources.SettingsServer,
1 => Resources.SettingsLocalPlaybackHeader,
2 => Resources.SettingsDatabase,
3 => Resources.SettingsAnalytics,
4 => Resources.SettingsAbout,
2 => Resources.SettingsOutputsHeader,
3 => Resources.SettingsDatabase,
4 => Resources.SettingsAnalytics,
5 => Resources.SettingsAbout,
_ => "",
};
}
Expand All @@ -50,8 +55,9 @@ public override string TitleForFooter(UITableView tableView, nint section)
return (int)section switch
{
1 => Resources.SettingsLocalPlaybackText,
2 => Resources.SettingsAlbumArtText,
3 => Resources.SettingsApplyOnRestart,
2 => Resources.SettingsOutputsText,
3 => Resources.SettingsAlbumArtText,
4 => Resources.SettingsApplyOnRestart,
_ => "",
};
}
Expand Down Expand Up @@ -85,6 +91,10 @@ public override void ViewDidLoad()

Binder.Bind<bool>(LocalPlaybackToggle, "enabled", nameof(ViewModel.IsStreamingAvailable));
Binder.Bind<bool>(LocalPlaybackToggle, "on", nameof(ViewModel.IsLocalPlaybackEnabled), true);

Binder.Bind<int>(LocalPlaybackPortField, "text", nameof(ViewModel.LocalPlaybackPort), true,
valueTransformer: intToStringTransformer);

Binder.Bind<bool>(AnalyticsToggle, "on", nameof(ViewModel.EnableAnalytics), true);
Binder.Bind<bool>(AlbumArtToggle, "on", nameof(ViewModel.IsAlbumArtFetchingEnabled), true);

Expand Down Expand Up @@ -112,7 +122,83 @@ public override void ViewDidLoad()
ViewModel.RetryConnection();
};

var outputsDataSource = new ServerOutputsDataSource(ServerOutputsTable, ViewModel.Outputs);

ServerOutputsTable.DataSource = outputsDataSource;
ServerOutputsTable.Delegate = outputsDataSource;

}
}

public class ServerOutputsDataSource : UITableViewDelegate, IUITableViewDataSource
{
private UITableView _tableView;
private ObservableCollection<OutputViewModel> _sourceCollection;

public ServerOutputsDataSource(UITableView tableView, ObservableCollection<OutputViewModel> source)
{
_tableView = tableView;
_sourceCollection = source;

_sourceCollection.CollectionChanged += (s, e) => UIApplication.SharedApplication.InvokeOnMainThread(
() => UpdateUITableView(e));
}

public nint RowsInSection(UITableView tableView, nint section)
{
return _sourceCollection.Count;
}

public UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("outputCell") as ServerOutputCell;

if (_sourceCollection.Count <= indexPath.Row)
return cell; // Safety check

var outputViewModel = _sourceCollection[indexPath.Row];

cell.Configure(indexPath.Row, outputViewModel);

return cell;
}

// TODO make an extension of UITableView?
private void UpdateUITableView(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
_tableView.ReloadData();
}
else
{
_tableView.BeginUpdates();

//Build a NSIndexPath array that matches the changes from the ObservableCollection.
var indexPaths = new List<NSIndexPath>();

if (e.Action == NotifyCollectionChangedAction.Add)
{
for (var i = e.NewStartingIndex; i < e.NewStartingIndex + e.NewItems.Count; i++)
indexPaths.Add(NSIndexPath.FromItemSection(i, 0));

_tableView.InsertRows(indexPaths.ToArray(), UITableViewRowAnimation.Left);
}

if (e.Action == NotifyCollectionChangedAction.Remove)
{
var startIndex = e.OldStartingIndex;

for (var i = startIndex; i < startIndex + e.OldItems.Count; i++)
indexPaths.Add(NSIndexPath.FromItemSection(i, 0));

_tableView.DeleteRows(indexPaths.ToArray(), UITableViewRowAnimation.Right);
}

_tableView.EndUpdates();
}
}

}

}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// This file has been autogenerated from a class added in the UI designer.

using System;
using Stylophone.Common.Helpers;
using Stylophone.Common.ViewModels;
using Stylophone.iOS.Helpers;
using Foundation;
using UIKit;
using Stylophone.Common.ViewModels.Items;

namespace Stylophone.iOS.Views
{
public partial class ServerOutputCell : UITableViewCell
{
public ServerOutputCell (IntPtr handle) : base (handle)
{
}

private PropertyBinder<OutputViewModel> _propertyBinder;
private OutputViewModel _outputViewModel;

internal void Configure(int row, OutputViewModel outputViewModel)
{
// Bind output
_outputViewModel = outputViewModel;
_propertyBinder?.Dispose();
_propertyBinder = new PropertyBinder<OutputViewModel>(outputViewModel);
var negateBoolTransformer = NSValueTransformer.GetValueTransformer(nameof(ReverseBoolValueTransformer));

if (outputViewModel != null)
{
OutputLabel.Text = outputViewModel.Name + " (" + outputViewModel.Plugin + ")";

_propertyBinder.Bind<bool>(OutputToggle, "on", nameof(outputViewModel.IsEnabled), true);
}

}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 337e83c

Please sign in to comment.