From ea3015520ee4a75e1e4be671a0d8f928ad6bae35 Mon Sep 17 00:00:00 2001 From: Jan Marsh Date: Thu, 8 Sep 2022 17:35:50 +0200 Subject: [PATCH 1/6] clean architecture with pure flutter --- lib/main.dart | 9 +++++- lib/src/app.dart | 8 +++-- lib/src/core/{utils => util}/.gitkeep | 0 lib/src/feature/authentication/.gitkeep | 0 .../data/datasource/counter.datasource.dart | 12 ++++++++ .../data/datasource/local/counter.db.dart | 15 ++++++++++ .../data/datasource/remote/counter.api.dart | 19 ++++++++++++ .../data/repository/counter.repository.dart | 30 +++++++++++++++++++ .../feature/counter/domain/counter.model.dart | 13 ++++++++ .../presentation/counter.controller.dart | 16 ++++++++++ .../counter/presentation}/counter.page.dart | 16 +++++++--- pubspec.lock | 7 +++++ pubspec.yaml | 1 + test/widget_test.dart | 7 ++++- 14 files changed, 144 insertions(+), 9 deletions(-) rename lib/src/core/{utils => util}/.gitkeep (100%) create mode 100644 lib/src/feature/authentication/.gitkeep create mode 100644 lib/src/feature/counter/data/datasource/counter.datasource.dart create mode 100644 lib/src/feature/counter/data/datasource/local/counter.db.dart create mode 100644 lib/src/feature/counter/data/datasource/remote/counter.api.dart create mode 100644 lib/src/feature/counter/data/repository/counter.repository.dart create mode 100644 lib/src/feature/counter/domain/counter.model.dart create mode 100644 lib/src/feature/counter/presentation/counter.controller.dart rename lib/src/{features/counter => feature/counter/presentation}/counter.page.dart (61%) diff --git a/lib/main.dart b/lib/main.dart index e00f7b8..9d2837a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,13 @@ import 'package:counter_workshop/src/app.dart'; +import 'package:counter_workshop/src/feature/counter/data/datasource/remote/counter.api.dart'; +import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; import 'package:flutter/material.dart'; void main() { - runApp(const App()); + final CounterRepository counterRepository = CounterRepository(counterDataSource: CounterAPI()); + runApp( + App( + counterRepository: counterRepository, + ), + ); } diff --git a/lib/src/app.dart b/lib/src/app.dart index 7de08a3..66af71a 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -1,8 +1,10 @@ -import 'package:counter_workshop/src/features/counter/counter.page.dart'; +import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; +import 'package:counter_workshop/src/feature/counter/presentation/counter.page.dart'; import 'package:flutter/material.dart'; class App extends StatelessWidget { - const App({super.key}); + const App({required this.counterRepository, super.key}); + final CounterRepository counterRepository; @override Widget build(BuildContext context) { @@ -11,7 +13,7 @@ class App extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - home: const CounterPage(), + home: CounterPage(counterRepository: counterRepository), ); } } diff --git a/lib/src/core/utils/.gitkeep b/lib/src/core/util/.gitkeep similarity index 100% rename from lib/src/core/utils/.gitkeep rename to lib/src/core/util/.gitkeep diff --git a/lib/src/feature/authentication/.gitkeep b/lib/src/feature/authentication/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/feature/counter/data/datasource/counter.datasource.dart b/lib/src/feature/counter/data/datasource/counter.datasource.dart new file mode 100644 index 0000000..f95c433 --- /dev/null +++ b/lib/src/feature/counter/data/datasource/counter.datasource.dart @@ -0,0 +1,12 @@ +import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; + +/// The interface for a DataSource that provides access to a single [Counter] +abstract class CounterDataSource { + /// Fetches a counter with the give id + /// + /// If no counter with the given id exits, a [CounterNotFoundException] error is thrown. + Future fetchCounter(String id); +} + +/// Error thrown when a [Counter] is not found. +class CounterNotFoundException implements Exception {} diff --git a/lib/src/feature/counter/data/datasource/local/counter.db.dart b/lib/src/feature/counter/data/datasource/local/counter.db.dart new file mode 100644 index 0000000..cf1e55e --- /dev/null +++ b/lib/src/feature/counter/data/datasource/local/counter.db.dart @@ -0,0 +1,15 @@ +import 'package:counter_workshop/src/feature/counter/data/datasource/counter.datasource.dart'; +import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; + +/// Locale app database like SqlLite that providers a [Counter] +class CounterDBDataSource implements CounterDataSource { + @override + Future fetchCounter(String id) { + // TODO: implement fetchCounter + + // 1. Connect to DB + // 2. SELECT data into CounterEntity + // 3. Translate the CounterEntity to CounterModel and return it + throw UnimplementedError(); + } +} diff --git a/lib/src/feature/counter/data/datasource/remote/counter.api.dart b/lib/src/feature/counter/data/datasource/remote/counter.api.dart new file mode 100644 index 0000000..1e407bb --- /dev/null +++ b/lib/src/feature/counter/data/datasource/remote/counter.api.dart @@ -0,0 +1,19 @@ +import 'package:counter_workshop/src/feature/counter/data/datasource/counter.datasource.dart'; +import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; + +/// Remote restful API that providers a [Counter] +class CounterAPI implements CounterDataSource { + @override + Future fetchCounter(String id) { + // simulate a network delay + return Future.delayed(const Duration(milliseconds: 300), () { + if (id == '1') { + // return a dummy counter + return Counter(value: 0); + } else { + // return a exception + throw CounterNotFoundException(); + } + }); + } +} diff --git a/lib/src/feature/counter/data/repository/counter.repository.dart b/lib/src/feature/counter/data/repository/counter.repository.dart new file mode 100644 index 0000000..af6ac48 --- /dev/null +++ b/lib/src/feature/counter/data/repository/counter.repository.dart @@ -0,0 +1,30 @@ +import 'dart:async'; + +import 'package:counter_workshop/src/feature/counter/data/datasource/counter.datasource.dart'; +import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; +import 'dart:developer'; + +class CounterRepository { + CounterRepository({required this.counterDataSource}) { + _fetchCounterData(); + } + + final CounterDataSource counterDataSource; + Counter _counter = Counter(value: 0); + + // prefill repository Counter from API + Future _fetchCounterData() async { + log('retriving default counter'); + _counter = await counterDataSource.fetchCounter('1'); + } + + Counter getCounter() { + return _counter; + } + + void increment({required int amount}) { + log('incrementing counter ${_counter.value} by $amount'); + _counter.value += amount; + return; + } +} diff --git a/lib/src/feature/counter/domain/counter.model.dart b/lib/src/feature/counter/domain/counter.model.dart new file mode 100644 index 0000000..3f76ace --- /dev/null +++ b/lib/src/feature/counter/domain/counter.model.dart @@ -0,0 +1,13 @@ +import 'package:equatable/equatable.dart'; + +// ignore: must_be_immutable +class Counter extends Equatable { + Counter({ + this.value = 0, + }); + + int value; + + @override + List get props => [value]; +} diff --git a/lib/src/feature/counter/presentation/counter.controller.dart b/lib/src/feature/counter/presentation/counter.controller.dart new file mode 100644 index 0000000..fc4ad72 --- /dev/null +++ b/lib/src/feature/counter/presentation/counter.controller.dart @@ -0,0 +1,16 @@ +import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; +import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; + +class CounterController { + const CounterController({required this.counterRepository}); + + final CounterRepository counterRepository; + + Counter get counter { + return counterRepository.getCounter(); + } + + void increment() async { + counterRepository.increment(amount: 1); + } +} diff --git a/lib/src/features/counter/counter.page.dart b/lib/src/feature/counter/presentation/counter.page.dart similarity index 61% rename from lib/src/features/counter/counter.page.dart rename to lib/src/feature/counter/presentation/counter.page.dart index 1057806..74aaabc 100644 --- a/lib/src/features/counter/counter.page.dart +++ b/lib/src/feature/counter/presentation/counter.page.dart @@ -1,18 +1,26 @@ +import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; +import 'package:counter_workshop/src/feature/counter/presentation/counter.controller.dart'; import 'package:flutter/material.dart'; class CounterPage extends StatefulWidget { - const CounterPage({super.key}); + const CounterPage({required this.counterRepository, super.key}); + final CounterRepository counterRepository; @override State createState() => _CounterPageState(); } class _CounterPageState extends State { - int _counter = 0; + late final CounterController counterController; + @override + void initState() { + counterController = CounterController(counterRepository: widget.counterRepository); + super.initState(); + } void _incrementCounter() { setState(() { - _counter++; + counterController.increment(); }); } @@ -30,7 +38,7 @@ class _CounterPageState extends State { 'You have pushed the button this many times:', ), Text( - '$_counter', + '${counterController.counter.value}', style: Theme.of(context).textTheme.headline4, ), ], diff --git a/pubspec.lock b/pubspec.lock index dcd008a..dbeb122 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -155,6 +155,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.3" + equatable: + dependency: "direct main" + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fca082e..c41b6db 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: sdk: flutter cupertino_icons: ^1.0.2 + equatable: ^2.0.5 dev_dependencies: flutter_test: diff --git a/test/widget_test.dart b/test/widget_test.dart index 504e6ab..5dac378 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -6,13 +6,18 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:counter_workshop/src/app.dart'; +import 'package:counter_workshop/src/feature/counter/data/datasource/remote/counter.api.dart'; +import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(const App()); + await tester.pumpWidget( + App(counterRepository: CounterRepository(counterDataSource: CounterAPI())), + const Duration(seconds: 1), // Should be using a Fake-/Mock-Implementation instead of slowing tests down + ); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); From ab9e6d7b2c6771820c9c6e0e561aecbcca0b2006 Mon Sep 17 00:00:00 2001 From: Jan Marsh Date: Thu, 8 Sep 2022 18:34:12 +0200 Subject: [PATCH 2/6] adding a more real world data layer --- lib/main.dart | 8 +++-- lib/src/app.dart | 4 +-- lib/src/core/{util => extensions}/.gitkeep | 0 .../authentication => core/utils}/.gitkeep | 0 lib/src/core/widgets/.gitkeep | 0 .../data/repository/counter.repository.dart | 30 ----------------- lib/src/features/authentication/.gitkeep | 0 .../data/datasources}/local/counter.db.dart | 6 ++-- .../data/datasources/remote/counter.api.dart} | 4 +-- .../remote/dtos/counter_response.dto.dart | 5 +++ .../src/graphql/counter_graphql.api.dart | 14 ++++++++ .../remote/src/mock/counter_fake.api.dart} | 6 ++-- .../remote/src/rest/counter_rest.api.dart | 23 +++++++++++++ .../data/repositories/counter.repository.dart | 32 +++++++++++++++++++ .../counter/domain/counter.model.dart | 0 .../presentation/counter.controller.dart | 4 +-- .../counter/presentation/counter.page.dart | 4 +-- pubspec.lock | 7 ++++ pubspec.yaml | 1 + test/widget_test.dart | 9 +++--- 20 files changed, 105 insertions(+), 52 deletions(-) rename lib/src/core/{util => extensions}/.gitkeep (100%) rename lib/src/{feature/authentication => core/utils}/.gitkeep (100%) create mode 100644 lib/src/core/widgets/.gitkeep delete mode 100644 lib/src/feature/counter/data/repository/counter.repository.dart create mode 100644 lib/src/features/authentication/.gitkeep rename lib/src/{feature/counter/data/datasource => features/counter/data/datasources}/local/counter.db.dart (56%) rename lib/src/{feature/counter/data/datasource/counter.datasource.dart => features/counter/data/datasources/remote/counter.api.dart} (75%) create mode 100644 lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart create mode 100644 lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart rename lib/src/{feature/counter/data/datasource/remote/counter.api.dart => features/counter/data/datasources/remote/src/mock/counter_fake.api.dart} (64%) create mode 100644 lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart create mode 100644 lib/src/features/counter/data/repositories/counter.repository.dart rename lib/src/{feature => features}/counter/domain/counter.model.dart (100%) rename lib/src/{feature => features}/counter/presentation/counter.controller.dart (61%) rename lib/src/{feature => features}/counter/presentation/counter.page.dart (87%) diff --git a/lib/main.dart b/lib/main.dart index 9d2837a..199d822 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,12 @@ import 'package:counter_workshop/src/app.dart'; -import 'package:counter_workshop/src/feature/counter/data/datasource/remote/counter.api.dart'; -import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/local/counter.db.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart'; +import 'package:counter_workshop/src/features/counter/data/repositories/counter.repository.dart'; import 'package:flutter/material.dart'; void main() { - final CounterRepository counterRepository = CounterRepository(counterDataSource: CounterAPI()); + final CounterRepository counterRepository = + CounterRepository(counterApi: CounterFakeApi(), counterDatabase: CounterDatabase()); runApp( App( counterRepository: counterRepository, diff --git a/lib/src/app.dart b/lib/src/app.dart index 66af71a..b524aa6 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -1,5 +1,5 @@ -import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; -import 'package:counter_workshop/src/feature/counter/presentation/counter.page.dart'; +import 'package:counter_workshop/src/features/counter/data/repositories/counter.repository.dart'; +import 'package:counter_workshop/src/features/counter/presentation/counter.page.dart'; import 'package:flutter/material.dart'; class App extends StatelessWidget { diff --git a/lib/src/core/util/.gitkeep b/lib/src/core/extensions/.gitkeep similarity index 100% rename from lib/src/core/util/.gitkeep rename to lib/src/core/extensions/.gitkeep diff --git a/lib/src/feature/authentication/.gitkeep b/lib/src/core/utils/.gitkeep similarity index 100% rename from lib/src/feature/authentication/.gitkeep rename to lib/src/core/utils/.gitkeep diff --git a/lib/src/core/widgets/.gitkeep b/lib/src/core/widgets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/feature/counter/data/repository/counter.repository.dart b/lib/src/feature/counter/data/repository/counter.repository.dart deleted file mode 100644 index af6ac48..0000000 --- a/lib/src/feature/counter/data/repository/counter.repository.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'dart:async'; - -import 'package:counter_workshop/src/feature/counter/data/datasource/counter.datasource.dart'; -import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; -import 'dart:developer'; - -class CounterRepository { - CounterRepository({required this.counterDataSource}) { - _fetchCounterData(); - } - - final CounterDataSource counterDataSource; - Counter _counter = Counter(value: 0); - - // prefill repository Counter from API - Future _fetchCounterData() async { - log('retriving default counter'); - _counter = await counterDataSource.fetchCounter('1'); - } - - Counter getCounter() { - return _counter; - } - - void increment({required int amount}) { - log('incrementing counter ${_counter.value} by $amount'); - _counter.value += amount; - return; - } -} diff --git a/lib/src/features/authentication/.gitkeep b/lib/src/features/authentication/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/feature/counter/data/datasource/local/counter.db.dart b/lib/src/features/counter/data/datasources/local/counter.db.dart similarity index 56% rename from lib/src/feature/counter/data/datasource/local/counter.db.dart rename to lib/src/features/counter/data/datasources/local/counter.db.dart index cf1e55e..a0c8ac7 100644 --- a/lib/src/feature/counter/data/datasource/local/counter.db.dart +++ b/lib/src/features/counter/data/datasources/local/counter.db.dart @@ -1,9 +1,7 @@ -import 'package:counter_workshop/src/feature/counter/data/datasource/counter.datasource.dart'; -import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; /// Locale app database like SqlLite that providers a [Counter] -class CounterDBDataSource implements CounterDataSource { - @override +class CounterDatabase { Future fetchCounter(String id) { // TODO: implement fetchCounter diff --git a/lib/src/feature/counter/data/datasource/counter.datasource.dart b/lib/src/features/counter/data/datasources/remote/counter.api.dart similarity index 75% rename from lib/src/feature/counter/data/datasource/counter.datasource.dart rename to lib/src/features/counter/data/datasources/remote/counter.api.dart index f95c433..80051a0 100644 --- a/lib/src/feature/counter/data/datasource/counter.datasource.dart +++ b/lib/src/features/counter/data/datasources/remote/counter.api.dart @@ -1,7 +1,7 @@ -import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; /// The interface for a DataSource that provides access to a single [Counter] -abstract class CounterDataSource { +abstract class CounterApi { /// Fetches a counter with the give id /// /// If no counter with the given id exits, a [CounterNotFoundException] error is thrown. diff --git a/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart b/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart new file mode 100644 index 0000000..56e2452 --- /dev/null +++ b/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart @@ -0,0 +1,5 @@ +class CounterResponseDto { + CounterResponseDto({this.counterValue}); + + final int? counterValue; +} diff --git a/lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart b/lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart new file mode 100644 index 0000000..8de0fc0 --- /dev/null +++ b/lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart @@ -0,0 +1,14 @@ +import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; + +/// Remote graphQL API that providers a [Counter] +class CounterGraphqlApi implements CounterApi { + CounterGraphqlApi(this.graphQLClient); + final dynamic graphQLClient; + + @override + Future fetchCounter(String id) { + // TODO: Implement + return graphQLClient.fetchCounter(); + } +} diff --git a/lib/src/feature/counter/data/datasource/remote/counter.api.dart b/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart similarity index 64% rename from lib/src/feature/counter/data/datasource/remote/counter.api.dart rename to lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart index 1e407bb..07157b7 100644 --- a/lib/src/feature/counter/data/datasource/remote/counter.api.dart +++ b/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart @@ -1,8 +1,8 @@ -import 'package:counter_workshop/src/feature/counter/data/datasource/counter.datasource.dart'; -import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; /// Remote restful API that providers a [Counter] -class CounterAPI implements CounterDataSource { +class CounterFakeApi implements CounterApi { @override Future fetchCounter(String id) { // simulate a network delay diff --git a/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart b/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart new file mode 100644 index 0000000..6600337 --- /dev/null +++ b/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart @@ -0,0 +1,23 @@ +import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; +import 'package:http/http.dart' as http; + +/// Remote restful API that providers a [Counter] +class CounterRestApi implements CounterApi { + CounterRestApi({required this.client}); + final http.Client client; + + @override + Future fetchCounter(String id) { + // simulate a network delay + return Future.delayed(const Duration(milliseconds: 300), () { + if (id == '1') { + // return a dummy counter + return Counter(value: 0); + } else { + // return a exception + throw CounterNotFoundException(); + } + }); + } +} diff --git a/lib/src/features/counter/data/repositories/counter.repository.dart b/lib/src/features/counter/data/repositories/counter.repository.dart new file mode 100644 index 0000000..9f85597 --- /dev/null +++ b/lib/src/features/counter/data/repositories/counter.repository.dart @@ -0,0 +1,32 @@ +import 'dart:async'; + +import 'package:counter_workshop/src/features/counter/data/datasources/local/counter.db.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; +import 'dart:developer'; + +class CounterRepository { + CounterRepository({required this.counterApi, required this.counterDatabase}) { + _fetchCounterData(); + } + + final CounterApi counterApi; + final CounterDatabase counterDatabase; + Counter _counter = Counter(value: 0); + + // prefill repository Counter from API + Future _fetchCounterData() async { + log('retriving default counter'); + _counter = await counterApi.fetchCounter('1'); + } + + Counter getCounter() { + return _counter; + } + + void increment({required int amount}) { + log('incrementing counter ${_counter.value} by $amount'); + _counter.value += amount; + return; + } +} diff --git a/lib/src/feature/counter/domain/counter.model.dart b/lib/src/features/counter/domain/counter.model.dart similarity index 100% rename from lib/src/feature/counter/domain/counter.model.dart rename to lib/src/features/counter/domain/counter.model.dart diff --git a/lib/src/feature/counter/presentation/counter.controller.dart b/lib/src/features/counter/presentation/counter.controller.dart similarity index 61% rename from lib/src/feature/counter/presentation/counter.controller.dart rename to lib/src/features/counter/presentation/counter.controller.dart index fc4ad72..d84fd91 100644 --- a/lib/src/feature/counter/presentation/counter.controller.dart +++ b/lib/src/features/counter/presentation/counter.controller.dart @@ -1,5 +1,5 @@ -import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; -import 'package:counter_workshop/src/feature/counter/domain/counter.model.dart'; +import 'package:counter_workshop/src/features/counter/data/repositories/counter.repository.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; class CounterController { const CounterController({required this.counterRepository}); diff --git a/lib/src/feature/counter/presentation/counter.page.dart b/lib/src/features/counter/presentation/counter.page.dart similarity index 87% rename from lib/src/feature/counter/presentation/counter.page.dart rename to lib/src/features/counter/presentation/counter.page.dart index 74aaabc..414063a 100644 --- a/lib/src/feature/counter/presentation/counter.page.dart +++ b/lib/src/features/counter/presentation/counter.page.dart @@ -1,5 +1,5 @@ -import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; -import 'package:counter_workshop/src/feature/counter/presentation/counter.controller.dart'; +import 'package:counter_workshop/src/features/counter/data/repositories/counter.repository.dart'; +import 'package:counter_workshop/src/features/counter/presentation/counter.controller.dart'; import 'package:flutter/material.dart'; class CounterPage extends StatefulWidget { diff --git a/pubspec.lock b/pubspec.lock index dbeb122..9f08ebd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -221,6 +221,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.5" http_multi_server: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c41b6db..64199fa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: cupertino_icons: ^1.0.2 equatable: ^2.0.5 + http: ^0.13.5 dev_dependencies: flutter_test: diff --git a/test/widget_test.dart b/test/widget_test.dart index 5dac378..bce9704 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -6,8 +6,9 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:counter_workshop/src/app.dart'; -import 'package:counter_workshop/src/feature/counter/data/datasource/remote/counter.api.dart'; -import 'package:counter_workshop/src/feature/counter/data/repository/counter.repository.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/local/counter.db.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart'; +import 'package:counter_workshop/src/features/counter/data/repositories/counter.repository.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -15,8 +16,8 @@ void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget( - App(counterRepository: CounterRepository(counterDataSource: CounterAPI())), - const Duration(seconds: 1), // Should be using a Fake-/Mock-Implementation instead of slowing tests down + App(counterRepository: CounterRepository(counterApi: CounterFakeApi(), counterDatabase: CounterDatabase())), + const Duration(milliseconds: 500), // Because of FakeApi delay ); // Verify that our counter starts at 0. From 4cc851337d2a303a69292ae531f883165e2d690a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Ku=CC=88hle?= Date: Fri, 9 Sep 2022 08:37:29 +0200 Subject: [PATCH 3/6] =?UTF-8?q?Mapper=20eingef=C3=BChrt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/datasources/local/counter.db.dart | 15 ++++++------ .../counter_response.converter.dart | 18 ++++++++++++++ .../data/datasources/remote/counter.api.dart | 12 +++++++--- .../remote/dtos/counter_response.dto.dart | 15 ++++++++++-- .../src/graphql/counter_graphql.api.dart | 14 ----------- .../remote/src/mock/counter_fake.api.dart | 24 ++++++++++++++++--- .../remote/src/rest/counter_rest.api.dart | 23 +++++++++--------- .../data/repositories/counter.repository.dart | 24 +++++++++++++------ .../counter/domain/counter.model.dart | 10 +++++--- .../presentation/counter.controller.dart | 2 +- 10 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 lib/src/features/counter/data/datasources/remote/converters/counter_response.converter.dart delete mode 100644 lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart diff --git a/lib/src/features/counter/data/datasources/local/counter.db.dart b/lib/src/features/counter/data/datasources/local/counter.db.dart index a0c8ac7..92e8e5c 100644 --- a/lib/src/features/counter/data/datasources/local/counter.db.dart +++ b/lib/src/features/counter/data/datasources/local/counter.db.dart @@ -1,13 +1,14 @@ import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; -/// Locale app database like SqlLite that providers a [Counter] +/// Locale app database like SqlLite that providers a [CounterModel] class CounterDatabase { - Future fetchCounter(String id) { - // TODO: implement fetchCounter + CounterModel _counter = CounterModel(value: 0); - // 1. Connect to DB - // 2. SELECT data into CounterEntity - // 3. Translate the CounterEntity to CounterModel and return it - throw UnimplementedError(); + CounterModel getCounter() { + return _counter; + } + + storeCounter(CounterModel counter) { + _counter = counter; } } diff --git a/lib/src/features/counter/data/datasources/remote/converters/counter_response.converter.dart b/lib/src/features/counter/data/datasources/remote/converters/counter_response.converter.dart new file mode 100644 index 0000000..cedca38 --- /dev/null +++ b/lib/src/features/counter/data/datasources/remote/converters/counter_response.converter.dart @@ -0,0 +1,18 @@ +import 'package:counter_workshop/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart'; +import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; + +class CounterResponseConverter { + CounterModel toModel(CounterResponseDto counterResponseDto) { + return CounterModel( + value: counterResponseDto.counterValue, + id: counterResponseDto.sysId, + ); + } + + CounterResponseDto toDto(CounterModel counter) { + return CounterResponseDto( + counterValue: counter.value, + sysId: counter.id, + ); + } +} diff --git a/lib/src/features/counter/data/datasources/remote/counter.api.dart b/lib/src/features/counter/data/datasources/remote/counter.api.dart index 80051a0..999a7c7 100644 --- a/lib/src/features/counter/data/datasources/remote/counter.api.dart +++ b/lib/src/features/counter/data/datasources/remote/counter.api.dart @@ -1,12 +1,18 @@ +import 'package:counter_workshop/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart'; import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; -/// The interface for a DataSource that provides access to a single [Counter] +/// The interface for a DataSource that provides access to a single [CounterModel] abstract class CounterApi { /// Fetches a counter with the give id /// /// If no counter with the given id exits, a [CounterNotFoundException] error is thrown. - Future fetchCounter(String id); + Future fetchCounter(String id); + + /// Increments counter with given id + /// + /// If no counter with the given id exits, a [CounterNotFoundException] error is thrown. + Future incrementCounter(String id, int amount); } -/// Error thrown when a [Counter] is not found. +/// Error thrown when a [CounterModel] is not found. class CounterNotFoundException implements Exception {} diff --git a/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart b/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart index 56e2452..acef8ed 100644 --- a/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart +++ b/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart @@ -1,5 +1,16 @@ class CounterResponseDto { - CounterResponseDto({this.counterValue}); + CounterResponseDto({ + this.sysId, + required this.counterValue, + this.createdAt, + this.updatedAt, + }); - final int? counterValue; + final int counterValue; + + final DateTime? createdAt; + + final DateTime? updatedAt; + + final String? sysId; } diff --git a/lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart b/lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart deleted file mode 100644 index 8de0fc0..0000000 --- a/lib/src/features/counter/data/datasources/remote/src/graphql/counter_graphql.api.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; -import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; - -/// Remote graphQL API that providers a [Counter] -class CounterGraphqlApi implements CounterApi { - CounterGraphqlApi(this.graphQLClient); - final dynamic graphQLClient; - - @override - Future fetchCounter(String id) { - // TODO: Implement - return graphQLClient.fetchCounter(); - } -} diff --git a/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart b/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart index 07157b7..49ba0aa 100644 --- a/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart +++ b/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart @@ -1,19 +1,37 @@ import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart'; import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; -/// Remote restful API that providers a [Counter] +/// Remote restful API that providers a [CounterModel] class CounterFakeApi implements CounterApi { + final CounterResponseDto _counterDto = CounterResponseDto( + counterValue: 0, + sysId: '1', + createdAt: DateTime.now(), + ); + @override - Future fetchCounter(String id) { + Future fetchCounter(String id) { // simulate a network delay return Future.delayed(const Duration(milliseconds: 300), () { if (id == '1') { // return a dummy counter - return Counter(value: 0); + return _counterDto; } else { // return a exception throw CounterNotFoundException(); } }); } + + @override + Future incrementCounter(String id, int amount) { + return Future.delayed(const Duration(milliseconds: 300), () { + return CounterResponseDto( + counterValue: _counterDto.counterValue + amount, + sysId: '1', + createdAt: DateTime.now(), + ); + }); + } } diff --git a/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart b/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart index 6600337..0a23bc5 100644 --- a/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart +++ b/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart @@ -1,23 +1,22 @@ import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart'; import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; import 'package:http/http.dart' as http; -/// Remote restful API that providers a [Counter] +/// Remote restful API that providers a [CounterModel] class CounterRestApi implements CounterApi { CounterRestApi({required this.client}); final http.Client client; @override - Future fetchCounter(String id) { - // simulate a network delay - return Future.delayed(const Duration(milliseconds: 300), () { - if (id == '1') { - // return a dummy counter - return Counter(value: 0); - } else { - // return a exception - throw CounterNotFoundException(); - } - }); + Future fetchCounter(String id) { + // TODO: implement fetchCounter + throw UnimplementedError(); + } + + @override + Future incrementCounter(String id, int amount) { + // TODO: implement incrementCounter + throw UnimplementedError(); } } diff --git a/lib/src/features/counter/data/repositories/counter.repository.dart b/lib/src/features/counter/data/repositories/counter.repository.dart index 9f85597..868e261 100644 --- a/lib/src/features/counter/data/repositories/counter.repository.dart +++ b/lib/src/features/counter/data/repositories/counter.repository.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'package:counter_workshop/src/features/counter/data/datasources/local/counter.db.dart'; import 'package:counter_workshop/src/features/counter/data/datasources/remote/counter.api.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/converters/counter_response.converter.dart'; +import 'package:counter_workshop/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart'; import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; import 'dart:developer'; @@ -12,21 +14,29 @@ class CounterRepository { final CounterApi counterApi; final CounterDatabase counterDatabase; - Counter _counter = Counter(value: 0); + + /// TODO Move to local storage // prefill repository Counter from API Future _fetchCounterData() async { log('retriving default counter'); - _counter = await counterApi.fetchCounter('1'); + CounterResponseDto counterResponseDto = await counterApi.fetchCounter('1'); + + // Map result to Model + CounterModel _counter = + CounterResponseConverter().toModel(counterResponseDto); + + // store in database + counterDatabase.storeCounter(_counter); } - Counter getCounter() { - return _counter; + CounterModel getCounter() { + return counterDatabase.getCounter(); } - void increment({required int amount}) { - log('incrementing counter ${_counter.value} by $amount'); - _counter.value += amount; + void updateCounter({required String id, required int value}) async { + log('update counter id by $value'); + await counterApi.incrementCounter(id, value); return; } } diff --git a/lib/src/features/counter/domain/counter.model.dart b/lib/src/features/counter/domain/counter.model.dart index 3f76ace..634c57e 100644 --- a/lib/src/features/counter/domain/counter.model.dart +++ b/lib/src/features/counter/domain/counter.model.dart @@ -1,13 +1,17 @@ import 'package:equatable/equatable.dart'; // ignore: must_be_immutable -class Counter extends Equatable { - Counter({ +class CounterModel extends Equatable { + CounterModel({ this.value = 0, + this.id, }); + /// technical counter id + String? id; + int value; @override - List get props => [value]; + List get props => [id, value]; } diff --git a/lib/src/features/counter/presentation/counter.controller.dart b/lib/src/features/counter/presentation/counter.controller.dart index d84fd91..6cdb267 100644 --- a/lib/src/features/counter/presentation/counter.controller.dart +++ b/lib/src/features/counter/presentation/counter.controller.dart @@ -6,7 +6,7 @@ class CounterController { final CounterRepository counterRepository; - Counter get counter { + CounterModel get counter { return counterRepository.getCounter(); } From 527f2f80a944004796e1a435f6abbc5bb3c28549 Mon Sep 17 00:00:00 2001 From: Jan Marsh Date: Fri, 9 Sep 2022 09:27:27 +0200 Subject: [PATCH 4/6] Updating API --- .../data/datasources/remote/counter.api.dart | 6 ++--- .../remote/dtos/counter_response.dto.dart | 7 ++--- .../remote/src/mock/counter_fake.api.dart | 27 +++++++++---------- .../remote/src/rest/counter_rest.api.dart | 2 +- .../data/repositories/counter.repository.dart | 22 +++++++-------- .../counter/domain/counter.model.dart | 4 +-- .../presentation/counter.controller.dart | 14 +++++----- .../counter/presentation/counter.page.dart | 2 +- test/widget_test.dart | 4 +-- 9 files changed, 41 insertions(+), 47 deletions(-) diff --git a/lib/src/features/counter/data/datasources/remote/counter.api.dart b/lib/src/features/counter/data/datasources/remote/counter.api.dart index 999a7c7..c78d714 100644 --- a/lib/src/features/counter/data/datasources/remote/counter.api.dart +++ b/lib/src/features/counter/data/datasources/remote/counter.api.dart @@ -3,15 +3,15 @@ import 'package:counter_workshop/src/features/counter/domain/counter.model.dart' /// The interface for a DataSource that provides access to a single [CounterModel] abstract class CounterApi { - /// Fetches a counter with the give id + /// Fetches a counter with the give [id] /// /// If no counter with the given id exits, a [CounterNotFoundException] error is thrown. Future fetchCounter(String id); - /// Increments counter with given id + /// Update the value [value] of a given counter [id] /// /// If no counter with the given id exits, a [CounterNotFoundException] error is thrown. - Future incrementCounter(String id, int amount); + Future updateCounter(String id, int value); } /// Error thrown when a [CounterModel] is not found. diff --git a/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart b/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart index acef8ed..dd580ee 100644 --- a/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart +++ b/lib/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart @@ -1,16 +1,13 @@ class CounterResponseDto { CounterResponseDto({ - this.sysId, + required this.sysId, required this.counterValue, this.createdAt, this.updatedAt, }); + final String sysId; final int counterValue; - final DateTime? createdAt; - final DateTime? updatedAt; - - final String? sysId; } diff --git a/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart b/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart index 49ba0aa..bd3572e 100644 --- a/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart +++ b/lib/src/features/counter/data/datasources/remote/src/mock/counter_fake.api.dart @@ -2,21 +2,19 @@ import 'package:counter_workshop/src/features/counter/data/datasources/remote/co import 'package:counter_workshop/src/features/counter/data/datasources/remote/dtos/counter_response.dto.dart'; import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; -/// Remote restful API that providers a [CounterModel] +/// FakeApi that simulates a remote restful API which providers a [CounterModel] class CounterFakeApi implements CounterApi { - final CounterResponseDto _counterDto = CounterResponseDto( - counterValue: 0, - sysId: '1', - createdAt: DateTime.now(), - ); - @override Future fetchCounter(String id) { // simulate a network delay return Future.delayed(const Duration(milliseconds: 300), () { if (id == '1') { // return a dummy counter - return _counterDto; + return CounterResponseDto( + counterValue: 0, + sysId: '1', + createdAt: DateTime.now(), + ); } else { // return a exception throw CounterNotFoundException(); @@ -25,13 +23,14 @@ class CounterFakeApi implements CounterApi { } @override - Future incrementCounter(String id, int amount) { + Future updateCounter(String id, int value) { return Future.delayed(const Duration(milliseconds: 300), () { - return CounterResponseDto( - counterValue: _counterDto.counterValue + amount, - sysId: '1', - createdAt: DateTime.now(), - ); + if (id == '1') { + return; + } else { + // return a exception + throw CounterNotFoundException(); + } }); } } diff --git a/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart b/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart index 0a23bc5..f712c0c 100644 --- a/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart +++ b/lib/src/features/counter/data/datasources/remote/src/rest/counter_rest.api.dart @@ -15,7 +15,7 @@ class CounterRestApi implements CounterApi { } @override - Future incrementCounter(String id, int amount) { + Future updateCounter(String id, int value) { // TODO: implement incrementCounter throw UnimplementedError(); } diff --git a/lib/src/features/counter/data/repositories/counter.repository.dart b/lib/src/features/counter/data/repositories/counter.repository.dart index 868e261..6c7a9a0 100644 --- a/lib/src/features/counter/data/repositories/counter.repository.dart +++ b/lib/src/features/counter/data/repositories/counter.repository.dart @@ -9,34 +9,32 @@ import 'dart:developer'; class CounterRepository { CounterRepository({required this.counterApi, required this.counterDatabase}) { + // prefill repository Counter from API _fetchCounterData(); } final CounterApi counterApi; final CounterDatabase counterDatabase; + final String defaultCounterId = '1'; // TODO: allow multiple counters - /// TODO Move to local storage - - // prefill repository Counter from API Future _fetchCounterData() async { log('retriving default counter'); - CounterResponseDto counterResponseDto = await counterApi.fetchCounter('1'); + CounterResponseDto counterResponseDto = await counterApi.fetchCounter(defaultCounterId); - // Map result to Model - CounterModel _counter = - CounterResponseConverter().toModel(counterResponseDto); + // map result to Model + CounterModel counterModel = CounterResponseConverter().toModel(counterResponseDto); - // store in database - counterDatabase.storeCounter(_counter); + // store model in database + counterDatabase.storeCounter(counterModel); } CounterModel getCounter() { return counterDatabase.getCounter(); } - void updateCounter({required String id, required int value}) async { - log('update counter id by $value'); - await counterApi.incrementCounter(id, value); + Future updateCounter({required CounterModel counterModel}) async { + log('updating counter: ${counterModel.id} with value: $counterModel'); + await counterApi.updateCounter(counterModel.id, counterModel.value); return; } } diff --git a/lib/src/features/counter/domain/counter.model.dart b/lib/src/features/counter/domain/counter.model.dart index 634c57e..880955d 100644 --- a/lib/src/features/counter/domain/counter.model.dart +++ b/lib/src/features/counter/domain/counter.model.dart @@ -4,11 +4,11 @@ import 'package:equatable/equatable.dart'; class CounterModel extends Equatable { CounterModel({ this.value = 0, - this.id, + this.id = '1', }); /// technical counter id - String? id; + final String id; int value; diff --git a/lib/src/features/counter/presentation/counter.controller.dart b/lib/src/features/counter/presentation/counter.controller.dart index 6cdb267..fc9eec1 100644 --- a/lib/src/features/counter/presentation/counter.controller.dart +++ b/lib/src/features/counter/presentation/counter.controller.dart @@ -2,15 +2,15 @@ import 'package:counter_workshop/src/features/counter/data/repositories/counter. import 'package:counter_workshop/src/features/counter/domain/counter.model.dart'; class CounterController { - const CounterController({required this.counterRepository}); + CounterController({required this.counterRepository}) { + counterModel = counterRepository.getCounter(); + } final CounterRepository counterRepository; + CounterModel counterModel = CounterModel(); - CounterModel get counter { - return counterRepository.getCounter(); - } - - void increment() async { - counterRepository.increment(amount: 1); + Future increment() async { + counterModel.value += 1; + counterRepository.updateCounter(counterModel: counterModel); } } diff --git a/lib/src/features/counter/presentation/counter.page.dart b/lib/src/features/counter/presentation/counter.page.dart index 414063a..da1bff7 100644 --- a/lib/src/features/counter/presentation/counter.page.dart +++ b/lib/src/features/counter/presentation/counter.page.dart @@ -38,7 +38,7 @@ class _CounterPageState extends State { 'You have pushed the button this many times:', ), Text( - '${counterController.counter.value}', + '${counterController.counterModel.value}', style: Theme.of(context).textTheme.headline4, ), ], diff --git a/test/widget_test.dart b/test/widget_test.dart index bce9704..6031a2c 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -17,7 +17,7 @@ void main() { // Build our app and trigger a frame. await tester.pumpWidget( App(counterRepository: CounterRepository(counterApi: CounterFakeApi(), counterDatabase: CounterDatabase())), - const Duration(milliseconds: 500), // Because of FakeApi delay + const Duration(milliseconds: 300), // Because of FakeApi delay ); // Verify that our counter starts at 0. @@ -26,7 +26,7 @@ void main() { // Tap the '+' icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); + await tester.pumpAndSettle(const Duration(milliseconds: 300)); // Because of FakeApi delay // Verify that our counter has incremented. expect(find.text('0'), findsNothing); From f346d95800cc60055f87d156b5db284b0be66f86 Mon Sep 17 00:00:00 2001 From: Jan Marsh Date: Fri, 9 Sep 2022 09:28:32 +0200 Subject: [PATCH 5/6] Adding DB Folders --- .../features/counter/data/datasources/local/converters/.gitkeep | 0 lib/src/features/counter/data/datasources/local/dtos/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/src/features/counter/data/datasources/local/converters/.gitkeep create mode 100644 lib/src/features/counter/data/datasources/local/dtos/.gitkeep diff --git a/lib/src/features/counter/data/datasources/local/converters/.gitkeep b/lib/src/features/counter/data/datasources/local/converters/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/features/counter/data/datasources/local/dtos/.gitkeep b/lib/src/features/counter/data/datasources/local/dtos/.gitkeep new file mode 100644 index 0000000..e69de29 From 53689f22deb97b3c40ed2e6caa4517e082225d8b Mon Sep 17 00:00:00 2001 From: Marcel Ploch Date: Thu, 19 Oct 2023 10:39:32 +0200 Subject: [PATCH 6/6] update for pubspec --- ios/Runner.xcodeproj/project.pbxproj | 5 +- pubspec.lock | 296 ++++++++++++++++----------- pubspec.yaml | 4 +- 3 files changed, 185 insertions(+), 120 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index b63f22c..6fd2c1b 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -171,10 +171,12 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -185,6 +187,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); diff --git a/pubspec.lock b/pubspec.lock index 9f08ebd..2c5f269 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,184 +5,210 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "64.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "6.2.0" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.2" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.1" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8" + url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.4.1" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.6" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + url: "https://pub.dev" source: hosted - version: "7.2.3" + version: "7.2.11" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + sha256: a8de5955205b4d1dbbbc267daddf2178bd737e4bab8987c04a500478c9651e74 + url: "https://pub.dev" source: hosted - version: "8.4.1" + version: "8.6.3" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677" + url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.7.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.1" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.1.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: abd7625e16f51f554ea244d090292945ec4d4be7bfbaf2ec8cccea568919d334 + url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.3" equatable: dependency: "direct main" description: name: equatable - url: "https://pub.dartlang.org" + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" source: hosted version: "2.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -192,9 +218,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: ad76540d21c066228ee3f9d1dad64a9f7e46530e8bb7c85011a88bc1fd874bc5 + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -204,156 +231,178 @@ packages: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "3.2.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.1" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "1.1.0" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.7" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.8.1" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.0.0" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.2.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.4" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.3" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.4" sky_engine: dependency: transitive description: flutter @@ -363,92 +412,105 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.5.1" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.0.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 64199fa..34f9e29 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,13 +14,13 @@ dependencies: cupertino_icons: ^1.0.2 equatable: ^2.0.5 - http: ^0.13.5 + http: ^1.1.0 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^3.0.0 build_runner: ^2.2.0 flutter: