├── .gitignore ├── .metadata ├── .vscode └── settings.json ├── README.md ├── amplify ├── .config │ └── project-config.json ├── backend │ ├── analytics │ │ └── amplifytodoapp │ │ │ ├── parameters.json │ │ │ └── pinpoint-cloudformation-template.json │ ├── api │ │ └── amplifytodoapp │ │ │ ├── parameters.json │ │ │ ├── resolvers │ │ │ └── README.md │ │ │ ├── schema.graphql │ │ │ ├── stacks │ │ │ └── CustomResources.json │ │ │ └── transform.conf.json │ ├── auth │ │ └── amplifytodoapp │ │ │ ├── amplifytodoapp-cloudformation-template.yml │ │ │ └── parameters.json │ ├── backend-config.json │ ├── storage │ │ └── s385ebe3d5 │ │ │ ├── parameters.json │ │ │ ├── s3-cloudformation-template.json │ │ │ └── storage-params.json │ └── tags.json ├── cli.json └── team-provider-info.json ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── amplify_todo │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── 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 │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── images ├── amazon-logo.png ├── applogo.png ├── aws.png ├── facebook-logo.png ├── google-logo.png ├── profile.png └── profile_image.png ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── account_screens_enum.dart ├── app_routes.dart ├── buttons_enum.dart ├── controllers │ ├── authController.dart │ ├── bindings │ │ ├── controllers_bindings.dart │ │ └── homepage_bindings.dart │ ├── todoController.dart │ └── userController.dart ├── main.dart ├── models │ ├── ModelProvider.dart │ ├── Todo.dart │ └── Users.dart ├── pages │ ├── email_sign_in_page.dart │ ├── home_page.dart │ ├── loading_page.dart │ └── sign_in_page.dart ├── services │ ├── amplify_service.dart │ ├── auth_service.dart │ └── datastore_service.dart └── widgets │ ├── email_sign_in_form.dart │ ├── sign_in_button.dart │ └── todo_card.dart ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── youtube.png /.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 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | 48 | #amplify 49 | amplify/\#current-cloud-backend 50 | amplify/.config/local-* 51 | amplify/logs 52 | amplify/mock-data 53 | amplify/backend/amplify-meta.json 54 | amplify/backend/awscloudformation 55 | amplify/backend/.temp 56 | build/ 57 | dist/ 58 | node_modules/ 59 | aws-exports.js 60 | awsconfiguration.json 61 | amplifyconfiguration.json 62 | amplifyconfiguration.dart 63 | amplify-build-config.json 64 | amplify-gradle-config.json 65 | amplifytools.xcconfig 66 | .secret-* -------------------------------------------------------------------------------- /.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: adc687823a831bbebe28bdccfac1a628ca621513 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "amplify/.config": true, 4 | "amplify/**/*-parameters.json": true, 5 | "amplify/**/amplify.state": true, 6 | "amplify/**/transform.conf.json": true, 7 | "amplify/#current-cloud-backend": true, 8 | "amplify/backend/amplify-meta.json": true, 9 | "amplify/backend/awscloudformation": true 10 | } 11 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Flutter Todo App using AWS Amplify & GetX 2 | 3 | 4 | A simple To-Do List app created using AWS Amplify and GetX. 5 | 6 | - [Read about it here](https://dev.to/offlineprogrammer/a-flutter-todo-app-using-awsamplify-getx-2oii) 7 | 8 | With this project you will learn how to: 9 | 10 | 1. Use AWSAmplify Auth. 11 | 2. Use AWSAmplify DataStore. 12 | 3. Manage the state of the application using GetXController. 13 | 4. 4. Make the UI reactive efficiently, rebuilding only the necessary widgets. 14 | 15 | YouTube video demo here: 16 | 17 | [![A Flutter Todo App using AWS Amplify & GetX](youtube.png)](https://youtu.be/thrhO2Oxqqc) 18 | -------------------------------------------------------------------------------- /amplify/.config/project-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | "awscloudformation" 4 | ], 5 | "projectName": "amplifytodoapp", 6 | "version": "3.1", 7 | "frontend": "flutter", 8 | "flutter": { 9 | "config": { 10 | "ResDir": "./lib/" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /amplify/backend/analytics/amplifytodoapp/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": "amplifytodoapp", 3 | "roleName": "pinpointLambdaRole62d4b472", 4 | "cloudformationPolicyName": "cloudformationPolicy62d4b472", 5 | "cloudWatchPolicyName": "cloudWatchPolicy62d4b472", 6 | "pinpointPolicyName": "pinpointPolicy62d4b472", 7 | "authPolicyName": "pinpoint_amplify_62d4b472", 8 | "unauthPolicyName": "pinpoint_amplify_62d4b472", 9 | "authRoleName": { 10 | "Ref": "AuthRoleName" 11 | }, 12 | "unauthRoleName": { 13 | "Ref": "UnauthRoleName" 14 | }, 15 | "authRoleArn": { 16 | "Fn::GetAtt": [ 17 | "AuthRole", 18 | "Arn" 19 | ] 20 | } 21 | } -------------------------------------------------------------------------------- /amplify/backend/analytics/amplifytodoapp/pinpoint-cloudformation-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Pinpoint resource stack creation using Amplify CLI", 4 | "Parameters": { 5 | "appName": { 6 | "Type": "String" 7 | }, 8 | "appId": { 9 | "Type": "String", 10 | "Default": "NONE" 11 | }, 12 | "roleName": { 13 | "Type": "String" 14 | }, 15 | "cloudformationPolicyName": { 16 | "Type": "String" 17 | }, 18 | "cloudWatchPolicyName": { 19 | "Type": "String" 20 | }, 21 | "pinpointPolicyName": { 22 | "Type": "String" 23 | }, 24 | "authPolicyName": { 25 | "Type": "String" 26 | }, 27 | "unauthPolicyName": { 28 | "Type": "String" 29 | }, 30 | "authRoleName": { 31 | "Type": "String" 32 | }, 33 | "unauthRoleName": { 34 | "Type": "String" 35 | }, 36 | "authRoleArn": { 37 | "Type": "String" 38 | }, 39 | "env": { 40 | "Type": "String" 41 | } 42 | }, 43 | "Metadata": { 44 | "AWS::CloudFormation::Interface": { 45 | "ParameterGroups": [ 46 | { 47 | "Label": { 48 | "default": "Creating pinpoint app" 49 | }, 50 | "Parameters": [ 51 | "appName" 52 | ] 53 | } 54 | ] 55 | } 56 | }, 57 | "Conditions": { 58 | "ShouldCreatePinpointApp": { 59 | "Fn::Equals": [ 60 | { 61 | "Ref": "appId" 62 | }, 63 | "NONE" 64 | ] 65 | }, 66 | "ShouldNotCreateEnvResources": { 67 | "Fn::Equals": [ 68 | { 69 | "Ref": "env" 70 | }, 71 | "NONE" 72 | ] 73 | } 74 | }, 75 | "Resources": { 76 | "LambdaExecutionRole": { 77 | "Condition": "ShouldCreatePinpointApp", 78 | "Type": "AWS::IAM::Role", 79 | "Properties": { 80 | "RoleName": { 81 | "Fn::If": [ 82 | "ShouldNotCreateEnvResources", 83 | { 84 | "Ref": "roleName" 85 | }, 86 | { 87 | "Fn::Join": [ 88 | "", 89 | [ 90 | { 91 | "Ref": "roleName" 92 | }, 93 | "-", 94 | { 95 | "Ref": "env" 96 | } 97 | ] 98 | ] 99 | } 100 | ] 101 | }, 102 | "AssumeRolePolicyDocument": { 103 | "Version": "2012-10-17", 104 | "Statement": [ 105 | { 106 | "Effect": "Allow", 107 | "Principal": { 108 | "Service": [ 109 | "lambda.amazonaws.com" 110 | ] 111 | }, 112 | "Action": [ 113 | "sts:AssumeRole" 114 | ] 115 | } 116 | ] 117 | }, 118 | "Policies": [ 119 | { 120 | "PolicyName": { 121 | "Ref": "cloudWatchPolicyName" 122 | }, 123 | "PolicyDocument": { 124 | "Version": "2012-10-17", 125 | "Statement": [ 126 | { 127 | "Effect": "Allow", 128 | "Action": [ 129 | "logs:CreateLogGroup", 130 | "logs:CreateLogStream", 131 | "logs:PutLogEvents" 132 | ], 133 | "Resource": "arn:aws:logs:*:*:*" 134 | } 135 | ] 136 | } 137 | }, 138 | { 139 | "PolicyName": { 140 | "Ref": "pinpointPolicyName" 141 | }, 142 | "PolicyDocument": { 143 | "Version": "2012-10-17", 144 | "Statement": [ 145 | { 146 | "Effect": "Allow", 147 | "Action": [ 148 | "mobileanalytics:*", 149 | "mobiletargeting:*" 150 | ], 151 | "Resource": "*" 152 | } 153 | ] 154 | } 155 | }, 156 | { 157 | "PolicyName": { 158 | "Ref": "cloudformationPolicyName" 159 | }, 160 | "PolicyDocument": { 161 | "Version": "2012-10-17", 162 | "Statement": [ 163 | { 164 | "Effect": "Allow", 165 | "Action": [ 166 | "cloudformation:*" 167 | ], 168 | "Resource": "*" 169 | } 170 | ] 171 | } 172 | } 173 | ] 174 | } 175 | }, 176 | "PinpointFunction": { 177 | "Type": "AWS::Lambda::Function", 178 | "Condition": "ShouldCreatePinpointApp", 179 | "Properties": { 180 | "Code": { 181 | "ZipFile": { 182 | "Fn::Join": [ 183 | "\n", 184 | [ 185 | "const response = require('cfn-response');", 186 | "const aws = require('aws-sdk');", 187 | "exports.handler = function(event, context) {", 188 | " if (event.RequestType == 'Delete') {", 189 | " const stackID = event.StackId;", 190 | " const cloudFormationClient = new aws.CloudFormation({ apiVersion: '2016-12-01', region: event.ResourceProperties.region });", 191 | " cloudFormationClient.describeStacks({ StackName: stackID }).promise()", 192 | " .then(describeStacksOutput => {", 193 | " let appId;", 194 | " if (describeStacksOutput.Stacks && describeStacksOutput.Stacks.length > 0) {", 195 | " const { Outputs } = describeStacksOutput.Stacks[0];", 196 | " const appIdOutput = Outputs.find((output)=>{ return output.OutputKey === 'Id'});", 197 | " appId = appIdOutput ? appIdOutput.OutputValue : undefined; ", 198 | " }", 199 | " return appId;", 200 | " })", 201 | " .then(appId => {", 202 | " if (appId) {", 203 | " const pinpointClient = new aws.Pinpoint({ apiVersion: '2016-12-01', region: event.ResourceProperties.pingPointRegion });", 204 | " const params = {", 205 | " ApplicationId: appId,", 206 | " };", 207 | " pinpointClient.deleteApp(params).promise();", 208 | " }", 209 | " })", 210 | " .then(()=>{", 211 | " response.send(event, context, response.SUCCESS, {'message': `Successfully deleted pinpoint project`});", 212 | " })", 213 | " .catch(e=>{", 214 | " response.send(event, context, response.FAILED, {'message': `Failed to deleted Pinpoint project`, 'exception': e});", 215 | " }); ", 216 | " }", 217 | " if (event.RequestType == 'Update') {", 218 | " response.send(event, context, response.SUCCESS);", 219 | " return;", 220 | " }", 221 | " if (event.RequestType == 'Create') {", 222 | " const appName = event.ResourceProperties.appName;", 223 | " let responseData = {};", 224 | " const params = {", 225 | " CreateApplicationRequest: {", 226 | " Name: appName", 227 | " }", 228 | " };", 229 | " const pinpoint = new aws.Pinpoint({ apiVersion: '2016-12-01', region: event.ResourceProperties.pingPointRegion });", 230 | " pinpoint.createApp(params).promise()", 231 | " .then((res) => {", 232 | " responseData = res.ApplicationResponse;", 233 | " response.send(event, context, response.SUCCESS, responseData);", 234 | " }).catch((err) => {", 235 | " console.log(err.stack);", 236 | " responseData = {Error: err};", 237 | " response.send(event, context, response.FAILED, responseData);", 238 | " throw err;", 239 | " });", 240 | " }", 241 | "};" 242 | ] 243 | ] 244 | } 245 | }, 246 | "Handler": "index.handler", 247 | "Runtime": "nodejs12.x", 248 | "Timeout": "300", 249 | "Role": { 250 | "Fn::GetAtt": [ 251 | "LambdaExecutionRole", 252 | "Arn" 253 | ] 254 | } 255 | } 256 | }, 257 | "PinpointFunctionOutputs": { 258 | "Type": "Custom::LambdaCallout", 259 | "Condition": "ShouldCreatePinpointApp", 260 | "Properties": { 261 | "ServiceToken": { 262 | "Fn::GetAtt": [ 263 | "PinpointFunction", 264 | "Arn" 265 | ] 266 | }, 267 | "region": { 268 | "Ref": "AWS::Region" 269 | }, 270 | "pingPointRegion": { 271 | "Fn::FindInMap": [ 272 | "RegionMapping", 273 | { 274 | "Ref": "AWS::Region" 275 | }, 276 | "pinpointRegion" 277 | ] 278 | }, 279 | "appName": { 280 | "Fn::If": [ 281 | "ShouldNotCreateEnvResources", 282 | { 283 | "Ref": "appName" 284 | }, 285 | { 286 | "Fn::Join": [ 287 | "", 288 | [ 289 | { 290 | "Ref": "appName" 291 | }, 292 | "-", 293 | { 294 | "Ref": "env" 295 | } 296 | ] 297 | ] 298 | } 299 | ] 300 | } 301 | }, 302 | "DependsOn": "PinpointFunction" 303 | }, 304 | "CognitoUnauthPolicy": { 305 | "Type": "AWS::IAM::Policy", 306 | "Condition": "ShouldCreatePinpointApp", 307 | "Properties": { 308 | "PolicyName": { 309 | "Ref": "unauthPolicyName" 310 | }, 311 | "Roles": [ 312 | { 313 | "Ref": "unauthRoleName" 314 | } 315 | ], 316 | "PolicyDocument": { 317 | "Version": "2012-10-17", 318 | "Statement": [ 319 | { 320 | "Effect": "Allow", 321 | "Action": [ 322 | "mobiletargeting:PutEvents", 323 | "mobiletargeting:UpdateEndpoint" 324 | ], 325 | "Resource": [ 326 | { 327 | "Fn::If": [ 328 | "ShouldCreatePinpointApp", 329 | { 330 | "Fn::Join": [ 331 | "", 332 | [ 333 | "arn:aws:mobiletargeting:*:", 334 | { 335 | "Fn::Select": [ 336 | "4", 337 | { 338 | "Fn::Split": [ 339 | ":", 340 | { 341 | "Ref": "authRoleArn" 342 | } 343 | ] 344 | } 345 | ] 346 | }, 347 | ":apps/", 348 | { 349 | "Fn::GetAtt": [ 350 | "PinpointFunctionOutputs", 351 | "Id" 352 | ] 353 | }, 354 | "*" 355 | ] 356 | ] 357 | }, 358 | { 359 | "Fn::Join": [ 360 | "", 361 | [ 362 | "arn:aws:mobiletargeting:*:", 363 | { 364 | "Fn::Select": [ 365 | "4", 366 | { 367 | "Fn::Split": [ 368 | ":", 369 | { 370 | "Ref": "authRoleArn" 371 | } 372 | ] 373 | } 374 | ] 375 | }, 376 | ":apps/", 377 | { 378 | "Ref": "appId" 379 | }, 380 | "*" 381 | ] 382 | ] 383 | } 384 | ] 385 | } 386 | ] 387 | } 388 | ] 389 | } 390 | } 391 | }, 392 | "CognitoAuthPolicy": { 393 | "Type": "AWS::IAM::Policy", 394 | "Condition": "ShouldCreatePinpointApp", 395 | "Properties": { 396 | "PolicyName": { 397 | "Ref": "authPolicyName" 398 | }, 399 | "Roles": [ 400 | { 401 | "Ref": "authRoleName" 402 | } 403 | ], 404 | "PolicyDocument": { 405 | "Version": "2012-10-17", 406 | "Statement": [ 407 | { 408 | "Effect": "Allow", 409 | "Action": [ 410 | "mobiletargeting:PutEvents", 411 | "mobiletargeting:UpdateEndpoint" 412 | ], 413 | "Resource": [ 414 | { 415 | "Fn::If": [ 416 | "ShouldCreatePinpointApp", 417 | { 418 | "Fn::Join": [ 419 | "", 420 | [ 421 | "arn:aws:mobiletargeting:*:", 422 | { 423 | "Fn::Select": [ 424 | "4", 425 | { 426 | "Fn::Split": [ 427 | ":", 428 | { 429 | "Ref": "authRoleArn" 430 | } 431 | ] 432 | } 433 | ] 434 | }, 435 | ":apps/", 436 | { 437 | "Fn::GetAtt": [ 438 | "PinpointFunctionOutputs", 439 | "Id" 440 | ] 441 | }, 442 | "*" 443 | ] 444 | ] 445 | }, 446 | { 447 | "Fn::Join": [ 448 | "", 449 | [ 450 | "arn:aws:mobiletargeting:*:", 451 | { 452 | "Fn::Select": [ 453 | "4", 454 | { 455 | "Fn::Split": [ 456 | ":", 457 | { 458 | "Ref": "authRoleArn" 459 | } 460 | ] 461 | } 462 | ] 463 | }, 464 | ":apps/", 465 | { 466 | "Ref": "appId" 467 | }, 468 | "*" 469 | ] 470 | ] 471 | } 472 | ] 473 | } 474 | ] 475 | } 476 | ] 477 | } 478 | } 479 | } 480 | }, 481 | "Outputs": { 482 | "Region": { 483 | "Value": { 484 | "Fn::FindInMap": [ 485 | "RegionMapping", 486 | { 487 | "Ref": "AWS::Region" 488 | }, 489 | "pinpointRegion" 490 | ] 491 | } 492 | }, 493 | "Id": { 494 | "Value": { 495 | "Fn::If": [ 496 | "ShouldCreatePinpointApp", 497 | { 498 | "Fn::GetAtt": [ 499 | "PinpointFunctionOutputs", 500 | "Id" 501 | ] 502 | }, 503 | { 504 | "Ref": "appId" 505 | } 506 | ] 507 | } 508 | }, 509 | "appName": { 510 | "Value": { 511 | "Fn::If": [ 512 | "ShouldCreatePinpointApp", 513 | { 514 | "Fn::GetAtt": [ 515 | "PinpointFunctionOutputs", 516 | "Name" 517 | ] 518 | }, 519 | { 520 | "Ref": "appName" 521 | } 522 | ] 523 | } 524 | } 525 | }, 526 | "Mappings": { 527 | "RegionMapping": { 528 | "us-east-1": { 529 | "pinpointRegion": "us-east-1" 530 | }, 531 | "us-east-2": { 532 | "pinpointRegion": "us-east-1" 533 | }, 534 | "sa-east-1": { 535 | "pinpointRegion": "us-east-1" 536 | }, 537 | "ca-central-1": { 538 | "pinpointRegion": "us-east-1" 539 | }, 540 | "us-west-1": { 541 | "pinpointRegion": "us-west-2" 542 | }, 543 | "us-west-2": { 544 | "pinpointRegion": "us-west-2" 545 | }, 546 | "cn-north-1": { 547 | "pinpointRegion": "us-west-2" 548 | }, 549 | "cn-northwest-1": { 550 | "pinpointRegion": "us-west-2" 551 | }, 552 | "ap-south-1": { 553 | "pinpointRegion": "us-west-2" 554 | }, 555 | "ap-northeast-3": { 556 | "pinpointRegion": "us-west-2" 557 | }, 558 | "ap-northeast-2": { 559 | "pinpointRegion": "us-west-2" 560 | }, 561 | "ap-southeast-1": { 562 | "pinpointRegion": "us-west-2" 563 | }, 564 | "ap-southeast-2": { 565 | "pinpointRegion": "us-west-2" 566 | }, 567 | "ap-northeast-1": { 568 | "pinpointRegion": "us-west-2" 569 | }, 570 | "eu-central-1": { 571 | "pinpointRegion": "eu-central-1" 572 | }, 573 | "eu-west-1": { 574 | "pinpointRegion": "eu-west-1" 575 | }, 576 | "eu-west-2": { 577 | "pinpointRegion": "eu-west-1" 578 | }, 579 | "eu-west-3": { 580 | "pinpointRegion": "eu-west-1" 581 | } 582 | } 583 | } 584 | } -------------------------------------------------------------------------------- /amplify/backend/api/amplifytodoapp/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSyncApiName": "amplifytodoapp", 3 | "DynamoDBBillingMode": "PAY_PER_REQUEST", 4 | "DynamoDBEnableServerSideEncryption": false 5 | } -------------------------------------------------------------------------------- /amplify/backend/api/amplifytodoapp/resolvers/README.md: -------------------------------------------------------------------------------- 1 | Any resolvers that you add in this directory will override the ones automatically generated by Amplify CLI and will be directly copied to the cloud. 2 | For more information, visit [https://docs.amplify.aws/cli/graphql-transformer/resolvers](https://docs.amplify.aws/cli/graphql-transformer/resolvers) -------------------------------------------------------------------------------- /amplify/backend/api/amplifytodoapp/schema.graphql: -------------------------------------------------------------------------------- 1 | type Todo @model @auth(rules: [{allow: public}]) @key(name: "byUser", fields: ["userId"]) { 2 | id: ID! 3 | name: String! 4 | createdAt: AWSDateTime 5 | updatedAt: AWSDateTime 6 | isDone: Boolean 7 | userId: ID! 8 | } 9 | 10 | type Users @model @auth(rules: [{allow: public}]) { 11 | id: ID! 12 | username: String 13 | email: AWSEmail 14 | imageKey: String! 15 | imageUrl: String! 16 | isVerified: Boolean 17 | createdAt: AWSDateTime 18 | todos: [Todo] @connection(keyName: "byUser", fields: ["id"]) 19 | 20 | } 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /amplify/backend/api/amplifytodoapp/stacks/CustomResources.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "An auto-generated nested stack.", 4 | "Metadata": {}, 5 | "Parameters": { 6 | "AppSyncApiId": { 7 | "Type": "String", 8 | "Description": "The id of the AppSync API associated with this project." 9 | }, 10 | "AppSyncApiName": { 11 | "Type": "String", 12 | "Description": "The name of the AppSync API", 13 | "Default": "AppSyncSimpleTransform" 14 | }, 15 | "env": { 16 | "Type": "String", 17 | "Description": "The environment name. e.g. Dev, Test, or Production", 18 | "Default": "NONE" 19 | }, 20 | "S3DeploymentBucket": { 21 | "Type": "String", 22 | "Description": "The S3 bucket containing all deployment assets for the project." 23 | }, 24 | "S3DeploymentRootKey": { 25 | "Type": "String", 26 | "Description": "An S3 key relative to the S3DeploymentBucket that points to the root\nof the deployment directory." 27 | } 28 | }, 29 | "Resources": { 30 | "EmptyResource": { 31 | "Type": "Custom::EmptyResource", 32 | "Condition": "AlwaysFalse" 33 | } 34 | }, 35 | "Conditions": { 36 | "HasEnvironmentParameter": { 37 | "Fn::Not": [ 38 | { 39 | "Fn::Equals": [ 40 | { 41 | "Ref": "env" 42 | }, 43 | "NONE" 44 | ] 45 | } 46 | ] 47 | }, 48 | "AlwaysFalse": { 49 | "Fn::Equals": ["true", "false"] 50 | } 51 | }, 52 | "Outputs": { 53 | "EmptyOutput": { 54 | "Description": "An empty output. You may delete this if you have at least one resource above.", 55 | "Value": "" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /amplify/backend/api/amplifytodoapp/transform.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": 5, 3 | "ElasticsearchWarning": true, 4 | "ResolverConfig": { 5 | "project": { 6 | "ConflictHandler": "AUTOMERGE", 7 | "ConflictDetection": "VERSION" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /amplify/backend/auth/amplifytodoapp/amplifytodoapp-cloudformation-template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Parameters: 4 | env: 5 | Type: String 6 | authRoleArn: 7 | Type: String 8 | unauthRoleArn: 9 | Type: String 10 | 11 | 12 | 13 | 14 | identityPoolName: 15 | Type: String 16 | 17 | 18 | 19 | allowUnauthenticatedIdentities: 20 | Type: String 21 | 22 | resourceNameTruncated: 23 | Type: String 24 | 25 | 26 | userPoolName: 27 | Type: String 28 | 29 | 30 | 31 | autoVerifiedAttributes: 32 | Type: CommaDelimitedList 33 | 34 | mfaConfiguration: 35 | Type: String 36 | 37 | 38 | 39 | mfaTypes: 40 | Type: CommaDelimitedList 41 | 42 | smsAuthenticationMessage: 43 | Type: String 44 | 45 | 46 | smsVerificationMessage: 47 | Type: String 48 | 49 | 50 | emailVerificationSubject: 51 | Type: String 52 | 53 | 54 | emailVerificationMessage: 55 | Type: String 56 | 57 | 58 | 59 | defaultPasswordPolicy: 60 | Type: String 61 | 62 | 63 | passwordPolicyMinLength: 64 | Type: Number 65 | 66 | 67 | passwordPolicyCharacters: 68 | Type: CommaDelimitedList 69 | 70 | 71 | requiredAttributes: 72 | Type: CommaDelimitedList 73 | 74 | 75 | userpoolClientGenerateSecret: 76 | Type: String 77 | 78 | 79 | userpoolClientRefreshTokenValidity: 80 | Type: Number 81 | 82 | 83 | userpoolClientWriteAttributes: 84 | Type: CommaDelimitedList 85 | 86 | 87 | userpoolClientReadAttributes: 88 | Type: CommaDelimitedList 89 | 90 | userpoolClientLambdaRole: 91 | Type: String 92 | 93 | 94 | 95 | userpoolClientSetAttributes: 96 | Type: String 97 | 98 | sharedId: 99 | Type: String 100 | 101 | 102 | resourceName: 103 | Type: String 104 | 105 | 106 | authSelections: 107 | Type: String 108 | 109 | 110 | 111 | 112 | serviceName: 113 | Type: String 114 | 115 | 116 | 117 | usernameAttributes: 118 | Type: CommaDelimitedList 119 | 120 | useDefault: 121 | Type: String 122 | 123 | 124 | 125 | userPoolGroups: 126 | Type: String 127 | 128 | 129 | userPoolGroupList: 130 | Type: CommaDelimitedList 131 | 132 | 133 | adminQueries: 134 | Type: String 135 | 136 | 137 | thirdPartyAuth: 138 | Type: String 139 | 140 | 141 | authProviders: 142 | Type: CommaDelimitedList 143 | 144 | 145 | usernameCaseSensitive: 146 | Type: String 147 | 148 | 149 | dependsOn: 150 | Type: CommaDelimitedList 151 | 152 | Conditions: 153 | ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ] 154 | 155 | ShouldOutputAppClientSecrets: !Equals [!Ref userpoolClientGenerateSecret, true ] 156 | 157 | 158 | Resources: 159 | 160 | 161 | # BEGIN SNS ROLE RESOURCE 162 | SNSRole: 163 | # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process 164 | Type: AWS::IAM::Role 165 | Properties: 166 | RoleName: !If [ShouldNotCreateEnvResources, 'amplif249d9f98_sns-role', !Join ['',[ 'sns', '249d9f98', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] 167 | AssumeRolePolicyDocument: 168 | Version: "2012-10-17" 169 | Statement: 170 | - Sid: "" 171 | Effect: "Allow" 172 | Principal: 173 | Service: "cognito-idp.amazonaws.com" 174 | Action: 175 | - "sts:AssumeRole" 176 | Condition: 177 | StringEquals: 178 | sts:ExternalId: amplif249d9f98_role_external_id 179 | Policies: 180 | - 181 | PolicyName: amplif249d9f98-sns-policy 182 | PolicyDocument: 183 | Version: "2012-10-17" 184 | Statement: 185 | - 186 | Effect: "Allow" 187 | Action: 188 | - "sns:Publish" 189 | Resource: "*" 190 | # BEGIN USER POOL RESOURCES 191 | UserPool: 192 | # Created upon user selection 193 | # Depends on SNS Role for Arn if MFA is enabled 194 | Type: AWS::Cognito::UserPool 195 | UpdateReplacePolicy: Retain 196 | Properties: 197 | UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]] 198 | 199 | 200 | UsernameConfiguration: 201 | CaseSensitive: false 202 | 203 | Schema: 204 | 205 | - 206 | Name: email 207 | Required: true 208 | Mutable: true 209 | 210 | 211 | 212 | 213 | AutoVerifiedAttributes: !Ref autoVerifiedAttributes 214 | 215 | 216 | EmailVerificationMessage: !Ref emailVerificationMessage 217 | EmailVerificationSubject: !Ref emailVerificationSubject 218 | 219 | Policies: 220 | PasswordPolicy: 221 | MinimumLength: !Ref passwordPolicyMinLength 222 | RequireLowercase: true 223 | RequireNumbers: true 224 | RequireSymbols: true 225 | RequireUppercase: true 226 | 227 | UsernameAttributes: !Ref usernameAttributes 228 | 229 | MfaConfiguration: !Ref mfaConfiguration 230 | SmsVerificationMessage: !Ref smsVerificationMessage 231 | SmsAuthenticationMessage: !Ref smsAuthenticationMessage 232 | SmsConfiguration: 233 | SnsCallerArn: !GetAtt SNSRole.Arn 234 | ExternalId: amplif249d9f98_role_external_id 235 | 236 | 237 | UserPoolClientWeb: 238 | # Created provide application access to user pool 239 | # Depends on UserPool for ID reference 240 | Type: "AWS::Cognito::UserPoolClient" 241 | Properties: 242 | ClientName: amplif249d9f98_app_clientWeb 243 | 244 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity 245 | UserPoolId: !Ref UserPool 246 | DependsOn: UserPool 247 | UserPoolClient: 248 | # Created provide application access to user pool 249 | # Depends on UserPool for ID reference 250 | Type: "AWS::Cognito::UserPoolClient" 251 | Properties: 252 | ClientName: amplif249d9f98_app_client 253 | 254 | GenerateSecret: !Ref userpoolClientGenerateSecret 255 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity 256 | UserPoolId: !Ref UserPool 257 | DependsOn: UserPool 258 | # BEGIN USER POOL LAMBDA RESOURCES 259 | UserPoolClientRole: 260 | # Created to execute Lambda which gets userpool app client config values 261 | Type: 'AWS::IAM::Role' 262 | Properties: 263 | RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', '249d9f98', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] 264 | AssumeRolePolicyDocument: 265 | Version: '2012-10-17' 266 | Statement: 267 | - Effect: Allow 268 | Principal: 269 | Service: 270 | - lambda.amazonaws.com 271 | Action: 272 | - 'sts:AssumeRole' 273 | DependsOn: UserPoolClient 274 | UserPoolClientLambda: 275 | # Lambda which gets userpool app client config values 276 | # Depends on UserPool for id 277 | # Depends on UserPoolClientRole for role ARN 278 | Type: 'AWS::Lambda::Function' 279 | Properties: 280 | Code: 281 | ZipFile: !Join 282 | - |+ 283 | - - 'const response = require(''cfn-response'');' 284 | - 'const aws = require(''aws-sdk'');' 285 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 286 | - 'exports.handler = (event, context, callback) => {' 287 | - ' if (event.RequestType == ''Delete'') { ' 288 | - ' response.send(event, context, response.SUCCESS, {})' 289 | - ' }' 290 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 291 | - ' const params = {' 292 | - ' ClientId: event.ResourceProperties.clientId,' 293 | - ' UserPoolId: event.ResourceProperties.userpoolId' 294 | - ' };' 295 | - ' identity.describeUserPoolClient(params).promise()' 296 | - ' .then((res) => {' 297 | - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});' 298 | - ' })' 299 | - ' .catch((err) => {' 300 | - ' response.send(event, context, response.FAILED, {err});' 301 | - ' });' 302 | - ' }' 303 | - '};' 304 | Handler: index.handler 305 | Runtime: nodejs12.x 306 | Timeout: '300' 307 | Role: !GetAtt 308 | - UserPoolClientRole 309 | - Arn 310 | DependsOn: UserPoolClientRole 311 | UserPoolClientLambdaPolicy: 312 | # Sets userpool policy for the role that executes the Userpool Client Lambda 313 | # Depends on UserPool for Arn 314 | # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing 315 | Type: 'AWS::IAM::Policy' 316 | Properties: 317 | PolicyName: amplif249d9f98_userpoolclient_lambda_iam_policy 318 | Roles: 319 | - !Ref UserPoolClientRole 320 | PolicyDocument: 321 | Version: '2012-10-17' 322 | Statement: 323 | - Effect: Allow 324 | Action: 325 | - 'cognito-idp:DescribeUserPoolClient' 326 | Resource: !GetAtt UserPool.Arn 327 | DependsOn: UserPoolClientLambda 328 | UserPoolClientLogPolicy: 329 | # Sets log policy for the role that executes the Userpool Client Lambda 330 | # Depends on UserPool for Arn 331 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing 332 | Type: 'AWS::IAM::Policy' 333 | Properties: 334 | PolicyName: amplif249d9f98_userpoolclient_lambda_log_policy 335 | Roles: 336 | - !Ref UserPoolClientRole 337 | PolicyDocument: 338 | Version: 2012-10-17 339 | Statement: 340 | - Effect: Allow 341 | Action: 342 | - 'logs:CreateLogGroup' 343 | - 'logs:CreateLogStream' 344 | - 'logs:PutLogEvents' 345 | Resource: !Sub 346 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 347 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda} 348 | DependsOn: UserPoolClientLambdaPolicy 349 | UserPoolClientInputs: 350 | # Values passed to Userpool client Lambda 351 | # Depends on UserPool for Id 352 | # Depends on UserPoolClient for Id 353 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing 354 | Type: 'Custom::LambdaCallout' 355 | Properties: 356 | ServiceToken: !GetAtt UserPoolClientLambda.Arn 357 | clientId: !Ref UserPoolClient 358 | userpoolId: !Ref UserPool 359 | DependsOn: UserPoolClientLogPolicy 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | # BEGIN IDENTITY POOL RESOURCES 368 | 369 | 370 | IdentityPool: 371 | # Always created 372 | Type: AWS::Cognito::IdentityPool 373 | Properties: 374 | IdentityPoolName: !If [ShouldNotCreateEnvResources, 'testAuthIdentityPool', !Join ['',['testAuthIdentityPool', '__', !Ref env]]] 375 | 376 | CognitoIdentityProviders: 377 | - ClientId: !Ref UserPoolClient 378 | ProviderName: !Sub 379 | - cognito-idp.${region}.amazonaws.com/${client} 380 | - { region: !Ref "AWS::Region", client: !Ref UserPool} 381 | - ClientId: !Ref UserPoolClientWeb 382 | ProviderName: !Sub 383 | - cognito-idp.${region}.amazonaws.com/${client} 384 | - { region: !Ref "AWS::Region", client: !Ref UserPool} 385 | 386 | AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities 387 | 388 | 389 | DependsOn: UserPoolClientInputs 390 | 391 | 392 | IdentityPoolRoleMap: 393 | # Created to map Auth and Unauth roles to the identity pool 394 | # Depends on Identity Pool for ID ref 395 | Type: AWS::Cognito::IdentityPoolRoleAttachment 396 | Properties: 397 | IdentityPoolId: !Ref IdentityPool 398 | Roles: 399 | unauthenticated: !Ref unauthRoleArn 400 | authenticated: !Ref authRoleArn 401 | DependsOn: IdentityPool 402 | 403 | 404 | Outputs : 405 | 406 | IdentityPoolId: 407 | Value: !Ref 'IdentityPool' 408 | Description: Id for the identity pool 409 | IdentityPoolName: 410 | Value: !GetAtt IdentityPool.Name 411 | 412 | 413 | 414 | 415 | UserPoolId: 416 | Value: !Ref 'UserPool' 417 | Description: Id for the user pool 418 | UserPoolArn: 419 | Value: !GetAtt UserPool.Arn 420 | Description: Arn for the user pool 421 | UserPoolName: 422 | Value: !Ref userPoolName 423 | AppClientIDWeb: 424 | Value: !Ref 'UserPoolClientWeb' 425 | Description: The user pool app client id for web 426 | AppClientID: 427 | Value: !Ref 'UserPoolClient' 428 | Description: The user pool app client id 429 | AppClientSecret: 430 | Value: !GetAtt UserPoolClientInputs.appSecret 431 | Condition: ShouldOutputAppClientSecrets 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | -------------------------------------------------------------------------------- /amplify/backend/auth/amplifytodoapp/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "identityPoolName": "testAuthIdentityPool", 3 | "allowUnauthenticatedIdentities": true, 4 | "resourceNameTruncated": "amplif249d9f98", 5 | "userPoolName": "amplifytodoapp", 6 | "autoVerifiedAttributes": [ 7 | "email" 8 | ], 9 | "mfaConfiguration": "OFF", 10 | "mfaTypes": [ 11 | "SMS Text Message" 12 | ], 13 | "smsAuthenticationMessage": "Your authentication code is {####}", 14 | "smsVerificationMessage": "Your verification code is {####}", 15 | "emailVerificationSubject": "Your auth code: {####}", 16 | "emailVerificationMessage": "auth code: {####}", 17 | "defaultPasswordPolicy": false, 18 | "passwordPolicyMinLength": 8, 19 | "passwordPolicyCharacters": [ 20 | "Requires Lowercase", 21 | "Requires Numbers", 22 | "Requires Symbols", 23 | "Requires Uppercase" 24 | ], 25 | "requiredAttributes": [ 26 | "email" 27 | ], 28 | "userpoolClientGenerateSecret": false, 29 | "userpoolClientRefreshTokenValidity": 30, 30 | "userpoolClientWriteAttributes": [], 31 | "userpoolClientReadAttributes": [], 32 | "userpoolClientLambdaRole": "amplif249d9f98_userpoolclient_lambda_role", 33 | "userpoolClientSetAttributes": false, 34 | "sharedId": "249d9f98", 35 | "resourceName": "amplifytodoapp", 36 | "authSelections": "identityPoolAndUserPool", 37 | "authRoleArn": { 38 | "Fn::GetAtt": [ 39 | "AuthRole", 40 | "Arn" 41 | ] 42 | }, 43 | "unauthRoleArn": { 44 | "Fn::GetAtt": [ 45 | "UnauthRole", 46 | "Arn" 47 | ] 48 | }, 49 | "serviceName": "Cognito", 50 | "usernameAttributes": [ 51 | "email" 52 | ], 53 | "useDefault": "manual", 54 | "userPoolGroups": false, 55 | "userPoolGroupList": [], 56 | "adminQueries": false, 57 | "thirdPartyAuth": false, 58 | "authProviders": [], 59 | "usernameCaseSensitive": false, 60 | "dependsOn": [] 61 | } -------------------------------------------------------------------------------- /amplify/backend/backend-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "amplifytodoapp": { 4 | "service": "Cognito", 5 | "providerPlugin": "awscloudformation", 6 | "dependsOn": [], 7 | "customAuth": false 8 | } 9 | }, 10 | "api": { 11 | "amplifytodoapp": { 12 | "service": "AppSync", 13 | "providerPlugin": "awscloudformation", 14 | "output": { 15 | "authConfig": { 16 | "defaultAuthentication": { 17 | "authenticationType": "API_KEY", 18 | "apiKeyConfig": { 19 | "apiKeyExpirationDays": 365, 20 | "description": "ToDoAPIKey" 21 | } 22 | }, 23 | "additionalAuthenticationProviders": [] 24 | } 25 | } 26 | } 27 | }, 28 | "analytics": { 29 | "amplifytodoapp": { 30 | "service": "Pinpoint", 31 | "providerPlugin": "awscloudformation" 32 | } 33 | }, 34 | "storage": { 35 | "s385ebe3d5": { 36 | "service": "S3", 37 | "providerPlugin": "awscloudformation" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /amplify/backend/storage/s385ebe3d5/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "bucketName": "amplifytodoapp09fdff3699294a6c95477320411e6ed6", 3 | "authPolicyName": "s3_amplify_85ebe3d5", 4 | "unauthPolicyName": "s3_amplify_85ebe3d5", 5 | "authRoleName": { 6 | "Ref": "AuthRoleName" 7 | }, 8 | "unauthRoleName": { 9 | "Ref": "UnauthRoleName" 10 | }, 11 | "selectedGuestPermissions": [ 12 | "s3:GetObject", 13 | "s3:ListBucket" 14 | ], 15 | "selectedAuthenticatedPermissions": [ 16 | "s3:PutObject", 17 | "s3:GetObject", 18 | "s3:ListBucket", 19 | "s3:DeleteObject" 20 | ], 21 | "s3PermissionsAuthenticatedPublic": "s3:PutObject,s3:GetObject,s3:DeleteObject", 22 | "s3PublicPolicy": "Public_policy_285916c6", 23 | "s3PermissionsAuthenticatedUploads": "s3:PutObject", 24 | "s3UploadsPolicy": "Uploads_policy_285916c6", 25 | "s3PermissionsAuthenticatedProtected": "s3:PutObject,s3:GetObject,s3:DeleteObject", 26 | "s3ProtectedPolicy": "Protected_policy_285916c6", 27 | "s3PermissionsAuthenticatedPrivate": "s3:PutObject,s3:GetObject,s3:DeleteObject", 28 | "s3PrivatePolicy": "Private_policy_285916c6", 29 | "AuthenticatedAllowList": "ALLOW", 30 | "s3ReadPolicy": "read_policy_285916c6", 31 | "s3PermissionsGuestPublic": "DISALLOW", 32 | "s3PermissionsGuestUploads": "DISALLOW", 33 | "GuestAllowList": "DISALLOW", 34 | "triggerFunction": "NONE" 35 | } -------------------------------------------------------------------------------- /amplify/backend/storage/s385ebe3d5/s3-cloudformation-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "S3 resource stack creation using Amplify CLI", 4 | "Parameters": { 5 | "bucketName": { 6 | "Type": "String" 7 | }, 8 | "authPolicyName": { 9 | "Type": "String" 10 | }, 11 | "unauthPolicyName": { 12 | "Type": "String" 13 | }, 14 | "authRoleName": { 15 | "Type": "String" 16 | }, 17 | "unauthRoleName": { 18 | "Type": "String" 19 | }, 20 | "s3PublicPolicy": { 21 | "Type": "String", 22 | "Default" : "NONE" 23 | }, 24 | "s3PrivatePolicy": { 25 | "Type": "String", 26 | "Default" : "NONE" 27 | }, 28 | "s3ProtectedPolicy": { 29 | "Type": "String", 30 | "Default" : "NONE" 31 | }, 32 | "s3UploadsPolicy": { 33 | "Type": "String", 34 | "Default" : "NONE" 35 | }, 36 | "s3ReadPolicy": { 37 | "Type": "String", 38 | "Default" : "NONE" 39 | }, 40 | "s3PermissionsAuthenticatedPublic": { 41 | "Type": "String", 42 | "Default" : "DISALLOW" 43 | }, 44 | "s3PermissionsAuthenticatedProtected": { 45 | "Type": "String", 46 | "Default" : "DISALLOW" 47 | }, 48 | "s3PermissionsAuthenticatedPrivate": { 49 | "Type": "String", 50 | "Default" : "DISALLOW" 51 | }, 52 | "s3PermissionsAuthenticatedUploads": { 53 | "Type": "String", 54 | "Default" : "DISALLOW" 55 | }, 56 | "s3PermissionsGuestPublic": { 57 | "Type": "String", 58 | "Default" : "DISALLOW" 59 | }, 60 | "s3PermissionsGuestUploads": { 61 | "Type": "String", 62 | "Default" : "DISALLOW" }, 63 | "AuthenticatedAllowList": { 64 | "Type": "String", 65 | "Default" : "DISALLOW" 66 | }, 67 | "GuestAllowList": { 68 | "Type": "String", 69 | "Default" : "DISALLOW" 70 | }, 71 | "selectedGuestPermissions": { 72 | "Type": "CommaDelimitedList", 73 | "Default" : "NONE" 74 | }, 75 | "selectedAuthenticatedPermissions": { 76 | "Type": "CommaDelimitedList", 77 | "Default" : "NONE" 78 | }, 79 | "env": { 80 | "Type": "String" 81 | }, 82 | "triggerFunction": { 83 | "Type": "String" 84 | } 85 | 86 | 87 | }, 88 | "Conditions": { 89 | "ShouldNotCreateEnvResources": { 90 | "Fn::Equals": [ 91 | { 92 | "Ref": "env" 93 | }, 94 | "NONE" 95 | ] 96 | }, 97 | "CreateAuthPublic": { 98 | "Fn::Not" : [{ 99 | "Fn::Equals" : [ 100 | {"Ref" : "s3PermissionsAuthenticatedPublic"}, 101 | "DISALLOW" 102 | ] 103 | }] 104 | }, 105 | "CreateAuthProtected": { 106 | "Fn::Not" : [{ 107 | "Fn::Equals" : [ 108 | {"Ref" : "s3PermissionsAuthenticatedProtected"}, 109 | "DISALLOW" 110 | ] 111 | }] 112 | }, 113 | "CreateAuthPrivate": { 114 | "Fn::Not" : [{ 115 | "Fn::Equals" : [ 116 | {"Ref" : "s3PermissionsAuthenticatedPrivate"}, 117 | "DISALLOW" 118 | ] 119 | }] 120 | }, 121 | "CreateAuthUploads": { 122 | "Fn::Not" : [{ 123 | "Fn::Equals" : [ 124 | {"Ref" : "s3PermissionsAuthenticatedUploads"}, 125 | "DISALLOW" 126 | ] 127 | }] 128 | }, 129 | "CreateGuestPublic": { 130 | "Fn::Not" : [{ 131 | "Fn::Equals" : [ 132 | {"Ref" : "s3PermissionsGuestPublic"}, 133 | "DISALLOW" 134 | ] 135 | }] 136 | }, 137 | "CreateGuestUploads": { 138 | "Fn::Not" : [{ 139 | "Fn::Equals" : [ 140 | {"Ref" : "s3PermissionsGuestUploads"}, 141 | "DISALLOW" 142 | ] 143 | }] 144 | }, 145 | "AuthReadAndList": { 146 | "Fn::Not" : [{ 147 | "Fn::Equals" : [ 148 | {"Ref" : "AuthenticatedAllowList"}, 149 | "DISALLOW" 150 | ] 151 | }] 152 | }, 153 | "GuestReadAndList": { 154 | "Fn::Not" : [{ 155 | "Fn::Equals" : [ 156 | {"Ref" : "GuestAllowList"}, 157 | "DISALLOW" 158 | ] 159 | }] 160 | } 161 | }, 162 | "Resources": { 163 | "S3Bucket": { 164 | "Type": "AWS::S3::Bucket", 165 | 166 | "DeletionPolicy" : "Retain", 167 | "Properties": { 168 | "BucketName": { 169 | "Fn::If": [ 170 | "ShouldNotCreateEnvResources", 171 | { 172 | "Ref": "bucketName" 173 | }, 174 | { 175 | "Fn::Join": [ 176 | "", 177 | [ 178 | { 179 | "Ref": "bucketName" 180 | }, 181 | { 182 | "Fn::Select": [ 183 | 3, 184 | { 185 | "Fn::Split": [ 186 | "-", 187 | { 188 | "Ref": "AWS::StackName" 189 | } 190 | ] 191 | } 192 | ] 193 | }, 194 | "-", 195 | { 196 | "Ref": "env" 197 | } 198 | ] 199 | ] 200 | } 201 | ] 202 | }, 203 | 204 | "CorsConfiguration": { 205 | "CorsRules": [ 206 | { 207 | "AllowedHeaders": [ 208 | "*" 209 | ], 210 | "AllowedMethods": [ 211 | "GET", 212 | "HEAD", 213 | "PUT", 214 | "POST", 215 | "DELETE" 216 | ], 217 | "AllowedOrigins": [ 218 | "*" 219 | ], 220 | "ExposedHeaders": [ 221 | "x-amz-server-side-encryption", 222 | "x-amz-request-id", 223 | "x-amz-id-2", 224 | "ETag" 225 | ], 226 | "Id": "S3CORSRuleId1", 227 | "MaxAge": "3000" 228 | } 229 | ] 230 | } 231 | } 232 | }, 233 | 234 | 235 | "S3AuthPublicPolicy": { 236 | "DependsOn": [ 237 | "S3Bucket" 238 | ], 239 | "Condition": "CreateAuthPublic", 240 | "Type": "AWS::IAM::Policy", 241 | "Properties": { 242 | "PolicyName": { 243 | "Ref": "s3PublicPolicy" 244 | }, 245 | "Roles": [ 246 | { 247 | "Ref": "authRoleName" 248 | } 249 | ], 250 | "PolicyDocument": { 251 | "Version": "2012-10-17", 252 | "Statement": [ 253 | { 254 | "Effect": "Allow", 255 | "Action": { 256 | "Fn::Split" : [ "," , { 257 | "Ref": "s3PermissionsAuthenticatedPublic" 258 | } ] 259 | }, 260 | "Resource": [ 261 | { 262 | "Fn::Join": [ 263 | "", 264 | [ 265 | "arn:aws:s3:::", 266 | { 267 | "Ref": "S3Bucket" 268 | }, 269 | "/public/*" 270 | ] 271 | ] 272 | } 273 | ] 274 | } 275 | ] 276 | } 277 | } 278 | }, 279 | "S3AuthProtectedPolicy": { 280 | "DependsOn": [ 281 | "S3Bucket" 282 | ], 283 | "Condition": "CreateAuthProtected", 284 | "Type": "AWS::IAM::Policy", 285 | "Properties": { 286 | "PolicyName": { 287 | "Ref": "s3ProtectedPolicy" 288 | }, 289 | "Roles": [ 290 | { 291 | "Ref": "authRoleName" 292 | } 293 | ], 294 | "PolicyDocument": { 295 | "Version": "2012-10-17", 296 | "Statement": [ 297 | { 298 | "Effect": "Allow", 299 | "Action": { 300 | "Fn::Split" : [ "," , { 301 | "Ref": "s3PermissionsAuthenticatedProtected" 302 | } ] 303 | }, 304 | "Resource": [ 305 | { 306 | "Fn::Join": [ 307 | "", 308 | [ 309 | "arn:aws:s3:::", 310 | { 311 | "Ref": "S3Bucket" 312 | }, 313 | "/protected/${cognito-identity.amazonaws.com:sub}/*" 314 | ] 315 | ] 316 | } 317 | ] 318 | } 319 | ] 320 | } 321 | } 322 | }, 323 | "S3AuthPrivatePolicy": { 324 | "DependsOn": [ 325 | "S3Bucket" 326 | ], 327 | "Condition": "CreateAuthPrivate", 328 | "Type": "AWS::IAM::Policy", 329 | "Properties": { 330 | "PolicyName": { 331 | "Ref": "s3PrivatePolicy" 332 | }, 333 | "Roles": [ 334 | { 335 | "Ref": "authRoleName" 336 | } 337 | ], 338 | "PolicyDocument": { 339 | "Version": "2012-10-17", 340 | "Statement": [ 341 | { 342 | "Effect": "Allow", 343 | "Action": { 344 | "Fn::Split" : [ "," , { 345 | "Ref": "s3PermissionsAuthenticatedPrivate" 346 | } ] 347 | }, 348 | "Resource": [ 349 | { 350 | "Fn::Join": [ 351 | "", 352 | [ 353 | "arn:aws:s3:::", 354 | { 355 | "Ref": "S3Bucket" 356 | }, 357 | "/private/${cognito-identity.amazonaws.com:sub}/*" 358 | ] 359 | ] 360 | } 361 | ] 362 | } 363 | ] 364 | } 365 | } 366 | }, 367 | "S3AuthUploadPolicy": { 368 | "DependsOn": [ 369 | "S3Bucket" 370 | ], 371 | "Condition": "CreateAuthUploads", 372 | "Type": "AWS::IAM::Policy", 373 | "Properties": { 374 | "PolicyName": { 375 | "Ref": "s3UploadsPolicy" 376 | }, 377 | "Roles": [ 378 | { 379 | "Ref": "authRoleName" 380 | } 381 | ], 382 | "PolicyDocument": { 383 | "Version": "2012-10-17", 384 | "Statement": [ 385 | { 386 | "Effect": "Allow", 387 | "Action": { 388 | "Fn::Split" : [ "," , { 389 | "Ref": "s3PermissionsAuthenticatedUploads" 390 | } ] 391 | }, 392 | "Resource": [ 393 | { 394 | "Fn::Join": [ 395 | "", 396 | [ 397 | "arn:aws:s3:::", 398 | { 399 | "Ref": "S3Bucket" 400 | }, 401 | "/uploads/*" 402 | ] 403 | ] 404 | } 405 | ] 406 | } 407 | ] 408 | } 409 | } 410 | }, 411 | "S3AuthReadPolicy": { 412 | "DependsOn": [ 413 | "S3Bucket" 414 | ], 415 | "Condition": "AuthReadAndList", 416 | "Type": "AWS::IAM::Policy", 417 | "Properties": { 418 | "PolicyName": { 419 | "Ref": "s3ReadPolicy" 420 | }, 421 | "Roles": [ 422 | { 423 | "Ref": "authRoleName" 424 | } 425 | ], 426 | "PolicyDocument": { 427 | "Version": "2012-10-17", 428 | "Statement": [ 429 | { 430 | "Effect": "Allow", 431 | "Action": [ 432 | "s3:GetObject" 433 | ], 434 | "Resource": [ 435 | { 436 | "Fn::Join": [ 437 | "", 438 | [ 439 | "arn:aws:s3:::", 440 | { 441 | "Ref": "S3Bucket" 442 | }, 443 | "/protected/*" 444 | ] 445 | ] 446 | } 447 | ] 448 | }, 449 | { 450 | "Effect": "Allow", 451 | "Action": [ 452 | "s3:ListBucket" 453 | ], 454 | "Resource": [ 455 | { 456 | "Fn::Join": [ 457 | "", 458 | [ 459 | "arn:aws:s3:::", 460 | { 461 | "Ref": "S3Bucket" 462 | } 463 | ] 464 | ] 465 | } 466 | ], 467 | "Condition": { 468 | "StringLike": { 469 | "s3:prefix": [ 470 | "public/", 471 | "public/*", 472 | "protected/", 473 | "protected/*", 474 | "private/${cognito-identity.amazonaws.com:sub}/", 475 | "private/${cognito-identity.amazonaws.com:sub}/*" 476 | ] 477 | } 478 | } 479 | } 480 | ] 481 | } 482 | } 483 | }, 484 | "S3GuestPublicPolicy": { 485 | "DependsOn": [ 486 | "S3Bucket" 487 | ], 488 | "Condition": "CreateGuestPublic", 489 | "Type": "AWS::IAM::Policy", 490 | "Properties": { 491 | "PolicyName": { 492 | "Ref": "s3PublicPolicy" 493 | }, 494 | "Roles": [ 495 | { 496 | "Ref": "unauthRoleName" 497 | } 498 | ], 499 | "PolicyDocument": { 500 | "Version": "2012-10-17", 501 | "Statement": [ 502 | { 503 | "Effect": "Allow", 504 | "Action": { 505 | "Fn::Split" : [ "," , { 506 | "Ref": "s3PermissionsGuestPublic" 507 | } ] 508 | }, 509 | "Resource": [ 510 | { 511 | "Fn::Join": [ 512 | "", 513 | [ 514 | "arn:aws:s3:::", 515 | { 516 | "Ref": "S3Bucket" 517 | }, 518 | "/public/*" 519 | ] 520 | ] 521 | } 522 | ] 523 | } 524 | ] 525 | } 526 | } 527 | }, 528 | "S3GuestUploadPolicy": { 529 | "DependsOn": [ 530 | "S3Bucket" 531 | ], 532 | "Condition": "CreateGuestUploads", 533 | "Type": "AWS::IAM::Policy", 534 | "Properties": { 535 | "PolicyName": { 536 | "Ref": "s3UploadsPolicy" 537 | }, 538 | "Roles": [ 539 | { 540 | "Ref": "unauthRoleName" 541 | } 542 | ], 543 | "PolicyDocument": { 544 | "Version": "2012-10-17", 545 | "Statement": [ 546 | { 547 | "Effect": "Allow", 548 | "Action": { 549 | "Fn::Split" : [ "," , { 550 | "Ref": "s3PermissionsGuestUploads" 551 | } ] 552 | }, 553 | "Resource": [ 554 | { 555 | "Fn::Join": [ 556 | "", 557 | [ 558 | "arn:aws:s3:::", 559 | { 560 | "Ref": "S3Bucket" 561 | }, 562 | "/uploads/*" 563 | ] 564 | ] 565 | } 566 | ] 567 | } 568 | ] 569 | } 570 | } 571 | }, 572 | "S3GuestReadPolicy": { 573 | "DependsOn": [ 574 | "S3Bucket" 575 | ], 576 | "Condition": "GuestReadAndList", 577 | "Type": "AWS::IAM::Policy", 578 | "Properties": { 579 | "PolicyName": { 580 | "Ref": "s3ReadPolicy" 581 | }, 582 | "Roles": [ 583 | { 584 | "Ref": "unauthRoleName" 585 | } 586 | ], 587 | "PolicyDocument": { 588 | "Version": "2012-10-17", 589 | "Statement": [ 590 | { 591 | "Effect": "Allow", 592 | "Action": [ 593 | "s3:GetObject" 594 | ], 595 | "Resource": [ 596 | { 597 | "Fn::Join": [ 598 | "", 599 | [ 600 | "arn:aws:s3:::", 601 | { 602 | "Ref": "S3Bucket" 603 | }, 604 | "/protected/*" 605 | ] 606 | ] 607 | } 608 | ] 609 | }, 610 | { 611 | "Effect": "Allow", 612 | "Action": [ 613 | "s3:ListBucket" 614 | ], 615 | "Resource": [ 616 | { 617 | "Fn::Join": [ 618 | "", 619 | [ 620 | "arn:aws:s3:::", 621 | { 622 | "Ref": "S3Bucket" 623 | } 624 | ] 625 | ] 626 | } 627 | ], 628 | "Condition": { 629 | "StringLike": { 630 | "s3:prefix": [ 631 | "public/", 632 | "public/*", 633 | "protected/", 634 | "protected/*" 635 | ] 636 | } 637 | } 638 | } 639 | ] 640 | } 641 | } 642 | } 643 | }, 644 | "Outputs": { 645 | "BucketName": { 646 | "Value": { 647 | "Ref": "S3Bucket" 648 | }, 649 | "Description": "Bucket name for the S3 bucket" 650 | }, 651 | "Region": { 652 | "Value": { 653 | "Ref": "AWS::Region" 654 | } 655 | } 656 | } 657 | } 658 | -------------------------------------------------------------------------------- /amplify/backend/storage/s385ebe3d5/storage-params.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /amplify/backend/tags.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Key": "user:Stack", 4 | "Value": "{project-env}" 5 | }, 6 | { 7 | "Key": "user:Application", 8 | "Value": "{project-name}" 9 | } 10 | ] -------------------------------------------------------------------------------- /amplify/cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "features": { 3 | "graphqltransformer": { 4 | "addmissingownerfields": true, 5 | "validatetypenamereservedwords": true, 6 | "useexperimentalpipelinedtransformer": false, 7 | "enableiterativegsiupdates": true, 8 | "secondarykeyasgsi": true, 9 | "skipoverridemutationinputtypes": true 10 | }, 11 | "frontend-ios": { 12 | "enablexcodeintegration": true 13 | }, 14 | "auth": { 15 | "enablecaseinsensitivity": true, 16 | "useinclusiveterminology": true 17 | }, 18 | "codegen": { 19 | "useappsyncmodelgenplugin": true, 20 | "usedocsgeneratorplugin": true, 21 | "usetypesgeneratorplugin": true, 22 | "cleangeneratedmodelsdirectory": true, 23 | "retaincasestyle": true, 24 | "enableDartNullSafety": true 25 | }, 26 | "appsync": { 27 | "generategraphqlpermissions": true 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /amplify/team-provider-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "staging": { 3 | "awscloudformation": { 4 | "AuthRoleName": "amplify-amplifytodoapp-staging-221527-authRole", 5 | "UnauthRoleArn": "arn:aws:iam::279012124572:role/amplify-amplifytodoapp-staging-221527-unauthRole", 6 | "AuthRoleArn": "arn:aws:iam::279012124572:role/amplify-amplifytodoapp-staging-221527-authRole", 7 | "Region": "us-east-1", 8 | "DeploymentBucketName": "amplify-amplifytodoapp-staging-221527-deployment", 9 | "UnauthRoleName": "amplify-amplifytodoapp-staging-221527-unauthRole", 10 | "StackName": "amplify-amplifytodoapp-staging-221527", 11 | "StackId": "arn:aws:cloudformation:us-east-1:279012124572:stack/amplify-amplifytodoapp-staging-221527/ba4f1900-af81-11eb-b8f5-0e892a71c9a9", 12 | "AmplifyAppId": "d56396euhmf0k" 13 | }, 14 | "categories": { 15 | "auth": { 16 | "amplifytodoapp": {} 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /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 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.example.amplify_todo" 38 | minSdkVersion 16 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/amplify_todo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.amplify_todo 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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:4.1.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 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /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-6.7-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /images/amazon-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/images/amazon-logo.png -------------------------------------------------------------------------------- /images/applogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/images/applogo.png -------------------------------------------------------------------------------- /images/aws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/images/aws.png -------------------------------------------------------------------------------- /images/facebook-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/images/facebook-logo.png -------------------------------------------------------------------------------- /images/google-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/images/google-logo.png -------------------------------------------------------------------------------- /images/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/images/profile.png -------------------------------------------------------------------------------- /images/profile_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/images/profile_image.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '13.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Amplify (1.11.0): 3 | - Amplify/Default (= 1.11.0) 4 | - Amplify/Default (1.11.0) 5 | - amplify_analytics_pinpoint (0.0.1): 6 | - Amplify (~> 1.11.0) 7 | - amplify_core 8 | - AmplifyPlugins/AWSPinpointAnalyticsPlugin (~> 1.11.0) 9 | - Flutter 10 | - amplify_api (0.0.1): 11 | - Amplify (~> 1.11.0) 12 | - amplify_core 13 | - AmplifyPlugins/AWSAPIPlugin (~> 1.11.0) 14 | - Flutter 15 | - amplify_auth_cognito (0.0.1): 16 | - Amplify (~> 1.11.0) 17 | - amplify_core 18 | - AmplifyPlugins/AWSCognitoAuthPlugin (~> 1.11.0) 19 | - Flutter 20 | - ObjectMapper 21 | - amplify_core (0.0.1): 22 | - Flutter 23 | - amplify_datastore (0.0.1): 24 | - Amplify (~> 1.11.0) 25 | - amplify_core 26 | - AmplifyPlugins/AWSDataStorePlugin (~> 1.11.0) 27 | - Flutter 28 | - amplify_flutter (0.0.1): 29 | - Amplify (~> 1.11.0) 30 | - amplify_core 31 | - AmplifyPlugins/AWSCognitoAuthPlugin (~> 1.11.0) 32 | - AWSPluginsCore (~> 1.11.0) 33 | - Flutter 34 | - amplify_storage_s3 (0.0.1): 35 | - Amplify (~> 1.11.0) 36 | - amplify_core 37 | - AmplifyPlugins/AWSS3StoragePlugin (~> 1.11.0) 38 | - Flutter 39 | - AmplifyPlugins/AWSAPIPlugin (1.11.0): 40 | - AppSyncRealTimeClient (~> 1.4) 41 | - AWSCore (~> 2.24.0) 42 | - AWSPluginsCore (= 1.11.0) 43 | - AmplifyPlugins/AWSCognitoAuthPlugin (1.11.0): 44 | - AWSAuthCore (~> 2.24.0) 45 | - AWSCognitoIdentityProvider (~> 2.24.0) 46 | - AWSCognitoIdentityProviderASF (~> 2.24.0) 47 | - AWSCore (~> 2.24.0) 48 | - AWSMobileClient (~> 2.24.0) 49 | - AWSPluginsCore (= 1.11.0) 50 | - AmplifyPlugins/AWSDataStorePlugin (1.11.0): 51 | - AWSCore (~> 2.24.0) 52 | - AWSPluginsCore (= 1.11.0) 53 | - SQLite.swift (= 0.12.2) 54 | - AmplifyPlugins/AWSPinpointAnalyticsPlugin (1.11.0): 55 | - AWSCore (~> 2.24.0) 56 | - AWSPinpoint (~> 2.24.0) 57 | - AWSPluginsCore (= 1.11.0) 58 | - AmplifyPlugins/AWSS3StoragePlugin (1.11.0): 59 | - AWSCore (~> 2.24.0) 60 | - AWSPluginsCore (= 1.11.0) 61 | - AWSS3 (~> 2.24.0) 62 | - AppSyncRealTimeClient (1.5.0): 63 | - Starscream (~> 3.1.1) 64 | - AWSAuthCore (2.24.2): 65 | - AWSCore (= 2.24.2) 66 | - AWSCognitoIdentityProvider (2.24.2): 67 | - AWSCognitoIdentityProviderASF (= 2.24.2) 68 | - AWSCore (= 2.24.2) 69 | - AWSCognitoIdentityProviderASF (2.24.2) 70 | - AWSCore (2.24.2) 71 | - AWSMobileClient (2.24.2): 72 | - AWSAuthCore (= 2.24.2) 73 | - AWSCognitoIdentityProvider (= 2.24.2) 74 | - AWSCognitoIdentityProviderASF (= 2.24.2) 75 | - AWSCore (= 2.24.2) 76 | - AWSPinpoint (2.24.2): 77 | - AWSCore (= 2.24.2) 78 | - AWSPluginsCore (1.11.0): 79 | - Amplify (= 1.11.0) 80 | - AWSCore (~> 2.24.0) 81 | - AWSS3 (2.24.2): 82 | - AWSCore (= 2.24.2) 83 | - Flutter (1.0.0) 84 | - image_picker (0.0.1): 85 | - Flutter 86 | - ObjectMapper (4.2.0) 87 | - SQLite.swift (0.12.2): 88 | - SQLite.swift/standard (= 0.12.2) 89 | - SQLite.swift/standard (0.12.2) 90 | - Starscream (3.1.1) 91 | 92 | DEPENDENCIES: 93 | - amplify_analytics_pinpoint (from `.symlinks/plugins/amplify_analytics_pinpoint/ios`) 94 | - amplify_api (from `.symlinks/plugins/amplify_api/ios`) 95 | - amplify_auth_cognito (from `.symlinks/plugins/amplify_auth_cognito/ios`) 96 | - amplify_core (from `.symlinks/plugins/amplify_core/ios`) 97 | - amplify_datastore (from `.symlinks/plugins/amplify_datastore/ios`) 98 | - amplify_flutter (from `.symlinks/plugins/amplify_flutter/ios`) 99 | - amplify_storage_s3 (from `.symlinks/plugins/amplify_storage_s3/ios`) 100 | - Flutter (from `Flutter`) 101 | - image_picker (from `.symlinks/plugins/image_picker/ios`) 102 | 103 | SPEC REPOS: 104 | trunk: 105 | - Amplify 106 | - AmplifyPlugins 107 | - AppSyncRealTimeClient 108 | - AWSAuthCore 109 | - AWSCognitoIdentityProvider 110 | - AWSCognitoIdentityProviderASF 111 | - AWSCore 112 | - AWSMobileClient 113 | - AWSPinpoint 114 | - AWSPluginsCore 115 | - AWSS3 116 | - ObjectMapper 117 | - SQLite.swift 118 | - Starscream 119 | 120 | EXTERNAL SOURCES: 121 | amplify_analytics_pinpoint: 122 | :path: ".symlinks/plugins/amplify_analytics_pinpoint/ios" 123 | amplify_api: 124 | :path: ".symlinks/plugins/amplify_api/ios" 125 | amplify_auth_cognito: 126 | :path: ".symlinks/plugins/amplify_auth_cognito/ios" 127 | amplify_core: 128 | :path: ".symlinks/plugins/amplify_core/ios" 129 | amplify_datastore: 130 | :path: ".symlinks/plugins/amplify_datastore/ios" 131 | amplify_flutter: 132 | :path: ".symlinks/plugins/amplify_flutter/ios" 133 | amplify_storage_s3: 134 | :path: ".symlinks/plugins/amplify_storage_s3/ios" 135 | Flutter: 136 | :path: Flutter 137 | image_picker: 138 | :path: ".symlinks/plugins/image_picker/ios" 139 | 140 | SPEC CHECKSUMS: 141 | Amplify: cf25ee17b0762b3bacd4d4d49891ddada6bee912 142 | amplify_analytics_pinpoint: 883dfa68ed6688c0c75c9b8f1733da7a0f5e2e94 143 | amplify_api: 5ef7294d41dadf25acb1c145869931d82022a9b2 144 | amplify_auth_cognito: 38761b51a433d49ecf5927de45488fcbf81a8c29 145 | amplify_core: 8b38d20089fe4f225c14db6892f586bd03824a42 146 | amplify_datastore: c0f2bcf9410731862612c986a9f331cb4f8691e4 147 | amplify_flutter: 77665b732c1b8d04ed7f3eeb5a743f0b75838db1 148 | amplify_storage_s3: 703f62456f65b84aed6f29d73427ed5581056c00 149 | AmplifyPlugins: bb73475de41297a7244e8f3fdbf40cdad8115048 150 | AppSyncRealTimeClient: 2b4482b1770a3e5cf64f9714a6d198550017b5a2 151 | AWSAuthCore: d2cb921db598ea03d67284977a3c691e9a1aee83 152 | AWSCognitoIdentityProvider: f9d68c563718fa5aa76e077752df06c73810efba 153 | AWSCognitoIdentityProviderASF: 21681469334e286df6e5470f3cbab3b10edbf818 154 | AWSCore: 08a61ac2b1d98b2d43f59ee40c4bd68e58dfdea3 155 | AWSMobileClient: 6af7fff9e58f8d427acf3381cbbae2f0c34d52ab 156 | AWSPinpoint: a422ed2d24e0cc94499aaf60e2fbb7666954c8bf 157 | AWSPluginsCore: 1670f03a8612d60bd84c541ffa34f538e4037052 158 | AWSS3: 1782d0db43a1219a118ea6263d4ea01f76f8cdf4 159 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c 160 | image_picker: e06f7a68f000bd36f552c1847e33cda96ed31f1f 161 | ObjectMapper: 1eb41f610210777375fa806bf161dc39fb832b81 162 | SQLite.swift: d2b4642190917051ce6bd1d49aab565fe794eea3 163 | Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0 164 | 165 | PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b 166 | 167 | COCOAPODS: 1.10.1 168 | -------------------------------------------------------------------------------- /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 | 16DA5870F6ED87EA2DE88B19 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA0985E0B2368CC61C1400E8 /* Pods_Runner.framework */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 0A0D6664BD51D2C2E75DE271 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 34 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 35 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 37 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 38 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 39 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 40 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 41 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 42 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | A2DA71C38B5950A3E2760C33 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 48 | EA0985E0B2368CC61C1400E8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | EF673D65B93492E61B5E635B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 16DA5870F6ED87EA2DE88B19 /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 4A1B0A4DFC32ACE0EC95140A /* Frameworks */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | EA0985E0B2368CC61C1400E8 /* Pods_Runner.framework */, 68 | ); 69 | name = Frameworks; 70 | sourceTree = ""; 71 | }; 72 | 9740EEB11CF90186004384FC /* Flutter */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 76 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 77 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 78 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 79 | ); 80 | name = Flutter; 81 | sourceTree = ""; 82 | }; 83 | 97C146E51CF9000F007C117D = { 84 | isa = PBXGroup; 85 | children = ( 86 | 9740EEB11CF90186004384FC /* Flutter */, 87 | 97C146F01CF9000F007C117D /* Runner */, 88 | 97C146EF1CF9000F007C117D /* Products */, 89 | BB8AA0EDE6249BB31E2AEC14 /* Pods */, 90 | 4A1B0A4DFC32ACE0EC95140A /* Frameworks */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 97C146EF1CF9000F007C117D /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146EE1CF9000F007C117D /* Runner.app */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 97C146F01CF9000F007C117D /* Runner */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 106 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 107 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 108 | 97C147021CF9000F007C117D /* Info.plist */, 109 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 110 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 111 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 112 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 113 | ); 114 | path = Runner; 115 | sourceTree = ""; 116 | }; 117 | BB8AA0EDE6249BB31E2AEC14 /* Pods */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | A2DA71C38B5950A3E2760C33 /* Pods-Runner.debug.xcconfig */, 121 | 0A0D6664BD51D2C2E75DE271 /* Pods-Runner.release.xcconfig */, 122 | EF673D65B93492E61B5E635B /* Pods-Runner.profile.xcconfig */, 123 | ); 124 | name = Pods; 125 | path = Pods; 126 | sourceTree = ""; 127 | }; 128 | /* End PBXGroup section */ 129 | 130 | /* Begin PBXNativeTarget section */ 131 | 97C146ED1CF9000F007C117D /* Runner */ = { 132 | isa = PBXNativeTarget; 133 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 134 | buildPhases = ( 135 | 63EC73F7852E3FAE8251129D /* [CP] Check Pods Manifest.lock */, 136 | 9740EEB61CF901F6004384FC /* Run Script */, 137 | 97C146EA1CF9000F007C117D /* Sources */, 138 | 97C146EB1CF9000F007C117D /* Frameworks */, 139 | 97C146EC1CF9000F007C117D /* Resources */, 140 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 142 | A5DE5287E6AB7243D569807B /* [CP] Embed Pods Frameworks */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = Runner; 149 | productName = Runner; 150 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 151 | productType = "com.apple.product-type.application"; 152 | }; 153 | /* End PBXNativeTarget section */ 154 | 155 | /* Begin PBXProject section */ 156 | 97C146E61CF9000F007C117D /* Project object */ = { 157 | isa = PBXProject; 158 | attributes = { 159 | LastUpgradeCheck = 1020; 160 | ORGANIZATIONNAME = ""; 161 | TargetAttributes = { 162 | 97C146ED1CF9000F007C117D = { 163 | CreatedOnToolsVersion = 7.3.1; 164 | LastSwiftMigration = 1100; 165 | }; 166 | }; 167 | }; 168 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 169 | compatibilityVersion = "Xcode 9.3"; 170 | developmentRegion = en; 171 | hasScannedForEncodings = 0; 172 | knownRegions = ( 173 | en, 174 | Base, 175 | ); 176 | mainGroup = 97C146E51CF9000F007C117D; 177 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 178 | projectDirPath = ""; 179 | projectRoot = ""; 180 | targets = ( 181 | 97C146ED1CF9000F007C117D /* Runner */, 182 | ); 183 | }; 184 | /* End PBXProject section */ 185 | 186 | /* Begin PBXResourcesBuildPhase section */ 187 | 97C146EC1CF9000F007C117D /* Resources */ = { 188 | isa = PBXResourcesBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 192 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 193 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | /* End PBXResourcesBuildPhase section */ 199 | 200 | /* Begin PBXShellScriptBuildPhase section */ 201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 202 | isa = PBXShellScriptBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | ); 206 | inputPaths = ( 207 | ); 208 | name = "Thin Binary"; 209 | outputPaths = ( 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | shellPath = /bin/sh; 213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 214 | }; 215 | 63EC73F7852E3FAE8251129D /* [CP] Check Pods Manifest.lock */ = { 216 | isa = PBXShellScriptBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | ); 220 | inputFileListPaths = ( 221 | ); 222 | inputPaths = ( 223 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 224 | "${PODS_ROOT}/Manifest.lock", 225 | ); 226 | name = "[CP] Check Pods Manifest.lock"; 227 | outputFileListPaths = ( 228 | ); 229 | outputPaths = ( 230 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | shellPath = /bin/sh; 234 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 235 | showEnvVarsInLog = 0; 236 | }; 237 | 9740EEB61CF901F6004384FC /* Run Script */ = { 238 | isa = PBXShellScriptBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | ); 242 | inputPaths = ( 243 | ); 244 | name = "Run Script"; 245 | outputPaths = ( 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | shellPath = /bin/sh; 249 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 250 | }; 251 | A5DE5287E6AB7243D569807B /* [CP] Embed Pods Frameworks */ = { 252 | isa = PBXShellScriptBuildPhase; 253 | buildActionMask = 2147483647; 254 | files = ( 255 | ); 256 | inputFileListPaths = ( 257 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 258 | ); 259 | name = "[CP] Embed Pods Frameworks"; 260 | outputFileListPaths = ( 261 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | shellPath = /bin/sh; 265 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 266 | showEnvVarsInLog = 0; 267 | }; 268 | /* End PBXShellScriptBuildPhase section */ 269 | 270 | /* Begin PBXSourcesBuildPhase section */ 271 | 97C146EA1CF9000F007C117D /* Sources */ = { 272 | isa = PBXSourcesBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 276 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXSourcesBuildPhase section */ 281 | 282 | /* Begin PBXVariantGroup section */ 283 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 284 | isa = PBXVariantGroup; 285 | children = ( 286 | 97C146FB1CF9000F007C117D /* Base */, 287 | ); 288 | name = Main.storyboard; 289 | sourceTree = ""; 290 | }; 291 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 292 | isa = PBXVariantGroup; 293 | children = ( 294 | 97C147001CF9000F007C117D /* Base */, 295 | ); 296 | name = LaunchScreen.storyboard; 297 | sourceTree = ""; 298 | }; 299 | /* End PBXVariantGroup section */ 300 | 301 | /* Begin XCBuildConfiguration section */ 302 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 333 | ENABLE_NS_ASSERTIONS = NO; 334 | ENABLE_STRICT_OBJC_MSGSEND = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_NO_COMMON_BLOCKS = YES; 337 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 338 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 339 | GCC_WARN_UNDECLARED_SELECTOR = YES; 340 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 341 | GCC_WARN_UNUSED_FUNCTION = YES; 342 | GCC_WARN_UNUSED_VARIABLE = YES; 343 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 344 | MTL_ENABLE_DEBUG_INFO = NO; 345 | SDKROOT = iphoneos; 346 | SUPPORTED_PLATFORMS = iphoneos; 347 | TARGETED_DEVICE_FAMILY = "1,2"; 348 | VALIDATE_PRODUCT = YES; 349 | }; 350 | name = Profile; 351 | }; 352 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 353 | isa = XCBuildConfiguration; 354 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 355 | buildSettings = { 356 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 357 | CLANG_ENABLE_MODULES = YES; 358 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 359 | ENABLE_BITCODE = NO; 360 | INFOPLIST_FILE = Runner/Info.plist; 361 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 362 | PRODUCT_BUNDLE_IDENTIFIER = com.example.amplifyTodo; 363 | PRODUCT_NAME = "$(TARGET_NAME)"; 364 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 365 | SWIFT_VERSION = 5.0; 366 | VERSIONING_SYSTEM = "apple-generic"; 367 | }; 368 | name = Profile; 369 | }; 370 | 97C147031CF9000F007C117D /* Debug */ = { 371 | isa = XCBuildConfiguration; 372 | buildSettings = { 373 | ALWAYS_SEARCH_USER_PATHS = NO; 374 | CLANG_ANALYZER_NONNULL = YES; 375 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 376 | CLANG_CXX_LIBRARY = "libc++"; 377 | CLANG_ENABLE_MODULES = YES; 378 | CLANG_ENABLE_OBJC_ARC = YES; 379 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 380 | CLANG_WARN_BOOL_CONVERSION = YES; 381 | CLANG_WARN_COMMA = YES; 382 | CLANG_WARN_CONSTANT_CONVERSION = YES; 383 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 384 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 385 | CLANG_WARN_EMPTY_BODY = YES; 386 | CLANG_WARN_ENUM_CONVERSION = YES; 387 | CLANG_WARN_INFINITE_RECURSION = YES; 388 | CLANG_WARN_INT_CONVERSION = YES; 389 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 390 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 391 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 392 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 393 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 394 | CLANG_WARN_STRICT_PROTOTYPES = YES; 395 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 396 | CLANG_WARN_UNREACHABLE_CODE = YES; 397 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 398 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 399 | COPY_PHASE_STRIP = NO; 400 | DEBUG_INFORMATION_FORMAT = dwarf; 401 | ENABLE_STRICT_OBJC_MSGSEND = YES; 402 | ENABLE_TESTABILITY = YES; 403 | GCC_C_LANGUAGE_STANDARD = gnu99; 404 | GCC_DYNAMIC_NO_PIC = NO; 405 | GCC_NO_COMMON_BLOCKS = YES; 406 | GCC_OPTIMIZATION_LEVEL = 0; 407 | GCC_PREPROCESSOR_DEFINITIONS = ( 408 | "DEBUG=1", 409 | "$(inherited)", 410 | ); 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 = 9.0; 418 | MTL_ENABLE_DEBUG_INFO = YES; 419 | ONLY_ACTIVE_ARCH = YES; 420 | SDKROOT = iphoneos; 421 | TARGETED_DEVICE_FAMILY = "1,2"; 422 | }; 423 | name = Debug; 424 | }; 425 | 97C147041CF9000F007C117D /* Release */ = { 426 | isa = XCBuildConfiguration; 427 | buildSettings = { 428 | ALWAYS_SEARCH_USER_PATHS = NO; 429 | CLANG_ANALYZER_NONNULL = YES; 430 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 431 | CLANG_CXX_LIBRARY = "libc++"; 432 | CLANG_ENABLE_MODULES = YES; 433 | CLANG_ENABLE_OBJC_ARC = YES; 434 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 435 | CLANG_WARN_BOOL_CONVERSION = YES; 436 | CLANG_WARN_COMMA = YES; 437 | CLANG_WARN_CONSTANT_CONVERSION = YES; 438 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 439 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 440 | CLANG_WARN_EMPTY_BODY = YES; 441 | CLANG_WARN_ENUM_CONVERSION = YES; 442 | CLANG_WARN_INFINITE_RECURSION = YES; 443 | CLANG_WARN_INT_CONVERSION = YES; 444 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 445 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 446 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 447 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 448 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 449 | CLANG_WARN_STRICT_PROTOTYPES = YES; 450 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 451 | CLANG_WARN_UNREACHABLE_CODE = YES; 452 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 453 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 454 | COPY_PHASE_STRIP = NO; 455 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 456 | ENABLE_NS_ASSERTIONS = NO; 457 | ENABLE_STRICT_OBJC_MSGSEND = YES; 458 | GCC_C_LANGUAGE_STANDARD = gnu99; 459 | GCC_NO_COMMON_BLOCKS = YES; 460 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 461 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 462 | GCC_WARN_UNDECLARED_SELECTOR = YES; 463 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 464 | GCC_WARN_UNUSED_FUNCTION = YES; 465 | GCC_WARN_UNUSED_VARIABLE = YES; 466 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 467 | MTL_ENABLE_DEBUG_INFO = NO; 468 | SDKROOT = iphoneos; 469 | SUPPORTED_PLATFORMS = iphoneos; 470 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 471 | TARGETED_DEVICE_FAMILY = "1,2"; 472 | VALIDATE_PRODUCT = YES; 473 | }; 474 | name = Release; 475 | }; 476 | 97C147061CF9000F007C117D /* Debug */ = { 477 | isa = XCBuildConfiguration; 478 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 479 | buildSettings = { 480 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 481 | CLANG_ENABLE_MODULES = YES; 482 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 483 | ENABLE_BITCODE = NO; 484 | INFOPLIST_FILE = Runner/Info.plist; 485 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 486 | PRODUCT_BUNDLE_IDENTIFIER = com.example.amplifyTodo; 487 | PRODUCT_NAME = "$(TARGET_NAME)"; 488 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 489 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 490 | SWIFT_VERSION = 5.0; 491 | VERSIONING_SYSTEM = "apple-generic"; 492 | }; 493 | name = Debug; 494 | }; 495 | 97C147071CF9000F007C117D /* Release */ = { 496 | isa = XCBuildConfiguration; 497 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 498 | buildSettings = { 499 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 500 | CLANG_ENABLE_MODULES = YES; 501 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 502 | ENABLE_BITCODE = NO; 503 | INFOPLIST_FILE = Runner/Info.plist; 504 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 505 | PRODUCT_BUNDLE_IDENTIFIER = com.example.amplifyTodo; 506 | PRODUCT_NAME = "$(TARGET_NAME)"; 507 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 508 | SWIFT_VERSION = 5.0; 509 | VERSIONING_SYSTEM = "apple-generic"; 510 | }; 511 | name = Release; 512 | }; 513 | /* End XCBuildConfiguration section */ 514 | 515 | /* Begin XCConfigurationList section */ 516 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 517 | isa = XCConfigurationList; 518 | buildConfigurations = ( 519 | 97C147031CF9000F007C117D /* Debug */, 520 | 97C147041CF9000F007C117D /* Release */, 521 | 249021D3217E4FDB00AE95B9 /* Profile */, 522 | ); 523 | defaultConfigurationIsVisible = 0; 524 | defaultConfigurationName = Release; 525 | }; 526 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 527 | isa = XCConfigurationList; 528 | buildConfigurations = ( 529 | 97C147061CF9000F007C117D /* Debug */, 530 | 97C147071CF9000F007C117D /* Release */, 531 | 249021D4217E4FDB00AE95B9 /* Profile */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | /* End XCConfigurationList section */ 537 | }; 538 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 539 | } 540 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.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/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 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/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/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | amplify_todo 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 | NSPhotoLibraryUsageDescription 45 | Allow access to photo library 46 | NSCameraUsageDescription 47 | Allow access to camera to capture photos 48 | NSMicrophoneUsageDescription 49 | Allow access to microphone 50 | 51 | 52 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/account_screens_enum.dart: -------------------------------------------------------------------------------- 1 | enum AccountStatus { 2 | sign_in, 3 | sign_up, 4 | reset_password, 5 | confirm_code, 6 | main_screen 7 | } 8 | -------------------------------------------------------------------------------- /lib/app_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/controllers/bindings/homepage_bindings.dart'; 2 | import 'package:amplify_todo/pages/email_sign_in_page.dart'; 3 | import 'package:amplify_todo/pages/home_page.dart'; 4 | import 'package:amplify_todo/pages/sign_in_page.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class AppRoutes { 8 | static final routes = [ 9 | GetPage(name: '/home', page: () => HomePage(), binding: HomeBindings()), 10 | GetPage( 11 | name: '/emaillogin', 12 | page: () => EmailSignInPage(), 13 | ), 14 | GetPage( 15 | name: '/signin', 16 | page: () => SignInPage(), 17 | ), 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /lib/buttons_enum.dart: -------------------------------------------------------------------------------- 1 | enum Buttons { 2 | /// This is a list of all the library built buttons. 3 | Email, 4 | Google, 5 | Facebook, 6 | Amazon, 7 | Apple, 8 | } 9 | -------------------------------------------------------------------------------- /lib/controllers/authController.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; 2 | import 'package:amplify_todo/services/auth_service.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:get/get.dart'; 5 | 6 | enum EmailSignInFormType { signIn, register, confirm } 7 | 8 | class AuthController extends GetxController { 9 | static AuthController to = Get.find(); 10 | AuthService _authService = AuthService(); 11 | Rx emailformType = EmailSignInFormType.signIn.obs; 12 | RxBool isLoading = false.obs; 13 | RxBool isSignedIn = false.obs; 14 | bool submitted = false; 15 | RxBool submitEnabled = false.obs; 16 | 17 | final TextEditingController emailController = TextEditingController(); 18 | final TextEditingController passwordController = TextEditingController(); 19 | final TextEditingController codeController = TextEditingController(); 20 | final FocusNode codeFocusNode = FocusNode(); 21 | final FocusNode emailFocusNode = FocusNode(); 22 | final FocusNode passwordFocusNode = FocusNode(); 23 | final String invalidEmailErrorText = 'Email can\'t be empty'; 24 | final String invalidPasswordErrorText = 'Password can\'t be empty'; 25 | 26 | String get primaryButtonText { 27 | switch (emailformType.value) { 28 | case EmailSignInFormType.signIn: 29 | return 'Sign In'; 30 | case EmailSignInFormType.register: 31 | return 'Create an account'; 32 | case EmailSignInFormType.confirm: 33 | return 'Confirm Sign Up'; 34 | } 35 | } 36 | 37 | String get secondaryButtonText { 38 | return emailformType.value == EmailSignInFormType.signIn 39 | ? 'Need an account? Register' 40 | : 'Have an account? Sign in'; 41 | } 42 | 43 | String? get emailErrorText { 44 | bool showErrorText = submitted && !GetUtils.isEmail(emailController.text); 45 | return showErrorText ? invalidEmailErrorText : null; 46 | } 47 | 48 | void toggleFormType() { 49 | emailformType.value = emailformType.value == EmailSignInFormType.signIn 50 | ? EmailSignInFormType.register 51 | : EmailSignInFormType.signIn; 52 | 53 | emailController.clear(); 54 | passwordController.clear(); 55 | submitted = false; 56 | } 57 | 58 | Future submitEmailAndPassword() async { 59 | submitted = true; 60 | isLoading.value = true; 61 | 62 | try { 63 | switch (emailformType.value) { 64 | case EmailSignInFormType.signIn: 65 | isSignedIn.value = await _authService.signInWithEmailAndPassword( 66 | emailController.text, passwordController.text); 67 | break; 68 | case EmailSignInFormType.register: 69 | final isSignedUp = await _authService.registerWithEmailAndPassword( 70 | emailController.text, passwordController.text); 71 | if (!isSignedUp) { 72 | emailformType.value = EmailSignInFormType.confirm; 73 | } 74 | break; 75 | case EmailSignInFormType.confirm: 76 | isSignedIn.value = (await _authService.confirmRegisterWithCode( 77 | emailController.text, 78 | passwordController.text, 79 | codeController.text))!; 80 | } 81 | } catch (e) { 82 | rethrow; 83 | } finally { 84 | isLoading.value = false; 85 | } 86 | } 87 | 88 | @override 89 | void onReady() { 90 | isUserSignedIn(); 91 | ever(isSignedIn, handleAuthChanged); 92 | super.onReady(); 93 | } 94 | 95 | void isUserSignedIn() async { 96 | try { 97 | isLoading.value = true; 98 | isSignedIn.value = await _authService.isSignedIn(); 99 | } catch (e) { 100 | throw e; 101 | } finally { 102 | isLoading.value = false; 103 | } 104 | } 105 | 106 | handleAuthChanged(isSignedIn) { 107 | if (!isSignedIn) { 108 | Get.offAllNamed("/signin"); 109 | } else { 110 | Get.offAllNamed("/home"); 111 | } 112 | } 113 | 114 | void signIn(AuthProvider authProvider) async { 115 | try { 116 | await _authService.signIn(authProvider); 117 | isSignedIn.value = true; 118 | //_setuplistener(); 119 | } catch (e) { 120 | throw e; 121 | } 122 | } 123 | 124 | void signOut() async { 125 | try { 126 | await _authService.signOut(); 127 | isSignedIn.value = false; 128 | isLoading.value = false; 129 | } on AuthException catch (e) { 130 | print(e.message); 131 | } 132 | } 133 | 134 | void updateform(String value) { 135 | submitEnabled.value = GetUtils.isEmail(emailController.text) && 136 | !GetUtils.isBlank(passwordController.text)! && 137 | !isLoading.value; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /lib/controllers/bindings/controllers_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/controllers/authController.dart'; 2 | import 'package:get/get.dart'; 3 | 4 | class ControllersBindings extends Bindings { 5 | @override 6 | void dependencies() { 7 | Get.lazyPut(() => AuthController()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/controllers/bindings/homepage_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/controllers/authController.dart'; 2 | 3 | import 'package:amplify_todo/controllers/todoController.dart'; 4 | import 'package:amplify_todo/controllers/userController.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class HomeBindings extends Bindings { 8 | @override 9 | void dependencies() { 10 | Get.put(AuthController(), permanent: true); 11 | //Get.lazyPut(() => AuthController()); 12 | Get.put(TodoController(), permanent: true); 13 | //Get.lazyPut(() => TodoController()); 14 | Get.put(UserController(), permanent: true); 15 | 16 | //Get.lazyPut(() => UserController()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/controllers/todoController.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_analytics_pinpoint/amplify_analytics_pinpoint.dart'; 2 | import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; 3 | import 'package:amplify_datastore/amplify_datastore.dart'; 4 | import 'package:amplify_flutter/amplify.dart'; 5 | import 'package:amplify_todo/models/ModelProvider.dart'; 6 | import 'package:amplify_todo/models/Todo.dart'; 7 | import 'package:amplify_todo/services/auth_service.dart'; 8 | import 'package:amplify_todo/services/datastore_service.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:get/get.dart'; 11 | 12 | class TodoController extends GetxController { 13 | static TodoController to = Get.find(); 14 | DataStoreService _datastoreService = DataStoreService(); 15 | AuthService _authService = AuthService(); 16 | final TextEditingController todoTitleController = TextEditingController(); 17 | 18 | List todoList = [].obs; 19 | 20 | @override 21 | void onReady() { 22 | getTodos(); 23 | super.onReady(); 24 | } 25 | 26 | Future getTodos() async { 27 | AuthUser _authUser = await _authService.getCurrentUser(); 28 | List? _list = await _datastoreService.getTodos(_authUser.userId); 29 | if (_list != null) { 30 | todoList.addAll(_list); 31 | } 32 | } 33 | 34 | Future addTodo() async { 35 | AuthUser _authUser = await _authService.getCurrentUser(); 36 | Todo todo = new Todo( 37 | name: todoTitleController.text.toString(), 38 | isDone: false, 39 | createdAt: TemporalDateTime.now(), 40 | updatedAt: TemporalDateTime.now(), 41 | userId: _authUser.userId); 42 | await _datastoreService.saveTodo(todo); 43 | AnalyticsEvent event = AnalyticsEvent('add_todo'); 44 | Amplify.Analytics.recordEvent(event: event); 45 | todoList.add(todo); 46 | } 47 | 48 | Future removeTodo(Todo todo) async { 49 | await _datastoreService.removeTodo(todo); 50 | AnalyticsEvent event = AnalyticsEvent('remove_todo'); 51 | Amplify.Analytics.recordEvent(event: event); 52 | todoList.remove(todo); 53 | } 54 | 55 | Future setToDoDone(Todo todo, bool newValue) async { 56 | await _datastoreService.setToDoDone(todo, newValue); 57 | AnalyticsEvent event = AnalyticsEvent('done_todo'); 58 | Amplify.Analytics.recordEvent(event: event); 59 | todoList[todoList.indexWhere((element) => element.id == todo.id)] = 60 | todo.copyWith(isDone: newValue); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/controllers/userController.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; 4 | import 'package:amplify_flutter/amplify.dart'; 5 | import 'package:amplify_storage_s3/amplify_storage_s3.dart'; 6 | import 'package:amplify_todo/models/Users.dart'; 7 | import 'package:amplify_todo/services/auth_service.dart'; 8 | import 'package:amplify_todo/services/datastore_service.dart'; 9 | import 'package:get/get.dart'; 10 | import 'package:image_picker/image_picker.dart'; 11 | import 'package:uuid/uuid.dart'; 12 | 13 | class UserController extends GetxController { 14 | static UserController to = Get.find(); 15 | DataStoreService _datastoreService = DataStoreService(); 16 | AuthService _authService = AuthService(); 17 | Rxn currentUser = Rxn(); 18 | RxBool isLoading = false.obs; 19 | RxString imageUrl = ''.obs; 20 | 21 | Users? get user => currentUser.value; 22 | 23 | @override 24 | void onInit() { 25 | super.onInit(); 26 | } 27 | 28 | @override 29 | void onReady() { 30 | getCurrUser(); 31 | super.onReady(); 32 | } 33 | 34 | Future getCurrUser() async { 35 | AuthUser authUser = await _authService.getCurrentUser(); 36 | currentUser.value = await _datastoreService.getUser(authUser.userId); 37 | print(currentUser.value); 38 | } 39 | 40 | Future setUserImage() async { 41 | File _image; 42 | final picker = ImagePicker(); 43 | 44 | try { 45 | isLoading.value = true; 46 | final pickedFile = await picker.getImage(source: ImageSource.gallery); 47 | if (pickedFile != null) { 48 | _image = File(pickedFile.path); 49 | 50 | _image.existsSync(); 51 | final userImageKey = currentUser.value!.id + Uuid().v1() + '.png'; 52 | print(userImageKey); 53 | 54 | Map metadata = {}; 55 | metadata['name'] = currentUser.value!.id; 56 | metadata['desc'] = 'A test file'; 57 | S3UploadFileOptions options = S3UploadFileOptions( 58 | accessLevel: StorageAccessLevel.guest, metadata: metadata); 59 | UploadFileResult result = await Amplify.Storage.uploadFile( 60 | key: userImageKey, local: _image, options: options); 61 | print('uploaded'); 62 | GetUrlOptions _getUrlOptions = GetUrlOptions(expires: 60000); 63 | GetUrlResult resultUrl = await Amplify.Storage.getUrl( 64 | key: userImageKey, options: _getUrlOptions); 65 | print('URL: ' + resultUrl.url); 66 | 67 | currentUser.value = currentUser.value! 68 | .copyWith(imageKey: userImageKey, imageUrl: resultUrl.url); 69 | 70 | print(currentUser.value); 71 | 72 | imageUrl.value = resultUrl.url; 73 | 74 | await _datastoreService.saveUser(currentUser.value!); 75 | } else { 76 | return null; 77 | } 78 | } catch (e) { 79 | print(e.toString()); 80 | } finally { 81 | isLoading.value = false; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/app_routes.dart'; 2 | import 'package:amplify_todo/controllers/bindings/controllers_bindings.dart'; 3 | import 'package:amplify_todo/pages/loading_page.dart'; 4 | import 'package:amplify_todo/services/amplify_service.dart'; 5 | 6 | import 'package:flutter/material.dart'; 7 | import 'package:get/get.dart'; 8 | 9 | void main() { 10 | runApp(MyApp()); 11 | } 12 | 13 | class MyApp extends StatefulWidget { 14 | // This widget is the root of your application. 15 | @override 16 | _MyAppState createState() => _MyAppState(); 17 | } 18 | 19 | class _MyAppState extends State { 20 | bool _amplifyConfigured = false; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | WidgetsBinding.instance!.addPostFrameCallback((_) { 26 | _configureAmplify(); 27 | }); 28 | } 29 | 30 | void _configureAmplify() async { 31 | await AmplifyService.configureAmplify(); 32 | try { 33 | setState(() { 34 | _amplifyConfigured = true; 35 | }); 36 | } catch (e) { 37 | print(e); 38 | } 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return GetMaterialApp( 44 | initialBinding: ControllersBindings(), 45 | title: 'ToDo', 46 | theme: ThemeData( 47 | primarySwatch: Colors.indigo, 48 | ), 49 | home: _amplifyConfigured ? LoadingPage() : _waitForAmplify(), 50 | getPages: AppRoutes.routes, 51 | ); 52 | } 53 | 54 | Scaffold _waitForAmplify() { 55 | return Scaffold( 56 | body: Container( 57 | child: Center( 58 | child: CircularProgressIndicator(), 59 | ), 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/models/ModelProvider.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | // ignore_for_file: public_member_api_docs 17 | 18 | import 'package:amplify_datastore_plugin_interface/amplify_datastore_plugin_interface.dart'; 19 | import 'Todo.dart'; 20 | import 'Users.dart'; 21 | 22 | export 'Todo.dart'; 23 | export 'Users.dart'; 24 | 25 | class ModelProvider implements ModelProviderInterface { 26 | @override 27 | String version = "3698b77bc12dd60cac275fa34d4ba22b"; 28 | @override 29 | List modelSchemas = [Todo.schema, Users.schema]; 30 | static final ModelProvider _instance = ModelProvider(); 31 | 32 | static ModelProvider get instance => _instance; 33 | 34 | ModelType getModelTypeByModelName(String modelName) { 35 | switch(modelName) { 36 | case "Todo": { 37 | return Todo.classType; 38 | } 39 | break; 40 | case "Users": { 41 | return Users.classType; 42 | } 43 | break; 44 | default: { 45 | throw Exception("Failed to find model in model provider for model name: " + modelName); 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /lib/models/Todo.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | // ignore_for_file: public_member_api_docs 17 | 18 | import 'package:amplify_datastore_plugin_interface/amplify_datastore_plugin_interface.dart'; 19 | import 'package:flutter/foundation.dart'; 20 | 21 | 22 | /** This is an auto generated class representing the Todo type in your schema. */ 23 | @immutable 24 | class Todo extends Model { 25 | static const classType = const _TodoModelType(); 26 | final String id; 27 | final String? _name; 28 | final TemporalDateTime? _createdAt; 29 | final TemporalDateTime? _updatedAt; 30 | final bool? _isDone; 31 | final String? _userId; 32 | 33 | @override 34 | getInstanceType() => classType; 35 | 36 | @override 37 | String getId() { 38 | return id; 39 | } 40 | 41 | String get name { 42 | try { 43 | return _name!; 44 | } catch(e) { 45 | throw new DataStoreException(DataStoreExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, recoverySuggestion: DataStoreExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, underlyingException: e.toString()); 46 | } 47 | } 48 | 49 | TemporalDateTime? get createdAt { 50 | return _createdAt; 51 | } 52 | 53 | TemporalDateTime? get updatedAt { 54 | return _updatedAt; 55 | } 56 | 57 | bool? get isDone { 58 | return _isDone; 59 | } 60 | 61 | String get userId { 62 | try { 63 | return _userId!; 64 | } catch(e) { 65 | throw new DataStoreException(DataStoreExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, recoverySuggestion: DataStoreExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, underlyingException: e.toString()); 66 | } 67 | } 68 | 69 | const Todo._internal({required this.id, required name, createdAt, updatedAt, isDone, required userId}): _name = name, _createdAt = createdAt, _updatedAt = updatedAt, _isDone = isDone, _userId = userId; 70 | 71 | factory Todo({String? id, required String name, TemporalDateTime? createdAt, TemporalDateTime? updatedAt, bool? isDone, required String userId}) { 72 | return Todo._internal( 73 | id: id == null ? UUID.getUUID() : id, 74 | name: name, 75 | createdAt: createdAt, 76 | updatedAt: updatedAt, 77 | isDone: isDone, 78 | userId: userId); 79 | } 80 | 81 | bool equals(Object other) { 82 | return this == other; 83 | } 84 | 85 | @override 86 | bool operator ==(Object other) { 87 | if (identical(other, this)) return true; 88 | return other is Todo && 89 | id == other.id && 90 | _name == other._name && 91 | _createdAt == other._createdAt && 92 | _updatedAt == other._updatedAt && 93 | _isDone == other._isDone && 94 | _userId == other._userId; 95 | } 96 | 97 | @override 98 | int get hashCode => toString().hashCode; 99 | 100 | @override 101 | String toString() { 102 | var buffer = new StringBuffer(); 103 | 104 | buffer.write("Todo {"); 105 | buffer.write("id=" + "$id" + ", "); 106 | buffer.write("name=" + "$_name" + ", "); 107 | buffer.write("createdAt=" + (_createdAt != null ? _createdAt!.format() : "null") + ", "); 108 | buffer.write("updatedAt=" + (_updatedAt != null ? _updatedAt!.format() : "null") + ", "); 109 | buffer.write("isDone=" + (_isDone != null ? _isDone!.toString() : "null") + ", "); 110 | buffer.write("userId=" + "$_userId"); 111 | buffer.write("}"); 112 | 113 | return buffer.toString(); 114 | } 115 | 116 | Todo copyWith({String? id, String? name, TemporalDateTime? createdAt, TemporalDateTime? updatedAt, bool? isDone, String? userId}) { 117 | return Todo( 118 | id: id ?? this.id, 119 | name: name ?? this.name, 120 | createdAt: createdAt ?? this.createdAt, 121 | updatedAt: updatedAt ?? this.updatedAt, 122 | isDone: isDone ?? this.isDone, 123 | userId: userId ?? this.userId); 124 | } 125 | 126 | Todo.fromJson(Map json) 127 | : id = json['id'], 128 | _name = json['name'], 129 | _createdAt = json['createdAt'] != null ? TemporalDateTime.fromString(json['createdAt']) : null, 130 | _updatedAt = json['updatedAt'] != null ? TemporalDateTime.fromString(json['updatedAt']) : null, 131 | _isDone = json['isDone'], 132 | _userId = json['userId']; 133 | 134 | Map toJson() => { 135 | 'id': id, 'name': _name, 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format(), 'isDone': _isDone, 'userId': _userId 136 | }; 137 | 138 | static final QueryField ID = QueryField(fieldName: "todo.id"); 139 | static final QueryField NAME = QueryField(fieldName: "name"); 140 | static final QueryField CREATEDAT = QueryField(fieldName: "createdAt"); 141 | static final QueryField UPDATEDAT = QueryField(fieldName: "updatedAt"); 142 | static final QueryField ISDONE = QueryField(fieldName: "isDone"); 143 | static final QueryField USERID = QueryField(fieldName: "userId"); 144 | static var schema = Model.defineSchema(define: (ModelSchemaDefinition modelSchemaDefinition) { 145 | modelSchemaDefinition.name = "Todo"; 146 | modelSchemaDefinition.pluralName = "Todos"; 147 | 148 | modelSchemaDefinition.authRules = [ 149 | AuthRule( 150 | authStrategy: AuthStrategy.PUBLIC, 151 | operations: [ 152 | ModelOperation.CREATE, 153 | ModelOperation.UPDATE, 154 | ModelOperation.DELETE, 155 | ModelOperation.READ 156 | ]) 157 | ]; 158 | 159 | modelSchemaDefinition.addField(ModelFieldDefinition.id()); 160 | 161 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 162 | key: Todo.NAME, 163 | isRequired: true, 164 | ofType: ModelFieldType(ModelFieldTypeEnum.string) 165 | )); 166 | 167 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 168 | key: Todo.CREATEDAT, 169 | isRequired: false, 170 | ofType: ModelFieldType(ModelFieldTypeEnum.dateTime) 171 | )); 172 | 173 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 174 | key: Todo.UPDATEDAT, 175 | isRequired: false, 176 | ofType: ModelFieldType(ModelFieldTypeEnum.dateTime) 177 | )); 178 | 179 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 180 | key: Todo.ISDONE, 181 | isRequired: false, 182 | ofType: ModelFieldType(ModelFieldTypeEnum.bool) 183 | )); 184 | 185 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 186 | key: Todo.USERID, 187 | isRequired: true, 188 | ofType: ModelFieldType(ModelFieldTypeEnum.string) 189 | )); 190 | }); 191 | } 192 | 193 | class _TodoModelType extends ModelType { 194 | const _TodoModelType(); 195 | 196 | @override 197 | Todo fromJson(Map jsonData) { 198 | return Todo.fromJson(jsonData); 199 | } 200 | } -------------------------------------------------------------------------------- /lib/models/Users.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | // ignore_for_file: public_member_api_docs 17 | 18 | import 'ModelProvider.dart'; 19 | import 'package:amplify_datastore_plugin_interface/amplify_datastore_plugin_interface.dart'; 20 | import 'package:collection/collection.dart'; 21 | import 'package:flutter/foundation.dart'; 22 | 23 | 24 | /** This is an auto generated class representing the Users type in your schema. */ 25 | @immutable 26 | class Users extends Model { 27 | static const classType = const _UsersModelType(); 28 | final String id; 29 | final String? _username; 30 | final String? _email; 31 | final String? _imageKey; 32 | final String? _imageUrl; 33 | final bool? _isVerified; 34 | final TemporalDateTime? _createdAt; 35 | final List? _todos; 36 | 37 | @override 38 | getInstanceType() => classType; 39 | 40 | @override 41 | String getId() { 42 | return id; 43 | } 44 | 45 | String? get username { 46 | return _username; 47 | } 48 | 49 | String? get email { 50 | return _email; 51 | } 52 | 53 | String get imageKey { 54 | try { 55 | return _imageKey!; 56 | } catch(e) { 57 | throw new DataStoreException(DataStoreExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, recoverySuggestion: DataStoreExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, underlyingException: e.toString()); 58 | } 59 | } 60 | 61 | String get imageUrl { 62 | try { 63 | return _imageUrl!; 64 | } catch(e) { 65 | throw new DataStoreException(DataStoreExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, recoverySuggestion: DataStoreExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, underlyingException: e.toString()); 66 | } 67 | } 68 | 69 | bool? get isVerified { 70 | return _isVerified; 71 | } 72 | 73 | TemporalDateTime? get createdAt { 74 | return _createdAt; 75 | } 76 | 77 | List? get todos { 78 | return _todos; 79 | } 80 | 81 | const Users._internal({required this.id, username, email, required imageKey, required imageUrl, isVerified, createdAt, todos}): _username = username, _email = email, _imageKey = imageKey, _imageUrl = imageUrl, _isVerified = isVerified, _createdAt = createdAt, _todos = todos; 82 | 83 | factory Users({String? id, String? username, String? email, required String imageKey, required String imageUrl, bool? isVerified, TemporalDateTime? createdAt, List? todos}) { 84 | return Users._internal( 85 | id: id == null ? UUID.getUUID() : id, 86 | username: username, 87 | email: email, 88 | imageKey: imageKey, 89 | imageUrl: imageUrl, 90 | isVerified: isVerified, 91 | createdAt: createdAt, 92 | todos: todos != null ? List.unmodifiable(todos) : todos); 93 | } 94 | 95 | bool equals(Object other) { 96 | return this == other; 97 | } 98 | 99 | @override 100 | bool operator ==(Object other) { 101 | if (identical(other, this)) return true; 102 | return other is Users && 103 | id == other.id && 104 | _username == other._username && 105 | _email == other._email && 106 | _imageKey == other._imageKey && 107 | _imageUrl == other._imageUrl && 108 | _isVerified == other._isVerified && 109 | _createdAt == other._createdAt && 110 | DeepCollectionEquality().equals(_todos, other._todos); 111 | } 112 | 113 | @override 114 | int get hashCode => toString().hashCode; 115 | 116 | @override 117 | String toString() { 118 | var buffer = new StringBuffer(); 119 | 120 | buffer.write("Users {"); 121 | buffer.write("id=" + "$id" + ", "); 122 | buffer.write("username=" + "$_username" + ", "); 123 | buffer.write("email=" + "$_email" + ", "); 124 | buffer.write("imageKey=" + "$_imageKey" + ", "); 125 | buffer.write("imageUrl=" + "$_imageUrl" + ", "); 126 | buffer.write("isVerified=" + (_isVerified != null ? _isVerified!.toString() : "null") + ", "); 127 | buffer.write("createdAt=" + (_createdAt != null ? _createdAt!.format() : "null")); 128 | buffer.write("}"); 129 | 130 | return buffer.toString(); 131 | } 132 | 133 | Users copyWith({String? id, String? username, String? email, String? imageKey, String? imageUrl, bool? isVerified, TemporalDateTime? createdAt, List? todos}) { 134 | return Users( 135 | id: id ?? this.id, 136 | username: username ?? this.username, 137 | email: email ?? this.email, 138 | imageKey: imageKey ?? this.imageKey, 139 | imageUrl: imageUrl ?? this.imageUrl, 140 | isVerified: isVerified ?? this.isVerified, 141 | createdAt: createdAt ?? this.createdAt, 142 | todos: todos ?? this.todos); 143 | } 144 | 145 | Users.fromJson(Map json) 146 | : id = json['id'], 147 | _username = json['username'], 148 | _email = json['email'], 149 | _imageKey = json['imageKey'], 150 | _imageUrl = json['imageUrl'], 151 | _isVerified = json['isVerified'], 152 | _createdAt = json['createdAt'] != null ? TemporalDateTime.fromString(json['createdAt']) : null, 153 | _todos = json['todos'] is List 154 | ? (json['todos'] as List) 155 | .where((e) => e?['serializedData'] != null) 156 | .map((e) => Todo.fromJson(new Map.from(e['serializedData']))) 157 | .toList() 158 | : null; 159 | 160 | Map toJson() => { 161 | 'id': id, 'username': _username, 'email': _email, 'imageKey': _imageKey, 'imageUrl': _imageUrl, 'isVerified': _isVerified, 'createdAt': _createdAt?.format(), 'todos': _todos?.map((e) => e?.toJson())?.toList() 162 | }; 163 | 164 | static final QueryField ID = QueryField(fieldName: "users.id"); 165 | static final QueryField USERNAME = QueryField(fieldName: "username"); 166 | static final QueryField EMAIL = QueryField(fieldName: "email"); 167 | static final QueryField IMAGEKEY = QueryField(fieldName: "imageKey"); 168 | static final QueryField IMAGEURL = QueryField(fieldName: "imageUrl"); 169 | static final QueryField ISVERIFIED = QueryField(fieldName: "isVerified"); 170 | static final QueryField CREATEDAT = QueryField(fieldName: "createdAt"); 171 | static final QueryField TODOS = QueryField( 172 | fieldName: "todos", 173 | fieldType: ModelFieldType(ModelFieldTypeEnum.model, ofModelName: (Todo).toString())); 174 | static var schema = Model.defineSchema(define: (ModelSchemaDefinition modelSchemaDefinition) { 175 | modelSchemaDefinition.name = "Users"; 176 | modelSchemaDefinition.pluralName = "Users"; 177 | 178 | modelSchemaDefinition.authRules = [ 179 | AuthRule( 180 | authStrategy: AuthStrategy.PUBLIC, 181 | operations: [ 182 | ModelOperation.CREATE, 183 | ModelOperation.UPDATE, 184 | ModelOperation.DELETE, 185 | ModelOperation.READ 186 | ]) 187 | ]; 188 | 189 | modelSchemaDefinition.addField(ModelFieldDefinition.id()); 190 | 191 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 192 | key: Users.USERNAME, 193 | isRequired: false, 194 | ofType: ModelFieldType(ModelFieldTypeEnum.string) 195 | )); 196 | 197 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 198 | key: Users.EMAIL, 199 | isRequired: false, 200 | ofType: ModelFieldType(ModelFieldTypeEnum.string) 201 | )); 202 | 203 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 204 | key: Users.IMAGEKEY, 205 | isRequired: true, 206 | ofType: ModelFieldType(ModelFieldTypeEnum.string) 207 | )); 208 | 209 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 210 | key: Users.IMAGEURL, 211 | isRequired: true, 212 | ofType: ModelFieldType(ModelFieldTypeEnum.string) 213 | )); 214 | 215 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 216 | key: Users.ISVERIFIED, 217 | isRequired: false, 218 | ofType: ModelFieldType(ModelFieldTypeEnum.bool) 219 | )); 220 | 221 | modelSchemaDefinition.addField(ModelFieldDefinition.field( 222 | key: Users.CREATEDAT, 223 | isRequired: false, 224 | ofType: ModelFieldType(ModelFieldTypeEnum.dateTime) 225 | )); 226 | 227 | modelSchemaDefinition.addField(ModelFieldDefinition.hasMany( 228 | key: Users.TODOS, 229 | isRequired: false, 230 | ofModelName: (Todo).toString(), 231 | associatedKey: Todo.USERID 232 | )); 233 | }); 234 | } 235 | 236 | class _UsersModelType extends ModelType { 237 | const _UsersModelType(); 238 | 239 | @override 240 | Users fromJson(Map jsonData) { 241 | return Users.fromJson(jsonData); 242 | } 243 | } -------------------------------------------------------------------------------- /lib/pages/email_sign_in_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/widgets/email_sign_in_form.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class EmailSignInPage extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | appBar: AppBar( 9 | title: Text('Sign In'), 10 | elevation: 10, 11 | ), 12 | body: SingleChildScrollView( 13 | child: Padding( 14 | padding: const EdgeInsets.all(16.0), 15 | child: Card( 16 | child: EmailSignInForm(), 17 | ), 18 | ), 19 | ), 20 | backgroundColor: Colors.grey[200], 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/controllers/authController.dart'; 2 | import 'package:amplify_todo/controllers/todoController.dart'; 3 | import 'package:amplify_todo/controllers/userController.dart'; 4 | import 'package:amplify_todo/widgets/todo_card.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:get/get.dart'; 7 | import 'package:get/get_state_manager/get_state_manager.dart'; 8 | 9 | class HomePage extends GetWidget { 10 | TodoController _todocontroller = Get.find(); 11 | AuthController _authcontroller = Get.find(); 12 | 13 | get kTransparentImage => null; 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | backgroundColor: Color(0xffE1E5E4), 18 | appBar: AppBar( 19 | title: GetX( 20 | initState: (_) async { 21 | await Get.find().getCurrUser(); 22 | }, 23 | builder: (_) { 24 | return Text(controller.user?.email ?? '', 25 | style: TextStyle(fontSize: 12)); 26 | }, 27 | ), 28 | centerTitle: true, 29 | actions: [ 30 | IconButton( 31 | icon: Icon(Icons.logout), 32 | onPressed: () { 33 | _authcontroller.signOut(); 34 | }, 35 | ), 36 | ], 37 | ), 38 | floatingActionButton: FloatingActionButton( 39 | onPressed: () { 40 | Get.dialog(AlertDialog( 41 | title: Text('Add Todo here'), 42 | content: TextFormField( 43 | controller: _todocontroller.todoTitleController, 44 | decoration: InputDecoration(hintText: "Title"), 45 | ), 46 | actions: [ 47 | TextButton( 48 | child: Text('OK'), 49 | onPressed: () async { 50 | if (_todocontroller.todoTitleController.text != "") { 51 | await _todocontroller.addTodo(); 52 | _todocontroller.todoTitleController.clear(); 53 | } 54 | Get.back(); 55 | }, 56 | ), 57 | ], 58 | )); 59 | }, 60 | child: Icon(Icons.add), 61 | ), 62 | body: Padding( 63 | padding: EdgeInsets.all(16), 64 | child: Column( 65 | //mainAxisAlignment: MainAxisAlignment.center, 66 | crossAxisAlignment: CrossAxisAlignment.stretch, 67 | children: [ 68 | Obx( 69 | () => (controller.imageUrl.value != null && 70 | controller.imageUrl.value.isEmpty == false) 71 | ? Container( 72 | height: 150, 73 | child: controller.isLoading.value == true 74 | ? const Center(child: CircularProgressIndicator()) 75 | : Image.network(controller.imageUrl.value)) 76 | : Container( 77 | color: Color(0xffE1E5E4), 78 | height: 150, 79 | child: Image.asset( 80 | 'images/profile_image.png', 81 | fit: BoxFit.contain, 82 | ), 83 | ), 84 | ), 85 | SizedBox( 86 | height: 8, 87 | ), 88 | new Row( 89 | mainAxisAlignment: MainAxisAlignment.center, 90 | children: [ 91 | new IconButton( 92 | onPressed: () => controller.setUserImage(), 93 | icon: Icon(Icons.camera_alt), 94 | ), 95 | ], 96 | ), 97 | Text( 98 | "Your Todos", 99 | textAlign: TextAlign.center, 100 | style: TextStyle( 101 | fontSize: 20, 102 | fontWeight: FontWeight.bold, 103 | ), 104 | ), 105 | SizedBox( 106 | height: 8, 107 | ), 108 | Obx( 109 | () => Expanded( 110 | child: ListView.builder( 111 | itemCount: _todocontroller.todoList.length, 112 | itemBuilder: (_, index) { 113 | return TodoCard(todo: _todocontroller.todoList[index]); 114 | }, 115 | ), 116 | ), 117 | ), 118 | ], 119 | ), 120 | )); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/pages/loading_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/controllers/authController.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:get/get.dart'; 4 | 5 | class LoadingPage extends StatelessWidget { 6 | @override 7 | Widget build(BuildContext context) { 8 | AuthController controller = Get.find(); 9 | return Scaffold( 10 | appBar: AppBar(title: Text('ToDo App')), 11 | body: Container( 12 | // color: Color(0xff90CCE6), 13 | child: Center( 14 | child: Column( 15 | mainAxisAlignment: MainAxisAlignment.center, 16 | crossAxisAlignment: CrossAxisAlignment.stretch, 17 | children: [ 18 | Container( 19 | color: Color(0xffE1E5E4), 20 | // height: 200, 21 | child: Image.asset( 22 | 'images/aws.png', 23 | fit: BoxFit.cover, 24 | ), 25 | ), 26 | SizedBox( 27 | height: 48.0, 28 | ), 29 | Padding( 30 | padding: const EdgeInsets.all(8.0), 31 | child: Center( 32 | child: CircularProgressIndicator(), 33 | ), 34 | ), 35 | ], 36 | ), 37 | ), 38 | ), 39 | backgroundColor: Color(0xffE1E5E4), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/pages/sign_in_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; 2 | import 'package:amplify_todo/buttons_enum.dart'; 3 | import 'package:amplify_todo/controllers/authController.dart'; 4 | import 'package:amplify_todo/widgets/sign_in_button.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:get/get.dart'; 7 | 8 | class SignInPage extends GetWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return Scaffold( 12 | appBar: AppBar( 13 | title: Text('ToDo'), 14 | elevation: 10, 15 | ), 16 | body: _buildContent(context), 17 | backgroundColor: Colors.grey[200], 18 | ); 19 | } 20 | 21 | Widget _buildContent(BuildContext context) { 22 | return Padding( 23 | padding: EdgeInsets.all(16), 24 | child: Column( 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.stretch, 27 | children: [ 28 | SizedBox( 29 | child: Text( 30 | 'Sign In', 31 | textAlign: TextAlign.center, 32 | style: TextStyle( 33 | fontSize: 32, 34 | fontWeight: FontWeight.w600, 35 | ), 36 | ), 37 | height: 50.0, 38 | ), 39 | SizedBox( 40 | height: 48.0, 41 | ), 42 | SocialSignInButton( 43 | button: Buttons.Google, 44 | onPressed: () => controller.signIn(AuthProvider.google), 45 | color: Colors.white, 46 | text: 'Sign in with Google', 47 | textColor: Colors.black87, 48 | ), 49 | SizedBox( 50 | height: 8.0, 51 | ), 52 | SocialSignInButton( 53 | button: Buttons.Facebook, 54 | onPressed: () => controller.signIn(AuthProvider.facebook), 55 | color: Color(0xFF334D92), 56 | text: 'Sign in with Facebook', 57 | textColor: Colors.white, 58 | ), 59 | SizedBox( 60 | height: 8.0, 61 | ), 62 | SocialSignInButton( 63 | button: Buttons.Apple, 64 | onPressed: () => controller.signIn(AuthProvider.apple), 65 | color: Colors.black54, 66 | text: 'Sign in with Apple', 67 | textColor: Colors.white, 68 | ), 69 | SizedBox( 70 | height: 8.0, 71 | ), 72 | SocialSignInButton( 73 | button: Buttons.Amazon, 74 | onPressed: () => controller.signIn(AuthProvider.amazon), 75 | color: Colors.black87, 76 | text: 'Sign in with Amazon', 77 | textColor: Colors.white, 78 | ), 79 | SizedBox( 80 | height: 8.0, 81 | ), 82 | Text( 83 | 'Or', 84 | style: TextStyle( 85 | fontSize: 14, 86 | color: Colors.black87, 87 | ), 88 | textAlign: TextAlign.center, 89 | ), 90 | SizedBox( 91 | height: 8.0, 92 | ), 93 | SocialSignInButton( 94 | button: Buttons.Email, 95 | onPressed: () => Get.toNamed("/emaillogin"), 96 | color: Colors.deepOrange, 97 | text: 'Sign in with email', 98 | textColor: Colors.white, 99 | ), 100 | ], 101 | ), 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/services/amplify_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_analytics_pinpoint/amplify_analytics_pinpoint.dart'; 2 | import 'package:amplify_api/amplify_api.dart'; 3 | import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; 4 | import 'package:amplify_datastore/amplify_datastore.dart'; 5 | import 'package:amplify_flutter/amplify.dart'; 6 | import 'package:amplify_storage_s3/amplify_storage_s3.dart'; 7 | import 'package:amplify_todo/models/ModelProvider.dart'; 8 | import '../amplifyconfiguration.dart'; 9 | 10 | class AmplifyService { 11 | static configureAmplify() async { 12 | AmplifyAuthCognito authPlugin = AmplifyAuthCognito(); 13 | 14 | AmplifyDataStore datastorePlugin = 15 | AmplifyDataStore(modelProvider: ModelProvider.instance); 16 | AmplifyStorageS3 storage = AmplifyStorageS3(); 17 | Amplify.addPlugins([ 18 | authPlugin, 19 | datastorePlugin, 20 | AmplifyAnalyticsPinpoint(), 21 | storage, 22 | AmplifyAPI() 23 | ]); 24 | 25 | try { 26 | await Amplify.configure(amplifyconfig); 27 | print('Amplify Configured'); 28 | } catch (e) { 29 | print("Tried to reconfigure Amplify"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/services/auth_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; 4 | import 'package:amplify_datastore/amplify_datastore.dart'; 5 | import 'package:amplify_flutter/amplify.dart'; 6 | import 'package:amplify_todo/models/Users.dart'; 7 | import 'package:amplify_todo/services/datastore_service.dart'; 8 | 9 | class AuthService { 10 | DataStoreService _dataStoreService = DataStoreService(); 11 | Future signIn(AuthProvider authProvider) async { 12 | try { 13 | await Amplify.Auth.signInWithWebUI(provider: authProvider); 14 | } catch (e) { 15 | throw e; 16 | } 17 | } 18 | 19 | Future signOut() async { 20 | try { 21 | await Amplify.DataStore.clear(); 22 | await Amplify.Auth.signOut(); 23 | } on AuthException catch (e) { 24 | print(e.message); 25 | } 26 | } 27 | 28 | Future isSignedIn() async { 29 | AuthSession authSessions = await Amplify.Auth.fetchAuthSession(); 30 | return authSessions.isSignedIn; 31 | } 32 | 33 | Future getCurrentUser() async { 34 | AuthUser authUser = await Amplify.Auth.getCurrentUser(); 35 | return authUser; 36 | } 37 | 38 | Future registerWithEmailAndPassword( 39 | String email, String password) async { 40 | try { 41 | Map userAttributes = { 42 | 'email': email, 43 | 'preferred_username': email, 44 | }; 45 | SignUpResult res = await Amplify.Auth.signUp( 46 | username: email, 47 | password: password, 48 | options: CognitoSignUpOptions(userAttributes: userAttributes)); 49 | return res.isSignUpComplete; 50 | } on AuthException catch (e) { 51 | print(e.message); 52 | throw e; 53 | } 54 | } 55 | 56 | Future signInWithEmailAndPassword(String email, String password) async { 57 | try { 58 | await signOut(); 59 | SignInResult res = await Amplify.Auth.signIn( 60 | username: email.trim(), 61 | password: password.trim(), 62 | ); 63 | 64 | await saveUser(email); 65 | 66 | return res.isSignedIn; 67 | } catch (e) { 68 | throw e; 69 | } 70 | } 71 | 72 | Future saveUser(String email) async { 73 | AuthUser authUser = await Amplify.Auth.getCurrentUser(); 74 | Users user = new Users( 75 | id: authUser.userId, 76 | username: email, 77 | email: email, 78 | isVerified: true, 79 | createdAt: TemporalDateTime.now(), 80 | imageKey: '', 81 | imageUrl: ''); 82 | await _dataStoreService.saveUser(user); 83 | } 84 | 85 | Future confirmRegisterWithCode( 86 | String email, String password, String code) async { 87 | try { 88 | SignUpResult res = await Amplify.Auth.confirmSignUp( 89 | username: email, confirmationCode: code); 90 | 91 | if (res.isSignUpComplete) { 92 | final signInRes = await signInWithEmailAndPassword(email, password); 93 | await saveUser(email); 94 | return signInRes; 95 | } 96 | } catch (e) { 97 | throw e; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/services/datastore_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_flutter/amplify.dart'; 2 | import 'package:amplify_todo/models/Todo.dart'; 3 | import 'package:amplify_todo/models/Users.dart'; 4 | 5 | class DataStoreService { 6 | Future saveUser(Users user) async { 7 | try { 8 | await Amplify.DataStore.save(user); 9 | } catch (e) { 10 | throw e; 11 | } 12 | } 13 | 14 | Future getUser(String userId) async { 15 | try { 16 | List user = await Amplify.DataStore.query(Users.classType, 17 | where: Users.ID.eq(userId)); 18 | if (user.length > 0) { 19 | return user.first; 20 | } else 21 | print('null'); 22 | return null; 23 | } catch (e) { 24 | throw e; 25 | } 26 | } 27 | 28 | Future?> getTodos(String userId) async { 29 | try { 30 | List todos = await Amplify.DataStore.query(Todo.classType, 31 | where: Todo.USERID.eq(userId)); 32 | if (todos.length > 0) { 33 | return todos; 34 | } else 35 | return null; 36 | } catch (e) { 37 | throw e; 38 | } 39 | } 40 | 41 | Future removeTodo(Todo todo) async { 42 | try { 43 | await Amplify.DataStore.delete(todo); 44 | } catch (e) { 45 | throw e; 46 | } 47 | } 48 | 49 | Future saveTodo(Todo todo) async { 50 | try { 51 | await Amplify.DataStore.save(todo); 52 | } catch (e) { 53 | throw e; 54 | } 55 | } 56 | 57 | Future setToDoDone(Todo todo, bool newValue) async { 58 | try { 59 | Todo todoData = (await Amplify.DataStore.query(Todo.classType, 60 | where: Todo.ID.eq(todo.id)))[0]; 61 | await Amplify.DataStore.save(todoData.copyWith(isDone: newValue)); 62 | } catch (e) { 63 | throw e; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/widgets/email_sign_in_form.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/controllers/authController.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:get/get.dart'; 4 | 5 | class EmailSignInForm extends GetWidget { 6 | @override 7 | Widget build(BuildContext context) { 8 | return Obx(() { 9 | return Padding( 10 | padding: const EdgeInsets.all(16.0), 11 | child: Column( 12 | crossAxisAlignment: CrossAxisAlignment.stretch, 13 | mainAxisSize: MainAxisSize.min, 14 | children: 15 | controller.emailformType.value == EmailSignInFormType.confirm 16 | ? _buildConfirmchildren() 17 | : _buildFormchildren(), 18 | ), 19 | ); 20 | }); 21 | } 22 | 23 | Future _submit() async { 24 | try {} catch (e) {} 25 | } 26 | 27 | List _buildFormchildren() { 28 | return [ 29 | TextField( 30 | decoration: InputDecoration( 31 | enabled: controller.isLoading.value == false, 32 | labelText: 'Email', 33 | hintText: 'test@test.com', 34 | errorText: controller.emailErrorText, 35 | ), 36 | controller: controller.emailController, 37 | autocorrect: false, 38 | keyboardType: TextInputType.emailAddress, 39 | textInputAction: TextInputAction.next, 40 | focusNode: controller.emailFocusNode, 41 | onChanged: controller.updateform 42 | //onEditingComplete: () => _emailEditingComplete(), 43 | ), 44 | SizedBox( 45 | height: 8.0, 46 | ), 47 | TextField( 48 | decoration: InputDecoration( 49 | // enabled: model.isLoading == false, 50 | labelText: 'Password', 51 | // errorText: model.passwordErrorText, 52 | ), 53 | obscureText: true, 54 | controller: controller.passwordController, 55 | textInputAction: TextInputAction.done, 56 | focusNode: controller.passwordFocusNode, 57 | onEditingComplete: controller.submitEmailAndPassword, 58 | onChanged: controller.updateform), 59 | SizedBox( 60 | height: 8.0, 61 | ), 62 | ElevatedButton( 63 | onPressed: controller.submitEnabled.value 64 | ? controller.submitEmailAndPassword 65 | : null, // 66 | child: Text( 67 | controller.primaryButtonText, 68 | ), 69 | ), 70 | SizedBox( 71 | height: 8.0, 72 | ), 73 | TextButton( 74 | onPressed: 75 | !controller.isLoading.value ? controller.toggleFormType : null, 76 | child: Text(controller.secondaryButtonText), 77 | ) 78 | ]; 79 | } 80 | 81 | List _buildConfirmchildren() { 82 | return [ 83 | TextField( 84 | decoration: InputDecoration( 85 | enabled: controller.isLoading.value == false, 86 | labelText: 'Confirmation Code', 87 | hintText: 'The code we sent you', 88 | errorText: controller.emailErrorText, 89 | ), 90 | controller: controller.codeController, 91 | autocorrect: false, 92 | keyboardType: TextInputType.text, 93 | textInputAction: TextInputAction.done, 94 | focusNode: controller.codeFocusNode, 95 | onEditingComplete: controller.submitEmailAndPassword, 96 | ), 97 | SizedBox( 98 | height: 8.0, 99 | ), 100 | ElevatedButton( 101 | onPressed: controller.submitEnabled.value 102 | ? controller.submitEmailAndPassword 103 | : null, 104 | child: Text( 105 | controller.primaryButtonText, 106 | ), 107 | ), 108 | SizedBox( 109 | height: 8.0, 110 | ), 111 | ]; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/widgets/sign_in_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/buttons_enum.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 5 | 6 | class SocialSignInButton extends StatelessWidget { 7 | final Color color; 8 | final String text; 9 | final Color textColor; 10 | final double height; 11 | static const double borderRadius = 4.0; 12 | final VoidCallback onPressed; 13 | final Buttons button; 14 | 15 | const SocialSignInButton({ 16 | Key? key, 17 | required this.color, 18 | required this.onPressed, 19 | this.height: 50, 20 | required this.button, 21 | required this.text, 22 | required this.textColor, 23 | }) : super(key: key); 24 | @override 25 | Widget build(BuildContext context) { 26 | return SizedBox( 27 | height: height, 28 | child: ElevatedButton( 29 | onPressed: onPressed, 30 | style: ElevatedButton.styleFrom( 31 | primary: color, 32 | shape: const RoundedRectangleBorder( 33 | borderRadius: BorderRadius.all(Radius.circular(borderRadius))), 34 | ), 35 | child: buildRow(), 36 | ), 37 | ); 38 | } 39 | 40 | Row buildRow() { 41 | switch (button) { 42 | case Buttons.Google: 43 | return Row( 44 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 45 | children: [ 46 | Image.asset('images/google-logo.png'), 47 | Text( 48 | text, 49 | style: TextStyle(color: textColor, fontSize: 15), 50 | ), 51 | Opacity(opacity: 0.0, child: Image.asset('images/google-logo.png')), 52 | ], 53 | ); 54 | case Buttons.Email: 55 | return Row( 56 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 57 | children: [ 58 | Icon( 59 | Icons.email, 60 | ), 61 | Text( 62 | text, 63 | style: TextStyle(color: textColor, fontSize: 15), 64 | ), 65 | Opacity( 66 | opacity: 0.0, 67 | child: Icon( 68 | Icons.email, 69 | ), 70 | ), 71 | ], 72 | ); 73 | 74 | case Buttons.Facebook: 75 | return Row( 76 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 77 | children: [ 78 | Image.asset('images/facebook-logo.png'), 79 | Text( 80 | text, 81 | style: TextStyle(color: textColor, fontSize: 15), 82 | ), 83 | Opacity( 84 | opacity: 0.0, child: Image.asset('images/facebook-logo.png')), 85 | ], 86 | ); 87 | 88 | case Buttons.Amazon: 89 | return Row( 90 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 91 | children: [ 92 | Image.asset('images/amazon-logo.png'), 93 | Text( 94 | text, 95 | style: TextStyle(color: textColor, fontSize: 15), 96 | ), 97 | Opacity(opacity: 0.0, child: Image.asset('images/amazon-logo.png')), 98 | ], 99 | ); 100 | 101 | case Buttons.Apple: 102 | return Row( 103 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 104 | children: [ 105 | Icon( 106 | FontAwesomeIcons.apple, 107 | color: Colors.white, 108 | ), 109 | Text( 110 | text, 111 | style: TextStyle(color: textColor, fontSize: 15), 112 | ), 113 | Opacity( 114 | opacity: 0.0, 115 | child: Icon( 116 | FontAwesomeIcons.apple, 117 | ), 118 | ), 119 | ], 120 | ); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /lib/widgets/todo_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:amplify_todo/controllers/todoController.dart'; 2 | import 'package:amplify_todo/models/Todo.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:get/get.dart'; 5 | import 'package:intl/intl.dart'; 6 | 7 | class TodoCard extends StatelessWidget { 8 | final Todo todo; 9 | const TodoCard({required this.todo}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | TodoController _todocontroller = Get.find(); 14 | return _buildContent(_todocontroller); 15 | } 16 | 17 | Dismissible _buildContent(TodoController _todocontroller) { 18 | return Dismissible( 19 | direction: DismissDirection.startToEnd, 20 | onDismissed: (DismissDirection direction) { 21 | if (direction == DismissDirection.startToEnd) { 22 | _todocontroller.removeTodo(todo); 23 | } 24 | }, 25 | background: Container( 26 | alignment: Alignment.centerLeft, 27 | color: Colors.red, 28 | child: Padding( 29 | padding: const EdgeInsets.all(8.0), 30 | child: Icon( 31 | Icons.delete, 32 | color: Colors.white, 33 | ), 34 | ), 35 | ), 36 | key: ValueKey(todo.id), 37 | child: _buildCard(_todocontroller), 38 | ); 39 | } 40 | 41 | Card _buildCard(TodoController _todocontroller) { 42 | return Card( 43 | margin: EdgeInsets.symmetric(horizontal: 10, vertical: 5), 44 | child: ListTile( 45 | leading: Checkbox( 46 | value: todo.isDone, 47 | onChanged: (newValue) { 48 | _todocontroller.setToDoDone(todo, newValue!); 49 | }, 50 | ), 51 | title: Text( 52 | todo.name, 53 | style: TextStyle( 54 | color: Colors.black, 55 | fontSize: 15, 56 | fontWeight: FontWeight.bold, 57 | ), 58 | ), 59 | subtitle: Column( 60 | crossAxisAlignment: CrossAxisAlignment.start, 61 | children: [ 62 | Text( 63 | DateFormat.yMMMMEEEEd() 64 | .format(todo.createdAt!.getDateTimeInUtc()), 65 | style: TextStyle( 66 | color: Colors.grey, 67 | fontSize: 10, 68 | ), 69 | ), 70 | ], 71 | ), 72 | ), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | amplify_analytics_pinpoint: 5 | dependency: "direct main" 6 | description: 7 | name: amplify_analytics_pinpoint 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "0.2.0" 11 | amplify_analytics_plugin_interface: 12 | dependency: transitive 13 | description: 14 | name: amplify_analytics_plugin_interface 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "0.2.0" 18 | amplify_api: 19 | dependency: "direct main" 20 | description: 21 | name: amplify_api 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "0.2.0" 25 | amplify_api_plugin_interface: 26 | dependency: transitive 27 | description: 28 | name: amplify_api_plugin_interface 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "0.2.0" 32 | amplify_auth_cognito: 33 | dependency: "direct main" 34 | description: 35 | name: amplify_auth_cognito 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "0.2.0" 39 | amplify_auth_plugin_interface: 40 | dependency: transitive 41 | description: 42 | name: amplify_auth_plugin_interface 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.2.0" 46 | amplify_core: 47 | dependency: transitive 48 | description: 49 | name: amplify_core 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.2.0" 53 | amplify_datastore: 54 | dependency: "direct main" 55 | description: 56 | name: amplify_datastore 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "0.2.0" 60 | amplify_datastore_plugin_interface: 61 | dependency: transitive 62 | description: 63 | name: amplify_datastore_plugin_interface 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "0.2.0" 67 | amplify_flutter: 68 | dependency: "direct main" 69 | description: 70 | name: amplify_flutter 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "0.2.0" 74 | amplify_storage_plugin_interface: 75 | dependency: transitive 76 | description: 77 | name: amplify_storage_plugin_interface 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "0.2.0" 81 | amplify_storage_s3: 82 | dependency: "direct main" 83 | description: 84 | name: amplify_storage_s3 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.2.0" 88 | async: 89 | dependency: transitive 90 | description: 91 | name: async 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "2.6.1" 95 | boolean_selector: 96 | dependency: transitive 97 | description: 98 | name: boolean_selector 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "2.1.0" 102 | characters: 103 | dependency: transitive 104 | description: 105 | name: characters 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "1.1.0" 109 | charcode: 110 | dependency: transitive 111 | description: 112 | name: charcode 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "1.2.0" 116 | clock: 117 | dependency: transitive 118 | description: 119 | name: clock 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "1.1.0" 123 | collection: 124 | dependency: transitive 125 | description: 126 | name: collection 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.15.0" 130 | crypto: 131 | dependency: transitive 132 | description: 133 | name: crypto 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "3.0.1" 137 | cupertino_icons: 138 | dependency: "direct main" 139 | description: 140 | name: cupertino_icons 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "1.0.3" 144 | date_time_format: 145 | dependency: transitive 146 | description: 147 | name: date_time_format 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "2.0.1" 151 | fake_async: 152 | dependency: transitive 153 | description: 154 | name: fake_async 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "1.2.0" 158 | flutter: 159 | dependency: "direct main" 160 | description: flutter 161 | source: sdk 162 | version: "0.0.0" 163 | flutter_plugin_android_lifecycle: 164 | dependency: transitive 165 | description: 166 | name: flutter_plugin_android_lifecycle 167 | url: "https://pub.dartlang.org" 168 | source: hosted 169 | version: "2.0.2" 170 | flutter_test: 171 | dependency: "direct dev" 172 | description: flutter 173 | source: sdk 174 | version: "0.0.0" 175 | flutter_web_plugins: 176 | dependency: transitive 177 | description: flutter 178 | source: sdk 179 | version: "0.0.0" 180 | font_awesome_flutter: 181 | dependency: "direct main" 182 | description: 183 | name: font_awesome_flutter 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "9.0.0" 187 | get: 188 | dependency: "direct main" 189 | description: 190 | name: get 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "4.1.4" 194 | http: 195 | dependency: transitive 196 | description: 197 | name: http 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "0.13.3" 201 | http_parser: 202 | dependency: transitive 203 | description: 204 | name: http_parser 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "4.0.0" 208 | image_picker: 209 | dependency: "direct main" 210 | description: 211 | name: image_picker 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "0.8.1+1" 215 | image_picker_for_web: 216 | dependency: transitive 217 | description: 218 | name: image_picker_for_web 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "2.0.0" 222 | image_picker_platform_interface: 223 | dependency: transitive 224 | description: 225 | name: image_picker_platform_interface 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "2.1.0" 229 | intl: 230 | dependency: "direct main" 231 | description: 232 | name: intl 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "0.17.0" 236 | js: 237 | dependency: transitive 238 | description: 239 | name: js 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "0.6.3" 243 | matcher: 244 | dependency: transitive 245 | description: 246 | name: matcher 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "0.12.10" 250 | meta: 251 | dependency: transitive 252 | description: 253 | name: meta 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "1.3.0" 257 | path: 258 | dependency: transitive 259 | description: 260 | name: path 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "1.8.0" 264 | pedantic: 265 | dependency: transitive 266 | description: 267 | name: pedantic 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "1.11.1" 271 | plugin_platform_interface: 272 | dependency: transitive 273 | description: 274 | name: plugin_platform_interface 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "2.0.0" 278 | sky_engine: 279 | dependency: transitive 280 | description: flutter 281 | source: sdk 282 | version: "0.0.99" 283 | source_span: 284 | dependency: transitive 285 | description: 286 | name: source_span 287 | url: "https://pub.dartlang.org" 288 | source: hosted 289 | version: "1.8.1" 290 | stack_trace: 291 | dependency: transitive 292 | description: 293 | name: stack_trace 294 | url: "https://pub.dartlang.org" 295 | source: hosted 296 | version: "1.10.0" 297 | stream_channel: 298 | dependency: transitive 299 | description: 300 | name: stream_channel 301 | url: "https://pub.dartlang.org" 302 | source: hosted 303 | version: "2.1.0" 304 | string_scanner: 305 | dependency: transitive 306 | description: 307 | name: string_scanner 308 | url: "https://pub.dartlang.org" 309 | source: hosted 310 | version: "1.1.0" 311 | term_glyph: 312 | dependency: transitive 313 | description: 314 | name: term_glyph 315 | url: "https://pub.dartlang.org" 316 | source: hosted 317 | version: "1.2.0" 318 | test_api: 319 | dependency: transitive 320 | description: 321 | name: test_api 322 | url: "https://pub.dartlang.org" 323 | source: hosted 324 | version: "0.3.0" 325 | transparent_image: 326 | dependency: "direct main" 327 | description: 328 | name: transparent_image 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "2.0.0" 332 | typed_data: 333 | dependency: transitive 334 | description: 335 | name: typed_data 336 | url: "https://pub.dartlang.org" 337 | source: hosted 338 | version: "1.3.0" 339 | uuid: 340 | dependency: "direct main" 341 | description: 342 | name: uuid 343 | url: "https://pub.dartlang.org" 344 | source: hosted 345 | version: "3.0.4" 346 | vector_math: 347 | dependency: transitive 348 | description: 349 | name: vector_math 350 | url: "https://pub.dartlang.org" 351 | source: hosted 352 | version: "2.1.0" 353 | sdks: 354 | dart: ">=2.12.0 <3.0.0" 355 | flutter: ">=2.0.0" 356 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: amplify_todo 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | get: ^4.1.4 27 | amplify_flutter: ^0.2.0 28 | amplify_auth_cognito: ^0.2.0 29 | amplify_datastore: ^0.2.0 30 | amplify_analytics_pinpoint: ^0.2.0 31 | font_awesome_flutter: ^9.0.0 32 | amplify_storage_s3: ^0.2.0 33 | amplify_api: ^0.2.0 34 | intl: ^0.17.0 35 | image_picker: ^0.8.0+3 36 | uuid: ^3.0.4 37 | transparent_image: ^2.0.0 38 | 39 | 40 | # The following adds the Cupertino Icons font to your application. 41 | # Use with the CupertinoIcons class for iOS style icons. 42 | cupertino_icons: ^1.0.2 43 | 44 | dev_dependencies: 45 | flutter_test: 46 | sdk: flutter 47 | 48 | # For information on the generic Dart part of this file, see the 49 | # following page: https://dart.dev/tools/pub/pubspec 50 | 51 | # The following section is specific to Flutter. 52 | flutter: 53 | 54 | # The following line ensures that the Material Icons font is 55 | # included with your application, so that you can use the icons in 56 | # the material Icons class. 57 | uses-material-design: true 58 | 59 | # To add assets to your application, add an assets section, like this: 60 | assets: 61 | - images/facebook-logo.png 62 | - images/google-logo.png 63 | - images/amazon-logo.png 64 | - images/applogo.png 65 | - images/aws.png 66 | - images/profile.png 67 | - images/profile_image.png 68 | 69 | # An image asset can refer to one or more resolution-specific "variants", see 70 | # https://flutter.dev/assets-and-images/#resolution-aware. 71 | 72 | # For details regarding adding assets from package dependencies, see 73 | # https://flutter.dev/assets-and-images/#from-packages 74 | 75 | # To add custom fonts to your application, add a fonts section here, 76 | # in this "flutter" section. Each entry in this list should have a 77 | # "family" key with the font family name, and a "fonts" key with a 78 | # list giving the asset and other descriptors for the font. For 79 | # example: 80 | # fonts: 81 | # - family: Schyler 82 | # fonts: 83 | # - asset: fonts/Schyler-Regular.ttf 84 | # - asset: fonts/Schyler-Italic.ttf 85 | # style: italic 86 | # - family: Trajan Pro 87 | # fonts: 88 | # - asset: fonts/TrajanPro.ttf 89 | # - asset: fonts/TrajanPro_Bold.ttf 90 | # weight: 700 91 | # 92 | # For details regarding fonts from package dependencies, 93 | # see https://flutter.dev/custom-fonts/#from-packages 94 | -------------------------------------------------------------------------------- /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:amplify_todo/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 | -------------------------------------------------------------------------------- /youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/offlineprogrammer/amplify_todo/a73225e52755edb069d0903784424a6f03603017/youtube.png --------------------------------------------------------------------------------