├── .idea ├── libraries │ ├── Dart_Packages.xml │ └── Dart_SDK.xml ├── misc.xml ├── modules.xml ├── runConfigurations │ ├── scaled_server_dart.xml │ └── server_dart.xml ├── vcs.xml └── workspace.xml ├── README.md ├── client ├── .gitignore ├── .idea │ ├── modules.xml │ └── runConfigurations │ │ └── main_dart.xml ├── README.md ├── android.iml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── yourcompany │ │ │ │ └── client │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ └── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ ├── build.gradle │ ├── gradle.properties │ └── settings.gradle ├── client.iml ├── client_android.iml ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ └── contents.xcworkspacedata │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── main.m ├── lib │ ├── main.dart │ └── src │ │ └── widgets │ │ ├── chat_home.dart │ │ ├── chat_login.dart │ │ └── chat_message_list.dart ├── pubspec.lock └── pubspec.yaml ├── common ├── .gitignore ├── common.iml ├── lib │ ├── common.dart │ └── src │ │ └── models │ │ ├── models.dart │ │ └── models.g.dart ├── pubspec.lock ├── pubspec.yaml └── tool │ ├── build.dart │ ├── phases.dart │ └── watch.dart ├── screenshots ├── conversation.PNG ├── conversation_small.PNG ├── login.PNG └── typing.PNG └── server ├── .analysis-options ├── .dockerignore ├── .gitignore ├── .idea ├── angel.iml ├── misc.xml ├── modules.xml └── runConfigurations │ ├── Load_Balanced_Server__PRODUCTION_.xml │ ├── Message_Tests.xml │ ├── Multi_Threaded_Server__PRODUCTION_.xml │ ├── Start_Server.xml │ ├── Start_Server__PRODUCTION_.xml │ ├── Todo_Tests.xml │ └── Users_Tests.xml ├── .vscode ├── launch.json └── tasks.json ├── Dockerfile ├── LICENSE ├── README.md ├── bin ├── cluster.dart ├── common.dart ├── multi_server.dart ├── scaled_server.dart └── server.dart ├── config ├── default.yaml ├── development.yaml └── production.yaml ├── lib ├── server.dart └── src │ ├── config │ ├── config.dart │ └── plugins │ │ └── plugins.dart │ ├── routes │ ├── controllers │ │ ├── auth.dart │ │ └── controllers.dart │ └── routes.dart │ ├── services │ ├── message.dart │ ├── services.dart │ └── user.dart │ └── validators │ ├── message.dart │ ├── todo.dart │ └── user.dart ├── pubspec.lock ├── pubspec.yaml ├── server.iml ├── test └── services │ ├── message_test.dart │ ├── todo_test.dart │ └── users_test.dart ├── tool └── grind.dart ├── views ├── error.mustache └── hello.mustache └── web ├── images ├── dart.png ├── favicon.png ├── flutter.jpg └── google.png └── robots.txt /.idea/libraries/Dart_Packages.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/scaled_server_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/runConfigurations/server_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter 2 | [Tutorial on Dart Academy](https://dart.academy/building-a-real-time-chat-app-with-angel-and-flutter/) 3 | 4 | A realtime chatroom built with 5 | [Angel](https://angel-dart.github.io) and 6 | [Flutter](https://flutter.io). 7 | 8 | This application uses WebSockets and local authentication, 9 | as well as service hooks. In terms of server-side code, it is relatively 10 | simple; this serves as a testament to Angel's promise of expedited 11 | development cycles. 12 | 13 | ![Login Screen](screenshots/login.PNG) 14 | ![Chat Screen](screenshots/conversation.PNG) 15 | 16 | ## Organization 17 | This project is divided into three sub-projects: 18 | 19 | * `common` - Shared code, i.e. models. 20 | * `server` - A server powered by the Angel framework 21 | * `client` - A mobile app, written with [Flutter](https://flutter.io), that queries the `server`. 22 | 23 | ## Learn More 24 | [![The Angel Framework](https://angel-dart.github.io/images/logo.png)](https://angel-dart.github.io) 25 | 26 | To learn more about the Angel framework, check out the 27 | [main website](https://angel-dart.github.io) and 28 | [wiki](https://github.com/angel-dart/angel/wiki). 29 | 30 | Also consider starring the [main repo](https://github.com/angel-dart/angel)! Thank you! 31 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Dart template 3 | # See https://www.dartlang.org/tools/private-files.html 4 | 5 | # source_gen 6 | .dart_tool 7 | 8 | # Files and directories created by pub 9 | .buildlog 10 | .packages 11 | .project 12 | .pub/ 13 | .scripts-bin/ 14 | build/ 15 | **/packages/ 16 | 17 | # Files created by dart2js 18 | # (Most Dart developers will use pub build to compile Dart, use/modify these 19 | # rules if you intend to use dart2js directly 20 | # Convention is to use extension '.dart.js' for Dart compiled to Javascript to 21 | # differentiate from explicit Javascript files) 22 | *.dart.js 23 | *.part.js 24 | *.js.deps 25 | *.js.map 26 | *.info.json 27 | 28 | # Directory created by dartdoc 29 | doc/api/ 30 | 31 | # Don't commit pubspec lock file 32 | # (Library packages only! Remove pattern if developing an application package) 33 | # pubspec.lock 34 | ### JetBrains template 35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 36 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 37 | 38 | # User-specific stuff: 39 | .idea/workspace.xml 40 | .idea/tasks.xml 41 | .idea/dictionaries 42 | .idea/vcs.xml 43 | .idea/jsLibraryMappings.xml 44 | 45 | # Sensitive or high-churn files: 46 | .idea/dataSources.ids 47 | .idea/dataSources.xml 48 | .idea/dataSources.local.xml 49 | .idea/sqlDataSources.xml 50 | .idea/dynamic.xml 51 | .idea/uiDesigner.xml 52 | 53 | # Gradle: 54 | .idea/gradle.xml 55 | .idea/libraries 56 | 57 | # Mongo Explorer plugin: 58 | .idea/mongoSettings.xml 59 | 60 | ## File-based project format: 61 | *.iws 62 | 63 | ## Plugin-specific files: 64 | 65 | # IntelliJ 66 | /out/ 67 | 68 | # mpeltonen/sbt-idea plugin 69 | .idea_modules/ 70 | 71 | # JIRA plugin 72 | atlassian-ide-plugin.xml 73 | 74 | # Crashlytics plugin (for Android Studio and IntelliJ) 75 | com_crashlytics_export_strings.xml 76 | crashlytics.properties 77 | crashlytics-build.properties 78 | fabric.properties 79 | 80 | ### VSCode template 81 | .vscode/* 82 | !.vscode/settings.json 83 | !.vscode/tasks.json 84 | !.vscode/launch.json 85 | !.vscode/extensions.json 86 | 87 | logs/ 88 | *.pem 89 | .DS_Store 90 | -------------------------------------------------------------------------------- /client/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/.idea/runConfigurations/main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # client 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](http://flutter.io/). 9 | -------------------------------------------------------------------------------- /client/android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /client/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | GeneratedPluginRegistrant.java 10 | 11 | /gradle 12 | /gradlew 13 | /gradlew.bat 14 | -------------------------------------------------------------------------------- /client/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withInputStream { stream -> 5 | localProperties.load(stream) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | apply plugin: 'com.android.application' 15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 16 | 17 | android { 18 | compileSdkVersion 25 19 | buildToolsVersion '25.0.3' 20 | 21 | lintOptions { 22 | disable 'InvalidPackage' 23 | } 24 | 25 | defaultConfig { 26 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 27 | 28 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 29 | applicationId "com.yourcompany.client" 30 | } 31 | 32 | buildTypes { 33 | release { 34 | // TODO: Add your own signing config for the release build. 35 | // Signing with the debug keys for now, so `flutter run --release` works. 36 | signingConfig signingConfigs.debug 37 | } 38 | } 39 | } 40 | 41 | flutter { 42 | source '../..' 43 | } 44 | 45 | dependencies { 46 | androidTestCompile 'com.android.support:support-annotations:25.0.0' 47 | androidTestCompile 'com.android.support.test:runner:0.5' 48 | androidTestCompile 'com.android.support.test:rules:0.5' 49 | } 50 | -------------------------------------------------------------------------------- /client/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 19 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /client/android/app/src/main/java/com/yourcompany/client/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yourcompany.client; 2 | 3 | import android.os.Bundle; 4 | 5 | import io.flutter.app.FlutterActivity; 6 | import io.flutter.plugins.GeneratedPluginRegistrant; 7 | 8 | public class MainActivity extends FlutterActivity { 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | GeneratedPluginRegistrant.registerWith(this); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:2.2.3' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | jcenter() 14 | } 15 | } 16 | 17 | rootProject.buildDir = '../build' 18 | subprojects { 19 | project.buildDir = "${rootProject.buildDir}/${project.name}" 20 | project.evaluationDependsOn(':app') 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | 27 | task wrapper(type: Wrapper) { 28 | gradleVersion = '2.14.1' 29 | } 30 | -------------------------------------------------------------------------------- /client/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /client/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withInputStream { stream -> plugins.load(stream) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /client/client.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /client/client_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /client/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | *.pbxuser 16 | *.mode1v3 17 | *.mode2v3 18 | *.perspectivev3 19 | 20 | !default.pbxuser 21 | !default.mode1v3 22 | !default.mode2v3 23 | !default.perspectivev3 24 | 25 | xcuserdata 26 | 27 | *.moved-aside 28 | 29 | *.pyc 30 | *sync/ 31 | Icon? 32 | .tags* 33 | 34 | /Flutter/app.flx 35 | /Flutter/app.zip 36 | /Flutter/App.framework 37 | /Flutter/Flutter.framework 38 | /Flutter/Generated.xcconfig 39 | /ServiceDefinitions.json 40 | 41 | Pods/ 42 | -------------------------------------------------------------------------------- /client/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | UIRequiredDeviceCapabilities 24 | 25 | arm64 26 | 27 | MinimumOSVersion 28 | 8.0 29 | 30 | 31 | -------------------------------------------------------------------------------- /client/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /client/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /client/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | if ENV['FLUTTER_FRAMEWORK_DIR'] == nil 5 | abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') 6 | end 7 | 8 | target 'Runner' do 9 | # Pods for Runner 10 | 11 | # Flutter Pods 12 | pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] 13 | 14 | if File.exists? '../.flutter-plugins' 15 | flutter_root = File.expand_path('..') 16 | File.foreach('../.flutter-plugins') { |line| 17 | plugin = line.split(pattern='=') 18 | if plugin.length == 2 19 | name = plugin[0].strip() 20 | path = plugin[1].strip() 21 | resolved_path = File.expand_path("#{path}/ios", flutter_root) 22 | pod name, :path => resolved_path 23 | else 24 | puts "Invalid plugin specification: #{line}" 25 | end 26 | } 27 | end 28 | end 29 | 30 | post_install do |installer| 31 | installer.pods_project.targets.each do |target| 32 | target.build_configurations.each do |config| 33 | config.build_settings['ENABLE_BITCODE'] = 'NO' 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /client/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 15 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 17 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; 18 | 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; 19 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 20 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 21 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 22 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 23 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXCopyFilesBuildPhase section */ 27 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 28 | isa = PBXCopyFilesBuildPhase; 29 | buildActionMask = 2147483647; 30 | dstPath = ""; 31 | dstSubfolderSpec = 10; 32 | files = ( 33 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 34 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 35 | ); 36 | name = "Embed Frameworks"; 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXCopyFilesBuildPhase section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 43 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 51 | 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = ""; }; 52 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 53 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 55 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 56 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 57 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 58 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | /* End PBXFileReference section */ 60 | 61 | /* Begin PBXFrameworksBuildPhase section */ 62 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 63 | isa = PBXFrameworksBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 67 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXFrameworksBuildPhase section */ 72 | 73 | /* Begin PBXGroup section */ 74 | 9740EEB11CF90186004384FC /* Flutter */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 9740EEB71CF902C7004384FC /* app.flx */, 78 | 3B80C3931E831B6300D905FE /* App.framework */, 79 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 80 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 81 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 82 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 83 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 84 | ); 85 | name = Flutter; 86 | sourceTree = ""; 87 | }; 88 | 97C146E51CF9000F007C117D = { 89 | isa = PBXGroup; 90 | children = ( 91 | 9740EEB11CF90186004384FC /* Flutter */, 92 | 97C146F01CF9000F007C117D /* Runner */, 93 | 97C146EF1CF9000F007C117D /* Products */, 94 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, 95 | ); 96 | sourceTree = ""; 97 | }; 98 | 97C146EF1CF9000F007C117D /* Products */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 97C146EE1CF9000F007C117D /* Runner.app */, 102 | ); 103 | name = Products; 104 | sourceTree = ""; 105 | }; 106 | 97C146F01CF9000F007C117D /* Runner */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 110 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 111 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 112 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 113 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 114 | 97C147021CF9000F007C117D /* Info.plist */, 115 | 97C146F11CF9000F007C117D /* Supporting Files */, 116 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 117 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 118 | ); 119 | path = Runner; 120 | sourceTree = ""; 121 | }; 122 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 97C146F21CF9000F007C117D /* main.m */, 126 | ); 127 | name = "Supporting Files"; 128 | sourceTree = ""; 129 | }; 130 | /* End PBXGroup section */ 131 | 132 | /* Begin PBXNativeTarget section */ 133 | 97C146ED1CF9000F007C117D /* Runner */ = { 134 | isa = PBXNativeTarget; 135 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 136 | buildPhases = ( 137 | 9740EEB61CF901F6004384FC /* Run Script */, 138 | 97C146EA1CF9000F007C117D /* Sources */, 139 | 97C146EB1CF9000F007C117D /* Frameworks */, 140 | 97C146EC1CF9000F007C117D /* Resources */, 141 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 142 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = Runner; 149 | productName = Runner; 150 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 151 | productType = "com.apple.product-type.application"; 152 | }; 153 | /* End PBXNativeTarget section */ 154 | 155 | /* Begin PBXProject section */ 156 | 97C146E61CF9000F007C117D /* Project object */ = { 157 | isa = PBXProject; 158 | attributes = { 159 | LastUpgradeCheck = 0830; 160 | ORGANIZATIONNAME = "The Chromium Authors"; 161 | TargetAttributes = { 162 | 97C146ED1CF9000F007C117D = { 163 | CreatedOnToolsVersion = 7.3.1; 164 | }; 165 | }; 166 | }; 167 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 168 | compatibilityVersion = "Xcode 3.2"; 169 | developmentRegion = English; 170 | hasScannedForEncodings = 0; 171 | knownRegions = ( 172 | en, 173 | Base, 174 | ); 175 | mainGroup = 97C146E51CF9000F007C117D; 176 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 177 | projectDirPath = ""; 178 | projectRoot = ""; 179 | targets = ( 180 | 97C146ED1CF9000F007C117D /* Runner */, 181 | ); 182 | }; 183 | /* End PBXProject section */ 184 | 185 | /* Begin PBXResourcesBuildPhase section */ 186 | 97C146EC1CF9000F007C117D /* Resources */ = { 187 | isa = PBXResourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 9740EEBB1CF902C7004384FC /* app.flx in Resources */, 191 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 192 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, 193 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 194 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 195 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 196 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | }; 200 | /* End PBXResourcesBuildPhase section */ 201 | 202 | /* Begin PBXShellScriptBuildPhase section */ 203 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 204 | isa = PBXShellScriptBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | ); 208 | inputPaths = ( 209 | ); 210 | name = "Thin Binary"; 211 | outputPaths = ( 212 | ); 213 | runOnlyForDeploymentPostprocessing = 0; 214 | shellPath = /bin/sh; 215 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 216 | }; 217 | 9740EEB61CF901F6004384FC /* Run Script */ = { 218 | isa = PBXShellScriptBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | ); 222 | inputPaths = ( 223 | ); 224 | name = "Run Script"; 225 | outputPaths = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | shellPath = /bin/sh; 229 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 230 | }; 231 | /* End PBXShellScriptBuildPhase section */ 232 | 233 | /* Begin PBXSourcesBuildPhase section */ 234 | 97C146EA1CF9000F007C117D /* Sources */ = { 235 | isa = PBXSourcesBuildPhase; 236 | buildActionMask = 2147483647; 237 | files = ( 238 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 239 | 97C146F31CF9000F007C117D /* main.m in Sources */, 240 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXSourcesBuildPhase section */ 245 | 246 | /* Begin PBXVariantGroup section */ 247 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 248 | isa = PBXVariantGroup; 249 | children = ( 250 | 97C146FB1CF9000F007C117D /* Base */, 251 | ); 252 | name = Main.storyboard; 253 | sourceTree = ""; 254 | }; 255 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 256 | isa = PBXVariantGroup; 257 | children = ( 258 | 97C147001CF9000F007C117D /* Base */, 259 | ); 260 | name = LaunchScreen.storyboard; 261 | sourceTree = ""; 262 | }; 263 | /* End PBXVariantGroup section */ 264 | 265 | /* Begin XCBuildConfiguration section */ 266 | 97C147031CF9000F007C117D /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 269 | buildSettings = { 270 | ALWAYS_SEARCH_USER_PATHS = NO; 271 | CLANG_ANALYZER_NONNULL = YES; 272 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 273 | CLANG_CXX_LIBRARY = "libc++"; 274 | CLANG_ENABLE_MODULES = YES; 275 | CLANG_ENABLE_OBJC_ARC = YES; 276 | CLANG_WARN_BOOL_CONVERSION = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INFINITE_RECURSION = YES; 282 | CLANG_WARN_INT_CONVERSION = YES; 283 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 284 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 285 | CLANG_WARN_UNREACHABLE_CODE = YES; 286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 288 | COPY_PHASE_STRIP = NO; 289 | DEBUG_INFORMATION_FORMAT = dwarf; 290 | ENABLE_STRICT_OBJC_MSGSEND = YES; 291 | ENABLE_TESTABILITY = YES; 292 | GCC_C_LANGUAGE_STANDARD = gnu99; 293 | GCC_DYNAMIC_NO_PIC = NO; 294 | GCC_NO_COMMON_BLOCKS = YES; 295 | GCC_OPTIMIZATION_LEVEL = 0; 296 | GCC_PREPROCESSOR_DEFINITIONS = ( 297 | "DEBUG=1", 298 | "$(inherited)", 299 | ); 300 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 301 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 302 | GCC_WARN_UNDECLARED_SELECTOR = YES; 303 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 304 | GCC_WARN_UNUSED_FUNCTION = YES; 305 | GCC_WARN_UNUSED_VARIABLE = YES; 306 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 307 | MTL_ENABLE_DEBUG_INFO = YES; 308 | ONLY_ACTIVE_ARCH = YES; 309 | SDKROOT = iphoneos; 310 | TARGETED_DEVICE_FAMILY = "1,2"; 311 | }; 312 | name = Debug; 313 | }; 314 | 97C147041CF9000F007C117D /* Release */ = { 315 | isa = XCBuildConfiguration; 316 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 317 | buildSettings = { 318 | ALWAYS_SEARCH_USER_PATHS = NO; 319 | CLANG_ANALYZER_NONNULL = YES; 320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 321 | CLANG_CXX_LIBRARY = "libc++"; 322 | CLANG_ENABLE_MODULES = YES; 323 | CLANG_ENABLE_OBJC_ARC = YES; 324 | CLANG_WARN_BOOL_CONVERSION = YES; 325 | CLANG_WARN_CONSTANT_CONVERSION = YES; 326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 327 | CLANG_WARN_EMPTY_BODY = YES; 328 | CLANG_WARN_ENUM_CONVERSION = YES; 329 | CLANG_WARN_INFINITE_RECURSION = YES; 330 | CLANG_WARN_INT_CONVERSION = YES; 331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 332 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 333 | CLANG_WARN_UNREACHABLE_CODE = YES; 334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 335 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 336 | COPY_PHASE_STRIP = NO; 337 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 338 | ENABLE_NS_ASSERTIONS = NO; 339 | ENABLE_STRICT_OBJC_MSGSEND = YES; 340 | GCC_C_LANGUAGE_STANDARD = gnu99; 341 | GCC_NO_COMMON_BLOCKS = YES; 342 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 343 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 344 | GCC_WARN_UNDECLARED_SELECTOR = YES; 345 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 346 | GCC_WARN_UNUSED_FUNCTION = YES; 347 | GCC_WARN_UNUSED_VARIABLE = YES; 348 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 349 | MTL_ENABLE_DEBUG_INFO = NO; 350 | SDKROOT = iphoneos; 351 | TARGETED_DEVICE_FAMILY = "1,2"; 352 | VALIDATE_PRODUCT = YES; 353 | }; 354 | name = Release; 355 | }; 356 | 97C147061CF9000F007C117D /* Debug */ = { 357 | isa = XCBuildConfiguration; 358 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 359 | buildSettings = { 360 | ARCHS = arm64; 361 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 362 | ENABLE_BITCODE = NO; 363 | FRAMEWORK_SEARCH_PATHS = ( 364 | "$(inherited)", 365 | "$(PROJECT_DIR)/Flutter", 366 | ); 367 | INFOPLIST_FILE = Runner/Info.plist; 368 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 369 | LIBRARY_SEARCH_PATHS = ( 370 | "$(inherited)", 371 | "$(PROJECT_DIR)/Flutter", 372 | ); 373 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.client; 374 | PRODUCT_NAME = "$(TARGET_NAME)"; 375 | }; 376 | name = Debug; 377 | }; 378 | 97C147071CF9000F007C117D /* Release */ = { 379 | isa = XCBuildConfiguration; 380 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 381 | buildSettings = { 382 | ARCHS = arm64; 383 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 384 | ENABLE_BITCODE = NO; 385 | FRAMEWORK_SEARCH_PATHS = ( 386 | "$(inherited)", 387 | "$(PROJECT_DIR)/Flutter", 388 | ); 389 | INFOPLIST_FILE = Runner/Info.plist; 390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 391 | LIBRARY_SEARCH_PATHS = ( 392 | "$(inherited)", 393 | "$(PROJECT_DIR)/Flutter", 394 | ); 395 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.client; 396 | PRODUCT_NAME = "$(TARGET_NAME)"; 397 | }; 398 | name = Release; 399 | }; 400 | /* End XCBuildConfiguration section */ 401 | 402 | /* Begin XCConfigurationList section */ 403 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 404 | isa = XCConfigurationList; 405 | buildConfigurations = ( 406 | 97C147031CF9000F007C117D /* Debug */, 407 | 97C147041CF9000F007C117D /* Release */, 408 | ); 409 | defaultConfigurationIsVisible = 0; 410 | defaultConfigurationName = Release; 411 | }; 412 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 413 | isa = XCConfigurationList; 414 | buildConfigurations = ( 415 | 97C147061CF9000F007C117D /* Debug */, 416 | 97C147071CF9000F007C117D /* Release */, 417 | ); 418 | defaultConfigurationIsVisible = 0; 419 | defaultConfigurationName = Release; 420 | }; 421 | /* End XCConfigurationList section */ 422 | }; 423 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 424 | } 425 | -------------------------------------------------------------------------------- /client/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /client/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /client/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /client/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 7 | [GeneratedPluginRegistrant registerWithRegistry:self]; 8 | // Override point for customization after application launch. 9 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /client/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /client/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | client 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | arm64 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UIViewControllerBasedStatusBarAppearance 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /client/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'src/widgets/chat_home.dart'; 3 | 4 | void main() { 5 | runApp(new ChatApp()); 6 | } 7 | 8 | class ChatApp extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return new MaterialApp( 12 | theme: new ThemeData(primarySwatch: Colors.teal), 13 | home: new ChatHome(), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/lib/src/widgets/chat_home.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:angel_client/flutter.dart'; 3 | import 'package:angel_websocket/flutter.dart'; 4 | import 'package:common/common.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'chat_login.dart'; 7 | import 'chat_message_list.dart'; 8 | 9 | class ChatHome extends StatefulWidget { 10 | @override 11 | State createState() => new _ChatHomeState(); 12 | } 13 | 14 | class _ChatHomeState extends State { 15 | final Angel restApp = new Rest('http://10.134.80.167:3000'); 16 | String token; 17 | User user; 18 | WebSockets wsApp; 19 | Service service; 20 | bool connecting = true, error = false; 21 | List messages = []; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | if (user == null) { 26 | return new Scaffold( 27 | appBar: new AppBar( 28 | title: new Text('Log In'), 29 | ), 30 | body: new ChatLogin(restApp, (AngelAuthResult auth) { 31 | setState(() { 32 | user = User.parse(auth.data); 33 | token = auth.token; 34 | wsApp = new WebSockets('ws://10.134.80.167:3000/ws'); 35 | }); 36 | 37 | wsApp 38 | .connect() 39 | .then((_) { 40 | var c = new Completer(); 41 | StreamSubscription onAuth, onError; 42 | 43 | onAuth = wsApp.onAuthenticated.listen((_) { 44 | service = wsApp.service('api/messages'); 45 | 46 | service 47 | ..onIndexed.listen((WebSocketEvent e) { 48 | setState(() { 49 | messages 50 | ..clear() 51 | ..addAll(e.data.map(Message.parse)); 52 | }); 53 | }) 54 | ..onCreated.listen((WebSocketEvent e) { 55 | setState(() { 56 | messages.add(Message.parse(e.data)); 57 | }); 58 | }); 59 | 60 | service.index(); 61 | onAuth.cancel(); 62 | c.complete(); 63 | }); 64 | 65 | onError = wsApp.onError.listen((e) { 66 | onError.cancel(); 67 | c.completeError(e); 68 | }); 69 | 70 | wsApp.authenticateViaJwt(auth.token); 71 | return c.future; 72 | }) 73 | .timeout(new Duration(minutes: 1)) 74 | .catchError((e) { 75 | showDialog( 76 | context: context, 77 | child: new SimpleDialog( 78 | title: new Text('Couldn\'t connect to chat server.'), 79 | )).then((_) { 80 | setState(() => error = true); 81 | }); 82 | }) 83 | .whenComplete(() { 84 | setState(() => connecting = false); 85 | }); 86 | }), 87 | ); 88 | } 89 | 90 | Widget body; 91 | 92 | // Render different content depending on the state of the application. 93 | if (connecting) 94 | body = new Text('Connecting to server...'); 95 | else if (error) 96 | body = new Text('An error occurred while connecting to the server.'); 97 | else { 98 | body = new ChatMessageList(restApp, service, messages, user); 99 | } 100 | 101 | return new Scaffold( 102 | appBar: new AppBar( 103 | title: new Text('Chat (${messages.length} messages)'), 104 | ), 105 | body: body, 106 | ); 107 | } 108 | } -------------------------------------------------------------------------------- /client/lib/src/widgets/chat_login.dart: -------------------------------------------------------------------------------- 1 | import 'package:angel_client/flutter.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// A callback that handles the result of successful authentication against a server. 5 | typedef void HandleAuth(AngelAuthResult auth); 6 | 7 | /// Renders a log-in screen that POSTs to /auth/lccal on our server. 8 | class ChatLogin extends StatefulWidget { 9 | /// An [Angel] client that interacts with the server over plain HTTP. 10 | /// 11 | /// We need this to POST to /auth/local and receive a JWT. 12 | /// 13 | /// Once we receive the JWT, we can use it to authenticate our WebSocket. 14 | final Angel restApp; 15 | 16 | /// Invoke this with the [AngelAuthResult] that contains an authenticated user, and a JWT. 17 | final HandleAuth handleAuth; 18 | 19 | ChatLogin(this.restApp, this.handleAuth); 20 | 21 | @override 22 | State createState() => new _ChatLoginState(restApp, handleAuth); 23 | } 24 | 25 | class _ChatLoginState extends State { 26 | final Angel restApp; 27 | final HandleAuth handleAuth; 28 | String username, password; 29 | bool sending = false; 30 | 31 | _ChatLoginState(this.restApp, this.handleAuth); 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return new Padding( 36 | padding: const EdgeInsets.all(16.0), 37 | child: new Form( 38 | child: new Column( 39 | children: [ 40 | new TextField( 41 | decoration: new InputDecoration(labelText: 'Username'), 42 | onChanged: (String str) => setState(() => username = str), 43 | ), 44 | new TextField( 45 | decoration: new InputDecoration(labelText: 'Password'), 46 | onChanged: (String str) => setState(() => password = str), 47 | ), 48 | sending 49 | ? new CircularProgressIndicator() 50 | : new RaisedButton( 51 | onPressed: () { 52 | setState(() => sending = true); 53 | 54 | // The `authenticate` method will not only POST to /auth/, 55 | // but also parse the server's response. 56 | // 57 | // Naturally, this API expects that your server is using 58 | // `package:angel_auth`, which issues signed JWT's. 59 | // 60 | // For more documentation: 61 | // * https://github.com/angel-dart/auth 62 | // * https://github.com/angel-dart/client 63 | // * https://jwt.io 64 | restApp.authenticate(type: 'local', credentials: { 65 | 'username': username, 66 | 'password': password 67 | }).then((auth) { 68 | // Alert the parent widget that we've logged in! 69 | handleAuth(auth); 70 | }).catchError((e) { 71 | // If we fail to log-in, tell the user that something went wrong. 72 | showDialog( 73 | context: context, 74 | child: new SimpleDialog( 75 | title: new Text('Login Error: $e'), 76 | )); 77 | }).whenComplete(() { 78 | setState(() => sending = false); 79 | }); 80 | }, 81 | color: Theme.of(context).primaryColor, 82 | highlightColor: Theme.of(context).highlightColor, 83 | child: new Text( 84 | 'SUBMIT', 85 | style: new TextStyle(color: Colors.white), 86 | ), 87 | ) 88 | ], 89 | ), 90 | ), 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /client/lib/src/widgets/chat_message_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:angel_client/angel_client.dart'; 2 | import 'package:common/common.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// Simply renders a list of chat messages. 6 | class ChatMessageList extends StatelessWidget { 7 | /// An [Angel] client pointing toward an HTTP server. 8 | /// 9 | /// We need it for its [basePath] property. 10 | final Angel restApp; 11 | 12 | /// A client-side [Service], which mirrors the server-side implementation. 13 | /// 14 | /// We use this to create messages on the server, in this case via WebSocket. 15 | final Service service; 16 | final List messages; 17 | final User user; 18 | 19 | ChatMessageList(this.restApp, this.service, this.messages, this.user); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return new Column( 24 | children: [ 25 | new Flexible( 26 | child: messages.isEmpty 27 | ? new Text('Nobody has said anything yet... Break the silence!') 28 | : new ListView.builder( 29 | itemCount: messages.length, 30 | itemBuilder: (_, int i) { 31 | return new ListTile( 32 | // Resolve the path of an image on the server, using the `basePath` 33 | // of our `restApp`. 34 | leading: new Image.network( 35 | '${restApp.basePath}/images/${messages[i].user.avatar}'), 36 | title: new Text( 37 | messages[i].user.username, 38 | style: new TextStyle(fontWeight: FontWeight.bold), 39 | ), 40 | subtitle: new Text(messages[i].text), 41 | ); 42 | }), 43 | ), 44 | new Divider(height: 1.0), 45 | new Container( 46 | decoration: new BoxDecoration(color: Theme.of(context).cardColor), 47 | child: new Padding( 48 | padding: const EdgeInsets.only(left: 8.0, right: 8.0), 49 | child: new TextField( 50 | decoration: new InputDecoration(labelText: 'Send a message...'), 51 | onSubmitted: (String msg) { 52 | if (msg.isNotEmpty) { 53 | // When the user wants to send a message, all 54 | // we need to do is send an action through our 55 | // WebSocket. 56 | // 57 | // `package:angel_websocket` provides a clean API 58 | // that accomplishes this while also implementing the 59 | // `package:angel_client` API. 60 | // 61 | // This resembles the server-side, and makes developing full-stack 62 | // with Angel make a little bit more sense. 63 | // 64 | // We don't need to call any fancy state-setting functions, because 65 | // our chat app is already listening to our WebSocket to modify its state 66 | // when new messages come in. 67 | service.create({'text': msg}); 68 | } 69 | }, 70 | ), 71 | ), 72 | ) 73 | ], 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /client/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See http://pub.dartlang.org/doc/glossary.html#lockfile 3 | packages: 4 | analyzer: 5 | description: 6 | name: analyzer 7 | url: "https://pub.dartlang.org" 8 | source: hosted 9 | version: "0.30.0+2" 10 | angel_auth: 11 | description: 12 | name: angel_auth 13 | url: "https://pub.dartlang.org" 14 | source: hosted 15 | version: "1.0.5" 16 | angel_client: 17 | description: 18 | name: angel_client 19 | url: "https://pub.dartlang.org" 20 | source: hosted 21 | version: "1.0.7" 22 | angel_framework: 23 | description: 24 | name: angel_framework 25 | url: "https://pub.dartlang.org" 26 | source: hosted 27 | version: "1.0.6" 28 | angel_route: 29 | description: 30 | name: angel_route 31 | url: "https://pub.dartlang.org" 32 | source: hosted 33 | version: "1.0.4" 34 | angel_serialize: 35 | description: 36 | name: angel_serialize 37 | url: "https://pub.dartlang.org" 38 | source: hosted 39 | version: "1.0.0-alpha" 40 | angel_websocket: 41 | description: 42 | name: angel_websocket 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.0.8" 46 | args: 47 | description: 48 | name: args 49 | url: "https://pub.dartlang.org" 50 | source: hosted 51 | version: "0.13.7" 52 | async: 53 | description: 54 | name: async 55 | url: "https://pub.dartlang.org" 56 | source: hosted 57 | version: "1.13.3" 58 | body_parser: 59 | description: 60 | name: body_parser 61 | url: "https://pub.dartlang.org" 62 | source: hosted 63 | version: "1.0.1" 64 | build: 65 | description: 66 | name: build 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "0.9.3" 70 | charcode: 71 | description: 72 | name: charcode 73 | url: "https://pub.dartlang.org" 74 | source: hosted 75 | version: "1.1.1" 76 | cli_util: 77 | description: 78 | name: cli_util 79 | url: "https://pub.dartlang.org" 80 | source: hosted 81 | version: "0.1.1" 82 | code_builder: 83 | description: 84 | name: code_builder 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "1.0.4" 88 | collection: 89 | description: 90 | name: collection 91 | url: "https://pub.dartlang.org" 92 | source: hosted 93 | version: "1.14.1" 94 | common: 95 | description: 96 | path: "..\\common" 97 | relative: true 98 | source: path 99 | version: "0.0.0" 100 | container: 101 | description: 102 | name: container 103 | url: "https://pub.dartlang.org" 104 | source: hosted 105 | version: "0.1.2" 106 | convert: 107 | description: 108 | name: convert 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "2.0.1" 112 | crypto: 113 | description: 114 | name: crypto 115 | url: "https://pub.dartlang.org" 116 | source: hosted 117 | version: "2.0.1" 118 | csslib: 119 | description: 120 | name: csslib 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "0.14.0" 124 | dart_style: 125 | description: 126 | name: dart_style 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.0.6" 130 | flatten: 131 | description: 132 | name: flatten 133 | url: "https://pub.dartlang.org" 134 | source: hosted 135 | version: "1.0.0" 136 | flutter: 137 | description: flutter 138 | source: sdk 139 | version: "0.0.27" 140 | front_end: 141 | description: 142 | name: front_end 143 | url: "https://pub.dartlang.org" 144 | source: hosted 145 | version: "0.1.0-alpha.4" 146 | func: 147 | description: 148 | name: func 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "1.0.0" 152 | glob: 153 | description: 154 | name: glob 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "1.1.3" 158 | html: 159 | description: 160 | name: html 161 | url: "https://pub.dartlang.org" 162 | source: hosted 163 | version: "0.13.2" 164 | http: 165 | description: 166 | name: http 167 | url: "https://pub.dartlang.org" 168 | source: hosted 169 | version: "0.11.3+13" 170 | http_parser: 171 | description: 172 | name: http_parser 173 | url: "https://pub.dartlang.org" 174 | source: hosted 175 | version: "3.1.1" 176 | http_server: 177 | description: 178 | name: http_server 179 | url: "https://pub.dartlang.org" 180 | source: hosted 181 | version: "0.9.6" 182 | id: 183 | description: 184 | name: id 185 | url: "https://pub.dartlang.org" 186 | source: hosted 187 | version: "1.0.16" 188 | intl: 189 | description: 190 | name: intl 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "0.14.0" 194 | isolate: 195 | description: 196 | name: isolate 197 | url: "https://pub.dartlang.org" 198 | source: hosted 199 | version: "1.0.0" 200 | json_god: 201 | description: 202 | name: json_god 203 | url: "https://pub.dartlang.org" 204 | source: hosted 205 | version: "2.0.0-beta+1" 206 | kernel: 207 | description: 208 | name: kernel 209 | url: "https://pub.dartlang.org" 210 | source: hosted 211 | version: "0.3.0-alpha.1" 212 | logging: 213 | description: 214 | name: logging 215 | url: "https://pub.dartlang.org" 216 | source: hosted 217 | version: "0.11.3+1" 218 | matcher: 219 | description: 220 | name: matcher 221 | url: "https://pub.dartlang.org" 222 | source: hosted 223 | version: "0.12.1+1" 224 | merge_map: 225 | description: 226 | name: merge_map 227 | url: "https://pub.dartlang.org" 228 | source: hosted 229 | version: "1.0.0" 230 | meta: 231 | description: 232 | name: meta 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "1.0.5" 236 | mime: 237 | description: 238 | name: mime 239 | url: "https://pub.dartlang.org" 240 | source: hosted 241 | version: "0.9.3" 242 | package_config: 243 | description: 244 | name: package_config 245 | url: "https://pub.dartlang.org" 246 | source: hosted 247 | version: "1.0.1" 248 | path: 249 | description: 250 | name: path 251 | url: "https://pub.dartlang.org" 252 | source: hosted 253 | version: "1.4.2" 254 | plugin: 255 | description: 256 | name: plugin 257 | url: "https://pub.dartlang.org" 258 | source: hosted 259 | version: "0.2.0" 260 | quiver: 261 | description: 262 | name: quiver 263 | url: "https://pub.dartlang.org" 264 | source: hosted 265 | version: "0.24.0" 266 | random_string: 267 | description: 268 | name: random_string 269 | url: "https://pub.dartlang.org" 270 | source: hosted 271 | version: "0.0.1" 272 | recase: 273 | description: 274 | name: recase 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.0.0+1" 278 | sky_engine: 279 | description: 280 | path: "..\\..\\..\\Source\\flutter\\bin\\cache\\pkg\\sky_engine" 281 | relative: true 282 | source: path 283 | version: "0.0.99" 284 | source_gen: 285 | description: 286 | name: source_gen 287 | url: "https://pub.dartlang.org" 288 | source: hosted 289 | version: "0.5.10+1" 290 | source_span: 291 | description: 292 | name: source_span 293 | url: "https://pub.dartlang.org" 294 | source: hosted 295 | version: "1.4.0" 296 | stack_trace: 297 | description: 298 | name: stack_trace 299 | url: "https://pub.dartlang.org" 300 | source: hosted 301 | version: "1.7.4" 302 | stream_channel: 303 | description: 304 | name: stream_channel 305 | url: "https://pub.dartlang.org" 306 | source: hosted 307 | version: "1.6.1" 308 | string_scanner: 309 | description: 310 | name: string_scanner 311 | url: "https://pub.dartlang.org" 312 | source: hosted 313 | version: "1.0.2" 314 | typed_data: 315 | description: 316 | name: typed_data 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "1.1.3" 320 | utf: 321 | description: 322 | name: utf 323 | url: "https://pub.dartlang.org" 324 | source: hosted 325 | version: "0.9.0+3" 326 | uuid: 327 | description: 328 | name: uuid 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "0.5.3" 332 | vector_math: 333 | description: 334 | name: vector_math 335 | url: "https://pub.dartlang.org" 336 | source: hosted 337 | version: "2.0.4" 338 | watcher: 339 | description: 340 | name: watcher 341 | url: "https://pub.dartlang.org" 342 | source: hosted 343 | version: "0.9.7+3" 344 | web_socket_channel: 345 | description: 346 | name: web_socket_channel 347 | url: "https://pub.dartlang.org" 348 | source: hosted 349 | version: "1.0.4" 350 | yaml: 351 | description: 352 | name: yaml 353 | url: "https://pub.dartlang.org" 354 | source: hosted 355 | version: "2.1.12" 356 | sdks: 357 | dart: ">=1.23.0-dev.0.0 <2.0.0" 358 | -------------------------------------------------------------------------------- /client/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: client 2 | description: A new Flutter project. 3 | 4 | dependencies: 5 | angel_websocket: ^1.0.0 6 | common: 7 | path: ../common 8 | flutter: 9 | sdk: flutter 10 | 11 | # For information on the generic Dart part of this file, see the 12 | # following page: https://www.dartlang.org/tools/pub/pubspec 13 | 14 | # The following section is specific to Flutter. 15 | flutter: 16 | 17 | # The following line ensures that the Material Icons font is 18 | # included with your application, so that you can use the icons in 19 | # the Icons class. 20 | uses-material-design: true 21 | 22 | # To add assets to your application, add an assets section here, in 23 | # this "flutter" section, as in: 24 | # assets: 25 | # - images/a_dot_burr.jpeg 26 | # - images/a_dot_ham.jpeg 27 | 28 | # To add assets from package dependencies, first ensure the asset 29 | # is in the lib/ directory of the dependency. Then, 30 | # refer to the asset with a path prefixed with 31 | # `packages/PACKAGE_NAME/`. Note: the `lib/` is implied, do not 32 | # include `lib/` in the asset path. 33 | # 34 | # Here is an example: 35 | # 36 | # assets: 37 | # - packages/PACKAGE_NAME/path/to/asset 38 | 39 | # To add custom fonts to your application, add a fonts section here, 40 | # in this "flutter" section. Each entry in this list should have a 41 | # "family" key with the font family name, and a "fonts" key with a 42 | # list giving the asset and other descriptors for the font. For 43 | # example: 44 | # fonts: 45 | # - family: Schyler 46 | # fonts: 47 | # - asset: fonts/Schyler-Regular.ttf 48 | # - asset: fonts/Schyler-Italic.ttf 49 | # style: italic 50 | # - family: Trajan Pro 51 | # fonts: 52 | # - asset: fonts/TrajanPro.ttf 53 | # - asset: fonts/TrajanPro_Bold.ttf 54 | # weight: 700 55 | -------------------------------------------------------------------------------- /common/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Dart template 3 | # See https://www.dartlang.org/tools/private-files.html 4 | 5 | # source_gen 6 | .dart_tool 7 | 8 | # Files and directories created by pub 9 | .buildlog 10 | .packages 11 | .project 12 | .pub/ 13 | .scripts-bin/ 14 | build/ 15 | **/packages/ 16 | 17 | # Files created by dart2js 18 | # (Most Dart developers will use pub build to compile Dart, use/modify these 19 | # rules if you intend to use dart2js directly 20 | # Convention is to use extension '.dart.js' for Dart compiled to Javascript to 21 | # differentiate from explicit Javascript files) 22 | *.dart.js 23 | *.part.js 24 | *.js.deps 25 | *.js.map 26 | *.info.json 27 | 28 | # Directory created by dartdoc 29 | doc/api/ 30 | 31 | # Don't commit pubspec lock file 32 | # (Library packages only! Remove pattern if developing an application package) 33 | # pubspec.lock 34 | ### JetBrains template 35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 36 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 37 | 38 | # User-specific stuff: 39 | .idea/workspace.xml 40 | .idea/tasks.xml 41 | .idea/dictionaries 42 | .idea/vcs.xml 43 | .idea/jsLibraryMappings.xml 44 | 45 | # Sensitive or high-churn files: 46 | .idea/dataSources.ids 47 | .idea/dataSources.xml 48 | .idea/dataSources.local.xml 49 | .idea/sqlDataSources.xml 50 | .idea/dynamic.xml 51 | .idea/uiDesigner.xml 52 | 53 | # Gradle: 54 | .idea/gradle.xml 55 | .idea/libraries 56 | 57 | # Mongo Explorer plugin: 58 | .idea/mongoSettings.xml 59 | 60 | ## File-based project format: 61 | *.iws 62 | 63 | ## Plugin-specific files: 64 | 65 | # IntelliJ 66 | /out/ 67 | 68 | # mpeltonen/sbt-idea plugin 69 | .idea_modules/ 70 | 71 | # JIRA plugin 72 | atlassian-ide-plugin.xml 73 | 74 | # Crashlytics plugin (for Android Studio and IntelliJ) 75 | com_crashlytics_export_strings.xml 76 | crashlytics.properties 77 | crashlytics-build.properties 78 | fabric.properties 79 | 80 | ### VSCode template 81 | .vscode/* 82 | !.vscode/settings.json 83 | !.vscode/tasks.json 84 | !.vscode/launch.json 85 | !.vscode/extensions.json 86 | 87 | logs/ 88 | *.pem 89 | .DS_Store 90 | -------------------------------------------------------------------------------- /common/common.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /common/lib/common.dart: -------------------------------------------------------------------------------- 1 | export 'src/models/models.dart'; -------------------------------------------------------------------------------- /common/lib/src/models/models.dart: -------------------------------------------------------------------------------- 1 | library common.models; 2 | import 'package:angel_model/angel_model.dart'; 3 | import 'package:angel_serialize/angel_serialize.dart'; 4 | part 'models.g.dart'; 5 | 6 | @serializable 7 | class _User extends Model { 8 | String username, password, salt, avatar; 9 | } 10 | 11 | @serializable 12 | class _Message extends Model { 13 | String userId, text; 14 | _User user; 15 | } -------------------------------------------------------------------------------- /common/lib/src/models/models.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of common.models; 4 | 5 | // ************************************************************************** 6 | // Generator: JsonModelGenerator 7 | // Target: class _User 8 | // ************************************************************************** 9 | 10 | class User extends _User { 11 | @override 12 | String id; 13 | 14 | @override 15 | String username; 16 | 17 | @override 18 | String password; 19 | 20 | @override 21 | String salt; 22 | 23 | @override 24 | String avatar; 25 | 26 | @override 27 | DateTime createdAt; 28 | 29 | @override 30 | DateTime updatedAt; 31 | 32 | User( 33 | {this.id, 34 | this.username, 35 | this.password, 36 | this.salt, 37 | this.avatar, 38 | this.createdAt, 39 | this.updatedAt}); 40 | 41 | factory User.fromJson(Map data) { 42 | return new User( 43 | id: data['id'], 44 | username: data['username'], 45 | password: data['password'], 46 | salt: data['salt'], 47 | avatar: data['avatar'], 48 | createdAt: data['created_at'] is DateTime 49 | ? data['created_at'] 50 | : (data['created_at'] is String 51 | ? DateTime.parse(data['created_at']) 52 | : null), 53 | updatedAt: data['updated_at'] is DateTime 54 | ? data['updated_at'] 55 | : (data['updated_at'] is String 56 | ? DateTime.parse(data['updated_at']) 57 | : null)); 58 | } 59 | 60 | Map toJson() => { 61 | 'id': id, 62 | 'username': username, 63 | 'password': password, 64 | 'salt': salt, 65 | 'avatar': avatar, 66 | 'created_at': createdAt == null ? null : createdAt.toIso8601String(), 67 | 'updated_at': updatedAt == null ? null : updatedAt.toIso8601String() 68 | }; 69 | 70 | static User parse(Map map) => new User.fromJson(map); 71 | } 72 | 73 | // ************************************************************************** 74 | // Generator: JsonModelGenerator 75 | // Target: class _Message 76 | // ************************************************************************** 77 | 78 | class Message extends _Message { 79 | @override 80 | String id; 81 | 82 | @override 83 | String userId; 84 | 85 | @override 86 | String text; 87 | 88 | @override 89 | _User user; 90 | 91 | @override 92 | DateTime createdAt; 93 | 94 | @override 95 | DateTime updatedAt; 96 | 97 | Message( 98 | {this.id, 99 | this.userId, 100 | this.text, 101 | this.user, 102 | this.createdAt, 103 | this.updatedAt}); 104 | 105 | factory Message.fromJson(Map data) { 106 | return new Message( 107 | id: data['id'], 108 | userId: data['user_id'], 109 | text: data['text'], 110 | user: data['user'] == null 111 | ? null 112 | : (data['user'] is User 113 | ? data['user'] 114 | : new User.fromJson(data['user'])), 115 | createdAt: data['created_at'] is DateTime 116 | ? data['created_at'] 117 | : (data['created_at'] is String 118 | ? DateTime.parse(data['created_at']) 119 | : null), 120 | updatedAt: data['updated_at'] is DateTime 121 | ? data['updated_at'] 122 | : (data['updated_at'] is String 123 | ? DateTime.parse(data['updated_at']) 124 | : null)); 125 | } 126 | 127 | Map toJson() => { 128 | 'id': id, 129 | 'user_id': userId, 130 | 'text': text, 131 | 'user': user, 132 | 'created_at': createdAt == null ? null : createdAt.toIso8601String(), 133 | 'updated_at': updatedAt == null ? null : updatedAt.toIso8601String() 134 | }; 135 | 136 | static Message parse(Map map) => new Message.fromJson(map); 137 | } 138 | -------------------------------------------------------------------------------- /common/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See http://pub.dartlang.org/doc/glossary.html#lockfile 3 | packages: 4 | analyzer: 5 | description: 6 | name: analyzer 7 | url: "https://pub.dartlang.org" 8 | source: hosted 9 | version: "0.30.0+2" 10 | angel_model: 11 | description: 12 | name: angel_model 13 | url: "https://pub.dartlang.org" 14 | source: hosted 15 | version: "1.0.0" 16 | angel_serialize: 17 | description: 18 | name: angel_serialize 19 | url: "https://pub.dartlang.org" 20 | source: hosted 21 | version: "1.0.0-alpha+1" 22 | angel_serialize_generator: 23 | description: 24 | name: angel_serialize_generator 25 | url: "https://pub.dartlang.org" 26 | source: hosted 27 | version: "1.0.0-alpha+1" 28 | args: 29 | description: 30 | name: args 31 | url: "https://pub.dartlang.org" 32 | source: hosted 33 | version: "0.13.7" 34 | async: 35 | description: 36 | name: async 37 | url: "https://pub.dartlang.org" 38 | source: hosted 39 | version: "1.13.3" 40 | barback: 41 | description: 42 | name: barback 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.15.2+11" 46 | build: 47 | description: 48 | name: build 49 | url: "https://pub.dartlang.org" 50 | source: hosted 51 | version: "0.9.3" 52 | build_barback: 53 | description: 54 | name: build_barback 55 | url: "https://pub.dartlang.org" 56 | source: hosted 57 | version: "0.3.0" 58 | build_runner: 59 | description: 60 | name: build_runner 61 | url: "https://pub.dartlang.org" 62 | source: hosted 63 | version: "0.3.4+1" 64 | charcode: 65 | description: 66 | name: charcode 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.1.1" 70 | cli_util: 71 | description: 72 | name: cli_util 73 | url: "https://pub.dartlang.org" 74 | source: hosted 75 | version: "0.1.2" 76 | code_builder: 77 | description: 78 | name: code_builder 79 | url: "https://pub.dartlang.org" 80 | source: hosted 81 | version: "1.0.4" 82 | code_transformers: 83 | description: 84 | name: code_transformers 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.5.1+3" 88 | collection: 89 | description: 90 | name: collection 91 | url: "https://pub.dartlang.org" 92 | source: hosted 93 | version: "1.14.3" 94 | convert: 95 | description: 96 | name: convert 97 | url: "https://pub.dartlang.org" 98 | source: hosted 99 | version: "2.0.1" 100 | crypto: 101 | description: 102 | name: crypto 103 | url: "https://pub.dartlang.org" 104 | source: hosted 105 | version: "2.0.2" 106 | csslib: 107 | description: 108 | name: csslib 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "0.14.0" 112 | dart_style: 113 | description: 114 | name: dart_style 115 | url: "https://pub.dartlang.org" 116 | source: hosted 117 | version: "1.0.7" 118 | front_end: 119 | description: 120 | name: front_end 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "0.1.0-alpha.4" 124 | func: 125 | description: 126 | name: func 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.0.0" 130 | glob: 131 | description: 132 | name: glob 133 | url: "https://pub.dartlang.org" 134 | source: hosted 135 | version: "1.1.3" 136 | html: 137 | description: 138 | name: html 139 | url: "https://pub.dartlang.org" 140 | source: hosted 141 | version: "0.13.2" 142 | http_parser: 143 | description: 144 | name: http_parser 145 | url: "https://pub.dartlang.org" 146 | source: hosted 147 | version: "3.1.1" 148 | id: 149 | description: 150 | name: id 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "1.0.16" 154 | isolate: 155 | description: 156 | name: isolate 157 | url: "https://pub.dartlang.org" 158 | source: hosted 159 | version: "1.0.0" 160 | kernel: 161 | description: 162 | name: kernel 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "0.3.0-alpha.1" 166 | logging: 167 | description: 168 | name: logging 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "0.11.3+1" 172 | matcher: 173 | description: 174 | name: matcher 175 | url: "https://pub.dartlang.org" 176 | source: hosted 177 | version: "0.12.1+1" 178 | meta: 179 | description: 180 | name: meta 181 | url: "https://pub.dartlang.org" 182 | source: hosted 183 | version: "1.1.1" 184 | mime: 185 | description: 186 | name: mime 187 | url: "https://pub.dartlang.org" 188 | source: hosted 189 | version: "0.9.3" 190 | package_config: 191 | description: 192 | name: package_config 193 | url: "https://pub.dartlang.org" 194 | source: hosted 195 | version: "1.0.2" 196 | path: 197 | description: 198 | name: path 199 | url: "https://pub.dartlang.org" 200 | source: hosted 201 | version: "1.4.2" 202 | plugin: 203 | description: 204 | name: plugin 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "0.2.0+1" 208 | pool: 209 | description: 210 | name: pool 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "1.3.1" 214 | quiver: 215 | description: 216 | name: quiver 217 | url: "https://pub.dartlang.org" 218 | source: hosted 219 | version: "0.24.0" 220 | recase: 221 | description: 222 | name: recase 223 | url: "https://pub.dartlang.org" 224 | source: hosted 225 | version: "1.0.0+1" 226 | shelf: 227 | description: 228 | name: shelf 229 | url: "https://pub.dartlang.org" 230 | source: hosted 231 | version: "0.6.8" 232 | shelf_static: 233 | description: 234 | name: shelf_static 235 | url: "https://pub.dartlang.org" 236 | source: hosted 237 | version: "0.2.5" 238 | source_gen: 239 | description: 240 | name: source_gen 241 | url: "https://pub.dartlang.org" 242 | source: hosted 243 | version: "0.6.1+1" 244 | source_maps: 245 | description: 246 | name: source_maps 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "0.10.4" 250 | source_span: 251 | description: 252 | name: source_span 253 | url: "https://pub.dartlang.org" 254 | source: hosted 255 | version: "1.4.0" 256 | stack_trace: 257 | description: 258 | name: stack_trace 259 | url: "https://pub.dartlang.org" 260 | source: hosted 261 | version: "1.8.0" 262 | stream_channel: 263 | description: 264 | name: stream_channel 265 | url: "https://pub.dartlang.org" 266 | source: hosted 267 | version: "1.6.1" 268 | stream_transform: 269 | description: 270 | name: stream_transform 271 | url: "https://pub.dartlang.org" 272 | source: hosted 273 | version: "0.0.7" 274 | string_scanner: 275 | description: 276 | name: string_scanner 277 | url: "https://pub.dartlang.org" 278 | source: hosted 279 | version: "1.0.2" 280 | typed_data: 281 | description: 282 | name: typed_data 283 | url: "https://pub.dartlang.org" 284 | source: hosted 285 | version: "1.1.3" 286 | utf: 287 | description: 288 | name: utf 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "0.9.0+3" 292 | watcher: 293 | description: 294 | name: watcher 295 | url: "https://pub.dartlang.org" 296 | source: hosted 297 | version: "0.9.7+3" 298 | yaml: 299 | description: 300 | name: yaml 301 | url: "https://pub.dartlang.org" 302 | source: hosted 303 | version: "2.1.12" 304 | sdks: 305 | dart: ">=1.22.1 <2.0.0-dev.infinity" 306 | -------------------------------------------------------------------------------- /common/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: common 2 | dependencies: 3 | angel_model: ^1.0.0 4 | angel_serialize: ^1.0.0-alpha 5 | dev_dependencies: 6 | angel_serialize_generator: ^1.0.0-alpha 7 | build_runner: ^0.3.0 -------------------------------------------------------------------------------- /common/tool/build.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_runner/build_runner.dart'; 2 | import 'phases.dart'; 3 | 4 | main() => build(PHASES, deleteFilesByDefault: true); -------------------------------------------------------------------------------- /common/tool/phases.dart: -------------------------------------------------------------------------------- 1 | import 'package:angel_serialize_generator/angel_serialize_generator.dart'; 2 | import 'package:build_runner/build_runner.dart'; 3 | import 'package:source_gen/source_gen.dart'; 4 | 5 | final PhaseGroup PHASES = new PhaseGroup.singleAction( 6 | new GeneratorBuilder([new JsonModelGenerator()]), 7 | new InputSet('common', const ['lib/src/models/*.dart'])); 8 | -------------------------------------------------------------------------------- /common/tool/watch.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_runner/build_runner.dart'; 2 | import 'phases.dart'; 3 | 4 | main() => watch(PHASES, deleteFilesByDefault: true); -------------------------------------------------------------------------------- /screenshots/conversation.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/screenshots/conversation.PNG -------------------------------------------------------------------------------- /screenshots/conversation_small.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/screenshots/conversation_small.PNG -------------------------------------------------------------------------------- /screenshots/login.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/screenshots/login.PNG -------------------------------------------------------------------------------- /screenshots/typing.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/screenshots/typing.PNG -------------------------------------------------------------------------------- /server/.analysis-options: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | exclude: 4 | - .scripts-bin/**/*.dart 5 | -------------------------------------------------------------------------------- /server/.dockerignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .idea 3 | .pub 4 | .vscode 5 | logs/ 6 | test/ 7 | build/ 8 | .analysis-options 9 | .packages 10 | *.g.dart -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Dart template 3 | # See https://www.dartlang.org/tools/private-files.html 4 | 5 | # source_gen 6 | .dart_tool 7 | 8 | # Files and directories created by pub 9 | .buildlog 10 | .packages 11 | .project 12 | .pub/ 13 | .scripts-bin/ 14 | build/ 15 | **/packages/ 16 | 17 | # Files created by dart2js 18 | # (Most Dart developers will use pub build to compile Dart, use/modify these 19 | # rules if you intend to use dart2js directly 20 | # Convention is to use extension '.dart.js' for Dart compiled to Javascript to 21 | # differentiate from explicit Javascript files) 22 | *.dart.js 23 | *.part.js 24 | *.js.deps 25 | *.js.map 26 | *.info.json 27 | 28 | # Directory created by dartdoc 29 | doc/api/ 30 | 31 | # Don't commit pubspec lock file 32 | # (Library packages only! Remove pattern if developing an application package) 33 | # pubspec.lock 34 | ### JetBrains template 35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 36 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 37 | 38 | # User-specific stuff: 39 | .idea/workspace.xml 40 | .idea/tasks.xml 41 | .idea/dictionaries 42 | .idea/vcs.xml 43 | .idea/jsLibraryMappings.xml 44 | 45 | # Sensitive or high-churn files: 46 | .idea/dataSources.ids 47 | .idea/dataSources.xml 48 | .idea/dataSources.local.xml 49 | .idea/sqlDataSources.xml 50 | .idea/dynamic.xml 51 | .idea/uiDesigner.xml 52 | 53 | # Gradle: 54 | .idea/gradle.xml 55 | .idea/libraries 56 | 57 | # Mongo Explorer plugin: 58 | .idea/mongoSettings.xml 59 | 60 | ## File-based project format: 61 | *.iws 62 | 63 | ## Plugin-specific files: 64 | 65 | # IntelliJ 66 | /out/ 67 | 68 | # mpeltonen/sbt-idea plugin 69 | .idea_modules/ 70 | 71 | # JIRA plugin 72 | atlassian-ide-plugin.xml 73 | 74 | # Crashlytics plugin (for Android Studio and IntelliJ) 75 | com_crashlytics_export_strings.xml 76 | crashlytics.properties 77 | crashlytics-build.properties 78 | fabric.properties 79 | 80 | ### VSCode template 81 | .vscode/* 82 | !.vscode/settings.json 83 | !.vscode/tasks.json 84 | !.vscode/launch.json 85 | !.vscode/extensions.json 86 | 87 | logs/ 88 | *.pem 89 | .DS_Store 90 | -------------------------------------------------------------------------------- /server/.idea/angel.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /server/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | General 15 | 16 | 17 | XPath 18 | 19 | 20 | 21 | 22 | AngularJS 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /server/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /server/.idea/runConfigurations/Load_Balanced_Server__PRODUCTION_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /server/.idea/runConfigurations/Message_Tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /server/.idea/runConfigurations/Multi_Threaded_Server__PRODUCTION_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /server/.idea/runConfigurations/Start_Server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /server/.idea/runConfigurations/Start_Server__PRODUCTION_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | -------------------------------------------------------------------------------- /server/.idea/runConfigurations/Todo_Tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /server/.idea/runConfigurations/Users_Tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Start Server", 6 | "type": "dart-cli", 7 | "request": "launch", 8 | "program": "${workspaceRoot}/bin/server.dart", 9 | "checkedMode": true 10 | }, 11 | { 12 | "name": "Multi-Threaded Server", 13 | "type": "dart-cli", 14 | "request": "launch", 15 | "program": "${workspaceRoot}/bin/scaled_server.dart", 16 | "checkedMode": true 17 | }, 18 | { 19 | "name": "Load-Balanced Server", 20 | "type": "dart-cli", 21 | "request": "launch", 22 | "program": "${workspaceRoot}/bin/multi_server.dart", 23 | "checkedMode": true 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /server/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "command": "pub", 6 | "isShellCommand": true, 7 | "echoCommand": true, 8 | "showOutput": "always", 9 | "tasks": [ 10 | { 11 | "taskName": "pub:build", 12 | "suppressTaskName": true, 13 | "args": [ 14 | "build" 15 | ] 16 | }, 17 | { 18 | "taskName": "pub:serve", 19 | "showOutput": "silent", 20 | "suppressTaskName": true, 21 | "isBackground": true, 22 | "args": [ 23 | "serve" 24 | ] 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER Tobe O 3 | 4 | # Install Dart SDK 1.21.0 5 | RUN sudo apt-get update 6 | RUN sudo apt-get install -y apt-transport-https 7 | RUN sudo apt-get install -y curl 8 | RUN sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' 9 | RUN sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list' 10 | RUN sudo apt-get update 11 | RUN sudo apt-get install -y dart=1.21.0-1 12 | RUN export PATH="/usr/lib/dart/bin:$PATH" 13 | 14 | # Copy necessary files 15 | ADD bin/ bin/ 16 | ADD config/ config/ 17 | ADD lib/ lib/ 18 | ADD tool/ tool/ 19 | ADD views/ views/ 20 | ADD web/ web/ 21 | ADD pubspec.yaml pubspec.yaml 22 | 23 | # Install dependencies, pre-build 24 | RUN /usr/lib/dart/bin/pub get 25 | RUN /usr/lib/dart/bin/dart tool/build.dart 26 | RUN /usr/lib/dart/bin/pub build 27 | 28 | # Set environment, start multi-server :) 29 | ENV ANGEL_ENV=production 30 | EXPOSE 3000 31 | ENTRYPOINT ["/usr/lib/dart/bin/dart"] 32 | CMD ["bin/multi_server.dart"] -------------------------------------------------------------------------------- /server/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 angel-dart 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | [![The Angel Framework](https://angel-dart.github.io/images/logo.png)](https://angel-dart.github.io) 2 | 3 | [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/angel_dart/discussion) 4 | [![version: v1.0.0](https://img.shields.io/badge/pub-v1.0.0-brightgreen.svg)](https://pub.dartlang.org/packages/angel_common) 5 | 6 | **Fill out the [v1.0.0 survey](https://docs.google.com/forms/d/e/1FAIpQLSfEgBNsOoi_nYZMmg2IAGyMv1nNaa6B3kUk3QdNJU5987ucVA/viewform?usp=sf_link) now!!!** 7 | 8 | [Wiki (in-depth documentation)](https://github.com/angel-dart/angel/wiki) 9 | 10 | [API Documentation](http://www.dartdocs.org/documentation/angel_common/latest) 11 | 12 | [Roadmap](https://github.com/angel-dart/roadmap/blob/master/ROADMAP.md) 13 | 14 | [File an Issue](https://github.com/angel-dart/roadmap/issues) 15 | 16 | **The Dart server framework that's ready for showtime.** 17 | 18 | Angel is a full-featured server-side Web application framework for the Dart programming language. It strives to be a flexible, extensible system, to be easily scalable, and to allow as much code to be shared between clients and servers as possible. Ultimately, I believe that this approach will shorten the time it takes to build a full-stack Web application, from start to finish. [Read more...](https://medium.com/the-angel-framework/announcing-angel-v1-0-0-beta-46dfb4aa8afe) 19 | 20 | Like what you see? Please lend us a star. :star: 21 | 22 | ## Newest Tutorials 23 | * [Serving Static Files](https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae) 24 | * Use With Angular2 ([article](https://dart.academy/using-angel-with-angular2/) | [video](https://www.youtube.com/watch?v=O8tCXj_lljY&feature=youtu.be)) 25 | * [Instant REST API's - Intro to Services](https://medium.com/the-angel-framework/instant-rest-apis-and-more-an-introduction-to-angel-services-b843f3187f67) 26 | 27 | ## Installation & Setup 28 | *Having errors with a fresh Angel installation? See [here](https://github.com/angel-dart/angel/wiki/Installation-&-Setup) for help.* 29 | 30 | Once you have [Dart](https://www.dartlang.org/) installed, bootstrapping a project is as simple as running one shell command: 31 | 32 | Install the [Angel CLI](https://github.com/angel-dart/cli): 33 | 34 | ```bash 35 | pub global activate angel_cli 36 | ``` 37 | 38 | Bootstrap a project: 39 | 40 | ```bash 41 | angel init hello 42 | ``` 43 | 44 | You can even have your server run and be *live-reloaded* on file changes: 45 | 46 | ```bash 47 | dart bin/server.dart 48 | ``` 49 | 50 | Next, check out the [detailed documentation](https://github.com/angel-dart/angel/wiki) to learn to flesh out your project. 51 | 52 | ## Features 53 | With features like the following, Angel is the all-in-one framework you should choose to build your next project: 54 | * [Advanced, Modular Routing](https://github.com/angel-dart/route) 55 | * [Middleware](https://github.com/angel-dart/angel/wiki/Middleware) 56 | * [Dependency Injection](https://github.com/angel-dart/angel/wiki/Dependency-Injection) 57 | * And [much more](https://github.com/angel-dart)... 58 | 59 | ## Basic Example 60 | More examples and complete projects can be found in the [angel-example](https://github.com/angel-example) organization. 61 | 62 | The following is an [explosive application](https://github.com/angel-example/explode) complete with a REST API and 63 | WebSocket support. It interacts with a MongoDB database, and reads configuration automatically from a `config/.yaml` file. Templates are rendered with Mustache, and all responses are compressed via GZIP. 64 | 65 | **All in just about 20 lines of actual code.** 66 | 67 | ```dart 68 | import 'dart:async'; 69 | import 'package:angel_common/angel_common.dart'; 70 | import 'package:angel_websocket/server.dart'; 71 | import 'package:mongo_dart/mongo_dart.dart'; 72 | 73 | main() async { 74 | var app = await createServer(); 75 | var server = await app.startServer(InternetAddress.LOOPBACK_IP_V4, 8080); 76 | print('Angel listening at http://${server.address.address}:${server.port}'); 77 | } 78 | 79 | Future createServer() async { 80 | // New instance... 81 | var app = new Angel(); 82 | 83 | // Configuration 84 | await app.configure(loadConfigurationFile()); 85 | await app.configure(mustache()); 86 | Db db = new Db(); 87 | await db.open(app.mongodb_url); 88 | app.container.singleton(db); // Add to DI 89 | 90 | // Routes 91 | app.get('/foo', (req, res) => res.render('hello')); 92 | 93 | app.post('/query', (Db db) async { 94 | // Db is an injected dependency here :) 95 | return await db.collection('foo').find().toList(); 96 | }); 97 | 98 | // Services (which build REST API's and are broadcasted over WS) 99 | app.use('/bombs', new MongoService(db.collection('bombs'))); 100 | app.use('/users', new MongoService(db.collection('users'))); 101 | app.use('/explosions', new AnonymousService(create: (data, [params]) => data)); 102 | 103 | 104 | // Setup WebSockets, add GZIP, etc. 105 | await app.configure(new AngelWebSocket()); 106 | app.responseFinalizers.add(gzip()); 107 | 108 | return app; 109 | } 110 | ``` 111 | 112 | ## Get Social 113 | Join an activate chat about the Angel Framework, or seek assistance: https://gitter.im/angel_dart/discussion 114 | -------------------------------------------------------------------------------- /server/bin/cluster.dart: -------------------------------------------------------------------------------- 1 | library server.cluster; 2 | 3 | import 'dart:async'; 4 | import 'common.dart'; 5 | import 'dart:isolate'; 6 | 7 | main(args, SendPort sendPort) async { 8 | runZoned(startServer(args, sendPort: sendPort), onError: onError); 9 | } 10 | -------------------------------------------------------------------------------- /server/bin/common.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:isolate'; 3 | import 'package:server/server.dart'; 4 | import 'package:angel_diagnostics/angel_diagnostics.dart'; 5 | import 'package:angel_hot/angel_hot.dart'; 6 | import 'package:intl/intl.dart'; 7 | 8 | /// Start a single instance of this application. 9 | /// 10 | /// If a [sendPort] is provided, then the URL of the mounted server will be sent through the port. 11 | /// Use this if you are starting multiple instances of your server. 12 | startServer(args, {SendPort sendPort}) { 13 | return () async { 14 | var app = await createServer(); 15 | var dateFormat = new DateFormat("y-MM-dd"); 16 | var logFile = new File("logs/${dateFormat.format(new DateTime.now())}.txt"); 17 | InternetAddress host; 18 | int port; 19 | 20 | // Load the right host and port from application config. 21 | host = new InternetAddress(app.properties['host']); 22 | 23 | // Listen on port 0 if we are using the load balancer. 24 | port = sendPort != null ? 0 : app.properties['port']; 25 | 26 | // Log requests and errors to a log file. 27 | await app.configure(logRequests(logFile)); 28 | HttpServer server; 29 | 30 | // Use `package:angel_hot` in any case, EXCEPT if starting in production mode. 31 | // 32 | // With hot-reloading, our server will automatically reload in-place on file changes, 33 | // for a faster development cycle. :) 34 | if (Platform.environment['ANGEL_ENV'] == 'production') 35 | server = await app.startServer(host, port); 36 | else { 37 | var hot = new HotReloader(() async { 38 | // If we are hot-reloading, we need to provide a callback 39 | // to use to start a fresh instance on-the-fly. 40 | var app = await createServer(); 41 | await app.configure(logRequests(logFile)); 42 | return app; 43 | }, 44 | // Paths we might want to listen for changes on... 45 | [ 46 | new Directory('config'), 47 | new Directory('lib'), 48 | new Directory('views') 49 | ]); 50 | server = await hot.startServer(host, port); 51 | } 52 | 53 | if (sendPort == null) { 54 | print('Listening at http://${server.address.address}:${server.port}'); 55 | } else 56 | sendPort?.send([server.address.address, server.port]); 57 | }; 58 | } 59 | 60 | onError(error, [StackTrace stackTrace]) { 61 | stderr.writeln("Unhandled error occurred: $error"); 62 | if (stackTrace != null) { 63 | stderr.writeln(stackTrace); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /server/bin/multi_server.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | library server.multi_server; 3 | 4 | import 'dart:io'; 5 | import 'package:angel_compress/angel_compress.dart'; 6 | import 'package:angel_multiserver/angel_multiserver.dart'; 7 | 8 | final Uri cluster = Platform.script.resolve('cluster.dart'); 9 | 10 | /// The number of isolates to spawn. You might consider starting one instance 11 | /// per processor core on your machine. 12 | final int nInstances = Platform.numberOfProcessors; 13 | 14 | main() async { 15 | var app = new LoadBalancer(); 16 | // Or, for SSL: 17 | // var app = new LoadBalancer.secure('', ''); 18 | 19 | // Response compression! 20 | app.responseFinalizers.add(gzip()); 21 | 22 | // Cache static assets - just to lower response time 23 | await app.configure(cacheResponses(filters: [new RegExp(r'images/.*')])); 24 | 25 | // Start up multiple instances of our main application. 26 | await app.spawnIsolates(cluster, count: nInstances); 27 | 28 | app.onCrash.listen((_) async { 29 | // Boot up a new instance on crash 30 | await app.spawnIsolates(cluster); 31 | }); 32 | 33 | var host = InternetAddress.ANY_IP_V4; 34 | var port = 3000; 35 | var server = await app.startServer(host, port); 36 | print('Listening at http://${server.address.address}:${server.port}'); 37 | print('Load-balancing $nInstances instance(s)'); 38 | } 39 | -------------------------------------------------------------------------------- /server/bin/scaled_server.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | 3 | library server.scaled_server; 4 | 5 | import 'dart:io'; 6 | import 'dart:isolate'; 7 | import 'package:angel_compress/angel_compress.dart'; 8 | import 'package:angel_diagnostics/angel_diagnostics.dart'; 9 | import 'package:angel_multiserver/angel_multiserver.dart'; 10 | import 'package:server/server.dart'; 11 | 12 | /// The number of isolates to spawn. You might consider starting one instance 13 | /// per processor core on your machine. 14 | final int nInstances = Platform.numberOfProcessors; 15 | 16 | main() { 17 | var startupPort = new ReceivePort(); 18 | List startupMessages = []; 19 | 20 | // Start up multiple instances of our application. 21 | for (int i = 0; i < nInstances; i++) { 22 | Isolate.spawn(isolateMain, [i, startupPort.sendPort]); 23 | } 24 | 25 | int nStarted = 0; 26 | 27 | // Listen for notifications of application startup... 28 | startupPort.listen((String startupMessage) { 29 | startupMessages.add(startupMessage); 30 | 31 | if (++nStarted == nInstances) { 32 | // Keep track of how many instances successfully started up, 33 | // and print a success message when they all boot. 34 | startupMessages.forEach(print); 35 | print('Spawned $nInstances instance(s) of Angel.'); 36 | } 37 | }); 38 | } 39 | 40 | void isolateMain(List args) { 41 | int instanceId = args[0]; 42 | SendPort startupPort = args[1]; 43 | 44 | createServer().then((app) async { 45 | // Response compression via GZIP. 46 | // 47 | // See the documentation here: 48 | // https://github.com/angel-dart/compress 49 | app.responseFinalizers.add(gzip()); 50 | 51 | // Cache static assets - just to lower response time. 52 | // 53 | // See the documentation here: 54 | // https://github.com/angel-dart/multiserver 55 | // 56 | // Here is an example of response caching: 57 | // https://github.com/angel-dart/multiserver/blob/master/example/cache.dart 58 | await app.configure(cacheResponses(filters: [new RegExp(r'images/.*')])); 59 | 60 | var server = await app.startServer( 61 | InternetAddress.ANY_IP_V4, app.properties['port'] ?? 3000); 62 | 63 | // Print request and error information to the console. 64 | await app.configure(logRequests()); 65 | 66 | // Send a notification back to the main isolate 67 | startupPort.send('Instance #$instanceId listening at http://${server.address.address}:${server.port}'); 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /server/bin/server.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | import 'dart:async'; 3 | import 'common.dart'; 4 | 5 | main(args) async { 6 | runZoned(startServer(args), onError: onError); 7 | } 8 | -------------------------------------------------------------------------------- /server/config/default.yaml: -------------------------------------------------------------------------------- 1 | # Default server configuration. 2 | host: 0.0.0.0 3 | mongo_db: mongodb://localhost:27017/server 4 | port: 3000 5 | jwt_secret: "VU517um0wJMWcA7H8Uatje80WnfDkR0W" -------------------------------------------------------------------------------- /server/config/development.yaml: -------------------------------------------------------------------------------- 1 | # Development-only server configuration. 2 | debug: true -------------------------------------------------------------------------------- /server/config/production.yaml: -------------------------------------------------------------------------------- 1 | # Production-only server configuration 2 | debug: false 3 | # jwt_secret: "72302125357831322256836652434772" -------------------------------------------------------------------------------- /server/lib/server.dart: -------------------------------------------------------------------------------- 1 | library server; 2 | 3 | import 'dart:async'; 4 | import 'package:angel_common/angel_common.dart'; 5 | import 'package:angel_websocket/server.dart'; 6 | import 'src/config/config.dart' as configuration; 7 | import 'src/routes/routes.dart' as routes; 8 | import 'src/services/services.dart' as services; 9 | 10 | /// Creates and configures the server instance. 11 | Future createServer() async { 12 | /// Passing `startShared` to the constructor allows us to start multiple 13 | /// instances of our application concurrently, listening on a single port. 14 | /// 15 | /// This effectively lets us multi-thread the application. 16 | var app = new Angel.custom(startShared); 17 | 18 | /// Set up our application, using three plug-ins defined with this project. 19 | await app.configure(configuration.configureServer); 20 | await app.configure(services.configureServer); 21 | await app.configure(routes.configureServer); 22 | await app.configure(new AngelWebSocket()); 23 | 24 | return app; 25 | } 26 | -------------------------------------------------------------------------------- /server/lib/src/config/config.dart: -------------------------------------------------------------------------------- 1 | library server.config; 2 | 3 | import 'dart:convert'; 4 | import 'dart:io'; 5 | import 'package:angel_common/angel_common.dart'; 6 | import 'plugins/plugins.dart' as plugins; 7 | 8 | /// This is a perfect place to include configuration and load plug-ins. 9 | configureServer(Angel app) async { 10 | // Speed boost. 11 | app.lazyParseBodies = true; 12 | //app.injectSerializer(JSON.encode); 13 | 14 | // Load configuration from the `config/` directory. 15 | // 16 | // See: https://github.com/angel-dart/configuration 17 | await app.configure(loadConfigurationFile()); 18 | 19 | // Configure our application to render Mustache templates from the `views/` directory. 20 | // 21 | // See: https://github.com/angel-dart/mustache 22 | await app.configure(mustache(new Directory('views'))); 23 | 24 | // Apply another plug-ins, i.e. ones that *you* have written. 25 | // 26 | // Typically, the plugins in `lib/src/config/plugins/plugins.dart` are plug-ins 27 | // that add functionality specific to your application. 28 | // 29 | // If you write a plug-in that you plan to use again, or are 30 | // using one created by the community, include it in 31 | // `lib/src/config/config.dart`. 32 | await plugins.configureServer(app); 33 | } 34 | -------------------------------------------------------------------------------- /server/lib/src/config/plugins/plugins.dart: -------------------------------------------------------------------------------- 1 | library server.config.plugins; 2 | 3 | import 'dart:async'; 4 | import 'package:angel_common/angel_common.dart'; 5 | import 'package:angel_seeder/angel_seeder.dart'; 6 | 7 | Future configureServer(Angel app) async { 8 | // Include any plugins you have made here. 9 | await app.configure(seedApp); 10 | } 11 | 12 | Future seedApp(Angel app) async { 13 | await app.configure(seedUsers); 14 | } 15 | 16 | Future seedUsers(Angel app) async { 17 | // Auto-generate users... 18 | app.justBeforeStart.add((app) async { 19 | await app.configure(seed( 20 | 'api/users', 21 | new SeederConfiguration(count: 10, template: { 22 | 'username': () => faker.internet.userName(), 23 | 'password': () => faker.internet.password() 24 | }))); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /server/lib/src/routes/controllers/auth.dart: -------------------------------------------------------------------------------- 1 | library server.routes.controllers.auth; 2 | 3 | import 'package:angel_common/angel_common.dart'; 4 | import 'package:common/common.dart'; 5 | import '../../services/user.dart'; 6 | 7 | /// Configures the application to authenticate users securely. 8 | /// See the documentation for controllers: 9 | /// 10 | /// https://github.com/angel-dart/angel/wiki/Controllers 11 | @Expose('/auth') 12 | class AuthController extends Controller { 13 | /// Controls application authentication. 14 | /// 15 | /// See the documentation: 16 | /// * https://medium.com/the-angel-framework/logging-users-in-to-angel-applications-ccf32aba0dac 17 | /// * https://github.com/angel-dart/auth 18 | AngelAuth auth; 19 | 20 | /// Clients will see the result of `deserializer`, so let's pretend to be a client. 21 | /// 22 | /// Our User service is already wired to remove sensitive data from serialized JSON. 23 | deserializer(String id) async => 24 | app.service('api/users').read(id, {'provider': Providers.REST}); 25 | 26 | serializer(User user) async => user.id; 27 | 28 | /// Attempts to log a user in. 29 | LocalAuthVerifier localVerifier(Service userService) { 30 | return (String username, String password) async { 31 | Iterable users = (await userService.index({ 32 | 'query': {'username': username} 33 | })) 34 | .map(User.parse); 35 | 36 | if (users.isNotEmpty) { 37 | return users.firstWhere((user) { 38 | var hash = hashPassword(password, user.salt, app.jwt_secret); 39 | return user.username == username && user.password == hash; 40 | }, orElse: () => null); 41 | } else { 42 | // Let's just make a new user, because I am lazy. 43 | return await app.service('api/users').create( 44 | {'username': username, 'password': password}).then(User.parse); 45 | } 46 | }; 47 | } 48 | 49 | @override 50 | call(Angel app) async { 51 | // Wire up local authentication, connected to our User service 52 | auth = new AngelAuth(jwtKey: app.jwt_secret) 53 | ..serializer = serializer 54 | ..deserializer = deserializer 55 | ..strategies 56 | .add(new LocalAuthStrategy(localVerifier(app.service('api/users')))); 57 | 58 | await super.call(app); 59 | await app.configure(auth); 60 | } 61 | 62 | @Expose('/local', method: 'POST') 63 | login() => auth.authenticate('local'); 64 | } 65 | -------------------------------------------------------------------------------- /server/lib/src/routes/controllers/controllers.dart: -------------------------------------------------------------------------------- 1 | library server.routes.controllers; 2 | 3 | import 'package:angel_common/angel_common.dart'; 4 | import 'auth.dart'; 5 | 6 | configureServer(Angel app) async { 7 | /// Controllers will not function unless wired to the application! 8 | await app.configure(new AuthController()); 9 | } 10 | -------------------------------------------------------------------------------- /server/lib/src/routes/routes.dart: -------------------------------------------------------------------------------- 1 | library server.routes; 2 | 3 | import 'dart:io'; 4 | import 'package:angel_common/angel_common.dart'; 5 | import 'controllers/controllers.dart' as controllers; 6 | 7 | /// Adds global middleware to the application. 8 | /// 9 | /// Use these to apply functionality to requests before business logic is run. 10 | /// 11 | /// More on the request lifecycle: 12 | /// https://github.com/angel-dart/angel/wiki/Request-Lifecycle 13 | configureBefore(Angel app) async { 14 | app.before.add(cors()); 15 | } 16 | 17 | /// Put your app routes here! 18 | /// 19 | /// See the wiki for information about routing, requests, and responses: 20 | /// * https://github.com/angel-dart/angel/wiki/Basic-Routing 21 | /// * https://github.com/angel-dart/angel/wiki/Requests-&-Responses 22 | configureRoutes(Angel app) async { 23 | // Render `views/hello.mustache` when a user visits the application root. 24 | app.get('/', (req, ResponseContext res) => res.render('hello')); 25 | } 26 | 27 | /// Configures fallback middleware. 28 | /// 29 | /// Use these to run generic actions on requests that were not terminated by 30 | /// earlier request handlers. 31 | /// 32 | /// Note that these middleware might not always run. 33 | /// 34 | /// More on the request lifecycle: https://github.com/angel-dart/angel/wiki/Request-Lifecycle 35 | configureAfter(Angel app) async { 36 | // Uncomment this to proxy over `pub serve` while in development. 37 | // This is a useful feature for full-stack applications, especially if you 38 | // are using Angular2. 39 | // 40 | // For documentation, see `package:angel_proxy`: 41 | // https://github.com/angel-dart/proxy 42 | // 43 | // await app.configure(new PubServeLayer()); 44 | 45 | // Mount static server at /web or /build/web, depending on if 46 | // you are running in production mode. `Cache-Control` headers will also be enabled. 47 | // 48 | // Read the following two sources for documentation: 49 | // * https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae 50 | // * https://github.com/angel-dart/static 51 | await app.configure(new CachingVirtualDirectory()); 52 | 53 | // Set our application up to handle different errors. 54 | // 55 | // Read the following two sources for documentation: 56 | // * https://github.com/angel-dart/angel/wiki/Error-Handling 57 | // * https://github.com/angel-dart/errors 58 | var errors = new ErrorHandler(handlers: { 59 | // Display a 404 page if no resource is found. 60 | 404: (req, res) async => 61 | res.render('error', {'message': 'No file exists at ${req.path}.'}), 62 | 63 | // On generic errors, give information about why the application failed. 64 | // 65 | // An `AngelHttpException` instance will be present in `req.properties` 66 | // as `error`. 67 | 500: (req, res) async => res.render('error', {'message': req.error.message}) 68 | }); 69 | 70 | // Use a fatal error handler to attempt to resolve any issues that 71 | // result in Angel not being able to send the user a response. 72 | errors.fatalErrorHandler = (AngelFatalError e) async { 73 | try { 74 | // Manually create a request and response context. 75 | var req = await RequestContext.from(e.request, app); 76 | var res = new ResponseContext(e.request.response, app); 77 | 78 | // *Attempt* to render an error page. 79 | res.render('error', {'message': 'Internal Server Error: ${e.error}'}); 80 | await app.sendResponse(e.request, req, res); 81 | } catch (_) { 82 | // If execution fails here, there is nothing we can do. 83 | stderr..writeln('Fatal error: ${e.error}')..writeln(e.stack); 84 | } 85 | }; 86 | 87 | // Throw a 404 if no route matched the request. 88 | app.after.add(() => throw new AngelHttpException.notFound()); 89 | 90 | // Handle errors when they occur, based on outgoing status code. 91 | // By default, requests will go through the 500 handler, unless 92 | // they have an outgoing 200, or their status code has a handler 93 | // registered. 94 | app.after.add(errors.middleware()); 95 | 96 | // Pass AngelHttpExceptions through handler as well. 97 | // 98 | // Again, here is the error handling documentation: 99 | // * https://github.com/angel-dart/angel/wiki/Error-Handling 100 | // * https://github.com/angel-dart/errors 101 | await app.configure(errors); 102 | } 103 | 104 | /// Adds response finalizers to the application. 105 | /// 106 | /// These run after every request. 107 | /// 108 | /// See more on the request lifecycle here: 109 | /// https://github.com/angel-dart/angel/wiki/Request-Lifecycle 110 | configureFinalizers(Angel app) async {} 111 | 112 | /// Adds routes to our application. 113 | /// 114 | /// See the wiki for information about routing, requests, and responses: 115 | /// * https://github.com/angel-dart/angel/wiki/Basic-Routing 116 | /// * https://github.com/angel-dart/angel/wiki/Requests-&-Responses 117 | configureServer(Angel app) async { 118 | // The order in which we run these plug-ins is relatively significant. 119 | // Try not to change it. 120 | 121 | // Add global middleware. 122 | await configureBefore(app); 123 | 124 | // Typically, you want to mount controllers first, after any global middleware. 125 | await app.configure(controllers.configureServer); 126 | 127 | // Next, you can add any supplemental routes. 128 | await configureRoutes(app); 129 | 130 | // Add handlers to run after requests are handled. 131 | // 132 | // See the request lifecycle docs to find out why these two 133 | // are separate: 134 | // https://github.com/angel-dart/angel/wiki/Request-Lifecycle 135 | await configureAfter(app); 136 | await configureFinalizers(app); 137 | } 138 | -------------------------------------------------------------------------------- /server/lib/src/services/message.dart: -------------------------------------------------------------------------------- 1 | import 'package:angel_common/angel_common.dart'; 2 | import 'package:angel_framework/hooks.dart' as hooks; 3 | import 'package:angel_relations/angel_relations.dart' as relations; 4 | import 'package:angel_security/hooks.dart' as auth; 5 | import 'package:angel_websocket/hooks.dart' as ws; 6 | 7 | AngelConfigurer configureServer() { 8 | return (Angel app) async { 9 | app.use('/api/messages', new MapService()); 10 | var service = app.service('api/messages') as HookedService; 11 | 12 | // Users should only be able to index the message collection, 13 | // read individual messages, and create new messages. 14 | // 15 | // Disable everything else (for clients); 16 | service.before([ 17 | HookedServiceEvent.MODIFIED, 18 | HookedServiceEvent.UPDATED, 19 | HookedServiceEvent.REMOVED 20 | ], hooks.chainListeners([hooks.disable(), ws.doNotBroadcast()])); 21 | 22 | // Each message should have a `user_id` pointing to the user who sent it. 23 | // 24 | // Use this hook to automatically set a `user_id` on create events. 25 | // This hook also throws a 403 if the user is not logged in. 26 | service.beforeCreated 27 | .listen(auth.associateCurrentUser(ownerField: 'user_id')); 28 | 29 | // Use a simple belongsTo hook to populate a 'user' field. 30 | // 31 | // This assumes that each Message has a `user_id`. It then 32 | // searches the `api/users` services for a user with a matching ID. 33 | // 34 | // If it finds a user, it sets `user` to the user it finds. The hook 35 | // is intelligent enough to set this `user` field on both Maps and Dart 36 | // objects without hassle. 37 | service.afterAll( 38 | relations.belongsTo('api/users', as: 'user', localKey: 'user_id')); 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /server/lib/src/services/services.dart: -------------------------------------------------------------------------------- 1 | library server.services; 2 | 3 | import 'package:angel_common/angel_common.dart'; 4 | import 'message.dart' as message; 5 | import 'user.dart' as user; 6 | 7 | /// Configure our application to use *services*. 8 | /// Services must be wired to the app via `app.use`. 9 | /// 10 | /// They provide many benefits, such as instant REST API generation, 11 | /// and respond to both REST and WebSockets. 12 | /// 13 | /// Read more here: 14 | /// https://github.com/angel-dart/angel/wiki/Service-Basics 15 | configureServer(Angel app) async { 16 | await app.configure(message.configureServer()); 17 | await app.configure(user.configureServer()); 18 | } 19 | -------------------------------------------------------------------------------- /server/lib/src/services/user.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | import 'package:angel_common/angel_common.dart'; 3 | import 'package:angel_framework/hooks.dart' as hooks; 4 | import 'package:angel_websocket/hooks.dart' as ws; 5 | import 'package:crypto/crypto.dart' show sha256; 6 | import 'package:random_string/random_string.dart' as rs; 7 | // import '../validators/user.dart'; 8 | 9 | const List avatars = const [ 10 | 'dart.png', 11 | 'favicon.png', 12 | 'flutter.jpg', 13 | 'google.png' 14 | ]; 15 | 16 | /// Sets up a service mounted at `api/users`. 17 | /// 18 | /// In the real world, you will want to hook this up to a database. 19 | /// However, for the sake of the boilerplate, an in-memory service is used, 20 | /// so that users are not tied into using just one database. :) 21 | configureServer() { 22 | return (Angel app) async { 23 | // Store data in-memory. 24 | app.use('/api/users', new MapService()); 25 | 26 | // Configure hooks for the user service. 27 | // Hooks can be used to add additional functionality, or change the behavior 28 | // of services, and run on any service, regardless of which database you are using. 29 | // 30 | // If you have not already, *definitely* read the service hook documentation: 31 | // https://github.com/angel-dart/angel/wiki/Hooks 32 | 33 | var service = app.service('api/users') as HookedService; 34 | 35 | // Clients can't create, modify, update, or remove users. 36 | // 37 | // Refrain from broadcasting these events via WebSockets. 38 | service.before([ 39 | HookedServiceEvent.CREATED, 40 | HookedServiceEvent.MODIFIED, 41 | HookedServiceEvent.UPDATED, 42 | HookedServiceEvent.REMOVED 43 | ], hooks.chainListeners([hooks.disable(), ws.doNotBroadcast()])); 44 | 45 | // Hash user passwords. 46 | service.beforeCreated.listen((e) { 47 | var salt = rs.randomAlphaNumeric(12); 48 | e.data 49 | ..['password'] = hashPassword(e.data['password'], salt, app.jwt_secret) 50 | ..['salt'] = salt; 51 | }); 52 | 53 | // Choose a random avatar when a new user is created. 54 | var rnd = new math.Random(); 55 | 56 | service.beforeCreated.listen((HookedServiceEvent e) { 57 | var avatar = avatars[rnd.nextInt(avatars.length)]; 58 | e.data['avatar'] = avatar; 59 | }); 60 | 61 | // Remove sensitive data from serialized JSON. 62 | service.afterAll(hooks.remove(['password', 'salt'])); 63 | }; 64 | } 65 | 66 | /// SHA-256 hash any string, particularly a password. 67 | String hashPassword(String password, String salt, String pepper) => 68 | sha256.convert(('$salt:$password:$pepper').codeUnits).toString(); 69 | -------------------------------------------------------------------------------- /server/lib/src/validators/message.dart: -------------------------------------------------------------------------------- 1 | library server.validtors.message; 2 | import 'package:angel_validate/angel_validate.dart'; 3 | 4 | final Validator MESSAGE = new Validator({ 5 | 'name': [isString, isNotEmpty], 6 | 'desc': [isString, isNotEmpty] 7 | }); 8 | 9 | final Validator CREATE_MESSAGE = MESSAGE.extend({}) 10 | ..requiredFields.addAll(['name', 'desc']); -------------------------------------------------------------------------------- /server/lib/src/validators/todo.dart: -------------------------------------------------------------------------------- 1 | library server.validtors.todo; 2 | import 'package:angel_validate/angel_validate.dart'; 3 | 4 | final Validator TODO = new Validator({ 5 | 'name': [isString, isNotEmpty], 6 | 'desc': [isString, isNotEmpty] 7 | }); 8 | 9 | final Validator CREATE_TODO = TODO.extend({}) 10 | ..requiredFields.addAll(['name', 'desc']); -------------------------------------------------------------------------------- /server/lib/src/validators/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:angel_validate/angel_validate.dart'; 2 | 3 | // Validators can be used on the server, in the browser, and even in Flutter. 4 | // 5 | // It is highly recommended that you read the documentation: 6 | // https://github.com/angel-dart/validate 7 | final Validator USER = new Validator({ 8 | 'email': [isString, isNotEmpty, isEmail], 9 | 'username': [isString, isNotEmpty], 10 | 'password': [isString, isNotEmpty] 11 | }); 12 | 13 | final Validator CREATE_USER = USER.extend({}) 14 | ..requiredFields.addAll(['email', 'username', 'password']) 15 | ..forbiddenFields.addAll(['salt', 'roles']); 16 | -------------------------------------------------------------------------------- /server/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See http://pub.dartlang.org/doc/glossary.html#lockfile 3 | packages: 4 | _discoveryapis_commons: 5 | description: 6 | name: _discoveryapis_commons 7 | url: "https://pub.dartlang.org" 8 | source: hosted 9 | version: "0.1.4" 10 | analyzer: 11 | description: 12 | name: analyzer 13 | url: "https://pub.dartlang.org" 14 | source: hosted 15 | version: "0.30.0+2" 16 | angel_auth: 17 | description: 18 | name: angel_auth 19 | url: "https://pub.dartlang.org" 20 | source: hosted 21 | version: "1.0.5" 22 | angel_auth_google: 23 | description: 24 | name: angel_auth_google 25 | url: "https://pub.dartlang.org" 26 | source: hosted 27 | version: "1.0.0+1" 28 | angel_client: 29 | description: 30 | name: angel_client 31 | url: "https://pub.dartlang.org" 32 | source: hosted 33 | version: "1.0.7" 34 | angel_common: 35 | description: 36 | name: angel_common 37 | url: "https://pub.dartlang.org" 38 | source: hosted 39 | version: "1.0.0" 40 | angel_compress: 41 | description: 42 | name: angel_compress 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.0.0+2" 46 | angel_configuration: 47 | description: 48 | name: angel_configuration 49 | url: "https://pub.dartlang.org" 50 | source: hosted 51 | version: "1.0.4" 52 | angel_cors: 53 | description: 54 | name: angel_cors 55 | url: "https://pub.dartlang.org" 56 | source: hosted 57 | version: "1.0.0+1" 58 | angel_diagnostics: 59 | description: 60 | name: angel_diagnostics 61 | url: "https://pub.dartlang.org" 62 | source: hosted 63 | version: "1.0.2" 64 | angel_errors: 65 | description: 66 | name: angel_errors 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.0.0" 70 | angel_file_security: 71 | description: 72 | name: angel_file_security 73 | url: "https://pub.dartlang.org" 74 | source: hosted 75 | version: "1.0.1" 76 | angel_framework: 77 | description: 78 | name: angel_framework 79 | url: "https://pub.dartlang.org" 80 | source: hosted 81 | version: "1.0.7+1" 82 | angel_hot: 83 | description: 84 | name: angel_hot 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "1.0.1" 88 | angel_model: 89 | description: 90 | name: angel_model 91 | url: "https://pub.dartlang.org" 92 | source: hosted 93 | version: "1.0.0" 94 | angel_mongo: 95 | description: 96 | name: angel_mongo 97 | url: "https://pub.dartlang.org" 98 | source: hosted 99 | version: "1.1.6" 100 | angel_multiserver: 101 | description: 102 | name: angel_multiserver 103 | url: "https://pub.dartlang.org" 104 | source: hosted 105 | version: "1.0.9" 106 | angel_mustache: 107 | description: 108 | name: angel_mustache 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "1.0.3" 112 | angel_proxy: 113 | description: 114 | name: angel_proxy 115 | url: "https://pub.dartlang.org" 116 | source: hosted 117 | version: "1.0.8" 118 | angel_relations: 119 | description: 120 | name: angel_relations 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.0.1" 124 | angel_route: 125 | description: 126 | name: angel_route 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.0.4" 130 | angel_security: 131 | description: 132 | name: angel_security 133 | url: "https://pub.dartlang.org" 134 | source: hosted 135 | version: "1.0.2" 136 | angel_seeder: 137 | description: 138 | name: angel_seeder 139 | url: "https://pub.dartlang.org" 140 | source: hosted 141 | version: "1.0.1" 142 | angel_serialize: 143 | description: 144 | name: angel_serialize 145 | url: "https://pub.dartlang.org" 146 | source: hosted 147 | version: "1.0.0-alpha+1" 148 | angel_static: 149 | description: 150 | name: angel_static 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "1.2.4" 154 | angel_test: 155 | description: 156 | name: angel_test 157 | url: "https://pub.dartlang.org" 158 | source: hosted 159 | version: "1.0.6" 160 | angel_validate: 161 | description: 162 | name: angel_validate 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "1.0.2+4" 166 | angel_websocket: 167 | description: 168 | name: angel_websocket 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "1.0.8" 172 | ansicolor: 173 | description: 174 | name: ansicolor 175 | url: "https://pub.dartlang.org" 176 | source: hosted 177 | version: "0.0.9" 178 | args: 179 | description: 180 | name: args 181 | url: "https://pub.dartlang.org" 182 | source: hosted 183 | version: "0.13.7" 184 | async: 185 | description: 186 | name: async 187 | url: "https://pub.dartlang.org" 188 | source: hosted 189 | version: "1.13.3" 190 | barback: 191 | description: 192 | name: barback 193 | url: "https://pub.dartlang.org" 194 | source: hosted 195 | version: "0.15.2+11" 196 | body_parser: 197 | description: 198 | name: body_parser 199 | url: "https://pub.dartlang.org" 200 | source: hosted 201 | version: "1.0.2" 202 | boolean_selector: 203 | description: 204 | name: boolean_selector 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "1.0.2" 208 | bson: 209 | description: 210 | name: bson 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "0.2.0" 214 | charcode: 215 | description: 216 | name: charcode 217 | url: "https://pub.dartlang.org" 218 | source: hosted 219 | version: "1.1.1" 220 | cli_util: 221 | description: 222 | name: cli_util 223 | url: "https://pub.dartlang.org" 224 | source: hosted 225 | version: "0.1.2" 226 | collection: 227 | description: 228 | name: collection 229 | url: "https://pub.dartlang.org" 230 | source: hosted 231 | version: "1.14.3" 232 | common: 233 | description: 234 | path: "..\\common" 235 | relative: true 236 | source: path 237 | version: "0.0.0" 238 | console: 239 | description: 240 | name: console 241 | url: "https://pub.dartlang.org" 242 | source: hosted 243 | version: "2.2.4" 244 | container: 245 | description: 246 | name: container 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "0.1.2" 250 | convert: 251 | description: 252 | name: convert 253 | url: "https://pub.dartlang.org" 254 | source: hosted 255 | version: "2.0.1" 256 | crypto: 257 | description: 258 | name: crypto 259 | url: "https://pub.dartlang.org" 260 | source: hosted 261 | version: "2.0.2" 262 | csslib: 263 | description: 264 | name: csslib 265 | url: "https://pub.dartlang.org" 266 | source: hosted 267 | version: "0.14.0" 268 | dotenv: 269 | description: 270 | name: dotenv 271 | url: "https://pub.dartlang.org" 272 | source: hosted 273 | version: "0.1.3+3" 274 | faker: 275 | description: 276 | name: faker 277 | url: "https://pub.dartlang.org" 278 | source: hosted 279 | version: "0.0.5" 280 | fixnum: 281 | description: 282 | name: fixnum 283 | url: "https://pub.dartlang.org" 284 | source: hosted 285 | version: "0.10.6" 286 | flatten: 287 | description: 288 | name: flatten 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "1.0.0" 292 | fnx_profiler: 293 | description: 294 | name: fnx_profiler 295 | url: "https://pub.dartlang.org" 296 | source: hosted 297 | version: "0.9.1" 298 | front_end: 299 | description: 300 | name: front_end 301 | url: "https://pub.dartlang.org" 302 | source: hosted 303 | version: "0.1.0-alpha.4" 304 | glob: 305 | description: 306 | name: glob 307 | url: "https://pub.dartlang.org" 308 | source: hosted 309 | version: "1.1.3" 310 | googleapis: 311 | description: 312 | name: googleapis 313 | url: "https://pub.dartlang.org" 314 | source: hosted 315 | version: "0.32.0" 316 | googleapis_auth: 317 | description: 318 | name: googleapis_auth 319 | url: "https://pub.dartlang.org" 320 | source: hosted 321 | version: "0.2.3+6" 322 | grinder: 323 | description: 324 | name: grinder 325 | url: "https://pub.dartlang.org" 326 | source: hosted 327 | version: "0.8.0+3" 328 | html: 329 | description: 330 | name: html 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "0.13.2" 334 | html_builder: 335 | description: 336 | name: html_builder 337 | url: "https://pub.dartlang.org" 338 | source: hosted 339 | version: "1.0.1" 340 | http: 341 | description: 342 | name: http 343 | url: "https://pub.dartlang.org" 344 | source: hosted 345 | version: "0.11.3+14" 346 | http_multi_server: 347 | description: 348 | name: http_multi_server 349 | url: "https://pub.dartlang.org" 350 | source: hosted 351 | version: "2.0.3" 352 | http_parser: 353 | description: 354 | name: http_parser 355 | url: "https://pub.dartlang.org" 356 | source: hosted 357 | version: "3.1.1" 358 | http_server: 359 | description: 360 | name: http_server 361 | url: "https://pub.dartlang.org" 362 | source: hosted 363 | version: "0.9.6" 364 | intl: 365 | description: 366 | name: intl 367 | url: "https://pub.dartlang.org" 368 | source: hosted 369 | version: "0.15.0" 370 | isolate: 371 | description: 372 | name: isolate 373 | url: "https://pub.dartlang.org" 374 | source: hosted 375 | version: "1.0.0" 376 | js: 377 | description: 378 | name: js 379 | url: "https://pub.dartlang.org" 380 | source: hosted 381 | version: "0.6.1" 382 | json_god: 383 | description: 384 | name: json_god 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "2.0.0-beta+1" 388 | json_rpc_2: 389 | description: 390 | name: json_rpc_2 391 | url: "https://pub.dartlang.org" 392 | source: hosted 393 | version: "2.0.4" 394 | kernel: 395 | description: 396 | name: kernel 397 | url: "https://pub.dartlang.org" 398 | source: hosted 399 | version: "0.3.0-alpha.1" 400 | logging: 401 | description: 402 | name: logging 403 | url: "https://pub.dartlang.org" 404 | source: hosted 405 | version: "0.11.3+1" 406 | matcher: 407 | description: 408 | name: matcher 409 | url: "https://pub.dartlang.org" 410 | source: hosted 411 | version: "0.12.1+1" 412 | memcached_client: 413 | description: 414 | name: memcached_client 415 | url: "https://pub.dartlang.org" 416 | source: hosted 417 | version: "0.5.3" 418 | merge_map: 419 | description: 420 | name: merge_map 421 | url: "https://pub.dartlang.org" 422 | source: hosted 423 | version: "1.0.0" 424 | meta: 425 | description: 426 | name: meta 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "1.1.1" 430 | mime: 431 | description: 432 | name: mime 433 | url: "https://pub.dartlang.org" 434 | source: hosted 435 | version: "0.9.3" 436 | mock_request: 437 | description: 438 | name: mock_request 439 | url: "https://pub.dartlang.org" 440 | source: hosted 441 | version: "1.0.2" 442 | mockable_filesystem: 443 | description: 444 | name: mockable_filesystem 445 | url: "https://pub.dartlang.org" 446 | source: hosted 447 | version: "0.0.3" 448 | mongo_dart: 449 | description: 450 | name: mongo_dart 451 | url: "https://pub.dartlang.org" 452 | source: hosted 453 | version: "0.2.10" 454 | mongo_dart_query: 455 | description: 456 | name: mongo_dart_query 457 | url: "https://pub.dartlang.org" 458 | source: hosted 459 | version: "0.2.2" 460 | more: 461 | description: 462 | name: more 463 | url: "https://pub.dartlang.org" 464 | source: hosted 465 | version: "1.6.0" 466 | mustache4dart: 467 | description: 468 | name: mustache4dart 469 | url: "https://pub.dartlang.org" 470 | source: hosted 471 | version: "1.1.0" 472 | node_preamble: 473 | description: 474 | name: node_preamble 475 | url: "https://pub.dartlang.org" 476 | source: hosted 477 | version: "1.4.0" 478 | package_config: 479 | description: 480 | name: package_config 481 | url: "https://pub.dartlang.org" 482 | source: hosted 483 | version: "1.0.2" 484 | package_resolver: 485 | description: 486 | name: package_resolver 487 | url: "https://pub.dartlang.org" 488 | source: hosted 489 | version: "1.0.2" 490 | path: 491 | description: 492 | name: path 493 | url: "https://pub.dartlang.org" 494 | source: hosted 495 | version: "1.4.2" 496 | plugin: 497 | description: 498 | name: plugin 499 | url: "https://pub.dartlang.org" 500 | source: hosted 501 | version: "0.2.0+1" 502 | pool: 503 | description: 504 | name: pool 505 | url: "https://pub.dartlang.org" 506 | source: hosted 507 | version: "1.3.1" 508 | pub_semver: 509 | description: 510 | name: pub_semver 511 | url: "https://pub.dartlang.org" 512 | source: hosted 513 | version: "1.3.2" 514 | quiver: 515 | description: 516 | name: quiver 517 | url: "https://pub.dartlang.org" 518 | source: hosted 519 | version: "0.22.0" 520 | random_string: 521 | description: 522 | name: random_string 523 | url: "https://pub.dartlang.org" 524 | source: hosted 525 | version: "0.0.1" 526 | redis_client: 527 | description: 528 | name: redis_client 529 | url: "https://pub.dartlang.org" 530 | source: hosted 531 | version: "0.1.16" 532 | shelf: 533 | description: 534 | name: shelf 535 | url: "https://pub.dartlang.org" 536 | source: hosted 537 | version: "0.6.8" 538 | shelf_packages_handler: 539 | description: 540 | name: shelf_packages_handler 541 | url: "https://pub.dartlang.org" 542 | source: hosted 543 | version: "1.0.0" 544 | shelf_static: 545 | description: 546 | name: shelf_static 547 | url: "https://pub.dartlang.org" 548 | source: hosted 549 | version: "0.2.5" 550 | shelf_web_socket: 551 | description: 552 | name: shelf_web_socket 553 | url: "https://pub.dartlang.org" 554 | source: hosted 555 | version: "0.2.1" 556 | source_map_stack_trace: 557 | description: 558 | name: source_map_stack_trace 559 | url: "https://pub.dartlang.org" 560 | source: hosted 561 | version: "1.1.4" 562 | source_maps: 563 | description: 564 | name: source_maps 565 | url: "https://pub.dartlang.org" 566 | source: hosted 567 | version: "0.10.4" 568 | source_span: 569 | description: 570 | name: source_span 571 | url: "https://pub.dartlang.org" 572 | source: hosted 573 | version: "1.4.0" 574 | stack_trace: 575 | description: 576 | name: stack_trace 577 | url: "https://pub.dartlang.org" 578 | source: hosted 579 | version: "1.8.0" 580 | stream_channel: 581 | description: 582 | name: stream_channel 583 | url: "https://pub.dartlang.org" 584 | source: hosted 585 | version: "1.6.1" 586 | string_scanner: 587 | description: 588 | name: string_scanner 589 | url: "https://pub.dartlang.org" 590 | source: hosted 591 | version: "1.0.2" 592 | supports_color: 593 | description: 594 | name: supports_color 595 | url: "https://pub.dartlang.org" 596 | source: hosted 597 | version: "0.1.1" 598 | term_glyph: 599 | description: 600 | name: term_glyph 601 | url: "https://pub.dartlang.org" 602 | source: hosted 603 | version: "1.0.0" 604 | test: 605 | description: 606 | name: test 607 | url: "https://pub.dartlang.org" 608 | source: hosted 609 | version: "0.12.24" 610 | typed_data: 611 | description: 612 | name: typed_data 613 | url: "https://pub.dartlang.org" 614 | source: hosted 615 | version: "1.1.3" 616 | unscripted: 617 | description: 618 | name: unscripted 619 | url: "https://pub.dartlang.org" 620 | source: hosted 621 | version: "0.6.2" 622 | utf: 623 | description: 624 | name: utf 625 | url: "https://pub.dartlang.org" 626 | source: hosted 627 | version: "0.9.0+3" 628 | uuid: 629 | description: 630 | name: uuid 631 | url: "https://pub.dartlang.org" 632 | source: hosted 633 | version: "0.5.3" 634 | vector_math: 635 | description: 636 | name: vector_math 637 | url: "https://pub.dartlang.org" 638 | source: hosted 639 | version: "1.4.7" 640 | vm_service_client: 641 | description: 642 | ref: reload_sources_poc 643 | resolved-ref: f607e69ef7c34e5503ff92719b7a96a390c6cdf2 644 | url: "git://github.com/BlackHC/vm_service_client.git" 645 | source: git 646 | version: "0.2.4" 647 | watcher: 648 | description: 649 | name: watcher 650 | url: "https://pub.dartlang.org" 651 | source: hosted 652 | version: "0.9.7+3" 653 | web_socket_channel: 654 | description: 655 | name: web_socket_channel 656 | url: "https://pub.dartlang.org" 657 | source: hosted 658 | version: "1.0.4" 659 | yaml: 660 | description: 661 | name: yaml 662 | url: "https://pub.dartlang.org" 663 | source: hosted 664 | version: "2.1.12" 665 | sdks: 666 | dart: ">=1.23.0 <2.0.0-dev.infinity" 667 | -------------------------------------------------------------------------------- /server/pubspec.yaml: -------------------------------------------------------------------------------- 1 | description: "An easily-extensible web server framework in Dart." 2 | homepage: "https://github.com/angel-dart/angel" 3 | name: "server" 4 | publish_to: "none" 5 | dependencies: 6 | angel_auth_google: ^1.0.0 7 | angel_common: "^1.0.0" 8 | angel_configuration: "^1.0.0" 9 | angel_hot: "^1.0.0-rc.1" 10 | angel_multiserver: "^1.0.0" 11 | angel_seeder: ^1.0.0 12 | angel_security: ^1.0.0 13 | angel_websocket: ^1.0.0 14 | common: 15 | path: ../common 16 | dev_dependencies: 17 | grinder: "^0.8.0" 18 | http: "^0.11.3" 19 | test: "^0.12.13" 20 | environment: 21 | sdk: ">=1.19.0" 22 | transformers: 23 | - "angel_configuration" 24 | -------------------------------------------------------------------------------- /server/server.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /server/test/services/message_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:server/server.dart'; 3 | import 'package:angel_common/angel_common.dart'; 4 | import 'package:angel_test/angel_test.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | main() async { 8 | Angel app; 9 | TestClient client; 10 | 11 | setUp(() async { 12 | app = await createServer(); 13 | client = await connectTo(app); 14 | }); 15 | 16 | tearDown(() async { 17 | await client.close(); 18 | app = null; 19 | }); 20 | 21 | test('index via REST', () async { 22 | var response = await client.get('/api/messages'); 23 | expect(response, hasStatus(HttpStatus.OK)); 24 | }); 25 | 26 | test('Index messages', () async { 27 | var messages = await client.service('api/messages').index(); 28 | print(messages); 29 | }); 30 | } -------------------------------------------------------------------------------- /server/test/services/todo_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:server/server.dart'; 3 | import 'package:angel_common/angel_common.dart'; 4 | import 'package:angel_test/angel_test.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | main() async { 8 | Angel app; 9 | TestClient client; 10 | 11 | setUp(() async { 12 | app = await createServer(); 13 | client = await connectTo(app); 14 | }); 15 | 16 | tearDown(() async { 17 | await client.close(); 18 | app = null; 19 | }); 20 | 21 | test('index via REST', () async { 22 | var response = await client.get('/api/todos'); 23 | expect(response, hasStatus(HttpStatus.OK)); 24 | }); 25 | 26 | test('Index todos', () async { 27 | var todos = await client.service('api/todos').index(); 28 | print(todos); 29 | }); 30 | } -------------------------------------------------------------------------------- /server/test/services/users_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:server/server.dart'; 3 | import 'package:angel_test/angel_test.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | // Angel also includes facilities to make testing easier. 7 | // 8 | // `package:angel_test` ships a client that can test 9 | // both plain HTTP and WebSockets. 10 | // 11 | // Tests do not require your server to actually be mounted on a port, 12 | // so they will run faster than they would in other frameworks, where you 13 | // would have to first bind a socket, and then account for network latency. 14 | // 15 | // See the documentation here: 16 | // https://github.com/angel-dart/test 17 | // 18 | // If you are unfamiliar with Dart's advanced testing library, you can read up 19 | // here: 20 | // https://github.com/dart-lang/test 21 | 22 | main() async { 23 | TestClient client; 24 | 25 | setUp(() async { 26 | var app = await createServer(); 27 | client = await connectTo(app); 28 | }); 29 | 30 | tearDown(() async { 31 | await client.close(); 32 | }); 33 | 34 | test('index users', () async { 35 | // Request a resource at the given path. 36 | var response = await client.get('/api/users'); 37 | 38 | // By default, we locked this away from the Internet... 39 | // Expect a 403 response. 40 | expect(response, hasStatus(HttpStatus.FORBIDDEN)); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /server/tool/grind.dart: -------------------------------------------------------------------------------- 1 | // Grinder is not part of Angel, but you may consider using it 2 | // to run tasks, a la Gulp. 3 | // 4 | // See its documentation here: 5 | // https://github.com/google/grinder.dart 6 | 7 | import 'package:grinder/grinder.dart'; 8 | 9 | main(args) => grind(args); 10 | 11 | @Task() 12 | test() => new TestRunner().testAsync(); 13 | 14 | @DefaultTask() 15 | @Depends(test) 16 | build() { 17 | Pub.build(); 18 | } 19 | 20 | @Task() 21 | clean() => defaultClean(); -------------------------------------------------------------------------------- /server/views/error.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 | 8 | 9 | 42 | 43 | 44 |
45 |
46 |
{{message}}
47 |
48 |
49 | 50 | -------------------------------------------------------------------------------- /server/views/hello.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angel 5 | 6 | 7 | 8 | 9 | 38 | 39 | 40 |
41 |
42 |
Angel
43 |
44 |
45 | 46 | -------------------------------------------------------------------------------- /server/web/images/dart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/server/web/images/dart.png -------------------------------------------------------------------------------- /server/web/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/server/web/images/favicon.png -------------------------------------------------------------------------------- /server/web/images/flutter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/server/web/images/flutter.jpg -------------------------------------------------------------------------------- /server/web/images/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angel-example/flutter/86cf10ae589df74a88d494f2efb901453bca9b29/server/web/images/google.png -------------------------------------------------------------------------------- /server/web/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /admin --------------------------------------------------------------------------------