├── REST_API
├── __init__.py
├── resources
│ ├── __init__.py
│ ├── account.py
│ ├── TweetResource.py
│ └── UserResource.py
├── migrations
│ ├── README
│ ├── script.py.mako
│ ├── alembic.ini
│ ├── versions
│ │ └── 0ad77229d72d_.py
│ └── env.py
├── .vscode
│ └── settings.json
├── users.txt
├── requirements.txt
├── config.py
├── migrate.py
├── app.py
├── run.py
└── Model.py
├── ios
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── 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-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── project.pbxproj
└── .gitignore
├── assets
├── x.png
├── tick.png
├── user.png
└── background.jpg
├── android
├── gradle.properties
├── .gitignore
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── 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
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ └── values
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── simple_api_app
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── build.gradle
├── .metadata
├── lib
├── networking
│ ├── Response.dart
│ ├── CustomException.dart
│ └── ApiProvider.dart
├── main.dart
├── repository
│ └── UserRepository.dart
├── blocs
│ ├── UserBloc.dart
│ └── addUserBloc.dart
├── models
│ ├── UserModel.dart
│ └── PostUserModel.dart
├── view
│ ├── home_screen.dart
│ ├── user_details_view.dart
│ ├── new_user_adding.dart
│ ├── show_user.dart
│ └── new_user_setup.dart
└── CustomAlert
│ └── CustomAlertDialog.dart
├── pubspec.yaml
├── .gitignore
├── test
└── widget_test.dart
├── README.md
└── pubspec.lock
/REST_API/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/REST_API/resources/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/REST_API/migrations/README:
--------------------------------------------------------------------------------
1 | Generic single-database configuration.
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/REST_API/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.pythonPath": "/usr/bin/python"
3 | }
--------------------------------------------------------------------------------
/assets/x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/assets/x.png
--------------------------------------------------------------------------------
/assets/tick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/assets/tick.png
--------------------------------------------------------------------------------
/assets/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/assets/user.png
--------------------------------------------------------------------------------
/REST_API/users.txt:
--------------------------------------------------------------------------------
1 |
2 | username: jasoncaughers123
3 | Password: Pa55word
4 | email: jason@hotmail.com
5 | Age: 21
--------------------------------------------------------------------------------
/assets/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/assets/background.jpg
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonc2901/Full-Stack-Flutter-Python-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/simple_api_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.simple_api_app
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/REST_API/resources/account.py:
--------------------------------------------------------------------------------
1 | from flask_restful import Resource
2 |
3 | class Account(Resource):
4 |
5 | #handles the get requests
6 | def get(self):
7 | return {"message": "This is the account, welcome!"}
8 |
9 |
--------------------------------------------------------------------------------
/REST_API/requirements.txt:
--------------------------------------------------------------------------------
1 | flask>=1.0.0
2 | flask_restful==0.3.6
3 | flask_script==2.0.6
4 | flask_migrate==2.1.1
5 | marshmallow>=2.15.1
6 | flask_sqlalchemy==2.3.2
7 | flask_marshmallow==0.8.0
8 | marshmallow-sqlalchemy==0.13.2
9 | psycopg2==2.7.5
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/REST_API/resources/TweetResource.py:
--------------------------------------------------------------------------------
1 | from flask import request
2 | from flask_restful import Resource
3 | from Model import db, User
4 | import random
5 | import string
6 |
7 | class TweetResource(Resource):
8 | def get(self):
9 | return {
10 | "message" : "Success"
11 | }
12 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/REST_API/config.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | # You need to add your DB_CONN_STRING into your own .bash_profile inside of the /REST_API directory
4 | basedir = os.path.abspath(os.path.dirname(__file__))
5 | SQLALCHEMY_ECHO = False
6 | SQLALCHEMY_TRACK_MODIFICATIONS = True
7 | SQLALCHEMY_DATABASE_URI = os.environ.get('DB_CONN_STRING')
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: e6b34c2b5c96bb95325269a29a84e83ed8909b5f
8 | channel: beta
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/REST_API/migrate.py:
--------------------------------------------------------------------------------
1 | from flask_script import Manager
2 | from flask_migrate import Migrate, MigrateCommand
3 | from Model import db
4 | from run import create_app
5 |
6 | app = create_app('config')
7 |
8 | migrate = Migrate(app, db)
9 | manager = Manager(app)
10 | manager.add_command('db', MigrateCommand)
11 |
12 |
13 | if __name__ == '__main__':
14 | manager.run()
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/REST_API/app.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint
2 | from flask_restful import Api
3 | from resources.UserResource import UserResource
4 | from resources.TweetResource import TweetResource
5 | from resources.account import Account
6 |
7 | api_bp = Blueprint('api', __name__)
8 | api = Api(api_bp)
9 |
10 | # Route
11 | api.add_resource(UserResource, '/user')
12 | api.add_resource(TweetResource, '/tweet')
13 |
--------------------------------------------------------------------------------
/REST_API/run.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | def create_app(config_filename):
4 | app = Flask(__name__)
5 | app.config.from_object(config_filename)
6 |
7 | from app import api_bp
8 | app.register_blueprint(api_bp, url_prefix='/api')
9 |
10 | from Model import db
11 | db.init_app(app)
12 |
13 | return app
14 |
15 |
16 |
17 | if __name__ == "__main__":
18 | app = create_app("config")
19 | app.run(debug=True)
20 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/networking/Response.dart:
--------------------------------------------------------------------------------
1 | class Response {
2 | Status status;
3 | T data;
4 | String message;
5 |
6 | Response.loading(this.message) : status = Status.LOADING;
7 | Response.completed(this.data) : status = Status.COMPLETED;
8 | Response.error(this.message) : status = Status.ERROR;
9 |
10 | @override
11 | String toString() {
12 | return "Status : $status \n Message : $message \n Data : $data";
13 | }
14 | }
15 |
16 | enum Status { LOADING, COMPLETED, ERROR }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:simple_api_app/view/home_screen.dart';
3 | import 'package:simple_api_app/view/user_details_view.dart';
4 |
5 | void main() => runApp(MyApp());
6 |
7 | class MyApp extends StatelessWidget {
8 | @override
9 | Widget build(BuildContext context) {
10 | return MaterialApp(
11 | title: 'Return Users',
12 | home: HomePage(),
13 | debugShowCheckedModeBanner: false); // define it once at root level.
14 | }
15 | }
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/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.withReader('UTF-8') { reader -> plugins.load(reader) }
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 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: simple_api_app
2 | description: A new Flutter project.
3 |
4 | publish_to: 'none'
5 |
6 | version: 1.0.0+1
7 |
8 | environment:
9 | sdk: ">=2.7.0 <3.0.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 |
15 | cupertino_icons: ^0.1.3
16 | http: ^0.12.0+1
17 |
18 | dev_dependencies:
19 | flutter_test:
20 | sdk: flutter
21 |
22 | flutter:
23 |
24 | assets:
25 | - assets/user.png
26 | - assets/background.jpg
27 | - assets/x.png
28 | - assets/tick.png
29 |
30 | uses-material-design: true
31 |
32 |
--------------------------------------------------------------------------------
/REST_API/migrations/script.py.mako:
--------------------------------------------------------------------------------
1 | """${message}
2 |
3 | Revision ID: ${up_revision}
4 | Revises: ${down_revision | comma,n}
5 | Create Date: ${create_date}
6 |
7 | """
8 | from alembic import op
9 | import sqlalchemy as sa
10 | ${imports if imports else ""}
11 |
12 | # revision identifiers, used by Alembic.
13 | revision = ${repr(up_revision)}
14 | down_revision = ${repr(down_revision)}
15 | branch_labels = ${repr(branch_labels)}
16 | depends_on = ${repr(depends_on)}
17 |
18 |
19 | def upgrade():
20 | ${upgrades if upgrades else "pass"}
21 |
22 |
23 | def downgrade():
24 | ${downgrades if downgrades else "pass"}
25 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/lib/repository/UserRepository.dart:
--------------------------------------------------------------------------------
1 | import 'package:simple_api_app/models/PostUserModel.dart';
2 | import 'package:simple_api_app/networking/ApiProvider.dart';
3 | import 'package:simple_api_app/models/UserModel.dart';
4 | import 'dart:async';
5 |
6 | class UserRepository {
7 | ApiProvider _provider = ApiProvider();
8 |
9 | Future fetchUserData(String username) async {
10 | final response = await _provider.get("api/user?username=" + username);
11 | return UserModel.fromJson(response);
12 | }
13 |
14 | Future postUserData(String username, String firstname, String lastname, String password,
15 | String email, String imageUrl) async {
16 | final response = await _provider.post("api/user", username, firstname, lastname, password, email, imageUrl);
17 | return PostUserModel.fromJson(response);
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/lib/networking/CustomException.dart:
--------------------------------------------------------------------------------
1 | class CustomException implements Exception {
2 | final _message;
3 | final _prefix;
4 |
5 | CustomException([this._message, this._prefix]);
6 |
7 | String toString() {
8 | return "$_prefix$_message";
9 | }
10 | }
11 |
12 | class FetchDataException extends CustomException {
13 | FetchDataException([String message])
14 | : super(message, "Error During Communication: ");
15 | }
16 |
17 | class BadRequestException extends CustomException {
18 | BadRequestException([message]) : super(message, "Invalid Request: ");
19 | }
20 |
21 | class UnauthorisedException extends CustomException {
22 | UnauthorisedException([message]) : super(message, "Unauthorised: ");
23 | }
24 |
25 | class InvalidInputException extends CustomException {
26 | InvalidInputException([String message]) : super(message, "Invalid Input: ");
27 | }
28 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | /build/
32 |
33 | # Web related
34 | lib/generated_plugin_registrant.dart
35 |
36 | # Symbolication related
37 | app.*.symbols
38 |
39 | # Obfuscation related
40 | app.*.map.json
41 |
42 | # Exceptions to above rules.
43 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
44 |
45 | #add the bash profile to .gitignore
46 | /REST_API/.bash_profile
47 | /REST_API/env/
48 |
--------------------------------------------------------------------------------
/REST_API/migrations/alembic.ini:
--------------------------------------------------------------------------------
1 | # A generic, single database configuration.
2 |
3 | [alembic]
4 | # template used to generate migration files
5 | # file_template = %%(rev)s_%%(slug)s
6 |
7 | # set to 'true' to run the environment during
8 | # the 'revision' command, regardless of autogenerate
9 | # revision_environment = false
10 |
11 |
12 | # Logging configuration
13 | [loggers]
14 | keys = root,sqlalchemy,alembic
15 |
16 | [handlers]
17 | keys = console
18 |
19 | [formatters]
20 | keys = generic
21 |
22 | [logger_root]
23 | level = WARN
24 | handlers = console
25 | qualname =
26 |
27 | [logger_sqlalchemy]
28 | level = WARN
29 | handlers =
30 | qualname = sqlalchemy.engine
31 |
32 | [logger_alembic]
33 | level = INFO
34 | handlers =
35 | qualname = alembic
36 |
37 | [handler_console]
38 | class = StreamHandler
39 | args = (sys.stderr,)
40 | level = NOTSET
41 | formatter = generic
42 |
43 | [formatter_generic]
44 | format = %(levelname)-5.5s [%(name)s] %(message)s
45 | datefmt = %H:%M:%S
46 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:simple_api_app/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/lib/blocs/UserBloc.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:async';
3 | import 'package:simple_api_app/networking/Response.dart';
4 | import 'package:simple_api_app/repository/UserRepository.dart';
5 | import 'package:simple_api_app/models/UserModel.dart';
6 |
7 | class UserBloc {
8 | UserRepository _userRepository;
9 | StreamController _userDataController;
10 |
11 | StreamSink> get userDataSink =>
12 | _userDataController.sink;
13 |
14 | Stream> get userDataStream =>
15 | _userDataController.stream;
16 |
17 | UserBloc(String username) {
18 | _userDataController = StreamController>();
19 | _userRepository = UserRepository();
20 | fetchUserDetails(username);
21 | }
22 |
23 | fetchUserDetails(String username) async {
24 | userDataSink.add(Response.loading('Fetching User Details!'));
25 | try {
26 | UserModel userDetails = await _userRepository.fetchUserData(username);
27 | userDataSink.add(Response.completed(userDetails));
28 | } catch (e) {
29 | userDataSink.add(Response.error(e.toString()));
30 | print(e);
31 | }
32 | }
33 |
34 | dispose() {
35 | _userDataController?.close();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/REST_API/migrations/versions/0ad77229d72d_.py:
--------------------------------------------------------------------------------
1 | """empty message
2 |
3 | Revision ID: 0ad77229d72d
4 | Revises:
5 | Create Date: 2020-07-25 21:04:00.236811
6 |
7 | """
8 | from alembic import op
9 | import sqlalchemy as sa
10 |
11 |
12 | # revision identifiers, used by Alembic.
13 | revision = '0ad77229d72d'
14 | down_revision = None
15 | branch_labels = None
16 | depends_on = None
17 |
18 |
19 | def upgrade():
20 | # ### commands auto generated by Alembic - please adjust! ###
21 | op.create_table('users',
22 | sa.Column('id', sa.Integer(), nullable=False),
23 | sa.Column('api_key', sa.String(), nullable=True),
24 | sa.Column('username', sa.String(), nullable=True),
25 | sa.Column('first_name', sa.String(), nullable=True),
26 | sa.Column('last_name', sa.String(), nullable=True),
27 | sa.Column('password', sa.String(), nullable=True),
28 | sa.Column('email_address', sa.String(), nullable=True),
29 | sa.Column('image_url', sa.String(), nullable=True),
30 | sa.PrimaryKeyConstraint('id'),
31 | sa.UniqueConstraint('api_key'),
32 | sa.UniqueConstraint('id')
33 | )
34 | # ### end Alembic commands ###
35 |
36 |
37 | def downgrade():
38 | # ### commands auto generated by Alembic - please adjust! ###
39 | op.drop_table('users')
40 | # ### end Alembic commands ###
41 |
--------------------------------------------------------------------------------
/lib/blocs/addUserBloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:simple_api_app/models/PostUserModel.dart';
3 | import 'package:simple_api_app/networking/Response.dart';
4 | import 'package:simple_api_app/repository/UserRepository.dart';
5 |
6 |
7 | class AddUserBloc {
8 | UserRepository _userRepository;
9 | StreamController _userDataController;
10 |
11 | StreamSink> get userDataSink =>
12 | _userDataController.sink;
13 |
14 | Stream> get userDataStream =>
15 | _userDataController.stream;
16 |
17 | AddUserBloc(String username, String firstname, String lastname, String password,
18 | String email, String imageUrl) {
19 | _userDataController = StreamController>();
20 | _userRepository = UserRepository();
21 | postUserDetails(username, firstname, lastname, password, email, imageUrl);
22 | }
23 |
24 | postUserDetails(String username, String firstname, String lastname, String password,
25 | String email, String imageUrl) async {
26 | userDataSink.add(Response.loading('Posting User Details!'));
27 | try {
28 | PostUserModel userDetails = await _userRepository.postUserData(username,firstname,lastname,password,email,imageUrl);
29 | userDataSink.add(Response.completed(userDetails));
30 | } catch (e) {
31 | userDataSink.add(Response.error(e.toString()));
32 | print(e);
33 | }
34 | }
35 |
36 | dispose() {
37 | _userDataController?.close();
38 | }
39 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # simple_api_app
2 |
3 | With this project I wanted to gain experience with programming a simple Full Stack mobile application using a combination of Flutter/Dart for the front end and Python for the REST API on the backend.
4 |
5 | ## Getting Started
6 | Before running this application you must first initialise the REST API on your own machine. Download this project and navigate to the REST_API directory. When in this folder run the following command in a terminal/cmd window.
7 |
8 | - code .bash_profile
9 |
10 | Once the .bash_profile file has opened, enter the following line (replacing the value with your database URI connection string)
11 |
12 | - export DB_CONN_STRING='ENTER_YOUR_DB_URI_HERE'
13 |
14 | Save the file and run the following command to ensure the changes have been registered
15 |
16 | - source .bash_profile
17 |
18 | Now that the connection to the database has been established you are now able to run the REST API Server and launch the app.
19 |
20 | # Run Server
21 | - open a terminal tab and navigate into the REST_API folder in this project
22 | - create a virtual env using 'virtualenv env'
23 | - enter the env by running 'source env/bin/activate'
24 | - install all requirements by running 'pip3 install -r requirements.txt'
25 | - finall run the server 'python run.py'
26 |
27 | # Launch the app
28 | - launch the app by opening a device simulator or connecting your mobile device
29 | - run 'flutter run'
30 |
31 | # ENJOY!!
32 | You can now begin using the tool and begin adding users to the database using the 'New User' section and view them under the 'View User' section.
33 |
34 |
35 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | simple_api_app
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/lib/models/UserModel.dart:
--------------------------------------------------------------------------------
1 | class UserModel {
2 | Data data;
3 | int status;
4 |
5 | UserModel({this.data, this.status});
6 |
7 | UserModel.fromJson(Map json) {
8 | data = json['data'] != null ? new Data.fromJson(json['data']) : null;
9 | status = json['status'];
10 | }
11 |
12 | Map toJson() {
13 | final Map data = new Map();
14 | if (this.data != null) {
15 | data['data'] = this.data.toJson();
16 | }
17 | data['status'] = this.status;
18 | return data;
19 | }
20 | }
21 |
22 | class Data {
23 | String apiKey;
24 | String emailAddress;
25 | String firstName;
26 | int id;
27 | String lastName;
28 | String password;
29 | String username;
30 | String imageUrl;
31 |
32 | Data(
33 | {this.apiKey,
34 | this.emailAddress,
35 | this.firstName,
36 | this.id,
37 | this.lastName,
38 | this.password,
39 | this.username,
40 | this.imageUrl});
41 |
42 | Data.fromJson(Map json) {
43 | apiKey = json['api_key'];
44 | emailAddress = json['email_address'];
45 | firstName = json['first_name'];
46 | id = json['id'];
47 | lastName = json['last_name'];
48 | password = json['password'];
49 | username = json['username'];
50 | imageUrl = json['image_url'];
51 | }
52 |
53 | Map toJson() {
54 | final Map data = new Map();
55 | data['api_key'] = this.apiKey;
56 | data['email_address'] = this.emailAddress;
57 | data['first_name'] = this.firstName;
58 | data['id'] = this.id;
59 | data['last_name'] = this.lastName;
60 | data['password'] = this.password;
61 | data['username'] = this.username;
62 | data['image_url'] = this.imageUrl;
63 | return data;
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/lib/models/PostUserModel.dart:
--------------------------------------------------------------------------------
1 | class PostUserModel {
2 | int status;
3 | User user;
4 |
5 | PostUserModel({this.status, this.user});
6 |
7 | PostUserModel.fromJson(Map json) {
8 | status = json['status'];
9 | user = json['user'] != null ? new User.fromJson(json['user']) : null;
10 | }
11 |
12 | Map toJson() {
13 | final Map data = new Map();
14 | data['status'] = this.status;
15 | if (this.user != null) {
16 | data['user'] = this.user.toJson();
17 | }
18 | return data;
19 | }
20 | }
21 |
22 | class User {
23 | String apiKey;
24 | String emailAddress;
25 | String firstName;
26 | int id;
27 | String imageUrl;
28 | String lastName;
29 | String password;
30 | String username;
31 |
32 | User(
33 | {this.apiKey,
34 | this.emailAddress,
35 | this.firstName,
36 | this.id,
37 | this.imageUrl,
38 | this.lastName,
39 | this.password,
40 | this.username});
41 |
42 | User.fromJson(Map json) {
43 | apiKey = json['api_key'];
44 | emailAddress = json['email_address'];
45 | firstName = json['first_name'];
46 | id = json['id'];
47 | imageUrl = json['image_url'];
48 | lastName = json['last_name'];
49 | password = json['password'];
50 | username = json['username'];
51 | }
52 |
53 | Map toJson() {
54 | final Map data = new Map();
55 | data['api_key'] = this.apiKey;
56 | data['email_address'] = this.emailAddress;
57 | data['first_name'] = this.firstName;
58 | data['id'] = this.id;
59 | data['image_url'] = this.imageUrl;
60 | data['last_name'] = this.lastName;
61 | data['password'] = this.password;
62 | data['username'] = this.username;
63 | return data;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/REST_API/Model.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from marshmallow import Schema, fields, pre_load, validate
3 | from flask_marshmallow import Marshmallow
4 | from flask_sqlalchemy import SQLAlchemy
5 |
6 | ma = Marshmallow()
7 | db = SQLAlchemy()
8 |
9 | class User(db.Model):
10 | __tablename__ = 'users'
11 |
12 | id = db.Column(db.Integer(), primary_key=True, unique=True)
13 | api_key = db.Column(db.String(),unique=True)
14 | username = db.Column(db.String())
15 | first_name = db.Column(db.String())
16 | last_name = db.Column(db.String())
17 | password = db.Column(db.String())
18 | email_address = db.Column(db.String())
19 | image_url = db.Column(db.String())
20 |
21 | def __init__(self,api_key,username,first_name,last_name,password,email_address, image_url):
22 | self.api_key = api_key
23 | self.username = username
24 | self.first_name = first_name
25 | self.last_name = last_name
26 | self.password = password
27 | self.email_address = email_address
28 | self.image_url = image_url
29 |
30 | def __repr__(self):
31 | return ''.format(self.id)
32 |
33 |
34 | def serialize(self):
35 | return {
36 | 'id' : self.id,
37 | 'api_key' : self.api_key,
38 | 'username' : self.username,
39 | 'first_name' : self.first_name,
40 | 'last_name' : self.last_name,
41 | 'password' : self.password,
42 | 'email_address' : self.email_address,
43 | 'image_url' : self.image_url
44 | }
45 |
46 |
47 | class UserSchema(ma.Schema):
48 | id = fields.Integer()
49 | api_key = fields.String(required=True)
50 | username = fields.String(required=True)
51 | first_name = fields.String(required=True)
52 | last_name = fields.String(required=True)
53 | password = fields.String(required=True)
54 | email_address = fields.String(required=True)
55 | image_url = fields.String(required=True)
56 |
57 |
58 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
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 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.example.simple_api_app"
42 | minSdkVersion 16
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | }
47 |
48 | buildTypes {
49 | release {
50 | // TODO: Add your own signing config for the release build.
51 | // Signing with the debug keys for now, so `flutter run --release` works.
52 | signingConfig signingConfigs.debug
53 | }
54 | }
55 | }
56 |
57 | flutter {
58 | source '../..'
59 | }
60 |
61 | dependencies {
62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
63 | }
64 |
--------------------------------------------------------------------------------
/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lib/networking/ApiProvider.dart:
--------------------------------------------------------------------------------
1 | import 'package:simple_api_app/networking/CustomException.dart';
2 | import 'package:http/http.dart' as http;
3 | import 'dart:io';
4 | import 'dart:convert';
5 | import 'dart:async';
6 |
7 | class ApiProvider {
8 | //EMULATOR ADDRESS
9 | final String _baseUrl = "http://10.0.2.2:5000/";
10 |
11 |
12 | Future get(String url) async {
13 | var responseJson;
14 | try {
15 | String responsestring = _baseUrl + url;
16 | print("Response URL: " + responsestring);
17 | final response = await http.get(_baseUrl + url);
18 | responseJson = _response(response);
19 | } on SocketException{
20 | throw FetchDataException('Server is down');
21 | }
22 | return responseJson;
23 | }
24 |
25 | Future post(String url,String username, String firstname, String lastname, String password,
26 | String email, String imageUrl) async {
27 | var responseJson;
28 | try {
29 | String responsestring = _baseUrl + url;
30 | print("Response URL: " + responsestring);
31 | final response = await http.post(
32 | _baseUrl + url,
33 | headers: {
34 | 'Content-Type': 'application/json',
35 | },
36 | body: jsonEncode({
37 | 'username': username,
38 | 'first_name': firstname,
39 | 'last_name': lastname,
40 | 'password': password,
41 | 'email_address': email,
42 | 'image_url': imageUrl
43 | }),
44 | );
45 | responseJson = _response(response);
46 | } on SocketException{
47 | throw FetchDataException('Server is down');
48 | }
49 | return responseJson;
50 | }
51 |
52 | dynamic _response(http.Response response) {
53 | switch (response.statusCode) {
54 | case 200:
55 | var responseJson = json.decode(response.body.toString());
56 | print(responseJson);
57 | return responseJson;
58 | case 201:
59 | var responseJson = json.decode(response.body.toString());
60 | print(responseJson);
61 | return responseJson;
62 | case 400:
63 | throw BadRequestException(response.body.toString());
64 | case 401:
65 |
66 | case 403:
67 | throw UnauthorisedException(response.body.toString());
68 | case 500:
69 |
70 | default:
71 | throw FetchDataException(
72 | 'Error occured while Communication with Server with StatusCode : ${response.statusCode}');
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/REST_API/resources/UserResource.py:
--------------------------------------------------------------------------------
1 | from flask import request, jsonify
2 | from flask_restful import Resource
3 | from Model import db, User, UserSchema
4 | import random
5 | import string
6 | import json
7 |
8 | users_schema = UserSchema(many=True)
9 |
10 | class UserResource(Resource):
11 | def get(self):
12 | users = User.query.all()
13 | users_data = users_schema.dump(users).data
14 | userid = request.args.get('id',type = int)
15 | username = request.args.get('username', type = str)
16 |
17 | if not username:
18 | return {'status': 'all_existing_users', 'data': users_data, "number_of_users": len(users_data)}, 200
19 |
20 | for i in range(0, len(users_data)):
21 | if users_data[i]["username"] == username:
22 | return {'status': 200, 'data': users_data[i]}, 200
23 |
24 | return {'status': 400, 'data': 'No User found'},400
25 |
26 |
27 | def post(self):
28 | json_data = request.get_json(force=True)
29 |
30 | #validates that the username doesn't already exist
31 | user = User.query.filter_by(username=json_data['username']).first()
32 | if user:
33 | return {'message': 'User already exists'}, 400
34 |
35 | #validates that the email hasnt already been signed up
36 | user = User.query.filter_by(email_address=json_data['email_address']).first()
37 | if user:
38 | return {'message': 'Email already signed up!'}, 400
39 |
40 | api_key = self.generateApiKey()
41 |
42 | #makes sure api key is not already added in the database
43 | user = User.query.filter_by(api_key=api_key).first()
44 | if user:
45 | return {'message': 'API Key already exists!'}, 400
46 |
47 | user = User(
48 | api_key=api_key,
49 | username=json_data['username'],
50 | first_name=json_data['first_name'],
51 | last_name=json_data['last_name'],
52 | password=json_data['password'],
53 | email_address=json_data['email_address'],
54 | image_url=json_data['image_url']
55 | )
56 |
57 | db.session.add(user)
58 | db.session.commit()
59 |
60 | result = User.serialize(user)
61 |
62 | return { "status": 200, "user": result}, 200
63 |
64 | def generateApiKey(self):
65 | key = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(24))
66 | return(key)
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
12 |
19 |
23 |
27 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/lib/view/home_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:simple_api_app/blocs/addUserBloc.dart';
3 | import 'package:simple_api_app/view/new_user_setup.dart';
4 | import 'package:simple_api_app/view/user_details_view.dart';
5 |
6 | class HomePage extends StatefulWidget {
7 | @override
8 | _GetHomeState createState() => _GetHomeState();
9 | }
10 |
11 | class _GetHomeState extends State {
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | appBar: AppBar(
16 | elevation: 0.0,
17 | automaticallyImplyLeading: false,
18 | title:
19 | Text('Home', style: TextStyle(color: Colors.white, fontSize: 27)),
20 | backgroundColor: Color(0xFF333333),
21 | ),
22 | backgroundColor: Color(0xFF333333),
23 | body: Container(
24 | child: Center(
25 | child: Column(
26 | children: [
27 | Padding(
28 | padding: EdgeInsets.only(top: 20),
29 | ),
30 | Text(
31 | "Welcome!",
32 | textAlign: TextAlign.center,
33 | style: TextStyle(fontSize: 50, color: Colors.white),
34 | ),
35 | Padding(
36 | padding: EdgeInsets.only(top: 50, bottom: 100),
37 | ),
38 | ButtonTheme(
39 | minWidth: 150,
40 | height: 70,
41 | child: RaisedButton(
42 | onPressed: () {
43 | print("New User Button Pressed!!!");
44 | Navigator.of(context).push(MaterialPageRoute(
45 | builder: (context) => CreateNewUserPage()));
46 | },
47 | color: Colors.grey[600],
48 | child: Text('New User',
49 | style: TextStyle(fontSize: 27, color: Colors.white)),
50 | ),
51 | ),
52 | Padding(
53 | padding: EdgeInsets.only(top: 70),
54 | ),
55 | ButtonTheme(
56 | minWidth: 150,
57 | height: 70,
58 | child: RaisedButton(
59 | onPressed: () {
60 | print("Existing User Button Pressed!!!");
61 | Navigator.push(
62 | context,
63 | MaterialPageRoute(builder: (context) => GetUserDetails()),
64 | );
65 | },
66 | color: Colors.grey[600],
67 | child: Text('View User',
68 | style: TextStyle(fontSize: 27, color: Colors.white)),
69 | ),
70 | ),
71 | ],
72 | ),
73 | ),
74 | ));
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/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 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/REST_API/migrations/env.py:
--------------------------------------------------------------------------------
1 | from __future__ import with_statement
2 | from alembic import context
3 | from sqlalchemy import engine_from_config, pool
4 | from logging.config import fileConfig
5 | import logging
6 |
7 | # this is the Alembic Config object, which provides
8 | # access to the values within the .ini file in use.
9 | config = context.config
10 |
11 | # Interpret the config file for Python logging.
12 | # This line sets up loggers basically.
13 | fileConfig(config.config_file_name)
14 | logger = logging.getLogger('alembic.env')
15 |
16 | # add your model's MetaData object here
17 | # for 'autogenerate' support
18 | # from myapp import mymodel
19 | # target_metadata = mymodel.Base.metadata
20 | from flask import current_app
21 | config.set_main_option('sqlalchemy.url',
22 | current_app.config.get('SQLALCHEMY_DATABASE_URI'))
23 | target_metadata = current_app.extensions['migrate'].db.metadata
24 |
25 | # other values from the config, defined by the needs of env.py,
26 | # can be acquired:
27 | # my_important_option = config.get_main_option("my_important_option")
28 | # ... etc.
29 |
30 |
31 | def run_migrations_offline():
32 | """Run migrations in 'offline' mode.
33 |
34 | This configures the context with just a URL
35 | and not an Engine, though an Engine is acceptable
36 | here as well. By skipping the Engine creation
37 | we don't even need a DBAPI to be available.
38 |
39 | Calls to context.execute() here emit the given string to the
40 | script output.
41 |
42 | """
43 | url = config.get_main_option("sqlalchemy.url")
44 | context.configure(url=url)
45 |
46 | with context.begin_transaction():
47 | context.run_migrations()
48 |
49 |
50 | def run_migrations_online():
51 | """Run migrations in 'online' mode.
52 |
53 | In this scenario we need to create an Engine
54 | and associate a connection with the context.
55 |
56 | """
57 |
58 | # this callback is used to prevent an auto-migration from being generated
59 | # when there are no changes to the schema
60 | # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
61 | def process_revision_directives(context, revision, directives):
62 | if getattr(config.cmd_opts, 'autogenerate', False):
63 | script = directives[0]
64 | if script.upgrade_ops.is_empty():
65 | directives[:] = []
66 | logger.info('No changes in schema detected.')
67 |
68 | engine = engine_from_config(config.get_section(config.config_ini_section),
69 | prefix='sqlalchemy.',
70 | poolclass=pool.NullPool)
71 |
72 | connection = engine.connect()
73 | context.configure(connection=connection,
74 | target_metadata=target_metadata,
75 | process_revision_directives=process_revision_directives,
76 | **current_app.extensions['migrate'].configure_args)
77 |
78 | try:
79 | with context.begin_transaction():
80 | context.run_migrations()
81 | finally:
82 | connection.close()
83 |
84 | if context.is_offline_mode():
85 | run_migrations_offline()
86 | else:
87 | run_migrations_online()
88 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/CustomAlert/CustomAlertDialog.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 | import 'package:flutter/material.dart';
3 |
4 | class CustomDialog extends StatelessWidget {
5 | final String title, description, buttonText;
6 | final String alertImage;
7 | final Color buttonColor;
8 |
9 | CustomDialog({
10 | @required this.title,
11 | @required this.description,
12 | @required this.buttonText,
13 | @required this.alertImage,
14 | @required this.buttonColor
15 | });
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Dialog(
20 | shape: RoundedRectangleBorder(
21 | borderRadius: BorderRadius.circular(Consts.padding),
22 | ),
23 | elevation: 0.0,
24 | backgroundColor: Colors.transparent,
25 | child: dialogContent(context),
26 | );
27 | }
28 |
29 | dialogContent(BuildContext context) {
30 | return Stack(
31 | children: [
32 | Container(
33 | padding: EdgeInsets.only(
34 | top: Consts.avatarRadius + Consts.padding,
35 | bottom: Consts.padding,
36 | left: Consts.padding,
37 | right: Consts.padding,
38 | ),
39 | margin: EdgeInsets.only(top: Consts.avatarRadius),
40 | decoration: new BoxDecoration(
41 | color: Colors.grey[800],
42 | shape: BoxShape.rectangle,
43 | borderRadius: BorderRadius.circular(Consts.padding),
44 | boxShadow: [
45 | BoxShadow(
46 | color: Colors.black26,
47 | blurRadius: 10.0,
48 | offset: const Offset(0.0, 10.0),
49 | ),
50 | ],
51 | ),
52 | child: Column(
53 | mainAxisSize: MainAxisSize.min, // To make the card compact
54 | children: [
55 | Text(
56 | title,
57 | style: TextStyle(
58 | fontSize: 25.0,
59 | fontWeight: FontWeight.w700,
60 | color: Colors.white
61 | ),
62 | ),
63 | SizedBox(height: 16.0),
64 | Text(
65 | description,
66 | textAlign: TextAlign.center,
67 | style: TextStyle(
68 | fontSize: 20.0,
69 | color: Colors.white
70 | ),
71 | ),
72 | SizedBox(height: 24.0),
73 | Align(
74 | alignment: Alignment.bottomCenter,
75 | child: FlatButton(
76 | color: buttonColor,
77 | onPressed: () {
78 | Navigator.of(context).pop(); // To close the dialog
79 | },
80 | child: Text(
81 | buttonText,
82 | style: TextStyle(
83 | fontSize: 20,
84 | color: Colors.white
85 | ),
86 | ),
87 | ),
88 | ),
89 | ],
90 | ),
91 | ),
92 | Positioned(
93 | left: Consts.padding,
94 | right: Consts.padding,
95 | top: Consts.paddingtop,
96 | child: ClipOval(
97 | child: Image.asset(
98 | alertImage,
99 | fit: BoxFit.contain,
100 | width: 10.0,
101 | height: 110.0,
102 | )),
103 | ),
104 | ],
105 | );
106 | }
107 | }
108 |
109 | class Consts {
110 | Consts._();
111 |
112 | static const double padding = 20.0;
113 | static const double paddingtop = 45.0;
114 | static const double avatarRadius = 70.0;
115 | }
116 |
--------------------------------------------------------------------------------
/lib/view/user_details_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:simple_api_app/blocs/UserBloc.dart';
3 | import 'package:simple_api_app/networking/Response.dart';
4 | import 'package:simple_api_app/models/UserModel.dart';
5 | import 'package:simple_api_app/view/home_screen.dart';
6 | import 'package:simple_api_app/view/show_user.dart';
7 | import 'package:simple_api_app/view/user_details_view.dart';
8 | import 'package:simple_api_app/CustomAlert/CustomAlertDialog.dart';
9 |
10 | class GetUserDetails extends StatefulWidget {
11 | @override
12 | _GetUserState createState() => _GetUserState();
13 | }
14 |
15 | class _GetUserState extends State {
16 | final usernameController = TextEditingController();
17 |
18 | @override
19 | void dispose() {
20 | // Clean up the controller when the widget is disposed.
21 | usernameController.dispose();
22 | super.dispose();
23 | }
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return Scaffold(
28 | appBar: AppBar(
29 | elevation: 0.0,
30 | automaticallyImplyLeading: false,
31 | title: Text('User Details',
32 | style: TextStyle(color: Colors.white, fontSize: 20)),
33 | backgroundColor: Color(0xFF333333),
34 | leading: new IconButton(
35 | icon: new Icon(Icons.arrow_back),
36 | onPressed: () {
37 | Navigator.push(
38 | context,
39 | MaterialPageRoute(builder: (context) => HomePage()),
40 | );
41 | })),
42 | backgroundColor: Color(0xFF333333),
43 | body: Container(
44 | child: Column(
45 | children: [
46 | Padding(
47 | padding: EdgeInsets.only(top: 60, left: 10),
48 | child: Text(
49 | "Enter Username",
50 | style: TextStyle(
51 | color: Colors.white,
52 | fontSize: 30,
53 | ),
54 | textAlign: TextAlign.left,
55 | ),
56 | ),
57 | Padding(
58 | padding: EdgeInsets.only(top: 20, left: 10, bottom: 20),
59 | child: new TextFormField(
60 | controller: usernameController,
61 | validator: (val) => val.length < 2 ? 'Still too short' : null,
62 | decoration: new InputDecoration(
63 | hintText: 'Username',
64 | hintStyle: TextStyle(color: Colors.white),
65 | fillColor: Colors.grey,
66 | filled: true,
67 | border: new OutlineInputBorder(
68 | borderRadius: new BorderRadius.circular(25.0),
69 | borderSide: new BorderSide(),
70 | ),
71 | ),
72 | keyboardType: TextInputType.text,
73 | style: new TextStyle(
74 | fontFamily: "Calibri",
75 | color: Colors.white,
76 | ),
77 | ),
78 | ),
79 | FloatingActionButton(
80 | onPressed: () {
81 | if (usernameController.text.length > 0) {
82 | Navigator.of(context).push(MaterialPageRoute(
83 | builder: (context) =>
84 | ShowUserPage(usernameController.text)));
85 | } else {
86 | showDialog(
87 | context: context,
88 | child: new CustomDialog(
89 | title: 'Cannot leave field empty!',
90 | description: "Please enter a valid username.",
91 | buttonText: "Okay",
92 | alertImage: "assets/x.png",
93 | buttonColor: Colors.red[700],
94 | ),
95 | );
96 | }
97 | },
98 | tooltip: 'Show user!',
99 | backgroundColor: Colors.grey,
100 | child: Icon(
101 | Icons.add,
102 | color: Colors.white,
103 | ))
104 | ],
105 | ),
106 | ),
107 | );
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.0.13"
11 | args:
12 | dependency: transitive
13 | description:
14 | name: args
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "1.6.0"
18 | async:
19 | dependency: transitive
20 | description:
21 | name: async
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.4.1"
25 | boolean_selector:
26 | dependency: transitive
27 | description:
28 | name: boolean_selector
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "2.0.0"
32 | charcode:
33 | dependency: transitive
34 | description:
35 | name: charcode
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "1.1.3"
39 | collection:
40 | dependency: transitive
41 | description:
42 | name: collection
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.14.12"
46 | convert:
47 | dependency: transitive
48 | description:
49 | name: convert
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "2.1.1"
53 | crypto:
54 | dependency: transitive
55 | description:
56 | name: crypto
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "2.1.4"
60 | cupertino_icons:
61 | dependency: "direct main"
62 | description:
63 | name: cupertino_icons
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "0.1.3"
67 | flutter:
68 | dependency: "direct main"
69 | description: flutter
70 | source: sdk
71 | version: "0.0.0"
72 | flutter_test:
73 | dependency: "direct dev"
74 | description: flutter
75 | source: sdk
76 | version: "0.0.0"
77 | http:
78 | dependency: "direct main"
79 | description:
80 | name: http
81 | url: "https://pub.dartlang.org"
82 | source: hosted
83 | version: "0.12.1"
84 | http_parser:
85 | dependency: transitive
86 | description:
87 | name: http_parser
88 | url: "https://pub.dartlang.org"
89 | source: hosted
90 | version: "3.1.4"
91 | image:
92 | dependency: transitive
93 | description:
94 | name: image
95 | url: "https://pub.dartlang.org"
96 | source: hosted
97 | version: "2.1.12"
98 | matcher:
99 | dependency: transitive
100 | description:
101 | name: matcher
102 | url: "https://pub.dartlang.org"
103 | source: hosted
104 | version: "0.12.6"
105 | meta:
106 | dependency: transitive
107 | description:
108 | name: meta
109 | url: "https://pub.dartlang.org"
110 | source: hosted
111 | version: "1.1.8"
112 | path:
113 | dependency: transitive
114 | description:
115 | name: path
116 | url: "https://pub.dartlang.org"
117 | source: hosted
118 | version: "1.6.4"
119 | pedantic:
120 | dependency: transitive
121 | description:
122 | name: pedantic
123 | url: "https://pub.dartlang.org"
124 | source: hosted
125 | version: "1.9.0"
126 | petitparser:
127 | dependency: transitive
128 | description:
129 | name: petitparser
130 | url: "https://pub.dartlang.org"
131 | source: hosted
132 | version: "2.4.0"
133 | quiver:
134 | dependency: transitive
135 | description:
136 | name: quiver
137 | url: "https://pub.dartlang.org"
138 | source: hosted
139 | version: "2.1.3"
140 | sky_engine:
141 | dependency: transitive
142 | description: flutter
143 | source: sdk
144 | version: "0.0.99"
145 | source_span:
146 | dependency: transitive
147 | description:
148 | name: source_span
149 | url: "https://pub.dartlang.org"
150 | source: hosted
151 | version: "1.7.0"
152 | stack_trace:
153 | dependency: transitive
154 | description:
155 | name: stack_trace
156 | url: "https://pub.dartlang.org"
157 | source: hosted
158 | version: "1.9.3"
159 | stream_channel:
160 | dependency: transitive
161 | description:
162 | name: stream_channel
163 | url: "https://pub.dartlang.org"
164 | source: hosted
165 | version: "2.0.0"
166 | string_scanner:
167 | dependency: transitive
168 | description:
169 | name: string_scanner
170 | url: "https://pub.dartlang.org"
171 | source: hosted
172 | version: "1.0.5"
173 | term_glyph:
174 | dependency: transitive
175 | description:
176 | name: term_glyph
177 | url: "https://pub.dartlang.org"
178 | source: hosted
179 | version: "1.1.0"
180 | test_api:
181 | dependency: transitive
182 | description:
183 | name: test_api
184 | url: "https://pub.dartlang.org"
185 | source: hosted
186 | version: "0.2.15"
187 | typed_data:
188 | dependency: transitive
189 | description:
190 | name: typed_data
191 | url: "https://pub.dartlang.org"
192 | source: hosted
193 | version: "1.1.6"
194 | vector_math:
195 | dependency: transitive
196 | description:
197 | name: vector_math
198 | url: "https://pub.dartlang.org"
199 | source: hosted
200 | version: "2.0.8"
201 | xml:
202 | dependency: transitive
203 | description:
204 | name: xml
205 | url: "https://pub.dartlang.org"
206 | source: hosted
207 | version: "3.6.1"
208 | sdks:
209 | dart: ">=2.7.0 <3.0.0"
210 |
--------------------------------------------------------------------------------
/lib/view/new_user_adding.dart:
--------------------------------------------------------------------------------
1 | import 'package:simple_api_app/CustomAlert/CustomAlertDialog.dart';
2 | import 'package:simple_api_app/blocs/addUserBloc.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:simple_api_app/models/PostUserModel.dart';
5 | import 'package:simple_api_app/networking/Response.dart';
6 |
7 | class SendUserToAPI extends StatefulWidget {
8 | final String username;
9 | final String firstname;
10 | final String lastname;
11 | final String email;
12 | final String password;
13 | final String imageurl;
14 |
15 | const SendUserToAPI(this.username, this.firstname, this.lastname, this.email,
16 | this.password, this.imageurl);
17 |
18 | @override
19 | _SendUserToAPIState createState() => _SendUserToAPIState();
20 | }
21 |
22 | class _SendUserToAPIState extends State {
23 | AddUserBloc _bloc;
24 |
25 | @override
26 | void initState() {
27 | super.initState();
28 | _bloc = AddUserBloc(widget.username, widget.firstname, widget.lastname,
29 | widget.email, widget.password, widget.imageurl);
30 | }
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | return Scaffold(
35 | appBar: AppBar(
36 | elevation: 5.0,
37 | title: Text('Adding User ...',
38 | style: TextStyle(color: Colors.white, fontSize: 20)),
39 | backgroundColor: Color(0xFF333333),
40 | ),
41 | backgroundColor: Color(0xFF333333),
42 | body: RefreshIndicator(
43 | onRefresh: () => _bloc.postUserDetails(
44 | widget.username,
45 | widget.firstname,
46 | widget.lastname,
47 | widget.password,
48 | widget.email,
49 | widget.imageurl),
50 | child: StreamBuilder>(
51 | stream: _bloc.userDataStream,
52 | builder: (context, snapshot) {
53 | if (snapshot.hasData) {
54 | switch (snapshot.data.status) {
55 | case Status.LOADING:
56 | return Loading(loadingMessage: snapshot.data.message);
57 | break;
58 | case Status.COMPLETED:
59 | return UserSuccess(displayUser: snapshot.data.data);
60 | break;
61 | case Status.ERROR:
62 | String error = snapshot.data.message;
63 |
64 | if (error.contains("No User found")) {
65 | error = "No User Found!";
66 | }
67 |
68 | if (error.contains("User already exists")) {
69 | error = "User already exists";
70 | }
71 |
72 | if (error.contains("Email already signed up!")) {
73 | error = "Email already signed up!";
74 | }
75 |
76 | print("Error Simplified: " + error.toString());
77 | return Error(
78 | errorMessage: error,
79 | onRetryPressed: () => _bloc.postUserDetails(
80 | widget.username,
81 | widget.firstname,
82 | widget.lastname,
83 | widget.password,
84 | widget.email,
85 | widget.imageurl),
86 | );
87 | break;
88 | }
89 | }
90 | return Container();
91 | },
92 | ),
93 | ),
94 | );
95 | }
96 |
97 | @override
98 | void dispose() {
99 | _bloc.dispose();
100 | super.dispose();
101 | }
102 | }
103 |
104 | class UserSuccess extends StatelessWidget {
105 | final PostUserModel displayUser;
106 |
107 | const UserSuccess({Key key, this.displayUser}) : super(key: key);
108 |
109 | @override
110 | Widget build(BuildContext context) {
111 | return new Scaffold(
112 | backgroundColor: Color(0xFF333333),
113 | body: Container(
114 | child: CustomDialog(
115 | title: 'SUCCESS!',
116 | description: "${displayUser.user.username} Added to DB.",
117 | buttonText: "Okay",
118 | alertImage: "assets/tick.png",
119 | buttonColor: Colors.green[400],
120 | ),
121 | ),
122 | );
123 | }
124 | }
125 |
126 | class Error extends StatelessWidget {
127 | final String errorMessage;
128 |
129 | final Function onRetryPressed;
130 |
131 | const Error({Key key, this.errorMessage, this.onRetryPressed})
132 | : super(key: key);
133 |
134 | @override
135 | Widget build(BuildContext context) {
136 | return Center(
137 | child: Column(
138 | mainAxisAlignment: MainAxisAlignment.center,
139 | children: [
140 | Text(
141 | errorMessage,
142 | textAlign: TextAlign.center,
143 | style: TextStyle(
144 | color: Colors.white,
145 | fontSize: 22,
146 | ),
147 | ),
148 | SizedBox(height: 8),
149 | RaisedButton(
150 | color: Colors.white,
151 | child: Text('Retry', style: TextStyle(color: Colors.black)),
152 | onPressed: onRetryPressed,
153 | )
154 | ],
155 | ),
156 | );
157 | }
158 | }
159 |
160 | class Loading extends StatelessWidget {
161 | final String loadingMessage;
162 |
163 | const Loading({Key key, this.loadingMessage}) : super(key: key);
164 |
165 | @override
166 | Widget build(BuildContext context) {
167 | return Center(
168 | child: Column(
169 | mainAxisAlignment: MainAxisAlignment.center,
170 | children: [
171 | Text(
172 | loadingMessage,
173 | textAlign: TextAlign.center,
174 | style: TextStyle(
175 | color: Colors.white,
176 | fontSize: 24,
177 | ),
178 | ),
179 | SizedBox(height: 24),
180 | CircularProgressIndicator(
181 | valueColor: AlwaysStoppedAnimation(Colors.white),
182 | ),
183 | ],
184 | ),
185 | );
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/lib/view/show_user.dart:
--------------------------------------------------------------------------------
1 | import 'package:simple_api_app/models/UserModel.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:simple_api_app/blocs/UserBloc.dart';
4 | import 'package:simple_api_app/networking/Response.dart';
5 |
6 |
7 | class ShowUserPage extends StatefulWidget {
8 | final String selectedUsername;
9 |
10 | const ShowUserPage(this.selectedUsername);
11 |
12 | @override
13 | _ShowUserPageState createState() => _ShowUserPageState();
14 | }
15 |
16 | class _ShowUserPageState extends State {
17 | UserBloc _bloc;
18 |
19 | @override
20 | void initState() {
21 | super.initState();
22 | _bloc = UserBloc(widget.selectedUsername);
23 | }
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return Scaffold(
28 | appBar: AppBar(
29 | elevation: 5.0,
30 | title: Text('User Page',
31 | style: TextStyle(color: Colors.white, fontSize: 20)),
32 | backgroundColor: Color(0xFF333333),
33 | ),
34 | backgroundColor: Color(0xFF333333),
35 | body: RefreshIndicator(
36 | onRefresh: () => _bloc.fetchUserDetails(widget.selectedUsername),
37 | child: StreamBuilder>(
38 | stream: _bloc.userDataStream,
39 | builder: (context, snapshot) {
40 | if (snapshot.hasData) {
41 | switch (snapshot.data.status) {
42 | case Status.LOADING:
43 | return Loading(loadingMessage: snapshot.data.message);
44 | break;
45 | case Status.COMPLETED:
46 | return UserDetails(displayUser: snapshot.data.data);
47 | break;
48 | case Status.ERROR:
49 | String error = snapshot.data.message;
50 |
51 | if (error.contains("No User found")){
52 | error = "No User Found!";
53 | }
54 |
55 | print("Error Simplified: " + error.toString());
56 | return Error(
57 | errorMessage: error,
58 | onRetryPressed: () =>
59 | _bloc.fetchUserDetails(widget.selectedUsername),
60 | );
61 | break;
62 | }
63 | }
64 | return Container();
65 | },
66 | ),
67 | ),
68 | );
69 | }
70 |
71 | @override
72 | void dispose() {
73 | _bloc.dispose();
74 | super.dispose();
75 | }
76 | }
77 |
78 | class UserDetails extends StatelessWidget {
79 | final UserModel displayUser;
80 |
81 | const UserDetails({Key key, this.displayUser}) : super(key: key);
82 |
83 | @override
84 | Widget build(BuildContext context) {
85 | return new Scaffold(
86 | body: new Container(
87 | constraints: new BoxConstraints.expand(),
88 | color: new Color(0xFF736AB7),
89 | child: new Stack(
90 | children: [
91 | _getBackground(),
92 | _getContent(),
93 | ],
94 | ),
95 | ),
96 | );
97 | }
98 |
99 | Container _getBackground() {
100 | return new Container(
101 | child: Container(
102 | decoration: BoxDecoration(
103 | color: Color(0xFF333333)
104 | ),
105 | ),
106 | );
107 | }
108 |
109 | Widget _getContent() {
110 | return new ListView(
111 | padding: new EdgeInsets.fromLTRB(0.0, 100, 0.0, 32.0),
112 | children: [
113 | new Container(
114 | margin: EdgeInsets.all(70.0),
115 | decoration: BoxDecoration(
116 | color: Colors.grey[600],
117 | shape: BoxShape.rectangle,
118 | borderRadius: BorderRadius.only(
119 | topLeft: Radius.circular(25.0),
120 | bottomRight: Radius.circular(25.0))),
121 | padding: new EdgeInsets.symmetric(horizontal: 32.0),
122 | child: new Column(
123 | crossAxisAlignment: CrossAxisAlignment.start,
124 | children: [
125 | Center(
126 | child: new Container(
127 | margin: EdgeInsets.fromLTRB(5, 15, 0.0, 0.0),
128 | child: CircleAvatar(
129 | radius: 80,
130 | backgroundImage: new NetworkImage(
131 | displayUser.data.imageUrl
132 | ),
133 | ),
134 | ),
135 | ),
136 | Center(
137 | child: new Padding(
138 | padding: const EdgeInsets.only(top:15.0, bottom: 15),
139 | child: Text(
140 | "First Name: " + displayUser.data.firstName + "\n\nLast Name: " + displayUser.data.lastName + "\n\nEmail Address: " + displayUser.data.emailAddress,
141 | style: TextStyle(
142 | color: Colors.white,
143 | fontSize: 20,
144 | fontWeight: FontWeight.w400,
145 | ),
146 | ),
147 | ),
148 | ),
149 | ],
150 | ),
151 | ),
152 | ],
153 | );
154 | }
155 | }
156 |
157 | class Error extends StatelessWidget {
158 | final String errorMessage;
159 |
160 | final Function onRetryPressed;
161 |
162 | const Error({Key key, this.errorMessage, this.onRetryPressed})
163 | : super(key: key);
164 |
165 | @override
166 | Widget build(BuildContext context) {
167 | return Center(
168 | child: Column(
169 | mainAxisAlignment: MainAxisAlignment.center,
170 | children: [
171 | Text(
172 | errorMessage,
173 | textAlign: TextAlign.center,
174 | style: TextStyle(
175 | color: Colors.white,
176 | fontSize: 22,
177 | ),
178 | ),
179 | SizedBox(height: 8),
180 | RaisedButton(
181 | color: Colors.white,
182 | child: Text('Retry', style: TextStyle(color: Colors.black)),
183 | onPressed: onRetryPressed,
184 | )
185 | ],
186 | ),
187 | );
188 | }
189 | }
190 |
191 | class Loading extends StatelessWidget {
192 | final String loadingMessage;
193 |
194 | const Loading({Key key, this.loadingMessage}) : super(key: key);
195 |
196 | @override
197 | Widget build(BuildContext context) {
198 | return Center(
199 | child: Column(
200 | mainAxisAlignment: MainAxisAlignment.center,
201 | children: [
202 | Text(
203 | loadingMessage,
204 | textAlign: TextAlign.center,
205 | style: TextStyle(
206 | color: Colors.white,
207 | fontSize: 24,
208 | ),
209 | ),
210 | SizedBox(height: 24),
211 | CircularProgressIndicator(
212 | valueColor: AlwaysStoppedAnimation(Colors.white),
213 | ),
214 | ],
215 | ),
216 | );
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/lib/view/new_user_setup.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:simple_api_app/CustomAlert/CustomAlertDialog.dart';
3 | import 'package:simple_api_app/blocs/addUserBloc.dart';
4 |
5 | import 'home_screen.dart';
6 | import 'new_user_adding.dart';
7 |
8 | class CreateNewUserPage extends StatefulWidget {
9 | @override
10 | _CreateNewUserState createState() => _CreateNewUserState();
11 | }
12 |
13 | class _CreateNewUserState extends State {
14 | AddUserBloc _bloc;
15 | final usernameController = TextEditingController();
16 | final firstnameController = TextEditingController();
17 | final lastnameController = TextEditingController();
18 | final passwordController = TextEditingController();
19 | final emailController = TextEditingController();
20 | final imageURLController = TextEditingController();
21 |
22 | @override
23 | void dispose() {
24 | // Clean up the controller when the widget is disposed.
25 | usernameController.dispose();
26 | firstnameController.dispose();
27 | lastnameController.dispose();
28 | passwordController.dispose();
29 | emailController.dispose();
30 | imageURLController.dispose();
31 |
32 | _bloc.dispose();
33 | super.dispose();
34 | }
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | return Scaffold(
39 | appBar: AppBar(
40 | elevation: 0.0,
41 | automaticallyImplyLeading: false,
42 | title: Text('New User',
43 | style: TextStyle(color: Colors.white, fontSize: 27)),
44 | backgroundColor: Color(0xFF333333),
45 | leading: new IconButton(
46 | icon: new Icon(Icons.arrow_back),
47 | onPressed: () {
48 | Navigator.push(
49 | context,
50 | MaterialPageRoute(builder: (context) => HomePage()),
51 | );
52 | })),
53 | backgroundColor: Color(0xFF333333),
54 | body: ListView(
55 | children: [
56 | Container(
57 | child: Center(
58 | child: Column(
59 | children: [
60 | Padding(
61 | padding: EdgeInsets.only(top: 10),
62 | ),
63 | Padding(
64 | padding: EdgeInsets.only(top: 30, left: 10, right: 10),
65 | child: Text(
66 | "Enter Username",
67 | style: TextStyle(
68 | color: Colors.white,
69 | fontSize: 25,
70 | ),
71 | textAlign: TextAlign.left,
72 | ),
73 | ),
74 | Padding(
75 | padding: EdgeInsets.only(top: 10, left: 100, right: 100),
76 | child: Container(
77 | height: 40,
78 | child: new TextFormField(
79 | controller: usernameController,
80 | validator: (val) =>
81 | val.length < 2 ? 'Still too short' : null,
82 | decoration: new InputDecoration(
83 | hintText: 'Username',
84 | hintStyle: TextStyle(color: Colors.white),
85 | fillColor: Colors.grey,
86 | filled: true,
87 | ),
88 | keyboardType: TextInputType.text,
89 | style: new TextStyle(
90 | fontFamily: "Calibri",
91 | color: Colors.white,
92 | ),
93 | ),
94 | ),
95 | ),
96 | Padding(
97 | padding: EdgeInsets.only(top: 30, left: 10, right: 10),
98 | child: Text(
99 | "Enter First name",
100 | style: TextStyle(
101 | color: Colors.white,
102 | fontSize: 25,
103 | ),
104 | textAlign: TextAlign.left,
105 | ),
106 | ),
107 | Padding(
108 | padding: EdgeInsets.only(top: 10, left: 100, right: 100),
109 | child: Container(
110 | height: 40,
111 | child: new TextFormField(
112 | controller: firstnameController,
113 | validator: (val) =>
114 | val.length < 2 ? 'Still too short' : null,
115 | decoration: new InputDecoration(
116 | hintText: 'First Name',
117 | hintStyle: TextStyle(color: Colors.white),
118 | fillColor: Colors.grey,
119 | filled: true,
120 | ),
121 | keyboardType: TextInputType.text,
122 | style: new TextStyle(
123 | fontFamily: "Calibri",
124 | color: Colors.white,
125 | ),
126 | ),
127 | ),
128 | ),
129 | Padding(
130 | padding: EdgeInsets.only(top: 30, left: 10, right: 10),
131 | child: Text(
132 | "Enter Last name",
133 | style: TextStyle(
134 | color: Colors.white,
135 | fontSize: 25,
136 | ),
137 | textAlign: TextAlign.left,
138 | ),
139 | ),
140 | Padding(
141 | padding: EdgeInsets.only(top: 10, left: 100, right: 100),
142 | child: Container(
143 | height: 40,
144 | child: new TextFormField(
145 | controller: lastnameController,
146 | validator: (val) =>
147 | val.length < 2 ? 'Still too short' : null,
148 | decoration: new InputDecoration(
149 | hintText: 'Last Name',
150 | hintStyle: TextStyle(color: Colors.white),
151 | fillColor: Colors.grey,
152 | filled: true,
153 | ),
154 | keyboardType: TextInputType.text,
155 | style: new TextStyle(
156 | fontFamily: "Calibri",
157 | color: Colors.white,
158 | ),
159 | ),
160 | ),
161 | ),
162 | Padding(
163 | padding: EdgeInsets.only(top: 30, left: 10, right: 10),
164 | child: Text(
165 | "Enter Email",
166 | style: TextStyle(
167 | color: Colors.white,
168 | fontSize: 25,
169 | ),
170 | textAlign: TextAlign.left,
171 | ),
172 | ),
173 | Padding(
174 | padding: EdgeInsets.only(top: 10, left: 100, right: 100),
175 | child: Container(
176 | height: 40,
177 | child: new TextFormField(
178 | controller: emailController,
179 | validator: (val) =>
180 | val.length < 2 ? 'Still too short' : null,
181 | decoration: new InputDecoration(
182 | hintText: 'Email Address',
183 | hintStyle: TextStyle(color: Colors.white),
184 | fillColor: Colors.grey,
185 | filled: true,
186 | ),
187 | keyboardType: TextInputType.text,
188 | style: new TextStyle(
189 | fontFamily: "Calibri",
190 | color: Colors.white,
191 | ),
192 | ),
193 | ),
194 | ),
195 | Padding(
196 | padding: EdgeInsets.only(top: 30, left: 10, right: 10),
197 | child: Text(
198 | "Enter Password",
199 | style: TextStyle(
200 | color: Colors.white,
201 | fontSize: 25,
202 | ),
203 | textAlign: TextAlign.left,
204 | ),
205 | ),
206 | Padding(
207 | padding: EdgeInsets.only(top: 10, left: 100, right: 100),
208 | child: Container(
209 | height: 40,
210 | child: new TextFormField(
211 | controller: passwordController,
212 | validator: (val) =>
213 | val.length < 2 ? 'Still too short' : null,
214 | decoration: new InputDecoration(
215 | hintText: 'Password',
216 | hintStyle: TextStyle(color: Colors.white),
217 | fillColor: Colors.grey,
218 | filled: true,
219 | ),
220 | keyboardType: TextInputType.text,
221 | style: new TextStyle(
222 | fontFamily: "Calibri",
223 | color: Colors.white,
224 | ),
225 | ),
226 | ),
227 | ),
228 | Padding(
229 | padding: EdgeInsets.only(top: 60, left: 100, right: 100),
230 | child: ButtonTheme(
231 | minWidth: 200,
232 | height: 60,
233 | child: RaisedButton(
234 | color: Colors.grey[600],
235 | child: Text(
236 | "Save User!",
237 | style: TextStyle(color: Colors.white, fontSize: 30),
238 | ),
239 | onPressed: () {
240 | print("User Saved!");
241 | String username = usernameController.text;
242 | String firstname = firstnameController.text;
243 | String lastname = lastnameController.text;
244 | String password = passwordController.text;
245 | String emailaddress = emailController.text;
246 | String imageurl = "";
247 |
248 | if (username.length < 1 ||
249 | firstname.length < 1 ||
250 | lastname.length < 1 ||
251 | password.length < 1 ||
252 | emailaddress.length < 1) {
253 | showDialog(
254 | context: context,
255 | child: new CustomDialog(
256 | title: 'Blank field!',
257 | description: "Please ensure fields are filled.",
258 | buttonText: "Okay",
259 | alertImage: "assets/x.png",
260 | buttonColor: Colors.red[700],
261 | ));
262 | } else {
263 | Navigator.of(context).push(MaterialPageRoute(
264 | builder: (context) =>
265 | SendUserToAPI(username,firstname,lastname,password, emailaddress,imageurl)));
266 | }
267 | },
268 | ),
269 | ),
270 | )
271 | ],
272 | ),
273 | ),
274 | ),
275 | ]
276 | ),
277 | );
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/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 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 97C146F11CF9000F007C117D /* Supporting Files */,
94 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
95 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
96 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
97 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
98 | );
99 | path = Runner;
100 | sourceTree = "";
101 | };
102 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
103 | isa = PBXGroup;
104 | children = (
105 | );
106 | name = "Supporting Files";
107 | sourceTree = "";
108 | };
109 | /* End PBXGroup section */
110 |
111 | /* Begin PBXNativeTarget section */
112 | 97C146ED1CF9000F007C117D /* Runner */ = {
113 | isa = PBXNativeTarget;
114 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
115 | buildPhases = (
116 | 9740EEB61CF901F6004384FC /* Run Script */,
117 | 97C146EA1CF9000F007C117D /* Sources */,
118 | 97C146EB1CF9000F007C117D /* Frameworks */,
119 | 97C146EC1CF9000F007C117D /* Resources */,
120 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
121 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
122 | );
123 | buildRules = (
124 | );
125 | dependencies = (
126 | );
127 | name = Runner;
128 | productName = Runner;
129 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
130 | productType = "com.apple.product-type.application";
131 | };
132 | /* End PBXNativeTarget section */
133 |
134 | /* Begin PBXProject section */
135 | 97C146E61CF9000F007C117D /* Project object */ = {
136 | isa = PBXProject;
137 | attributes = {
138 | LastUpgradeCheck = 1020;
139 | ORGANIZATIONNAME = "";
140 | TargetAttributes = {
141 | 97C146ED1CF9000F007C117D = {
142 | CreatedOnToolsVersion = 7.3.1;
143 | LastSwiftMigration = 1100;
144 | };
145 | };
146 | };
147 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
148 | compatibilityVersion = "Xcode 9.3";
149 | developmentRegion = en;
150 | hasScannedForEncodings = 0;
151 | knownRegions = (
152 | en,
153 | Base,
154 | );
155 | mainGroup = 97C146E51CF9000F007C117D;
156 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
157 | projectDirPath = "";
158 | projectRoot = "";
159 | targets = (
160 | 97C146ED1CF9000F007C117D /* Runner */,
161 | );
162 | };
163 | /* End PBXProject section */
164 |
165 | /* Begin PBXResourcesBuildPhase section */
166 | 97C146EC1CF9000F007C117D /* Resources */ = {
167 | isa = PBXResourcesBuildPhase;
168 | buildActionMask = 2147483647;
169 | files = (
170 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
171 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
172 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
173 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
174 | );
175 | runOnlyForDeploymentPostprocessing = 0;
176 | };
177 | /* End PBXResourcesBuildPhase section */
178 |
179 | /* Begin PBXShellScriptBuildPhase section */
180 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
181 | isa = PBXShellScriptBuildPhase;
182 | buildActionMask = 2147483647;
183 | files = (
184 | );
185 | inputPaths = (
186 | );
187 | name = "Thin Binary";
188 | outputPaths = (
189 | );
190 | runOnlyForDeploymentPostprocessing = 0;
191 | shellPath = /bin/sh;
192 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
193 | };
194 | 9740EEB61CF901F6004384FC /* Run Script */ = {
195 | isa = PBXShellScriptBuildPhase;
196 | buildActionMask = 2147483647;
197 | files = (
198 | );
199 | inputPaths = (
200 | );
201 | name = "Run Script";
202 | outputPaths = (
203 | );
204 | runOnlyForDeploymentPostprocessing = 0;
205 | shellPath = /bin/sh;
206 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
207 | };
208 | /* End PBXShellScriptBuildPhase section */
209 |
210 | /* Begin PBXSourcesBuildPhase section */
211 | 97C146EA1CF9000F007C117D /* Sources */ = {
212 | isa = PBXSourcesBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
216 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
217 | );
218 | runOnlyForDeploymentPostprocessing = 0;
219 | };
220 | /* End PBXSourcesBuildPhase section */
221 |
222 | /* Begin PBXVariantGroup section */
223 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
224 | isa = PBXVariantGroup;
225 | children = (
226 | 97C146FB1CF9000F007C117D /* Base */,
227 | );
228 | name = Main.storyboard;
229 | sourceTree = "";
230 | };
231 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
232 | isa = PBXVariantGroup;
233 | children = (
234 | 97C147001CF9000F007C117D /* Base */,
235 | );
236 | name = LaunchScreen.storyboard;
237 | sourceTree = "";
238 | };
239 | /* End PBXVariantGroup section */
240 |
241 | /* Begin XCBuildConfiguration section */
242 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
243 | isa = XCBuildConfiguration;
244 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
245 | buildSettings = {
246 | ALWAYS_SEARCH_USER_PATHS = NO;
247 | CLANG_ANALYZER_NONNULL = YES;
248 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
249 | CLANG_CXX_LIBRARY = "libc++";
250 | CLANG_ENABLE_MODULES = YES;
251 | CLANG_ENABLE_OBJC_ARC = YES;
252 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
253 | CLANG_WARN_BOOL_CONVERSION = YES;
254 | CLANG_WARN_COMMA = YES;
255 | CLANG_WARN_CONSTANT_CONVERSION = YES;
256 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
257 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
258 | CLANG_WARN_EMPTY_BODY = YES;
259 | CLANG_WARN_ENUM_CONVERSION = YES;
260 | CLANG_WARN_INFINITE_RECURSION = YES;
261 | CLANG_WARN_INT_CONVERSION = YES;
262 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
263 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
264 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
265 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
266 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
267 | CLANG_WARN_STRICT_PROTOTYPES = YES;
268 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
269 | CLANG_WARN_UNREACHABLE_CODE = YES;
270 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
271 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
272 | COPY_PHASE_STRIP = NO;
273 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
274 | ENABLE_NS_ASSERTIONS = NO;
275 | ENABLE_STRICT_OBJC_MSGSEND = YES;
276 | GCC_C_LANGUAGE_STANDARD = gnu99;
277 | GCC_NO_COMMON_BLOCKS = YES;
278 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
279 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
280 | GCC_WARN_UNDECLARED_SELECTOR = YES;
281 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
282 | GCC_WARN_UNUSED_FUNCTION = YES;
283 | GCC_WARN_UNUSED_VARIABLE = YES;
284 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
285 | MTL_ENABLE_DEBUG_INFO = NO;
286 | SDKROOT = iphoneos;
287 | SUPPORTED_PLATFORMS = iphoneos;
288 | TARGETED_DEVICE_FAMILY = "1,2";
289 | VALIDATE_PRODUCT = YES;
290 | };
291 | name = Profile;
292 | };
293 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
294 | isa = XCBuildConfiguration;
295 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
296 | buildSettings = {
297 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
298 | CLANG_ENABLE_MODULES = YES;
299 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
300 | ENABLE_BITCODE = NO;
301 | FRAMEWORK_SEARCH_PATHS = (
302 | "$(inherited)",
303 | "$(PROJECT_DIR)/Flutter",
304 | );
305 | INFOPLIST_FILE = Runner/Info.plist;
306 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
307 | LIBRARY_SEARCH_PATHS = (
308 | "$(inherited)",
309 | "$(PROJECT_DIR)/Flutter",
310 | );
311 | PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleApiApp;
312 | PRODUCT_NAME = "$(TARGET_NAME)";
313 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
314 | SWIFT_VERSION = 5.0;
315 | VERSIONING_SYSTEM = "apple-generic";
316 | };
317 | name = Profile;
318 | };
319 | 97C147031CF9000F007C117D /* Debug */ = {
320 | isa = XCBuildConfiguration;
321 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
322 | buildSettings = {
323 | ALWAYS_SEARCH_USER_PATHS = NO;
324 | CLANG_ANALYZER_NONNULL = YES;
325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
326 | CLANG_CXX_LIBRARY = "libc++";
327 | CLANG_ENABLE_MODULES = YES;
328 | CLANG_ENABLE_OBJC_ARC = YES;
329 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
330 | CLANG_WARN_BOOL_CONVERSION = YES;
331 | CLANG_WARN_COMMA = YES;
332 | CLANG_WARN_CONSTANT_CONVERSION = YES;
333 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
335 | CLANG_WARN_EMPTY_BODY = YES;
336 | CLANG_WARN_ENUM_CONVERSION = YES;
337 | CLANG_WARN_INFINITE_RECURSION = YES;
338 | CLANG_WARN_INT_CONVERSION = YES;
339 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
340 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
341 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
343 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
344 | CLANG_WARN_STRICT_PROTOTYPES = YES;
345 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
346 | CLANG_WARN_UNREACHABLE_CODE = YES;
347 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
348 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
349 | COPY_PHASE_STRIP = NO;
350 | DEBUG_INFORMATION_FORMAT = dwarf;
351 | ENABLE_STRICT_OBJC_MSGSEND = YES;
352 | ENABLE_TESTABILITY = YES;
353 | GCC_C_LANGUAGE_STANDARD = gnu99;
354 | GCC_DYNAMIC_NO_PIC = NO;
355 | GCC_NO_COMMON_BLOCKS = YES;
356 | GCC_OPTIMIZATION_LEVEL = 0;
357 | GCC_PREPROCESSOR_DEFINITIONS = (
358 | "DEBUG=1",
359 | "$(inherited)",
360 | );
361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
362 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
363 | GCC_WARN_UNDECLARED_SELECTOR = YES;
364 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
365 | GCC_WARN_UNUSED_FUNCTION = YES;
366 | GCC_WARN_UNUSED_VARIABLE = YES;
367 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
368 | MTL_ENABLE_DEBUG_INFO = YES;
369 | ONLY_ACTIVE_ARCH = YES;
370 | SDKROOT = iphoneos;
371 | TARGETED_DEVICE_FAMILY = "1,2";
372 | };
373 | name = Debug;
374 | };
375 | 97C147041CF9000F007C117D /* Release */ = {
376 | isa = XCBuildConfiguration;
377 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
378 | buildSettings = {
379 | ALWAYS_SEARCH_USER_PATHS = NO;
380 | CLANG_ANALYZER_NONNULL = YES;
381 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
382 | CLANG_CXX_LIBRARY = "libc++";
383 | CLANG_ENABLE_MODULES = YES;
384 | CLANG_ENABLE_OBJC_ARC = YES;
385 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
386 | CLANG_WARN_BOOL_CONVERSION = YES;
387 | CLANG_WARN_COMMA = YES;
388 | CLANG_WARN_CONSTANT_CONVERSION = YES;
389 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
390 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
391 | CLANG_WARN_EMPTY_BODY = YES;
392 | CLANG_WARN_ENUM_CONVERSION = YES;
393 | CLANG_WARN_INFINITE_RECURSION = YES;
394 | CLANG_WARN_INT_CONVERSION = YES;
395 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
396 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
397 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
398 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
399 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
400 | CLANG_WARN_STRICT_PROTOTYPES = YES;
401 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
402 | CLANG_WARN_UNREACHABLE_CODE = YES;
403 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
404 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
405 | COPY_PHASE_STRIP = NO;
406 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
407 | ENABLE_NS_ASSERTIONS = NO;
408 | ENABLE_STRICT_OBJC_MSGSEND = YES;
409 | GCC_C_LANGUAGE_STANDARD = gnu99;
410 | GCC_NO_COMMON_BLOCKS = YES;
411 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
412 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
413 | GCC_WARN_UNDECLARED_SELECTOR = YES;
414 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
415 | GCC_WARN_UNUSED_FUNCTION = YES;
416 | GCC_WARN_UNUSED_VARIABLE = YES;
417 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
418 | MTL_ENABLE_DEBUG_INFO = NO;
419 | SDKROOT = iphoneos;
420 | SUPPORTED_PLATFORMS = iphoneos;
421 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
422 | TARGETED_DEVICE_FAMILY = "1,2";
423 | VALIDATE_PRODUCT = YES;
424 | };
425 | name = Release;
426 | };
427 | 97C147061CF9000F007C117D /* Debug */ = {
428 | isa = XCBuildConfiguration;
429 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
430 | buildSettings = {
431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
432 | CLANG_ENABLE_MODULES = YES;
433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
434 | ENABLE_BITCODE = NO;
435 | FRAMEWORK_SEARCH_PATHS = (
436 | "$(inherited)",
437 | "$(PROJECT_DIR)/Flutter",
438 | );
439 | INFOPLIST_FILE = Runner/Info.plist;
440 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
441 | LIBRARY_SEARCH_PATHS = (
442 | "$(inherited)",
443 | "$(PROJECT_DIR)/Flutter",
444 | );
445 | PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleApiApp;
446 | PRODUCT_NAME = "$(TARGET_NAME)";
447 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
448 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
449 | SWIFT_VERSION = 5.0;
450 | VERSIONING_SYSTEM = "apple-generic";
451 | };
452 | name = Debug;
453 | };
454 | 97C147071CF9000F007C117D /* Release */ = {
455 | isa = XCBuildConfiguration;
456 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
457 | buildSettings = {
458 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
459 | CLANG_ENABLE_MODULES = YES;
460 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
461 | ENABLE_BITCODE = NO;
462 | FRAMEWORK_SEARCH_PATHS = (
463 | "$(inherited)",
464 | "$(PROJECT_DIR)/Flutter",
465 | );
466 | INFOPLIST_FILE = Runner/Info.plist;
467 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
468 | LIBRARY_SEARCH_PATHS = (
469 | "$(inherited)",
470 | "$(PROJECT_DIR)/Flutter",
471 | );
472 | PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleApiApp;
473 | PRODUCT_NAME = "$(TARGET_NAME)";
474 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
475 | SWIFT_VERSION = 5.0;
476 | VERSIONING_SYSTEM = "apple-generic";
477 | };
478 | name = Release;
479 | };
480 | /* End XCBuildConfiguration section */
481 |
482 | /* Begin XCConfigurationList section */
483 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
484 | isa = XCConfigurationList;
485 | buildConfigurations = (
486 | 97C147031CF9000F007C117D /* Debug */,
487 | 97C147041CF9000F007C117D /* Release */,
488 | 249021D3217E4FDB00AE95B9 /* Profile */,
489 | );
490 | defaultConfigurationIsVisible = 0;
491 | defaultConfigurationName = Release;
492 | };
493 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
494 | isa = XCConfigurationList;
495 | buildConfigurations = (
496 | 97C147061CF9000F007C117D /* Debug */,
497 | 97C147071CF9000F007C117D /* Release */,
498 | 249021D4217E4FDB00AE95B9 /* Profile */,
499 | );
500 | defaultConfigurationIsVisible = 0;
501 | defaultConfigurationName = Release;
502 | };
503 | /* End XCConfigurationList section */
504 | };
505 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
506 | }
507 |
--------------------------------------------------------------------------------