diff --git a/ios/Flutter/.last_build_id b/ios/Flutter/.last_build_id new file mode 100644 index 0000000..bb82b1c --- /dev/null +++ b/ios/Flutter/.last_build_id @@ -0,0 +1 @@ +1a1a381ead1ef7899cf6d3ddded5560d \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 723080e..6e228d5 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -9,11 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -27,8 +23,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -39,13 +33,11 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -58,8 +50,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -69,9 +59,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -203,7 +191,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -255,7 +243,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -331,7 +318,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -387,7 +373,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/lib/api/cheetah_api.dart b/lib/api/cheetah_api.dart new file mode 100644 index 0000000..c2ddc1f --- /dev/null +++ b/lib/api/cheetah_api.dart @@ -0,0 +1,11 @@ +import 'dart:async'; + +Future getProfileUserName() async { + await Future.delayed(Duration(seconds: 5)); + + return "Julian Currie"; +} + +Stream getSessionTime() { + return Stream.periodic(Duration(seconds: 1), (sessionTime) => sessionTime++); +} diff --git a/lib/main.dart b/lib/main.dart index 38a8a32..218eb18 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,8 +7,11 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( + debugShowCheckedModeBanner: false, theme: ThemeData( - appBarTheme: AppBarTheme(color: Color(0xFFe67e00)), + appBarTheme: AppBarTheme(color: Color(0xFF064479)), + primaryColor: Color(0xFF064479), + backgroundColor: Color(0xFFb7eeff), ), home: Home(), ); diff --git a/lib/model/user.dart b/lib/model/user.dart new file mode 100644 index 0000000..9e7d340 --- /dev/null +++ b/lib/model/user.dart @@ -0,0 +1,6 @@ +class User { + String? name; + String? city; + + User(this.name, this.city); +} diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 44ef858..76e2843 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,31 +1,101 @@ +import 'package:CWCFlutter/model/user.dart'; +import 'package:CWCFlutter/screens/user_list_screen.dart'; +import 'package:CWCFlutter/widget/cheetah_button.dart'; +import 'package:CWCFlutter/widget/cheetah_input.dart'; +import 'package:CWCFlutter/widget/user_list.dart'; import 'package:flutter/material.dart'; -class Home extends StatelessWidget { +class Home extends StatefulWidget { + @override + HomeState createState() => HomeState(); +} + +class HomeState extends State { + String? _name; + String? _city; + + List userList = []; + + addUser(User user) { + setState(() { + userList.add(user); + }); + } + + deleteUser(User user) { + setState(() { + userList.removeWhere((_user) => _user.name == user.name); + }); + } + + final GlobalKey _formKey = GlobalKey(); + @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text('Cheetah Coding')), - body: Container( - color: Colors.black, - padding: EdgeInsets.all(16), - child: Center( + backgroundColor: Theme.of(context).backgroundColor, + appBar: AppBar( + title: Text( + "Riverpod Demo", + style: TextStyle(color: Colors.white), + ), + ), + body: SingleChildScrollView( + padding: EdgeInsets.all(32), + child: Form( + key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Image.asset( - 'assets/images/logo.png', - height: 200, - ), - SizedBox(height: 24), Text( - 'Master Branch', - style: TextStyle(fontSize: 36, color: Colors.white), + "Cheetah Coding", + style: TextStyle(fontSize: 30), ), - SizedBox(height: 24), - Text( - 'As you can see, there is not a lot here. Each branch relates to a specific Flutter topic discussed in the videos. Checkout the other branches and Happy browsing!', - style: TextStyle(fontSize: 20, color: Colors.white), + SizedBox(height: 16), + CheetahInput( + labelText: 'Name', + onSaved: (String? value) { + _name = value; + }, + ), + SizedBox(height: 16), + CheetahInput( + labelText: 'City', + onSaved: (String? value) { + _city = value; + }, + ), + SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CheetahButton( + text: 'Add', + onPressed: () { + if (!_formKey.currentState!.validate()) return; + + _formKey.currentState!.save(); + + addUser(User(_name, _city)); + }, + ), + SizedBox(width: 8), + CheetahButton( + text: 'List', + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + UserListScreen(userList, deleteUser), + ), + ); + }, + ), + ], ), + SizedBox(height: 20), + UserList(userList, deleteUser), ], ), ), diff --git a/lib/screens/user_list_screen.dart b/lib/screens/user_list_screen.dart new file mode 100644 index 0000000..2178174 --- /dev/null +++ b/lib/screens/user_list_screen.dart @@ -0,0 +1,38 @@ +import 'package:CWCFlutter/model/user.dart'; +import 'package:CWCFlutter/widget/user_list.dart'; +import 'package:flutter/material.dart'; + +class UserListScreen extends StatefulWidget { + final List users; + final Function(User) onDelete; + + UserListScreen(this.users, this.onDelete); + + @override + _UserListScreenState createState() => _UserListScreenState(); +} + +class _UserListScreenState extends State { + deleteUser(User user) { + setState(() { + widget.onDelete(user); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).backgroundColor, + appBar: AppBar( + title: Text( + 'Users', + style: TextStyle(color: Colors.white), + ), + ), + body: Padding( + child: UserList(widget.users, deleteUser), + padding: EdgeInsets.all(8), + ), + ); + } +} diff --git a/lib/widget/cheetah_button.dart b/lib/widget/cheetah_button.dart new file mode 100644 index 0000000..d409530 --- /dev/null +++ b/lib/widget/cheetah_button.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class CheetahButton extends StatelessWidget { + final String text; + final Function onPressed; + final Color? color; + + CheetahButton({ + required this.text, + required this.onPressed, + this.color, + }); + + @override + Widget build(BuildContext context) { + return Expanded( + child: TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.all(16), + elevation: 8, + backgroundColor: Theme.of(context).primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + ), + child: Text( + text, + style: TextStyle( + fontSize: 16, + color: Colors.white, + ), + ), + onPressed: onPressed as void Function()?, + ), + ); + } +} diff --git a/lib/widget/cheetah_input.dart b/lib/widget/cheetah_input.dart new file mode 100644 index 0000000..ea1e37e --- /dev/null +++ b/lib/widget/cheetah_input.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +class CheetahInput extends StatelessWidget { + final String labelText; + final Function onSaved; + + CheetahInput({ + required this.labelText, + required this.onSaved, + }); + + @override + Widget build(BuildContext context) { + return TextFormField( + decoration: InputDecoration( + fillColor: Colors.white, + filled: true, + labelText: labelText, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + ), + initialValue: '', + validator: (String? value) { + if (value!.isEmpty) { + return '$labelText is required'; + } + + return null; + }, + onSaved: onSaved as void Function(String?)?, + ); + } +} diff --git a/lib/widget/user_list.dart b/lib/widget/user_list.dart new file mode 100644 index 0000000..5d5a260 --- /dev/null +++ b/lib/widget/user_list.dart @@ -0,0 +1,45 @@ +import 'package:CWCFlutter/model/user.dart'; +import 'package:flutter/material.dart'; + +class UserList extends StatelessWidget { + final List users; + final Function(User) onDelete; + + UserList(this.users, this.onDelete); + + @override + Widget build(BuildContext context) { + return ListView.builder( + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) => Card( + elevation: 8, + child: Padding( + padding: EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Name: ${users[index].name}', + style: TextStyle(fontSize: 18), + ), + Text( + 'City: ${users[index].city}', + style: TextStyle(fontSize: 18), + ), + ], + ), + IconButton( + icon: Icon(Icons.delete), + onPressed: () => onDelete(users[index]), + ) + ], + ), + ), + ), + itemCount: users.length, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 65e5fc2..ebd1af7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,87 +7,115 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "1.0.2" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0+1" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" + riverpod: + dependency: transitive + description: + name: riverpod + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0+1" sky_engine: dependency: transitive description: flutter @@ -99,55 +127,63 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" + state_notifier: + dependency: transitive + description: + name: state_notifier + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" sdks: - dart: ">=2.10.0-110 <2.11.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index f6db4d8..9c2e6ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,15 +14,16 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter + flutter_riverpod: ^0.14.0+1 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: