Skip to content

Commit

Permalink
Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
naweed committed Aug 27, 2022
1 parent 3d7ac71 commit c00ff45
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 17 deletions.
44 changes: 44 additions & 0 deletions src/Maui.Apps.Framework/Extensions/DateExtensions.cs
@@ -0,0 +1,44 @@
namespace Maui.Apps.Framework.Extensions;

public static class DateExtensions
{
public static string ToTimeAgo(this DateTime baseTime)
{
var _timeSpan = DateTime.Now - baseTime;

if (_timeSpan.TotalMinutes == 0)
return "Just now";

if (_timeSpan.TotalMinutes < 60)
return Convert.ToInt32(_timeSpan.TotalMinutes).ToString() + " mins ago";

if (_timeSpan.TotalHours < 2)
return Convert.ToInt32(_timeSpan.TotalHours).ToString() + " hour ago";

if (_timeSpan.TotalHours < 24)
return Convert.ToInt32(_timeSpan.TotalHours).ToString() + " hours ago";

if (_timeSpan.TotalDays < 2)
return Convert.ToInt32(_timeSpan.TotalDays).ToString() + " day ago";

if (_timeSpan.TotalDays < 365)
return Convert.ToInt32(_timeSpan.TotalDays).ToString() + " days ago";

if (Convert.ToDouble(_timeSpan.TotalDays / 365) < 2)
return "1 year ago";

return Convert.ToDouble(_timeSpan.TotalDays / 365).ToString("#") + " years ago";
}

public static string ToReadableString(this TimeSpan span) =>
string.Format("{0}{1}{2}{3}",
span.Duration().Days > 0 ? string.Format("{0:0} day{1}, ", span.Days, span.Days == 1 ? string.Empty : "s") : string.Empty,
span.Duration().Hours > 0 ? string.Format("{0:0} hr{1}, ", span.Hours, span.Hours == 1 ? string.Empty : "s") : string.Empty,
span.Duration().Minutes > 0 ? string.Format("{0:0} min{1}, ", span.Minutes, span.Minutes == 1 ? string.Empty : "s") : string.Empty,
span.Duration().Seconds > 0 ? string.Format("{0:0} sec{1}", span.Seconds, span.Seconds == 1 ? string.Empty : "s") : string.Empty);

public static TimeSpan ToTimeSpan(this string isoDuration) =>
System.Xml.XmlConvert.ToTimeSpan(isoDuration);
}


12 changes: 12 additions & 0 deletions src/Maui.Apps.Framework/Extensions/NumberExtensions.cs
@@ -0,0 +1,12 @@
namespace Maui.Apps.Framework.Extensions;

public static class NumberExtensions
{
public static string FormattedNumber(this double number) =>
number switch
{
>= 1000000 => (number / 1000000D).ToString("0.#M"),
>= 10000 => (number / 1000D).ToString("0.#K"),
_ => number.ToString("#,0")
};
}
3 changes: 3 additions & 0 deletions src/Maui.Apps.Framework/Extensions/StringExtensions.cs
Expand Up @@ -4,5 +4,8 @@ public static class StringExtensions
{
public static string CleanCacheKey(this string uri) =>
Regex.Replace((new Regex("[\\~#%&*{}/:<>?|\"-]")).Replace(uri, " "), @"\s+", "_");

public static string FormattedNumber(this string number) =>
Convert.ToDouble(number).FormattedNumber();
}

2 changes: 2 additions & 0 deletions src/MauiTubePlayer/IServices/IApiService.cs
Expand Up @@ -4,5 +4,7 @@ public interface IApiService
{
Task<VideoSearchResult> SearchVideos(string searchQuery, string nextPageToken = "");
Task<ChannelSearchResult> GetChannels(string channelIDs);
Task<YoutubeVideoDetail> GetVideoDetails(string videoID);
Task<CommentsSearchResult> GetComments(string videoID);
}

2 changes: 2 additions & 0 deletions src/MauiTubePlayer/MauiProgram.cs
Expand Up @@ -49,6 +49,8 @@ private static void RegisterAppServices(IServiceCollection services)

//Register View Models
services.AddSingleton<StartPageViewModel>();
services.AddTransient<VideoDetailsPageViewModel>();

}
}

125 changes: 123 additions & 2 deletions src/MauiTubePlayer/Models/YoutubeModels.cs
Expand Up @@ -58,6 +58,27 @@ public class Snippet
public string ChannelTitle { get; set; }

public string ChannelImageURL { get; set; }

//For Details
[JsonPropertyName("tags")]
public List<string> Tags { get; set; }

//For Comments
[JsonPropertyName("topLevelComment")]
public TopLevelComment TopLevelComment { get; set; }

[JsonPropertyName("textDisplay")]
public string TextDisplay { get; set; }

[JsonPropertyName("authorDisplayName")]
public string AuthorDisplayName { get; set; }

[JsonPropertyName("authorProfileImageUrl")]
public string AuthorProfileImageUrl { get; set; }

[JsonPropertyName("likeCount")]
public int LikeCount { get; set; }

}

public class Thumbnails
Expand Down Expand Up @@ -91,7 +112,107 @@ public class Channel
[JsonPropertyName("snippet")]
public Snippet Snippet { get; set; }

//[JsonPropertyName("statistics")]
//public Statistics Statistics { get; set; }
[JsonPropertyName("statistics")]
public Statistics Statistics { get; set; }

public string SubscribersCount
{
get => $"{Statistics.SubscriberCount.FormattedNumber()} subscribers";
}


}

