From 70595875c83bcee865f5e394a7cfca2773dbdffd Mon Sep 17 00:00:00 2001 From: akv3sic Date: Sat, 4 Nov 2023 21:34:15 +0100 Subject: [PATCH 1/2] Add style cop and xml comments --- MauiStoreApp.sln | 7 +- MauiStoreApp/MauiStoreApp.csproj | 16 +++++ MauiStoreApp/Models/Address.cs | 35 ++++++++- MauiStoreApp/Models/Cart.cs | 26 ++++++- MauiStoreApp/Models/CartItemDetail.cs | 24 ++++++- MauiStoreApp/Models/CartProduct.cs | 17 ++++- MauiStoreApp/Models/Category.cs | 17 ++++- MauiStoreApp/Models/Geolocation.cs | 17 ++++- MauiStoreApp/Models/LoginRequest.cs | 19 ++++- MauiStoreApp/Models/LoginResponse.cs | 18 ++++- MauiStoreApp/Models/Name.cs | 17 ++++- MauiStoreApp/Models/Product.cs | 32 ++++++++- MauiStoreApp/Models/Rating.cs | 17 ++++- MauiStoreApp/Models/User.cs | 38 +++++++++- MauiStoreApp/Services/AuthService.cs | 28 +++++++- MauiStoreApp/Services/BaseService.cs | 37 +++++++++- MauiStoreApp/Services/CartService.cs | 17 ++++- MauiStoreApp/Services/CategoryService.cs | 20 +++++- MauiStoreApp/Services/ProductService.cs | 36 +++++++++- .../Services/RecentlyViewedProductsService.cs | 34 ++++++++- MauiStoreApp/Services/UserService.cs | 25 ++++++- MauiStoreApp/ViewModels/BaseViewModel.cs | 27 ++++++- MauiStoreApp/ViewModels/CartViewModel.cs | 72 ++++++++++++++----- .../ViewModels/CategoryPageViewModel.cs | 56 +++++++++++++-- MauiStoreApp/ViewModels/HomePageViewModel.cs | 59 +++++++++++++-- MauiStoreApp/ViewModels/LoginViewModel.cs | 25 ++++++- .../ViewModels/ProductDetailsViewModel.cs | 52 ++++++++++++-- .../ViewModels/ProfilePageViewModel.cs | 51 +++++++++++-- .../ViewModels/RecentlyViewedPageViewModel.cs | 41 +++++++++-- MauiStoreApp/stylecop.json | 20 ++++++ 30 files changed, 823 insertions(+), 77 deletions(-) create mode 100644 MauiStoreApp/stylecop.json diff --git a/MauiStoreApp.sln b/MauiStoreApp.sln index 4bad6d9..9bf00c6 100644 --- a/MauiStoreApp.sln +++ b/MauiStoreApp.sln @@ -3,7 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.34024.191 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MauiStoreApp", "MauiStoreApp\MauiStoreApp.csproj", "{9D34B1B5-C517-43AD-A59C-D57426129FD8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiStoreApp", "MauiStoreApp\MauiStoreApp.csproj", "{9D34B1B5-C517-43AD-A59C-D57426129FD8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6982EDC3-5252-4F81-8E3F-485E4134D54B}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/MauiStoreApp/MauiStoreApp.csproj b/MauiStoreApp/MauiStoreApp.csproj index 2c8cd6a..edfab50 100644 --- a/MauiStoreApp/MauiStoreApp.csproj +++ b/MauiStoreApp/MauiStoreApp.csproj @@ -80,11 +80,27 @@ + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/MauiStoreApp/Models/Address.cs b/MauiStoreApp/Models/Address.cs index 0c171ba..1352e69 100644 --- a/MauiStoreApp/Models/Address.cs +++ b/MauiStoreApp/Models/Address.cs @@ -1,28 +1,61 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents an address. + /// public class Address { + /// + /// Gets or sets the geolocation of the address. + /// [JsonPropertyName("geolocation")] public Geolocation Geolocation { get; set; } + /// + /// Gets or sets the city of the address. + /// [JsonPropertyName("city")] public string City { get; set; } + /// + /// Gets or sets the street of the address. + /// [JsonPropertyName("street")] public string Street { get; set; } + /// + /// Gets or sets the number of the address. + /// [JsonPropertyName("number")] public int Number { get; set; } + /// + /// Gets or sets the zipcode of the address. + /// [JsonPropertyName("zipcode")] public string Zipcode { get; set; } + /// + /// Gets the city with the first letter capitalized. + /// public string CityCapitalized => $"{City?.ToUpper()[0]}{City?.ToLower()[1..]}"; + /// + /// Gets the city and zipcode concatenated. + /// public string CityAndZipcode => $"{CityCapitalized} {Zipcode}"; + /// + /// Gets the full street with the first letter capitalized followed by the street number. + /// public string FullStreet => $"{Street?.ToUpper()[0]}{Street?.ToLower()[1..]} {Number}"; } } diff --git a/MauiStoreApp/Models/Cart.cs b/MauiStoreApp/Models/Cart.cs index 7ca0013..e31242f 100644 --- a/MauiStoreApp/Models/Cart.cs +++ b/MauiStoreApp/Models/Cart.cs @@ -1,21 +1,45 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents a shopping cart. + /// public class Cart { + /// + /// Gets or sets the unique identifier of the cart. + /// [JsonPropertyName("id")] public int Id { get; set; } + /// + /// Gets or sets the unique identifier of the user to whom the cart belongs. + /// [JsonPropertyName("userId")] public int UserId { get; set; } + /// + /// Gets or sets the date the cart was created or last updated. + /// [JsonPropertyName("date")] public DateTime Date { get; set; } + /// + /// Gets or sets the list of products in the cart. + /// [JsonPropertyName("products")] public List Products { get; set; } + /// + /// Gets or sets the version of the cart. + /// [JsonPropertyName("__v")] public int Version { get; set; } } diff --git a/MauiStoreApp/Models/CartItemDetail.cs b/MauiStoreApp/Models/CartItemDetail.cs index 6d4b855..d4af477 100644 --- a/MauiStoreApp/Models/CartItemDetail.cs +++ b/MauiStoreApp/Models/CartItemDetail.cs @@ -1,12 +1,24 @@ -using System.ComponentModel; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.ComponentModel; namespace MauiStoreApp.Models { + /// + /// Represents the details of an item in the shopping cart, including the product and quantity. + /// public class CartItemDetail : INotifyPropertyChanged { private Product _product; private int _quantity; + /// + /// Gets or sets the product in the cart item. + /// public Product Product { get => _product; @@ -20,6 +32,9 @@ public Product Product } } + /// + /// Gets or sets the quantity of the product in the cart item. + /// public int Quantity { get => _quantity; @@ -33,8 +48,15 @@ public int Quantity } } + /// + /// Occurs when a property value changes. + /// public event PropertyChangedEventHandler PropertyChanged; + /// + /// Raises the PropertyChanged event for the specified property. + /// + /// The name of the property that has changed. protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); diff --git a/MauiStoreApp/Models/CartProduct.cs b/MauiStoreApp/Models/CartProduct.cs index c1003c4..c41446e 100644 --- a/MauiStoreApp/Models/CartProduct.cs +++ b/MauiStoreApp/Models/CartProduct.cs @@ -1,12 +1,27 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents a product in the shopping cart, including the product ID and quantity. + /// public class CartProduct { + /// + /// Gets or sets the ID of the product. + /// [JsonPropertyName("productId")] public int ProductId { get; set; } + /// + /// Gets or sets the quantity of the product in the cart. + /// [JsonPropertyName("quantity")] public int Quantity { get; set; } } diff --git a/MauiStoreApp/Models/Category.cs b/MauiStoreApp/Models/Category.cs index eae37ea..0bf94f3 100644 --- a/MauiStoreApp/Models/Category.cs +++ b/MauiStoreApp/Models/Category.cs @@ -1,9 +1,24 @@ -namespace MauiStoreApp.Models +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace MauiStoreApp.Models { + /// + /// Represents a product category with a name and associated image. + /// public class Category { + /// + /// Gets or sets the name of the category. + /// public string Name { get; set; } + /// + /// Gets the filename of the image associated with the category. + /// public string ImageName { get diff --git a/MauiStoreApp/Models/Geolocation.cs b/MauiStoreApp/Models/Geolocation.cs index 3f9c850..213a25c 100644 --- a/MauiStoreApp/Models/Geolocation.cs +++ b/MauiStoreApp/Models/Geolocation.cs @@ -1,12 +1,27 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents a geographical location with latitude and longitude. + /// public class Geolocation { + /// + /// Gets or sets the latitude of the geographical location. + /// [JsonPropertyName("lat")] public string Lat { get; set; } + /// + /// Gets or sets the longitude of the geographical location. + /// [JsonPropertyName("long")] public string Long { get; set; } } diff --git a/MauiStoreApp/Models/LoginRequest.cs b/MauiStoreApp/Models/LoginRequest.cs index 0bca834..34ca292 100644 --- a/MauiStoreApp/Models/LoginRequest.cs +++ b/MauiStoreApp/Models/LoginRequest.cs @@ -1,12 +1,27 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents a request for user login with username and password. + /// public class LoginRequest - { + { + /// + /// Gets or sets the username for login. + /// [JsonPropertyName("username")] public string Username { get; set; } + /// + /// Gets or sets the password for login. + /// [JsonPropertyName("password")] public string Password { get; set; } } diff --git a/MauiStoreApp/Models/LoginResponse.cs b/MauiStoreApp/Models/LoginResponse.cs index 8641924..5e3fd50 100644 --- a/MauiStoreApp/Models/LoginResponse.cs +++ b/MauiStoreApp/Models/LoginResponse.cs @@ -1,12 +1,28 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents the response from a login attempt, including an authentication token and user ID. + /// public class LoginResponse { + /// + /// Gets or sets the authentication token for the user. + /// [JsonPropertyName("token")] public string Token { get; set; } + /// + /// Gets or sets the user ID. + /// + [JsonPropertyName("userId")] public int UserId { get; set; } } } diff --git a/MauiStoreApp/Models/Name.cs b/MauiStoreApp/Models/Name.cs index 01a03fc..bbd5ddf 100644 --- a/MauiStoreApp/Models/Name.cs +++ b/MauiStoreApp/Models/Name.cs @@ -1,12 +1,27 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents a person's first and last name. + /// public class Name { + /// + /// Gets or sets the first name of the person. + /// [JsonPropertyName("firstname")] public string Firstname { get; set; } + /// + /// Gets or sets the last name of the person. + /// [JsonPropertyName("lastname")] public string Lastname { get; set; } } diff --git a/MauiStoreApp/Models/Product.cs b/MauiStoreApp/Models/Product.cs index bbe7709..c36259b 100644 --- a/MauiStoreApp/Models/Product.cs +++ b/MauiStoreApp/Models/Product.cs @@ -1,27 +1,57 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents a product with its details. + /// public class Product { + /// + /// Gets or sets the identifier of the product. + /// [JsonPropertyName("id")] public int Id { get; set; } + /// + /// Gets or sets the title of the product. + /// [JsonPropertyName("title")] public string Title { get; set; } + /// + /// Gets or sets the price of the product. + /// [JsonPropertyName("price")] public decimal Price { get; set; } + /// + /// Gets or sets the description of the product. + /// [JsonPropertyName("description")] public string Description { get; set; } + /// + /// Gets or sets the category of the product. + /// [JsonPropertyName("category")] public string Category { get; set; } + /// + /// Gets or sets the image URL of the product. + /// [JsonPropertyName("image")] public string Image { get; set; } + /// + /// Gets or sets the rating of the product. + /// [JsonPropertyName("rating")] public Rating Rating { get; set; } } diff --git a/MauiStoreApp/Models/Rating.cs b/MauiStoreApp/Models/Rating.cs index b7eb1dc..8b8ac6c 100644 --- a/MauiStoreApp/Models/Rating.cs +++ b/MauiStoreApp/Models/Rating.cs @@ -1,12 +1,27 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents the rating of a product. + /// public class Rating { + /// + /// Gets or sets the rate value of the product. + /// [JsonPropertyName("rate")] public double Rate { get; set; } + /// + /// Gets or sets the number of ratings for the product. + /// [JsonPropertyName("count")] public int Count { get; set; } } diff --git a/MauiStoreApp/Models/User.cs b/MauiStoreApp/Models/User.cs index be847ed..fb22acc 100644 --- a/MauiStoreApp/Models/User.cs +++ b/MauiStoreApp/Models/User.cs @@ -1,32 +1,68 @@ -using System.Text.Json.Serialization; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Text.Json.Serialization; namespace MauiStoreApp.Models { + /// + /// Represents a user. + /// public class User { + /// + /// Gets or sets the user's identifier. + /// [JsonPropertyName("id")] public int Id { get; set; } + /// + /// Gets or sets the user's email address. + /// [JsonPropertyName("email")] public string Email { get; set; } + /// + /// Gets or sets the user's username. + /// [JsonPropertyName("username")] public string Username { get; set; } + /// + /// Gets or sets the user's password. + /// [JsonPropertyName("password")] public string Password { get; set; } + /// + /// Gets or sets the user's name information. + /// [JsonPropertyName("name")] public Name Name { get; set; } + /// + /// Gets or sets the user's phone number. + /// [JsonPropertyName("phone")] public string Phone { get; set; } + /// + /// Gets or sets the user's address information. + /// [JsonPropertyName("address")] public Address Address { get; set; } + /// + /// Gets the user's full name. + /// public string FullName => $"{Name?.Firstname?.ToUpper()[0]}{Name?.Firstname?.ToLower()[1..]} {Name?.Lastname?.ToUpper()[0]}{Name?.Lastname?.ToLower()[1..]}"; + /// + /// Gets the initials of the user's name. + /// public string AvatarInitials => $"{Name?.Firstname?.ToUpper()[0]}{Name?.Lastname?.ToUpper()[0]}"; } } diff --git a/MauiStoreApp/Services/AuthService.cs b/MauiStoreApp/Services/AuthService.cs index f8851eb..91af726 100644 --- a/MauiStoreApp/Services/AuthService.cs +++ b/MauiStoreApp/Services/AuthService.cs @@ -1,15 +1,33 @@ -using MauiStoreApp.Models; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + using System.Text; using System.Text.Json; +using MauiStoreApp.Models; namespace MauiStoreApp.Services { + /// + /// This class is responsible for authenticating the user and storing the token and userId in secure storage. + /// public class AuthService : BaseService { + /// + /// Initializes a new instance of the class. + /// public AuthService() { } + /// + /// Gets or sets a value indicating whether the user is logged in. + /// + /// + /// Checks if the token is stored in secure storage. If set to false, removes the token and userId from secure storage. + /// public bool IsUserLoggedIn { get @@ -29,12 +47,18 @@ public bool IsUserLoggedIn } } + /// + /// Logs the user in. + /// + /// The username of the user. + /// The password of the user. + /// A task of type . public async Task LoginAsync(string username, string password) { var request = new LoginRequest { Username = username, - Password = password + Password = password, }; var content = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); diff --git a/MauiStoreApp/Services/BaseService.cs b/MauiStoreApp/Services/BaseService.cs index eef30ab..fcc9fcf 100644 --- a/MauiStoreApp/Services/BaseService.cs +++ b/MauiStoreApp/Services/BaseService.cs @@ -1,11 +1,26 @@ -using System.Diagnostics; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Diagnostics; namespace MauiStoreApp.Services { + /// + /// This class provides base functionality for other service classes. + /// public class BaseService { + /// + /// An instance of . + /// protected readonly HttpClient _httpClient; + /// + /// Initializes a new instance of the class. + /// public BaseService() { _httpClient = new HttpClient @@ -14,6 +29,12 @@ public BaseService() }; } + /// + /// Sends a GET request to the specified endpoint and returns the response as an instance of type . + /// + /// The type of the response object. + /// The endpoint to send the GET request to. + /// A task of type . protected async Task GetAsync(string endpoint) { if (!IsInternetAvailable()) @@ -38,6 +59,11 @@ protected async Task GetAsync(string endpoint) } } + /// + /// Sends a DELETE request to the specified endpoint and returns the response. + /// + /// The endpoint to send the DELETE request to. + /// A task of type . protected async Task DeleteAsync(string endpoint) { if (!IsInternetAvailable()) @@ -57,6 +83,10 @@ protected async Task DeleteAsync(string endpoint) } } + /// + /// Checks if an internet connection is available. + /// + /// true if an internet connection is available; otherwise, false. private bool IsInternetAvailable() { NetworkAccess accessType = Connectivity.NetworkAccess; @@ -66,10 +96,15 @@ private bool IsInternetAvailable() if (Shell.Current != null) { if (accessType == NetworkAccess.ConstrainedInternet) + { Shell.Current.DisplayAlert("Greška!", "Internet veza je ograničena.", "U redu"); + } else + { Shell.Current.DisplayAlert("Greška!", "Internet veza nije dostupna.", "U redu"); + } } + return false; } diff --git a/MauiStoreApp/Services/CartService.cs b/MauiStoreApp/Services/CartService.cs index 6d63302..79f5c73 100644 --- a/MauiStoreApp/Services/CartService.cs +++ b/MauiStoreApp/Services/CartService.cs @@ -1,16 +1,29 @@ -using MauiStoreApp.Models; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using MauiStoreApp.Models; namespace MauiStoreApp.Services { + /// + /// Provides services for managing the shopping cart. + /// public class CartService : BaseService { private readonly ProductService _productService; private List _cartItems = new List(); // Internal cart items collection private int? cartId = null; + /// + /// Initializes a new instance of the class. + /// + /// The product service to use for retrieving product details. public CartService(ProductService productService) { - _productService = productService; + _productService = productService ?? throw new ArgumentNullException(nameof(productService)); } /// diff --git a/MauiStoreApp/Services/CategoryService.cs b/MauiStoreApp/Services/CategoryService.cs index b374d35..fc7213a 100644 --- a/MauiStoreApp/Services/CategoryService.cs +++ b/MauiStoreApp/Services/CategoryService.cs @@ -1,14 +1,30 @@ -using MauiStoreApp.Models; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using MauiStoreApp.Models; namespace MauiStoreApp.Services { + /// + /// Provides services for managing and retrieving product categories. + /// public class CategoryService : BaseService { + /// + /// Asynchronously retrieves a collection of all available product categories. + /// + /// + /// A task that represents the asynchronous operation. + /// The task result contains an enumerable collection of objects. + /// public async Task> GetCategoriesAsync() { var categories = await GetAsync>("products/categories"); - // Mapping each string to a Category object + // Maps each category name to a Category object. var categoryList = new List(); foreach (var category in categories) { diff --git a/MauiStoreApp/Services/ProductService.cs b/MauiStoreApp/Services/ProductService.cs index ba03934..d6bde1b 100644 --- a/MauiStoreApp/Services/ProductService.cs +++ b/MauiStoreApp/Services/ProductService.cs @@ -1,19 +1,53 @@ -using MauiStoreApp.Models; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using MauiStoreApp.Models; namespace MauiStoreApp.Services { + /// + /// Provides services for managing and retrieving products. + /// public class ProductService : BaseService { + /// + /// Asynchronously retrieves a collection of all available products, optionally sorted in a specific order. + /// + /// The order in which the products should be sorted. Defaults to "asc" for ascending. + /// + /// A task that represents the asynchronous operation. + /// The task result contains an enumerable collection of objects. + /// public async Task> GetProductsAsync(string sortOrder = "asc") { return await GetAsync>($"products?sort={sortOrder}"); } + /// + /// Asynchronously retrieves a product by its ID. + /// + /// The ID of the product to retrieve. + /// + /// A task that represents the asynchronous operation. + /// The task result contains the object with the specified ID. + /// public async Task GetProductByIdAsync(int id) { return await GetAsync($"products/{id}"); } + /// + /// Asynchronously retrieves a collection of products belonging to a specific category, optionally sorted in a specific order. + /// + /// The category of the products to retrieve. + /// The order in which the products should be sorted. Defaults to "asc" for ascending. + /// + /// A task that represents the asynchronous operation. + /// The task result contains an enumerable collection of objects belonging to the specified category. + /// public async Task> GetProductsByCategoryAsync(string category, string sortOrder = "asc") { return await GetAsync>($"products/category/{category}?sort={sortOrder}"); diff --git a/MauiStoreApp/Services/RecentlyViewedProductsService.cs b/MauiStoreApp/Services/RecentlyViewedProductsService.cs index a6c5017..98ee60a 100644 --- a/MauiStoreApp/Services/RecentlyViewedProductsService.cs +++ b/MauiStoreApp/Services/RecentlyViewedProductsService.cs @@ -1,19 +1,41 @@ -using CommunityToolkit.Mvvm.ComponentModel; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; using MauiStoreApp.Models; using Newtonsoft.Json; -using System.Collections.ObjectModel; namespace MauiStoreApp.Services { - public partial class RecentlyViewedProductsService: ObservableObject + /// + /// Manages and persists the list of recently viewed products. + /// + public partial class RecentlyViewedProductsService : ObservableObject { + /// + /// Initializes a new instance of the class. + /// public RecentlyViewedProductsService() { } + /// + /// Gets or sets the list of recently viewed products. + /// [ObservableProperty] private Collection recentlyViewedProducts = new(); + /// + /// Adds a product to the list of recently viewed products. + /// If the product already exists in the list, it is moved to the front. + /// The list is capped at 8 products, and older products are removed. + /// The list is then saved to persistent storage. + /// + /// The product to add. public void AddProduct(Product product) { var existingProduct = RecentlyViewedProducts.FirstOrDefault(p => p.Id == product.Id); @@ -32,6 +54,9 @@ public void AddProduct(Product product) SaveProducts(); } + /// + /// Loads the list of recently viewed products from persistent storage. + /// public void LoadProducts() { var productsJson = Preferences.Get("recently_viewed", string.Empty); @@ -42,6 +67,9 @@ public void LoadProducts() } } + /// + /// Saves the list of recently viewed products to persistent storage. + /// public void SaveProducts() { var productsJson = JsonConvert.SerializeObject(RecentlyViewedProducts); diff --git a/MauiStoreApp/Services/UserService.cs b/MauiStoreApp/Services/UserService.cs index 3f17825..c47244e 100644 --- a/MauiStoreApp/Services/UserService.cs +++ b/MauiStoreApp/Services/UserService.cs @@ -1,21 +1,44 @@ -using MauiStoreApp.Models; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using MauiStoreApp.Models; namespace MauiStoreApp.Services { + /// + /// Provides methods to interact with user data. + /// public class UserService : BaseService { private readonly AuthService _authService; + /// + /// Initializes a new instance of the class. + /// + /// An instance of the class used for authentication operations. public UserService(AuthService authService) { _authService = authService; } + /// + /// Retrieves user information by user ID. + /// + /// The ID of the user to retrieve information for. + /// A object representing the user's information. public async Task GetUserAsync(int userId) { return await GetAsync($"users/{userId}"); } + /// + /// Deletes a user account by user ID. + /// + /// The ID of the user whose account is to be deleted. + /// A boolean value indicating whether the account deletion was successful. public async Task DeleteUserAccountAsync(int userId) { var response = await DeleteAsync($"users/{userId}"); diff --git a/MauiStoreApp/ViewModels/BaseViewModel.cs b/MauiStoreApp/ViewModels/BaseViewModel.cs index 6a7ae1b..84cb032 100644 --- a/MauiStoreApp/ViewModels/BaseViewModel.cs +++ b/MauiStoreApp/ViewModels/BaseViewModel.cs @@ -1,24 +1,47 @@ -using CommunityToolkit.Mvvm.ComponentModel; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace MauiStoreApp.ViewModels { + /// + /// Provides a base implementation for view models. + /// public partial class BaseViewModel : ObservableObject { + /// + /// Initializes a new instance of the class. + /// public BaseViewModel() { } private bool _isBusy; + + /// + /// Gets or sets a value indicating whether the view model is busy performing an operation. + /// public bool IsBusy { get => _isBusy; set => SetProperty(ref _isBusy, value); } + /// + /// Gets or sets the title of the page. + /// [ObservableProperty] string title; + /// + /// Navigates back to the previous page in the navigation stack. + /// + /// A task that represents the asynchronous operation. [RelayCommand] public async Task GoBack() { @@ -36,4 +59,4 @@ private async Task GoToRoute(string pageName) await Shell.Current.GoToAsync($"//{pageName}"); } } -} \ No newline at end of file +} diff --git a/MauiStoreApp/ViewModels/CartViewModel.cs b/MauiStoreApp/ViewModels/CartViewModel.cs index bce9dbb..1a41c0a 100644 --- a/MauiStoreApp/ViewModels/CartViewModel.cs +++ b/MauiStoreApp/ViewModels/CartViewModel.cs @@ -1,13 +1,21 @@ - +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Collections.ObjectModel; +using System.Diagnostics; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MauiStoreApp.Models; using MauiStoreApp.Services; -using System.Collections.ObjectModel; -using System.Diagnostics; namespace MauiStoreApp.ViewModels { + /// + /// Represents the view model for the cart page. + /// public partial class CartViewModel : BaseViewModel { private readonly CartService _cartService; @@ -15,26 +23,45 @@ public partial class CartViewModel : BaseViewModel bool isFirstRun; - public CartViewModel(CartService cartService, ProductService productService, AuthService authService) + /// + /// Initializes a new instance of the class. + /// + /// An instance of the class used for cart operations. + /// An instance of the class used for authentication operations. + public CartViewModel(CartService cartService, AuthService authService) { _cartService = cartService; _authService = authService; isFirstRun = true; } + /// + /// Initializes a new instance of the class. + /// public CartViewModel() { } + /// + /// Gets or sets a value indicating whether the user is logged in. + /// [ObservableProperty] public bool isUserLoggedIn; - + /// + /// Gets or sets a value indicating whether the view model is busy with cart modification. + /// [ObservableProperty] private bool isBusyWithCartModification; + /// + /// Gets the cart items. + /// public ObservableCollection CartItems { get; private set; } = new ObservableCollection(); + /// + /// Initializes the cart view model. + /// [RelayCommand] public async Task Init() { @@ -45,7 +72,7 @@ public async Task Init() } else { - this.SyncCartItems(); + this.SyncCartItems(); } IsUserLoggedIn = _authService.IsUserLoggedIn; } @@ -55,7 +82,9 @@ private async Task GetCartByUserIdAsync() if (_authService.IsUserLoggedIn) { if (IsBusy) + { return; + } int userId; var userIdStr = await SecureStorage.GetAsync("userId"); @@ -89,33 +118,41 @@ private async Task GetCartByUserIdAsync() } } + /// + /// Navigates to the login page. + /// + /// A task that represents the asynchronous operation. [RelayCommand] public async Task GoToLoginPage() { await Shell.Current.GoToAsync("LoginPage"); } + /// + /// Deletes the cart. + /// + /// A task that represents the asynchronous operation. [RelayCommand] public async Task DeleteCart() { if (IsBusy || IsBusyWithCartModification) + { return; + } try { - // Ask the user for confirmation var userResponse = await Shell.Current.DisplayAlert("Potvrda", "Jeste li sigurni da želite obrisati košaricu?", "Da", "Ne"); if (!userResponse) { Debug.WriteLine("Cart deletion cancelled by the user."); - return; // exit if the user cancels the deletion + return; } if (CartItems.Count > 0) { IsBusyWithCartModification = true; - // Delete the cart var response = await _cartService.DeleteCartAsync(); if (response != null && response.IsSuccessStatusCode) @@ -147,14 +184,16 @@ public async Task DeleteCart() } } + /// + /// Increases the quantity of the specified product in the cart. + /// + /// The product whose quantity to increase. [RelayCommand] public void IncreaseProductQuantity(Product product) { try { _cartService.IncreaseProductQuantity(product.Id); - - // Refresh the cart item in the ViewModel SyncCartItems(); } catch (Exception ex) @@ -164,14 +203,16 @@ public void IncreaseProductQuantity(Product product) } } + /// + /// Decreases the quantity of the specified product in the cart. + /// + /// The product whose quantity to decrease. [RelayCommand] public void DecreaseProductQuantity(Product product) { try { _cartService.DecreaseProductQuantity(product.Id); - - // Refresh the cart items in the ViewModel SyncCartItems(); } catch (Exception ex) @@ -184,8 +225,6 @@ public void DecreaseProductQuantity(Product product) private void SyncCartItems() { var updatedCartItems = _cartService.GetCartItems(); - - // Remove items not in the updated list foreach (var item in CartItems.ToList()) { if (!updatedCartItems.Any(ci => ci.Product.Id == item.Product.Id)) @@ -194,7 +233,6 @@ private void SyncCartItems() } } - // Add or update items foreach (var updatedItem in updatedCartItems) { var existingItem = CartItems.FirstOrDefault(ci => ci.Product.Id == updatedItem.Product.Id); @@ -204,7 +242,7 @@ private void SyncCartItems() } else { - existingItem.Quantity = updatedItem.Quantity; // Assuming Quantity property notifies changes + existingItem.Quantity = updatedItem.Quantity; } } } diff --git a/MauiStoreApp/ViewModels/CategoryPageViewModel.cs b/MauiStoreApp/ViewModels/CategoryPageViewModel.cs index c29add4..dbd5389 100644 --- a/MauiStoreApp/ViewModels/CategoryPageViewModel.cs +++ b/MauiStoreApp/ViewModels/CategoryPageViewModel.cs @@ -1,48 +1,82 @@ - +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Collections.ObjectModel; +using System.Diagnostics; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MauiStoreApp.Models; using MauiStoreApp.Services; using MauiStoreApp.Views; -using System.Collections.ObjectModel; -using System.Diagnostics; namespace MauiStoreApp.ViewModels { + /// + /// Represents the view model for the category page. + /// [QueryProperty(nameof(Category), "Category")] public partial class CategoryPageViewModel : BaseViewModel { - private readonly ProductService _productService; private readonly RecentlyViewedProductsService _recentlyViewedProductsService; + /// + /// Initializes a new instance of the class. + /// + /// The product service. + /// The recently viewed products service. public CategoryPageViewModel(ProductService productService, RecentlyViewedProductsService recentlyViewedProductsService) { _productService = productService; _recentlyViewedProductsService = recentlyViewedProductsService; } + /// + /// Gets or sets the category. + /// [ObservableProperty] Category category; + /// + /// Gets or sets the sort order. + /// [ObservableProperty] string sortOrder = "asc"; + /// + /// Gets or sets a value indicating whether the view model is busy with sorting. + /// [ObservableProperty] bool isBusyWithSorting = false; + /// + /// Gets the products. + /// public ObservableCollection Products { get; private set; } = new ObservableCollection(); + /// + /// Initializes the category page view model. + /// + /// A representing the asynchronous operation. [RelayCommand] public async Task Init() { await GetProductsByCategoryAsync(); } + /// + /// Gets the products by category. + /// + /// The sort order. Can be "asc" or "desc". Defaults to "asc". private async Task GetProductsByCategoryAsync(string sortOrder = "asc") { if (IsBusy) + { return; + } try { @@ -66,18 +100,23 @@ private async Task GetProductsByCategoryAsync(string sortOrder = "asc") } } - + /// + /// Handles the product tapped event. + /// + /// The tapped product. [RelayCommand] private async Task ProductTapped(Product product) { IsBusy = true; if (product == null) + { return; + } var navigationParameter = new Dictionary { - { "Product", product } + { "Product", product }, }; _recentlyViewedProductsService.AddProduct(product); @@ -87,11 +126,16 @@ private async Task ProductTapped(Product product) IsBusy = false; } + /// + /// Sorts the products. + /// [RelayCommand] private async Task SortProducts() { if (IsBusyWithSorting) + { return; + } IsBusyWithSorting = true; diff --git a/MauiStoreApp/ViewModels/HomePageViewModel.cs b/MauiStoreApp/ViewModels/HomePageViewModel.cs index e8bf112..374feb8 100644 --- a/MauiStoreApp/ViewModels/HomePageViewModel.cs +++ b/MauiStoreApp/ViewModels/HomePageViewModel.cs @@ -1,23 +1,45 @@ -using MauiStoreApp.Models; -using MauiStoreApp.Services; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + using System.Collections.ObjectModel; using System.Diagnostics; using CommunityToolkit.Mvvm.Input; +using MauiStoreApp.Models; +using MauiStoreApp.Services; using MauiStoreApp.Views; namespace MauiStoreApp.ViewModels { + /// + /// Represents the view model for the home page. + /// public partial class HomePageViewModel : BaseViewModel { private readonly ProductService _productService; private readonly CategoryService _categoryService; private readonly RecentlyViewedProductsService _recentlyViewedProductsService; + /// + /// Gets the products. + /// public ObservableCollection Products { get; } = new ObservableCollection(); + + /// + /// Gets the categories. + /// public ObservableCollection Categories { get; } = new ObservableCollection(); - bool isFirstRun; + private bool isFirstRun; + /// + /// Initializes a new instance of the class. + /// + /// The product service. + /// The category service. + /// The recently viewed products service. public HomePageViewModel(ProductService productService, CategoryService categoryService, RecentlyViewedProductsService recentlyViewedProductsService) { _productService = productService; @@ -26,10 +48,17 @@ public HomePageViewModel(ProductService productService, CategoryService category isFirstRun = true; } + /// + /// Initializes a new instance of the class. This empty constructor is used for design-time data. + /// public HomePageViewModel() { } + /// + /// Initializes the home page view model. + /// + /// A representing the asynchronous operation. [RelayCommand] public async Task Init() { @@ -42,6 +71,9 @@ public async Task Init() } } + /// + /// Gets the categories. + /// private async Task GetCategoriesAsync() { var categories = await _categoryService.GetCategoriesAsync(); @@ -51,10 +83,15 @@ private async Task GetCategoriesAsync() } } + /// + /// Gets the products. + /// private async Task GetProductsAsync() { if (IsBusy) + { return; + } try { @@ -78,15 +115,21 @@ private async Task GetProductsAsync() } } + /// + /// Handles the product tapped event. + /// + /// The tapped product. [RelayCommand] private async Task ProductTapped(Product product) { if (product == null) + { return; + } var navigationParameter = new Dictionary { - { "Product", product } + { "Product", product }, }; _recentlyViewedProductsService.AddProduct(product); @@ -94,15 +137,21 @@ private async Task ProductTapped(Product product) await Shell.Current.GoToAsync($"{nameof(ProductDetailsPage)}", true, navigationParameter); } + /// + /// Handles the category tapped event. + /// + /// The tapped category. [RelayCommand] private async Task CategoryTapped(Category category) { if (category == null) + { return; + } var navigationParameter = new Dictionary { - { "Category", category } + { "Category", category }, }; await Shell.Current.GoToAsync($"{nameof(CategoryPage)}", true, navigationParameter); diff --git a/MauiStoreApp/ViewModels/LoginViewModel.cs b/MauiStoreApp/ViewModels/LoginViewModel.cs index 26ce17f..ed39d66 100644 --- a/MauiStoreApp/ViewModels/LoginViewModel.cs +++ b/MauiStoreApp/ViewModels/LoginViewModel.cs @@ -1,33 +1,51 @@ - +using System.Diagnostics; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MauiStoreApp.Models; using MauiStoreApp.Services; -using System.Diagnostics; namespace MauiStoreApp.ViewModels { + /// + /// The view model for the login page. + /// public partial class LoginViewModel : BaseViewModel { private readonly AuthService _authService; + /// + /// Initializes a new instance of the class. + /// + /// The authentication service. public LoginViewModel(AuthService authService) { _authService = authService; } + /// + /// Initializes a new instance of the class. This empty constructor is used for design-time data. + /// public LoginViewModel() { } + /// + /// Gets or sets the username. + /// [ObservableProperty] string username; + /// + /// Gets or sets the password. + /// [ObservableProperty] string password; - LoginResponse loginResponse = new LoginResponse(); + private LoginResponse loginResponse = new LoginResponse(); + /// + /// Attempts to log in the user. + /// [RelayCommand] public async Task Login() { @@ -45,6 +63,7 @@ public async Task Login() // save token to secure storage await SecureStorage.Default.SetAsync("token", loginResponse.Token); + // save user id to secure storage await SecureStorage.Default.SetAsync("userId", loginResponse.UserId.ToString()); diff --git a/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs b/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs index cb7243b..45ee476 100644 --- a/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs +++ b/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs @@ -1,22 +1,35 @@ - +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Collections.ObjectModel; +using System.Diagnostics; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MauiStoreApp.Models; using MauiStoreApp.Services; using MauiStoreApp.Views; -using System.Collections.ObjectModel; -using System.Diagnostics; namespace MauiStoreApp.ViewModels { + /// + /// Represents the view model for the product details page. + /// [QueryProperty(nameof(Product), "Product")] public partial class ProductDetailsViewModel : BaseViewModel { - private readonly ProductService _productService; private readonly CartService _cartService; private readonly RecentlyViewedProductsService _recentlyViewedProductsService; + /// + /// Initializes a new instance of the class. + /// + /// The product service. + /// The cart service. + /// The recently viewed products service. public ProductDetailsViewModel(ProductService productService, CartService cartService, RecentlyViewedProductsService recentlyViewedProductsService) { _productService = productService; @@ -24,18 +37,31 @@ public ProductDetailsViewModel(ProductService productService, CartService cartSe _recentlyViewedProductsService = recentlyViewedProductsService; } + /// + /// Initializes a new instance of the class. This empty constructor is used for design-time data. + /// public ProductDetailsViewModel() { - } + } + /// + /// Gets or sets the current product. + /// [ObservableProperty] Product product; + /// + /// Gets the cross-sell products. + /// public ObservableCollection CrossSellProducts { get; private set; } = new ObservableCollection(); + /// + /// Initializes the view model. + /// + /// A representing the asynchronous operation. [RelayCommand] public async Task Init() - { + { await GetProductByIdAsync(); await GetCrossSellProductsAsync(); } @@ -92,6 +118,10 @@ private async Task GetCrossSellProductsAsync() } } + /// + /// Handles the product tapped event. + /// + /// The tapped product. [RelayCommand] private async Task ProductTapped(Product product) { @@ -112,6 +142,10 @@ private async Task ProductTapped(Product product) IsBusy = false; } + /// + /// Shares the product. + /// + /// The product to share. [RelayCommand] private async Task ShareProduct(Product product) { @@ -122,10 +156,14 @@ await Share.RequestAsync(new ShareTextRequest { Uri = product.Image, Title = product.Title, - Text = "Pogledaj ovaj proizod na AStore!" + Text = "Check out this product on AStore!" }); } + /// + /// Adds the product to the cart. + /// + /// The product to add to the cart. [RelayCommand] private async Task AddToCart(Product product) { diff --git a/MauiStoreApp/ViewModels/ProfilePageViewModel.cs b/MauiStoreApp/ViewModels/ProfilePageViewModel.cs index bbb8700..5ba49e9 100644 --- a/MauiStoreApp/ViewModels/ProfilePageViewModel.cs +++ b/MauiStoreApp/ViewModels/ProfilePageViewModel.cs @@ -1,34 +1,59 @@ - +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Diagnostics; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MauiStoreApp.Models; using MauiStoreApp.Services; using MauiStoreApp.Views; -using System.Diagnostics; namespace MauiStoreApp.ViewModels { + /// + /// Represents the view model for the profile page. + /// public partial class ProfilePageViewModel : BaseViewModel { private readonly UserService _userService; private readonly AuthService _authService; + /// + /// Initializes a new instance of the class. + /// + /// The user service. + /// The authentication service. public ProfilePageViewModel(UserService userService, AuthService authService) { _userService = userService; _authService = authService; } + /// + /// Initializes a new instance of the class. This empty constructor is used for design-time data. + /// public ProfilePageViewModel() { } + /// + /// Gets or sets a value indicating whether the user is logged in. + /// [ObservableProperty] public bool isUserLoggedIn; + /// + /// Gets or sets the user. + /// [ObservableProperty] User user; + /// + /// Initializes the view model. + /// [RelayCommand] public async Task Init() { @@ -45,12 +70,12 @@ private async Task GetUserByIdAsync() { IsBusy = true; - // read id from secure storage + // Read id from secure storage var userId = await SecureStorage.Default.GetAsync("userId"); if (userId == null) { - Debug.WriteLine("User id not found in secure storage."); + Debug.WriteLine("User id not found in secure storage."); return; } else @@ -74,6 +99,9 @@ private async Task GetUserByIdAsync() } } + /// + /// Logs the user out. + /// [RelayCommand] private async Task Logout() { @@ -84,23 +112,32 @@ private async Task Logout() { _authService.IsUserLoggedIn = false; - // navigate to home page + // Navigate to home page await Shell.Current.GoToAsync("//HomePage"); } } + /// + /// Navigates to the login page. + /// [RelayCommand] private async Task Login() { await Shell.Current.GoToAsync($"{nameof(LoginPage)}"); } + /// + /// Opens the FakeStoreAPI website in a browser. + /// [RelayCommand] private static async Task OpenFakeStoreApi() { await Browser.OpenAsync("https://fakestoreapi.com/"); } + /// + /// Deletes the user account. + /// [RelayCommand] private async Task DeleteAccount() { @@ -109,7 +146,7 @@ private async Task DeleteAccount() if (result) { - // read id from secure storage + // Read id from secure storage var userId = await SecureStorage.Default.GetAsync("userId"); if (userId == null) @@ -125,7 +162,7 @@ private async Task DeleteAccount() { await Shell.Current.DisplayAlert("Obavijest", "Račun je uspješno izbrisan.", "U redu"); - // navigate to home page + // Navigate to home page await Shell.Current.GoToAsync("//HomePage"); } else diff --git a/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs b/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs index 8df393f..2596e39 100644 --- a/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs +++ b/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs @@ -1,25 +1,48 @@ -using CommunityToolkit.Mvvm.ComponentModel; +// ----------------------------------------------------------------------- +// +// Copyright (c) Kvesic, Matkovic, FSRE. All rights reserved. +// +// ----------------------------------------------------------------------- + +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MauiStoreApp.Models; -using MauiStoreApp.Views; using MauiStoreApp.Services; +using MauiStoreApp.Views; namespace MauiStoreApp.ViewModels { + /// + /// Represents the view model for the recently viewed products page. + /// public partial class RecentlyViewedPageViewModel : BaseViewModel { + /// + /// Gets or sets the recently viewed products service. + /// [ObservableProperty] public RecentlyViewedProductsService recentlyViewedProductsService; + /// + /// Initializes a new instance of the class. + /// + /// The recently viewed products service. public RecentlyViewedPageViewModel(RecentlyViewedProductsService recentlyViewedProductsService) { RecentlyViewedProductsService = recentlyViewedProductsService; } + /// + /// Initializes a new instance of the class. This empty constructor is used for design-time data. + /// public RecentlyViewedPageViewModel() { } + /// + /// Initializes the view model. + /// + /// A representing the asynchronous operation. [RelayCommand] public async Task Init() { @@ -28,6 +51,10 @@ public async Task Init() await Task.CompletedTask; } + /// + /// Handles the product tapped event. + /// + /// The tapped product. [RelayCommand] private async Task ProductTapped(Product product) { @@ -38,7 +65,7 @@ private async Task ProductTapped(Product product) var navigationParameter = new Dictionary { - { "Product", product } + { "Product", product }, }; await Shell.Current.GoToAsync($"{nameof(ProductDetailsPage)}", true, navigationParameter); @@ -46,12 +73,18 @@ private async Task ProductTapped(Product product) IsBusy = false; } + /// + /// Navigates to the home page. + /// [RelayCommand] private async Task GoToHome() { await Shell.Current.GoToAsync($"//{nameof(HomePage)}"); } + /// + /// Deletes all recently viewed products. + /// [RelayCommand] private async Task DeleteAll() { @@ -59,7 +92,7 @@ private async Task DeleteAll() var result = await Shell.Current.DisplayAlert("Brisanje", "Sigurno želite izbrisati sve nedavno gledane proizvode?", "Da", "Ne"); if (!result) - return; // exit if user cancels + return; // Exit if user cancels RecentlyViewedProductsService.RecentlyViewedProducts.Clear(); RecentlyViewedProductsService.SaveProducts(); diff --git a/MauiStoreApp/stylecop.json b/MauiStoreApp/stylecop.json new file mode 100644 index 0000000..495e3eb --- /dev/null +++ b/MauiStoreApp/stylecop.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": "Kvesic, Matkovic, FSRE", + "copyrightText": "Copyright (c) {companyName}. All rights reserved.", + "headerDecoration": "-----------------------------------------------------------------------" + }, + "orderingRules": { + "systemUsingDirectivesFirst": true, + "usingDirectivesPlacement": "outsideNamespace", + "elementOrder": [ + "kind", + "constant", + "static", + "readonly" + ] + } + } +} \ No newline at end of file From 12c6fb1426217656d4843f59d9e0ef40b1eb0df1 Mon Sep 17 00:00:00 2001 From: akv3sic Date: Sat, 4 Nov 2023 21:53:54 +0100 Subject: [PATCH 2/2] Add more comments and improve code style --- MauiStoreApp/Models/Category.cs | 2 +- MauiStoreApp/Services/CartService.cs | 2 +- MauiStoreApp/ViewModels/CartViewModel.cs | 1 + .../ViewModels/ProductDetailsViewModel.cs | 16 ++++++++++++---- MauiStoreApp/ViewModels/ProfilePageViewModel.cs | 7 +++++-- .../ViewModels/RecentlyViewedPageViewModel.cs | 4 ++++ 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/MauiStoreApp/Models/Category.cs b/MauiStoreApp/Models/Category.cs index 0bf94f3..2fbab85 100644 --- a/MauiStoreApp/Models/Category.cs +++ b/MauiStoreApp/Models/Category.cs @@ -28,7 +28,7 @@ public string ImageName return null; } - string formattedName = Name.Replace(" ", "_").Replace("'", "").ToLower(); + string formattedName = Name.Replace(" ", "_").Replace("'", string.Empty).ToLower(); return formattedName + ".jpg"; } } diff --git a/MauiStoreApp/Services/CartService.cs b/MauiStoreApp/Services/CartService.cs index 79f5c73..7c3a18b 100644 --- a/MauiStoreApp/Services/CartService.cs +++ b/MauiStoreApp/Services/CartService.cs @@ -67,7 +67,7 @@ public async Task RefreshCartItemsByUserIdAsync(int userId) _cartItems.Add(new CartItemDetail { Product = productDetails, - Quantity = cartProduct.Quantity + Quantity = cartProduct.Quantity, }); } } diff --git a/MauiStoreApp/ViewModels/CartViewModel.cs b/MauiStoreApp/ViewModels/CartViewModel.cs index 1a41c0a..019e227 100644 --- a/MauiStoreApp/ViewModels/CartViewModel.cs +++ b/MauiStoreApp/ViewModels/CartViewModel.cs @@ -62,6 +62,7 @@ public CartViewModel() /// /// Initializes the cart view model. /// + /// A representing the asynchronous operation. [RelayCommand] public async Task Init() { diff --git a/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs b/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs index 45ee476..d376be6 100644 --- a/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs +++ b/MauiStoreApp/ViewModels/ProductDetailsViewModel.cs @@ -81,7 +81,7 @@ private async Task GetProductByIdAsync() catch (Exception ex) { Debug.WriteLine($"Unable to get product: {ex.Message}"); - await Shell.Current.DisplayAlert("Error!", ex.Message, "OK"); + await Shell.Current.DisplayAlert("Došlo je do pogreške!", ex.Message, "U redu"); } finally { @@ -92,7 +92,9 @@ private async Task GetProductByIdAsync() private async Task GetCrossSellProductsAsync() { if (IsBusy || Product == null) + { return; + } try { @@ -110,7 +112,7 @@ private async Task GetCrossSellProductsAsync() catch (Exception ex) { Debug.WriteLine($"Unable to get cross-sell products: {ex.Message}"); - await Shell.Current.DisplayAlert("Error!", ex.Message, "OK"); + await Shell.Current.DisplayAlert("Došlo je do pogreške!", ex.Message, "U redu"); } finally { @@ -128,11 +130,13 @@ private async Task ProductTapped(Product product) IsBusy = true; if (product == null) + { return; + } var navigationParameter = new Dictionary { - { "Product", product } + { "Product", product }, }; _recentlyViewedProductsService.AddProduct(product); @@ -156,7 +160,7 @@ await Share.RequestAsync(new ShareTextRequest { Uri = product.Image, Title = product.Title, - Text = "Check out this product on AStore!" + Text = "Pogledaj ovaj proizvod na AStore!", }); } @@ -168,12 +172,16 @@ await Share.RequestAsync(new ShareTextRequest private async Task AddToCart(Product product) { if (IsBusy) + { return; + } try { if (product == null) + { return; + } _cartService.AddProductToCart(product); diff --git a/MauiStoreApp/ViewModels/ProfilePageViewModel.cs b/MauiStoreApp/ViewModels/ProfilePageViewModel.cs index 5ba49e9..cb03983 100644 --- a/MauiStoreApp/ViewModels/ProfilePageViewModel.cs +++ b/MauiStoreApp/ViewModels/ProfilePageViewModel.cs @@ -54,6 +54,7 @@ public ProfilePageViewModel() /// /// Initializes the view model. /// + /// A representing the asynchronous operation. [RelayCommand] public async Task Init() { @@ -64,7 +65,9 @@ public async Task Init() private async Task GetUserByIdAsync() { if (IsBusy) + { return; + } try { @@ -105,8 +108,8 @@ private async Task GetUserByIdAsync() [RelayCommand] private async Task Logout() { - // fire alert - var result = await Shell.Current.DisplayAlert("Odjava", "Jeste li sigurni da se želite odjaviti?", "Da", "Ne"); + // fire alert + var result = await Shell.Current.DisplayAlert("Odjava", "Jeste li sigurni da se želite odjaviti?", "Da", "Ne"); if (result) { diff --git a/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs b/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs index 2596e39..055c978 100644 --- a/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs +++ b/MauiStoreApp/ViewModels/RecentlyViewedPageViewModel.cs @@ -61,7 +61,9 @@ private async Task ProductTapped(Product product) IsBusy = true; if (product == null) + { return; + } var navigationParameter = new Dictionary { @@ -92,7 +94,9 @@ private async Task DeleteAll() var result = await Shell.Current.DisplayAlert("Brisanje", "Sigurno želite izbrisati sve nedavno gledane proizvode?", "Da", "Ne"); if (!result) + { return; // Exit if user cancels + } RecentlyViewedProductsService.RecentlyViewedProducts.Clear(); RecentlyViewedProductsService.SaveProducts();