Add more code :-)

develop
LEdoian 3 years ago
parent 85066e197c
commit 35c4937632

@ -71,9 +71,9 @@ namespace QuickPlay
[NonSerialized] [NonSerialized]
public static readonly AppConfiguration defaultConfiguration = new AppConfiguration public static readonly AppConfiguration defaultConfiguration = new AppConfiguration
{ {
playerConfigUrl = "file:///dev/null", playerConfigUrl = "http://www.ms.mff.cuni.cz/~turinskp/znelky.ini",
}; };
public PlayerConfiguration GetPlayerConfig() public async Task<PlayerConfiguration> GetPlayerConfig()
{ {
IPlayerConfigurationProvider cfgProvider; IPlayerConfigurationProvider cfgProvider;
if (playerConfigUrl.StartsWith("http:") || playerConfigUrl.StartsWith("https:")) if (playerConfigUrl.StartsWith("http:") || playerConfigUrl.StartsWith("https:"))
@ -84,11 +84,13 @@ namespace QuickPlay
string filename = playerConfigUrl.Substring("file://".Length); string filename = playerConfigUrl.Substring("file://".Length);
var reader = new StreamReader(filename); var reader = new StreamReader(filename);
cfgProvider = new FileConfigurationProvider(reader); cfgProvider = new FileConfigurationProvider(reader);
} else if (playerConfigUrl == "default") {
cfgProvider = new DummyConfigurationProvider();
} else } else
{ {
throw new InvalidOperationException("Schema of player config URL not supported"); throw new InvalidOperationException("Schema of player config URL not supported");
} }
return cfgProvider.GetConfigurationAsync().Result; // Bad code, but hopefully we dont hang. return await cfgProvider.GetConfigurationAsync();
} }
// We want to compare by values. // We want to compare by values.
@ -116,10 +118,10 @@ namespace QuickPlay
/// </summary> /// </summary>
public class PlayerConfiguration public class PlayerConfiguration
{ {
public Dictionary<string, IPlayable> songs; public Dictionary<string, IPlayable> songs = new Dictionary<string, IPlayable>();
public string playerName; public string playerName = "";
public PlayerType playerType; public PlayerType playerType;
public string playerConnectionDetails; // This is opaque to this class, the player will make sense of it. public string playerConnectionDetails = ""; // This is opaque to this class, the player will make sense of it.
public static PlayerConfiguration FromFile(StreamReader reader) public static PlayerConfiguration FromFile(StreamReader reader)
{ {
@ -199,7 +201,15 @@ namespace QuickPlay
sealed class DummyConfigurationProvider : IPlayerConfigurationProvider sealed class DummyConfigurationProvider : IPlayerConfigurationProvider
{ {
public Task<PlayerConfiguration> GetConfigurationAsync() => null; public Task<PlayerConfiguration> GetConfigurationAsync()
{
PlayerConfiguration cfg = new PlayerConfiguration();
cfg.playerType = PlayerType.MPD;
cfg.playerName = "Dummy player";
cfg.playerConnectionDetails = "127.0.0.1";
return Task.FromResult(cfg);
}
} }
class Song: IPlayable class Song: IPlayable

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using Android.Content;
// MPD client abstractions and simplifications // MPD client abstractions and simplifications
namespace QuickPlay namespace QuickPlay
@ -16,6 +18,17 @@ namespace QuickPlay
float CurrentProgress { get; } float CurrentProgress { get; }
bool IsReady { get; } bool IsReady { get; }
void SetReasonableOptions(); //TODO void SetReasonableOptions(); //TODO
/// <summary>
/// Attach to the real player.
///
/// Since this operation can be asynchronous, we cannot put it in th
/// constructor. And this allows for some tweaks before connecting.
/// </summary>
/// <param name="context">
/// Context to run possible services from.
/// </param>
/// <returns></returns>
Task ConnectAsync(Context context);
} }
/// <summary> /// <summary>
/// A simple dataclass to hold auxiliary data of the Playable objects. /// A simple dataclass to hold auxiliary data of the Playable objects.
@ -45,4 +58,11 @@ namespace QuickPlay
ILayout LayOut(ICollection<IPlayable> playables); ILayout LayOut(ICollection<IPlayable> playables);
} }
public class CannotConnectException: Exception
{
public CannotConnectException(string msg, Exception e) : base(msg, e) { }
public CannotConnectException(string msg) : base(msg) { }
public CannotConnectException() : base() { }
}
} }

