Skip to content

Commit

Permalink
improving code styles which should increase performances
Browse files Browse the repository at this point in the history
  • Loading branch information
iNoles committed Nov 5, 2024
1 parent d7d9638 commit 9d56155
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 75 deletions.
28 changes: 20 additions & 8 deletions MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@
xmlns:hackerNews="clr-namespace:HackerNews"
x:Class="HackerNews.MainPage"
x:DataType="hackerNews:NewsViewModel">
<ListView x:Name="NewsListView" ItemSelected="NewsListView_OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell x:DataType="hackerNews:StoryModel"
Text="{Binding Title}"
Detail="{Binding CreatedAt}" />

<CollectionView x:Name="NewsCollectionView"
ItemsSource="{Binding TopStoryCollection}"
SelectionMode="Single"
SelectionChanged="NewsCollectionView_OnSelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="hackerNews:StoryModel">
<Frame Padding="10" Margin="5" BorderColor="LightGray">
<StackLayout>
<Label Text="{Binding Title}"
FontSize="18"
FontAttributes="Bold" />
<Label Text="{Binding CreatedAt, StringFormat='{0:MMM dd, yyyy h:mm tt}'}"
FontSize="14"
TextColor="Gray" />
</StackLayout>
</Frame>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</CollectionView.ItemTemplate>
</CollectionView>

</ContentPage>
61 changes: 25 additions & 36 deletions MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,53 +1,42 @@
using Microsoft.Extensions.Logging;
namespace HackerNews;

namespace HackerNews;

public partial class MainPage
public partial class MainPage : ContentPage
{
private readonly NewsViewModel _newsViewModel;

public MainPage()

// Constructor accepting NewsViewModel via Dependency Injection
public MainPage(NewsViewModel newsViewModel)
{
InitializeComponent();
_newsViewModel = newsViewModel;

// Set up the logger
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole(); // Add other logging providers as necessary
});

var logger = loggerFactory.CreateLogger<NewsViewModel>();

// Create an instance of NewsService, passing the loggerFactory if needed
var newsService = new NewsService(loggerFactory);

// Create the NewsViewModel instance
_newsViewModel = new NewsViewModel(newsService, logger);

// Set the ItemsSource for the NewsListView
NewsListView.ItemsSource = _newsViewModel.TopStoryCollection;
// Set the BindingContext for data binding in XAML
BindingContext = _newsViewModel;
}

protected override async void OnAppearing()
{
base.OnAppearing();
await _newsViewModel.Refresh();
await _newsViewModel.RefreshAsync();
}

private async void NewsListView_OnItemSelected(object sender, SelectedItemChangedEventArgs e)
private async void NewsCollectionView_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listView = (ListView)sender;
listView.SelectedItem = null;

if (e.SelectedItem is not StoryModel storyModel) return;
if (!string.IsNullOrEmpty(storyModel.Url))
{
var browserOptions = new BrowserLaunchOptions();
await Browser.Default.OpenAsync(storyModel.Url, browserOptions);
}
else
// Check if there is a selected item and access it directly by index
if (e.CurrentSelection.Count > 0 && e.CurrentSelection[0] is StoryModel storyModel)
{
await DisplayAlert("Invalid Article", "ASK HN articles have no url", "OK");
// Clear selection
((CollectionView)sender).SelectedItem = null;

if (!string.IsNullOrEmpty(storyModel.Url))
{
var browserOptions = new BrowserLaunchOptions { LaunchMode = BrowserLaunchMode.SystemPreferred };
await Browser.Default.OpenAsync(storyModel.Url, browserOptions);
}
else
{
await DisplayAlert("Invalid Article", "ASK HN articles have no URL", "OK");
}
}
}
}
}
10 changes: 5 additions & 5 deletions NewsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ public class NewsService(ILoggerFactory loggerFactory)

private readonly ILogger<NewsService> _logger = loggerFactory.CreateLogger<NewsService>();

public async Task<string> GetTopStoryAsJson()
public async Task<string> GetTopStoryAsJsonAsync()
{
try
{
{
return await _firebaseClient
.Child("topstories.json?print=pretty")
.OnceAsJsonAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching top stories from Firebase");
throw;
_logger.LogError(ex, "Error fetching top stories from Firebase.");
throw;
}
}

public async Task<StoryModel> GetTopStory(string topStoryId)
public async Task<StoryModel> GetTopStoryAsync(string topStoryId)
{
try
{
Expand Down
46 changes: 27 additions & 19 deletions NewsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ namespace HackerNews;

public class NewsViewModel(NewsService newsService, ILogger<NewsViewModel> logger) : ObservableObject
{
public ObservableCollection<StoryModel> TopStoryCollection { get; } = new ObservableCollection<StoryModel>();
public ObservableCollection<StoryModel> TopStoryCollection { get; } = [];

private readonly NewsService _newsService = newsService;
private readonly ILogger<NewsViewModel> _logger = logger;

public async Task Refresh()
public async Task RefreshAsync()
{
// Ensure this method is called on the UI thread
await MainThread.InvokeOnMainThreadAsync(async () =>
Expand All @@ -21,7 +21,7 @@ await MainThread.InvokeOnMainThreadAsync(async () =>
{
TopStoryCollection.Clear();
await foreach (var story in GetTopStories().ConfigureAwait(false))
await foreach (var story in GetTopStoriesAsync())
{
InsertIntoSortedCollection(TopStoryCollection, (a, b) => b.Score.CompareTo(a.Score), story);
}
Expand Down Expand Up @@ -57,31 +57,39 @@ static void InsertIntoSortedCollection<T>(ObservableCollection<T> collection, Co
}
}

async IAsyncEnumerable<StoryModel> GetTopStories()
private async IAsyncEnumerable<StoryModel> GetTopStoriesAsync()
{
var stories = new List<StoryModel>();

List<string> topStoryIds = [];
try
{
var topStories = await _newsService.GetTopStoryAsJson();
var topStoryJson = JsonConvert.DeserializeObject<List<string>>(topStories);

foreach (var topStoryId in topStoryJson)
{
var story = await _newsService.GetTopStory(topStoryId);
stories.Add(story); // Add to the temporary list
}
var topStoriesJson = await _newsService.GetTopStoryAsJsonAsync();
topStoryIds = JsonConvert.DeserializeObject<List<string>>(topStoriesJson);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while fetching top stories.");
throw;
yield break; // Stop if there’s an issue fetching the top story IDs
}

// Yield the results after the try-catch block
foreach (var story in stories)

foreach (var id in topStoryIds)
{
yield return story;
StoryModel story = null;

try
{
story = await _newsService.GetTopStoryAsync(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching story with ID: {StoryId}", id);
continue; // Skip this story if there's an error fetching it
}

if (story != null)
{
yield return story; // Yield only if successfully fetched
}
}
}
}
8 changes: 1 addition & 7 deletions StoryModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,5 @@ namespace HackerNews;

public record StoryModel(long Id, string By, long Score, long Time, string Title, string Url)
{
public DateTime CreatedAt => UnixTimeStampToDateTimeOffset(Time).LocalDateTime;

static DateTimeOffset UnixTimeStampToDateTimeOffset(long unixTimeStamp)
{
var dateTimeOffset = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, default);
return dateTimeOffset.AddSeconds(unixTimeStamp);
}
public DateTime CreatedAt => DateTimeOffset.FromUnixTimeSeconds(Time).LocalDateTime;
}

0 comments on commit 9d56155

Please sign in to comment.