{"id":13552485,"url":"https://github.com/flutter-school/yo-flutter","last_synced_at":"2025-04-03T03:31:53.224Z","repository":{"id":217999849,"uuid":"175094484","full_name":"flutter-school/yo-flutter","owner":"flutter-school","description":"A clone of Yo!","archived":false,"fork":false,"pushed_at":"2019-03-12T19:11:35.000Z","size":361,"stargazers_count":21,"open_issues_count":0,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-03T23:34:55.520Z","etag":null,"topics":["firebase","flutter"],"latest_commit_sha":null,"homepage":"https://flutter.school","language":"Dart","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flutter-school.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-11T22:37:56.000Z","updated_at":"2024-03-31T14:43:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"0f42e2a1-0cc1-433e-9ee7-8002837ca608","html_url":"https://github.com/flutter-school/yo-flutter","commit_stats":null,"previous_names":["flutter-school/yo-flutter"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flutter-school%2Fyo-flutter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flutter-school%2Fyo-flutter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flutter-school%2Fyo-flutter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flutter-school%2Fyo-flutter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flutter-school","download_url":"https://codeload.github.com/flutter-school/yo-flutter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246933423,"owners_count":20857049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["firebase","flutter"],"created_at":"2024-08-01T12:02:04.765Z","updated_at":"2025-04-03T03:31:48.193Z","avatar_url":"https://github.com/flutter-school.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"# Yo! In Flutter.\n\n![yo_flutter](https://user-images.githubusercontent.com/11478053/49794374-b1a1ce00-fd37-11e8-9364-9ec0efde9ca6.png)\n\nBasically [Yo!](http://www.justyo.co/) written in Flutter. Done in a three hour workshop with people who never used Flutter before 🍻\n\n## Lesson 1\n\n- Clone the project `git clone git@github.com:flutter-school/yo-flutter.git` and \n- run it `flutter run`\n\nFlutter install instructions: \n- https://flutter.dev/docs/get-started/install\n- https://flutter.dev/docs/get-started/editor\n\nIf you have trouble setting up flutter, ask for support\n\nYou've finished this lessen if you see the congratulations screen on your phone.\n\n## Lesson 2\n\nCreate the list layout of your friends. Use the screenshot above as reference.\n\n1. Create a `FriendsPage` widget. \"Screen\" are called \"Pages\" in Flutter.\n2. Use the [`ListView.builder`](https://docs.flutter.io/flutter/widgets/ListView-class.html) widget to show the items. \n\nUse the existing `Person` data class in `person.dart`.\n\nHere are some helpful snippets:\n```dart\nfinal List\u003cPerson\u003e friends = [\n    Person(\"ffff\", \"Frederik Schweiger\", \"https://pbs.twimg.com/profile_images/1074391975820972033/SP7txc1D_400x400.jpg\"),\n    Person(\"pppp\", \"Pascal Welsch\", \"https://pbs.twimg.com/profile_images/941273826557677568/wCBwklPP_400x400.jpg\"),\n    Person(\"gggg\", \"Georg Bednorz\", \"https://pbs.twimg.com/profile_images/1091439933716381701/PIfcpdHq_400x400.png\"),\n    Person(\"ssss\", \"Seth Ladd\", \"https://pbs.twimg.com/profile_images/986316447293952000/oZWVUWDs_400x400.jpg\"),\n    Person(\"kkkk\", \"Kate Lovett\", \"https://pbs.twimg.com/profile_images/1048927764156432384/JxEqQ9dX_400x400.jpg\"),\n    Person(\"tttt\", \"Tim Sneath\", \"https://pbs.twimg.com/profile_images/653618067084218368/XlQA-oRl_400x400.jpg\"),\n    Person(\"hhhh\", \"Filip Hráček\", \"https://pbs.twimg.com/profile_images/796079953079111680/ymD9DY5g_400x400.jpg\"),\n    Person(\"aaaa\", \"Andrew Brogdon\", \"https://pbs.twimg.com/profile_images/651444930884186112/9vlhNFlu_400x400.png\"),\n    Person(\"nnnn\", \"Nitya Narasimhan\", \"https://pbs.twimg.com/profile_images/988808912504733697/z03gHVFL_400x400.jpg\"),\n];\n\nList\u003cColor\u003e _colors = [\n    Color(0xFFF8B195),\n    Color(0xFFF67280),\n    Color(0xFFC06C84),\n    Color(0xFF6C5B7B),\n    Color(0xFF355C7D),\n    Color(0xFF34495D),\n];\n```\n\n## Lesson 3\n\n\u003cimg height=\"400px\" src=\"https://user-images.githubusercontent.com/1096485/54165147-c2a9ca80-445f-11e9-8e9e-c1956e17c9ed.png\" \u003e\u003c/img\u003e\n\nBuild the login screen with [scoped_model](https://github.com/brianegan/scoped_model/)\n\nUse the existing `SessionModel` in `session_model.dart` and register it globally in your `main` function.\n\n```dart\nfinal SessionModel sessionModel = SessionModel();\nrunApp(ScopedModel\u003cSessionModel\u003e(\n  model: sessionModel,\n  child: YoApp(),\n  ));\n```\n\nBuild a Widget which toggles between the `FriedsPage` and a `LoginPage` depending on the session state.\nUse `ScopedModelDescendant` to access the `SessionModel`\n\n```dart\nScopedModelDescendant\u003cSessionModel\u003e(\n    builder: (BuildContext context, Widget child, SessionModel model) {\n      // TODO use model\n      return anyWidget;\n    },\n),\n```\n\nLear how ScopedModel works under the hood: [InheritedWidgets and App-scope/Page-scope](https://medium.com/@mehmetf_71205/inheriting-widgets-b7ac56dbbeb1)\n\n## Lesson 4 (optional)\n\nWe want to send YO!s to each other via push notifications. \nYou need a apple developer account to make it work with iOS.\nFor now, we'll focus on Android to receive the notifications.\n\nThe android project is already fully connected to a instance firebase. \nIf you want full access you have to create your own firebase project.\n\n- Create the Android app\n    - applicationId `school.flutter.yo`\n    - SHA-1 `D2:6E:E8:94:62:5E:1D:74:C7:84:26:0A:32:8A:4E:26:2D:DD:FE:E4` (for existing key `flutterschool.jks`)\n- (Create the iOS apps with `school.flutter.yo` as bundleId)\n\n\n- Download the firebase configuration files to\n    - `android/app/google-services.json` \n    - `ios/Runner/GoogleService-Info.plist`\n    On iOS you need to edit `ios/Runner/Info.plist` and paste in your `REVERSED_CLIENT_ID`.\n\n- Enable Google Authentication (`Develop -\u003e Authentication -\u003e Sign-in method -\u003e Goolge -\u003e Enable`) \n\n\n\n- Deploy firebase cloud functions, see `fireabse/README.md`\n\n## Lesson 5\n\nShow real users form firebase\n\n1. Refactor your static `FriendsPage` and load your Friends from firebase. \nDon't put the Firebase loading code in the UI, create a page-scoped model (`FriendsModel`). \n\nHere's some code for you to start\n```dart\nclass FriendsModel extends Model {\n  /// Easy access to this model using [ScopedModel.of]\n  static FriendsModel of(BuildContext context) =\u003e\n      ScopedModel.of\u003cFriendsModel\u003e(context);\n\n  FriendsModel(this.userModel) {\n    _loadFriends();\n  }\n\n  List\u003cPerson\u003e get friends =\u003e _friends?.toList() ?? [];\n  Iterable\u003cPerson\u003e _friends;\n\n  bool get isLoading =\u003e _friends == null;\n\n  SessionModel userModel;\n\n  Future\u003cvoid\u003e sendYo(Person person) async {\n    // TODO\n    throw \"not implemented\";\n  }\n\n  Future\u003cvoid\u003e _loadFriends() async {\n    // TODO\n    throw \"not implemented\";\n  }\n}\n```\n\nNow implement the data loading. \nThis is how you get your friends form firebase.\n(Don't forget to notify the UI after loading)\n```dart\nimport 'package:cloud_firestore/cloud_firestore.dart';\n\nfinal stream = Firestore.instance.collection(Person.REF).orderBy(\"name\").snapshots();\nstream.listen((QuerySnapshot snapshot) {\n  final friends = snapshot.documents.map((data) =\u003e Person.fromJson(data.data));\n});\n```\n\n## Lesson 6\n\nSend push notifications\n\nRegister for firebase notifications after successful login\n```dart\nimport 'package:firebase_messaging/firebase_messaging.dart';\n\nfinal fmToken = await FirebaseMessaging().getToken();\nFirestore.instance\n    .collection(\"tokens\")\n    .document(_user.uid)\n    .setData({'token': fmToken})\n```\n\nTip: `print` a message with the users email address after successfully writing the token to firebase. \n\n## Lesson 7\n\nSend yo! to another user\n\nImplement `FriendsModel.sendYo` and call the firebase cloud function to notify other users that you think about them\n```dart\nawait http.get('https://us-central1-yo-flutter-80f0f.cloudfunctions.net/sendYo?'\n    'fromUid=${userModel.uid}\u0026toUid=${person.uid}');\n```\n\nCaution: \n- You won't see a notification if the app is in foreground\n- Test on a real device, not the emulator/simulator\n- It doesn't work on iOS unless you've registered you APNs Authentication Key\n\n\n## Bonus 1\n\nAdd a logout button to your app. \nCall `ScopedModel.of\u003cSessionModel\u003e(context).logout();` instead of creating a `ScopedModelDescendant`.\n\n## Bonus 2\n\nRewrite the `FriendsModel` using immutable collections from [kt.dart](https://github.com/passsy/kt.dart)\n\n## Disclaimer\n\nPlease note that this code is not production ready, it should just show how quick you could build a million dollar app for Android and iOS 😉\n\n\n## Finished app\n\nIf you run into trouble we have a working example for you. Run\n\n```bash\nflutter run lib/finished/finished.dart\n```\n\n## License\n\n```\nCopyright 2019 flutter.school\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflutter-school%2Fyo-flutter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflutter-school%2Fyo-flutter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflutter-school%2Fyo-flutter/lists"}