--- /dev/null
+using System.Threading;
+using System.Threading.Tasks;
+using Tizen.NUI;
+using MusicPlayer.Common;
+
+namespace MusicPlayer.Core
+{
+ static class ColorExtractor
+ {
+ public static async Task<Palette> GetPaletteAsync(string imagePath)
+ {
+ Tizen.Log.Debug(AppConstants.LogTag, "Main Thread Id: " + Thread.CurrentThread.ManagedThreadId);
+ return await Task.Run(() => GeneratePalette(imagePath));
+ }
+
+ private static Palette GeneratePalette(string imagePath)
+ {
+ PixelBuffer pixelBuffer = ImageLoading.LoadImageFromFile(imagePath);
+ if(pixelBuffer == null)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "Pixel buffer is null");
+ return null;
+ }
+
+ Palette palette = null;
+
+ try
+ {
+ palette = Palette.Generate(pixelBuffer);
+ }
+ catch(System.ArgumentNullException e)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "ArgumentNullException: " + e.Message);
+ }
+
+ return palette;
+ }
+ }
+}
using Tizen.Multimedia;
using MusicPlayer.Models;
+using MusicPlayer.Common;
+using Tizen.NUI;
namespace MusicPlayer.ViewModels
{
- class LyricsViewModel
+ class LyricsViewModel : PropertyNotifier
{
internal LyricsModel lyricsModel;
}
}
+ private Color lyricsBackgroundColor;
+
+ public Color LyricsBackgroundColor
+ {
+ get => lyricsBackgroundColor;
+ set => SetProperty(ref lyricsBackgroundColor, value);
+ }
+
private string GetLyrics(string path)
{
var metadataExtractor = new MetadataExtractor(path);
Metadata metadata = metadataExtractor.GetMetadata();
- return metadata.UnsyncLyrics;
+ string lyrics = metadata.UnsyncLyrics;
+ if(string.IsNullOrEmpty(lyrics))
+ {
+ LyricsBackgroundColor = Color.Transparent;
+ return string.Empty;
+ }
+ else
+ {
+ LyricsBackgroundColor = UIColors.LyricsBackground;
+ return lyrics;
+ }
}
}
}
using MusicPlayer.Core;
using Tizen.NUI;
using Tizen.Multimedia;
+using System.Threading.Tasks;
namespace MusicPlayer.ViewModels
{
class PlayerViewModel : PropertyNotifier
{
private const int PlaybackTimerDuration = 1000;
+ private const int MinPaletteColorCount = 2;
internal PlayerModel playerModel;
internal LyricsViewModel lyricsViewModel;
set => SetProperty(ref hasNextTrack, value);
}
+ private PropertyMap playerBackground;
+
+ public PropertyMap PlayerBackground
+ {
+ get => playerBackground;
+ set => SetProperty(ref playerBackground, value);
+ }
+
public void SetPlayingList(ListViewModel<Track> trackListVM)
{
playingListViewModel.SetTrackListViewModel(trackListVM);
HasPreviousTrack = playingListViewModel.HasPrev();
HasNextTrack = playingListViewModel.HasNext();
+ // SetBackground
+ SetExtractedBackground(track.ThumbnailPath);
+
PlayerController.Instance.Uri = track.FilePath;
StartPlayback();
}
public void UpdatePlayerPosition(float value)
{
- int currentPosition = (int)(playerModel.CurrentTrack.Duration * value);
+ int currentPosition = (int)(playerModel.CurrentTrack.DurationInMS * value);
PlayerController.Instance.SetPosition(currentPosition);
playerModel.PlayingTime = TimeSpan.FromMilliseconds(currentPosition).ToString(AppConstants.TimeFormat);
playbackTimer.Start();
public void SetElapsedTime(float value)
{
- int currentPosition = (int)(playerModel.CurrentTrack.Duration * value);
+ int currentPosition = (int)(playerModel.CurrentTrack.DurationInMS * value);
playerModel.PlayingTime = TimeSpan.FromMilliseconds(currentPosition).ToString(AppConstants.TimeFormat);
}
private void UpdatePlayingTime()
{
int position = PlayerController.Instance.GetPosition();
- playerModel.ElapsedTime = position / (float)playerModel.CurrentTrack.Duration;
+ playerModel.ElapsedTime = position / (float)playerModel.CurrentTrack.DurationInMS;
playerModel.PlayingTime = TimeSpan.FromMilliseconds(position).ToString(AppConstants.TimeFormat);
}
VolumeLevel = e.Level;
}
}
+
+ private ImageVisual CreateImageVisual()
+ {
+ ImageVisual visual = new ImageVisual()
+ {
+ URL = Resources.GetImagePath() + "gradient_music_light.png",
+ };
+ return visual;
+ }
+
+ private GradientVisual CreateGradientVisual(PropertyArray stopColor)
+ {
+ GradientVisual gradientVisual = new GradientVisual()
+ {
+ StartPosition = new Vector2(0.0f, -1.0f),
+ EndPosition = new Vector2(0.0f, 1.0f),
+ StopColor = stopColor,
+ SpreadMethod = GradientVisualSpreadMethodType.Pad,
+ };
+ return gradientVisual;
+ }
+
+ private PropertyArray GetGradientStopColors(Palette palette)
+ {
+ PropertyArray propertyArray = new PropertyArray();
+ if(palette == null)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "Color palatte from background is null");
+ return propertyArray;
+ }
+
+ Palette.Swatch lightMutedSwatch = palette.GetLightMutedSwatch();
+ Palette.Swatch darkMutedSwatch = palette.GetDarkMutedSwatch();
+ if(lightMutedSwatch != null && darkMutedSwatch != null)
+ {
+ propertyArray.PushBack(new PropertyValue(lightMutedSwatch.GetRgb()));
+ propertyArray.PushBack(new PropertyValue(darkMutedSwatch.GetRgb()));
+ return propertyArray;
+ }
+
+ Palette.Swatch lightVibrantSwatch = palette.GetLightVibrantSwatch();
+ Palette.Swatch darkVibrantSwatch = palette.GetDarkVibrantSwatch();
+ if(lightVibrantSwatch != null && darkVibrantSwatch != null)
+ {
+ propertyArray.PushBack(new PropertyValue(lightVibrantSwatch.GetRgb()));
+ propertyArray.PushBack(new PropertyValue(darkVibrantSwatch.GetRgb()));
+ return propertyArray;
+ }
+
+ Palette.Swatch mutedSwatch = palette.GetMutedSwatch();
+ Palette.Swatch vibrantSwatch = palette.GetVibrantSwatch();
+ if(mutedSwatch != null && vibrantSwatch != null)
+ {
+ propertyArray.PushBack(new PropertyValue(mutedSwatch.GetRgb()));
+ propertyArray.PushBack(new PropertyValue(vibrantSwatch.GetRgb()));
+ return propertyArray;
+ }
+
+ IReadOnlyCollection<Palette.Swatch> swatches = palette.GetSwatches();
+ foreach(Palette.Swatch swatch in swatches)
+ {
+ if(propertyArray.Count() >= MinPaletteColorCount)
+ {
+ return propertyArray;
+ }
+ if(swatch != null)
+ {
+ propertyArray.PushBack(new PropertyValue(swatch.GetRgb()));
+ }
+ }
+ return propertyArray;
+ }
+
+ private async void SetExtractedBackground(string path)
+ {
+ Tizen.Log.Debug(AppConstants.LogTag, "Path for the color image thumbnail" + path);
+ Palette palette = await ColorExtractor.GetPaletteAsync(path);
+ PropertyArray stopColor = GetGradientStopColors(palette);
+ if (stopColor.Count() < MinPaletteColorCount)
+ {
+ Tizen.Log.Info(AppConstants.LogTag, "Palette or palatte values not valid, adding default gradient");
+ ImageVisual imageVisual = CreateImageVisual();
+ PlayerBackground = imageVisual.OutputVisualMap;
+ return;
+ }
+ else
+ {
+ Tizen.Log.Info(AppConstants.LogTag, "setting palette color");
+ GradientVisual gradientVisual = CreateGradientVisual(stopColor);
+ PlayerBackground = gradientVisual.OutputVisualMap;
+ }
+ }
}
}
// Need to check for same VM and in case same VM just update the playing track
Tizen.Log.Info(AppConstants.LogTag, "Setting Current Playing list");
tracklistViewModel = trackListVM;
- currentIndex = 0;
+ currentIndex = -1;
RepeatMode = RepeatMode.Off;
ShuffleMode = ShuffleMode.Off;
OnItemsSourceChanged(new EventArgs());
}
}
- public string Next()
+ public Track Next()
{
if(currentIndex < 0 )
{
}
if(RepeatMode == RepeatMode.RepeatOne)
{
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
else if(RepeatMode == RepeatMode.Off)
{
else
{
currentIndex += 1;
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
}
else
if (currentIndex + 1 >= shuffleList.Count)
{
currentIndex = 0;
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
else
{
currentIndex += 1;
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
}
}
- public string Prev()
+ public Track Prev()
{
if (currentIndex < 0)
{
}
if (RepeatMode == RepeatMode.RepeatOne)
{
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
else if (RepeatMode == RepeatMode.Off)
{
else
{
currentIndex -= 1;
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
}
else
if (currentIndex - 1 < 0)
{
currentIndex = shuffleList.Count-1;
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
else
{
currentIndex -= 1;
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ return tracklistViewModel[shuffleList[currentIndex]];
}
}
}
public bool HasNext()
{
- if (currentIndex < 0 && currentIndex > shuffleList.Count)
+ if (IsTrackIndexInvalid())
+ {
return false;
+ }
if(RepeatMode == RepeatMode.RepeatOne || RepeatMode == RepeatMode.RepeatAll)
{
return true;
public bool HasPrev()
{
- if (currentIndex < 0 && currentIndex > shuffleList.Count)
+ if (IsTrackIndexInvalid())
+ {
return false;
+ }
if (RepeatMode == RepeatMode.RepeatOne || RepeatMode == RepeatMode.RepeatAll)
{
return true;
}
}
- public string Current()
+ public Track Current()
{
- if (currentIndex < 0 && currentIndex > shuffleList.Count)
+ if (IsTrackIndexInvalid())
+ {
return null;
+ }
else
- return tracklistViewModel[shuffleList[currentIndex]].FilePath;
+ {
+ return tracklistViewModel[shuffleList[currentIndex]];
+ }
}
public void SetPlayingTrack(string mediaId)
{
- int count = 0;
- for(count = 0; count< tracklistViewModel.Count; ++count)
+ int count;
+ for (count = 0; count< tracklistViewModel.Count; ++count)
{
- if (mediaId == tracklistViewModel[0].Id)
+ if (mediaId == tracklistViewModel[count].Id)
{
currentIndex = count;
return;
}
currentIndex = -1;
}
+
+ public void SetPlayingTrack(Track track)
+ {
+ int count;
+ for (count = 0; count < tracklistViewModel.Count; ++count)
+ {
+ if (track == tracklistViewModel[count])
+ {
+ Tizen.Log.Debug(AppConstants.LogTag, "Current track index is " + count);
+ currentIndex = count;
+ return;
+ }
+ }
+ currentIndex = -1;
+ }
+
+ private bool IsTrackIndexInvalid()
+ {
+ if(currentIndex < 0 || currentIndex > shuffleList.Count)
+ {
+ return true;
+ }
+ return false;
+ }
}
}
Position2D = new Position2D(LyricsViewMargin, LyricsViewMargin),
Size2D = new Size2D(LyricsViewSize, LyricsViewSize),
ScrollingDirection = ScrollableBase.Direction.Vertical,
+ BackgroundColor = Color.Transparent,
};
+ scrollView.BindingContext = lyricsViewModel;
+ scrollView.SetBinding(View.BackgroundColorProperty, "LyricsBackgroundColor");
base.Add(scrollView);
lyricsLabel = new TextLabel()
{
WidthResizePolicy = ResizePolicyType.FillToParent,
- BackgroundColor = UIColors.LyricsBackground,
TextColor = Color.White,
MultiLine = true,
LineWrapMode = LineWrapMode.Word,
PointSize = 25.0f,
HorizontalAlignment = HorizontalAlignment.Center,
};
+ lyricsLabel.BindingContext = lyricsViewModel.lyricsModel;
lyricsLabel.SetBinding(TextLabel.TextProperty, "Lyrics");
scrollView.Add(lyricsLabel);
}
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Tizen.NUI.BaseComponents;
-using Tizen.NUI;
+using Tizen.NUI;
+using Tizen.Multimedia;
using Tizen.NUI.Components;
-using MusicPlayer.Common;
+using Tizen.NUI.BaseComponents;
using Tizen.NUI.Binding;
+using MusicPlayer.Common;
using MusicPlayer.ViewModels;
-using Tizen.Multimedia;
namespace MusicPlayer.Views
{
class PlayerView : View
{
+ private enum PlayerViewState
+ {
+ AlbumArt,
+ TrackList,
+ }
private const int LayoutPadding = 64;
private const int IconSize = 48;
private const int TopBarSize = 120;
private const int ArtistLabelHeight = 36;
private const int TopBarButtonsY = (TopBarSize / 2 - IconSize / 2);
+ private View playerBackgroundView;
private View leftView;
private View rightView;
+ private View rightViewBackground;
private Button backButton;
private Button moreButton;
private View controlsView;
+ private View sliderView;
private Button playButton;
private Button prevButton;
private Button nextButton;
private PlayerViewModel viewModel;
+ private PlayerViewState viewState;
+
public PlayerView(PlayerViewModel viewModel) : base()
{
this.viewModel = viewModel;
WidthResizePolicy = ResizePolicyType.FillToParent;
HeightResizePolicy = ResizePolicyType.FillToParent;
+ AddPlayerBackground();
+
+ viewState = PlayerViewState.AlbumArt;
+
leftView = CreateLeftView();
rightView = CreateRightView();
+ AddRightViewBackground();
AddTopButtons();
AddControlView();
AddPlaybackSlider();
AddListActionButtons();
AddThumbnail();
- //AddPlayingListView();
AddLyricsView();
}
+ private void AddPlayerBackground()
+ {
+ playerBackgroundView = new View();
+ playerBackgroundView.Size2D = new Size2D(Window.Instance.WindowSize.Width, Window.Instance.WindowSize.Height);
+ WidthResizePolicy = ResizePolicyType.FillToParent;
+ HeightResizePolicy = ResizePolicyType.FillToParent;
+ base.Add(playerBackgroundView);
+ playerBackgroundView.BackgroundColor = Color.Transparent;
+ playerBackgroundView.BindingContext = viewModel;
+ playerBackgroundView.SetBinding(BackgroundProperty, "PlayerBackground");
+ }
+
private Button CreateButton(ImageViewStyle style, int x, int y)
{
ButtonStyle buttonStyle = new ButtonStyle()
{
View rightView = new View()
{
- BackgroundColor = Color.Green,
+ BackgroundColor = Color.Transparent,
HeightResizePolicy = ResizePolicyType.FillToParent,
SizeWidth = Window.Instance.WindowSize.Width / 2,
Position2D = new Position2D(Window.Instance.WindowSize.Width / 2, 0),
return rightView;
}
+ private void AddRightViewBackground()
+ {
+ rightViewBackground = new View();
+ rightViewBackground.BackgroundColor = Color.Transparent;
+ rightViewBackground.SizeWidth = Window.Instance.WindowSize.Width / 2;
+ rightViewBackground.SizeHeight = Window.Instance.WindowSize.Height;
+ rightViewBackground.WidthResizePolicy = ResizePolicyType.FillToParent;
+ rightViewBackground.HeightResizePolicy = ResizePolicyType.FillToParent;
+ rightView.Add(rightViewBackground);
+ rightViewBackground.BindingContext = viewModel;
+ rightViewBackground.SetBinding(BackgroundProperty, "PlayerBackground");
+ rightViewBackground.Hide();
+ }
+
+ private void UpdatePlayerViewBackground(PlayerViewState state)
+ {
+ if (state == PlayerViewState.AlbumArt)
+ {
+ rightViewBackground.Hide();
+ playerBackgroundView.Show();
+ }
+ else
+ {
+ playerBackgroundView.Hide();
+ rightViewBackground.Show();
+ }
+ }
+
private void AddTopButtons()
{
backButton = CreateButton(Resources.GetImagePath() + "back_button.png", LayoutPadding, TopBarButtonsY);
private void AddPlaybackSlider()
{
- View sliderView = new View()
+ sliderView = new View()
{
Size2D = new Size2D(1792, 80),
Position2D = new Position2D(64, 950),
AddPlaybackSlider(sliderView);
AddCurrentTimeLabel(sliderView);
AddTotalTimeLabel(sliderView);
+ UpdatePlaybackSliderPosition(viewState);
+ }
+
+ private void UpdatePlaybackSliderPosition(PlayerViewState state)
+ {
+ if(state == PlayerViewState.AlbumArt)
+ {
+ sliderView.Size2D = new Size2D(1792, 80);
+ sliderView.Position2D = new Position2D(64, 950);
+ currentTime.Size2D = new Size2D(400, 32);
+ currentTime.Position2D = new Position2D(0, 48);
+ totalTime.Size2D = new Size2D(400, 32);
+ totalTime.Position2D = new Position2D(1392, 48);
+ }
+ else
+ {
+ sliderView.Size2D = new Size2D(640, 80);
+ sliderView.Position2D = new Position2D(1056, 950);
+ currentTime.Size2D = new Size2D(180, 32);
+ currentTime.Position2D = new Position2D(0, 48);
+ totalTime.Size2D = new Size2D(180, 32);
+ totalTime.Position2D = new Position2D(460, 48);
+ }
}
private void AddListActionButtons()
rightView.Add(actionButtonView);
listButton = CreateButton(Resources.GetImagePath() + "playing_queue.png", 0, 0);
+ listButton.Clicked += (object sender, ClickedEventArgs e) =>
+ {
+ if(viewState == PlayerViewState.AlbumArt)
+ {
+ Tizen.Log.Debug(AppConstants.LogTag, "Adding Playing list view");
+ viewState = PlayerViewState.TrackList;
+ RemoveLyricsView();
+ AddPlayingListView();
+ thumb.Show();
+ }
+ else
+ {
+ Tizen.Log.Debug(AppConstants.LogTag, "Adding album art view");
+ viewState = PlayerViewState.AlbumArt;
+ RemovePlayingListView();
+ AddLyricsView();
+ thumb.Hide();
+ }
+ UpdatePlaybackSliderPosition(viewState);
+ UpdatePlayerViewBackground(viewState);
+ };
actionButtonView.Add(listButton);
playlistButton = CreateButton(Resources.GetImagePath() + "addtoplaylist.png", 88, 0);
};
thumb.SetBinding(ImageView.ResourceUrlProperty, "ThumbnailPath");
rightView.Add(thumb);
+ thumb.Hide();
}
private void AddPlayingListView()
currentListView.Size2D = new Size2D(832, 900);
currentListView.Position2D = new Position2D(64, 108);
leftView.Add(currentListView);
+ currentListView.Show();
+ }
+
+ private void RemovePlayingListView()
+ {
+ if(currentListView == null)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "current listview is null, can't remove it");
+ return;
+ }
+ leftView.Remove(currentListView);
+ currentListView.Hide();
}
private void AddLyricsView()
lyricsView.Size2D = new Size2D(784, 784);
lyricsView.Position2D = new Position2D(88, 120);
leftView.Add(lyricsView);
+ lyricsView.Show();
+ }
+
+ private void RemoveLyricsView()
+ {
+ if(lyricsView == null)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "lyricsview is null, can't remove it");
+ return;
+ }
+ leftView.Remove(lyricsView);
+ lyricsView.Hide();
}
}
}