//Video Details related models
public class VideoDetailsResult
{
[JsonPropertyName("items")]
public List<YoutubeVideoDetail> Items { get; set; }
}

public class YoutubeVideoDetail
{
[JsonPropertyName("id")]
public string Id { get; set; }

[JsonPropertyName("snippet")]
public Snippet Snippet { get; set; }

//For Details
[JsonPropertyName("statistics")]
public Statistics Statistics { get; set; }

[JsonPropertyName("contentDetails")]
public ContentDetails ContentDetails { get; set; }

public string VideoSubtitle
{
get => $"{Statistics.ViewCount.FormattedNumber()} views | {Snippet.PublishedAt.ToTimeAgo()}";
}

public string LikesCount
{
get => Statistics.LikeCount.FormattedNumber();
}

public string VideoDuration
{
get => ContentDetails.Duration.ToTimeSpan().ToReadableString();
}

public string CommentsCount
{
get => Statistics.CommentCount.FormattedNumber();
}

}

public class ContentDetails
{
[JsonPropertyName("duration")]
public string Duration { get; set; }
}

public class Statistics
{
[JsonPropertyName("viewCount")]
public string ViewCount { get; set; }

[JsonPropertyName("likeCount")]
public string LikeCount { get; set; }

[JsonPropertyName("commentCount")]
public string CommentCount { get; set; }

[JsonPropertyName("subscriberCount")]
public string SubscriberCount { get; set; }

}

//Comments related models
public class CommentsSearchResult
{
[JsonPropertyName("nextPageToken")]
public string NextPageToken { get; set; }

[JsonPropertyName("items")]
public List<Comment> Items { get; set; }
}

public class Comment
{
[JsonPropertyName("id")]
public string Id { get; set; }

[JsonPropertyName("snippet")]
public Snippet Snippet { get; set; }
}

public class TopLevelComment
{
[JsonPropertyName("id")]
public string Id { get; set; }

[JsonPropertyName("snippet")]
public Snippet Snippet { get; set; }
}
19 changes: 19 additions & 0 deletions src/MauiTubePlayer/Services/YoutubeService.cs
Expand Up @@ -26,5 +26,24 @@ public async Task<ChannelSearchResult> GetChannels(string channelIDs)

return result;
}

public async Task<YoutubeVideoDetail> GetVideoDetails(string videoID)
{
var resourceUri = $"videos?part=contentDetails,id,snippet,statistics&key={Constants.ApiKey}&id={videoID}";

var result = await GetAsync<VideoDetailsResult>(resourceUri, 24); //Cached for 24 hours

return result.Items.First();
}

public async Task<CommentsSearchResult> GetComments(string videoID)
{
var resourceUri = $"commentThreads?part=snippet&maxResults=100&key={Constants.ApiKey}&videoId={videoID}";

var result = await GetAsync<CommentsSearchResult>(resourceUri, 4); //Cached for 4 hours

return result;
}

}

87 changes: 87 additions & 0 deletions src/MauiTubePlayer/ViewModels/VideoDetailsPageViewModel.cs
@@ -0,0 +1,87 @@
namespace MauiTubePlayer.ViewModels;

public partial class VideoDetailsPageViewModel : AppViewModelBase
{
[ObservableProperty]
private YoutubeVideoDetail theVideo;

[ObservableProperty]
private List<YoutubeVideo> similarVideos;

[ObservableProperty]
private Channel theChannel;

[ObservableProperty]
private bool similarVideosAvailable;

[ObservableProperty]
private List<Comment> comments;

public event EventHandler DownloadCompleted;


public VideoDetailsPageViewModel(IApiService appApiService) : base(appApiService)
{
this.Title = "TUBE PLAYER";
}

public override async void OnNavigatedTo(object parameters)
{
var videoID = (string)parameters;

SetDataLodingIndicators(true);

this.LoadingText = "Hold on while we load the video details...";

try
{
SimilarVideos = new();
Comments = new();

//Get Video Details
TheVideo = await _appApiService.GetVideoDetails(videoID);

//Get Channel URL and set in the video
var channelSearchResult = await _appApiService.GetChannels(TheVideo.Snippet.ChannelId);
TheChannel = channelSearchResult.Items.First();

//Find Similar Videos
if (TheVideo.Snippet.Tags is not null)
{
var similarVideosSearchResult = await _appApiService.SearchVideos(TheVideo.Snippet.Tags.First(), "");

SimilarVideos = similarVideosSearchResult.Items;
SimilarVideosAvailable = (SimilarVideos?.Count > 0);
}

//Get Comments
var commentsSearchResult = await _appApiService.GetComments(videoID);
Comments = commentsSearchResult.Items;


//Raise Data Load completed event to the UI
this.DataLoaded = true;

//Raise the Event to notify the UI of download completion
DownloadCompleted?.Invoke(this, new EventArgs());
}
catch (InternetConnectionException iex)
{
this.IsErrorState = true;
this.ErrorMessage = "Slow or no internet connection." + Environment.NewLine + "Please check you internet connection and try again.";
ErrorImage = "nointernet.png";
}
catch (Exception ex)
{
this.IsErrorState = true;
this.ErrorMessage = $"Something went wrong. If the problem persists, plz contact support at {Constants.EmailAddress} with the error message:" + Environment.NewLine + Environment.NewLine + ex.Message;
ErrorImage = "error.png";
}
finally
{
SetDataLodingIndicators(false);
}
}

}

0 comments on commit c00ff45

Please sign in to comment.