From 6aefe27acf7f56a709b3dd4f45f3b4b76fd842ae Mon Sep 17 00:00:00 2001 From: Demetrius Date: Tue, 4 Jun 2024 20:58:09 +0300 Subject: [PATCH 01/10] Lab 1 mostly done --- lib/templates/lab1/lab1.dart | 23 +++++++++++++++++------ pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/templates/lab1/lab1.dart b/lib/templates/lab1/lab1.dart index 2d27780d14..1f9b394427 100644 --- a/lib/templates/lab1/lab1.dart +++ b/lib/templates/lab1/lab1.dart @@ -60,20 +60,31 @@ class LAb1HomePage extends StatelessWidget { } Widget exercise1() { - return const FlutterLogo( - size: 100, + return const Text( + 'Flutter Rules', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.w900, + fontSize: 37.0, + color: Colors.teal, + ), ); } Widget exercise2() { - return const FlutterLogo( - size: 100, + return const Icon( + Icons.tv, + color: Colors.teal, + size: 42.0, ); } Widget exercise3() { - return const FlutterLogo( - size: 100, + return Image.network( + 'https://i.pinimg.com/736x/b7/43/26/b74326865ca5feff316e6416a1b73ddc.jpg', + width: 48.0, + height: 64.0, + fit: BoxFit.fill, ); } diff --git a/pubspec.lock b/pubspec.lock index 575eb0c069..0ef14d44f2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,5 +201,5 @@ packages: source: hosted version: "14.2.1" sdks: - dart: ">=3.4.1 <4.0.0" + dart: ">=3.4.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index 2641e6988a..5cb7264b73 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 0.1.0 environment: - sdk: '>=3.4.1 <4.0.0' + sdk: '>=3.4.0 <4.0.0' dependencies: flutter: From e856a058f1aa082534c2043165743236681345c8 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Tue, 4 Jun 2024 23:37:49 +0300 Subject: [PATCH 02/10] Lab 1 complete --- lib/templates/lab1/lab1.dart | 76 +++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/lib/templates/lab1/lab1.dart b/lib/templates/lab1/lab1.dart index 1f9b394427..a4349a6e8f 100644 --- a/lib/templates/lab1/lab1.dart +++ b/lib/templates/lab1/lab1.dart @@ -22,15 +22,15 @@ class LAb1HomePage extends StatelessWidget { backgroundColor: Colors.white, appBar: AppBar( leading: const Icon(Icons.stars), - title: const Text('Lab 2'), + title: const Text('Lab 1'), backgroundColor: Colors.teal, elevation: 4, ), - body: myWidget(), + body: myWidget(context), ); } - Widget myWidget() { + Widget myWidget(BuildContext context) { return SingleChildScrollView( child: Column( children: [ @@ -49,7 +49,7 @@ class LAb1HomePage extends StatelessWidget { const SizedBox( height: 25, ), - exercise4(), + exercise4(context), const SizedBox( height: 25, ), @@ -61,42 +61,72 @@ class LAb1HomePage extends StatelessWidget { Widget exercise1() { return const Text( - 'Flutter Rules', - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.w900, - fontSize: 37.0, - color: Colors.teal, - ), + 'Flutter Rules', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.w900, + fontSize: 37.0, + color: Colors.teal, + ), ); } Widget exercise2() { return const Icon( - Icons.tv, - color: Colors.teal, - size: 42.0, + Icons.tv, + color: Colors.teal, + size: 42.0, ); } Widget exercise3() { return Image.network( - 'https://i.pinimg.com/736x/b7/43/26/b74326865ca5feff316e6416a1b73ddc.jpg', - width: 48.0, - height: 64.0, - fit: BoxFit.fill, + 'https://i.pinimg.com/736x/b7/43/26/b74326865ca5feff316e6416a1b73ddc.jpg', + width: 48.0, + height: 64.0, + fit: BoxFit.fill, ); } - Widget exercise4() { - return const FlutterLogo( - size: 100, + Widget exercise4(BuildContext context) { + return TextButton( + style: TextButton.styleFrom( + foregroundColor: Colors.tealAccent[700], + ), + child: const Text('Press me'), + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('Pressed'), + )); + }, ); } Widget exercise5() { - return const FlutterLogo( - size: 100, + return Column( + children: [ + Container( + padding: const EdgeInsets.all(16.0), + decoration: const BoxDecoration( + color: Colors.teal, + borderRadius: BorderRadius.all(Radius.circular(30.0)), + ), + child: const Text( + 'There\'s a Column!', + style: TextStyle(color: Colors.white, fontWeight: FontWeight.w700), + ), + ), + Container( + padding: const EdgeInsets.all(32.0), + margin: const EdgeInsets.fromLTRB(4.0, 16.0, 4.0, 8.0), + decoration: const FlutterLogoDecoration(), + child: const Icon( + Icons.egg_sharp, + color: Colors.blue, + size: 25.0, + ), + ), + ], ); } } From 9f6f7116ba8817342c3fa3557d7522a2aac61dbe Mon Sep 17 00:00:00 2001 From: Demetrius Date: Wed, 5 Jun 2024 20:19:37 +0300 Subject: [PATCH 03/10] complete: Lab 2 --- lib/templates/lab2/lab2.dart | 171 +++++++++++++++++++++++++++++++++-- 1 file changed, 162 insertions(+), 9 deletions(-) diff --git a/lib/templates/lab2/lab2.dart b/lib/templates/lab2/lab2.dart index c8d2692e4e..504bb6deee 100644 --- a/lib/templates/lab2/lab2.dart +++ b/lib/templates/lab2/lab2.dart @@ -1,19 +1,172 @@ -class Book { - // your code here +import 'package:flutter/material.dart'; + +void main() => runApp(const Lab2()); + +class Lab2 extends StatelessWidget { + const Lab2({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + leading: const Icon(Icons.stars), + title: const Text('Lab 2'), + backgroundColor: Colors.teal, + elevation: 4, + ), + body: SingleChildScrollView( + child: Column( + children: [ + element(ex1()), + element(ex2()), + element(ex3()), + element(ex4()), + element(ex5()), + ], + ), + ), + )); + } + + Widget element(Widget widget) { + return Container( + margin: const EdgeInsets.all(16.0), + child: widget, + ); + } + + Widget ex1() { + List books = [ + Book('Book1', 'Author1', 13), + Book('Book2', 'Author2', 42), + Book('Book3', 'Author3', 37) + ]; + List details = []; + for (final book in books) { + details.add(Text(book.bookDetails())); + } + return Column( + children: details, + ); + } + + Widget ex2() { + List books = [ + FictionBook('Book1', 'Author1', 13, 'Thriller'), + FictionBook('Book2', 'Author2', 42, 'Comedy'), + FictionBook('Book3', 'Author3', 37, 'Detective') + ]; + List details = []; + for (final book in books) { + details.add(Text(book.bookDetails())); + } + return Column( + children: details, + ); + } + + Widget ex3() { + List books = [ + Book('Book1', 'Author1', 13), + Book('Book2', 'Author2', 42), + Book('Book3', 'Author3', 37) + ]; + List details = []; + for (final book in books) { + details.add(Text(book.toJson().toString())); + } + return Column( + children: details, + ); + } + + Widget ex4() { + return Column( + children: [ + Text( + 'length: 15, width 22, area: ${calculateArea(width: 22, length: 15)}'), + Text( + 'radius: 37, area: ${calculateArea(length: 37, width: 0, shape: 'circle')}') + ], + ); + } + + Widget ex5() { + List users = [ + User('Book1', email: 'Author1', age: 13), + User('Book2', age: 42), + User('Book3', email: 'Author3') + ]; + List details = []; + for (final book in users) { + details.add(Text(book.printUserDetails())); + } + return Column( + children: details, + ); + } } -class FictionBook { - // your code here +class Book with JsonSerializable { + String title; + String author; + int numOfPages; + + Book(this.title, this.author, this.numOfPages); + + String bookDetails() { + return "$author - $title ($numOfPages)"; + } +} + +class FictionBook extends Book { + String genre; + + FictionBook(super.title, super.author, super.numOfPages, this.genre); + + @override + String bookDetails() { + return "$author - $title <$genre> ($numOfPages)"; + } } mixin JsonSerializable { - // your code here + Map toJson() { + Map json = {}; + switch (runtimeType) { + case const (Book): + Book book = this as Book; + json['title'] = book.title; + json['author'] = book.author; + json['numOfPages'] = book.numOfPages; + return json; + } + return json; + } } -double calculateArea(){ - // your code here +double calculateArea( + {required double width, + required double length, + String shape = 'rectangle'}) { + switch (shape) { + case 'circle': + return 3.14 * length * length; + default: + return length * width; + } } -class User{ - // your code here +class User { + String name; + int? age; + String? email; + + User(this.name, {this.age, this.email}); + + String printUserDetails() { + return 'Name: $name\nAge: ${age ?? "N/A"}\nEmail: ${email ?? "N/A"}'; + } } From cfa4661adf0249c81164ac7629a5fa8e907b3b19 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Tue, 11 Jun 2024 20:56:11 +0300 Subject: [PATCH 04/10] Lab 3 --- lib/templates/lab3/hydration.dart | 6 +-- lib/templates/lab3/main.dart | 8 ++-- lib/templates/lab3/notifier.dart | 31 +++++++++++---- lib/templates/lab3/painter.dart | 26 +++++++------ lib/templates/lab3/screen.dart | 64 ++++++++++++++++++++++++++----- lib/templates/lab3/storage.dart | 5 +-- pubspec.lock | 2 +- 7 files changed, 102 insertions(+), 40 deletions(-) diff --git a/lib/templates/lab3/hydration.dart b/lib/templates/lab3/hydration.dart index 2c0d18c595..0488196f98 100644 --- a/lib/templates/lab3/hydration.dart +++ b/lib/templates/lab3/hydration.dart @@ -2,9 +2,9 @@ import 'package:education/templates/lab3/painter.dart'; import 'package:flutter/material.dart'; class HydrationWidget extends StatefulWidget { - final double waterIntakeLevel; + final double waterIntakeRatio; - const HydrationWidget({super.key, required this.waterIntakeLevel}); + const HydrationWidget({super.key, required this.waterIntakeRatio}); @override HydrationWidgetState createState() => HydrationWidgetState(); @@ -17,7 +17,7 @@ class HydrationWidgetState extends State { return SizedBox( width: size.width, height: size.height - 200, - child: WaterPainterWidget(waterIntakeLevel: widget.waterIntakeLevel), + child: WaterPainterWidget(waterIntakeRatio: widget.waterIntakeRatio), ); } } diff --git a/lib/templates/lab3/main.dart b/lib/templates/lab3/main.dart index ed39ca4763..0bf41be1ff 100644 --- a/lib/templates/lab3/main.dart +++ b/lib/templates/lab3/main.dart @@ -4,8 +4,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; void main() { runApp( - // TODO to enable riverpod - add ProviderScope - WaterBalanceApp(), + const ProviderScope( + child: WaterBalanceApp(), + ), ); } @@ -19,8 +20,7 @@ class WaterBalanceApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - // TODO to run app - change to needed screen widget - home: null, + home: const HydrationScreen(), ); } } diff --git a/lib/templates/lab3/notifier.dart b/lib/templates/lab3/notifier.dart index 881c69e296..3eab22f9ed 100644 --- a/lib/templates/lab3/notifier.dart +++ b/lib/templates/lab3/notifier.dart @@ -1,6 +1,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'storage.dart'; +const double maxLevel = 2000.0; +const int stepNumber = 20; + final localStorageServiceProvider = Provider((ref) { return LocalStorageService(); }); @@ -8,27 +11,39 @@ final localStorageServiceProvider = Provider((ref) { final waterIntakeProvider = StateNotifierProvider((ref) { final localStorageService = ref.watch(localStorageServiceProvider); - return WaterIntakeNotifier(localStorageService); + return WaterIntakeNotifier(localStorageService, + maxLevel: maxLevel, steps: stepNumber); }); class WaterIntakeNotifier extends StateNotifier { + final double maxLevel; + late double _step; + final LocalStorageService _localStorageService; - WaterIntakeNotifier(this._localStorageService) : super(0) { + WaterIntakeNotifier(this._localStorageService, + {required int steps, this.maxLevel = 100.0}) + : super(0.0) { + _step = (steps > 0.0) ? maxLevel / steps : maxLevel; _loadWaterIntake(); } void _loadWaterIntake() async { - // TODO - Load the water intake from _localStorageService using await - // state = + state = await _localStorageService.getWaterIntake(); } - void increment(double amount) async { - state += amount; - // TODO - Save the water intake into _localStorageService using saveWaterIntake + void increment() async { + if (state < maxLevel) { + state += _step; + if (maxLevel - state < .0001) { + state = maxLevel; + } + } + _localStorageService.saveWaterIntake(state); } void reset() async { - // TODO - reset state and save it into _localStorageService using saveWaterIntake + state = 0.0; + _localStorageService.saveWaterIntake(state); } } diff --git a/lib/templates/lab3/painter.dart b/lib/templates/lab3/painter.dart index 87a921851a..bfbda5d15f 100644 --- a/lib/templates/lab3/painter.dart +++ b/lib/templates/lab3/painter.dart @@ -2,26 +2,28 @@ import 'package:flutter/material.dart'; class WaterProgressPainter extends CustomPainter { - final double waterIntakeLevel; + final double waterIntakeRatio; WaterProgressPainter({ - required this.waterIntakeLevel, + required this.waterIntakeRatio, }); @override void paint(Canvas canvas, Size size) { - // TODO - Using size and waterIntakeLevel to calculate the water level - // final waterLevel = + final waterLevel = size.height * (1.0 - waterIntakeRatio); final paint = Paint() ..color = Colors.blueAccent.withOpacity(0.5) ..style = PaintingStyle.fill; - // TODO - Draw the water level on the canvas using rectangle and size from waterLevel - // canvas.drawRect( - // Rect.fromLTRB(left, top, right, bottom) - // paint, - // ); + canvas.drawRect( + Rect.fromLTRB( + size.topLeft(const Offset(0, 0)).dx, + size.topLeft(Offset(0, waterLevel)).dy, + size.bottomRight(const Offset(0, 0)).dx, + size.bottomRight(const Offset(0, 0)).dy), + paint, + ); } @override @@ -29,9 +31,9 @@ class WaterProgressPainter extends CustomPainter { } class WaterPainterWidget extends StatefulWidget { - final double waterIntakeLevel; + final double waterIntakeRatio; - const WaterPainterWidget({super.key, required this.waterIntakeLevel}); + const WaterPainterWidget({super.key, required this.waterIntakeRatio}); @override WaterPainterState createState() => WaterPainterState(); @@ -42,7 +44,7 @@ class WaterPainterState extends State { Widget build(BuildContext context) { return CustomPaint( painter: WaterProgressPainter( - waterIntakeLevel: widget.waterIntakeLevel, + waterIntakeRatio: widget.waterIntakeRatio, ), ); } diff --git a/lib/templates/lab3/screen.dart b/lib/templates/lab3/screen.dart index 5a1209aaa5..2bd4eac3d5 100644 --- a/lib/templates/lab3/screen.dart +++ b/lib/templates/lab3/screen.dart @@ -3,26 +3,72 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'hydration.dart'; import 'notifier.dart'; +const Color primary = Colors.teal; +const Color accent = Colors.tealAccent; + class HydrationScreen extends ConsumerWidget { const HydrationScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - // TODO - Add ref.watch and use provider to get the water intake - // final waterIntake = + final waterIntake = ref.watch(waterIntakeProvider); return Scaffold( - // TODO add AppBar with Icon to reset the water intake as actions parameter of AppBar - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, + appBar: AppBar( + backgroundColor: primary, + foregroundColor: accent, + leading: const Icon( + Icons.local_drink, + ), + title: const Text('Betta Watch Your Water Intake'), + actions: [ + TextButton( + child: const Icon( + Icons.bolt_outlined, + color: accent, + ), + onPressed: () { + ref.read(waterIntakeProvider.notifier).reset(); + }, + ) + ], + ), + body: SafeArea( + child: Stack( + alignment: Alignment.center, children: [ - // TODO - Add text to display the water intake - // TODO add HydrationWidget to display the water intake and put waterIntake into it + SizedBox.expand( + child: HydrationWidget( + waterIntakeRatio: waterIntake / maxLevel, + ), + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Your current water intake is:', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + Text( + '$waterIntake ml', + style: const TextStyle( + fontSize: 64, fontWeight: FontWeight.w700), + ), + ], + ), // Add more UI components if necessary ], ), ), - // TODO - Add floating action button to increment the water intake using ref.read(waterIntakeProvider.notifier).increment(x) + floatingActionButton: FloatingActionButton( + backgroundColor: accent, + foregroundColor: primary, + onPressed: () { + ref.read(waterIntakeProvider.notifier).increment(); + }, + child: const Icon( + Icons.water_drop, + ), + ), ); } } diff --git a/lib/templates/lab3/storage.dart b/lib/templates/lab3/storage.dart index 80ccddacb7..c1ae1b1cec 100644 --- a/lib/templates/lab3/storage.dart +++ b/lib/templates/lab3/storage.dart @@ -5,12 +5,11 @@ class LocalStorageService { Future saveWaterIntake(double intake) async { final prefs = await SharedPreferences.getInstance(); - // TODO - Save the water intake into prefs + await prefs.setDouble(_waterIntakeKey, intake); } Future getWaterIntake() async { final prefs = await SharedPreferences.getInstance(); - // TODO - Get the water intake from prefs, remove 'return 0.0' - return 0.0; + return prefs.getDouble(_waterIntakeKey) ?? 0.0; } } diff --git a/pubspec.lock b/pubspec.lock index 3d9d750ed1..bd4e111bcd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -374,5 +374,5 @@ packages: source: hosted version: "1.0.4" sdks: - dart: ">=3.4.1 <4.0.0" + dart: ">=3.4.0 <4.0.0" flutter: ">=3.22.0" From b4135edbcc4bec4b26c9b7810cc3cb715a79f815 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Tue, 18 Jun 2024 22:46:44 +0300 Subject: [PATCH 05/10] done: Lab 4 --- lib/templates/lab4/main.dart | 106 +++++++++++++++++++++++++---------- pubspec.lock | 16 ++++++ pubspec.yaml | 1 + 3 files changed, 93 insertions(+), 30 deletions(-) diff --git a/lib/templates/lab4/main.dart b/lib/templates/lab4/main.dart index 8ba313dd21..f6d9df8450 100644 --- a/lib/templates/lab4/main.dart +++ b/lib/templates/lab4/main.dart @@ -1,16 +1,21 @@ +import 'dart:typed_data'; + import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart' as riverpod; +import 'package:provider/provider.dart' as dartpv; import 'package:http/http.dart' as http; import 'package:dio/dio.dart'; void main() { - runApp(MyApp()); + runApp(const MyApp()); } class MyApp extends StatelessWidget { + const MyApp({super.key}); + @override Widget build(BuildContext context) { - return ProviderScope( + return const riverpod.ProviderScope( child: MaterialApp( home: MyHomePage(), ), @@ -18,12 +23,24 @@ class MyApp extends StatelessWidget { } } -class MyHomePage extends StatelessWidget { +class MyModel with ChangeNotifier { + int _count = 0; + int get count => _count; + + set count(int value) { + _count = value; + notifyListeners(); + } +} + +class MyHomePage extends riverpod.ConsumerWidget { + const MyHomePage({super.key}); + @override - Widget build(BuildContext context) { + Widget build(BuildContext context, riverpod.WidgetRef ref) { return Scaffold( appBar: AppBar( - title: Text('Flutter Tasks'), + title: const Text('Flutter Tasks'), ), body: Center( child: Column( @@ -31,41 +48,71 @@ class MyHomePage extends StatelessWidget { children: [ ElevatedButton( onPressed: () async { - // TODO // Exercise 1 - Perform an async operation using async/await String result = await fetchData(); print(result); }, - child: Text('Async/Await Task'), + child: const Text('Async/Await Task'), ), - ElevatedButton( - onPressed: () { - // Exercise 2 - Use Provider for state management - // Increment the counter - }, - child: Text('Provider Task'), + dartpv.ChangeNotifierProvider( + create: (context) => MyModel(), + builder: (context, _) => ElevatedButton( + onPressed: () { + // Exercise 2 - Use Provider for state management + // Increment the counter + final counter = dartpv.Provider.of( + context, + listen: false, + ); + counter.count += 1; + }, + child: Text( + 'Provider Task, count: ${dartpv.Provider.of(context).count}'), + ), ), ElevatedButton( onPressed: () { - // TODO // Exercise 3 - Use Riverpod for state management // Increment the counter + ref.read(counterProvider.notifier).state += 1; }, - child: Text('Riverpod Task'), + child: + Text('Riverpod Task, count: ${ref.watch(counterProvider)}'), ), ElevatedButton( onPressed: () async { - // TODO // Exercise 4 - Make an HTTP request using the HTTP package + final data = await fetchData(); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(data), + )); }, - child: Text('HTTP Task'), + child: const Text('HTTP Task'), ), ElevatedButton( onPressed: () async { - // TODO // Exercise 5 - Make an HTTP request using Dio and show it in App Screen + final Response image = await Dio().get( + 'https://http.cat/images/418.jpg', + options: Options(responseType: ResponseType.bytes)); + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('I\'m a teapot'), + content: Image.memory(image.data!), + actions: [ + TextButton( + child: const Text('Approve'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }); }, - child: Text('Dio Task'), + child: const Text('Dio Task'), ), ], ), @@ -75,15 +122,14 @@ class MyHomePage extends StatelessWidget { } Future fetchData() async { - // TODO get json from url and show as text - // 'https://jsonplaceholder.typicode.com/posts/1' - - return 'data'; + final url = Uri.parse('https://jsonplaceholder.typicode.com/posts/1'); + final data = await http.get(url); + // final data = await Dio().get(url.toString()); + if (data.statusCode == 200) { + return data.body; + } else { + throw Exception('Something went wrong'); + } } -final counterProvider = StateProvider((ref) => 0); - -// TODO create a state notifier -// final - -// TODO create class for state notifier +final counterProvider = riverpod.StateProvider((ref) => 0); diff --git a/pubspec.lock b/pubspec.lock index 1da4a2ff19..f868c9ccf2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -176,6 +176,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -224,6 +232,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" riverpod: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 923f439885..af50d37fe2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: sdk: flutter flutter_riverpod: ^2.5.1 http: ^1.2.1 + provider: ^6.1.2 riverpod: ^2.5.1 riverpod_annotation: ^2.3.5 shared_preferences: ^2.2.3 From 54ed5f1de2fa631aa9bc5d6c2876340b04ce2249 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Wed, 19 Jun 2024 22:42:04 +0300 Subject: [PATCH 06/10] done: Lab 5 (incomplete) --- lib/templates/lab5/comment.dart | 34 ++++++++++++++++++++++------ lib/templates/lab5/comment.g.dart | 23 +++++++++++++++++++ lib/templates/lab5/post.dart | 37 ++++++++++++++++++++++++------- 3 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 lib/templates/lab5/comment.g.dart diff --git a/lib/templates/lab5/comment.dart b/lib/templates/lab5/comment.dart index f8bd653ba2..fcc4295c76 100644 --- a/lib/templates/lab5/comment.dart +++ b/lib/templates/lab5/comment.dart @@ -1,16 +1,36 @@ -// TODO add dependencies -// TODO add comment.g.dart as part +import 'package:dio/dio.dart'; +import 'package:json_annotation/json_annotation.dart'; +part 'comment.g.dart'; + +@JsonSerializable() class Comment { // TODO task 2 to make this class for url http://jsonplaceholder.typicode.com/comments + final int postId; + final int id; + final String name; + final String email; + final String body; + + Comment( + {required this.postId, + required this.id, + required this.name, + required this.email, + required this.body}); - factory Comment.fromJson(Map json) {} + factory Comment.fromJson(Map json) => + _$CommentFromJson(json); + Map toJson() => _$CommentToJson(this); // Do not forget to run 'dart run build_runner build' to generate comment.g.dart } -Future> fetchComments() async { - // TODO task 2.2 to make this function for url http://jsonplaceholder.typicode.com/comments - // // Using fabric from class - return []; +Future> fetchComments({int start = 0, required int count}) async { + const url = 'http://jsonplaceholder.typicode.com/comments'; + List comments = []; + for (int i = start; i < start + count; ++i) { + comments.add(Comment.fromJson((await Dio().get('$url/$i')).data)); + } + return comments; } diff --git a/lib/templates/lab5/comment.g.dart b/lib/templates/lab5/comment.g.dart new file mode 100644 index 0000000000..a2fa46b246 --- /dev/null +++ b/lib/templates/lab5/comment.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'comment.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Comment _$CommentFromJson(Map json) => Comment( + postId: (json['postId'] as num).toInt(), + id: (json['id'] as num).toInt(), + name: json['name'] as String, + email: json['email'] as String, + body: json['body'] as String, + ); + +Map _$CommentToJson(Comment instance) => { + 'postId': instance.postId, + 'id': instance.id, + 'name': instance.name, + 'email': instance.email, + 'body': instance.body, + }; diff --git a/lib/templates/lab5/post.dart b/lib/templates/lab5/post.dart index 2f6292153b..fc453f83fe 100644 --- a/lib/templates/lab5/post.dart +++ b/lib/templates/lab5/post.dart @@ -1,15 +1,36 @@ -// TODO add dependencies +import 'package:dio/dio.dart'; class Post { - // TODO task 1 to make this class for url http://jsonplaceholder.typicode.com/posts + final int userId; + final int id; + final String title; + final String body; - factory Post.fromJson(Map json) {} + Post( + {required this.userId, + required this.id, + required this.title, + required this.body}); - factory Post.toJson(Post post) {} + factory Post.fromJson(Map json) => Post( + userId: json['userId'], + id: json['id'], + title: json['title'], + body: json['body']); + + Map toJson(Post post) => { + 'userId': userId, + 'id': id, + 'title': title, + 'body': body + }; } -Future> fetchPosts() async { - // TODO task 1.2 to make this function for url http://jsonplaceholder.typicode.com/posts - // // Using fabric from class - return []; +Future> fetchPosts({int start = 0, required int count}) async { + List posts = []; + const url = 'http://jsonplaceholder.typicode.com/posts'; + for (int i = start; i < start + count; ++i) { + posts.add(Post.fromJson((await Dio().get('$url/$i')).data)); + } + return posts; } From 4416ce7b0fb721370b944bb2c8106b39ccd75709 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Wed, 26 Jun 2024 21:54:02 +0300 Subject: [PATCH 07/10] in-work(lab7): GH Actions auto-tests --- .github/workflows/lab7.yaml | 22 ++++++++++++++++++++++ analysis_options.yaml | 5 +++++ pubspec.lock | 24 ++++++++++++------------ test/lab7_test.dart | 11 +++++++++++ 4 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/lab7.yaml create mode 100644 test/lab7_test.dart diff --git a/.github/workflows/lab7.yaml b/.github/workflows/lab7.yaml new file mode 100644 index 0000000000..484eaa5417 --- /dev/null +++ b/.github/workflows/lab7.yaml @@ -0,0 +1,22 @@ +name: Lab 7 CI + +on: + push: + branches: + - lab7 + pull_request: + branches: + - lab7 + +jobs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.23.0-0.1.pre + - run: flutter pub get + - run: flutter analyze lib/templates/lab7/main.dart + - run: flutter test test/lab7_test.dart + - run: flutter build web --release lib/templates/lab7/main.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index f9b303465f..88160b320c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1 +1,6 @@ include: package:flutter_lints/flutter.yaml + +analyzer: + errors: + avoid_unnecessary_containers: ignore + prefer_const_constructors: ignore diff --git a/pubspec.lock b/pubspec.lock index 0d5077bf67..297a51c912 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -377,18 +377,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -425,18 +425,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.14.0" mime: dependency: transitive description: @@ -710,10 +710,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.1" timing: dependency: transitive description: @@ -742,10 +742,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "7475cb4dd713d57b6f7464c0e13f06da0d535d8b2067e188962a59bac2cf280b" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.2" watcher: dependency: transitive description: diff --git a/test/lab7_test.dart b/test/lab7_test.dart new file mode 100644 index 0000000000..aeea4bc48b --- /dev/null +++ b/test/lab7_test.dart @@ -0,0 +1,11 @@ +import 'package:education/templates/lab7/main.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('We should be friendly and greet a user', (tester) async { + await tester.pumpWidget(MaterialApp(home: MyHomePage())); + final helloFinder = find.text('Hello World!'); + expect(helloFinder, findsOneWidget); + }); +} From 66d6391830e00154c4c94729f387437e49033e83 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Wed, 26 Jun 2024 19:10:53 +0300 Subject: [PATCH 08/10] in-work(lab7): GH Actions build for Windows --- .github/workflows/lab7.yaml | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/workflows/lab7.yaml b/.github/workflows/lab7.yaml index 484eaa5417..1f0b8fa56d 100644 --- a/.github/workflows/lab7.yaml +++ b/.github/workflows/lab7.yaml @@ -9,14 +9,28 @@ on: - lab7 jobs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version: 3.23.0-0.1.pre - - run: flutter pub get - - run: flutter analyze lib/templates/lab7/main.dart - - run: flutter test test/lab7_test.dart - - run: flutter build web --release lib/templates/lab7/main.dart + build-web: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.23.0-0.1.pre + - run: flutter pub get + - run: flutter analyze lib/templates/lab7/main.dart + - run: flutter test test/lab7_test.dart + - run: flutter build web --release lib/templates/lab7/main.dart + + build-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.23.0-0.1.pre + - run: flutter pub get + - run: flutter analyze lib/templates/lab7/main.dart + - run: flutter test test/lab7_test.dart + - run: flutter build windows --release lib/templates/lab7/main.dart From 43ab57ccd6803ed8bb641412eb44a27ce85e14b5 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Wed, 26 Jun 2024 20:30:02 +0300 Subject: [PATCH 09/10] done: lab 7 --- Dockerfile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 675af98386..0cf73997ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,16 @@ FROM debian:latest AS build-env -RUN apt-get update +RUN apt-get update -y && apt-get upgrade -y # Add apt-get install for flutter linux from # https://docs.flutter.dev/get-started/install/linux/desktop?tab=download +RUN apt-get install -y curl git unzip xz-utils zip libglu1-mesa RUN apt-get clean + # TODO clone original flutter github repo +RUN git clone https://github.com/flutter/flutter.git /usr/local/flutter -ENV PATH="/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin:${PATH}" +ENV PATH="${PATH}:/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin" RUN flutter doctor -v @@ -21,7 +24,10 @@ COPY . /app/ WORKDIR /app/ # TODO get dependencies +RUN flutter pub get + # TODO build web from needed file +RUN flutter build web --release lib/template/lab7/main.dart FROM nginx:1.21.1-alpine From c706d605afb8845d4a5e10fc5305249c5aad53e6 Mon Sep 17 00:00:00 2001 From: Demetrius Date: Wed, 26 Jun 2024 22:02:20 +0300 Subject: [PATCH 10/10] fix(lab7): Docker now run successfully --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0cf73997ea..4f22d23a25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ RUN apt-get clean # TODO clone original flutter github repo +RUN git -v RUN git clone https://github.com/flutter/flutter.git /usr/local/flutter ENV PATH="${PATH}:/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin" @@ -27,7 +28,7 @@ WORKDIR /app/ RUN flutter pub get # TODO build web from needed file -RUN flutter build web --release lib/template/lab7/main.dart +RUN flutter build web --release ./lib/templates/lab7/main.dart FROM nginx:1.21.1-alpine