Skip to content

Commit

Permalink
Merge pull request #10 from trunghvbk/structure
Browse files Browse the repository at this point in the history
add network package
  • Loading branch information
trunghvbk authored Jul 2, 2023
2 parents cb549f2 + 56f5422 commit 353d470
Show file tree
Hide file tree
Showing 20 changed files with 397 additions and 100 deletions.
17 changes: 6 additions & 11 deletions lib/features/cart/domain/cart.dart
Original file line number Diff line number Diff line change
@@ -1,44 +1,39 @@
import 'package:freezed_annotation/freezed_annotation.dart';

import '../../products/domain/product.dart';

part 'cart.g.dart';
part 'cart.freezed.dart';

@freezed
class Cart with _$Cart {
factory Cart({
required Map<ProductID, int> items,
required Map<String, int> items,
}) = _Cart;

factory Cart.fromJson(Map<String, dynamic> json) => _$CartFromJson(json);
}

/// Helper extension used to update the items in the shopping cart.
extension MutableCart on Cart {
Cart addItem(CartItem item) {
final copy = Map<ProductID, int>.from(items);
final copy = Map<String, int>.from(items);
// * update item quantity. Read this for more details:
// * https://codewithandrea.com/tips/dart-map-update-method/
copy[item.productID] = item.quantity + (copy[item.productID] ?? 0);
return Cart(items: copy);
}

Cart removeItemById(ProductID productId) {
final copy = Map<ProductID, int>.from(items);
Cart removeItemById(String productId) {
final copy = Map<String, int>.from(items);
copy.remove(productId);
return Cart(items: copy);
}

Cart setItem(CartItem item) {
final copy = Map<ProductID, int>.from(items);
final copy = Map<String, int>.from(items);
copy[item.productID] = item.quantity;
return Cart(items: copy);
}
}

class CartItem {
final ProductID productID;
final String productID;
final int quantity;

CartItem({required this.productID, required this.quantity});
Expand Down
19 changes: 1 addition & 18 deletions lib/features/cart/domain/cart.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,10 @@ T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');

Cart _$CartFromJson(Map<String, dynamic> json) {
return _Cart.fromJson(json);
}

/// @nodoc
mixin _$Cart {
Map<String, int> get items => throw _privateConstructorUsedError;

Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$CartCopyWith<Cart> get copyWith => throw _privateConstructorUsedError;
}
Expand Down Expand Up @@ -89,12 +84,10 @@ class __$$_CartCopyWithImpl<$Res> extends _$CartCopyWithImpl<$Res, _$_Cart>
}

/// @nodoc
@JsonSerializable()
class _$_Cart implements _Cart {
_$_Cart({required final Map<String, int> items}) : _items = items;

factory _$_Cart.fromJson(Map<String, dynamic> json) => _$$_CartFromJson(json);

final Map<String, int> _items;
@override
Map<String, int> get items {
Expand All @@ -116,7 +109,6 @@ class _$_Cart implements _Cart {
const DeepCollectionEquality().equals(other._items, _items));
}

@JsonKey(ignore: true)
@override
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(_items));
Expand All @@ -126,20 +118,11 @@ class _$_Cart implements _Cart {
@pragma('vm:prefer-inline')
_$$_CartCopyWith<_$_Cart> get copyWith =>
__$$_CartCopyWithImpl<_$_Cart>(this, _$identity);

@override
Map<String, dynamic> toJson() {
return _$$_CartToJson(
this,
);
}
}

abstract class _Cart implements Cart {
factory _Cart({required final Map<String, int> items}) = _$_Cart;

factory _Cart.fromJson(Map<String, dynamic> json) = _$_Cart.fromJson;

@override
Map<String, int> get items;
@override
Expand Down
15 changes: 0 additions & 15 deletions lib/features/cart/domain/cart.g.dart

This file was deleted.

20 changes: 16 additions & 4 deletions lib/features/main_page/presentation/widgets/main_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

class MainPage extends StatelessWidget {
Expand All @@ -15,11 +14,18 @@ class MainPage extends StatelessWidget {
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.amber,
selectedItemColor: Colors.orange.shade800,
unselectedItemColor: Colors.orange.shade100,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: 'Products',
),
BottomNavigationBarItem(
icon: Icon(Icons.logo_dev),
label: 'Weather',
Expand All @@ -40,12 +46,15 @@ class MainPage extends StatelessWidget {
if (location.startsWith('/home')) {
return 0;
}
if (location.startsWith('/weather')) {
if (location.startsWith('/product_list')) {
return 1;
}
if (location.startsWith('/account')) {
if (location.startsWith('/weather')) {
return 2;
}
if (location.startsWith('/account')) {
return 3;
}
return 0;
}

Expand All @@ -55,9 +64,12 @@ class MainPage extends StatelessWidget {
GoRouter.of(context).go('/home');
break;
case 1:
GoRouter.of(context).go('/weather');
GoRouter.of(context).go('/product_list');
break;
case 2:
GoRouter.of(context).go('/weather');
break;
case 3:
GoRouter.of(context).go('/account');
break;
}
Expand Down
5 changes: 5 additions & 0 deletions lib/features/products/application/product_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'package:flutter_app/features/products/domain/product.dart';

abstract class ProductService {
Future<List<Product>> getProducts(int currentPage, int pageSize);
}
8 changes: 0 additions & 8 deletions lib/features/products/domain/product.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import 'package:freezed_annotation/freezed_annotation.dart';

part 'product.g.dart';
part 'product.freezed.dart';

/// The ProductID is an important concept in our domain
/// so it deserves a type of its own
typedef ProductID = String;

@freezed
class Product with _$Product {
factory Product({
Expand All @@ -16,7 +11,4 @@ class Product with _$Product {
required double price,
required int availableQuantity,
}) = _Product;

factory Product.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
}
20 changes: 1 addition & 19 deletions lib/features/products/domain/product.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');

Product _$ProductFromJson(Map<String, dynamic> json) {
return _Product.fromJson(json);
}

/// @nodoc
mixin _$Product {
String get id => throw _privateConstructorUsedError;
Expand All @@ -26,7 +22,6 @@ mixin _$Product {
double get price => throw _privateConstructorUsedError;
int get availableQuantity => throw _privateConstructorUsedError;

Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ProductCopyWith<Product> get copyWith => throw _privateConstructorUsedError;
}
Expand Down Expand Up @@ -145,7 +140,7 @@ class __$$_ProductCopyWithImpl<$Res>
}

/// @nodoc
@JsonSerializable()
class _$_Product implements _Product {
_$_Product(
{required this.id,
Expand All @@ -154,9 +149,6 @@ class _$_Product implements _Product {
required this.price,
required this.availableQuantity});

factory _$_Product.fromJson(Map<String, dynamic> json) =>
_$$_ProductFromJson(json);

@override
final String id;
@override
Expand Down Expand Up @@ -187,7 +179,6 @@ class _$_Product implements _Product {
other.availableQuantity == availableQuantity));
}

@JsonKey(ignore: true)
@override
int get hashCode =>
Object.hash(runtimeType, id, imageUrl, title, price, availableQuantity);
Expand All @@ -197,13 +188,6 @@ class _$_Product implements _Product {
@pragma('vm:prefer-inline')
_$$_ProductCopyWith<_$_Product> get copyWith =>
__$$_ProductCopyWithImpl<_$_Product>(this, _$identity);

@override
Map<String, dynamic> toJson() {
return _$$_ProductToJson(
this,
);
}
}

abstract class _Product implements Product {
Expand All @@ -214,8 +198,6 @@ abstract class _Product implements Product {
required final double price,
required final int availableQuantity}) = _$_Product;

factory _Product.fromJson(Map<String, dynamic> json) = _$_Product.fromJson;

@override
String get id;
@override
Expand Down
24 changes: 0 additions & 24 deletions lib/features/products/domain/product.g.dart

This file was deleted.

18 changes: 18 additions & 0 deletions lib/features/products/presentation/product_list_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:flutter_app/features/products/application/product_service.dart';
import 'package:flutter_app/features/products/domain/product.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class ProductListController extends StateNotifier<AsyncValue<List<Product>>> {
ProductListController({required this.productService})
: super(const AsyncData([])) {
loadProducts();
}
final ProductService productService;

Future<void> loadProducts() async {
state = const AsyncLoading();
state = await AsyncValue.guard(
() => productService.getProducts(0, 100),
);
}
}
27 changes: 27 additions & 0 deletions lib/features/products/presentation/product_list_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/features/products/presentation/widgets/product_list_item.dart';
import 'package:flutter_app/providers/controller_providers.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class ProductListPage extends ConsumerWidget {
const ProductListPage({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final dataValue = ref.watch(productListControllerProvider);
return Scaffold(
appBar: AppBar(title: const Text('Product List')),
body: dataValue.when(
data: (data) {
return GridView.count(
crossAxisCount: 2,
children: data
.map((product) => ProductListItem(product: product))
.toList(),
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, __) => Text(e.toString())),
);
}
}
18 changes: 18 additions & 0 deletions lib/features/products/presentation/widgets/product_list_item.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_app/features/products/domain/product.dart';

class ProductListItem extends StatelessWidget {
final Product product;
const ProductListItem({super.key, required this.product});

@override
Widget build(BuildContext context) {
return Column(
children: [
Text(product.title),
Text('${product.availableQuantity}'),
Text('${product.price}')
],
);
}
}
Loading

0 comments on commit 353d470

Please sign in to comment.