diff --git a/.metadata b/.metadata
index 784ce129..391c336b 100644
--- a/.metadata
+++ b/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3"
+ revision: "5874a72aa4c779a02553007c47dacbefba2374dc"
channel: "stable"
project_type: app
@@ -13,11 +13,26 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
+ create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ - platform: android
+ create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ - platform: ios
+ create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ - platform: linux
+ create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ - platform: macos
+ create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
- platform: web
- create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
+ create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ - platform: windows
+ create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
+ base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
# User provided section
diff --git a/README.md b/README.md
index 451d649a..6f66bd14 100644
--- a/README.md
+++ b/README.md
@@ -1,132 +1,73 @@
-# get-flutter-fire
+# Chess Central
-This codebase provides a boilerplate code utilizing the following three technologies:
+## Introduction
-1. Flutter 3.0 - For UX and uses Dart languange. See [https://flutter.dev/]
-2. GetX - State management for Flutter. See [https://github.com/jonataslaw/getx/tree/4.6.1]
-3. Firebase - For Backend as a Service. See [https://firebase.google.com/]
- 1. Easy Authentication flow
- 2. Server side functions
- 3. Remote Configurations which can be used for A/B testing
+Hello! I'm Saubhagya Singh, a Flutter developer with a deep passion for chess. I was tasked with creating a Flutter app for the 1st round of Sharekhan, so I chose to go beyond conventional approaches and create something innovative. By leveraging the essence of the boilerplate code provided by Mr. Anshuman Das, I crafted a unique application.
-This was created as part of my own learning process and you will find that git commits were made according to the Steps listed below. You can use the git version history to check each commit and learn step by step, as I did.
+In my previous projects, I utilized the traditional Model-View-Controller (MVC) file system. For this project, however, I embraced a more advanced architecture: Bindings-Views-Controllers (BVC). This sophisticated approach, along with a structured folder system for services and widgets, enables a cleaner and more efficient development process.
-I am also using this codebase as an experiment towards hiring people (freshers especially but not limited to them) for my development team. If you are in Mumbai and are interested to join my team, you can use this codebase in the following manner:
+## Chess Central Overview
-* Fork the codebase
-* Add your own firebase_options.dart (follow steps and see firebase_options.template)
-* **Build your own application using this as a base (integrating any existing project of yours also works)**, or complete a TODO or fix a bug (only if you have no other ideas)
-* Send me a Pull Request. Mention a way of connecting with you in the commit message along with details of commit. Also modify ReadMe to say what you have changed in detail.
-* I will go through the request and then connect with you if I find the entry to be interesting and take an interview round.
+**Chess Central** is an app tailored for professional chess players, offering a range of features to enhance their chess experience. The app serves as a comprehensive solution with the following key functionalities:
-## The Steps
+1. **Live Chess Streamers on Twitch**:
+ - Access and view your favorite chess streams directly within the app.
-Step 1: Use Get CLI [https://pub.dev/packages/get_cli]
+2. **Top 100 World-Level Players List**:
+ - Stay updated with the list of the top 100 chess players globally, including their rankings and profiles.
-`get create project`
+3. **FIDE Search**:
+ - Search for a player's FIDE ID to obtain detailed information about their game history and profile. For example, you can check my FIDE ID [25660586](https://www.fide.com/en/players/25660586) and Magnus Carlsen's FIDE ID [1503014](https://www.fide.com/en/players/1503014).
-Step 2: Copy code from [https://github.com/jonataslaw/getx/tree/4.6.1/example_nav2/lib]
+4. **Firebase Authentication**:
+ - Secure user authentication using Firebase Auth to ensure a reliable and safe login experience.
-Step 3: Integrate FlutterFire Authentication
+5. **Google Sign-In Option**:
+ - Sign in easily with your Google account for a seamless authentication process.
-- Tutorials [https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps#0] for inspiration
-- Firebase Documentation [https://firebase.google.com/docs/auth/flutter/start]
-- Blog [www.medium.com/TBD]
-- To compile the code ensure that you generate your own firebase_options.dart by running
+6. **Image Picker for Profile Updates**:
+ - Use the image picker feature to update and customize your profile picture.
- `flutterfire configure`
+7. **Firestore Integration**:
+ - Store and manage user data, including profile images, using Firestore for a scalable and real-time database solution.
-Step 4: Add Google OAuth [https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps#6]. Note ensure you do the steps for Android and iOS as the code for it is not in Github
+## Development Insights
-Step 5: Add Guest User/Anonymous login with a Cart and Checkout use case [https://firebase.google.com/docs/auth/flutter/anonymous-auth]
+The development of Chess Central was completed within a tight timeframe, and there is ample room for future enhancements. Each step of the development process is meticulously documented through commit messages, allowing you to track the evolution of the project.
-* delete unlinked anonymous user post logout
+### Design and Assets
-Step 6: Add ImagePicker and Firebase Storage for profile image
+I have included the Excalidraw file, which contains the base design and wireframe of the app. Most of the images used in the app are Gemini-generated to avoid copyright issues, and the app's logo was designed using Canva.
-* Create PopupMenu button for web [https://api.flutter.dev/flutter/material/PopupMenuButton-class.html]
-* BottomSheet for phones and single file button for desktops
-* GetX and Image Picker [https://stackoverflow.com/questions/66559553/flutter-imagepicker-with-getx]
-* Add FilePicker [https://medium.com/@onuaugustine07/pick-any-file-file-picker-flutter-f82c0144e27c]
-* Firebase Storage [https://mercyjemosop.medium.com/select-and-upload-images-to-firebase-storage-flutter-6fac855970a9] and [https://firebase.google.com/docs/storage/flutter/start]
+### APIs Utilized
- Modify the Firebase Rules
- `service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow write: if request.auth.uid != null; allow read: if true; } } }`
+For real-time data integration, the following APIs have been used:
+- [FIDE API](https://app.fide.com/api/docs): Provides access to FIDE-related data and player information.
+- [Chess.com API](https://api.chess.com/pub/): Offers real-time chess data, including player profiles and game statistics.
- Fix CORS [https://stackoverflow.com/questions/37760695/firebase-storage-and-access-control-allow-origin]
-* PList additions [https://medium.com/unitechie/flutter-tutorial-image-picker-from-camera-gallery-c27af5490b74]
+A big thank you to the creators of these APIs for providing such valuable resources.
-Step 7: Additional Auth flow items
+### Development Environment
-1. Add a Change Password Screen. The Flutter Fire package does not have this screen.
-2. TODO: Add ReCaptcha to login flow for password authentication for Web only
- * Phone Auth on Web has a ReCaptcha already [https://firebase.flutter.dev/docs/auth/phone/]. Tried to use that library but it is very cryptic.
- * Use the following instead [https://stackoverflow.com/questions/60675575/how-to-implement-recaptcha-into-a-flutter-app] or [https://medium.com/cloudcraftz/securing-your-flutter-web-app-with-google-recaptcha-b556c567f409] or [https://pub.dev/packages/g_recaptcha_v3]
-3. TODO: Ensure Reset Password has Email verification
-4. TODO: Add Phone verification [https://firebase.google.com/docs/auth/flutter/phone-auth]
- * See [https://github.com/firebase/flutterfire/issues/4189].
-5. TODO: Add 2FA with SMS Pin. This screen is available in the Flutter Fire package
+This project was developed using the following tools and versions:
-Step 8: Add Firebase Emulator to test on laptop instead of server so that we can use Functions without upgrading the plan to Blaze. See [https://firebase.google.com/docs/emulator-suite/install_and_configure]
+- **Flutter**: 3.24.1 • channel stable • [Flutter GitHub Repository](https://github.com/flutter/flutter.git)
+ - Framework • revision 5874a72aa4 (11 days ago) • 2024-08-20 16:46:00 -0500
+ - Engine • revision c9b9d5780d
+ - Tools • Dart 3.5.1 • DevTools 2.37.2
-Step 9: Add User Roles using Custom Claims. This requires upgrade of plan as we need to use Firebase Functions. Instead using Emulator.
+- **Kotlin**: 1.7.10
+- **Groovy**: 3.0.13
+- **Ant**: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
+- **JVM**: 22.0.2 (Oracle Corporation 22.0.2+9-70)
+- **OS**: Windows 11 10.0 amd64
-1. In Emulator we can add user via http://127.0.0.1:4000/auth and add custom claim via UI as {"role":"admin"}. The effect is shown via Product page in Nav instead of Cart page for admin user.
-2. Add Function to add the custom claim to make the first user the admin using the Admin SDK
-3. Registeration form to collect some data post signUp and enforce email verification from Client side.
+### Stable Release APK
- * Note! for Emulator check the console to verify using the link provided as email is not sent.
-4. Enforcing verify email using a button which appears when SignIn fails due to non verification.
+A stable release APK of the app has been added to the `stableapks` folder in this repository. You can download and install it to experience the app without needing to build it from source.
- * Fixed the error handling message during login.
- * Coverted server side to Typescript
- * Enabled Resend verification mail button
- * Approach 1 - Use Email Link Authentication and signIn, assuming it marks email as verified also. We cannot send the verification mail as is, since that can be sent only if signed in (which was allowed only for first login post signup)
- * Refer https://firebase.google.com/docs/auth/flutter/email-link-auth
- * TODO Enable Deep Linking: According to https://firebase.google.com/docs/dynamic-links/flutter/receive, the Flutter feature is being deprecated and we should use the AppLinks (Android), UniversalLinks(iOS) instead. Leaving this for future as adding complexity.
- * We could use the server side handling instead of deep linking. See [https://firebase.google.com/docs/auth/custom-email-handler?hl=en&authuser=0#web]. However, this requires changing the email template for the URL which is not possible in Emulator. Using the continueURL instead does not work as oobCode is already expired. This handling also uses the web client sdk. Thus it is better to go with the below method instead.
- * Approach 2 - (Hack) send a create request with suffix ".verify" added in email when button clicked. Use the server side beforeCreate to catch this and send verification mail
- * Note that the Server side beforeCreate function can also bypass user creation till verification but the user record (esp password) needs to be stored anyways, so bypassing user creation is not a good idea. Instead, we should use the verified tag in subsequent processing
- * Sending emails from server side is possible but by using the web client SDK.
-5. TODO: Other Items
+## Contact Me
+For any questions or feedback, please reach out to me at:
- * TODO: Using autocomplete for emails is throwing error log in terminal. No impact but need to fix when all is done.
- * TODO: Add a job that removes all unverified users after a while automatically. This could be useful if you were victim of bot attacks, but adding the Recaptcha is better precaution. See [https://stackoverflow.com/questions/67148672/how-to-delete-unverified-e-mail-addresses-in-firebase-authentication-flutter/67150606#67150606]
-6. Added Roles of Buyer and Seller.
-
- 1. Added Access level in increasing order of role order => Buyer then Seller then Admin
- 2. Created Navigation for each of Admin, Buyer, Seller screens
- 3. Allowed switch from lower role Navigation to Navigation view till the given role of the user
-
-Step 10: Firebase Remote Config for A/B testing. See [https://firebase.google.com/docs/remote-config]
-
-1. Complete the Screen enum based Navigation framework
-2. Config useBottomSheetForProfileOptions for Navigation element to be one of the following
- * False: Drawer for Account, Settings, Sign Out
- * True: Hamburger that opens BottomSheet (Context Menu in larger screen) for the same options
-3. TODO: Config for adding Search Bar at the Top vs a Bottom Navigation button
-
-Step 11: TODO: CRUD
-
-* Users request role upgrade
-* Add this request data to Firebase Datastore
-* Create ListView with slidable tiles for approvals
-* Admin SDK used by admin user via workflow on this request data and is approved from app
- * Allow a Plan attribute via Custome Claims (e.g. Premium user flag) for Buyer and Seller, to add features which are not Navigation linked. Add a button Upgrade to Plan in Drawer that leads to Payment screen. Also certain aspects of premium plan can be visible that leads to upgrade plan screen via middleware
-* Nested Category, Sub-Category tree creation
-
-Step 12: TODO: Theming and Custom Settings
-
-* Add Persona (like that in Netflix) and create a Persona selection only for Buyer Role
-* Add Minimal (Three Color Gradient Pallette) Material Theme. Align it with Persona Templates (like Kids Template in Netflix)
-* Dark theme toggle setting based on each Persona of the logged in User
-
-Step 13: TODO: Large vs Small screen responsiveness
-
-* Drawer: Triggered by Top Left Icon (App Logo). For iOS this icon changes to back button when required. Contains allowed Role List, Screens specified as Drawer. Becomes Left Side Navigation for Horizontal Screens. Can have additional extreme left vertical Navigation Strip. Bottom Navigation Bar also folds into this strip in Horizontal Screens.
-* Top Right Icon: used for Login and post Login triggers BottomSheet/Context Menu for Persona Change, Profile, Settings, Change Password, Logout
-* Search Bar (Toggle Button for phones) on Top Center with Title
-* Status Bottom Bar for desktops only instead of SnackBars
-* FAB vs Main Menu
-
-Step 14: TODO: Make own login flow screens. Remove firebase library reference from all but auth_service
+Email: saubhagyasingh65@gmail.com
+WhatsApp: 7007084088
diff --git a/android/app/google-services.json b/android/app/google-services.json
new file mode 100644
index 00000000..dc848d97
--- /dev/null
+++ b/android/app/google-services.json
@@ -0,0 +1,54 @@
+{
+ "project_info": {
+ "project_number": "665419326653",
+ "project_id": "chess-central-4c15f",
+ "storage_bucket": "chess-central-4c15f.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:665419326653:android:077cf8ab4494bd67c183d4",
+ "android_client_info": {
+ "package_name": "com.chesscentral.app"
+ }
+ },
+ "oauth_client": [
+ {
+ "client_id": "665419326653-7boc52h82ni06dlnc16oevcfeoored5e.apps.googleusercontent.com",
+ "client_type": 1,
+ "android_info": {
+ "package_name": "com.chesscentral.app",
+ "certificate_hash": "4e961d881a11e79ac32d52e2a9a56fc31d17650c"
+ }
+ },
+ {
+ "client_id": "665419326653-uc4h9vcq20t5m38oglql9q34eah160fj.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
+ "api_key": [
+ {
+ "current_key": "AIzaSyDDN0LWO7i8Wpe6REmBbaTu5SmcGnUs0e4"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": [
+ {
+ "client_id": "665419326653-uc4h9vcq20t5m38oglql9q34eah160fj.apps.googleusercontent.com",
+ "client_type": 3
+ },
+ {
+ "client_id": "665419326653-a24rvt8u1atdcgvrhf08d6qq9h39d55n.apps.googleusercontent.com",
+ "client_type": 2,
+ "ios_info": {
+ "bundle_id": "com.example.getFlutterFire"
+ }
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt b/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt
new file mode 100644
index 00000000..6490c904
--- /dev/null
+++ b/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.chesscentral.app
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()
diff --git a/android/app/src/main/res/drawable/splash.png b/android/app/src/main/res/drawable/splash.png
new file mode 100644
index 00000000..77c7e427
Binary files /dev/null and b/android/app/src/main/res/drawable/splash.png differ
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..98ee8e6e
--- /dev/null
+++ b/android/app/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+
+ #000000
+
diff --git a/assets/icons/logo.png b/assets/icons/logo.png
index 77ffea42..5f7312f3 100644
Binary files a/assets/icons/logo.png and b/assets/icons/logo.png differ
diff --git a/assets/images/2dvs.png b/assets/images/2dvs.png
new file mode 100644
index 00000000..4245f912
Binary files /dev/null and b/assets/images/2dvs.png differ
diff --git a/assets/images/3dvs.png b/assets/images/3dvs.png
new file mode 100644
index 00000000..f62f43b8
Binary files /dev/null and b/assets/images/3dvs.png differ
diff --git a/assets/images/3dvs2.png b/assets/images/3dvs2.png
new file mode 100644
index 00000000..78840c86
Binary files /dev/null and b/assets/images/3dvs2.png differ
diff --git a/assets/images/ding.jpg b/assets/images/ding.jpg
new file mode 100644
index 00000000..89b1e566
Binary files /dev/null and b/assets/images/ding.jpg differ
diff --git a/assets/images/ding.png b/assets/images/ding.png
new file mode 100644
index 00000000..173b9fe2
Binary files /dev/null and b/assets/images/ding.png differ
diff --git a/assets/images/ding2.jpg b/assets/images/ding2.jpg
new file mode 100644
index 00000000..6ba7f1ec
Binary files /dev/null and b/assets/images/ding2.jpg differ
diff --git a/assets/images/goat.png b/assets/images/goat.png
new file mode 100644
index 00000000..92101cf5
Binary files /dev/null and b/assets/images/goat.png differ
diff --git a/assets/images/gukesh.jpg b/assets/images/gukesh.jpg
new file mode 100644
index 00000000..862b9526
Binary files /dev/null and b/assets/images/gukesh.jpg differ
diff --git a/assets/images/gukesh1.jpg b/assets/images/gukesh1.jpg
new file mode 100644
index 00000000..e629dd55
Binary files /dev/null and b/assets/images/gukesh1.jpg differ
diff --git a/assets/images/king.png b/assets/images/king.png
new file mode 100644
index 00000000..a5064ae8
Binary files /dev/null and b/assets/images/king.png differ
diff --git a/assets/images/modern.jpeg b/assets/images/modern.jpeg
new file mode 100644
index 00000000..2d79de28
Binary files /dev/null and b/assets/images/modern.jpeg differ
diff --git a/assets/images/modern2.jpeg b/assets/images/modern2.jpeg
new file mode 100644
index 00000000..53dfdf6f
Binary files /dev/null and b/assets/images/modern2.jpeg differ
diff --git a/assets/images/mvsd.png b/assets/images/mvsd.png
new file mode 100644
index 00000000..4829aab2
Binary files /dev/null and b/assets/images/mvsd.png differ
diff --git a/assets/images/search.gif b/assets/images/search.gif
new file mode 100644
index 00000000..b42e0363
Binary files /dev/null and b/assets/images/search.gif differ
diff --git a/assets/images/search.jpeg b/assets/images/search.jpeg
new file mode 100644
index 00000000..71d84d5c
Binary files /dev/null and b/assets/images/search.jpeg differ
diff --git a/assets/images/splash.png b/assets/images/splash.png
new file mode 100644
index 00000000..77c7e427
Binary files /dev/null and b/assets/images/splash.png differ
diff --git a/assets/images/worldchamp.png b/assets/images/worldchamp.png
new file mode 100644
index 00000000..629ef3f4
Binary files /dev/null and b/assets/images/worldchamp.png differ
diff --git a/assets/wireframe/CC.excalidraw b/assets/wireframe/CC.excalidraw
new file mode 100644
index 00000000..bd4b1db2
--- /dev/null
+++ b/assets/wireframe/CC.excalidraw
@@ -0,0 +1,3392 @@
+{
+ "type": "excalidraw",
+ "version": 2,
+ "source": "https://excalidraw.com",
+ "elements": [
+ {
+ "type": "rectangle",
+ "version": 442,
+ "versionNonce": 1299338806,
+ "index": "b6n",
+ "isDeleted": false,
+ "id": "FXvjVLrwWzoSHUCBZhgSb",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 406.27311271320133,
+ "y": -242.22454628281218,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 158.40002441406253,
+ "height": 355.19993591308594,
+ "seed": 1895450666,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "-xpptBQq6Jb01F8pUxDK6",
+ "type": "arrow"
+ },
+ {
+ "id": "1SJaY3ks4JjQ5D1I6TcnW",
+ "type": "arrow"
+ },
+ {
+ "id": "iiR_qjeK7p7m9ZV5WvTYm",
+ "type": "arrow"
+ },
+ {
+ "id": "G9qTJjjs2kmKx6ZIhiAJS",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724227622119,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 105,
+ "versionNonce": 688186102,
+ "index": "b6o",
+ "isDeleted": false,
+ "id": "WS7jIo0c-eQovWSVmbtV3",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 423.3640107068092,
+ "y": -109.88169655136687,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 122.4000244140625,
+ "height": 24.79998779296875,
+ "seed": 865317610,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 171,
+ "versionNonce": 6778730,
+ "index": "b6p",
+ "isDeleted": false,
+ "id": "VpWaAeXqQGYBnoxcjeaf6",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 420.8549331144797,
+ "y": -55.15440440381718,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 122.4000244140625,
+ "height": 24.79998779296875,
+ "seed": 489801130,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 120,
+ "versionNonce": 283698806,
+ "index": "b6q",
+ "isDeleted": false,
+ "id": "5OPPjw6tYAlvfh8FXNeG5",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 421.44658022856225,
+ "y": -183.09491341286736,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 132.73988342285156,
+ "height": 25,
+ "seed": 922714218,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227491117,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "Chess Central",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Chess Central",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 35,
+ "versionNonce": 379077814,
+ "index": "b6r",
+ "isDeleted": false,
+ "id": "FMHo0zwdje6Tr5z4t1Y4C",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 452.3112217039355,
+ "y": -223.48167213730437,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 49.359954833984375,
+ "height": 25,
+ "seed": 751297322,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227596517,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "Login",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Login",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 178,
+ "versionNonce": 1326783862,
+ "index": "b6s",
+ "isDeleted": false,
+ "id": "nqpYqtoDRWohRxorldIOw",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 422.78214591632633,
+ "y": -131.03925242319144,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 89.29779052734375,
+ "height": 16.630260672517053,
+ "seed": 2029383146,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.304208538013643,
+ "fontFamily": 5,
+ "text": "Phone Number",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Phone Number",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 199,
+ "versionNonce": 778968298,
+ "index": "b6t",
+ "isDeleted": false,
+ "id": "vSucd7UjXvj2AsYEq6FH4",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 423.16770291761355,
+ "y": -74.99681468059424,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 68.80084228515625,
+ "height": 16.630260672517053,
+ "seed": 278175914,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.304208538013643,
+ "fontFamily": 5,
+ "text": "Passsword",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Passsword",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 131,
+ "versionNonce": 1287519926,
+ "index": "b6u",
+ "isDeleted": false,
+ "id": "kcox0eMeq6xE7-EOcUq07",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 468.16402624303083,
+ "y": 33.53658292306494,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 28.559967041015618,
+ "height": 14.46515051374807,
+ "seed": 256834410,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 11.572120410998453,
+ "fontFamily": 5,
+ "text": "Login",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Login",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 117,
+ "versionNonce": 1697574826,
+ "index": "b6v",
+ "isDeleted": false,
+ "id": "qOQJJ4dYkjgDZ2fhJrg5_",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 445.9821359287553,
+ "y": 28.154758082866124,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 70.90913529829535,
+ "height": 22.400054931640625,
+ "seed": 1668283946,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 47,
+ "versionNonce": 2100869110,
+ "index": "b6w",
+ "isDeleted": false,
+ "id": "CLJ17aaoWqMEh_GPpE0ex",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 420.01855727108483,
+ "y": -20.208992028106934,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 11.199951171875,
+ "height": 10.400024414062498,
+ "seed": 2044897514,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 159,
+ "versionNonce": 432499306,
+ "index": "b6x",
+ "isDeleted": false,
+ "id": "GbuQcwwCa5Zabr69KvOP9",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 436.81860609920994,
+ "y": -19.381666033788747,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 55.49589538574219,
+ "height": 10.560472942175576,
+ "seed": 1781660586,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 8.44837835374046,
+ "fontFamily": 5,
+ "text": "Remember Me",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Remember Me",
+ "autoResize": false,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 119,
+ "versionNonce": 1485457718,
+ "index": "b6y",
+ "isDeleted": false,
+ "id": "_ISQYC9xshm-pn-pcC2_n",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 499.0003965377752,
+ "y": -19.77261562984694,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 58.70577692858535,
+ "height": 8.3002239411424,
+ "seed": 579401322,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 6.640179152913917,
+ "fontFamily": 5,
+ "text": "Forgot Password?",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Forgot Password?",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 112,
+ "versionNonce": 50498858,
+ "index": "b6z",
+ "isDeleted": false,
+ "id": "klMqvccTaHrPNXeciD4sh",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 423.2686868702097,
+ "y": 63.13651411979788,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 124.15773228386506,
+ "height": 10.235262243280879,
+ "seed": 330471722,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 8.18820979462471,
+ "fontFamily": 5,
+ "text": "Don't have an account?Sign Up",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Don't have an account?Sign Up",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 514,
+ "versionNonce": 1300567530,
+ "index": "b70",
+ "isDeleted": false,
+ "id": "prM0nSo85yF5nOouFNRnl",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 682.0407077861512,
+ "y": -241.24964314515063,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 158.40002441406253,
+ "height": 355.19993591308594,
+ "seed": 1561977834,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "-1fPzdFxQix34EAdVdGid",
+ "type": "arrow"
+ },
+ {
+ "id": "bFdnCyNspbPodVhK1OkrR",
+ "type": "arrow"
+ },
+ {
+ "id": "rNEmC7J_3DxIk4suQkygP",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724227577535,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 226,
+ "versionNonce": 1179342826,
+ "index": "b71",
+ "isDeleted": false,
+ "id": "uRqN-KiYxG1JXGhZsQqOj",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 698.4188306484095,
+ "y": -173.4876966484622,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 122.4000244140625,
+ "height": 21.948860076942708,
+ "seed": 2026493610,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 288,
+ "versionNonce": 413529014,
+ "index": "b72",
+ "isDeleted": false,
+ "id": "hZLIoqcVgq3daZlTW57or",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 700.1865126066903,
+ "y": -120.89870270433244,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 122.4000244140625,
+ "height": 19.810480301637767,
+ "seed": 1735225706,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 204,
+ "versionNonce": 1413478710,
+ "index": "b73",
+ "isDeleted": false,
+ "id": "AKI1cTCEQxlyGq7ae85Xp",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 695.7397993884495,
+ "y": -223.38113936344115,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 50.570220947265625,
+ "height": 16.890879046288333,
+ "seed": 1548727338,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227604312,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.512703237030665,
+ "fontFamily": 5,
+ "text": "Sign Up",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Sign Up",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 289,
+ "versionNonce": 1381633270,
+ "index": "b74",
+ "isDeleted": false,
+ "id": "Yk9psd3SdHsvYGqY-tuQg",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 699.9752912519752,
+ "y": -196.7835507237067,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 59.14501953125,
+ "height": 16.630260672517053,
+ "seed": 1767612138,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.304208538013643,
+ "fontFamily": 5,
+ "text": "Full Name",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Full Name",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 319,
+ "versionNonce": 567403882,
+ "index": "b75",
+ "isDeleted": false,
+ "id": "fXZsx94qW7TCcqI9sLASn",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 698.2225228592138,
+ "y": -144.30504301911327,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 90.10081481933594,
+ "height": 16.630260672517053,
+ "seed": 723268010,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.304208538013643,
+ "fontFamily": 5,
+ "text": "Email Address",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Email Address",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 230,
+ "versionNonce": 146341430,
+ "index": "b76",
+ "isDeleted": false,
+ "id": "DIYewGVT9cHWHQadz6H5p",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 732.5270560706197,
+ "y": 34.081377891294665,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 48.95277404785156,
+ "height": 14.465150513748066,
+ "seed": 1958505578,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 11.572120410998453,
+ "fontFamily": 5,
+ "text": "Continue",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Continue",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 210,
+ "versionNonce": 973449258,
+ "index": "b77",
+ "isDeleted": false,
+ "id": "-E-V9qxqJWjlToPsy3Oca",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 719.6113512264003,
+ "y": 31.550653576493573,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 78.74977050565231,
+ "height": 22.400054931640625,
+ "seed": 2080853802,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 242,
+ "versionNonce": 279431030,
+ "index": "b78",
+ "isDeleted": false,
+ "id": "jS9aji5LutC8eATg4DqOE",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 703.3129871125129,
+ "y": 67.95801425738085,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 104.95719909667969,
+ "height": 20.470524486561775,
+ "seed": 90692074,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 8.18820979462471,
+ "fontFamily": 5,
+ "text": "Already have an account?\n Login",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Already have an account?\n Login",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 333,
+ "versionNonce": 70456042,
+ "index": "b79",
+ "isDeleted": false,
+ "id": "4GczQE3wj7t75YL5xQRxZ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 700.3792031929515,
+ "y": -92.91010288662125,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 89.28448486328125,
+ "height": 16.630260672517053,
+ "seed": 266931370,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.304208538013643,
+ "fontFamily": 5,
+ "text": "Mobile Number",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Mobile Number",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 326,
+ "versionNonce": 1516988598,
+ "index": "b7A",
+ "isDeleted": false,
+ "id": "s6XArw17fSd2uLstu2x3p",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 699.4015752121375,
+ "y": -72.04732022767865,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 122.4000244140625,
+ "height": 20.523309814243873,
+ "seed": 20309866,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 377,
+ "versionNonce": 1659184554,
+ "index": "b7B",
+ "isDeleted": false,
+ "id": "XMCBuymky01mwL8G2cmi1",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 700.9907953229069,
+ "y": -43.72774872340409,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 61.578948974609375,
+ "height": 16.630260672517053,
+ "seed": 1369008682,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.304208538013643,
+ "fontFamily": 5,
+ "text": "Password",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Password",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 354,
+ "versionNonce": 94953974,
+ "index": "b7C",
+ "isDeleted": false,
+ "id": "E8rBwyLOC9D8FYdct9PSx",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 700.1143503434871,
+ "y": -24.290761042815575,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 122.4000244140625,
+ "height": 18.384930038938933,
+ "seed": 939431146,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 29,
+ "versionNonce": 1969566518,
+ "index": "b7E",
+ "isDeleted": false,
+ "id": "mNuGUk6ViljJLJQmMhzph",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 589.333091947382,
+ "y": -384.184898113112,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 65.1279296875,
+ "height": 20,
+ "seed": 1671029354,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 16,
+ "fontFamily": 5,
+ "text": "Firebase",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Firebase",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "line",
+ "version": 48,
+ "versionNonce": 1696809770,
+ "index": "b7F",
+ "isDeleted": false,
+ "id": "CpcfuVC8gxSE42dZ5zHcC",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 565.7107249630485,
+ "y": -95.79625669737948,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 116.1428913270629,
+ "height": 1.9685305820278245,
+ "seed": 1539704106,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 116.1428913270629,
+ -1.9685305820278245
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 55,
+ "versionNonce": 1678072950,
+ "index": "b7G",
+ "isDeleted": false,
+ "id": "NkUwiaNBej08n2EnMeJJ4",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 567.6792930916743,
+ "y": -47.567463943987036,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 113.19007668072209,
+ "height": 0.9842465177149506,
+ "seed": 668979178,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 113.19007668072209,
+ -0.9842465177149506
+ ]
+ ]
+ },
+ {
+ "type": "arrow",
+ "version": 106,
+ "versionNonce": 1323650538,
+ "index": "b7H",
+ "isDeleted": false,
+ "id": "bFdnCyNspbPodVhK1OkrR",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 745.0292077989357,
+ "y": -241.26535908083773,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 92.70343759944762,
+ "height": 88.78517330609739,
+ "seed": 1274167978,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "prM0nSo85yF5nOouFNRnl",
+ "focus": 0.6395257626710378,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -92.70343759944762,
+ -88.78517330609739
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "arrow",
+ "version": 71,
+ "versionNonce": 2001624502,
+ "index": "b7I",
+ "isDeleted": false,
+ "id": "-1fPzdFxQix34EAdVdGid",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 671.3206445826227,
+ "y": -351.4155674944127,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 110.92761837832927,
+ "height": 108.96432686163223,
+ "seed": 313023850,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": {
+ "elementId": "prM0nSo85yF5nOouFNRnl",
+ "focus": 0.7808875509645764,
+ "gap": 1.201597487629897,
+ "fixedPoint": null
+ },
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 110.92761837832927,
+ 108.96432686163223
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "arrow",
+ "version": 77,
+ "versionNonce": 1829666154,
+ "index": "b7J",
+ "isDeleted": false,
+ "id": "-xpptBQq6Jb01F8pUxDK6",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 515.0125180756479,
+ "y": -244.57837045127667,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 73.33625226082336,
+ "height": 85.47214316235949,
+ "seed": 961355818,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724227271445,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "FXvjVLrwWzoSHUCBZhgSb",
+ "focus": -0.5391729579713302,
+ "gap": 2.3538241684644845,
+ "fixedPoint": null
+ },
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 73.33625226082336,
+ -85.47214316235949
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "arrow",
+ "version": 62,
+ "versionNonce": 569327658,
+ "index": "b7K",
+ "isDeleted": false,
+ "id": "1SJaY3ks4JjQ5D1I6TcnW",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 570.6320326448192,
+ "y": -346.7829484676766,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 96.11274736587353,
+ "height": 103.18882453411481,
+ "seed": 466324202,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724227271445,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": {
+ "elementId": "FXvjVLrwWzoSHUCBZhgSb",
+ "focus": -0.7262277159721162,
+ "gap": 1.3695776507495907,
+ "fixedPoint": null
+ },
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -96.11274736587353,
+ 103.18882453411481
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "text",
+ "version": 128,
+ "versionNonce": 2028362602,
+ "index": "b7L",
+ "isDeleted": false,
+ "id": "GS1kNxHdKMV3G5dbDUP0_",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 5.498273904393826,
+ "x": 474.15585381112777,
+ "y": -325.2681521004248,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 60.223821879947465,
+ "height": 25.097455684717463,
+ "seed": 1622056362,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 20.077964547773973,
+ "fontFamily": 5,
+ "text": "Token",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Token",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 233,
+ "versionNonce": 869197878,
+ "index": "b7M",
+ "isDeleted": false,
+ "id": "zsEPXWNpyhUJ3lxHVpE96",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0.768450896522431,
+ "x": 704.8918433318988,
+ "y": -335.7094219654956,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 60.223821879947465,
+ "height": 25.097455684717463,
+ "seed": 622942314,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227214383,
+ "link": null,
+ "locked": false,
+ "fontSize": 20.077964547773973,
+ "fontFamily": 5,
+ "text": "Token",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Token",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 83,
+ "versionNonce": 817312054,
+ "index": "b8h",
+ "isDeleted": false,
+ "id": "iE6NnUl9si_INv-LPb7k3",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 571.9683507283529,
+ "y": -418.09852769639747,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 96,
+ "height": 81.60000610351562,
+ "seed": 1378402998,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227260263,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 580,
+ "versionNonce": 1526374327,
+ "index": "b8i",
+ "isDeleted": false,
+ "id": "xCL62vJS3Djunq00elpil",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 730.716335165434,
+ "y": 197.88681408113348,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 158.40002441406253,
+ "height": 355.19993591308594,
+ "seed": 619366902,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313739398,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 176,
+ "versionNonce": 1209766103,
+ "index": "b8j",
+ "isDeleted": false,
+ "id": "OQ95Z_EDBqSbQo_did4Ac",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 733.5435553774457,
+ "y": 199.7157689493942,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 153.37361803460158,
+ "height": 234.70795126955753,
+ "seed": 453063146,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "iiR_qjeK7p7m9ZV5WvTYm",
+ "type": "arrow"
+ },
+ {
+ "id": "rNEmC7J_3DxIk4suQkygP",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724313739398,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 178,
+ "versionNonce": 354257975,
+ "index": "b8k",
+ "isDeleted": false,
+ "id": "kgaet7vYYIiVjH9k1A71h",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 768.4012723990882,
+ "y": 454.17642948613354,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 82.49636942255256,
+ "height": 35,
+ "seed": 1372817014,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "jJE67OTl4CUYJv6f5xfqq"
+ }
+ ],
+ "updated": 1724313739399,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 97,
+ "versionNonce": 137162071,
+ "index": "b8kV",
+ "isDeleted": false,
+ "id": "jJE67OTl4CUYJv6f5xfqq",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 784.9694796933723,
+ "y": 459.17642948613354,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 49.359954833984375,
+ "height": 25,
+ "seed": 438117814,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313739399,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "Login",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "kgaet7vYYIiVjH9k1A71h",
+ "originalText": "Login",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 154,
+ "versionNonce": 1626548855,
+ "index": "b8l",
+ "isDeleted": false,
+ "id": "Q2g0MKwh9kM93JM5_plC9",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 769.5630869678523,
+ "y": 499.4913641019825,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 85.98216771897683,
+ "height": 36.019620237939534,
+ "seed": 35040054,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313739399,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 121,
+ "versionNonce": 2083832727,
+ "index": "b8m",
+ "isDeleted": false,
+ "id": "Xz08JMiM1jB7wEIVVUWgA",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 782.3441996421859,
+ "y": 507.62486391112793,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 59.3199462890625,
+ "height": 25,
+ "seed": 513026294,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313739399,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "signup",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "signup",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 99,
+ "versionNonce": 707147959,
+ "index": "b8n",
+ "isDeleted": false,
+ "id": "3beqJmFbXM9Qv-cLluyXI",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 760.267772589943,
+ "y": 310.0983031245074,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 93.15994262695312,
+ "height": 25,
+ "seed": 910659306,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313739399,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "GRAPHIC",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "GRAPHIC",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "arrow",
+ "version": 161,
+ "versionNonce": 37838327,
+ "index": "b8o",
+ "isDeleted": false,
+ "id": "iiR_qjeK7p7m9ZV5WvTYm",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 732.3816521611486,
+ "y": 202.1725264009276,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 245.41519792176564,
+ "height": 82.84343199494077,
+ "seed": 1102209334,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724313739398,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "OQ95Z_EDBqSbQo_did4Ac",
+ "focus": 0.6186667460792661,
+ "gap": 1.1619032162971337,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "FXvjVLrwWzoSHUCBZhgSb",
+ "focus": 0.7474425823149594,
+ "gap": 6.353704775713084,
+ "fixedPoint": null
+ },
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -245.41519792176564,
+ -82.84343199494077
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "arrow",
+ "version": 215,
+ "versionNonce": 1282443031,
+ "index": "b8p",
+ "isDeleted": false,
+ "id": "rNEmC7J_3DxIk4suQkygP",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 741.3006606962359,
+ "y": 198.5538657330971,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 4.521203109068324,
+ "height": 74.57711413815571,
+ "seed": 1685232490,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724313739399,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "OQ95Z_EDBqSbQo_did4Ac",
+ "focus": -0.7367988812586695,
+ "gap": 1.1619032162971337,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "prM0nSo85yF5nOouFNRnl",
+ "focus": -0.7507134751938123,
+ "gap": 10.026458827006081,
+ "fixedPoint": null
+ },
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -4.521203109068324,
+ -74.57711413815571
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "arrow",
+ "version": 35,
+ "versionNonce": 1230922998,
+ "index": "b8q",
+ "isDeleted": false,
+ "id": "G9qTJjjs2kmKx6ZIhiAJS",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 404.5066714463828,
+ "y": -78.96229657536588,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 174.3183790626664,
+ "height": 1.2275757509713117,
+ "seed": 112174006,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724227622119,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "FXvjVLrwWzoSHUCBZhgSb",
+ "focus": 0.0836780866072362,
+ "gap": 1.766441266818532,
+ "fixedPoint": null
+ },
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -174.3183790626664,
+ 1.2275757509713117
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "rectangle",
+ "version": 675,
+ "versionNonce": 375567449,
+ "index": "b8r",
+ "isDeleted": false,
+ "id": "t9EEpbt7WRoh3CG2X-sl1",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 58.918693983440306,
+ "y": -230.782775714899,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 158.40002441406253,
+ "height": 540.0468851439483,
+ "seed": 2004879466,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "nf48T58h_fR28P8-_AqTS",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724312769839,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 95,
+ "versionNonce": 1517750122,
+ "index": "b8s",
+ "isDeleted": false,
+ "id": "XhwEKJ1zhfYvdcKU5WYWI",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 59.55264057396403,
+ "y": -231.1840311464693,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 154.6769797310725,
+ "height": 168.1804534787966,
+ "seed": 285465334,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "vk6N2JOzCNjEjTd2MeWNb"
+ }
+ ],
+ "updated": 1724227685760,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 15,
+ "versionNonce": 1437484470,
+ "index": "b8sV",
+ "isDeleted": false,
+ "id": "vk6N2JOzCNjEjTd2MeWNb",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 90.31115912602371,
+ "y": -159.593804407071,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 93.15994262695312,
+ "height": 25,
+ "seed": 972540662,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227689148,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "GRAPHIC",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "XhwEKJ1zhfYvdcKU5WYWI",
+ "originalText": "GRAPHIC",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 84,
+ "versionNonce": 929886326,
+ "index": "b8t",
+ "isDeleted": false,
+ "id": "iC1U4z5-CkhGiLphBfHcI",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 84.10453022549609,
+ "y": -223.81838932458862,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 96.49489427055641,
+ "height": 18.608254178941987,
+ "seed": 2085113654,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227682026,
+ "link": null,
+ "locked": false,
+ "fontSize": 14.88660334315359,
+ "fontFamily": 5,
+ "text": "Welcome User",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Welcome User",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 63,
+ "versionNonce": 1126892214,
+ "index": "b8v",
+ "isDeleted": false,
+ "id": "CyM7l9v_-NKxOA8vJ68XW",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 128.91170074213397,
+ "y": -45.81725959450165,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 45.42095839212368,
+ "height": 62.60734670881436,
+ "seed": 1054496694,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227731384,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 109,
+ "versionNonce": 2127417898,
+ "index": "b8w",
+ "isDeleted": false,
+ "id": "cuygWoJZVy7QLWXO5IJ3V",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 190.2914248709638,
+ "y": -47.21797866499057,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 24.431275870773902,
+ "height": 64.94188442999899,
+ "seed": 789334186,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227779467,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 77,
+ "versionNonce": 1466709290,
+ "index": "b8x",
+ "isDeleted": false,
+ "id": "910sOvH_zMVXT3Rhee8EP",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 68.75959919328858,
+ "y": -43.975895968044654,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 45.42095839212368,
+ "height": 62.60734670881436,
+ "seed": 2042153258,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227743123,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 133,
+ "versionNonce": 251571958,
+ "index": "b8z",
+ "isDeleted": false,
+ "id": "ukMiKDMk-KT6N8C8O3A-n",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 73.91054501747732,
+ "y": -17.49336025312914,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 36.924040581998824,
+ "height": 16.63245528542518,
+ "seed": 1473016490,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227757429,
+ "link": null,
+ "locked": false,
+ "fontSize": 13.30596422834014,
+ "fontFamily": 5,
+ "text": "NEWS",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "NEWS",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 243,
+ "versionNonce": 597884470,
+ "index": "b90",
+ "isDeleted": false,
+ "id": "MocuRrg3N33NOID5WllCn",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 87.15697994179152,
+ "y": 39.96229759213509,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 100.41071068232077,
+ "height": 83.67547616365187,
+ "seed": 286379050,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227859473,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 240,
+ "versionNonce": 696802934,
+ "index": "b91",
+ "isDeleted": false,
+ "id": "27AxzcpgiQF1jOAXBFtLb",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 87.91774232668126,
+ "y": 141.1336981145859,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 100.41071068232077,
+ "height": 83.67547616365187,
+ "seed": 1559801514,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227850795,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 57,
+ "versionNonce": 1017710570,
+ "index": "b93",
+ "isDeleted": false,
+ "id": "UT1gKlP2UcwliNDXjd-Jx",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 103.89224347836432,
+ "y": 52.133291507360184,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 63.913799053174145,
+ "height": 66.63245528542518,
+ "seed": 1121282230,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227888037,
+ "link": null,
+ "locked": false,
+ "fontSize": 17.768654742780043,
+ "fontFamily": 5,
+ "text": "Card\nCurrent\nWC",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Card\nCurrent\nWC",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 116,
+ "versionNonce": 1608946614,
+ "index": "b94",
+ "isDeleted": false,
+ "id": "vVcpukbKPip-tvUhWy_mH",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 99.32006212484364,
+ "y": 153.45864324539764,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 78.88397271006423,
+ "height": 61.307582877659044,
+ "seed": 1798983222,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227901869,
+ "link": null,
+ "locked": false,
+ "fontSize": 16.348688767375744,
+ "fontFamily": 5,
+ "text": "Card\nCurrent\nChallenger",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Card\nCurrent\nChallenger",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 73,
+ "versionNonce": 1411000601,
+ "index": "b95",
+ "isDeleted": false,
+ "id": "ekUQARtsSUwsGe7G2PvWZ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 59.01170250916232,
+ "y": 259.8008343794606,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 157.46217302198818,
+ "height": 47.162595980640106,
+ "seed": 618801654,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "hP40xJGzcB4JwMJBza-ZT",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724313638547,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 33,
+ "versionNonce": 834302103,
+ "index": "b96",
+ "isDeleted": false,
+ "id": "kQZ2YFpV6rJPnnVcY7mJG",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 94.76402343261134,
+ "y": 274.2539558508835,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 79.73995971679688,
+ "height": 25,
+ "seed": 975025462,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [
+ {
+ "id": "AuU91flN9pjKN_T7ZTqLW",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724313719829,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "NAVBAR",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "NAVBAR",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 25,
+ "versionNonce": 1839013622,
+ "index": "b97",
+ "isDeleted": false,
+ "id": "bnw81QMwn7VPjYlG4CQca",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 82.34215541688332,
+ "y": -271.8599046081596,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 117.81991577148438,
+ "height": 25,
+ "seed": 1691721974,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227963722,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "Home Screen",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Home Screen",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 728,
+ "versionNonce": 96612889,
+ "index": "b98",
+ "isDeleted": false,
+ "id": "tK_3nOoV2eTrvXhWjv2ps",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -244.59800687372865,
+ "y": -239.13284903055848,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 158.40002441406253,
+ "height": 540.0468851439483,
+ "seed": 1790809578,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "nf48T58h_fR28P8-_AqTS",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724312769839,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 153,
+ "versionNonce": 639271414,
+ "index": "b99",
+ "isDeleted": false,
+ "id": "ecOjT0hLuGTShu5u17L7n",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -243.96406028320496,
+ "y": -239.53410446212877,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 154.6769797310725,
+ "height": 168.1804534787966,
+ "seed": 992430250,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "5QDwdl2R3OsJRa3XDtbPh"
+ }
+ ],
+ "updated": 1724228012135,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 102,
+ "versionNonce": 1077887082,
+ "index": "b9A",
+ "isDeleted": false,
+ "id": "5QDwdl2R3OsJRa3XDtbPh",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -234.65551579120387,
+ "y": -192.94387772273046,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 136.0598907470703,
+ "height": 75,
+ "seed": 558670698,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724228012135,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "GRAPHIC\ncurrent \nWC/Challenger",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "ecOjT0hLuGTShu5u17L7n",
+ "originalText": "GRAPHIC\ncurrent WC/Challenger",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 125,
+ "versionNonce": 1017005226,
+ "index": "b9K",
+ "isDeleted": false,
+ "id": "hnmjtsYPP4gXPO6BCU7Jk",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -244.50499834800667,
+ "y": 251.4507610638011,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 157.46217302198818,
+ "height": 47.162595980640106,
+ "seed": 1508329194,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724227973330,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 85,
+ "versionNonce": 1384390506,
+ "index": "b9L",
+ "isDeleted": false,
+ "id": "7-M7A7Kw7prL1LI8EUFMc",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -208.75267742455765,
+ "y": 265.903882535224,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 79.73995971679688,
+ "height": 25,
+ "seed": 1542642090,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724227973330,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "NAVBAR",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "NAVBAR",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 113,
+ "versionNonce": 1353996215,
+ "index": "b9M",
+ "isDeleted": false,
+ "id": "K_L_9jNxhDa0BQaPPyik0",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -221.3039771666896,
+ "y": -42.755207474166355,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 112.90814351670736,
+ "height": 267.47165610030083,
+ "seed": 325297303,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724312707293,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 28,
+ "versionNonce": 1542930233,
+ "index": "b9N",
+ "isDeleted": false,
+ "id": "GrGXLINzWlZIVKPF0s9d7",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -204.86104851666767,
+ "y": -29.600772557782932,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 85.919921875,
+ "height": 50,
+ "seed": 787289591,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724312730088,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": " Player\nRankings",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": " Player\nRankings",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 27,
+ "versionNonce": 1879955929,
+ "index": "b9O",
+ "isDeleted": false,
+ "id": "GsgH25NR6fxHBKC5Z0vsi",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -204.8610903331978,
+ "y": -302.5533421499627,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 81.919921875,
+ "height": 50,
+ "seed": 605652217,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724312762504,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "Ranking \nScreen",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Ranking \nScreen",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "arrow",
+ "version": 76,
+ "versionNonce": 1755103545,
+ "index": "b9P",
+ "isDeleted": false,
+ "id": "nf48T58h_fR28P8-_AqTS",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 52.744833667007924,
+ "y": -6.580647357834323,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 131.54342920017484,
+ "height": 2.192398849975575,
+ "seed": 1744959385,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724312769839,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "t9EEpbt7WRoh3CG2X-sl1",
+ "focus": 0.16362440762729344,
+ "gap": 6.173860316432396,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "tK_3nOoV2eTrvXhWjv2ps",
+ "focus": -0.15149423693701303,
+ "gap": 7.3993869264992185,
+ "fixedPoint": null
+ },
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -131.54342920017484,
+ -2.192398849975575
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "text",
+ "version": 81,
+ "versionNonce": 737197785,
+ "index": "b9R",
+ "isDeleted": false,
+ "id": "XUYaiNjTLadp1lZnZkV6R",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -202.969660702753,
+ "y": 405.3020488538849,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 92.2002111777847,
+ "height": 35.45074272107543,
+ "seed": 60311385,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313624268,
+ "link": null,
+ "locked": false,
+ "fontSize": 28.360594176860335,
+ "fontFamily": 5,
+ "text": "Search",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Search",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 781,
+ "versionNonce": 1413095833,
+ "index": "b9S",
+ "isDeleted": false,
+ "id": "_Th4i6zInzO-ZJpHEVirb",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -230.79428231753286,
+ "y": 452.0588444013297,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 158.40002441406253,
+ "height": 540.0468851439483,
+ "seed": 279376151,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313515700,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 223,
+ "versionNonce": 1043560153,
+ "index": "b9T",
+ "isDeleted": false,
+ "id": "Y6ASRTNx13l9W83HIU02t",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -230.16033572700917,
+ "y": 451.6575889697594,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 154.6769797310725,
+ "height": 168.1804534787966,
+ "seed": 452376119,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "gA6krVJqbvF7p5M1qPDWy"
+ },
+ {
+ "id": "hP40xJGzcB4JwMJBza-ZT",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724313638547,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 188,
+ "versionNonce": 1858996601,
+ "index": "b9U",
+ "isDeleted": false,
+ "id": "gA6krVJqbvF7p5M1qPDWy",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -204.66181931117995,
+ "y": 523.2478157091577,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 103.67994689941406,
+ "height": 25,
+ "seed": 223401815,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313566521,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "FIDE IMG",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "Y6ASRTNx13l9W83HIU02t",
+ "originalText": "FIDE IMG",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 178,
+ "versionNonce": 1073609785,
+ "index": "b9V",
+ "isDeleted": false,
+ "id": "EVBARa2mgbeKoBGKxT1T2",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -230.70127379181088,
+ "y": 942.6424544956893,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 157.46217302198818,
+ "height": 47.162595980640106,
+ "seed": 772396151,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313515700,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 138,
+ "versionNonce": 1933839641,
+ "index": "b9W",
+ "isDeleted": false,
+ "id": "sn2vDN7cGjvx-adcIvzSz",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -194.94895286836186,
+ "y": 957.0955759671122,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 79.73995971679688,
+ "height": 25,
+ "seed": 82193815,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313515700,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "NAVBAR",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "NAVBAR",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 69,
+ "versionNonce": 150565751,
+ "index": "b9Z",
+ "isDeleted": false,
+ "id": "rNgU16JN94Lew6NWXpoXw",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -214.6212952012737,
+ "y": 471.275894041763,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 131.11642764501062,
+ "height": 33.743192612169025,
+ "seed": 915763193,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313536589,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "ellipse",
+ "version": 25,
+ "versionNonce": 664569977,
+ "index": "b9a",
+ "isDeleted": false,
+ "id": "5MbA2MjRKrAECnhsI6qGm",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -109.53537456110132,
+ "y": 478.9886164262551,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 17.35367133655882,
+ "height": 15.425444768984164,
+ "seed": 1049226391,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724313547868,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "line",
+ "version": 11,
+ "versionNonce": 818861783,
+ "index": "b9b",
+ "isDeleted": false,
+ "id": "NRhtyHddLHepvEibw9Nz9",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -93.14577973116855,
+ "y": 492.4858714048259,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 9.640912174905452,
+ "height": 9.640912174905452,
+ "seed": 1492126903,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724313553007,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 9.640912174905452,
+ 9.640912174905452
+ ]
+ ]
+ },
+ {
+ "type": "text",
+ "version": 68,
+ "versionNonce": 1967957911,
+ "index": "b9c",
+ "isDeleted": false,
+ "id": "H2tH6_L1PfypytDP6fIkR",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -198.23173714850225,
+ "y": 473.2040102778537,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 62.779937744140625,
+ "height": 25,
+ "seed": 73988599,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313578001,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "search",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "search",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 84,
+ "versionNonce": 762329657,
+ "index": "b9e",
+ "isDeleted": false,
+ "id": "zj5lNbi79leyBCh6yWRbi",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -213.65721869464767,
+ "y": 640.9559519978149,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 124.36774498998318,
+ "height": 272.83778880581065,
+ "seed": 2117712281,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313598907,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 47,
+ "versionNonce": 801187063,
+ "index": "b9f",
+ "isDeleted": false,
+ "id": "ziZNv9GG0DdcvozFJ44fs",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": -198.23173714850225,
+ "y": 747.0059675331938,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 91.9599609375,
+ "height": 50,
+ "seed": 30392313,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313609751,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "PLAYER\nDETAILS",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "PLAYER\nDETAILS",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "arrow",
+ "version": 62,
+ "versionNonce": 285711865,
+ "index": "b9g",
+ "isDeleted": false,
+ "id": "hP40xJGzcB4JwMJBza-ZT",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 60.60568420946731,
+ "y": 310.86309891412225,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 141.40911948374003,
+ "height": 132.63960771689761,
+ "seed": 439327897,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724313638547,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "ekUQARtsSUwsGe7G2PvWZ",
+ "focus": 0.46056174126467136,
+ "gap": 3.899668554021588,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "Y6ASRTNx13l9W83HIU02t",
+ "focus": -0.15764879053534478,
+ "gap": 8.154882338739554,
+ "fixedPoint": null
+ },
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -141.40911948374003,
+ 132.63960771689761
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "text",
+ "version": 162,
+ "versionNonce": 1297927513,
+ "index": "b9h",
+ "isDeleted": false,
+ "id": "MWPS748Sn2ziqtfPS7VqI",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 64.04013941701555,
+ "y": 416.4763020523714,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 91.89131164550781,
+ "height": 35.45074272107542,
+ "seed": 560014135,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313725781,
+ "link": null,
+ "locked": false,
+ "fontSize": 28.360594176860335,
+ "fontFamily": 5,
+ "text": "Profile",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Profile",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 829,
+ "versionNonce": 245064919,
+ "index": "b9i",
+ "isDeleted": false,
+ "id": "SN7uTuRRXEg3AFufg1Dq0",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 49.36982726902909,
+ "y": 450.0787463164927,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 158.40002441406253,
+ "height": 540.0468851439483,
+ "seed": 367371351,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313648746,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "rectangle",
+ "version": 226,
+ "versionNonce": 574480439,
+ "index": "b9l",
+ "isDeleted": false,
+ "id": "CDiwKF7RwVNR7XC5iD8GE",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 49.46283579475107,
+ "y": 940.6623564108523,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 157.46217302198818,
+ "height": 47.162595980640106,
+ "seed": 2019970999,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313648746,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 186,
+ "versionNonce": 908247383,
+ "index": "b9m",
+ "isDeleted": false,
+ "id": "VmhvPb3c14TbxNC-3JAUT",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 85.21515671820009,
+ "y": 955.1154778822751,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 79.73995971679688,
+ "height": 25,
+ "seed": 479281367,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313648746,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "NAVBAR",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "NAVBAR",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 60,
+ "versionNonce": 1231346137,
+ "index": "b9t",
+ "isDeleted": false,
+ "id": "eaT6wF2NCGViev6d6Xssd",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 54.028613109130674,
+ "y": 452.2723020309222,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 149.0825363669195,
+ "height": 41.65543179168105,
+ "seed": 227334713,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [],
+ "updated": 1724313682600,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 62,
+ "versionNonce": 722595513,
+ "index": "b9u",
+ "isDeleted": false,
+ "id": "PAcqOaFzai2o1OnjhkWz3",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 70.47145812609244,
+ "y": 463.23421264774015,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 129.93995666503906,
+ "height": 25,
+ "seed": 395900825,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1724313692594,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "Name Edit",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Name Edit",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 54,
+ "versionNonce": 1747613399,
+ "index": "b9v",
+ "isDeleted": false,
+ "id": "mhkDJI2tRHHzr0BHXO6NH",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 157.07089907615284,
+ "y": 451.1760816976695,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 47.136428916619934,
+ "height": 38.366833516717634,
+ "seed": 1492014201,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "AuU91flN9pjKN_T7ZTqLW",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1724313719829,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "arrow",
+ "version": 52,
+ "versionNonce": 1550730679,
+ "index": "b9w",
+ "isDeleted": false,
+ "id": "AuU91flN9pjKN_T7ZTqLW",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 171.32147069272912,
+ "y": 306.4783012141711,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 4.384714066891092,
+ "height": 140.31298278354723,
+ "seed": 1467155543,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1724313719829,
+ "link": null,
+ "locked": false,
+ "startBinding": {
+ "elementId": "kQZ2YFpV6rJPnnVcY7mJG",
+ "focus": -0.8959402478900943,
+ "gap": 7.224345363287625,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "mhkDJI2tRHHzr0BHXO6NH",
+ "focus": -0.17363818252117977,
+ "gap": 4.38479769995115,
+ "fixedPoint": null
+ },
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 4.384714066891092,
+ 140.31298278354723
+ ]
+ ],
+ "elbowed": false
+ }
+ ],
+ "appState": {
+ "gridSize": 20,
+ "gridStep": 5,
+ "gridModeEnabled": false,
+ "viewBackgroundColor": "#ffffff"
+ },
+ "files": {}
+}
\ No newline at end of file
diff --git a/assets/wireframe/use.txt b/assets/wireframe/use.txt
new file mode 100644
index 00000000..4ba8e01d
--- /dev/null
+++ b/assets/wireframe/use.txt
@@ -0,0 +1 @@
+visit excalidraw.com and upload this file to look at the base wireframe i made before i started working on this project
\ No newline at end of file
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
deleted file mode 100644
index 7c569640..00000000
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- App
- CFBundleIdentifier
- io.flutter.flutter.app
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- App
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
- CFBundleVersion
- 1.0
- MinimumOSVersion
- 12.0
-
-
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
deleted file mode 100644
index fc7f1dd4..00000000
--- a/ios/Runner/Info.plist
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- Get Flutter Fire
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- get_flutter_fire
- 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
-
- CADisableMinimumFrameDurationOnPhone
-
- UIApplicationSupportsIndirectInputEvents
-
- NSCameraUsageDescription
- Allow access to camera
- NSMicrophoneUsageDescription
- Allow access to microphone for video recording
- NSPhotoLibraryUsageDescription
- Allow access to photo library
-
-
diff --git a/lib/Main_View.dart b/lib/Main_View.dart
new file mode 100644
index 00000000..87ac780c
--- /dev/null
+++ b/lib/Main_View.dart
@@ -0,0 +1,63 @@
+import 'package:flutter/material.dart';
+import 'app/modules/home/views/home_view.dart';
+import 'app/modules/profile/views/profile_view.dart';
+import 'app/modules/ranking/views/ranking_view.dart';
+import 'app/modules/search/views/search_view.dart';
+
+class MainView extends StatefulWidget {
+ @override
+ _MainViewState createState() => _MainViewState();
+}
+
+class _MainViewState extends State {
+ int _selectedIndex = 0;
+
+ final List _pages = [
+ HomeView(),
+ SearchView(),
+ RankingView(),
+ ProfileView(),
+ ];
+
+ void _onItemTapped(int index) {
+ setState(() {
+ _selectedIndex = index;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.black, // Set the background color to black
+ body: _pages[_selectedIndex],
+ bottomNavigationBar: BottomNavigationBar(
+ currentIndex: _selectedIndex,
+ onTap: _onItemTapped,
+ items: [
+ BottomNavigationBarItem(
+ icon: Icon(Icons.home),
+ label: 'Home',
+ ),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.search),
+ label: 'Search',
+ ),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.leaderboard),
+ label: 'Ranking',
+ ),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.person),
+ label: 'Profile',
+ ),
+ ],
+ backgroundColor: Colors.black, // Set the navigation bar background to black
+ selectedItemColor: Colors.white, // Set selected item color to white
+ unselectedItemColor: Colors.grey, // Set unselected item color to grey
+ type: BottomNavigationBarType.fixed, // Ensure icons and labels are always displayed
+ selectedLabelStyle: TextStyle(fontSize: 12), // Adjust the selected label font size
+ unselectedLabelStyle: TextStyle(fontSize: 12), // Adjust the unselected label font size
+ ),
+ );
+ }
+}
diff --git a/lib/app/middleware/auth_middleware.dart b/lib/app/middleware/auth_middleware.dart
deleted file mode 100644
index 827dd96c..00000000
--- a/lib/app/middleware/auth_middleware.dart
+++ /dev/null
@@ -1,94 +0,0 @@
-// ignore_for_file: avoid_print
-import 'package:get/get.dart';
-import 'package:get_flutter_fire/models/role.dart';
-import 'package:get_flutter_fire/services/auth_service.dart';
-import 'package:get_flutter_fire/app/routes/app_pages.dart';
-
-Future loginVerify(bool check, GetNavConfig route,
- Future Function(GetNavConfig) redirector) async {
- final newRoute = route.location == Routes.LOGIN
- ? Routes.LOGIN
- : Routes.LOGIN_THEN(route.location);
- if (check) {
- return GetNavConfig.fromRoute(newRoute);
- }
-
- // Below could be used if the login was happening without verification.
- // This will never get reached if server is sending error in login due to non verification
- // With customClaims status == "creating", it will reach here for SignUp case only
- if (!AuthService.to.isEmailVerified && !AuthService.to.registered.value) {
- return GetNavConfig.fromRoute(route.location == Routes.REGISTER
- ? Routes.REGISTER
- : Routes.REGISTER_THEN(route.location));
- }
-
- return await redirector(route);
-}
-
-// class EnsureAuthMiddleware extends GetMiddleware {
-// @override
-// Future redirectDelegate(GetNavConfig route) async {
-// // you can do whatever you want here
-// // but it's preferable to make this method fast
-
-// return await loginVerify(
-// !AuthService.to.isLoggedInValue, route, super.redirectDelegate);
-// }
-// }
-
-class EnsureNotAuthedOrGuestMiddleware extends GetMiddleware {
- //AccessLevel.notAuthed
- @override
- Future redirectDelegate(GetNavConfig route) async {
- if (AuthService.to.isLoggedInValue && !AuthService.to.isAnon) {
- //NEVER navigate to auth screen, when user is already authed
- return GetNavConfig.fromRoute(
- AuthService.to.registered.value ? Routes.HOME : Routes.REGISTER);
- }
- return await super.redirectDelegate(route);
- }
-}
-
-class EnsureAuthedAndNotGuestMiddleware extends GetMiddleware {
- //AccessLevel.authenticated
- @override
- Future redirectDelegate(GetNavConfig route) async {
- return await loginVerify(
- !AuthService.to.isLoggedInValue || AuthService.to.isAnon,
- route,
- super.redirectDelegate);
- }
-}
-
-class EnsureRoleMiddleware extends GetMiddleware {
- //AccessLevel.roleBased
- Role role;
- EnsureRoleMiddleware(this.role);
-
- @override
- Future redirectDelegate(GetNavConfig route) async {
- if (!AuthService.to.isLoggedInValue || !AuthService.to.hasRole(role)) {
- final newRoute = Routes.LOGIN_THEN(route.location);
- return GetNavConfig.fromRoute(newRoute);
- }
- return await super.redirectDelegate(route);
- }
-}
-
-class EnsureAuthOrGuestMiddleware extends GetMiddleware {
- //AccessLevel.guest
- @override
- Future redirectDelegate(GetNavConfig route) async {
- // you can do whatever you want here
- // but it's preferable to make this method fast
- // In this case this is taking human input and is not fast
-
- if (!AuthService.to.isLoggedInValue) {
- bool? value = await AuthService.to.guest();
- if (value != true) {
- return GetNavConfig.fromRoute(Routes.LOGIN);
- }
- }
- return await super.redirectDelegate(route);
- }
-}
diff --git a/lib/app/modules/auth/bindings/auth_binding.dart b/lib/app/modules/auth/bindings/auth_binding.dart
new file mode 100644
index 00000000..66caaf00
--- /dev/null
+++ b/lib/app/modules/auth/bindings/auth_binding.dart
@@ -0,0 +1,10 @@
+import 'package:get/get.dart';
+
+import '../controllers/auth_controller.dart';
+
+class AuthBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(() => AuthController());
+ }
+}
diff --git a/lib/app/modules/auth/controllers/auth_controller.dart b/lib/app/modules/auth/controllers/auth_controller.dart
new file mode 100644
index 00000000..eb7b3678
--- /dev/null
+++ b/lib/app/modules/auth/controllers/auth_controller.dart
@@ -0,0 +1,169 @@
+import 'package:cloud_firestore/cloud_firestore.dart';
+import 'package:firebase_auth/firebase_auth.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import '../../../../services/auth_services.dart';
+import '../../../routes/app_routes.dart';
+
+class AuthController extends GetxController {
+ final AuthService _authService = AuthService();
+ Rxn firebaseUser = Rxn();
+
+ @override
+ void onInit() {
+ super.onInit();
+ firebaseUser.bindStream(_authService.authStateChanges());
+ }
+ Future signUp({
+ required String email,
+ required String password,
+ required String name,
+ required String phoneNumber,
+ }) async {
+ try {
+ User? user = await _authService.signUpWithEmailPassword(email, password);
+
+ if (user != null) {
+ await user.sendEmailVerification();
+ print('Verification email sent successfully.');
+ await _storeUserData(user, name, email, phoneNumber);
+ Get.snackbar(
+ 'Verification Email Sent',
+ 'Please verify your email before logging in.',
+ backgroundColor: Colors.green,
+ colorText: Colors.white,
+ );
+ Get.offAllNamed(AppRoutes.login);
+ }
+ } on FirebaseAuthException catch (e) {
+ print('FirebaseAuthException Code: ${e.code}');
+ _handleError('Sign up failed', e);
+ } catch (e) {
+ print('Unknown Error: $e');
+ _handleError('An unknown error occurred', e);
+ }
+ }
+
+
+
+ Future login(String email, String password) async {
+ try {
+ User? user = await _authService.loginWithEmailPassword(email, password);
+ if (user != null) {
+ if (user.emailVerified) {
+ Get.offAllNamed(AppRoutes.main);
+ } else {
+ Get.snackbar(
+ 'Email Not Verified',
+ 'Please verify your email before logging in.',
+ backgroundColor: Colors.orange,
+ colorText: Colors.white,
+ );
+ await signOut();
+ }
+ }
+ } catch (e) {
+ _handleError('Login failed', e);
+ }
+ }
+
+ Future signInWithGoogle() async {
+ try {
+ User? user = await _authService.signInWithGoogle();
+ if (user != null) {
+ await _checkAndStoreGoogleUserData(user);
+ Get.offAllNamed(AppRoutes.main);
+ }
+ } catch (e) {
+ _handleError('Google Sign-In failed', e);
+ }
+ }
+
+ Future signOut() async {
+ try {
+ await _authService.signOut();
+ Get.offAllNamed(AppRoutes.login);
+ } catch (e) {
+ _handleError('Sign out failed', e);
+ }
+ }
+
+ Future sendPasswordResetEmail(String email) async {
+ try {
+ await _authService.sendPasswordResetEmail(email);
+ Get.snackbar(
+ 'Reset Link Sent',
+ 'A password reset link has been sent to $email.',
+ backgroundColor: Colors.green,
+ colorText: Colors.white,
+ );
+ Get.offAllNamed(AppRoutes.login);
+ } catch (e) {
+ _handleError('Failed to send reset link', e);
+ }
+ }
+
+ Future _storeUserData(
+ User user, String name, String email, String phoneNumber) async {
+ try {
+ print('Storing user data for UID: ${user.uid}'); // Debugging line
+
+ // Check if user data already exists
+ DocumentSnapshot userDoc = await FirebaseFirestore.instance.collection('users').doc(user.uid).get();
+
+ if (!userDoc.exists) {
+ // User data does not exist, store new user data
+ print('No existing user data found, storing new user data.');
+ await FirebaseFirestore.instance.collection('users').doc(user.uid).set({
+ 'createdAt': FieldValue.serverTimestamp(),
+ 'email': email,
+ 'imageUrl': 'https://via.placeholder.com/150',
+ 'isEmailVerified': user.emailVerified, // Note: This will be false at signup
+ 'name': name,
+ 'phoneNumber': phoneNumber,
+ });
+ print('User data stored successfully.');
+ } else {
+ // User data already exists
+ print('User data already exists, no action needed.');
+ }
+ } catch (e) {
+ print('Failed to store user data: $e'); // More specific error handling
+ _handleError('Failed to store user data', e); // Use _handleError for consistent error handling
+ rethrow; // Rethrow to let the controller handle it
+ }
+ }
+
+ Future _checkAndStoreGoogleUserData(User user) async {
+ try {
+ DocumentSnapshot userDoc =
+ await FirebaseFirestore.instance.collection('users').doc(user.uid).get();
+ if (!userDoc.exists) {
+ print('No existing user data found, storing Google user data.');
+ await FirebaseFirestore.instance.collection('users').doc(user.uid).set({
+ 'name': user.displayName ?? 'Anonymous',
+ 'email': user.email ?? '',
+ 'phoneNumber': user.phoneNumber ?? '',
+ 'imageUrl': user.photoURL ?? 'https://via.placeholder.com/150',
+ 'createdAt': FieldValue.serverTimestamp(),
+ 'isEmailVerified': user.emailVerified,
+ });
+ print('Google user data stored successfully.');
+ } else {
+ print('User data already exists, no action needed.');
+ }
+ } catch (e) {
+ _handleError('Failed to check/store Google user data', e);
+ }
+ }
+
+ void _handleError(String message, dynamic e) {
+ Get.snackbar(
+ 'Error',
+ '$message: ${e.toString()}',
+ backgroundColor: Colors.red,
+ colorText: Colors.white,
+ );
+ print('Error: $message: $e');
+ }
+}
diff --git a/lib/app/modules/auth/views/ForgotPasswordView.dart b/lib/app/modules/auth/views/ForgotPasswordView.dart
new file mode 100644
index 00000000..076f4bda
--- /dev/null
+++ b/lib/app/modules/auth/views/ForgotPasswordView.dart
@@ -0,0 +1,78 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import '../../../../constants.dart';
+import '../controllers/auth_controller.dart';
+
+class ForgotPasswordView extends StatelessWidget {
+ final AuthController authController = Get.find();
+ final TextEditingController emailController = TextEditingController();
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.black,
+ appBar: AppBar(
+ title: Text('Forgot Password'),
+ backgroundColor: Colors.black,
+ ),
+ body: Center(
+ child: SingleChildScrollView(
+ padding: const EdgeInsets.symmetric(horizontal: 24.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Text(
+ 'Reset Password',
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 24,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ const SizedBox(height: 24),
+ Text(
+ 'Enter your email address below to receive a password reset link.',
+ style: TextStyle(color: Colors.white),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 24),
+ TextField(
+ controller: emailController,
+ decoration: InputDecoration(
+ labelText: 'Email',
+ labelStyle: TextStyle(color: Colors.white),
+ prefixIcon: Icon(Icons.email, color: Colors.white),
+ enabledBorder: OutlineInputBorder(
+ borderSide: BorderSide(color: Colors.white),
+ ),
+ focusedBorder: OutlineInputBorder(
+ borderSide: BorderSide(color: Colors.blue),
+ ),
+ ),
+ keyboardType: TextInputType.emailAddress,
+ style: TextStyle(color: Colors.white),
+ ),
+ const SizedBox(height: 24),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: kButtonBackgroundColor,
+ foregroundColor: kButtonTextColor,
+ padding: kButtonPadding,
+ ),
+ onPressed: () async {
+ await authController.sendPasswordResetEmail(
+ emailController.text.trim());
+ },
+ child: Text(
+ 'Send Reset Link',
+ style: kButtonTextStyle,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/auth/views/login_view.dart b/lib/app/modules/auth/views/login_view.dart
new file mode 100644
index 00000000..89804a3b
--- /dev/null
+++ b/lib/app/modules/auth/views/login_view.dart
@@ -0,0 +1,128 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:get_flutter_fire/app/routes/app_routes.dart';
+
+import '../../../../constants.dart';
+import '../../../widgets/custom_text_field.dart';
+import '../controllers/auth_controller.dart';
+
+class LoginView extends StatelessWidget {
+ final AuthController authController = Get.put(AuthController());
+
+ final TextEditingController emailController = TextEditingController();
+ final TextEditingController passwordController = TextEditingController();
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.black,
+ body: Center(
+ child: SingleChildScrollView(
+ padding: const EdgeInsets.symmetric(horizontal: 24.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Text(
+ 'Login',
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 32,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ const SizedBox(height: 24),
+ CustomTextField(
+ controller: emailController,
+ label: 'Email',
+ icon: Icons.email,
+ keyboardType: TextInputType.emailAddress,
+ ),
+ const SizedBox(height: 16),
+ CustomTextField(
+ controller: passwordController,
+ label: 'Password',
+ icon: Icons.lock,
+ obscureText: true,
+ ),
+ const SizedBox(height: 8),
+ Align(
+ alignment: Alignment.centerRight,
+ child: TextButton(
+ onPressed: () {
+ Get.toNamed(AppRoutes.forgotPassword); // Navigate to the Forgot Password screen
+ },
+ child: Text(
+ 'Forgot Password?',
+ style: TextStyle(
+ color: Colors.blue, // Color for the Forgot Password text
+ fontSize: 14,
+ decoration: TextDecoration.underline,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 16),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: kButtonBackgroundColor,
+ foregroundColor: kButtonTextColor,
+ padding: kButtonPadding,
+ ),
+ onPressed: () async {
+ // Call the login method and await its result
+ await authController.login(
+ emailController.text.trim(),
+ passwordController.text.trim(),
+ );
+ },
+ child: Text(
+ 'Login',
+ style: kButtonTextStyle,
+ ),
+ ),
+ const SizedBox(height: 16),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: Colors.white, // Google button color
+ foregroundColor: Colors.black, // Google button text color
+ padding: kButtonPadding,
+ ),
+ onPressed: () async {
+ await authController.signInWithGoogle();
+ },
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Icon(Icons.g_translate, color: Colors.black), // Google icon color
+ SizedBox(width: 10),
+ Text(
+ 'Sign in with Google',
+ style: TextStyle(
+ color: Colors.black, // Google button text color
+ fontSize: 16,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 16),
+ TextButton(
+ onPressed: () => Get.toNamed('/signup'),
+ child: Text(
+ 'Don\'t have an account? Sign Up',
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 14,
+ decoration: TextDecoration.underline,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/auth/views/signup_view.dart b/lib/app/modules/auth/views/signup_view.dart
new file mode 100644
index 00000000..bc7c265a
--- /dev/null
+++ b/lib/app/modules/auth/views/signup_view.dart
@@ -0,0 +1,117 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import '../../../../constants.dart';
+import '../../../routes/app_routes.dart';
+import '../../../widgets/custom_text_field.dart';
+import '../controllers/auth_controller.dart';
+
+class SignUpView extends StatelessWidget {
+ final AuthController authController = Get.put(AuthController());
+
+ final TextEditingController nameController = TextEditingController();
+ final TextEditingController emailController = TextEditingController();
+ final TextEditingController phoneController = TextEditingController();
+ final TextEditingController passwordController = TextEditingController();
+ final TextEditingController retypePasswordController = TextEditingController();
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.black,
+ body: Center(
+ child: SingleChildScrollView(
+ padding: const EdgeInsets.symmetric(horizontal: 24.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Text(
+ 'Sign Up',
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 32,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ const SizedBox(height: 24),
+ CustomTextField(
+ controller: nameController,
+ label: 'Name',
+ icon: Icons.person,
+ ),
+ const SizedBox(height: 16),
+ CustomTextField(
+ controller: emailController,
+ label: 'Email',
+ icon: Icons.email,
+ keyboardType: TextInputType.emailAddress,
+ ),
+ const SizedBox(height: 16),
+ CustomTextField(
+ controller: phoneController,
+ label: 'Phone Number',
+ icon: Icons.phone,
+ keyboardType: TextInputType.phone,
+ ),
+ const SizedBox(height: 16),
+ CustomTextField(
+ controller: passwordController,
+ label: 'Password',
+ icon: Icons.lock,
+ obscureText: true,
+ ),
+ const SizedBox(height: 16),
+ CustomTextField(
+ controller: retypePasswordController,
+ label: 'Retype Password',
+ icon: Icons.lock,
+ obscureText: true,
+ ),
+ const SizedBox(height: 24),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: kButtonBackgroundColor,
+ foregroundColor: kButtonTextColor,
+ padding: kButtonPadding,
+ ),
+ onPressed: () async {
+ if (passwordController.text == retypePasswordController.text) {
+ await authController.signUp(
+ email: emailController.text.trim(),
+ password: passwordController.text.trim(),
+ name: nameController.text.trim(),
+ phoneNumber: phoneController.text.trim(),
+ );
+ } else {
+ Get.snackbar(
+ 'Error',
+ 'Passwords do not match',
+ backgroundColor: Colors.red,
+ colorText: Colors.white,
+ );
+ }
+ },
+ child: Text(
+ 'Sign Up',
+ style: kButtonTextStyle,
+ ),
+ ),
+ const SizedBox(height: 16),
+ TextButton(
+ onPressed: () => Get.toNamed(AppRoutes.login),
+ child: Text(
+ 'Already have an account? Log in',
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 14,
+ decoration: TextDecoration.underline,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/cart/bindings/cart_binding.dart b/lib/app/modules/cart/bindings/cart_binding.dart
deleted file mode 100644
index 009c52ae..00000000
--- a/lib/app/modules/cart/bindings/cart_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/cart_controller.dart';
-
-class CartBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => CartController(),
- );
- }
-}
diff --git a/lib/app/modules/cart/controllers/cart_controller.dart b/lib/app/modules/cart/controllers/cart_controller.dart
deleted file mode 100644
index c938ec4c..00000000
--- a/lib/app/modules/cart/controllers/cart_controller.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:get/get.dart';
-
-class CartController extends GetxController {
- //TODO: Implement CartController
-
- final count = 0.obs;
- @override
- void onInit() {
- super.onInit();
- }
-
- @override
- void onReady() {
- super.onReady();
- }
-
- @override
- void onClose() {
- super.onClose();
- }
-
- void increment() => count.value++;
-}
diff --git a/lib/app/modules/cart/views/cart_view.dart b/lib/app/modules/cart/views/cart_view.dart
deleted file mode 100644
index 3e048c79..00000000
--- a/lib/app/modules/cart/views/cart_view.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-import 'package:get_flutter_fire/app/routes/app_pages.dart';
-import '../../../widgets/screen_widget.dart';
-import '../../../../services/auth_service.dart';
-import '../controllers/cart_controller.dart';
-
-class CartView extends GetView {
- const CartView({super.key});
- @override
- Widget build(BuildContext context) {
- return ScreenWidget(
- appBar: AppBar(
- title: Text('${AuthService.to.userName} Cart'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'CartView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- screen: screen!,
- );
- }
-}
diff --git a/lib/app/modules/categories/bindings/categories_binding.dart b/lib/app/modules/categories/bindings/categories_binding.dart
deleted file mode 100644
index 06e278c8..00000000
--- a/lib/app/modules/categories/bindings/categories_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/categories_controller.dart';
-
-class CategoriesBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => CategoriesController(),
- );
- }
-}
diff --git a/lib/app/modules/categories/controllers/categories_controller.dart b/lib/app/modules/categories/controllers/categories_controller.dart
deleted file mode 100644
index 6612e511..00000000
--- a/lib/app/modules/categories/controllers/categories_controller.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:get/get.dart';
-
-class CategoriesController extends GetxController {
- //TODO: Implement CategoriesController
-
- final count = 0.obs;
- @override
- void onInit() {
- super.onInit();
- }
-
- @override
- void onReady() {
- super.onReady();
- }
-
- @override
- void onClose() {
- super.onClose();
- }
-
- void increment() => count.value++;
-}
diff --git a/lib/app/modules/categories/views/categories_view.dart b/lib/app/modules/categories/views/categories_view.dart
deleted file mode 100644
index 97bfef38..00000000
--- a/lib/app/modules/categories/views/categories_view.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/categories_controller.dart';
-
-class CategoriesView extends GetView {
- const CategoriesView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('CategoriesView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'CategoriesView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
diff --git a/lib/app/modules/checkout/bindings/checkout_binding.dart b/lib/app/modules/checkout/bindings/checkout_binding.dart
deleted file mode 100644
index 42202b56..00000000
--- a/lib/app/modules/checkout/bindings/checkout_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/checkout_controller.dart';
-
-class CheckoutBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => CheckoutController(),
- );
- }
-}
diff --git a/lib/app/modules/checkout/controllers/checkout_controller.dart b/lib/app/modules/checkout/controllers/checkout_controller.dart
deleted file mode 100644
index aa1265f6..00000000
--- a/lib/app/modules/checkout/controllers/checkout_controller.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:get/get.dart';
-
-class CheckoutController extends GetxController {
- //TODO: Implement CheckoutController
-
- final count = 0.obs;
- @override
- void onInit() {
- super.onInit();
- }
-
- @override
- void onReady() {
- super.onReady();
- }
-
- @override
- void onClose() {
- super.onClose();
- }
-
- void increment() => count.value++;
-}
diff --git a/lib/app/modules/checkout/views/checkout_view.dart b/lib/app/modules/checkout/views/checkout_view.dart
deleted file mode 100644
index b8b17072..00000000
--- a/lib/app/modules/checkout/views/checkout_view.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/checkout_controller.dart';
-
-class CheckoutView extends GetView {
- const CheckoutView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('CheckoutView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'CheckoutView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
diff --git a/lib/app/modules/dashboard/bindings/dashboard_binding.dart b/lib/app/modules/dashboard/bindings/dashboard_binding.dart
deleted file mode 100644
index da48f13c..00000000
--- a/lib/app/modules/dashboard/bindings/dashboard_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/dashboard_controller.dart';
-
-class DashboardBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => DashboardController(),
- );
- }
-}
diff --git a/lib/app/modules/dashboard/controllers/dashboard_controller.dart b/lib/app/modules/dashboard/controllers/dashboard_controller.dart
deleted file mode 100644
index 24d91a16..00000000
--- a/lib/app/modules/dashboard/controllers/dashboard_controller.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-import 'dart:async';
-
-import 'package:get/get.dart';
-
-class DashboardController extends GetxController {
- final now = DateTime.now().obs;
- @override
- void onReady() {
- super.onReady();
- Timer.periodic(
- const Duration(seconds: 1),
- (timer) {
- now.value = DateTime.now();
- },
- );
- }
-}
diff --git a/lib/app/modules/dashboard/views/dashboard_view.dart b/lib/app/modules/dashboard/views/dashboard_view.dart
deleted file mode 100644
index f475030f..00000000
--- a/lib/app/modules/dashboard/views/dashboard_view.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../controllers/dashboard_controller.dart';
-
-class DashboardView extends GetView {
- const DashboardView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Center(
- child: Obx(
- () => Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const Text(
- 'DashboardView is working',
- style: TextStyle(fontSize: 20),
- ),
- Text('Time: ${controller.now.value.toString()}'),
- ],
- ),
- ),
- ),
- );
- }
-}
diff --git a/lib/app/modules/home/bindings/home_binding.dart b/lib/app/modules/home/bindings/home_binding.dart
index d08a80d4..005e3d33 100644
--- a/lib/app/modules/home/bindings/home_binding.dart
+++ b/lib/app/modules/home/bindings/home_binding.dart
@@ -1,12 +1,12 @@
import 'package:get/get.dart';
-
+import '../controllers/Ranking_Controller.dart';
import '../controllers/home_controller.dart';
class HomeBinding extends Bindings {
@override
void dependencies() {
- Get.lazyPut(
- () => HomeController(),
- );
+ Get.lazyPut(() => HomeController());
+ Get.lazyPut(() => RankingController());
+
}
}
diff --git a/lib/app/modules/home/controllers/Ranking_Controller.dart b/lib/app/modules/home/controllers/Ranking_Controller.dart
new file mode 100644
index 00000000..5f89c683
--- /dev/null
+++ b/lib/app/modules/home/controllers/Ranking_Controller.dart
@@ -0,0 +1,35 @@
+import 'package:get/get.dart';
+import 'dart:convert';
+import 'package:http/http.dart' as http;
+
+import '../../../../services/player.dart';
+
+class RankingController extends GetxController {
+ var players = [].obs;
+ var isLoading = true.obs;
+ var error = ''.obs;
+
+ @override
+ void onInit() {
+ fetchTopPlayers();
+ super.onInit();
+ }
+
+ void fetchTopPlayers() async {
+ try {
+ isLoading(true);
+ final response = await http.get(Uri.parse('https://fide-api.vercel.app/top_players'));
+
+ if (response.statusCode == 200) {
+ List jsonResponse = json.decode(response.body);
+ players.value = jsonResponse.map((player) => Player.fromJson(player)).toList();
+ } else {
+ error('Failed to load data');
+ }
+ } catch (e) {
+ error(e.toString());
+ } finally {
+ isLoading(false);
+ }
+ }
+}
diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart
index f058de2a..cc13423c 100644
--- a/lib/app/modules/home/controllers/home_controller.dart
+++ b/lib/app/modules/home/controllers/home_controller.dart
@@ -1,14 +1,30 @@
import 'package:get/get.dart';
+import '../../../../services/Streamer.dart';
+import '../../../../services/Streamer_Service.dart';
-import '../../../../models/role.dart';
-import '../../../../services/auth_service.dart';
class HomeController extends GetxController {
- final Rx chosenRole = Rx(AuthService.to.maxRole);
+ final StreamerService _streamerService = StreamerService();
- // Role get role => AuthService.to.maxRole;
+ var streamers = [].obs;
+ var isLoading = true.obs;
+ var error = ''.obs;
- get isBuyer => chosenRole.value == Role.buyer;
+ @override
+ void onInit() {
+ super.onInit();
+ fetchStreamers();
+ }
- get isAdmin => chosenRole.value == Role.admin;
+ void fetchStreamers() async {
+ try {
+ isLoading(true);
+ var fetchedStreamers = await _streamerService.fetchStreamers();
+ streamers.assignAll(fetchedStreamers);
+ } catch (e) {
+ error(e.toString());
+ } finally {
+ isLoading(false);
+ }
+ }
}
diff --git a/lib/app/modules/home/views/home_view.dart b/lib/app/modules/home/views/home_view.dart
index 0cfc040d..51d207f9 100644
--- a/lib/app/modules/home/views/home_view.dart
+++ b/lib/app/modules/home/views/home_view.dart
@@ -1,34 +1,99 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
-import '../../../routes/app_pages.dart';
-import '../../../widgets/screen_widget.dart';
+import 'package:get_flutter_fire/app/widgets/Vs_Widget.dart';
+import '../../../widgets/Scroll_Card_Widget.dart';
+import '../../../widgets/Ranking_Widget.dart';
+
import '../controllers/home_controller.dart';
-class HomeView extends GetView {
- const HomeView({super.key});
+class HomeView extends StatelessWidget {
+ final HomeController controller = Get.put(HomeController());
@override
Widget build(BuildContext context) {
- return GetRouterOutlet.builder(
- builder: (context, delegate, currentRoute) {
- var arg = Get.rootDelegate.arguments();
- if (arg != null) {
- controller.chosenRole.value = arg["role"];
- }
- var route = controller.chosenRole.value.tabs[0].route;
- //This router outlet handles the appbar and the bottom navigation bar
- return ScreenWidget(
- screen: screen!,
- body: GetRouterOutlet(
- initialRoute: route,
- // anchorRoute: Routes.HOME,
- key: Get.nestedKey(route),
+ return Scaffold(
+ body: CustomScrollView(
+ slivers: [
+ SliverAppBar(
+ expandedHeight: MediaQuery.of(context).size.height * 0.35,
+ pinned: true,
+ flexibleSpace: FlexibleSpaceBar(
+ background: Image.asset(
+ 'assets/images/ding.png',
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ SliverToBoxAdapter(
+ child: Container(
+ color: Colors.black,
+ child: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'Featured Streamers',
+ style: TextStyle(
+ fontSize: 24,
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ SizedBox(height: 16),
+ Obx(() {
+ if (controller.isLoading.value) {
+ return Center(child: CircularProgressIndicator());
+ } else if (controller.error.isNotEmpty) {
+ return Center(
+ child: Text(
+ 'Error: ${controller.error}',
+ style: TextStyle(color: Colors.red),
+ ),
+ );
+ } else if (controller.streamers.isEmpty) {
+ return Center(
+ child: Text(
+ 'No streamers found',
+ style: TextStyle(color: Colors.white),
+ ),
+ );
+ } else {
+ return ScrollCardWidget(streamers: controller.streamers);
+ }
+ }),
+ SizedBox(height: 40,),
+ Text(
+ 'World Championship',
+ style: TextStyle(
+ fontSize: 24,
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+
+ VsWidget(
+ imageUrl1: 'assets/images/ding.jpg',
+ imageUrl2: 'assets/images/gukesh.jpg',
+ label1: 'Ding liren',
+ label2: 'Gukesh D'),
+ SizedBox(height: 40),
+ Text(
+ 'Top 10 Players',
+ style: TextStyle(
+ fontSize: 24,
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ RankingWidget(numberOfPlayers: 10,), // Add the RankingWidget here
+ ],
+ ),
+ ),
+ ),
),
- role: controller.chosenRole.value,
- delegate: delegate,
- currentRoute: currentRoute,
- );
- },
+ ],
+ ),
);
}
}
diff --git a/lib/app/modules/login/bindings/login_binding.dart b/lib/app/modules/login/bindings/login_binding.dart
deleted file mode 100644
index ac119f4a..00000000
--- a/lib/app/modules/login/bindings/login_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/login_controller.dart';
-
-class LoginBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => LoginController(),
- );
- }
-}
diff --git a/lib/app/modules/login/controllers/login_controller.dart b/lib/app/modules/login/controllers/login_controller.dart
deleted file mode 100644
index 5178fec9..00000000
--- a/lib/app/modules/login/controllers/login_controller.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-import 'package:get/get.dart';
-
-import '../../../../services/auth_service.dart';
-
-class LoginController extends GetxController {
- static AuthService get to => Get.find();
-
- final Rx showReverificationButton = Rx(false);
-
- bool get isRobot => AuthService.to.robot.value == true;
-
- set robot(bool v) => AuthService.to.robot.value = v;
-
- bool get isLoggedIn => AuthService.to.isLoggedInValue;
-
- bool get isAnon => AuthService.to.isAnon;
-
- bool get isRegistered =>
- AuthService.to.registered.value || AuthService.to.isEmailVerified;
-}
diff --git a/lib/app/modules/login/views/login_view.dart b/lib/app/modules/login/views/login_view.dart
deleted file mode 100644
index 00c3af3f..00000000
--- a/lib/app/modules/login/views/login_view.dart
+++ /dev/null
@@ -1,162 +0,0 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:firebase_auth/firebase_auth.dart' as fba;
-import 'package:firebase_ui_auth/firebase_ui_auth.dart';
-import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import '../../../../firebase_options.dart';
-
-import '../../../../models/screens.dart';
-import '../../../widgets/login_widgets.dart';
-import '../controllers/login_controller.dart';
-
-class LoginView extends GetView {
- void showReverificationButton(
- bool show, fba.EmailAuthCredential? credential) {
- // Below is very important.
- // See [https://stackoverflow.com/questions/69351845/this-obx-widget-cannot-be-marked-as-needing-to-build-because-the-framework-is-al]
- WidgetsBinding.instance.addPostFrameCallback((_) {
- controller.showReverificationButton.value = show;
- });
- //or Future.delayed(Duration.zero, () {
- // We can get the email and password from the controllers either by making the whole screen from scratch
- // or probably by add flutter_test find.byKey (hacky)
- // tried using AuthStateChangeAction instead which is not getting called
- // Finally Subclassed EmailAuthProvider to handle the same, but that also did not work
- // So went for server side email sending option
- //}));
- }
-
- const LoginView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return Obx(() => loginScreen(context));
- }
-
- Widget subtitleBuilder(context, action) {
- return Padding(
- padding: const EdgeInsets.symmetric(vertical: 8.0),
- child: action == AuthAction.signIn
- ? const Text('Welcome to Get Flutter Fire, please sign in!')
- : const Text('New to Get Flutter Fire, please sign up!'),
- );
- }
-
- Widget footerBuilder(Rx show, Rxn credential) {
- return LoginWidgets.footerBuilder(EmailLinkButton(show, credential));
- }
-
- Widget loginScreen(BuildContext context) {
- Widget ui;
- if (!controller.isLoggedIn) {
- ui = !(GetPlatform.isAndroid || GetPlatform.isIOS) && controller.isRobot
- ? recaptcha()
- : SignInScreen(
- providers: [
- GoogleProvider(clientId: DefaultFirebaseOptions.webClientId),
- MyEmailAuthProvider(),
- ],
- showAuthActionSwitch: !controller.isRegistered,
- showPasswordVisibilityToggle: true,
- headerBuilder: LoginWidgets.headerBuilder,
- subtitleBuilder: subtitleBuilder,
- footerBuilder: (context, action) => footerBuilder(
- controller.showReverificationButton,
- LoginController.to.credential),
- sideBuilder: LoginWidgets.sideBuilder,
- actions: getActions(),
- );
- } else if (controller.isAnon) {
- ui = RegisterScreen(
- providers: [
- MyEmailAuthProvider(),
- ],
- showAuthActionSwitch: !controller.isAnon, //if Anon only SignUp
- showPasswordVisibilityToggle: true,
- headerBuilder: LoginWidgets.headerBuilder,
- subtitleBuilder: subtitleBuilder,
- footerBuilder: (context, action) => footerBuilder(
- controller.showReverificationButton, LoginController.to.credential),
- sideBuilder: LoginWidgets.sideBuilder,
- actions: getActions(),
- );
- } else {
- final thenTo = Get
- .rootDelegate.currentConfiguration!.currentPage!.parameters?['then'];
- Get.rootDelegate.offNamed(thenTo ??
- (controller.isRegistered ? Screen.HOME : Screen.REGISTER).route);
- ui = const Scaffold();
- }
- return ui;
- }
-
- Widget recaptcha() {
- //TODO: Add Recaptcha
- return Scaffold(
- body: TextButton(
- onPressed: () => controller.robot = false,
- child: const Text("Are you a Robot?"),
- ));
- }
-
- /// The following actions are useful here:
- /// - [AuthStateChangeAction]
- /// - [AuthCancelledAction]
- /// - [EmailLinkSignInAction]
- /// - [VerifyPhoneAction]
- /// - [SMSCodeRequestedAction]
-
- List getActions() {
- return [
- // AuthStateChangeAction((context, state) {
- AuthStateChangeAction((context, state) => LoginController.to
- .errorMessage(context, state, showReverificationButton)),
- // AuthStateChangeAction((context, state) {
- // // This is not required due to the AuthMiddleware
- // }),
- // EmailLinkSignInAction((context) {
- // final thenTo = Get.rootDelegate.currentConfiguration!.currentPage!
- // .parameters?['then'];
- // Get.rootDelegate.offNamed(thenTo ?? Routes.PROFILE);
- // }),
- ];
- }
-}
-
-class MyEmailAuthProvider extends EmailAuthProvider {
- @override
- void onCredentialReceived(
- fba.EmailAuthCredential credential,
- AuthAction action,
- ) {
- WidgetsBinding.instance.addPostFrameCallback((_) {
- LoginController.to.credential.value = credential;
- });
- super.onCredentialReceived(credential, action);
- }
-}
-
-class EmailLinkButton extends StatelessWidget {
- final Rx show;
- final Rxn credential;
-
- const EmailLinkButton(
- this.show,
- this.credential, {
- super.key,
- });
-
- @override
- Widget build(BuildContext context) {
- return Obx(() => Visibility(
- visible: show.value,
- child: Padding(
- padding: const EdgeInsets.only(top: 16),
- child: ElevatedButton(
- onPressed: () => LoginController.to
- .sendVerificationMail(emailAuth: credential.value),
- child: const Text('Resend Verification Mail')))));
- }
-}
diff --git a/lib/app/modules/my_products/bindings/my_products_binding.dart b/lib/app/modules/my_products/bindings/my_products_binding.dart
deleted file mode 100644
index a537f047..00000000
--- a/lib/app/modules/my_products/bindings/my_products_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/my_products_controller.dart';
-
-class MyProductsBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => MyProductsController(),
- );
- }
-}
diff --git a/lib/app/modules/my_products/controllers/my_products_controller.dart b/lib/app/modules/my_products/controllers/my_products_controller.dart
deleted file mode 100644
index 31696ea2..00000000
--- a/lib/app/modules/my_products/controllers/my_products_controller.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:get/get.dart';
-
-class MyProductsController extends GetxController {
- //TODO: Implement MyProductsController
-
- final count = 0.obs;
- @override
- void onInit() {
- super.onInit();
- }
-
- @override
- void onReady() {
- super.onReady();
- }
-
- @override
- void onClose() {
- super.onClose();
- }
-
- void increment() => count.value++;
-}
diff --git a/lib/app/modules/my_products/views/my_products_view.dart b/lib/app/modules/my_products/views/my_products_view.dart
deleted file mode 100644
index 43793ebb..00000000
--- a/lib/app/modules/my_products/views/my_products_view.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/my_products_controller.dart';
-
-class MyProductsView extends GetView {
- const MyProductsView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('MyProductsView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'MyProductsView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
diff --git a/lib/app/modules/product_details/bindings/product_details_binding.dart b/lib/app/modules/product_details/bindings/product_details_binding.dart
deleted file mode 100644
index 624d55ac..00000000
--- a/lib/app/modules/product_details/bindings/product_details_binding.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/product_details_controller.dart';
-
-class ProductDetailsBinding extends Bindings {
- @override
- void dependencies() {
- Get.create(
- () => ProductDetailsController(
- Get.parameters['productId'] ?? '',
- ),
- );
- }
-}
diff --git a/lib/app/modules/product_details/controllers/product_details_controller.dart b/lib/app/modules/product_details/controllers/product_details_controller.dart
deleted file mode 100644
index d894e10c..00000000
--- a/lib/app/modules/product_details/controllers/product_details_controller.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-import 'package:get/get.dart';
-
-class ProductDetailsController extends GetxController {
- final String productId;
-
- ProductDetailsController(this.productId);
- @override
- void onInit() {
- super.onInit();
- Get.log('ProductDetailsController created with id: $productId');
- }
-
- @override
- void onClose() {
- Get.log('ProductDetailsController close with id: $productId');
- super.onClose();
- }
-}
diff --git a/lib/app/modules/product_details/views/product_details_view.dart b/lib/app/modules/product_details/views/product_details_view.dart
deleted file mode 100644
index c9290724..00000000
--- a/lib/app/modules/product_details/views/product_details_view.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/product_details_controller.dart';
-
-class ProductDetailsView extends GetWidget {
- const ProductDetailsView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Center(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const Text(
- 'ProductDetailsView is working',
- style: TextStyle(fontSize: 20),
- ),
- Text('ProductId: ${controller.productId}')
- ],
- ),
- ),
- );
- }
-}
diff --git a/lib/app/modules/products/bindings/products_binding.dart b/lib/app/modules/products/bindings/products_binding.dart
deleted file mode 100644
index e7c762db..00000000
--- a/lib/app/modules/products/bindings/products_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/products_controller.dart';
-
-class ProductsBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => ProductsController(),
- );
- }
-}
diff --git a/lib/app/modules/products/controllers/products_controller.dart b/lib/app/modules/products/controllers/products_controller.dart
deleted file mode 100644
index 118c7dc8..00000000
--- a/lib/app/modules/products/controllers/products_controller.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'package:get/get.dart';
-
-import '../../../../models/product.dart';
-
-class ProductsController extends GetxController {
- final products = [].obs;
-
- void loadDemoProductsFromSomeWhere() {
- products.add(
- Product(
- name: 'Product added on: ${DateTime.now().toString()}',
- id: DateTime.now().millisecondsSinceEpoch.toString(),
- ),
- );
- }
-
- @override
- void onReady() {
- super.onReady();
- loadDemoProductsFromSomeWhere();
- }
-
- @override
- void onClose() {
- Get.printInfo(info: 'Products: onClose');
- super.onClose();
- }
-}
diff --git a/lib/app/modules/products/views/products_view.dart b/lib/app/modules/products/views/products_view.dart
deleted file mode 100644
index 5b190a6a..00000000
--- a/lib/app/modules/products/views/products_view.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../../../../models/role.dart';
-import '../../../routes/app_pages.dart';
-import '../controllers/products_controller.dart';
-
-class ProductsView extends GetView {
- const ProductsView({super.key});
-
- @override
- Widget build(BuildContext context) {
- var arg = Get.rootDelegate.arguments();
- return Scaffold(
- floatingActionButton:
- (arg != null && Get.rootDelegate.arguments()["role"] == Role.seller)
- ? FloatingActionButton.extended(
- onPressed: controller.loadDemoProductsFromSomeWhere,
- label: const Text('Add'),
- )
- : null,
- body: Column(
- children: [
- const Hero(
- tag: 'heroLogo',
- child: FlutterLogo(),
- ),
- Expanded(
- child: Obx(
- () => RefreshIndicator(
- onRefresh: () async {
- controller.products.clear();
- controller.loadDemoProductsFromSomeWhere();
- },
- child: ListView.builder(
- itemCount: controller.products.length,
- itemBuilder: (context, index) {
- final item = controller.products[index];
- return ListTile(
- onTap: () {
- Get.rootDelegate.toNamed(Routes.PRODUCT_DETAILS(
- item.id)); //we could use Get Parameters
- },
- title: Text(item.name),
- subtitle: Text(item.id),
- );
- },
- ),
- ),
- ),
- ),
- ],
- ),
- );
- }
-}
diff --git a/lib/app/modules/profile/bindings/profile_binding.dart b/lib/app/modules/profile/bindings/profile_binding.dart
index 5eb3b2bd..5f2d3610 100644
--- a/lib/app/modules/profile/bindings/profile_binding.dart
+++ b/lib/app/modules/profile/bindings/profile_binding.dart
@@ -1,12 +1,10 @@
import 'package:get/get.dart';
+import 'package:get_flutter_fire/app/modules/profile/controllers/profile_controller.dart';
-import '../controllers/profile_controller.dart';
-
-class ProfileBinding extends Bindings {
+class HomeBinding extends Bindings {
@override
void dependencies() {
- Get.lazyPut(
- () => ProfileController(),
- );
+ Get.lazyPut(() => ProfileController());
+
}
}
diff --git a/lib/app/modules/profile/controllers/profile_controller.dart b/lib/app/modules/profile/controllers/profile_controller.dart
index 0c1e059e..139d4c4c 100644
--- a/lib/app/modules/profile/controllers/profile_controller.dart
+++ b/lib/app/modules/profile/controllers/profile_controller.dart
@@ -1,62 +1,74 @@
-import 'dart:io';
-
-import 'package:firebase_auth/firebase_auth.dart';
-import 'package:firebase_storage/firebase_storage.dart';
import 'package:get/get.dart';
-import 'package:get_storage/get_storage.dart';
-
-import 'package:path/path.dart';
-import '../../../../services/auth_service.dart';
+import 'package:cloud_firestore/cloud_firestore.dart';
+import 'package:firebase_auth/firebase_auth.dart';
+import 'dart:io';
+import 'package:flutter/material.dart';
+import '../../../../services/firstore_service.dart';
+import '../../../routes/app_routes.dart';
class ProfileController extends GetxController {
- FirebaseStorage storage = FirebaseStorage.instance;
- User? currentUser = AuthService.to.user;
- final Rxn _photoURL = Rxn();
-
- File? _photo;
-
- String? get photoURL => _photoURL.value;
+ final FirestoreService _firestoreService = FirestoreService();
+ var userData = {}.obs;
+ RxBool isLoading = true.obs;
@override
- onInit() {
+ void onInit() {
super.onInit();
- _photoURL.value = currentUser!.photoURL;
- _photoURL.bindStream(currentUser!.photoURL.obs.stream);
+ fetchUserData();
}
- Future uploadFile(String path) async {
+ Future fetchUserData() async {
try {
- var byt = GetStorage().read(path);
- if (byt != null) {
- final fileName = path;
- final destination = 'profilePics/${currentUser!.uid}';
-
- final ref = storage.ref(destination).child(fileName);
- await ref.putData(byt);
- return "$destination/$fileName";
- } else {
- _photo = File(path);
- if (_photo == null) return null;
- final fileName = basename(_photo!.path);
- final destination = 'profilePics/${currentUser!.uid}';
-
- final ref = storage.ref(destination).child(fileName);
- await ref.putFile(_photo!);
- return "$destination/$fileName";
- }
+ isLoading(true);
+ DocumentSnapshot snapshot = await _firestoreService.getUserData();
+ userData.value = snapshot.data() as Map;
} catch (e) {
- Get.snackbar('Error', 'Image Not Uploaded as ${e.toString()}');
+ Get.snackbar(
+ 'Error',
+ 'Failed to fetch user data: ${e.toString()}',
+ backgroundColor: Colors.red,
+ colorText: Colors.white,
+ );
+ } finally {
+ isLoading(false);
}
- return null;
}
- void logout() {
- AuthService.to.logout();
+ Future signOut() async {
+ try {
+ await FirebaseAuth.instance.signOut();
+ Get.offAllNamed(AppRoutes.login);
+ } catch (e) {
+ Get.snackbar(
+ 'Error',
+ 'Sign out failed: ${e.toString()}',
+ backgroundColor: Colors.red,
+ colorText: Colors.white,
+ );
+ }
}
- Future updatePhotoURL(String dest) async {
- _photoURL.value = await storage.ref().child(dest).getDownloadURL();
- await currentUser?.updatePhotoURL(_photoURL.value);
- Get.snackbar('Success', 'Picture stored and linked');
+ Future updateUserData({
+ required String name,
+ required String email,
+ required String phoneNumber,
+ File? imageFile,
+ }) async {
+ try {
+ await _firestoreService.updateUserData(
+ name: name,
+ email: email,
+ phoneNumber: phoneNumber,
+ imageFile: imageFile,
+ );
+ fetchUserData(); // Refresh the data after updating
+ } catch (e) {
+ Get.snackbar(
+ 'Error',
+ 'Failed to update user data: ${e.toString()}',
+ backgroundColor: Colors.red,
+ colorText: Colors.white,
+ );
+ }
}
}
diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart
index c26d11c1..376ccd0a 100644
--- a/lib/app/modules/profile/views/profile_view.dart
+++ b/lib/app/modules/profile/views/profile_view.dart
@@ -1,124 +1,198 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:firebase_ui_auth/firebase_ui_auth.dart';
+import 'dart:io';
+import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
-
-import '../../../../services/auth_service.dart';
-import '../../../../models/screens.dart';
-import '../../../widgets/change_password_dialog.dart';
-import '../../../widgets/image_picker_button.dart';
+import 'package:image_picker/image_picker.dart';
import '../controllers/profile_controller.dart';
+import 'package:path_provider/path_provider.dart';
-class ProfileView extends GetView {
- const ProfileView({super.key});
- ShapeBorder get shape => const CircleBorder();
- double get size => 120;
- Color get placeholderColor => Colors.grey;
+class ProfileView extends StatelessWidget {
+ final ProfileController _controller = Get.put(ProfileController());
- Widget _imageFrameBuilder(
- BuildContext context,
- Widget? child,
- int? frame,
- bool? _,
- ) {
- if (frame == null) {
- return Container(color: placeholderColor);
- }
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.black,
+ appBar: AppBar(
+ title: Text('Profile', style: TextStyle(color: Colors.white)),
+ backgroundColor: Colors.black,
+ actions: [
+ IconButton(
+ icon: Icon(Icons.edit, color: Colors.white),
+ onPressed: () => _showEditDialog(context),
+ ),
+ ],
+ ),
+ body: Obx(() {
+ if (_controller.isLoading.value) {
+ return Center(child: CircularProgressIndicator(color: Colors.white));
+ }
- return child!;
+ return Center(
+ child: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ FutureBuilder(
+ future: _getLocalImageFile(),
+ builder: (context, snapshot) {
+ if (snapshot.connectionState == ConnectionState.waiting) {
+ return CircleAvatar(
+ radius: 50,
+ backgroundColor: Colors.grey,
+ );
+ } else if (snapshot.hasData && snapshot.data != null) {
+ return CircleAvatar(
+ radius: 50,
+ backgroundImage: FileImage(snapshot.data!),
+ );
+ } else {
+ return CircleAvatar(
+ radius: 50,
+ backgroundImage: NetworkImage(
+ _controller.userData['imageUrl'] ??
+ 'https://via.placeholder.com/150',
+ ),
+ );
+ }
+ },
+ ),
+ SizedBox(height: 20),
+ Text(
+ _controller.userData['name'] ?? 'No name',
+ style: TextStyle(
+ fontSize: 24,
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ SizedBox(height: 10),
+ Text(
+ _controller.userData['email'] ?? 'No email',
+ style: TextStyle(
+ fontSize: 18,
+ color: Colors.grey,
+ fontStyle: FontStyle.italic,
+ ),
+ ),
+ SizedBox(height: 30),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: Colors.red,
+ padding: EdgeInsets.symmetric(vertical: 12, horizontal: 24),
+ ),
+ onPressed: _controller.signOut,
+ child: Text(
+ 'Sign Out',
+ style: TextStyle(color: Colors.white, fontSize: 16),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }),
+ );
}
- @override
- Widget build(BuildContext context) {
- return Obx(() => profileScreen());
+ Future _getLocalImageFile() async {
+ User? user = FirebaseAuth.instance.currentUser;
+ if (user != null) {
+ Directory appDocDir = await getApplicationDocumentsDirectory();
+ String localPath = '${appDocDir.path}/user_${user.uid}.jpg';
+ File localFile = File(localPath);
+ if (localFile.existsSync()) {
+ return localFile;
+ }
+ }
+ return null;
}
- Widget profileScreen() {
- return AuthService.to.isLoggedInValue
- ? ProfileScreen(
- // We are using the Flutter Fire Profile Screen now but will change in subsequent steps.
- // The issues are highlighted in comments here
+ void _showEditDialog(BuildContext context) {
+ final nameController = TextEditingController(text: _controller.userData['name']);
+ final emailController = TextEditingController(text: _controller.userData['email']);
+ File? _selectedImage;
- // appBar: AppBar(
- // title: const Text('User Profile'),
- // ),
- avatar: SizedBox(
- //null will give the profile image component but it does not refresh the pic when changed
- height: size,
- width: size,
- child: ClipPath(
- clipper: ShapeBorderClipper(shape: shape),
- clipBehavior: Clip.hardEdge,
- child: controller.photoURL != null
- ? Image.network(
- controller.photoURL!,
- width: size,
- height: size,
- cacheWidth: size.toInt(),
- cacheHeight: size.toInt(),
- fit: BoxFit.contain,
- frameBuilder: _imageFrameBuilder,
- )
- : Center(
- child: Image.asset(
- 'assets/images/dash.png',
- width: size,
- fit: BoxFit.contain,
- ),
- ),
- ),
+ showDialog(
+ context: context,
+ builder: (context) {
+ return AlertDialog(
+ backgroundColor: Colors.black,
+ title: Text('Edit Profile', style: TextStyle(color: Colors.white)),
+ content: SingleChildScrollView(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ GestureDetector(
+ onTap: () async {
+ _selectedImage = await _pickImage(context);
+ },
+ child: CircleAvatar(
+ radius: 40,
+ backgroundImage: _selectedImage != null
+ ? FileImage(_selectedImage!)
+ : NetworkImage(_controller.userData['imageUrl'] ??
+ 'https://via.placeholder.com/150') as ImageProvider,
+ child: Icon(Icons.camera_alt, color: Colors.white.withOpacity(0.7), size: 40),
+ ),
+ ),
+ SizedBox(height: 20),
+ _buildTextField(nameController, 'Name'),
+ SizedBox(height: 10),
+ _buildTextField(emailController, 'Email'),
+ ],
),
- // showDeleteConfirmationDialog: true, //this does not work properly. Possibly a bug in FlutterFire
- actions: [
- SignedOutAction((context) {
- Get.back();
- controller.logout();
- Get.rootDelegate.toNamed(Screen.PROFILE.route);
- // Navigator.of(context).pop();
- }),
- AccountDeletedAction((context, user) {
- //If we don't include this the button is still shown but no action gets done. Ideally the button should also not be shown. Its a bug in FlutterFire
- Get.defaultDialog(
- //this is only called after the delete is done and not useful for confirmation of the delete action
- title: 'Deleted Account of ${user.displayName}',
- barrierDismissible: true,
- navigatorKey: Get.nestedKey(Screen.HOME.route),
+ ),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.of(context).pop(),
+ child: Text('Cancel', style: TextStyle(color: Colors.white)),
+ ),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
+ onPressed: () {
+ _controller.updateUserData(
+ name: nameController.text,
+ email: emailController.text,
+ phoneNumber: _controller.userData['phoneNumber'] ?? '',
+ imageFile: _selectedImage,
);
- })
- ],
- children: [
- //This is to show that we can add custom content here
- const Divider(),
- controller.currentUser?.email != null
- ? TextButton.icon(
- onPressed: callChangePwdDialog,
- label: const Text('Change Password'),
- icon: const Icon(Icons.password_rounded),
- )
- : const SizedBox.shrink(),
- ImagePickerButton(callback: (String? path) async {
- if (path != null) {
- //Upload to Store
- String? dest = await controller.uploadFile(path);
- //attach it to User imageUrl
- if (dest != null) {
- await controller.updatePhotoURL(dest);
- }
- }
- })
- ],
- )
- : const Scaffold();
+ Navigator.of(context).pop();
+ },
+ child: Text('Save', style: TextStyle(color: Colors.white)),
+ ),
+ ],
+ );
+ },
+ );
+ }
+
+ Future _pickImage(BuildContext context) async {
+ final ImagePicker _picker = ImagePicker();
+ final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
+
+ if (pickedFile != null) {
+ return File(pickedFile.path);
+ }
+ return null;
}
- void callChangePwdDialog() {
- var dlg = ChangePasswordDialog(controller.currentUser!);
- Get.defaultDialog(
- title: "Change Password",
- content: dlg,
- textConfirm: "Submit",
- textCancel: "Cancel",
- onConfirm: dlg.onSubmit);
+ Widget _buildTextField(TextEditingController controller, String label) {
+ return TextField(
+ controller: controller,
+ style: TextStyle(color: Colors.white),
+ decoration: InputDecoration(
+ labelText: label,
+ labelStyle: TextStyle(color: Colors.grey),
+ enabledBorder: UnderlineInputBorder(
+ borderSide: BorderSide(color: Colors.grey),
+ ),
+ focusedBorder: UnderlineInputBorder(
+ borderSide: BorderSide(color: Colors.white),
+ ),
+ ),
+ );
}
}
diff --git a/lib/app/modules/ranking/views/ranking_view.dart b/lib/app/modules/ranking/views/ranking_view.dart
new file mode 100644
index 00000000..86db2177
--- /dev/null
+++ b/lib/app/modules/ranking/views/ranking_view.dart
@@ -0,0 +1,68 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../../home/controllers/Ranking_Controller.dart';
+
+class RankingView extends StatelessWidget {
+ final RankingController rankingController = Get.put(RankingController());
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.black,
+ body: Obx(() {
+ if (rankingController.isLoading.value) {
+ return Center(child: CircularProgressIndicator(color: Colors.white));
+ } else if (rankingController.error.isNotEmpty) {
+ return Center(
+ child: Text(
+ 'Error: ${rankingController.error}',
+ style: TextStyle(color: Colors.red, fontSize: 18),
+ ),
+ );
+ } else {
+ return CustomScrollView(
+ slivers: [
+ SliverAppBar(
+ expandedHeight: 350.0, // Height of the image when expanded
+ floating: false,
+ pinned: true,
+ backgroundColor: Colors.black,
+ flexibleSpace: FlexibleSpaceBar(
+ background: Image.asset(
+ 'assets/images/goat.png', // Replace with your image asset
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ SliverList(
+ delegate: SliverChildBuilderDelegate(
+ (context, index) {
+ final player = rankingController.players[index];
+ return ListTile(
+ leading: Text(
+ player.rank.toString(),
+ style: TextStyle(color: Colors.white),
+ ),
+ title: Text(
+ player.name,
+ style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
+ ),
+ subtitle: Text(
+ 'Country: ${player.country} | Rating: ${player.rating}',
+ style: TextStyle(color: Colors.white70),
+ ),
+ tileColor: Colors.grey[900],
+ contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
+ );
+ },
+ childCount: rankingController.players.length > 100 ? 100 : rankingController.players.length,
+ ),
+ ),
+ ],
+ );
+ }
+ }),
+ );
+ }
+}
diff --git a/lib/app/modules/register/bindings/register_binding.dart b/lib/app/modules/register/bindings/register_binding.dart
deleted file mode 100644
index 1089ecbd..00000000
--- a/lib/app/modules/register/bindings/register_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/register_controller.dart';
-
-class RegisterBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => RegisterController(),
- );
- }
-}
diff --git a/lib/app/modules/register/controllers/register_controller.dart b/lib/app/modules/register/controllers/register_controller.dart
deleted file mode 100644
index 96cb2cb0..00000000
--- a/lib/app/modules/register/controllers/register_controller.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:get/get.dart';
-
-import '../../../../services/auth_service.dart';
-
-class RegisterController extends GetxController {
- @override
- void onInit() {
- super.onInit();
- // Send email verification and logout
- AuthService.to
- .sendVerificationMail(); //if we use the EmailVerificationScreen then no need to call this
- }
-
- // @override
- // void onReady() {
- // super.onReady();
- // }
-
- // @override
- // void onClose() {
- // super.onClose();
- // }
-}
diff --git a/lib/app/modules/register/views/register_view.dart b/lib/app/modules/register/views/register_view.dart
deleted file mode 100644
index 01f73e88..00000000
--- a/lib/app/modules/register/views/register_view.dart
+++ /dev/null
@@ -1,53 +0,0 @@
-// import 'package:firebase_ui_auth/firebase_ui_auth.dart';
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../../../../services/auth_service.dart';
-// import '../../../widgets/login_widgets.dart';
-import '../controllers/register_controller.dart';
-
-//ALso add a form to take additional info such as display name of other customer details mapped with uid in Firestore
-class RegisterView extends GetView {
- const RegisterView({super.key});
-
- @override
- Widget build(BuildContext context) {
- // Add pre verification Form if any. Mostly it can be post verification and can be the Profile or Setting screens
- try {
- // using this is causing an error when we send verification mail from server side
- // if it was initiated once, even when no visible. So we need to dispose when not visible
- var w =
- // EmailVerificationScreen(
- // headerBuilder: LoginWidgets.headerBuilder,
- // sideBuilder: LoginWidgets.sideBuilder,
- // actions: [
- // EmailVerifiedAction(() {
- // AuthService.to.register();
- // }),
- // ],
- // );
- Scaffold(
- appBar: AppBar(
- title: const Text('Registeration'),
- centerTitle: true,
- ),
- body: Center(
- child: Column(children: [
- const Text(
- 'Please verify your email (check SPAM folder), and then relogin',
- style: TextStyle(fontSize: 20),
- ),
- TextButton(
- onPressed: () => AuthService.to.register(),
- child: const Text("Verification Done. Relogin"),
- )
- ])),
- );
- return w;
- } catch (e) {
- // TODO
- }
- return const Scaffold();
- }
-}
diff --git a/lib/app/modules/root/bindings/root_binding.dart b/lib/app/modules/root/bindings/root_binding.dart
deleted file mode 100644
index e1e94d1d..00000000
--- a/lib/app/modules/root/bindings/root_binding.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:get/get.dart';
-
-import '../controllers/root_controller.dart';
-
-class RootBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => RootController(),
- );
- }
-}
diff --git a/lib/app/modules/root/controllers/my_drawer_controller.dart b/lib/app/modules/root/controllers/my_drawer_controller.dart
deleted file mode 100644
index f45ef122..00000000
--- a/lib/app/modules/root/controllers/my_drawer_controller.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-import 'package:get/get.dart';
-
-import '../../../../models/screens.dart';
-
-class MyDrawerController extends GetxController {
- MyDrawerController(Iterable iter)
- : values = Rx>(iter);
-
- final Rx> values;
-}
diff --git a/lib/app/modules/root/controllers/root_controller.dart b/lib/app/modules/root/controllers/root_controller.dart
deleted file mode 100644
index 7f160fc6..00000000
--- a/lib/app/modules/root/controllers/root_controller.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-class RootController extends GetxController {
- GlobalKey scaffoldKey = GlobalKey();
-
- void openDrawer() {
- scaffoldKey.currentState!.openDrawer();
- }
-
- void closeDrawer() {
- scaffoldKey.currentState!.openEndDrawer();
- }
-}
diff --git a/lib/app/modules/root/views/drawer.dart b/lib/app/modules/root/views/drawer.dart
deleted file mode 100644
index 908d0223..00000000
--- a/lib/app/modules/root/views/drawer.dart
+++ /dev/null
@@ -1,118 +0,0 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../../../../models/role.dart';
-import '../../../../services/auth_service.dart';
-
-import '../../../../models/screens.dart';
-import '../controllers/my_drawer_controller.dart';
-
-class DrawerWidget extends StatelessWidget {
- const DrawerWidget({
- super.key,
- });
-
- @override
- Widget build(BuildContext context) {
- MyDrawerController controller = Get.put(MyDrawerController([]),
- permanent: true); //must make true else gives error
- Screen.drawer().then((v) => {controller.values.value = v});
- return Obx(() => Drawer(
- //changing the shape of the drawer
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.only(
- topRight: Radius.circular(0), bottomRight: Radius.circular(20)),
- ),
- width: 200,
- child: Column(
- children: drawerItems(context, controller.values),
- ),
- ));
- }
-
- List drawerItems(BuildContext context, Rx> values) {
- List list = [
- Container(
- height: 100,
- color: Colors.red,
- //adding content in the highlighted part of the drawer
- child: Align(
- alignment: Alignment.centerLeft,
- child: Container(
- margin: const EdgeInsets.only(left: 15),
- child: const Text('User Name', //Profile Icon also
- style: TextStyle(fontWeight: FontWeight.bold)))),
- )
- ];
-
- if (AuthService.to.maxRole.index > 1) {
- for (var i = 0; i <= AuthService.to.maxRole.index; i++) {
- Role role = Role.values[i];
- list.add(ListTile(
- title: Text(
- role.name,
- style: const TextStyle(
- color: Colors.blue,
- ),
- ),
- onTap: () {
- Get.rootDelegate
- .toNamed(Screen.HOME.route, arguments: {'role': role});
- //to close the drawer
- Navigator.of(context).pop();
- },
- ));
- }
- }
-
- for (Screen screen in values.value) {
- list.add(ListTile(
- title: Text(screen.label ?? ''),
- onTap: () {
- Get.rootDelegate.toNamed(screen.route);
- //to close the drawer
-
- Navigator.of(context).pop();
- },
- ));
- }
-
- if (AuthService.to.isLoggedInValue) {
- list.add(ListTile(
- title: const Text(
- 'Logout',
- style: TextStyle(
- color: Colors.red,
- ),
- ),
- onTap: () {
- AuthService.to.logout();
- Get.rootDelegate.toNamed(Screen.LOGIN.route);
- //to close the drawer
-
- Navigator.of(context).pop();
- },
- ));
- }
- if (!AuthService.to.isLoggedInValue) {
- list.add(ListTile(
- title: const Text(
- 'Login',
- style: TextStyle(
- color: Colors.blue,
- ),
- ),
- onTap: () {
- Get.rootDelegate.toNamed(Screen.LOGIN.route);
- //to close the drawer
-
- Navigator.of(context).pop();
- },
- ));
- }
-
- return list;
- }
-}
diff --git a/lib/app/modules/root/views/root_view.dart b/lib/app/modules/root/views/root_view.dart
deleted file mode 100644
index 2bbf228c..00000000
--- a/lib/app/modules/root/views/root_view.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import 'package:get_flutter_fire/services/auth_service.dart';
-import '../../../routes/app_pages.dart';
-import '../../../../models/screens.dart';
-import '../controllers/root_controller.dart';
-import 'drawer.dart';
-
-class RootView extends GetView {
- const RootView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return GetRouterOutlet.builder(
- builder: (context, delegate, current) {
- final title = current!.currentPage!.title;
- return Scaffold(
- key: controller.scaffoldKey,
- drawer: const DrawerWidget(),
- appBar: AppBar(
- title: Text(title ?? ''),
- centerTitle: true,
- leading: GetPlatform.isIOS // Since Web and Android have back button
- &&
- current.locationString.contains(RegExp(r'(\/[^\/]*){3,}'))
- ? BackButton(
- onPressed: () =>
- Get.rootDelegate.popRoute(), //Navigator.pop(context),
- )
- : IconButton(
- icon: ImageIcon(
- const AssetImage("icons/logo.png"),
- color: Colors.grey.shade800,
- ),
- onPressed: () => AuthService.to.isLoggedInValue
- ? controller.openDrawer()
- : {Screen.HOME.doAction()},
- ),
- actions: topRightMenuButtons(current),
- // automaticallyImplyLeading: false, //removes drawer icon
- ),
- body: GetRouterOutlet(
- initialRoute: AppPages.INITIAL,
- // anchorRoute: '/',
- // filterPages: (afterAnchor) {
- // return afterAnchor.take(1);
- // },
- ),
- );
- },
- );
- }
-
-//This could be used to add icon buttons in expanded web view instead of the context menu
- List topRightMenuButtons(GetNavConfig current) {
- return [
- Container(
- margin: const EdgeInsets.only(right: 15),
- child: Screen.LOGIN.widget(current))
- ]; //TODO add seach button
- }
-}
diff --git a/lib/app/modules/search/bindings/Search_Binding.dart b/lib/app/modules/search/bindings/Search_Binding.dart
new file mode 100644
index 00000000..07e5d1c5
--- /dev/null
+++ b/lib/app/modules/search/bindings/Search_Binding.dart
@@ -0,0 +1,11 @@
+import 'package:get/get.dart';
+
+import '../controllers/Search_Controller.dart';
+
+
+class SearchBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(() => MySearchController());
+ }
+}
diff --git a/lib/app/modules/search/controllers/Search_Controller.dart b/lib/app/modules/search/controllers/Search_Controller.dart
new file mode 100644
index 00000000..3c74fcd7
--- /dev/null
+++ b/lib/app/modules/search/controllers/Search_Controller.dart
@@ -0,0 +1,52 @@
+import 'package:get/get.dart';
+import 'package:http/http.dart' as http;
+import 'dart:convert';
+
+class MySearchController extends GetxController {
+ var playerDetails = {}.obs;
+ var history =