@ -29,14 +29,25 @@ namespace QuickPlay
private Android.Support.V7.Widget.RecyclerView recyclerView; private Android.Support.V7.Widget.RecyclerView recyclerView;
private IPlayer currentPlayer; private IPlayer currentPlayer;
protected override void OnCreate(Bundle savedInstanceState) protected override async void OnCreate(Bundle savedInstanceState)
{ {
base.OnCreate(savedInstanceState); base.OnCreate(savedInstanceState);
// App initialization // App initialization
appConfig = AppConfiguration.loadConfiguration(); appConfig = AppConfiguration.loadConfiguration();
currentPlayer = appConfig.GetPlayerConfig().GetPlayer(); var playerConfig = await appConfig.GetPlayerConfig();
currentPlayer = playerConfig.GetPlayer();
try
{
await currentPlayer.ConnectAsync(this);
} catch (CannotConnectException e)
{
//TODO: View a toast with details and change some colors?
Console.WriteLine("This is bad.");
var t = Toast.MakeText(this, e.Message + ": " + e.InnerException.Message ?? "", ToastLength.Long);
t.Show();
}
// UI initialization // UI initialization
SetContentView(Resource.Layout.activity_main); SetContentView(Resource.Layout.activity_main);
@ -87,5 +98,17 @@ namespace QuickPlay
} }
return base.OnOptionsItemSelected(item); return base.OnOptionsItemSelected(item);
} }
/// <summary>
/// A callback for all player updates.
///
/// The update should be easy on resources, so no need to have separate
/// partial updates. This simply performs full update of the activity
/// state and views.
/// </summary>
public void OnPlayerUpdate()
{
throw new NotImplementedException("Activity should update.");
}
} }
} }

@ -11,7 +11,7 @@ using System.Text;
namespace QuickPlay namespace QuickPlay
{ {
[Service(Exported = true, Name = "cz.ledoian.quickplay.mpdmonior")] [Service]
class MpdMonitorService : Service class MpdMonitorService : Service
{ {
public override void OnCreate() public override void OnCreate()

@ -6,11 +6,20 @@ using Android.Views;
using Android.Widget; using Android.Widget;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using MpcCore;
using System.Net.Sockets;
namespace QuickPlay namespace QuickPlay
{ {
class MpdPlayer: IPlayer class MpdPlayer: IPlayer
{ {
MpcCoreClient mpd;
Thread serviceThread;
// MpcCore uses strings, so be it
string mpdIP, mpdPort;
public Dictionary<string, IPlayable> Songs { get; private set; } public Dictionary<string, IPlayable> Songs { get; private set; }
public float CurrentProgress { get { public float CurrentProgress { get {
throw new NotImplementedException(); throw new NotImplementedException();
@ -29,8 +38,34 @@ namespace QuickPlay
} }
public MpdPlayer(PlayerConfiguration cfg) public MpdPlayer(PlayerConfiguration cfg)
{ {
//TODO // Populate known fields/properties
Songs = cfg.songs; Songs = cfg.songs;
// NOTE: We separate the port by '@', since ':' could be part of IPv6 and we do not want to complicate parsing.
var connDetails = cfg.playerConnectionDetails.Split('@');
if (connDetails.Length > 2) throw new InvalidOperationException("Bad connection details");
mpdIP = connDetails[0];
mpdPort = connDetails.Length >=2 ? connDetails[1] : "6600"; // XXX: Unneccessary default here...
// Connecting and monitoring remote player is done in ConnectAsync.
}
public async Task ConnectAsync(Context ctx)
{
// Create a persistent connection
var conn = new MpcCoreConnection(mpdIP, mpdPort);
mpd = new MpcCoreClient(conn);
try
{
await mpd.ConnectAsync();
} catch (SocketException e)
{
throw new CannotConnectException("MPD connect failed", e);
}
// Start the monitoring service
Console.WriteLine("Hello! Will run thr.");
serviceThread = new Thread(() =>
{
var intent = new Intent(ctx, typeof(MpdMonitorService));
});
Console.WriteLine("Thread possibly started");
} }
} }
} }
Loading…
Cancel
Save