diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 60b919e92..8a2b62f08 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,9 +8,9 @@ I also wish to apply for the following categories - - [ ] Most Starred Fork -- [ ] Best All-Rounder -- [ ] Best App submission -- [ ] Best Backend submission +- [X] Best All-Rounder +- [x] Best App submission +- [X] Best Backend submission - [ ] Best Frontend submission - [ ] Best Machine Learning submission @@ -19,14 +19,14 @@ I also wish to apply for the following categories - - [App Development](app) - - [ ] [Week 1](app/week1): Learn Flutter and build a UI using Stateful and Stateless Widgets - - [ ] [Week 2](app/week2): Dive deeper into Flutter's Widgets by building ProductTile, Promoted product banners and implementing forms. Make the app dynamic and interactive! - - [ ] [Week 3](app/week3): Communicate with server resources and manage product data using HTTP methods. Enhancing our app's capabilities for seamless product management and smooth data handling - - [ ] [Week 4](app/week4): Implement Firebase user authentication, integrate cloud storage for image handling and explore Stripe for seamless payments + - [x] [Week 1](app/week1): Learn Flutter and build a UI using Stateful and Stateless Widgets + - [x] [Week 2](app/week2): Dive deeper into Flutter's Widgets by building ProductTile, Promoted product banners and implementing forms. Make the app dynamic and interactive! + - [x] [Week 3](app/week3): Communicate with server resources and manage product data using HTTP methods. Enhancing our app's capabilities for seamless product management and smooth data handling + - [x] [Week 4](app/week4): Implement Firebase user authentication, integrate cloud storage for image handling and explore Stripe for seamless payments - [Backend Development](backend) - - [ ] [Week 1](backend/week1): Learn how a backend works by analysing a real-world website, and then make your own backend, using raw Python & SQL and use it to create a simple URL shortener - - [ ] [Week 2](backend/week2): Setup a Django backend server, and learn database models, rendering templates, user authentication and forms. Bonus: make it production-ready! - - [ ] [Week 3](backend/week3): Convert your Django backend into a REST API, and learn about function based views, JWT authentication and documentation with Postman. Bonus: make it enterprise-grade! + - [x] [Week 1](backend/week1): Learn how a backend works by analysing a real-world website, and then make your own backend, using raw Python & SQL and use it to create a simple URL shortener + - [x] [Week 2](backend/week2): Setup a Django backend server, and learn database models, rendering templates, user authentication and forms. Bonus: make it production-ready! + - [x] [Week 3](backend/week3): Convert your Django backend into a REST API, and learn about function based views, JWT authentication and documentation with Postman. Bonus: make it enterprise-grade! - [ ] [Week 4](backend/week4): Deploy your Django project on Microsoft Azure cloud platform, and learn about virtual machines, domain names and HTTPS. - [Frontend Development](frontend) - [ ] [Week 1](frontend/week1): Learn how websites work using DevTools, and then learn how to build a simple static website using HTML and CSS, taking designs from Figma and host it on GitHub Pages @@ -41,11 +41,23 @@ I also wish to apply for the following categories - ## Technologies/Tools/Frameworks used/learnt +- flutter frame work +- google firbase +- django +- restapi +- jwt ## Features Implemented +- flutter frame work +- google firbase +- django +- restapi +- jwt + ## Deployment Link +Check release folder for app @@ -55,13 +67,15 @@ I also wish to apply for the following categories - +- app -> + https://www.youtube.com/watch?v=qi0BVqZsMEg ## Personal Details -| Name | | -| :----------- | ------------: | -| College | | -| Entry No | | -| Email ID | | -| Phone Number | | +| Name | Pritesh Mehta | +| :----------- | ----------------------: | +| College | IIT D | +| Entry No | 2022CS11916 | +| Email ID | 4mehtapritesh@gmail.com | +| Phone Number | 720104635 | diff --git a/app/myapp/.gitignore b/app/myapp/.gitignore new file mode 100644 index 000000000..24476c5d1 --- /dev/null +++ b/app/myapp/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/app/myapp/.metadata b/app/myapp/.metadata new file mode 100644 index 000000000..30d90a7ef --- /dev/null +++ b/app/myapp/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: android + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: ios + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: linux + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: macos + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: web + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: windows + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/app/myapp/README.md b/app/myapp/README.md new file mode 100644 index 000000000..a03d064f1 --- /dev/null +++ b/app/myapp/README.md @@ -0,0 +1,16 @@ +# myapp + +devclub week 1 + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/app/myapp/analysis_options.yaml b/app/myapp/analysis_options.yaml new file mode 100644 index 000000000..61b6c4de1 --- /dev/null +++ b/app/myapp/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/app/myapp/assets/banner/1.jpg b/app/myapp/assets/banner/1.jpg new file mode 100644 index 000000000..ef51c4aa2 Binary files /dev/null and b/app/myapp/assets/banner/1.jpg differ diff --git a/app/myapp/assets/banner/2.jpg b/app/myapp/assets/banner/2.jpg new file mode 100644 index 000000000..9b0ea39d2 Binary files /dev/null and b/app/myapp/assets/banner/2.jpg differ diff --git a/app/myapp/assets/banner/3.jpg b/app/myapp/assets/banner/3.jpg new file mode 100644 index 000000000..4df85bbc4 Binary files /dev/null and b/app/myapp/assets/banner/3.jpg differ diff --git a/app/myapp/assets/banner/4.jpg b/app/myapp/assets/banner/4.jpg new file mode 100644 index 000000000..02150d48a Binary files /dev/null and b/app/myapp/assets/banner/4.jpg differ diff --git a/app/myapp/assets/banner/5.jpg b/app/myapp/assets/banner/5.jpg new file mode 100644 index 000000000..9995bc422 Binary files /dev/null and b/app/myapp/assets/banner/5.jpg differ diff --git a/app/myapp/assets/banner/6.jpg b/app/myapp/assets/banner/6.jpg new file mode 100644 index 000000000..ed19aee5f Binary files /dev/null and b/app/myapp/assets/banner/6.jpg differ diff --git a/app/myapp/assets/images/Adam Farrell.png b/app/myapp/assets/images/Adam Farrell.png new file mode 100644 index 000000000..3ca404862 Binary files /dev/null and b/app/myapp/assets/images/Adam Farrell.png differ diff --git a/app/myapp/assets/images/Alyssa Mendez.png b/app/myapp/assets/images/Alyssa Mendez.png new file mode 100644 index 000000000..552cb94fe Binary files /dev/null and b/app/myapp/assets/images/Alyssa Mendez.png differ diff --git a/app/myapp/assets/images/Amanda Brooks.png b/app/myapp/assets/images/Amanda Brooks.png new file mode 100644 index 000000000..57b54ba9b Binary files /dev/null and b/app/myapp/assets/images/Amanda Brooks.png differ diff --git a/app/myapp/assets/images/Annette Harper.png b/app/myapp/assets/images/Annette Harper.png new file mode 100644 index 000000000..2f4ef8050 Binary files /dev/null and b/app/myapp/assets/images/Annette Harper.png differ diff --git a/app/myapp/assets/images/Ashley Fisher.png b/app/myapp/assets/images/Ashley Fisher.png new file mode 100644 index 000000000..e44312bf5 Binary files /dev/null and b/app/myapp/assets/images/Ashley Fisher.png differ diff --git a/app/myapp/assets/images/Ashley Smith.png b/app/myapp/assets/images/Ashley Smith.png new file mode 100644 index 000000000..e4cae3fe4 Binary files /dev/null and b/app/myapp/assets/images/Ashley Smith.png differ diff --git a/app/myapp/assets/images/Brad Stewart.png b/app/myapp/assets/images/Brad Stewart.png new file mode 100644 index 000000000..26c65cd9e Binary files /dev/null and b/app/myapp/assets/images/Brad Stewart.png differ diff --git a/app/myapp/assets/images/Brian Ferrell.png b/app/myapp/assets/images/Brian Ferrell.png new file mode 100644 index 000000000..cdd3e443c Binary files /dev/null and b/app/myapp/assets/images/Brian Ferrell.png differ diff --git a/app/myapp/assets/images/Brittany Berry.png b/app/myapp/assets/images/Brittany Berry.png new file mode 100644 index 000000000..d83d57c15 Binary files /dev/null and b/app/myapp/assets/images/Brittany Berry.png differ diff --git a/app/myapp/assets/images/Christy Jones.png b/app/myapp/assets/images/Christy Jones.png new file mode 100644 index 000000000..2e4958680 Binary files /dev/null and b/app/myapp/assets/images/Christy Jones.png differ diff --git a/app/myapp/assets/images/Cindy Wilkins.png b/app/myapp/assets/images/Cindy Wilkins.png new file mode 100644 index 000000000..d99d845a0 Binary files /dev/null and b/app/myapp/assets/images/Cindy Wilkins.png differ diff --git a/app/myapp/assets/images/David Warner.png b/app/myapp/assets/images/David Warner.png new file mode 100644 index 000000000..68972fd98 Binary files /dev/null and b/app/myapp/assets/images/David Warner.png differ diff --git a/app/myapp/assets/images/Deanna Johnson.png b/app/myapp/assets/images/Deanna Johnson.png new file mode 100644 index 000000000..d1e2460fe Binary files /dev/null and b/app/myapp/assets/images/Deanna Johnson.png differ diff --git a/app/myapp/assets/images/Debra Duncan.png b/app/myapp/assets/images/Debra Duncan.png new file mode 100644 index 000000000..006b16478 Binary files /dev/null and b/app/myapp/assets/images/Debra Duncan.png differ diff --git a/app/myapp/assets/images/Diana Willis.png b/app/myapp/assets/images/Diana Willis.png new file mode 100644 index 000000000..f9c289d12 Binary files /dev/null and b/app/myapp/assets/images/Diana Willis.png differ diff --git a/app/myapp/assets/images/Dustin Cox.png b/app/myapp/assets/images/Dustin Cox.png new file mode 100644 index 000000000..2152b7ab5 Binary files /dev/null and b/app/myapp/assets/images/Dustin Cox.png differ diff --git a/app/myapp/assets/images/Elizabeth Paul.png b/app/myapp/assets/images/Elizabeth Paul.png new file mode 100644 index 000000000..839e6930c Binary files /dev/null and b/app/myapp/assets/images/Elizabeth Paul.png differ diff --git a/app/myapp/assets/images/Emily Chase.png b/app/myapp/assets/images/Emily Chase.png new file mode 100644 index 000000000..2540510cb Binary files /dev/null and b/app/myapp/assets/images/Emily Chase.png differ diff --git a/app/myapp/assets/images/Eric Reynolds.png b/app/myapp/assets/images/Eric Reynolds.png new file mode 100644 index 000000000..fb5463919 Binary files /dev/null and b/app/myapp/assets/images/Eric Reynolds.png differ diff --git a/app/myapp/assets/images/Jacob Garza.png b/app/myapp/assets/images/Jacob Garza.png new file mode 100644 index 000000000..a7812e3a4 Binary files /dev/null and b/app/myapp/assets/images/Jacob Garza.png differ diff --git a/app/myapp/assets/images/Jason Simon.png b/app/myapp/assets/images/Jason Simon.png new file mode 100644 index 000000000..5ad46daca Binary files /dev/null and b/app/myapp/assets/images/Jason Simon.png differ diff --git a/app/myapp/assets/images/Jean Edwards DDS.png b/app/myapp/assets/images/Jean Edwards DDS.png new file mode 100644 index 000000000..122755439 Binary files /dev/null and b/app/myapp/assets/images/Jean Edwards DDS.png differ diff --git a/app/myapp/assets/images/Jeffrey Mack.png b/app/myapp/assets/images/Jeffrey Mack.png new file mode 100644 index 000000000..207d63aed Binary files /dev/null and b/app/myapp/assets/images/Jeffrey Mack.png differ diff --git a/app/myapp/assets/images/Jerry Scott.png b/app/myapp/assets/images/Jerry Scott.png new file mode 100644 index 000000000..359d15b91 Binary files /dev/null and b/app/myapp/assets/images/Jerry Scott.png differ diff --git a/app/myapp/assets/images/Jody Shea.png b/app/myapp/assets/images/Jody Shea.png new file mode 100644 index 000000000..ddddc3d4d Binary files /dev/null and b/app/myapp/assets/images/Jody Shea.png differ diff --git a/app/myapp/assets/images/John Ortiz.png b/app/myapp/assets/images/John Ortiz.png new file mode 100644 index 000000000..552cb94fe Binary files /dev/null and b/app/myapp/assets/images/John Ortiz.png differ diff --git a/app/myapp/assets/images/Judith Gay.png b/app/myapp/assets/images/Judith Gay.png new file mode 100644 index 000000000..e8591c065 Binary files /dev/null and b/app/myapp/assets/images/Judith Gay.png differ diff --git a/app/myapp/assets/images/Kathy Garrison.png b/app/myapp/assets/images/Kathy Garrison.png new file mode 100644 index 000000000..8abafeefc Binary files /dev/null and b/app/myapp/assets/images/Kathy Garrison.png differ diff --git a/app/myapp/assets/images/Kenneth Davis.png b/app/myapp/assets/images/Kenneth Davis.png new file mode 100644 index 000000000..00ab68894 Binary files /dev/null and b/app/myapp/assets/images/Kenneth Davis.png differ diff --git a/app/myapp/assets/images/Kimberly Clarke.png b/app/myapp/assets/images/Kimberly Clarke.png new file mode 100644 index 000000000..65995433e Binary files /dev/null and b/app/myapp/assets/images/Kimberly Clarke.png differ diff --git a/app/myapp/assets/images/Lance Soto.png b/app/myapp/assets/images/Lance Soto.png new file mode 100644 index 000000000..21d290ee5 Binary files /dev/null and b/app/myapp/assets/images/Lance Soto.png differ diff --git a/app/myapp/assets/images/Marie Brown.png b/app/myapp/assets/images/Marie Brown.png new file mode 100644 index 000000000..ff005efee Binary files /dev/null and b/app/myapp/assets/images/Marie Brown.png differ diff --git a/app/myapp/assets/images/Mark Lawrence.png b/app/myapp/assets/images/Mark Lawrence.png new file mode 100644 index 000000000..a02599b2f Binary files /dev/null and b/app/myapp/assets/images/Mark Lawrence.png differ diff --git a/app/myapp/assets/images/Michael Campbell.png b/app/myapp/assets/images/Michael Campbell.png new file mode 100644 index 000000000..454e121f3 Binary files /dev/null and b/app/myapp/assets/images/Michael Campbell.png differ diff --git a/app/myapp/assets/images/Michael Wiggins.png b/app/myapp/assets/images/Michael Wiggins.png new file mode 100644 index 000000000..b5d91b92e Binary files /dev/null and b/app/myapp/assets/images/Michael Wiggins.png differ diff --git a/app/myapp/assets/images/Nathan Lowe.png b/app/myapp/assets/images/Nathan Lowe.png new file mode 100644 index 000000000..de3ae34dc Binary files /dev/null and b/app/myapp/assets/images/Nathan Lowe.png differ diff --git a/app/myapp/assets/images/Nathan Lyons.png b/app/myapp/assets/images/Nathan Lyons.png new file mode 100644 index 000000000..7adeeb0eb Binary files /dev/null and b/app/myapp/assets/images/Nathan Lyons.png differ diff --git a/app/myapp/assets/images/Olivia Gonzalez.png b/app/myapp/assets/images/Olivia Gonzalez.png new file mode 100644 index 000000000..ceaf351e2 Binary files /dev/null and b/app/myapp/assets/images/Olivia Gonzalez.png differ diff --git a/app/myapp/assets/images/Patrick Ryan.png b/app/myapp/assets/images/Patrick Ryan.png new file mode 100644 index 000000000..d0d4da1e1 Binary files /dev/null and b/app/myapp/assets/images/Patrick Ryan.png differ diff --git a/app/myapp/assets/images/Peter Smith.png b/app/myapp/assets/images/Peter Smith.png new file mode 100644 index 000000000..519e35913 Binary files /dev/null and b/app/myapp/assets/images/Peter Smith.png differ diff --git a/app/myapp/assets/images/Robert Gomez.png b/app/myapp/assets/images/Robert Gomez.png new file mode 100644 index 000000000..75407e39f Binary files /dev/null and b/app/myapp/assets/images/Robert Gomez.png differ diff --git a/app/myapp/assets/images/Ronald Brown.png b/app/myapp/assets/images/Ronald Brown.png new file mode 100644 index 000000000..768d2ca8f Binary files /dev/null and b/app/myapp/assets/images/Ronald Brown.png differ diff --git a/app/myapp/assets/images/Sarah English.png b/app/myapp/assets/images/Sarah English.png new file mode 100644 index 000000000..8816836c2 Binary files /dev/null and b/app/myapp/assets/images/Sarah English.png differ diff --git a/app/myapp/assets/images/Selena Rogers.png b/app/myapp/assets/images/Selena Rogers.png new file mode 100644 index 000000000..7f49ce0c4 Binary files /dev/null and b/app/myapp/assets/images/Selena Rogers.png differ diff --git a/app/myapp/assets/images/Stephanie Peterson.png b/app/myapp/assets/images/Stephanie Peterson.png new file mode 100644 index 000000000..6b2d20ce0 Binary files /dev/null and b/app/myapp/assets/images/Stephanie Peterson.png differ diff --git a/app/myapp/assets/images/Steven Mason.png b/app/myapp/assets/images/Steven Mason.png new file mode 100644 index 000000000..db5234164 Binary files /dev/null and b/app/myapp/assets/images/Steven Mason.png differ diff --git a/app/myapp/assets/images/Summer Hill.png b/app/myapp/assets/images/Summer Hill.png new file mode 100644 index 000000000..b2e6ade10 Binary files /dev/null and b/app/myapp/assets/images/Summer Hill.png differ diff --git a/app/myapp/assets/images/Susan Schmidt.png b/app/myapp/assets/images/Susan Schmidt.png new file mode 100644 index 000000000..362142ebd Binary files /dev/null and b/app/myapp/assets/images/Susan Schmidt.png differ diff --git a/app/myapp/assets/images/Susan Thompson.png b/app/myapp/assets/images/Susan Thompson.png new file mode 100644 index 000000000..a7a59af13 Binary files /dev/null and b/app/myapp/assets/images/Susan Thompson.png differ diff --git a/app/myapp/assets/images/Teresa Williams.png b/app/myapp/assets/images/Teresa Williams.png new file mode 100644 index 000000000..5291bfe9f Binary files /dev/null and b/app/myapp/assets/images/Teresa Williams.png differ diff --git a/app/myapp/assets/images/Thomas Hansen.png b/app/myapp/assets/images/Thomas Hansen.png new file mode 100644 index 000000000..1be7804d7 Binary files /dev/null and b/app/myapp/assets/images/Thomas Hansen.png differ diff --git a/app/myapp/assets/images/Thomas Kane.png b/app/myapp/assets/images/Thomas Kane.png new file mode 100644 index 000000000..9d3d13aab Binary files /dev/null and b/app/myapp/assets/images/Thomas Kane.png differ diff --git a/app/myapp/assets/images/Wayne Blackwell.png b/app/myapp/assets/images/Wayne Blackwell.png new file mode 100644 index 000000000..27866fad9 Binary files /dev/null and b/app/myapp/assets/images/Wayne Blackwell.png differ diff --git a/app/myapp/assets/images/Wendy Colon.png b/app/myapp/assets/images/Wendy Colon.png new file mode 100644 index 000000000..38e076b1f Binary files /dev/null and b/app/myapp/assets/images/Wendy Colon.png differ diff --git a/app/myapp/assets/marketplace.csv b/app/myapp/assets/marketplace.csv new file mode 100644 index 000000000..82f288d5d --- /dev/null +++ b/app/myapp/assets/marketplace.csv @@ -0,0 +1,21 @@ +title,description,price,image +Jacob Carter,Star score where film friend record close. Forward people water resource.,1009.08,assets/images/Jason Simon.png +Alyssa Franco,Certain radio week care. Board center their. Like view where later bring.,418.367,assets/images/Kimberly Clarke.png +James Phillips,City chance policy type.,990.045,assets/images/Summer Hill.png +Jenna Arnold,Strategy lay clear financial that. Site look of me from help. Step tonight focus then.,393.54,assets/images/Peter Smith.png +Stacey Watts,Interest meeting she appear start mention. White never southern majority. Issue always why yes why she.,82.55,assets/images/Jason Simon.png +Todd Wilson,Yourself according through what about my. Rest minute everyone including win after.,76.313,assets/images/Steven Mason.png +Kayla Johnson,Pm move partner test offer industry huge choose. Meeting these total near move if religious. Police position fear senior success.,542.248,assets/images/Ronald Brown.png +Carlos Zamora,News religious seek necessary another kid state.,1004.392,assets/images/Selena Rogers.png +John Bonilla,Economic same accept customer card husband charge. Rule new study establish. Deal fine degree.,860.731,assets/images/Eric Reynolds.png +William Patterson,None contain call life result modern. Whatever source trouble look create see finish step. Until Republican cost discover.,497.714,assets/images/Judith Gay.png +Paul Houston,Party street stage natural middle certainly. Figure million particularly course mission. Feel certain system election.,432.473,assets/images/Ashley Fisher.png +Mark George,Responsibility better large life new southern. Size little town glass however. Require himself pattern finally.,51.069,assets/images/Eric Reynolds.png +Kristen Johnson,Positive arrive home scientist speech hundred cultural. Speak check factor material sit reduce course part. Bar body kind.,600.846,assets/images/Ashley Smith.png +Elizabeth Maldonado,Population total responsibility position doctor building resource care. Any film they political.,508.054,assets/images/Olivia Gonzalez.png +Susan Young,Future prove huge. Watch tonight religious north. Garden once arm. Financial possible politics develop keep throughout.,261.003,assets/images/Jean Edwards DDS.png +Alyssa Brown,Have trade include produce those moment. Exist change result fine attorney own or. Worker sit effort pattern exist.,780.124,assets/images/Deanna Johnson.png +Derek Miranda,Ten that without lose. Such another thing game out amount.,203.289,assets/images/Jerry Scott.png +Joseph Hernandez,Way over president if. Thus eye cold over add bank.,871.959,assets/images/Nathan Lyons.png +James Powell,Head fall unit who fast thing defense simply. Bit book organization include science record piece. Loss figure between same coach.,911.583,assets/images/Alyssa Mendez.png +Karen Anderson,Third five else name health seek test create. Of play medical administration year prepare room rich.,932.577,assets/images/Ashley Smith.png diff --git a/app/myapp/ios/.gitignore b/app/myapp/ios/.gitignore new file mode 100644 index 000000000..7a7f9873a --- /dev/null +++ b/app/myapp/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/app/myapp/ios/Flutter/AppFrameworkInfo.plist b/app/myapp/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000..9625e105d --- /dev/null +++ b/app/myapp/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/app/myapp/ios/Flutter/Debug.xcconfig b/app/myapp/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/app/myapp/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/app/myapp/ios/Flutter/Release.xcconfig b/app/myapp/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/app/myapp/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/app/myapp/ios/Runner.xcodeproj/project.pbxproj b/app/myapp/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..66d39d171 --- /dev/null +++ b/app/myapp/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,608 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C80F4294D02FB00263BE5 /* RunnerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 331C80F3294D02FB00263BE5 /* RunnerTests.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80F5294D02FB00263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C80F1294D02FB00263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80F3294D02FB00263BE5 /* RunnerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RunnerTests.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80EE294D02FB00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80F2294D02FB00263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80F3294D02FB00263BE5 /* RunnerTests.m */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 331C80F2294D02FB00263BE5 /* RunnerTests */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C80F1294D02FB00263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80F0294D02FB00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80F7294D02FB00263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80ED294D02FB00263BE5 /* Sources */, + 331C80EE294D02FB00263BE5 /* Frameworks */, + 331C80EF294D02FB00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80F6294D02FB00263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80F1294D02FB00263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80F0294D02FB00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C80F0294D02FB00263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80EF294D02FB00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80ED294D02FB00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80F4294D02FB00263BE5 /* RunnerTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80F6294D02FB00263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C80F5294D02FB00263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C80F8294D02FB00263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C80F9294D02FB00263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C80FA294D02FB00263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80F7294D02FB00263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80F8294D02FB00263BE5 /* Debug */, + 331C80F9294D02FB00263BE5 /* Release */, + 331C80FA294D02FB00263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/app/myapp/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/app/myapp/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/myapp/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..f7213505a --- /dev/null +++ b/app/myapp/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/myapp/ios/Runner.xcworkspace/contents.xcworkspacedata b/app/myapp/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/app/myapp/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/app/myapp/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/myapp/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/myapp/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/myapp/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/myapp/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/app/myapp/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/app/myapp/ios/Runner/AppDelegate.h b/app/myapp/ios/Runner/AppDelegate.h new file mode 100644 index 000000000..36e21bbf9 --- /dev/null +++ b/app/myapp/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/app/myapp/ios/Runner/AppDelegate.m b/app/myapp/ios/Runner/AppDelegate.m new file mode 100644 index 000000000..70e83933d --- /dev/null +++ b/app/myapp/ios/Runner/AppDelegate.m @@ -0,0 +1,13 @@ +#import "AppDelegate.h" +#import "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d36b1fab2 --- /dev/null +++ b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 000000000..dc9ada472 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 000000000..7353c41ec Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 000000000..797d452e4 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 000000000..6ed2d933e Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 000000000..4cd7b0099 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 000000000..fe730945a Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 000000000..321773cd8 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 000000000..797d452e4 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 000000000..502f463a9 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 000000000..0ec303439 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 000000000..0ec303439 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 000000000..e9f5fea27 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 000000000..84ac32ae7 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 000000000..8953cba09 Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 000000000..0467bf12a Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 000000000..0bedcf2fd --- /dev/null +++ b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000..89c2725b7 --- /dev/null +++ b/app/myapp/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/app/myapp/ios/Runner/Base.lproj/LaunchScreen.storyboard b/app/myapp/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..f2e259c7c --- /dev/null +++ b/app/myapp/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/myapp/ios/Runner/Base.lproj/Main.storyboard b/app/myapp/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000..f3c28516f --- /dev/null +++ b/app/myapp/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/myapp/ios/Runner/Info.plist b/app/myapp/ios/Runner/Info.plist new file mode 100644 index 000000000..3ddad1a69 --- /dev/null +++ b/app/myapp/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Myapp + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + myapp + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/app/myapp/ios/Runner/main.m b/app/myapp/ios/Runner/main.m new file mode 100644 index 000000000..dff6597e4 --- /dev/null +++ b/app/myapp/ios/Runner/main.m @@ -0,0 +1,9 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/app/myapp/ios/RunnerTests/RunnerTests.m b/app/myapp/ios/RunnerTests/RunnerTests.m new file mode 100644 index 000000000..6d8b0bdee --- /dev/null +++ b/app/myapp/ios/RunnerTests/RunnerTests.m @@ -0,0 +1,16 @@ +#import +#import +#import + +@interface RunnerTests : XCTestCase + +@end + +@implementation RunnerTests + +- (void)testExample { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. +} + +@end diff --git a/app/myapp/lib/apiservice.dart b/app/myapp/lib/apiservice.dart new file mode 100644 index 000000000..5cd5d95c3 --- /dev/null +++ b/app/myapp/lib/apiservice.dart @@ -0,0 +1,91 @@ +import 'package:http/http.dart' as http; +import 'product.dart'; +import 'dart:convert'; +class ApiService { + static const baseUrl = 'https://marketplace-1-b3203472.deta.app'; + static Future> fetchProducts() async { + final response = await http.get(Uri.parse('$baseUrl/search?query=&skip=0&limit=300')); + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + return List.from(jsonData.map((data) => Product.fromJson(data))); + } else { + throw Exception('Failed to fetch products'); + } + } + + // Function to make a POST request to add a new product + static Future addProduct( + String category, + String location, + String title, + String description, + String price, + String isNegotiable, + String imgurl, + ) async { + final response = await http.post( + Uri.parse('$baseUrl/product'), + body: jsonEncode({ + "category" : category, + "location" : location, + "title" : title, + "description" : description, + "price" : price, + "isNegotiable" : isNegotiable, + "isFeatured": "true", + "isPromoted":"true", + "img_url":imgurl, + }), + headers: {'Content-Type': 'application/json'}, + ); + print(jsonDecode(response.body)); + print(price); + if (response.statusCode != 201) { + throw Exception('Failed to add product'); + } + } + // Delete a product + static Future deleteProduct(String id) async { + final response = await http.delete( + Uri.parse('$baseUrl/product/$id'), + headers: {'Content-Type': 'application/json'}, + ); + + if (response.statusCode != 204) { + throw Exception('Failed to delete product'); + } + } + +// Edit a product + static Future editProduct( + String id, + String category, + String location, + String title, + String description, + String price, + String isNegotiable, + String imgurl, + ) async { + final response = await http.patch( + Uri.parse('$baseUrl/product/$id'), + body: jsonEncode({ + "id": id, + "category": category, + "location": location, + "title": title, + "description": description, + "price": price, + "isNegotiable": isNegotiable, + "isFeatured": "true", + "isPromoted": "true", + "img_url":imgurl + }), + headers: {'Content-Type': 'application/json'}, + ); + if (response.statusCode != 204) { + throw Exception('Failed to edit product'); + } + } + +} \ No newline at end of file diff --git a/app/myapp/lib/banner_item.dart b/app/myapp/lib/banner_item.dart new file mode 100644 index 000000000..bb6aa683c --- /dev/null +++ b/app/myapp/lib/banner_item.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class BannerItem extends StatelessWidget { + final String imageUrl; + + BannerItem({required this.imageUrl}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage(imageUrl), + fit: BoxFit.cover, + ), + ), + ); + } +} diff --git a/app/myapp/lib/cart.dart b/app/myapp/lib/cart.dart new file mode 100644 index 000000000..7ed7ded4f --- /dev/null +++ b/app/myapp/lib/cart.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; +import 'product.dart'; +import 'storage.dart'; +class CartItem { + final Product product; + int quantity; + + CartItem({required this.product, this.quantity = 1}); +} + +class Cart extends StatefulWidget { + List cartItems = Storage.cartItems; + Cart({Product? product}){ + if (product != null) { + var existingItem = cartItems.firstWhere( + (item) => item.product == product, + orElse: () => CartItem(product: product, quantity: 0), // Provide a default value + ); + + if (existingItem.quantity > 0) { + // If the product is already in the cart, increase the quantity by 1 + existingItem.quantity += 1; + } else { + // If the product is not in the cart, add it as a new item with a quantity of 1 + existingItem.quantity = 1; + cartItems.add(existingItem); + } + } + } + @override + _CartState createState() => _CartState(); +} + +class _CartState extends State { + List cartItems = Storage.cartItems; + void addToCart(Product product) { + setState(() { + // Check if the product is already in the cart + var existingItem = cartItems.firstWhere( + (item) => item.product == product, + orElse: () => CartItem(product: product, quantity: 0), // Provide a default value + ); + + if (existingItem.quantity > 0) { + // If the product is already in the cart, increase the quantity by 1 + existingItem.quantity += 1; + } else { + // If the product is not in the cart, add it as a new item with a quantity of 1 + existingItem.quantity = 1; + cartItems.add(existingItem); + } + }); + } + + + void removeItem(CartItem item) { + setState(() { + cartItems.remove(item); + }); + } + + void increaseQuantity(CartItem item) { + setState(() { + item.quantity += 1; + }); + } + + void decreaseQuantity(CartItem item) { + setState(() { + if (item.quantity > 1) { + item.quantity -= 1; + } + }); + } + + double getTotalAmount() { + double total = 0; + for (var item in cartItems) { + total += (item.product.price * item.quantity); + } + return total; + } + int getitemcount() { + int total = 0; + for (var item in cartItems) { + total += (item.quantity); + } + return total; + } + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Cart'), + ), + body: Column( + children: [ + Expanded( + child: ListView.builder( + itemCount: cartItems.length, + itemBuilder: (BuildContext context, int index) { + final cartItem = cartItems[index]; + + return ListTile( + leading: Image.network(cartItem.product.image), + title: Text(cartItem.product.title), + subtitle: Text('\$${cartItem.product.price.toStringAsFixed(2)}'), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon(Icons.remove), + onPressed: () => decreaseQuantity(cartItem), + ), + Text(cartItem.quantity.toString()), + IconButton( + icon: Icon(Icons.add), + onPressed: () => increaseQuantity(cartItem), + ), + IconButton( + icon: Icon(Icons.delete), + onPressed: () => removeItem(cartItem), + ), + ], + ), + ); + }, + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Total Items: ${getitemcount()}'), + Text('Total Amount: \$${getTotalAmount().toStringAsFixed(2)}'), + ], + ), + SizedBox(height: 16.0), + ElevatedButton( + onPressed: () { + // TODO: PURCHASE + }, + child: Text('Purchase'), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/app/myapp/lib/firebase_options.dart b/app/myapp/lib/firebase_options.dart new file mode 100644 index 000000000..34fc6f07b --- /dev/null +++ b/app/myapp/lib/firebase_options.dart @@ -0,0 +1,62 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for ios - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyAKzhbAQ3QcAGj6b5C4vu7KiBJ-dV5ij4A', + appId: '1:1059389359430:android:86d0a9de76ce9d8932d147', + messagingSenderId: '1059389359430', + projectId: 'myapp-8f3f4', + storageBucket: 'myapp-8f3f4.appspot.com', + ); +} diff --git a/app/myapp/lib/imagehandle.dart b/app/myapp/lib/imagehandle.dart new file mode 100644 index 000000000..f97daa2a3 --- /dev/null +++ b/app/myapp/lib/imagehandle.dart @@ -0,0 +1,73 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:image_picker/image_picker.dart'; +// import 'package:path_provider/path_provider.dart'; +// import 'package:firebase_core/firebase_core.dart'; +class ImageUploadScreen extends StatefulWidget { + @override + _ImageUploadScreenState createState() => _ImageUploadScreenState(); +} + +class _ImageUploadScreenState extends State { + File ?_image; + String ?_imageUrl; + + Future _uploadImage() async { + final picker = ImagePicker(); + final pickedImage = await picker.pickImage(source: ImageSource.gallery); + + setState(() { + if (pickedImage != null) { + _image = File(pickedImage.path); + } + }); + + if (_image != null) { + final metadata = SettableMetadata(contentType: "image/jpeg"); + final storageRef = FirebaseStorage.instance.ref(); + final filePath = "product_images/${DateTime.now().millisecondsSinceEpoch.toString()}.jpg"; + final uploadTask = storageRef.child(filePath).putData(await _image!.readAsBytes(), metadata); + + uploadTask.whenComplete(() async { + if (uploadTask.snapshot.state == TaskState.success) { + final downloadUrl = await storageRef.child(filePath).getDownloadURL(); + setState(() { + _imageUrl = downloadUrl; + }); + } else { + print("error"); + } + }); + } + + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Image Upload'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _image != null + ? Image.file(_image!) + : Text('No image selected'), + SizedBox(height: 20.0), + ElevatedButton( + child: Text('Select Image'), + onPressed: _uploadImage, + ), + SizedBox(height: 20.0), + _imageUrl != null + ? Text(_imageUrl!.toString()) + : Text('No uploaded image'), + ], + ), + ), + ); + } +} diff --git a/app/myapp/lib/main.dart b/app/myapp/lib/main.dart new file mode 100644 index 000000000..7e486e86d --- /dev/null +++ b/app/myapp/lib/main.dart @@ -0,0 +1,31 @@ +import 'package:firebase_core/firebase_core.dart'; +import 'firebase_options.dart'; +import 'package:flutter/material.dart'; +import 'product_tile_collection.dart'; +import 'imagehandle.dart'; +import 'profile.dart'; +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform,); + runApp(MarketplaceApp()); +} + +class MarketplaceApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Marketplace App', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + initialRoute: '/', + routes: { + '/': (context) => LoginPage(), + }, + ); + } +} + + + + diff --git a/app/myapp/lib/post_products.dart b/app/myapp/lib/post_products.dart new file mode 100644 index 000000000..c3374eaef --- /dev/null +++ b/app/myapp/lib/post_products.dart @@ -0,0 +1,356 @@ +import 'package:flutter/material.dart'; +import 'package:myapp/product.dart'; +import 'apiservice.dart'; +import 'dart:io'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:image_picker/image_picker.dart'; +class PostProductForm extends StatefulWidget { + final String addit; + final Product? product; + final Function() onUpdateParentState; + PostProductForm({required this.addit,required this.onUpdateParentState,this.product}); + @override + _PostProductFormState createState() => _PostProductFormState(); +} + +class _PostProductFormState extends State { + + final _formKey = GlobalKey(); + String _id = ''; + String _title = ''; + String _description = ''; + int _price = 0; + String _category = ''; + String _location = ''; + bool _isNegotiable = true; + String _imageUrl = ''; + String _uploadStatus = 'Upload Image...'; + @override + void initState() { + Product? product = widget.product; + if (product != null){ + _id = product.id; + _title = product.title; + _description = product.description; + _price = product.price; + _category = product.category; + _location = product.location; + _isNegotiable = product.isNegotiable; + _imageUrl = product.image; + _uploadStatus = "Previous image"; + } + super.initState(); + } + Future _uploadImage() async { + final picker = ImagePicker(); + final pickedImage = await picker.pickImage(source: ImageSource.gallery); + File ?_image; + setState(() { + if (pickedImage != null) { + _image = File(pickedImage.path); + _uploadStatus = "Uploading"; + } + }); + + if (_image != null) { + final metadata = SettableMetadata(contentType: "image/jpeg"); + final storageRef = FirebaseStorage.instance.ref(); + final filePath = "product_images/${DateTime.now().millisecondsSinceEpoch.toString()}.jpg"; + final uploadTask = storageRef.child(filePath).putData(await _image!.readAsBytes(), metadata); + + uploadTask.whenComplete(() async { + if (uploadTask.snapshot.state == TaskState.success) { + final downloadUrl = await storageRef.child(filePath).getDownloadURL(); + setState(() { + _imageUrl = downloadUrl; + + _uploadStatus = "Uploaded."; + }); + } else { + print("error"); + } + }); + } + + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('${widget.addit} Product'), + ), + body: Padding( + padding: const EdgeInsets.all(16), + child: SingleChildScrollView( + child: Form( + key: _formKey, + child: Column( + children: [ + Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(8), + ), + child: TextFormField( + initialValue: _title, + style: const TextStyle(color: Colors.blue), + decoration: const InputDecoration( + labelText: 'Title', + labelStyle: TextStyle(color: Colors.black), + border: InputBorder.none, + contentPadding: EdgeInsets.all(16), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a title'; + } + return null; + }, + onSaved: (value) { + _title = value ?? ''; + }, + ), + ), + const SizedBox(height: 16), + Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(8), + ), + child: TextFormField( + initialValue: _category, + style: const TextStyle(color: Colors.blue), + decoration: const InputDecoration( + labelText: 'Category', + labelStyle: TextStyle(color: Colors.black), + border: InputBorder.none, + contentPadding: EdgeInsets.all(16), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a category'; + } + return null; + }, + onSaved: (value) { + _category = value ?? ''; + }, + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(8), + ), + child: TextFormField( + initialValue: _price.toString(), + style: const TextStyle(color: Colors.blue), + decoration: const InputDecoration( + labelText: 'Price', + labelStyle: TextStyle(color: Colors.black), + border: InputBorder.none, + contentPadding: EdgeInsets.all(16), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a price'; + } + if (int.tryParse(value) == null) { + return 'Please enter a int price(backend issue)'; + } + return null; + }, + onSaved: (value) { + _price = int.tryParse(value ?? '') ?? 0; + }, + keyboardType: TextInputType.number, + ), + ), + ), + ], + ), + const SizedBox(height: 16), + Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(8), + ), + child: TextFormField( + initialValue: _location, + style: const TextStyle(color: Colors.blue), + decoration: const InputDecoration( + labelText: 'Location', + labelStyle: TextStyle(color: Colors.black), + border: InputBorder.none, + contentPadding: EdgeInsets.all(16), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a location'; + } + return null; + }, + onSaved: (value) { + _location = value ?? ''; + }, + ), + ), + const SizedBox(height: 16), + Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(8), + ), + child: TextFormField( + initialValue: _description, + style: const TextStyle(color: Colors.blue), + decoration: const InputDecoration( + labelText: 'Description', + labelStyle: TextStyle(color: Colors.black), + border: InputBorder.none, + contentPadding: EdgeInsets.all(16), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a description'; + } + return null; + }, + onSaved: (value) { + _description = value ?? ''; + }, + keyboardType: TextInputType.multiline, + maxLines: 4, + ), + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Is Negotiable', + style: TextStyle(color: Colors.black), + ), + Switch( + value: _isNegotiable, + onChanged: (value) { + setState(() { + _isNegotiable = value; + }); + }, + ), + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(_uploadStatus , + style: TextStyle(color: Colors.black), + ), + ElevatedButton( + onPressed: (){ + _uploadImage(); + }, + child: Text('Select Image'), + ), + ], + ), + const SizedBox(height: 16,), + ElevatedButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (_imageUrl != "") { + _formKey.currentState!.save(); + // Process the form data, e.g., save the product to the database + if (widget.addit == "Add") { + ApiService.addProduct( + _category, + _location, + _title, + _description, + _price.toString(), + _isNegotiable.toString(), + _imageUrl).then((value) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Product Added'), + content: const Text( + 'Your product has been added to the market place.'), + actions: [ + TextButton( + onPressed: () { + widget.onUpdateParentState(); + Navigator.of(context) + .pop(); // Navigate to the home page + Navigator.of(context).pop(); + }, + child: const Text('OK'), + ), + ], + ); + }, + ); + }); + } else { + if (!(widget.product == null)) { + ApiService.editProduct( + _id, + _category, + _location, + _title, + _description, + _price.toString(), + _isNegotiable.toString(), + _imageUrl.toString(), + ).then((value) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Edited'), + content: const Text( + 'Your product has been edited succesfully.'), + actions: [ + TextButton( + onPressed: () { + widget.onUpdateParentState(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + child: const Text('OK'), + ), + ], + ); + }, + ); + }); + } + } + } else{ + setState(() { + _uploadStatus = "Uploading image is compulsory."; + }); + } + } + }, + child: Text('${widget.addit} Product'), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/app/myapp/lib/product.dart b/app/myapp/lib/product.dart new file mode 100644 index 000000000..968af811a --- /dev/null +++ b/app/myapp/lib/product.dart @@ -0,0 +1,36 @@ +class Product { + final String id; + final String title; + final String description; + final String category; + final int price; + final String image; + final bool isNegotiable; + final String location; + const Product({ + required this.id, + required this.category, + required this.location, + required this.title, + required this.description, + required this.price, + this.image="https://firebasestorage.googleapis.com/v0/b/myapp-8f3f4.appspot.com/o/Profile%20pic.png?alt=media&token=2a1b52a6-6449-4059-a9db-b4cb83fa1a8a", + required this.isNegotiable, + }); + factory Product.fromJson(Map json,) { + return Product( + id: json['_id']['\$oid'], + title: json['title'], + description: json['description'], + price: json['price'].toInt(), + image: json.containsKey("img_url")?json['img_url']:"https://firebasestorage.googleapis.com/v0/b/myapp-8f3f4.appspot.com/o/Profile%20pic.png?alt=media&token=2a1b52a6-6449-4059-a9db-b4cb83fa1a8a", + location: json['location'], + isNegotiable: json['isNegotiable'], + category: json['category'], + ); + } + @override + bool operator ==(other) { + return (other is Product) && (other.id == id); + } +} \ No newline at end of file diff --git a/app/myapp/lib/product_tile.dart b/app/myapp/lib/product_tile.dart new file mode 100644 index 000000000..26444ce0c --- /dev/null +++ b/app/myapp/lib/product_tile.dart @@ -0,0 +1,84 @@ +import 'cart.dart'; +import 'storage.dart'; +import 'package:flutter/material.dart'; +import 'product.dart'; +import 'productdetail.dart'; +class ProductTile extends StatefulWidget { + final Product product; + final Function() onUpdateParentState; + ProductTile({required this.product,required this.onUpdateParentState}); + + @override + State createState() => _ProductTileState(); +} + +class _ProductTileState extends State { + @override + void initState() { + super.initState(); + } + void toggleFavorite() { + setState(() { + if (Storage.favorites.contains(widget.product)) { + Storage.favorites.remove(widget.product); + } else { + Storage.favorites.insert(0,widget.product); + } + // widget.onUpdateParentState(); + }); + } + @override + Widget build(BuildContext context) { + return GestureDetector( + onLongPress: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => Cart(product: widget.product), + ), + ); + }, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProductDetailsScreen(product: widget.product,onUpdateParentState: widget.onUpdateParentState), + ), + ); + }, + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Stack( + children: [ + Image.network(widget.product.image), + Positioned( + top: 0, + right: 0, + child: IconButton( + icon: Icon( + Storage.favorites.contains(widget.product) ? Icons.favorite : Icons.favorite_border, + color: Colors.red, + ), + onPressed: () { + toggleFavorite(); + // Perform additional logic here + }, + tooltip: Storage.favorites.contains(widget.product) ? 'Remove from favorites' : 'Add to favorites', + ) + ), + ], + ), + ), + Center(child: Text(widget.product.title, style: TextStyle(fontWeight: FontWeight.bold))), + Center(child: Text('\$${widget.product.price.toStringAsFixed(2)}')), + SizedBox(height: 5) + ], + ), + ), + ); + } +} diff --git a/app/myapp/lib/product_tile_collection.dart b/app/myapp/lib/product_tile_collection.dart new file mode 100644 index 000000000..ca3b40ca6 --- /dev/null +++ b/app/myapp/lib/product_tile_collection.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; +import 'product_tile.dart'; +import 'product.dart'; +import 'apiservice.dart'; +import 'promoted_product_banners.dart'; +import 'post_products.dart'; +import 'cart.dart'; +class ProductTileCollection extends StatefulWidget { + @override + _ProductTileCollectionState createState() => _ProductTileCollectionState(); +} + +class _ProductTileCollectionState extends State { + List products = []; + + @override + void initState() { + super.initState(); + _updateParentState(); + } + + Future _updateParentState() async { + try { + List fetchedProducts = await ApiService.fetchProducts(); + setState(() { + products = fetchedProducts; + }); + } catch (e) { + // Handle any error that occurred during product fetching + print('Error: $e'); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Product Listings'), + ), + body: Column( + children: [ + PromotedProductBanners(), + const Padding( + padding: EdgeInsets.all(12.0), + child: Center( + child: Text( + 'Items You Need!', + style: TextStyle( + fontFamily: 'Cupertino', + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + Expanded( + child: GridView.builder( + itemCount: products.length, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 5, + crossAxisSpacing: 0, + childAspectRatio: 0.82, + ), + itemBuilder: (BuildContext context, int index) { + return ProductTile( + product: products[index], + onUpdateParentState: _updateParentState, + ); + }, + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => Cart(), + ), + ); + }, + child: Text('View Cart'), + ), + ), + SizedBox(width: 16), + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PostProductForm(addit:"Add",onUpdateParentState: _updateParentState,), + ), + ); + }, + child: Text('Add your Product'), + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/app/myapp/lib/productdetail.dart b/app/myapp/lib/productdetail.dart new file mode 100644 index 000000000..4a5e2b938 --- /dev/null +++ b/app/myapp/lib/productdetail.dart @@ -0,0 +1,102 @@ +import 'package:myapp/apiservice.dart'; + +import 'storage.dart'; +import 'package:flutter/material.dart'; +import 'product.dart'; +import 'cart.dart'; +import 'post_products.dart'; +class ProductDetailsScreen extends StatelessWidget { + final Product product; + final Function() onUpdateParentState; + ProductDetailsScreen({required this.product, required this.onUpdateParentState}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Product Details'), + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Center( + child: Image.network(product.image), + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Text( + product.title, + style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + ), + ), + SizedBox(height: 8), + Center( + child: Text( + '\$${product.price.toStringAsFixed(2)} ${product.isNegotiable ? "" : "Not"} Negotiable', + style: TextStyle(fontSize: 18), + ), + ), + SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Location: \t${product.location}', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Text('Category: \t${product.category}', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ) + ], + ), + SizedBox(height: 8), + Text( + '${product.description}\n', + style: TextStyle(fontSize: 16), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PostProductForm(addit: "Edit", onUpdateParentState: onUpdateParentState,product:product), + ), + ); + }, + child: Text('Edit Product'), + ), + ), + SizedBox(width: 16), + Expanded( + child: ElevatedButton( + onPressed: () { + ApiService.deleteProduct(product.id).then((value) { + Navigator.pop(context); + onUpdateParentState(); + }); + }, + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), + child: Text('Delete Product'), + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/app/myapp/lib/profile.dart b/app/myapp/lib/profile.dart new file mode 100644 index 000000000..01ed83804 --- /dev/null +++ b/app/myapp/lib/profile.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'product_tile_collection.dart'; + +class LoginPage extends StatelessWidget { + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + + Future _register(BuildContext context) async { + try { + UserCredential userCredential = + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: _emailController.text, + password: _passwordController.text, + ); + // Registration success, navigate to profile screen or perform other actions. + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => ProductTileCollection(), + ), + ); + } on FirebaseAuthException catch (e) { + if (e.code == 'weak-password') { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Registration Error'), + content: Text('The password provided is too weak.'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + } else if (e.code == 'email-already-in-use') { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Registration Error'), + content: Text('The account already exists for that email.'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + } + // Handle other registration errors here. + } catch (e) { + print(e.toString()); + } + } + + Future _login(BuildContext context) async { + try { + UserCredential userCredential = + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: _emailController.text, + password: _passwordController.text, + ); + // Login success, navigate to profile screen or perform other actions. + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => ProductTileCollection(), + ), + ); + } on FirebaseAuthException catch (e) { + if (e.code == 'user-not-found') { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Login Error'), + content: Text('No user found for that email.'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + } else if (e.code == 'wrong-password') { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Login Error'), + content: Text('Wrong password provided for that user.'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + } + // Handle other login errors here. + } catch (e) { + print(e.toString()); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('Login')), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextField( + controller: _emailController, + decoration: InputDecoration( + labelText: 'Email', + ), + ), + TextField( + controller: _passwordController, + decoration: InputDecoration( + labelText: 'Password', + ), + obscureText: true, + ), + SizedBox(height: 16.0), + ElevatedButton( + onPressed: () => _register(context), + child: Text('Register'), + ), + ElevatedButton( + onPressed: () => _login(context), + child: Text('Login'), + ), + ], + ), + ), + ); + } +} diff --git a/app/myapp/lib/promoted_product_banners.dart b/app/myapp/lib/promoted_product_banners.dart new file mode 100644 index 000000000..b91a5ddbc --- /dev/null +++ b/app/myapp/lib/promoted_product_banners.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'banner_item.dart'; + +class PromotedProductBanners extends StatefulWidget { + @override + _PromotedProductBannersState createState() => _PromotedProductBannersState(); +} + +class _PromotedProductBannersState extends State { + final List bannerImageUrls = + List.generate(6, (index) => 'assets/banner/${index + 1}.jpg'); + final PageController _pageController = PageController(); + int _currentPage = 0; + + @override + void dispose() { + _pageController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Container( + height: 200, // Adjust the height as needed + child: PageView.builder( + controller: _pageController, + itemCount: bannerImageUrls.length, + onPageChanged: (int index) { + setState(() { + _currentPage = index; + }); + }, + itemBuilder: (BuildContext context, int index) { + final imageUrl = bannerImageUrls[index]; + return Padding( + padding: + const EdgeInsets.symmetric(vertical: 0.0, horizontal: 8.0), + child: BannerItem(imageUrl: imageUrl), + ); + }, + ), + ), + Positioned( + left: 0, + right: 0, + bottom: 100, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: Icon(Icons.chevron_left), + onPressed: () { + _pageController.previousPage( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, + ), + IconButton( + icon: Icon(Icons.chevron_right), + onPressed: () { + _pageController.nextPage( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, + ), + ], + ), + ), + ], + ); + } +} diff --git a/app/myapp/lib/storage.dart b/app/myapp/lib/storage.dart new file mode 100644 index 000000000..4b597820c --- /dev/null +++ b/app/myapp/lib/storage.dart @@ -0,0 +1,7 @@ +import 'product.dart'; +import 'cart.dart'; +class Storage{ + static List cartItems = []; + static List products = []; + static List favorites = []; +} diff --git a/app/myapp/linux/.gitignore b/app/myapp/linux/.gitignore new file mode 100644 index 000000000..d3896c984 --- /dev/null +++ b/app/myapp/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/app/myapp/linux/CMakeLists.txt b/app/myapp/linux/CMakeLists.txt new file mode 100644 index 000000000..4ac3d57bf --- /dev/null +++ b/app/myapp/linux/CMakeLists.txt @@ -0,0 +1,139 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "myapp") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.myapp") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/app/myapp/linux/flutter/CMakeLists.txt b/app/myapp/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000..d5bd01648 --- /dev/null +++ b/app/myapp/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/app/myapp/linux/flutter/generated_plugin_registrant.cc b/app/myapp/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..64a0ecea4 --- /dev/null +++ b/app/myapp/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); +} diff --git a/app/myapp/linux/flutter/generated_plugin_registrant.h b/app/myapp/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/app/myapp/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/app/myapp/linux/flutter/generated_plugins.cmake b/app/myapp/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..2db3c22ae --- /dev/null +++ b/app/myapp/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/app/myapp/linux/main.cc b/app/myapp/linux/main.cc new file mode 100644 index 000000000..e7c5c5437 --- /dev/null +++ b/app/myapp/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/app/myapp/linux/my_application.cc b/app/myapp/linux/my_application.cc new file mode 100644 index 000000000..e04ded17a --- /dev/null +++ b/app/myapp/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "myapp"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "myapp"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/app/myapp/linux/my_application.h b/app/myapp/linux/my_application.h new file mode 100644 index 000000000..72271d5e4 --- /dev/null +++ b/app/myapp/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/app/myapp/macos/.gitignore b/app/myapp/macos/.gitignore new file mode 100644 index 000000000..746adbb6b --- /dev/null +++ b/app/myapp/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/app/myapp/macos/Flutter/Flutter-Debug.xcconfig b/app/myapp/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000..c2efd0b60 --- /dev/null +++ b/app/myapp/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/app/myapp/macos/Flutter/Flutter-Release.xcconfig b/app/myapp/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000..c2efd0b60 --- /dev/null +++ b/app/myapp/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/app/myapp/macos/Flutter/GeneratedPluginRegistrant.swift b/app/myapp/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 000000000..f47e01366 --- /dev/null +++ b/app/myapp/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,24 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import cloud_firestore +import file_selector_macos +import firebase_auth +import firebase_core +import firebase_storage +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/app/myapp/macos/Runner.xcodeproj/project.pbxproj b/app/myapp/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a7255fb3a --- /dev/null +++ b/app/myapp/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,695 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* myapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "myapp.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* myapp.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* myapp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/myapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/myapp"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/myapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/myapp"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/myapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/myapp"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/app/myapp/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/myapp/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/myapp/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/myapp/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/myapp/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..8916bcc4a --- /dev/null +++ b/app/myapp/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/myapp/macos/Runner.xcworkspace/contents.xcworkspacedata b/app/myapp/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/app/myapp/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/app/myapp/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/myapp/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/myapp/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/myapp/macos/Runner/AppDelegate.swift b/app/myapp/macos/Runner/AppDelegate.swift new file mode 100644 index 000000000..d53ef6437 --- /dev/null +++ b/app/myapp/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a2ec33f19 --- /dev/null +++ b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 000000000..82b6f9d9a Binary files /dev/null and b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 000000000..13b35eba5 Binary files /dev/null and b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 000000000..0a3f5fa40 Binary files /dev/null and b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 000000000..bdb57226d Binary files /dev/null and b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 000000000..f083318e0 Binary files /dev/null and b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 000000000..326c0e72c Binary files /dev/null and b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 000000000..2f1632cfd Binary files /dev/null and b/app/myapp/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/app/myapp/macos/Runner/Base.lproj/MainMenu.xib b/app/myapp/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..80e867a4e --- /dev/null +++ b/app/myapp/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/myapp/macos/Runner/Configs/AppInfo.xcconfig b/app/myapp/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000..7acafc1f4 --- /dev/null +++ b/app/myapp/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = myapp + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/app/myapp/macos/Runner/Configs/Debug.xcconfig b/app/myapp/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000..36b0fd946 --- /dev/null +++ b/app/myapp/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/app/myapp/macos/Runner/Configs/Release.xcconfig b/app/myapp/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000..dff4f4956 --- /dev/null +++ b/app/myapp/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/app/myapp/macos/Runner/Configs/Warnings.xcconfig b/app/myapp/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000..42bcbf478 --- /dev/null +++ b/app/myapp/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/app/myapp/macos/Runner/DebugProfile.entitlements b/app/myapp/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000..dddb8a30c --- /dev/null +++ b/app/myapp/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/app/myapp/macos/Runner/Info.plist b/app/myapp/macos/Runner/Info.plist new file mode 100644 index 000000000..4789daa6a --- /dev/null +++ b/app/myapp/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/app/myapp/macos/Runner/MainFlutterWindow.swift b/app/myapp/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 000000000..3cc05eb23 --- /dev/null +++ b/app/myapp/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/app/myapp/macos/Runner/Release.entitlements b/app/myapp/macos/Runner/Release.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/app/myapp/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/app/myapp/macos/RunnerTests/RunnerTests.swift b/app/myapp/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000..5418c9f53 --- /dev/null +++ b/app/myapp/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/app/myapp/pubspec.lock b/app/myapp/pubspec.lock new file mode 100644 index 000000000..2c8de24cb --- /dev/null +++ b/app/myapp/pubspec.lock @@ -0,0 +1,602 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: "5dce45a06d386358334eb1689108db6455d90ceb0d75848d5f4819283d4ee2b8" + url: "https://pub.dev" + source: hosted + version: "1.3.4" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + sha256: "035b91f66b60dab5eefcc217accc734020234f79d963b075699920b95334a755" + url: "https://pub.dev" + source: hosted + version: "4.8.3" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + sha256: "86bd1865abbeb09a7d09da3e70364a09f894937270651fc611a1c6d6a9f7b02c" + url: "https://pub.dev" + source: hosted + version: "5.15.3" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + sha256: ac2eeb2a7ab1928c3aacc30eed750fa839d6f620e112a5459e321df217be2f47 + url: "https://pub.dev" + source: hosted + version: "3.6.3" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" + csv: + dependency: "direct main" + description: + name: csv + sha256: "016b31a51a913744a0a1655c74ff13c9379e1200e246a03d96c81c5d9ed297b5" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "4ada532862917bf16e3adb3891fe3a5917a58bae03293e497082203a80909412" + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" + url: "https://pub.dev" + source: hosted + version: "0.9.3" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + sha256: "87216661b409575ecb1a7849da38604a0abfcb6497146b66d4832cb97a4c9e0f" + url: "https://pub.dev" + source: hosted + version: "4.7.0" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + sha256: "4ab0a8997994db2b76bf0652689d7908ca935a99314857c683251bc23d31c287" + url: "https://pub.dev" + source: hosted + version: "6.16.0" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + sha256: c74c5753855896b31536b9e151e34bf7eea143f0d9c209947b5f7ddc8e111989 + url: "https://pub.dev" + source: hosted + version: "5.6.0" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "2e9324f719e90200dc7d3c4f5d2abc26052f9f2b995d3b6626c47a0dfe1c8192" + url: "https://pub.dev" + source: hosted + version: "2.15.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2 + url: "https://pub.dev" + source: hosted + version: "4.8.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0fd5c4b228de29b55fac38aed0d9e42514b3d3bd47675de52bf7f8fccaf922fa" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + sha256: "4b747005aee0c611242cdd553f58795f51e1567d2dfd4f75692fac3f67c8c336" + url: "https://pub.dev" + source: hosted + version: "11.2.5" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + sha256: c77c7b6b7d283280993c81ea8ac95552b2ae521a7bb46a95181c1482e62d1633 + url: "https://pub.dev" + source: hosted + version: "4.4.4" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + sha256: "6906245579f1af225e43df0395c9d9631cb3135cbfa3521a839196d3383bb89a" + url: "https://pub.dev" + source: hosted + version: "3.6.5" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" + url: "https://pub.dev" + source: hosted + version: "2.0.15" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "6296e98782726d37f59663f0727d0e978eee1ced1ffed45ccaba591786a7f7b3" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb + url: "https://pub.dev" + source: hosted + version: "0.8.7+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b + url: "https://pub.dev" + source: hosted + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee" + url: "https://pub.dev" + source: hosted + version: "2.8.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + url: "https://pub.dev" + source: hosted + version: "2.0.15" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + url: "https://pub.dev" + source: hosted + version: "2.0.27" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" + url: "https://pub.dev" + source: hosted + version: "2.2.4" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + url: "https://pub.dev" + source: hosted + version: "2.1.11" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" + source: hosted + version: "2.0.6" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + url: "https://pub.dev" + source: hosted + version: "2.1.7" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + url: "https://pub.dev" + source: hosted + version: "2.3.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + win32: + dependency: transitive + description: + name: win32 + sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee + url: "https://pub.dev" + source: hosted + version: "5.0.5" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff + url: "https://pub.dev" + source: hosted + version: "1.0.1" +sdks: + dart: ">=3.0.5 <4.0.0" + flutter: ">=3.3.0" diff --git a/app/myapp/pubspec.yaml b/app/myapp/pubspec.yaml new file mode 100644 index 000000000..2f5df2815 --- /dev/null +++ b/app/myapp/pubspec.yaml @@ -0,0 +1,96 @@ +name: myapp +description: devclub week 1 +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.0.5 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + csv: ^5.0.0 + cupertino_icons: ^1.0.2 + http: ^0.13.4 + shared_preferences: ^2.0.0 + firebase_core: ^2.15.0 + firebase_auth: ^4.7.0 + cloud_firestore: ^4.8.3 + firebase_storage: ^11.2.5 + image_picker: ^1.0.1 + path_provider: ^2.0.15 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/images/ + - assets/marketplace.csv + - assets/banner/ + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/app/myapp/web/favicon.png b/app/myapp/web/favicon.png new file mode 100644 index 000000000..8aaa46ac1 Binary files /dev/null and b/app/myapp/web/favicon.png differ diff --git a/app/myapp/web/icons/Icon-192.png b/app/myapp/web/icons/Icon-192.png new file mode 100644 index 000000000..b749bfef0 Binary files /dev/null and b/app/myapp/web/icons/Icon-192.png differ diff --git a/app/myapp/web/icons/Icon-512.png b/app/myapp/web/icons/Icon-512.png new file mode 100644 index 000000000..88cfd48df Binary files /dev/null and b/app/myapp/web/icons/Icon-512.png differ diff --git a/app/myapp/web/icons/Icon-maskable-192.png b/app/myapp/web/icons/Icon-maskable-192.png new file mode 100644 index 000000000..eb9b4d76e Binary files /dev/null and b/app/myapp/web/icons/Icon-maskable-192.png differ diff --git a/app/myapp/web/icons/Icon-maskable-512.png b/app/myapp/web/icons/Icon-maskable-512.png new file mode 100644 index 000000000..d69c56691 Binary files /dev/null and b/app/myapp/web/icons/Icon-maskable-512.png differ diff --git a/app/myapp/web/index.html b/app/myapp/web/index.html new file mode 100644 index 000000000..4cb62f656 --- /dev/null +++ b/app/myapp/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + myapp + + + + + + + + + + diff --git a/app/myapp/web/manifest.json b/app/myapp/web/manifest.json new file mode 100644 index 000000000..3ba37c261 --- /dev/null +++ b/app/myapp/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "myapp", + "short_name": "myapp", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "devclub week 1", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/app/myapp/windows/.gitignore b/app/myapp/windows/.gitignore new file mode 100644 index 000000000..d492d0d98 --- /dev/null +++ b/app/myapp/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/app/myapp/windows/CMakeLists.txt b/app/myapp/windows/CMakeLists.txt new file mode 100644 index 000000000..2657fb6c7 --- /dev/null +++ b/app/myapp/windows/CMakeLists.txt @@ -0,0 +1,102 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(myapp LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "myapp") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/app/myapp/windows/flutter/CMakeLists.txt b/app/myapp/windows/flutter/CMakeLists.txt new file mode 100644 index 000000000..930d2071a --- /dev/null +++ b/app/myapp/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/app/myapp/windows/flutter/generated_plugin_registrant.cc b/app/myapp/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..30fedc810 --- /dev/null +++ b/app/myapp/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,17 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); +} diff --git a/app/myapp/windows/flutter/generated_plugin_registrant.h b/app/myapp/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/app/myapp/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/app/myapp/windows/flutter/generated_plugins.cmake b/app/myapp/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..92783895b --- /dev/null +++ b/app/myapp/windows/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows + firebase_core +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/app/myapp/windows/runner/CMakeLists.txt b/app/myapp/windows/runner/CMakeLists.txt new file mode 100644 index 000000000..394917c05 --- /dev/null +++ b/app/myapp/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/app/myapp/windows/runner/Runner.rc b/app/myapp/windows/runner/Runner.rc new file mode 100644 index 000000000..a75d9ae7d --- /dev/null +++ b/app/myapp/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "myapp" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "myapp" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "myapp.exe" "\0" + VALUE "ProductName", "myapp" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/app/myapp/windows/runner/flutter_window.cpp b/app/myapp/windows/runner/flutter_window.cpp new file mode 100644 index 000000000..b25e363ef --- /dev/null +++ b/app/myapp/windows/runner/flutter_window.cpp @@ -0,0 +1,66 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/app/myapp/windows/runner/flutter_window.h b/app/myapp/windows/runner/flutter_window.h new file mode 100644 index 000000000..6da0652f0 --- /dev/null +++ b/app/myapp/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/app/myapp/windows/runner/main.cpp b/app/myapp/windows/runner/main.cpp new file mode 100644 index 000000000..a6156c847 --- /dev/null +++ b/app/myapp/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"myapp", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/app/myapp/windows/runner/resource.h b/app/myapp/windows/runner/resource.h new file mode 100644 index 000000000..66a65d1e4 --- /dev/null +++ b/app/myapp/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/app/myapp/windows/runner/resources/app_icon.ico b/app/myapp/windows/runner/resources/app_icon.ico new file mode 100644 index 000000000..c04e20caf Binary files /dev/null and b/app/myapp/windows/runner/resources/app_icon.ico differ diff --git a/app/myapp/windows/runner/runner.exe.manifest b/app/myapp/windows/runner/runner.exe.manifest new file mode 100644 index 000000000..a42ea7687 --- /dev/null +++ b/app/myapp/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/app/myapp/windows/runner/utils.cpp b/app/myapp/windows/runner/utils.cpp new file mode 100644 index 000000000..b2b08734d --- /dev/null +++ b/app/myapp/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/app/myapp/windows/runner/utils.h b/app/myapp/windows/runner/utils.h new file mode 100644 index 000000000..3879d5475 --- /dev/null +++ b/app/myapp/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/app/myapp/windows/runner/win32_window.cpp b/app/myapp/windows/runner/win32_window.cpp new file mode 100644 index 000000000..60608d0fe --- /dev/null +++ b/app/myapp/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/app/myapp/windows/runner/win32_window.h b/app/myapp/windows/runner/win32_window.h new file mode 100644 index 000000000..e901dde68 --- /dev/null +++ b/app/myapp/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/author.json b/author.json index 3d4a531ce..30cdaec3d 100644 --- a/author.json +++ b/author.json @@ -1,4 +1,4 @@ { - "name": "", - "entry_number": "" + "name": "Pritesh Mehta", + "entry_number": "2022MT11916" } diff --git a/backend/Product API.postman_collection.json b/backend/Product API.postman_collection.json new file mode 100644 index 000000000..49c1bdf43 --- /dev/null +++ b/backend/Product API.postman_collection.json @@ -0,0 +1,256 @@ +{ + "info": { + "_postman_id": "670c0ff7-200c-4d3c-bf3b-268145958e3d", + "name": "Product API", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "28370327" + }, + "item": [ + { + "name": "http://127.0.0.1:8000/api/signup/", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\"username\": \"\", \"password\": \"\"}" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/signup/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "signup", + "" + ] + }, + "description": "StartFragmentStartFragment\n\nCreates a new user account with the provided username and password. Upon successful creation, it returns the details of the user account, including username, user ID, and registration date.\n\nEndFragment" + }, + "response": [] + }, + { + "name": "http://127.0.0.1:8000/api/token/", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\"username\": \"\", \"password\": \"\"}" + }, + "url": { + "raw": "http://127.0.0.1:8000/api/token/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "token", + "" + ] + }, + "description": "StartFragment\n\nAuthenticates the user with the provided username and password. If the credentials are valid, it returns an access token that can be used for subsequent API calls to authenticate the user.\n\nEndFragment" + }, + "response": [] + }, + { + "name": "http://127.0.0.1:8000/products/", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer " + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://127.0.0.1:8000/products/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "products", + "" + ] + }, + "description": "StartFragment\n\nRetrieves a list of all products available in the system. Requires authentication with a valid access token. It returns an array of product objects containing details such as the product name, description, and price.\n\nEndFragment" + }, + "response": [] + }, + { + "name": "http://127.0.0.1:8000/products//", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer " + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://127.0.0.1:8000/products//", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "products", + "", + "" + ] + }, + "description": "StartFragment\n\nRetrieves detailed information about a specific product based on the provided product ID. Requires authentication with a valid access token. It returns the product details, including the name, description, price, and other relevant attributes.\n\nEndFragment" + }, + "response": [] + }, + { + "name": "http://127.0.0.1:8000/products//", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "value": "Bearer " + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://127.0.0.1:8000/products//", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "products", + "", + "" + ] + }, + "description": "StartFragment\n\nDeletes a specific product identified by the provided product ID. Requires authentication and authorization with a valid access token. If the product is successfully deleted, it returns a success message confirming the deletion.\n\nEndFragment" + }, + "response": [] + }, + { + "name": "http://127.0.0.1:8000/products//purchase/", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer " + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://127.0.0.1:8000/products//purchase/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "products", + "", + "purchase", + "" + ] + }, + "description": "StartFragment\n\nAllows the authenticated user to purchase a specific product identified by the provided product ID. Upon successful purchase, it returns a success message confirming the purchase and any relevant details, such as the order ID or transaction information.\n\nEndFragment" + }, + "response": [] + }, + { + "name": "http://127.0.0.1:8000/products/add/", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer " + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"\",\r\n \"description\": \"\",\r\n \"price\": \"\"\r\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/products/add/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "products", + "add", + "" + ] + }, + "description": "StartFragment\n\nAdds a new product to the system with the provided name, description, and price. Requires authentication with a valid access token. If the product is successfully added, it returns the details of the newly created product, including the product ID, name, description, and price.\n\nEndFragment" + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/backend/mydjangoproject/api/__init__.py b/backend/mydjangoproject/api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/mydjangoproject/api/__pycache__/__init__.cpython-311.pyc b/backend/mydjangoproject/api/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 000000000..5a350a17d Binary files /dev/null and b/backend/mydjangoproject/api/__pycache__/__init__.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/__pycache__/admin.cpython-311.pyc b/backend/mydjangoproject/api/__pycache__/admin.cpython-311.pyc new file mode 100644 index 000000000..616d4f870 Binary files /dev/null and b/backend/mydjangoproject/api/__pycache__/admin.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/__pycache__/apps.cpython-311.pyc b/backend/mydjangoproject/api/__pycache__/apps.cpython-311.pyc new file mode 100644 index 000000000..7cde8685c Binary files /dev/null and b/backend/mydjangoproject/api/__pycache__/apps.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/__pycache__/models.cpython-311.pyc b/backend/mydjangoproject/api/__pycache__/models.cpython-311.pyc new file mode 100644 index 000000000..e876342f5 Binary files /dev/null and b/backend/mydjangoproject/api/__pycache__/models.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/__pycache__/serializers.cpython-311.pyc b/backend/mydjangoproject/api/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 000000000..15f3e4525 Binary files /dev/null and b/backend/mydjangoproject/api/__pycache__/serializers.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/__pycache__/urls.cpython-311.pyc b/backend/mydjangoproject/api/__pycache__/urls.cpython-311.pyc new file mode 100644 index 000000000..81f250002 Binary files /dev/null and b/backend/mydjangoproject/api/__pycache__/urls.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/__pycache__/views.cpython-311.pyc b/backend/mydjangoproject/api/__pycache__/views.cpython-311.pyc new file mode 100644 index 000000000..6b11af14b Binary files /dev/null and b/backend/mydjangoproject/api/__pycache__/views.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/admin.py b/backend/mydjangoproject/api/admin.py new file mode 100644 index 000000000..39d4aabb5 --- /dev/null +++ b/backend/mydjangoproject/api/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from .models import Product + +@admin.register(Product) +class ProductAdmin(admin.ModelAdmin): + list_display = ['id','name', 'price', 'available','user', 'purchased_by', 'available'] + list_filter = ['available'] + diff --git a/backend/mydjangoproject/api/apps.py b/backend/mydjangoproject/api/apps.py new file mode 100644 index 000000000..66656fd29 --- /dev/null +++ b/backend/mydjangoproject/api/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ApiConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'api' diff --git a/backend/mydjangoproject/api/migrations/0001_initial.py b/backend/mydjangoproject/api/migrations/0001_initial.py new file mode 100644 index 000000000..f9de06c76 --- /dev/null +++ b/backend/mydjangoproject/api/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.2 on 2023-07-06 12:52 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Product', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('description', models.TextField()), + ('price', models.DecimalField(decimal_places=2, max_digits=8)), + ('available', models.BooleanField(default=True)), + ('purchased_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchased_products', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='created_products', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/backend/mydjangoproject/api/migrations/0002_alter_product_user.py b/backend/mydjangoproject/api/migrations/0002_alter_product_user.py new file mode 100644 index 000000000..aad656d36 --- /dev/null +++ b/backend/mydjangoproject/api/migrations/0002_alter_product_user.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.2 on 2023-07-06 14:08 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('api', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='product', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='add_product', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/backend/mydjangoproject/api/migrations/__init__.py b/backend/mydjangoproject/api/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/mydjangoproject/api/migrations/__pycache__/0001_initial.cpython-311.pyc b/backend/mydjangoproject/api/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 000000000..87c3ac3a1 Binary files /dev/null and b/backend/mydjangoproject/api/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/migrations/__pycache__/0002_alter_product_user.cpython-311.pyc b/backend/mydjangoproject/api/migrations/__pycache__/0002_alter_product_user.cpython-311.pyc new file mode 100644 index 000000000..b41bae2e3 Binary files /dev/null and b/backend/mydjangoproject/api/migrations/__pycache__/0002_alter_product_user.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/migrations/__pycache__/__init__.cpython-311.pyc b/backend/mydjangoproject/api/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 000000000..e63b56a70 Binary files /dev/null and b/backend/mydjangoproject/api/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/backend/mydjangoproject/api/models.py b/backend/mydjangoproject/api/models.py new file mode 100644 index 000000000..7ee24543c --- /dev/null +++ b/backend/mydjangoproject/api/models.py @@ -0,0 +1,26 @@ +from django.db import models +from django.contrib.auth.models import User + +class Product(models.Model): + name = models.CharField(max_length=100) + description = models.TextField() + price = models.DecimalField(max_digits=8, decimal_places=2) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='add_product') + purchased_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='purchased_products') + available = models.BooleanField(default=True) + + def __str__(self): + return self.name + + def purchase(self, user): + if self.available: + if self.user == user: + return 'You cannot purchase your own product.' + if self.purchased_by is not None: + return 'This product has already been purchased.' + self.purchased_by = user + self.available = False + self.save() + return 'Product purchased successfully.' + else: + return 'This product is not available for purchase.' diff --git a/backend/mydjangoproject/api/serializers.py b/backend/mydjangoproject/api/serializers.py new file mode 100644 index 000000000..b827606ef --- /dev/null +++ b/backend/mydjangoproject/api/serializers.py @@ -0,0 +1,19 @@ +from rest_framework import serializers +from .models import Product,User + +class ProductSerializer(serializers.ModelSerializer): + class Meta: + model = Product + fields = ['id', 'name', 'description', 'price', 'available'] +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ['username', 'password'] + extra_kwargs = {'password': {'write_only': True}} + + def create(self, validated_data): + user = User.objects.create_user( + username=validated_data['username'], + password=validated_data['password'] + ) + return user \ No newline at end of file diff --git a/backend/mydjangoproject/api/tests.py b/backend/mydjangoproject/api/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/backend/mydjangoproject/api/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/mydjangoproject/api/urls.py b/backend/mydjangoproject/api/urls.py new file mode 100644 index 000000000..127bdfc11 --- /dev/null +++ b/backend/mydjangoproject/api/urls.py @@ -0,0 +1,21 @@ +from django.urls import path +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView +from .views import ( + get_all_products, + get_product, + add_product, + delete_product, + purchase_product, + signup +) + +urlpatterns = [ + path('products/', get_all_products, name='get_all_products'), + path('products//', get_product, name='get_product'), + path('products/add/', add_product, name='add_product'), + path('products//delete/', delete_product, name='delete_product'), + path('products//purchase/', purchase_product, name='purchase_product'), + path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), + path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), + path('api/signup/', signup, name='signup'), +] diff --git a/backend/mydjangoproject/api/views.py b/backend/mydjangoproject/api/views.py new file mode 100644 index 000000000..535c1eac9 --- /dev/null +++ b/backend/mydjangoproject/api/views.py @@ -0,0 +1,134 @@ +from django.contrib.auth.models import User +from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated +from rest_framework.decorators import api_view, permission_classes +from rest_framework.response import Response +from rest_framework import status +from rest_framework_simplejwt.tokens import RefreshToken +from .models import Product +from .serializers import ProductSerializer, UserSerializer + + +def create_response(data=None, error=None, message=None, status_code=status.HTTP_200_OK): + response_data = {} + + if data is not None: + response_data['data'] = data + + if error is not None: + response_data['error'] = error + # Use error message as the default value for message + response_data['message'] = message or 'error' + elif message is not None: + response_data['message'] = message + + return Response(response_data, status=status_code) + + +@api_view(['GET']) +@permission_classes([IsAuthenticatedOrReadOnly]) +def get_all_products(request): + if request.method == 'GET': + products = Product.objects.all() + serializer = ProductSerializer(products, many=True) + return create_response(data=serializer.data, message='Products retrieved successfully.') + + +@api_view(['GET']) +@permission_classes([IsAuthenticatedOrReadOnly]) +def get_product(request, product_id): + if request.method == 'GET': + try: + product = Product.objects.get(pk=product_id) + serializer = ProductSerializer(product) + return create_response(data=serializer.data, message='Product retrieved successfully.') + except Product.DoesNotExist: + return create_response( + error='Product not found.', + status_code=status.HTTP_404_NOT_FOUND + ) + + +@api_view(['POST']) +@permission_classes([IsAuthenticated]) +def add_product(request): + if request.method == 'POST': + serializer = ProductSerializer(data=request.data) + if serializer.is_valid(): + serializer.save(user=request.user) + return create_response( + data=serializer.data, + message='Product added successfully.', + status_code=status.HTTP_201_CREATED + ) + return create_response( + error=serializer.errors, + status_code=status.HTTP_400_BAD_REQUEST + ) + + +@api_view(['DELETE']) +@permission_classes([IsAuthenticated]) +def delete_product(request, product_id): + if request.method == 'DELETE': + try: + product = Product.objects.get(pk=product_id) + + # Check if the authenticated user is the same as the user who created the product + if request.user != product.user: + return create_response( + error='You are not allowed to delete this product.', + status_code=status.HTTP_403_FORBIDDEN + ) + + product.delete() + return create_response( + message='Product deleted successfully.', + status_code=status.HTTP_204_NO_CONTENT + ) + except Product.DoesNotExist: + return create_response( + error='Product not found.', + status_code=status.HTTP_404_NOT_FOUND + ) + + +@api_view(['GET']) +@permission_classes([IsAuthenticated]) +def purchase_product(request, product_id): + try: + product = Product.objects.get(pk=product_id) + user = request.user + + if product.user == user: + return create_response( + error='You cannot purchase your own product.', + status_code=status.HTTP_400_BAD_REQUEST + ) + + message = product.purchase(user) + return create_response( + message=message, + data={'product_id': product_id}, + status_code=status.HTTP_200_OK + ) + except Product.DoesNotExist: + return create_response( + error='Product not found.', + status_code=status.HTTP_404_NOT_FOUND + ) + + +@api_view(['POST']) +def signup(request): + serializer = UserSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return create_response( + data=serializer.data, + message='User registered successfully.', + status_code=status.HTTP_201_CREATED + ) + return create_response( + error=serializer.errors, + status_code=status.HTTP_400_BAD_REQUEST + ) diff --git a/backend/mydjangoproject/db.sqlite3 b/backend/mydjangoproject/db.sqlite3 new file mode 100644 index 000000000..bb2069e2e Binary files /dev/null and b/backend/mydjangoproject/db.sqlite3 differ diff --git a/backend/mydjangoproject/manage.py b/backend/mydjangoproject/manage.py new file mode 100644 index 000000000..62f3e6225 --- /dev/null +++ b/backend/mydjangoproject/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/backend/mydjangoproject/mydjangoproject/__init__.py b/backend/mydjangoproject/mydjangoproject/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/mydjangoproject/mydjangoproject/__pycache__/__init__.cpython-311.pyc b/backend/mydjangoproject/mydjangoproject/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 000000000..dd76015ae Binary files /dev/null and b/backend/mydjangoproject/mydjangoproject/__pycache__/__init__.cpython-311.pyc differ diff --git a/backend/mydjangoproject/mydjangoproject/__pycache__/settings.cpython-311.pyc b/backend/mydjangoproject/mydjangoproject/__pycache__/settings.cpython-311.pyc new file mode 100644 index 000000000..5bc2e0275 Binary files /dev/null and b/backend/mydjangoproject/mydjangoproject/__pycache__/settings.cpython-311.pyc differ diff --git a/backend/mydjangoproject/mydjangoproject/__pycache__/urls.cpython-311.pyc b/backend/mydjangoproject/mydjangoproject/__pycache__/urls.cpython-311.pyc new file mode 100644 index 000000000..c8d4c7c89 Binary files /dev/null and b/backend/mydjangoproject/mydjangoproject/__pycache__/urls.cpython-311.pyc differ diff --git a/backend/mydjangoproject/mydjangoproject/__pycache__/wsgi.cpython-311.pyc b/backend/mydjangoproject/mydjangoproject/__pycache__/wsgi.cpython-311.pyc new file mode 100644 index 000000000..2c77f7999 Binary files /dev/null and b/backend/mydjangoproject/mydjangoproject/__pycache__/wsgi.cpython-311.pyc differ diff --git a/backend/mydjangoproject/mydjangoproject/asgi.py b/backend/mydjangoproject/mydjangoproject/asgi.py new file mode 100644 index 000000000..7e23598f6 --- /dev/null +++ b/backend/mydjangoproject/mydjangoproject/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for mydjangoproject project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + +application = get_asgi_application() diff --git a/backend/mydjangoproject/mydjangoproject/settings.py b/backend/mydjangoproject/mydjangoproject/settings.py new file mode 100644 index 000000000..e6e869cfd --- /dev/null +++ b/backend/mydjangoproject/mydjangoproject/settings.py @@ -0,0 +1,134 @@ +""" +Django settings for mydjangoproject project. + +Generated by 'django-admin startproject' using Django 4.2.2. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-a3r*juna7qy)&zmvh*rp55(z_tm(xx_%s9yf8#0yuwty&4+dpd' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'api', + 'rest_framework', + 'rest_framework_simplejwt', +] +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ], +} + +SIMPLE_JWT = { + 'AUTH_HEADER_TYPES': ('Bearer',), +} +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'mydjangoproject.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'mydjangoproject.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/backend/mydjangoproject/mydjangoproject/urls.py b/backend/mydjangoproject/mydjangoproject/urls.py new file mode 100644 index 000000000..6e4a49a0e --- /dev/null +++ b/backend/mydjangoproject/mydjangoproject/urls.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include('api.urls')), +] + diff --git a/backend/mydjangoproject/mydjangoproject/wsgi.py b/backend/mydjangoproject/mydjangoproject/wsgi.py new file mode 100644 index 000000000..f2f677db2 --- /dev/null +++ b/backend/mydjangoproject/mydjangoproject/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mydjangoproject project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + +application = get_wsgi_application() diff --git a/backend/mydjangoproject/requirements.txt b/backend/mydjangoproject/requirements.txt new file mode 100644 index 000000000..6d6c5a90c --- /dev/null +++ b/backend/mydjangoproject/requirements.txt @@ -0,0 +1,3 @@ +django +djangorestframework +djangorestframework-simplejwt diff --git a/backend/mydjangoproject/test.py b/backend/mydjangoproject/test.py new file mode 100644 index 000000000..73e65f857 --- /dev/null +++ b/backend/mydjangoproject/test.py @@ -0,0 +1,71 @@ +import requests +from faker import Faker +from random import randint +import json +fake = Faker() +baseurl = "http://127.0.0.1:8000/" + +class User: + def __init__(self, username, pwd): + self.username = username + self.pwd = pwd + self.headers = {"Content-Type": "application/json"} + + def add_token(self, token): + self.headers["Authorization"] = f"Bearer {token}" + + def signup(self): + print("signup...") + response = requests.post(f'{baseurl}api/signup/', {'username': self.username, 'password': self.pwd}) + print(response) + print(response.text) + + def login(self): + print("login...") + response = requests.post(f'{baseurl}api/token/', {'username': self.username, 'password': self.pwd}) + print(response) + self.add_token(response.json()["access"]) + + def get_all_products(self): + print("get_all_products...") + response = requests.get(f'{baseurl}products/', headers=self.headers) + print(response) + print(response.json()) + + def get_product(self, product_id): + print("get_product...") + response = requests.get(f'{baseurl}products/{product_id}/', headers=self.headers) + print(response) + print(response.json()) + + def delete_product(self, product_id): + print("delete_product...") + response = requests.delete(f'{baseurl}products/{product_id}/', headers=self.headers) + print(response) + print(response.text) + + def purchase_product(self, product_id): + print("purchase_product...") + response = requests.get(f'{baseurl}products/{product_id}/purchase/', headers=self.headers) + print(response) + print(response.text) + def add_product(self): + print("add_product...") + data = {'name':fake.name(),'description':fake.text(),'price':randint(1,100)} + print(data) + response = requests.post(f'{baseurl}products/add/',json.dumps(data),headers=self.headers) + print(response) + print(response.text) + + +# Create two different dummy users +user1 = User("user1", "password1") +user2 = User("user2", "password2") +user3 = User("user3", "password3") +user4 = User("user4", "password4") +# user1.login() +# user2.login() +# user3.login() +# user4.login() + +user3.purchase_product(45) \ No newline at end of file diff --git a/backend/week1/report.md b/backend/week1/report.md new file mode 100644 index 000000000..9085fc7dc --- /dev/null +++ b/backend/week1/report.md @@ -0,0 +1,96 @@ +# Moodle Browser-Server Communication Report + +This report analyzes the browser-server communication during the login process in Moodle. It explores the requests made by the browser to the server, the headers in the server responses, the login process, and the usage of cookies for authentication. + +## Requests and Initiators + +1. **Request 1:** + - URL: https://moodle.iitd.ac.in/login/index.php + - Method: POST + + Request Header: + ``` + POST /login/index.php HTTP/1.1 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 + ... + ``` + + Response Header: + ``` + HTTP/1.1 303 See Other + Date: Mon, 26 Jun 2023 03:17:36 GMT + ... + ``` + +2. **Request 2:** + - URL: https://moodle.iitd.ac.in/login/index.php?testsession=49144 + - Method: GET + + Request Header: + ``` + GET /login/index.php?testsession=49144 HTTP/1.1 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 + ... + ``` + + Response Header: + ``` + HTTP/1.1 303 See Other + Date: Mon, 26 Jun 2023 03:17:37 GMT + ... + ``` + +3. **Request 3:** + - URL: https://moodle.iitd.ac.in/my/ + - Method: GET + + Request Header: + ``` + GET /my/ HTTP/1.1 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 + ... + ``` + + Response Header: + ``` + HTTP/1.1 200 OK + Date: Mon, 26 Jun 2023 03:17:37 GMT + ... + ``` + +## Server Response Headers + +- Date: The date and time when the response was generated by the server. +- Server: The software and version information of the server. +- Expires: The date and time when the response should be considered expired and should not be cached. +- Cache-Control: Directives specifying caching behavior for the response. +- Pragma: Provides backward compatibility for HTTP/1.0 caches. +- Content-Language: The natural language(s) of the intended audience for the response. +- Content-Script-Type: The scripting language used in the response. +- Content-Style-Type: The style sheet language used in the response. +- X-UA-Compatible: Defines the compatibility mode for rendering the response in the browser. +- Accept-Ranges: Indicates if the server supports byte ranges for the requested resource. +- X-Frame-Options: Protects against clickjacking attacks by restricting how the page can be framed. +- Vary: Informs caches that the response may vary based on certain request headers. +- Content-Encoding: The type of encoding applied to the response body. +- Content-Length: The size of the response body in bytes. +- Keep-Alive: Indicates the maximum number of requests that can be sent on the connection before closing it. +- Connection: Specifies if the connection should be kept alive after the current request. +- Content-Type: The media type of the response body. + +## Login Process in Moodle + +1. The browser initiates a POST request to ```https://moodle.iitd.ac.in/login/index.php``` with the login credentials and other necessary data. +2. The server responds with a status code of 303 See Other, indicating a redirection. +3. The browser follows the redirect and sends a GET request to ```https://moodle.iitd.ac.in/login/index.php?testsession=49144```. +4. The server responds with a status code of 303 See Other, indicating another redirection. +5. The browser follows the second redirect and sends a GET request to ```https://moodle.iitd.ac.in/my/```. +6. The server responds with a status code of 200 OK, indicating a successful request. + +## Cookies and Authentication + +Cookies are used in the browser-server communication to maintain stateful communication, session management, and authentication. In Moodle, the following cookies are used: +- MoodleSession: This cookie stores the session ID, allowing the server to associate subsequent requests with the user's session. +- MOODLEID1_: This cookie is used for authentication and is assigned a unique value for each user. + +The cookies are sent by the browser in the Cookie header with each subsequent request, allowing the server to identify and authenticate the user. The server sets the cookies in the Set-Cookie header in the server responses, instructing the browser to store and send them in future requests. diff --git a/backend/week1/server.md b/backend/week1/server.md new file mode 100644 index 000000000..2c0872822 --- /dev/null +++ b/backend/week1/server.md @@ -0,0 +1,138 @@ +# URL Shortener Backend + +This is the backend server for a URL shortener application. It provides APIs for creating short URLs, redirecting to original URLs, updating URL destinations, and user authentication. + +## Base URL + +The base URL for the backend server is: `http://localhost:8000` + +## Endpoints + +### Login + +Request: +- Method: POST +- URL: `/login` +- Headers: + - Content-Type: application/json +- Body: + ```json + { + "username": "your_username", + "password": "your_password" + } + ``` + +Response: +- Status Code: 200 (OK) +- Headers: + - Content-Type: application/json +- Body: + ```json + { + "message": "Login successful", + "cookie": "your_cookie" + } + ``` + +### Signin + +Request: +- Method: POST +- URL: `/signin` +- Headers: + - Content-Type: application/json +- Body: + ```json + { + "username": "your_username", + "password": "your_password" + } + ``` + +Response: +- Status Code: 200 (OK) +- Headers: + - Content-Type: application/json +- Body: + ```json + { + "message": "Login successful", + "cookie": "your_cookie" + } + ``` + +### Create Short URL + +Request: +- Method: POST +- URL: `/create//` +- Headers: + - Content-Type: application/json + - Cookie: your_cookie (received from the login response) +- Example URL: `/create/abc123/http://www.example.com` + +Response: +- Status Code: 201 (Created) +- Headers: + - Content-Type: application/json +- Body: + ```json + { + "message": "Short URL created successfully" + } + ``` + +### Redirect to Original URL + +Request: +- Method: GET +- URL: `/redirect/` +- Example URL: `/redirect/abc123` + +Response: +- Status Code: 302 (Found) +- Headers: + - Location: http://www.example.com (original destination URL) + +### Update URL Destination + +Request: +- Method: PATCH +- URL: `/update//` +- Headers: + - Content-Type: application/json + - Cookie: your_cookie (received from the login response) +- Example URL: `/update/abc123/http://www.new-example.com` + +Response: +- Status Code: 200 (OK) +- Headers: + - Content-Type: application/json +- Body: + ```json + { + "message": "URL destination updated successfully" + } + ``` + +## Error Handling + +In case of errors, the server will respond with appropriate status codes and error messages in the response body. Here are some common status codes and their corresponding meanings: + +- 401 (Unauthorized): Invalid login credentials or session expired. +- 403 (Forbidden): User does not have permission to perform the requested action. +- 404 (Not Found): The requested resource or URL does not exist. +- 409 (Conflict): Short code or username already exists. + +Please ensure that you handle these error responses properly in your frontend application. + +## Authentication + +To authenticate requests, you need to include a cookie header with the received cookie value from the login response. Make sure to send the cookie with each subsequent request that requires authentication. + +## Contributing + +If you encounter any issues or have suggestions for improvement, please feel free to contribute to this project by submitting bug reports or pull requests. + +Thank you for using the URL shortener backend! diff --git a/backend/week1/server.py b/backend/week1/server.py new file mode 100644 index 000000000..47b662626 --- /dev/null +++ b/backend/week1/server.py @@ -0,0 +1,218 @@ +"""This is an API for creating shorturl for more instructions read server.md""" +import http.server +import sqlite3 +import json +from urllib.parse import parse_qs +import uuid + +# Empty dictionary to store cookies +cookies = {} + +# Database connection +conn = sqlite3.connect("url_shortener.db") +c = conn.cursor() + +# Create URLs table if it doesn't exist +c.execute(''' + CREATE TABLE IF NOT EXISTS urls ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + short_code TEXT NOT NULL, + destination_url TEXT NOT NULL, + user TEXT NOT NULL, + visit_count INTEGER DEFAULT 0 + ) +''') + +# Create users table if it doesn't exist +c.execute(''' + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password TEXT NOT NULL + ) +''') + +# Function to handle login request +def login_handler(body): + username = body.get("username", [""])[0] + password = body.get("password", [""])[0] + + c.execute("SELECT * FROM users WHERE username=?", (username,)) + user = c.fetchone() + + if user: + if user[2] == password: + user_id = str(uuid.uuid4()) + cookies[user_id] = username + return (200, {"message": "Login successful", "user_id": user_id}) + else: + return (401, {"message": "Invalid password"}) + else: + return (401, {"message": "Invalid username"}) + +# Function to handle signin request +def signin_handler(body): + username = body.get("username", [""])[0] + password = body.get("password", [""])[0] + + c.execute("SELECT * FROM users WHERE username=?", (username,)) + user = c.fetchone() + + if user: + return (409, {"message": "User already exists"}) + else: + user_id = str(uuid.uuid4()) + cookies[user_id] = username + c.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username, password)) + conn.commit() + return (200, {"message": "Signin successful", "user_id": user_id}) + +# Function to handle create short URL request +def create_handler(short_code, destination_url, user_cookie): + if user_cookie not in cookies: + return (401, {"message": "Session expired. Please login again"}) + + user = cookies[user_cookie] + + c.execute("SELECT * FROM urls WHERE short_code=?", (short_code,)) + url = c.fetchone() + + if url: + return (409, {"message": "Short code already exists"}) + + c.execute("INSERT INTO urls (short_code, destination_url, user) VALUES (?, ?, ?)", (short_code, destination_url, user)) + conn.commit() + return (201, {"message": "Short URL created successfully"}) + + +# Function to handle redirect request +def redirect_handler(short_code): + c.execute("SELECT * FROM urls WHERE short_code=?", (short_code,)) + url = c.fetchone() + + if url: + visit_count = url[4] + 1 + c.execute("UPDATE urls SET visit_count=? WHERE short_code=?", (visit_count, short_code)) + conn.commit() + return (302, {"Location": url[2]}) + else: + return (404, {"message": "Short URL not found"}) + + +# Function to handle update request +def update_handler(short_code, new_destination_url, user_cookie): + if user_cookie not in cookies: + return (401, {"message": "Session expired. Please login again"}) + + user = cookies[user_cookie] + + c.execute("SELECT * FROM urls WHERE short_code=?", (short_code,)) + url = c.fetchone() + + if url: + if url[3] != user: + return (403, {"message": "You don't have permission to update this URL"}) + + c.execute("UPDATE urls SET destination_url=?, visit_count=0 WHERE short_code=?", (new_destination_url, short_code)) + conn.commit() + return (200, {"message": "URL destination updated successfully"}) + else: + return (404, {"message": "Short URL not found"}) + + +# Custom HTTP request handler +class RequestHandler(http.server.BaseHTTPRequestHandler): + + # Set response headers + def set_headers(self, status_code, user_id=None): + self.send_response(status_code) + self.send_header("Content-Type", "application/json") + if user_id: + self.send_header("Set-Cookie", f"{user_id}") + self.end_headers() + + + + + # Parse the request body + def parse_body(self): + content_length = int(self.headers.get("Content-Length", 0)) + body = self.rfile.read(content_length).decode("utf-8") + return parse_qs(body) + + # Handle login request + def handle_login(self): + body = self.parse_body() + status_code, response_body = login_handler(body) + user_id = response_body.get("user_id") + self.set_headers(status_code, user_id) + self.wfile.write(bytes(json.dumps(response_body), "utf-8")) + + + # Handle signin request + def handle_signin(self): + body = self.parse_body() + status_code, response_body = signin_handler(body) + user_id = response_body.get("user_id") + self.set_headers(status_code, user_id) + self.wfile.write(bytes(json.dumps(response_body), "utf-8")) + + + # Handle create short URL request + def handle_create(self, short_code, destination_url): + user_cookie = self.headers.get("Cookie", "") + status_code, response_body = create_handler(short_code, destination_url, user_cookie) + self.set_headers(status_code) + self.wfile.write(bytes(json.dumps(response_body), "utf-8")) + + # Handle redirect request + def handle_redirect(self, short_code): + status_code, response_body = redirect_handler(short_code) + self.set_headers(status_code) + if status_code == 302: + self.send_header("Location", response_body["Location"]) + self.wfile.write(bytes("", "utf-8")) + + # Handle update request + def handle_update(self, short_code, new_destination_url): + user_cookie = self.headers.get("Cookie", "") + status_code, response_body = update_handler(short_code, new_destination_url, user_cookie) + self.set_headers(status_code) + self.wfile.write(bytes(json.dumps(response_body), "utf-8")) + + # Handle HTTP GET requests + def do_GET(self): + if self.path.startswith("/redirect/"): + short_code = self.path[len("/redirect/"):] + self.handle_redirect(short_code) + + # Handle HTTP POST requests + def do_POST(self): + if self.path == "/login": + self.handle_login() + elif self.path == "/signin": + self.handle_signin() + elif self.path == "/create": + body = self.parse_body() + short_code = body.get("short_code", [""])[0] + destination_url = body.get("destination_url", [""])[0] + self.handle_create(short_code, destination_url) + + # Handle HTTP PATCH requests + def do_PATCH(self): + if self.path.startswith("/update/"): + short_code = self.path[len("/update/"):] + body = self.parse_body() + new_destination_url = body.get("destination_url", [""])[0] + self.handle_update(short_code, new_destination_url) + + +# Run the server +def run(server_class=http.server.HTTPServer, handler_class=RequestHandler): + server_address = ("", 8000) + httpd = server_class(server_address, handler_class) + httpd.serve_forever() + + +if __name__ == "__main__": + run() diff --git a/gitcommands.txt b/gitcommands.txt new file mode 100644 index 000000000..30885cf00 --- /dev/null +++ b/gitcommands.txt @@ -0,0 +1,8 @@ +git fetch upstream +git checkout main +git merge upstream/main +git push origin main + +git add . +git commit -m "Submission" +git push origin main diff --git a/release/app-release.apk b/release/app-release.apk new file mode 100644 index 000000000..528b45944 Binary files /dev/null and b/release/app-release.apk differ