-
-
Notifications
You must be signed in to change notification settings - Fork 46
Store #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Store #71
Conversation
@@ -0,0 +1,3 @@ | |||
package com.example.store.models.product | |||
|
|||
class ProductsResponse : ArrayList<Product>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:final-newline reported by reviewdog 🐶
File must end with a newline (\n)
fontWeight = FontWeight.Medium | ||
) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:final-newline reported by reviewdog 🐶
File must end with a newline (\n)
} | ||
}, | ||
style = MaterialTheme.typography.bodyMedium, | ||
color = MaterialTheme.colorScheme.outline, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:trailing-comma-on-call-site reported by reviewdog 🐶
Unnecessary trailing comma before ")"
text = "$${"%.2f".format(product.price * product.quantity)}", | ||
style = MaterialTheme.typography.bodyMedium, | ||
color = MaterialTheme.colorScheme.error, | ||
fontWeight = FontWeight.Bold, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:trailing-comma-on-call-site reported by reviewdog 🐶
Unnecessary trailing comma before ")"
import androidx.compose.runtime.collectAsState | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.Color |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:no-unused-imports reported by reviewdog 🐶
Unused import
@@ -0,0 +1,2 @@ | |||
package com.example.store.ui.screen.categories |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:no-empty-file reported by reviewdog 🐶
File 'CategoriesViewModel.kt' should not be empty
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import com.example.store.theme.StoreAppTheme | ||
import com.example.store.ui.compositions.ProductItem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:no-unused-imports reported by reviewdog 🐶
Unused import
|
||
@Suppress("ktlint:compose:modifier-missing-check") | ||
@Composable | ||
fun CheckOutScreenSkeleton( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] compose:param-order-check reported by reviewdog 🐶
Parameters in a composable function should be ordered following this pattern: params without defaults, modifiers, params with defaults and optionally, a trailing function that might not have a default param.
Current params are: [goBack: () -> Unit = {}, products: List, toggleUIMode: () -> Unit, goToTab: () -> Unit = {}] but could be [products: List, toggleUIMode: () -> Unit, goBack: () -> Unit = {}, goToTab: () -> Unit = {}].
See https://mrmans0n.github.io/compose-rules/rules/#ordering-composable-parameters-properly for more information.
import androidx.compose.ui.text.input.VisualTransformation | ||
import androidx.compose.ui.tooling.preview.PreviewLightDark | ||
import androidx.compose.ui.unit.dp | ||
import androidx.compose.ui.unit.sp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] standard:no-unused-imports reported by reviewdog 🐶
Unused import
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @almuheetushihab, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
Summary of Changes
As gemini-code-assist, I've reviewed this pull request titled "Store". The primary goal of this PR is to introduce a new "Store" example feature into the application. This feature demonstrates a basic e-commerce flow, showcasing the integration of various modern Android development technologies including Jetpack Compose for the UI, Hilt for dependency injection, Retrofit and Moshi for networking, Paging 3 for list loading, and Compose Navigation for screen transitions. The new feature is added as a tutorial screen accessible from the main app's tutorial list.
Highlights
- New Store Module: A new Android library module
:store
has been created to encapsulate the entire store feature. - Jetpack Compose UI: The user interface for the store feature, including screens for Home, Product Details, Cart, Categories, Orders, Profile, and Checkout, is implemented entirely using Jetpack Compose.
- Compose Navigation: Navigation within the store feature is handled using Jetpack Compose Navigation, utilizing Serializable routes for passing arguments like product IDs or category names.
- Networking and Data: Retrofit and Moshi are used to interact with a fake store API (fakestoreapi.com) to fetch product and category data. Repositories are implemented to abstract data sources.
- Paging 3 Integration: The Paging 3 library is used in the Home screen to efficiently load and display a list of products.
- Dependency Injection: Hilt is configured and used within the
:store
module for managing dependencies, such as API interfaces and repositories. - Main App Integration: The new Store feature is integrated into the main application's navigation graph and added as an entry in the tutorial list.
Changelog
Click here to see the changelog
- .run/spotlessApply.run.xml
- Added a new Gradle run configuration for
spotlessApply
.
- Added a new Gradle run configuration for
- app/build.gradle.kts
- Added dependency on the new
:store
module.
- Added dependency on the new
- app/src/main/kotlin/org/imaginativeworld/whynotcompose/ui/screens/NavGraphMain.kt
- Imported
StoreMainScreen
. - Added
TutorialStore
data object toTutorialsScreen
sealed class. - Added a composable route for
TutorialsScreen.TutorialStore
to navigate toStoreMainScreen
.
- Imported
- app/src/main/kotlin/org/imaginativeworld/whynotcompose/ui/screens/tutorial/index/TutorialList.kt
- Added a new 'Store' entry to the list of tutorials.
- base/src/main/kotlin/org/imaginativeworld/whynotcompose/base/utils/Constants.kt
- Added
STORE_SERVER_ENDPOINT
constant for the fake store API URL.
- Added
- gradle/libs.versions.toml
- Added version reference for
material
. - Added library definitions for
androidx-material3
andmaterial
.
- Added version reference for
- settings.gradle.kts
- Included the new
:store
module in the project settings.
- Included the new
- store/.gitignore
- Added
/build
to the gitignore for the store module.
- Added
- store/build.gradle.kts
- Initial setup for the Android library module.
- Configured plugins (android library, kotlin, serialization, compose, ksp).
- Defined Android configuration (namespace, SDK versions, compile options, kotlin options, build features).
- Added dependencies for base module, common-ui-compose, core-ktx, appcompat, swiperefreshlayout, Compose libraries (UI, tooling, animation, foundation, material3, icons, runtime, navigation, constraintlayout, activity, viewmodel, paging), Timber, Hilt, Retrofit, OkHttp, Gson, Moshi, Room, Coil, Kotlinx Serialization, and Haze.
- store/src/main/AndroidManifest.xml
- Added a basic AndroidManifest file.
- store/src/main/kotlin/com/example/store/datasource/ProductPagingSource.kt
- Implemented
ProductPagingSource
using Paging 3 to load products from the repository.
- Implemented
- store/src/main/kotlin/com/example/store/di/StoreAppModule.kt
- Created a Hilt module (
StoreAppModule
) to provide Retrofit instance and API interfaces (ProductsApiInterface
,CategoriesApiInterface
) for the store feature.
- Created a Hilt module (
- store/src/main/kotlin/com/example/store/models/categorie/Categories.kt
- Defined
Categories
data class extendingArrayList<String>
.
- Defined
- store/src/main/kotlin/com/example/store/models/categorie/Category.kt
- Defined
Category
data class. - Added a dummy
categories
list for preview/placeholder.
- Defined
- store/src/main/kotlin/com/example/store/models/product/Product.kt
- Defined
Product
data class with Moshi annotations.
- Defined
- store/src/main/kotlin/com/example/store/models/product/ProductsResponse.kt
- Defined
ProductsResponse
data class extendingArrayList<Product>
.
- Defined
- store/src/main/kotlin/com/example/store/models/product/Rating.kt
- Defined
Rating
data class with Moshi annotations.
- Defined
- store/src/main/kotlin/com/example/store/network/api/CategoriesApiInterface.kt
- Defined Retrofit interface for fetching categories.
- store/src/main/kotlin/com/example/store/network/api/ProductsApiInterface.kt
- Defined Retrofit interface for fetching products with pagination.
- store/src/main/kotlin/com/example/store/repositories/CategoriesRepository.kt
- Implemented
CategoriesRepository
usingSafeApiRequest
to fetch categories.
- Implemented
- store/src/main/kotlin/com/example/store/repositories/ProductRepository.kt
- Implemented
ProductRepository
usingSafeApiRequest
to fetch products with pagination.
- Implemented
- store/src/main/kotlin/com/example/store/theme/Color.kt
- Defined basic Material 3 colors.
- store/src/main/kotlin/com/example/store/theme/Theme.kt
- Defined
StoreAppTheme
Composable using Material 3 color schemes and typography.
- Defined
- store/src/main/kotlin/com/example/store/theme/Type.kt
- Defined basic Material 3 typography.
- store/src/main/kotlin/com/example/store/ui/compositions/CartCard.kt
- Created
CartItemCard
Composable for displaying cart items with quantity controls.
- Created
- store/src/main/kotlin/com/example/store/ui/compositions/CategoryCard.kt
- Created
CategoryCard
Composable for displaying category items with Haze effect.
- Created
- store/src/main/kotlin/com/example/store/ui/compositions/KeyValue.kt
- Created
KeyValue
Composable for displaying key-value pairs.
- Created
- store/src/main/kotlin/com/example/store/ui/compositions/OrderCard.kt
- Created
OrderCard
Composable for displaying order summaries with expandable product lists.
- Created
- store/src/main/kotlin/com/example/store/ui/compositions/OrderProductItem.kt
- Created
OrderProductItem
Composable for displaying individual products within an order.
- Created
- store/src/main/kotlin/com/example/store/ui/compositions/ProductItem.kt
- Created
ProductItem
Composable for displaying product items in a grid with quantity controls and rating.
- Created
- store/src/main/kotlin/com/example/store/ui/compositions/StoreAppBar.kt
- Created
StoreAppBar
Composable for the top app bar with navigation and theme toggle.
- Created
- store/src/main/kotlin/com/example/store/ui/compositions/TabScreen.kt
- Created
TabScreen
Composable to define the main tab navigation structure (Home, Categories, Cart).
- Created
- store/src/main/kotlin/com/example/store/ui/screen/StoreMainScreen.kt
- Created
StoreMainScreen
as the entry point for the store feature, applying the theme and hosting the navigation graph.
- Created
- store/src/main/kotlin/com/example/store/ui/screen/StoreNavGraph.kt
- Defined the
StoreNavHost
Composable and navigation graph for the store feature, including routes for various screens.
- Defined the
- store/src/main/kotlin/com/example/store/ui/screen/cart/CartScreen.kt
- Implemented the Cart screen Composable, displaying cart items and total price (using dummy data).
- store/src/main/kotlin/com/example/store/ui/screen/categories/CategoriesScreen.kt
- Implemented the Categories screen Composable, displaying a grid of categories (using dummy data).
- store/src/main/kotlin/com/example/store/ui/screen/categories/CategoriesViewModel.kt
- Added an empty ViewModel file.
- store/src/main/kotlin/com/example/store/ui/screen/categorieswiseproduct/CategoriesWiseProductScreen.kt
- Implemented the Category Wise Product screen Composable (using dummy data).
- store/src/main/kotlin/com/example/store/ui/screen/checkout/CheckOutScreen.kt
- Implemented the Checkout screen Composable with address fields and order summary (using dummy data).
- store/src/main/kotlin/com/example/store/ui/screen/home/StoreHomeScreen.kt
- Implemented the Home screen Composable, displaying welcome message, profile icon, image carousel, category list, and product grid using Paging 3.
- store/src/main/kotlin/com/example/store/ui/screen/home/StoreHomeScreenViewModel.kt
- Implemented
StoreHomeScreenViewModel
using Hilt, fetching products via PagingSource and categories via repository, managing UI state.
- Implemented
- store/src/main/kotlin/com/example/store/ui/screen/login/LogInScreen.kt
- Implemented a simple Login screen Composable with basic validation.
- store/src/main/kotlin/com/example/store/ui/screen/order/OrderScreen.kt
- Implemented the Orders screen Composable, displaying a list of orders (using dummy data).
- store/src/main/kotlin/com/example/store/ui/screen/productdetails/ProductDetailsScreen.kt
- Implemented the Product Details screen Composable, displaying product information and quantity controls.
- Added dummy product data (
dummyProducts
).
- store/src/main/kotlin/com/example/store/ui/screen/profile/ProfileScreen.kt
- Implemented the Profile screen Composable as a modal bottom sheet, displaying user details and navigation options (using dummy data).
- store/src/main/kotlin/com/example/store/ui/screen/splash/SplashScreen.kt
- Implemented a simple Splash screen Composable with a delay.
- store/src/main/kotlin/com/example/store/utlis/Constants.kt
- Added a constants file with a
BASE_URL
(appears redundant given the base module's Constants).
- Added a constants file with a
- store/src/main/res/drawable/baseline_visibility_24.xml
- Added an XML drawable for a visibility icon.
- store/src/main/res/values/colors.xml
- Defined basic colors for the module.
- store/src/main/res/values/strings.xml
- Defined the app name string resource.
- store/src/main/res/values/themes.xml
- Defined a basic theme style.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Compose screens take flight,
With data flowing just right.
A store built with code,
A digital abode,
Shining bright in the dark or light.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a new 'Store' module to the project, demonstrating various UI components, navigation patterns, network calls (using Retrofit and Moshi), and data handling (using Paging 3). The structure of the new module is well-organized, separating concerns into UI, network, models, repositories, and DI. The use of Jetpack Compose for the UI is consistent with the project's theme. However, there are several areas for improvement, particularly regarding data handling, API usage, and some Compose best practices, which are detailed in the review comments below. I've reviewed the code based on general Android Kotlin Style Guide principles.
Summary of Findings
- Incorrect API Pagination Parameter: The
ProductPagingSource
andProductRepository
use apage
query parameter for fetching products, which is likely not supported by thefakestoreapi.com
API. The API documentation suggests usinglimit
andsort
instead. This will lead to incorrect or no pagination. - Incorrect Total Price Calculation: The
totalPrice
inCartScreen
andCheckOutScreen
is calculated only once on initial composition and does not update when quantities change. InCheckOutScreen
, the displayed total is also hardcoded. - Hardcoded Data in UI Screens: Several screens (
TabScreen
,StoreNavGraph
,CategoriesWiseProductScreen
,CheckOutScreen
) use hardcoded dummy data (dummyProducts
,dummyOrders
,categories
) instead of fetching dynamic data from the ViewModel/Repository. This prevents the UI from reflecting actual data changes. - Mixing API Model and UI State: The
Product
data class includes aquantity
field, which seems to be UI state (for the cart) mixed with API response fields. Separating these concerns into different data classes (e.g.,Product
andCartItem
) would improve maintainability. - Non-Idiomatic Kotlin (Extending ArrayList): Extending
ArrayList
directly inCategories.kt
andProductsResponse.kt
is not the standard Kotlin approach. Using type aliases or data classes wrappingList
is preferred. - Duplicate Constants: The
BASE_URL
constant is duplicated instore/src/main/kotlin/com/example/store/utlis/Constants.kt
andbase/src/main/kotlin/org/imaginativeworld/whynotcompose/base/utils/Constants.kt
. A single source of truth should be used. - Commented-Out Code: There is commented-out code in
CartCard.kt
,ProductItem.kt
,CategoriesWiseProductScreen.kt
, andStoreHomeScreen.kt
. This should be either uncommented or removed. - Hardcoded Local Images: Local drawable resources (
R.drawable.store
) are used for images inCategoryCard
,OrderProductItem
, andStoreHomeScreen
(profile image) instead of the image URLs provided in the data models. This prevents the display of actual images. - Modifier Suppression Annotations: Multiple composables have
@Suppress("ktlint:compose:modifier-missing-check")
annotations. The underlying lint issue should be addressed or the suppression justified. - Unconventional Navigation Back Stack Handling: The navigation logic in
StoreNavGraph.kt
usespopUpTo(MainScreen.TabScreen) { inclusive = true }
for navigating back to the tab screen from Order and Profile, andnavController.navigate
from Order/Checkout back to the tab screen. This deviates from standardpopBackStack()
behavior and might lead to unexpected back stack management. - Hardcoded Strings: The product count text in
OrderCard
is hardcoded and not localized.
Merge Readiness
This pull request introduces a significant new feature (the Store module). While the overall structure is good, there are several high-severity issues related to data correctness (pagination, total price calculation) and the use of hardcoded data instead of dynamic data fetching. These issues must be addressed before merging to ensure the module functions correctly with real data. Additionally, there are several medium-severity issues related to maintainability and navigation behavior that should also be addressed.
} | ||
composable(Screens.Cart.route) { | ||
CartScreen( | ||
products = dummyProducts, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fontWeight = FontWeight.Bold | ||
) | ||
Text( | ||
text = "$4948.00", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var name by remember { mutableStateOf(TextFieldValue("")) } | ||
var phone by remember { mutableStateOf(TextFieldValue("")) } | ||
var address by remember { mutableStateOf(TextFieldValue("")) } | ||
val totalPrice = products.sumOf { it.price } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
) { paddingValues -> | ||
val context = LocalContext.current | ||
val cartItems = remember { mutableStateListOf(*products.toTypedArray()) } | ||
val totalPrice by remember { mutableDoubleStateOf(cartItems.sumOf { it.price * it.quantity }) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The totalPrice
is calculated once when the composable is first composed. It will not update automatically when the quantities of items in cartItems
change via onQuantityChange
. You should use derivedStateOf
or recalculate the total price whenever the cartItems
list or any item's quantity changes.
val totalPrice by remember { mutableDoubleStateOf(cartItems.sumOf { it.price * it.quantity }) } | |
val totalPrice by remember(cartItems.sumOf { it.price * it.quantity }) { derivedStateOf { cartItems.sumOf { it.price * it.quantity } } } |
interface ProductsApiInterface { | ||
|
||
@GET("products") | ||
suspend fun getProducts(@Query("page") page: Long): Response<List<Product>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted in ProductPagingSource.kt
, the fakestoreapi.com
/products
endpoint does not appear to support a page
query parameter. It supports limit
and sort
. You will likely need to change this API definition to match the actual API capabilities.
suspend fun getProducts(@Query("page") page: Long): Response<List<Product>> | |
suspend fun getProducts(@Query("limit") limit: Int, @Query("sort") sort: String? = null): Response<List<Product>> |
@Suppress("ktlint:compose:modifier-missing-check") | ||
@Composable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Suppress("ktlint:compose:modifier-missing-check") | ||
@Composable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Image( | ||
painter = painterResource(org.imaginativeworld.whynotcompose.common.compose.R.drawable.store), | ||
contentDescription = "Profile Image", | ||
modifier = Modifier | ||
.size(100.dp) | ||
.clip(CircleShape), | ||
contentScale = ContentScale.Crop | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Suppress("ktlint:compose:modifier-missing-check") | ||
@Composable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
package com.example.store.utlis | ||
class Constants { | ||
companion object { | ||
const val BASE_URL = "https://fakestoreapi.com/" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Warning Gemini encountered an error creating the review. You can try again by commenting |
// description = "Easy upgrade for faster boot up, shutdown, application load and response.", | ||
// quantity = 6 | ||
// ) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [ktlint] reported by reviewdog 🐶
Not a valid Kotlin file (319:1 expecting a top level declaration)
No description provided.