using System.Text;
using MusicPlayer.Models;
using MusicPlayer.Common;
+using MusicPlayer.Core;
+using Tizen.NUI;
+using Tizen.Multimedia;
namespace MusicPlayer.ViewModels
{
class PlayerViewModel : PropertyNotifier
{
+ private const int PlaybackTimerDuration = 1000;
+
internal PlayerModel playerModel;
- internal PlayingListViewModel playingListViewModel;
internal LyricsViewModel lyricsViewModel;
- private string playPauseUrl;
+ private Timer playbackTimer;
+ private bool isVolumeChanging;
public PlayerViewModel()
{
lyricsViewModel = new LyricsViewModel();
playingListViewModel = new PlayingListViewModel();
playerModel = new PlayerModel();
+ playerModel.ElapsedTime = 0.0f;
PlayPauseUrl = Resources.GetImagePath() + "play.png";
+ PlayerController.Instance.PlayerEventOccurred += OnPlayerEventOccurred;
+ playbackTimer = new Timer(PlaybackTimerDuration);
+ playbackTimer.Tick += OnPlaybackTimerTick;
+ isVolumeChanging = false;
+ VolumeLevel = AudioManager.VolumeController.Level[AudioVolumeType.Media];
+ AudioManager.VolumeController.Changed += OnVolumeLevelChanged;
+ HasPreviousTrack = playingListViewModel.HasPrev();
+ HasNextTrack = playingListViewModel.HasNext();
}
+ internal PlayingListViewModel playingListViewModel;
public PlayingListViewModel CurrentPlayingListViewModel
{
get => playingListViewModel;
}
+ private string playPauseUrl;
+ public string PlayPauseUrl
+ {
+ get => playPauseUrl;
+ set => SetProperty(ref playPauseUrl, value);
+ }
+
+ private float volumeLevel;
+
+ public float VolumeLevel
+ {
+ get => volumeLevel;
+ set => SetProperty(ref volumeLevel, value);
+ }
+
+ private bool hasPreviousTrack;
+
+ public bool HasPreviousTrack
+ {
+ get => hasPreviousTrack;
+ set => SetProperty(ref hasPreviousTrack, value);
+ }
+
+ private bool hasNextTrack;
+
+ public bool HasNextTrack
+ {
+ get => hasNextTrack;
+ set => SetProperty(ref hasNextTrack, value);
+ }
+
+ public void SetPlayingList(TrackListViewModel trackListVM)
+ {
+ playingListViewModel.SetTrackListViewModel(trackListVM);
+ }
+
public void SetCurrentTrack(Track track)
{
+ Tizen.Log.Info(AppConstants.LogTag, "Setting Current track");
playerModel.CurrentTrack = track;
lyricsViewModel.CurrentTrack = track;
+ //TO DO need to set index properly
+ Track current = playingListViewModel.Current();
+ if (current == null)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "Current track is null so setting new track");
+ playingListViewModel.SetPlayingTrack(track);
+ }
+ // updating prev/next button state
+ HasPreviousTrack = playingListViewModel.HasPrev();
+ HasNextTrack = playingListViewModel.HasNext();
+
+ PlayerController.Instance.Uri = track.FilePath;
+ StartPlayback();
}
- public void SetPlayingList(TrackListViewModel trackListVM)
+ public void NextButtonClicked()
{
- playingListViewModel.SetTrackListViewModel(trackListVM);
+ Track nextTrack = playingListViewModel.Next();
+ if (nextTrack == null)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "nextTrack is null");
+ StopPlayback();
+ return;
+ }
+ Tizen.Log.Debug(AppConstants.LogTag, "Next track is: " + nextTrack.TrackTitle);
+ SetCurrentTrack(nextTrack);
+ }
+
+ public void PrevButtonClicked()
+ {
+ Track previousTrack = playingListViewModel.Prev();
+ if (previousTrack == null)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "previousTrack is null");
+ StopPlayback();
+ return;
+ }
+ Tizen.Log.Debug(AppConstants.LogTag, "Prev track is: " + previousTrack.TrackTitle);
+ SetCurrentTrack(previousTrack);
}
public void ShuffleChanged()
break;
i++;
}
- RepeatMode new_mode = RepeatMode.Off;
- RepeatMode [] repeatArr = (RepeatMode [])values;
- if(i+1 >= values.Length)
+
+ RepeatMode[] repeatArr = (RepeatMode[])values;
+ RepeatMode new_mode;
+ if (i + 1 >= values.Length)
{
new_mode = repeatArr[0];
}
playingListViewModel.RepeatMode = new_mode;
}
- public string PlayPauseUrl
- {
- get => playPauseUrl;
- set => SetProperty(ref playPauseUrl, value);
- }
-
public void PlayingStatusChanged()
{
- if(playerModel.PlayingStatus == PlayingStatus.Playing)
+ if (playerModel.PlayingStatus == PlayingStatus.Playing)
{
playerModel.PlayingStatus = PlayingStatus.Paused;
PlayPauseUrl = Resources.GetImagePath() + "play.png";
+ Pause();
+ playbackTimer.Stop();
}
else
{
playerModel.PlayingStatus = PlayingStatus.Playing;
PlayPauseUrl = Resources.GetImagePath() + "pause.png";
+ Resume();
+ playbackTimer.Start();
+ }
+ }
+
+ public void UpdatePlayerPosition(float value)
+ {
+ int currentPosition = (int)(playerModel.CurrentTrack.Duration * value);
+ PlayerController.Instance.SetPosition(currentPosition);
+ playerModel.PlayingTime = TimeSpan.FromMilliseconds(currentPosition).ToString(AppConstants.TimeFormat);
+ playbackTimer.Start();
+ }
+
+ public void StopPlaybackTimer()
+ {
+ playbackTimer.Stop();
+ }
+
+ public void SetElapsedTime(float value)
+ {
+ int currentPosition = (int)(playerModel.CurrentTrack.Duration * value);
+ playerModel.PlayingTime = TimeSpan.FromMilliseconds(currentPosition).ToString(AppConstants.TimeFormat);
+ }
+
+ public void VolumeChangeStarted()
+ {
+ isVolumeChanging = true;
+ }
+
+ public void VolumeChangeFinished(int value)
+ {
+ VolumeLevelChanged(value);
+ isVolumeChanging = false;
+ }
+ public void VolumeLevelChanged(int value)
+ {
+ AudioManager.VolumeController.Level[AudioVolumeType.Media] = value;
+ }
+
+ private bool OnPlaybackTimerTick(object source, Timer.TickEventArgs e)
+ {
+ UpdatePlayingTime();
+ return true;
+ }
+
+ private void OnPlayerEventOccurred(object sender, PlayerEventArgs e)
+ {
+ Tizen.Log.Error(AppConstants.LogTag, "Player Event Occurred:");
+ Tizen.Log.Error(AppConstants.LogTag, "\t"+e.Type.ToString());
+ Tizen.Log.Error(AppConstants.LogTag, "\t:"+e.Description);
+ if(e.Type == EventType.PlaybackCompleted)
+ {
+ PlayNext();
+ }
+ }
+
+ private void PlayNext()
+ {
+ if(playingListViewModel.RepeatMode == RepeatMode.Off)
+ {
+ Tizen.Log.Debug(AppConstants.LogTag, "Repeat is off, can't play next");
+ StopPlayback();
+ UpdatePlayingTime();
+ return;
+ }
+ NextButtonClicked();
+ }
+
+ private void UpdatePlayingTime()
+ {
+ int position = PlayerController.Instance.GetPosition();
+ playerModel.ElapsedTime = position / (float)playerModel.CurrentTrack.Duration;
+ playerModel.PlayingTime = TimeSpan.FromMilliseconds(position).ToString(AppConstants.TimeFormat);
+ }
+
+ private void StartPlayback()
+ {
+ playerModel.PlayingStatus = PlayingStatus.Playing;
+ PlayPauseUrl = Resources.GetImagePath() + "pause.png";
+ Play();
+ playbackTimer.Start();
+ }
+
+ private void StopPlayback()
+ {
+ playerModel.PlayingStatus = PlayingStatus.Stopped;
+ PlayPauseUrl = Resources.GetImagePath() + "play.png";
+ Stop();
+ playbackTimer.Stop();
+ }
+
+ private void Play()
+ {
+ PlayerController.Instance.Play();
+ }
+ private void Pause()
+ {
+ PlayerController.Instance.Pause();
+ }
+ private void Resume()
+ {
+ PlayerController.Instance.Resume();
+ }
+ private void Stop()
+ {
+ PlayerController.Instance.Stop();
+ }
+
+ private void OnVolumeLevelChanged(object sender, VolumeChangedEventArgs e)
+ {
+ if(e.Type == AudioVolumeType.Media && isVolumeChanging == false)
+ {
+ VolumeLevel = e.Level;
}
}
}
using MusicPlayer.Common;
using Tizen.NUI.Binding;
using MusicPlayer.ViewModels;
+using Tizen.Multimedia;
namespace MusicPlayer.Views
{
private const int ControlViewMargin = 315;
private const int TitleLabelHeight = 48;
private const int ArtistLabelHeight = 36;
+ private const int TopBarButtonsY = (TopBarSize / 2 - IconSize / 2);
private View leftView;
private View rightView;
AddLyricsView();
}
- private Button CreatButton(string url, int x, int y)
+ private Button CreateButton(ImageViewStyle style, int x, int y)
+ {
+ ButtonStyle buttonStyle = new ButtonStyle()
+ {
+ Icon = style,
+ IsSelectable = false,
+ IsEnabled = true,
+ };
+ Button button = new Button(buttonStyle)
+ {
+ Size2D = new Size2D(IconSize, IconSize),
+ Position2D = new Position2D(x, y),
+ };
+ return button;
+ }
+
+ private Button CreateButton(string url, int x, int y)
{
ButtonStyle buttonStyle = new ButtonStyle()
{
private void AddTopButtons()
{
- backButton = CreatButton(Resources.GetImagePath() + "back_button.png", LayoutPadding, (TopBarSize / 2 - IconSize / 2));
+ backButton = CreateButton(Resources.GetImagePath() + "back_button.png", LayoutPadding, TopBarButtonsY);
leftView.Add(backButton);
- moreButton = CreatButton(Resources.GetImagePath() + "more_button.png", Window.Instance.WindowSize.Width / 2 - LayoutPadding - IconSize, (TopBarSize / 2 - IconSize / 2));
+ moreButton = CreateButton(Resources.GetImagePath() + "more_button.png", Window.Instance.WindowSize.Width / 2 - LayoutPadding - IconSize, TopBarButtonsY);
rightView.Add(moreButton);
}
rightView.Add(controlsView);
}
- private void AddTextControlElements()
+ private void AddTitleLabel()
{
titleLabel = new TextLabel()
{
};
titleLabel.SetBinding(TextLabel.TextProperty, "TrackName");
controlsView.Add(titleLabel);
+ }
+ private void AddArtistLabel()
+ {
artistLabel = new TextLabel()
{
Size2D = new Size2D(ControlViewWidth, ArtistLabelHeight),
controlsView.Add(artistLabel);
}
- private void AddButtonControlElements()
+ private void AddTextControlElements()
{
- shuffleButton = CreatButton(Resources.GetImagePath() + "shuffle.png", 0, 196);
+ AddTitleLabel();
+ AddArtistLabel();
+ }
+
+ private void AddShuffleButton()
+ {
+ shuffleButton = CreateButton(Resources.GetImagePath() + "shuffle.png", 0, 196);
shuffleButton.Icon.BindingContext = viewModel.playingListViewModel;
shuffleButton.Icon.SetBinding(ImageView.ResourceUrlProperty, "ShuffleUrl");
+ // TODO need to implement command instead
shuffleButton.Clicked += (object sender, ClickedEventArgs e) =>
{
viewModel.ShuffleChanged();
};
controlsView.Add(shuffleButton);
+ }
- prevButton = CreatButton(Resources.GetImagePath() + "prev.png", 168, 196);
+ private void AddPreviousButton()
+ {
+ ImageViewStyle prevIconStyle = new ImageViewStyle()
+ {
+ ResourceUrl = new Selector<string>
+ {
+ Normal = Resources.GetImagePath() + "prev.png",
+ Disabled = Resources.GetImagePath() + "prev_disabled.png"
+ },
+ };
+ prevButton = CreateButton(prevIconStyle, 168, 196);
+ // TODO need to implement command instead
+ prevButton.Clicked += (object sender, ClickedEventArgs e) =>
+ {
+ viewModel.PrevButtonClicked();
+ };
+ prevButton.BindingContext = viewModel;
+ prevButton.SetBinding(Button.IsEnabledProperty, "HasPreviousTrack");
controlsView.Add(prevButton);
+ }
- playButton = CreatButton(Resources.GetImagePath() + "play.png", 296, 196);
+ private void AddPlayButton()
+ {
+ playButton = CreateButton(Resources.GetImagePath() + "play.png", 296, 196);
playButton.Icon.BindingContext = viewModel;
playButton.Icon.SetBinding(ImageView.ResourceUrlProperty, "PlayPauseUrl");
controlsView.Add(playButton);
+ // TODO need to implement command instead
playButton.Clicked += (object sender, ClickedEventArgs e) =>
{
viewModel.PlayingStatusChanged();
};
+ }
+
+ private void AddNextButton()
+ {
+ ImageViewStyle nextIconStyle = new ImageViewStyle()
+ {
+ ResourceUrl = new Selector<string>
+ {
+ Normal = Resources.GetImagePath() + "next.png",
+ Disabled = Resources.GetImagePath() + "next_disabled.png",
+ },
+ };
- nextButton = CreatButton(Resources.GetImagePath() + "next.png", 424, 196);
+ nextButton = CreateButton(nextIconStyle, 424, 196);
+ // TODO need to implement command instead
+ nextButton.Clicked += (object sender, ClickedEventArgs e) =>
+ {
+ viewModel.NextButtonClicked();
+ };
+ nextButton.BindingContext = viewModel;
+ nextButton.SetBinding(Button.IsEnabledProperty, "HasNextTrack");
controlsView.Add(nextButton);
+ }
- repeatButton = CreatButton(Resources.GetImagePath() + "repeat.png", 592, 196);
+ private void AddRepeatButton()
+ {
+ repeatButton = CreateButton(Resources.GetImagePath() + "repeat.png", 592, 196);
repeatButton.Icon.BindingContext = viewModel.playingListViewModel;
repeatButton.Icon.SetBinding(ImageView.ResourceUrlProperty, "RepeatUrl");
controlsView.Add(repeatButton);
+ // TODO need to implement command instead
repeatButton.Clicked += (object sender, ClickedEventArgs e) =>
{
viewModel.RepeatChanged();
};
}
- private void AddVolumeSliderElements()
+ private void AddButtonControlElements()
+ {
+ AddShuffleButton();
+ AddPreviousButton();
+ AddPlayButton();
+ AddNextButton();
+ AddRepeatButton();
+ }
+
+ private void AddLeftVolumeIcon()
{
leftVolumeIcon = new ImageView(Resources.GetImagePath() + "left_sound_icon.png")
{
Position2D = new Position2D(0, 336),
};
controlsView.Add(leftVolumeIcon);
+ }
+ private void AddRightVolumeIcon()
+ {
rightVolumeIcon = new ImageView(Resources.GetImagePath() + "right_sound_icon.png")
{
Size2D = new Size2D(IconSize, IconSize),
Position2D = new Position2D(592, 336),
};
controlsView.Add(rightVolumeIcon);
+ }
+ private SliderStyle CreateVolumeSliderStyle()
+ {
SliderStyle volumeSliderStyle = new SliderStyle()
{
IndicatorType = Slider.IndicatorType.Image,
},
},
};
+ return volumeSliderStyle;
+ }
- volumeSlider = new Slider(volumeSliderStyle);
+ private void AddVolumeSliderEventHandlers()
+ {
+ volumeSlider.SlidingStarted += (object sender, SliderSlidingStartedEventArgs e) =>
+ {
+ viewModel.VolumeChangeStarted();
+ };
+ volumeSlider.ValueChanged += (object sender, SliderValueChangedEventArgs e) =>
+ {
+ viewModel.VolumeLevelChanged((int)e.CurrentValue);
+ };
+ volumeSlider.SlidingFinished += (object sender, SliderSlidingFinishedEventArgs e) =>
+ {
+ viewModel.VolumeChangeFinished((int)e.CurrentValue);
+ };
+ }
+
+ private void AddVolumeSlider()
+ {
+ volumeSlider = new Slider(CreateVolumeSliderStyle());
volumeSlider.Indicator = Slider.IndicatorType.Text;
volumeSlider.TrackThickness = 4;
volumeSlider.ThumbImageURLSelector = new StringSelector
};
volumeSlider.Size2D = new Size2D(496, 48);
volumeSlider.Position2D = new Position2D(72, 336);
- volumeSlider.ThumbSize = new Size(36, 36);
+ volumeSlider.ThumbSize = new Tizen.NUI.Size(36, 36);
volumeSlider.Direction = Slider.DirectionType.Horizontal;
volumeSlider.MinValue = 0;
- volumeSlider.MaxValue = 100;
- volumeSlider.CurrentValue = 10;
+ volumeSlider.MaxValue = AudioManager.VolumeController.MaxLevel[AudioVolumeType.Media];
+ volumeSlider.CurrentValue = AudioManager.VolumeController.Level[AudioVolumeType.Media];
controlsView.Add(volumeSlider);
+ volumeSlider.BindingContext = viewModel;
+ volumeSlider.SetBinding(Slider.CurrentValueProperty, "VolumeLevel");
+ AddVolumeSliderEventHandlers();
+ }
+
+ private void AddVolumeSliderElements()
+ {
+ AddLeftVolumeIcon();
+ AddRightVolumeIcon();
+ AddVolumeSlider();
}
private void AddControlElements()
AddVolumeSliderElements();
}
- private void AddPlaybackSlider()
+ private SliderStyle CreatePlaybackSliderStyle()
{
- View sliderView = new View()
- {
- Size2D = new Size2D(1792, 80),
- Position2D = new Position2D(64, 950),
- BackgroundColor = Color.Transparent,
- };
SliderStyle playbackSliderStyle = new SliderStyle()
{
IndicatorType = Slider.IndicatorType.Image,
},
},
};
- playbackSlider = new Slider(playbackSliderStyle)
+ return playbackSliderStyle;
+ }
+
+ private void AddPlaybackSliderEventHandler()
+ {
+ playbackSlider.SlidingStarted += (object sender, SliderSlidingStartedEventArgs e) =>
+ {
+ viewModel.StopPlaybackTimer();
+ };
+ playbackSlider.ValueChanged += (object sender, SliderValueChangedEventArgs e) =>
+ {
+ viewModel.SetElapsedTime(e.CurrentValue);
+ };
+ playbackSlider.SlidingFinished += (object sender, SliderSlidingFinishedEventArgs e) =>
+ {
+ viewModel.UpdatePlayerPosition(e.CurrentValue);
+ };
+ }
+
+ private void AddPlaybackSlider(View sliderView)
+ {
+ playbackSlider = new Slider(CreatePlaybackSliderStyle())
{
ThumbImageURLSelector = new StringSelector
{
MaxValue = 1.0f,
WidthResizePolicy = ResizePolicyType.FillToParent,
SizeHeight = 44,
- ThumbSize = new Size(36, 36),
+ ThumbSize = new Tizen.NUI.Size(36, 36),
Direction = Slider.DirectionType.Horizontal,
+ IsCreateByXaml = true,
};
+ playbackSlider.SetBinding(Slider.CurrentValueProperty, "ElapsedTime");
sliderView.Add(playbackSlider);
+ AddPlaybackSliderEventHandler();
+ }
+
+ private void AddCurrentTimeLabel(View sliderView)
+ {
currentTime = new TextLabel()
{
Size2D = new Size2D(400, 32),
Text = "00::00:00",
HorizontalAlignment = HorizontalAlignment.Begin,
};
+ currentTime.SetBinding(TextLabel.TextProperty, "PlayingTime");
sliderView.Add(currentTime);
+ }
+
+ private void AddTotalTimeLabel(View sliderView)
+ {
totalTime = new TextLabel()
{
Size2D = new Size2D(400, 32),
- Position2D = new Position2D(1792-400, 48),
+ Position2D = new Position2D(1792 - 400, 48),
TextColor = UIColors.HEX001447,
PixelSize = 24,
FontFamily = "BreezeSans",
HorizontalAlignment = HorizontalAlignment.End,
Text = "59:59:59",
};
+ totalTime.SetBinding(TextLabel.TextProperty, "TrackLength");
sliderView.Add(totalTime);
- this.Add(sliderView);
+ }
+
+ private void AddPlaybackSlider()
+ {
+ View sliderView = new View()
+ {
+ Size2D = new Size2D(1792, 80),
+ Position2D = new Position2D(64, 950),
+ BackgroundColor = Color.Transparent,
+ };
+ Add(sliderView);
+
+ AddPlaybackSlider(sliderView);
+ AddCurrentTimeLabel(sliderView);
+ AddTotalTimeLabel(sliderView);
}
private void AddListActionButtons()
};
rightView.Add(actionButtonView);
- listButton = CreatButton(Resources.GetImagePath() + "playing_queue.png", 0, 0);
+ listButton = CreateButton(Resources.GetImagePath() + "playing_queue.png", 0, 0);
actionButtonView.Add(listButton);
- playlistButton = CreatButton(Resources.GetImagePath() + "addtoplaylist.png", 88, 0);
+ playlistButton = CreateButton(Resources.GetImagePath() + "addtoplaylist.png", 88, 0);
actionButtonView.Add(playlistButton);
- favouriteButton = CreatButton(Resources.GetImagePath() + "favourite_off.png", 176, 0);
+ favouriteButton = CreateButton(Resources.GetImagePath() + "favourite_off.png", 176, 0);
actionButtonView.Add(favouriteButton);
}