parent
00eb7808d8
commit
84222618d5
@ -0,0 +1,38 @@ |
|||||||
|
abstract class RemoteResource<T> { |
||||||
|
RemoteResource._(); |
||||||
|
|
||||||
|
factory RemoteResource.loading() { |
||||||
|
return LoadingRemoteResource(); |
||||||
|
} |
||||||
|
|
||||||
|
factory RemoteResource.error(String errorMessage) { |
||||||
|
return ErrorRemoteResource(errorMessage); |
||||||
|
} |
||||||
|
|
||||||
|
factory RemoteResource.finished(T value) { |
||||||
|
return FinishedRemoteResource(value); |
||||||
|
} |
||||||
|
|
||||||
|
FinishedRemoteResource<T> asFinished() { |
||||||
|
return this as FinishedRemoteResource<T>; |
||||||
|
} |
||||||
|
|
||||||
|
ErrorRemoteResource<T> asError() { |
||||||
|
return this as ErrorRemoteResource<T>; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class ErrorRemoteResource<T> extends RemoteResource<T> { |
||||||
|
final String errorMessage; |
||||||
|
|
||||||
|
ErrorRemoteResource(this.errorMessage) : super._(); |
||||||
|
} |
||||||
|
|
||||||
|
class LoadingRemoteResource<T> extends RemoteResource<T> { |
||||||
|
LoadingRemoteResource() : super._(); |
||||||
|
} |
||||||
|
|
||||||
|
class FinishedRemoteResource<T> extends RemoteResource<T> { |
||||||
|
final T value; |
||||||
|
FinishedRemoteResource(this.value) : super._(); |
||||||
|
} |
@ -1,31 +1,44 @@ |
|||||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||||
import 'package:thesis_shop/models/product.dart'; |
import 'package:thesis_shop/models/remote_resource.dart'; |
||||||
|
import 'package:thesis_shop/screens/product_list/cart_button_overlay.dart'; |
||||||
|
import 'package:thesis_shop/screens/product_list/product_list.dart'; |
||||||
|
import 'package:thesis_shop/stores/product_store.dart'; |
||||||
import 'package:thesis_shop/widgets/user_switch.dart'; |
import 'package:thesis_shop/widgets/user_switch.dart'; |
||||||
|
|
||||||
import 'cart_button_overlay.dart'; |
|
||||||
import 'product_list.dart'; |
|
||||||
|
|
||||||
const _productPlaceholder = [ |
|
||||||
Product(title: 'Bananen', price: 3), |
|
||||||
Product(title: 'Äpfel', price: 2), |
|
||||||
Product(title: 'Birnen', price: 2.5), |
|
||||||
Product(title: 'Kirschen', price: 1.2), |
|
||||||
]; |
|
||||||
|
|
||||||
class ProductListScreen extends StatelessWidget { |
class ProductListScreen extends StatelessWidget { |
||||||
const ProductListScreen({Key? key}) : super(key: key); |
const ProductListScreen({Key? key}) : super(key: key); |
||||||
|
|
||||||
@override |
@override |
||||||
Widget build(BuildContext context) { |
Widget build(BuildContext context) { |
||||||
const products = _productPlaceholder; |
|
||||||
return Scaffold( |
return Scaffold( |
||||||
appBar: AppBar( |
appBar: AppBar( |
||||||
title: const Text('Thesis Shop'), |
title: const Text('Thesis Shop'), |
||||||
actions: const [UserSwitch()], |
actions: const [UserSwitch()], |
||||||
), |
), |
||||||
body: const CartButtonOverlay( |
body: const _ProductStateSwitch(), |
||||||
child: ProductList(products: products), |
|
||||||
), |
|
||||||
); |
); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
|
class _ProductStateSwitch extends StatelessWidget { |
||||||
|
const _ProductStateSwitch({Key? key}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
final remoteProducts = ProductStore.of(context).products; |
||||||
|
if (remoteProducts is FinishedRemoteResource) { |
||||||
|
final products = remoteProducts.asFinished().value; |
||||||
|
return CartButtonOverlay( |
||||||
|
child: ProductList( |
||||||
|
products: products, |
||||||
|
), |
||||||
|
); |
||||||
|
} else if (remoteProducts is ErrorRemoteResource) { |
||||||
|
return Center(child: Text(remoteProducts.asError().errorMessage)); |
||||||
|
} else if (remoteProducts is LoadingRemoteResource) { |
||||||
|
return const Center(child: CircularProgressIndicator.adaptive()); |
||||||
|
} else { |
||||||
|
throw UnimplementedError(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
@ -0,0 +1,70 @@ |
|||||||
|
import 'package:flutter/widgets.dart'; |
||||||
|
import 'package:thesis_shop/models/product.dart'; |
||||||
|
import 'package:thesis_shop/models/remote_resource.dart'; |
||||||
|
import 'package:thesis_shop/service/product_service.dart'; |
||||||
|
|
||||||
|
class ProductStoreImplementation extends StatefulWidget { |
||||||
|
final Widget child; |
||||||
|
final ProductService productService; |
||||||
|
const ProductStoreImplementation({ |
||||||
|
Key? key, |
||||||
|
required this.child, |
||||||
|
required this.productService, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
_ProductStoreImplementationState createState() => |
||||||
|
_ProductStoreImplementationState(); |
||||||
|
} |
||||||
|
|
||||||
|
class _ProductStoreImplementationState |
||||||
|
extends State<ProductStoreImplementation> { |
||||||
|
RemoteResource<List<Product>> products = RemoteResource.loading(); |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
loadProducts().catchError( |
||||||
|
(err) => setState( |
||||||
|
() { |
||||||
|
products = RemoteResource.error(err.toString()); |
||||||
|
}, |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Future<void> loadProducts() async { |
||||||
|
final remoteProducts = await widget.productService.fetchProducts(); |
||||||
|
setState(() { |
||||||
|
products = RemoteResource.finished(remoteProducts); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return ProductStore(products: products, child: widget.child); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class ProductStore extends InheritedWidget { |
||||||
|
const ProductStore({ |
||||||
|
Key? key, |
||||||
|
required this.products, |
||||||
|
required Widget child, |
||||||
|
}) : super(key: key, child: child); |
||||||
|
|
||||||
|
final RemoteResource<List<Product>> products; |
||||||
|
List<Product> get mustProducts => products.asFinished().value; |
||||||
|
|
||||||
|
static ProductStore of(BuildContext context) { |
||||||
|
final ProductStore? result = |
||||||
|
context.dependOnInheritedWidgetOfExactType<ProductStore>(); |
||||||
|
assert(result != null, 'No ProductStore found in context'); |
||||||
|
return result!; |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
bool updateShouldNotify(ProductStore oldWidget) { |
||||||
|
return oldWidget.products != products; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue