Added create a unit screen, and implemented otp screen bloc and view

This commit is contained in:
Abdullah Alassaf
2024-05-30 10:59:22 +03:00
parent 28576f2cd5
commit 9877dde78e
22 changed files with 789 additions and 348 deletions

View File

@ -0,0 +1,6 @@
<svg width="20" height="23" viewBox="0 0 20 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.6455 8.78868L12.8125 18.6622C12.7753 19.1042 13.4423 19.1646 13.4799 18.7185L14.3129 8.84498C14.3285 8.66071 14.1917 8.49872 14.0074 8.48314C13.8229 8.4676 13.661 8.60436 13.6455 8.78868Z" fill="white"/>
<path d="M5.99277 8.48312C5.8085 8.49871 5.67174 8.6607 5.68723 8.84497L6.52023 18.7185C6.55791 19.1651 7.22486 19.1042 7.18762 18.6622L6.35462 8.78867C6.33913 8.60435 6.177 8.46768 5.99277 8.48312Z" fill="white"/>
<path d="M9.66504 8.81681V18.6903C9.66504 18.8753 9.81493 19.0252 9.99992 19.0252C10.1849 19.0252 10.3348 18.8753 10.3348 18.6903V8.81681C10.3348 8.63187 10.1849 8.48193 9.99992 8.48193C9.81493 8.48193 9.66504 8.63187 9.66504 8.81681Z" fill="white"/>
<path d="M18.4553 2.58668H13.1893V1.40966C13.1893 0.632383 12.5569 0 11.7796 0H8.2203C7.44303 0 6.81065 0.632383 6.81065 1.40966V2.58668H1.54463C0.692929 2.58668 0 3.27961 0 4.13132C0 4.98302 0.692929 5.67595 1.54463 5.67595H1.90483L3.15763 20.525C3.26899 21.8448 4.37247 22.861 5.69895 22.861H14.301C15.6254 22.861 16.7308 21.8468 16.8423 20.525L17.016 18.4664C17.0316 18.2821 16.8947 18.1201 16.7105 18.1045C16.5257 18.0887 16.3642 18.2257 16.3486 18.41L16.1749 20.4687C16.0935 21.4346 15.2703 22.1912 14.301 22.1912H5.69895C4.72963 22.1912 3.9065 21.4346 3.82502 20.4687L2.57695 5.67595H3.56845C3.75344 5.67595 3.90333 5.52601 3.90333 5.34107C3.90333 5.15613 3.75344 5.0062 3.56845 5.0062C2.83489 5.0062 1.96988 5.0062 1.54463 5.0062C1.06223 5.0062 0.669755 4.61372 0.669755 4.13132C0.669755 3.64891 1.06223 3.25644 1.54463 3.25644H18.4553C18.9377 3.25644 19.3302 3.64891 19.3302 4.13132C19.3302 4.61372 18.9377 5.0062 18.4553 5.0062C17.9351 5.0062 6.25962 5.0062 5.13492 5.0062C4.94994 5.0062 4.80005 5.15613 4.80005 5.34107C4.80005 5.52601 4.94994 5.67595 5.13492 5.67595H17.423L16.4804 16.8477C16.4649 17.032 16.6017 17.1939 16.786 17.2095C16.7956 17.2103 16.8051 17.2107 16.8146 17.2107C16.9867 17.2107 17.1331 17.0787 17.1479 16.904L18.0952 5.67595H18.4553C19.307 5.67595 20 4.98302 20 4.13132C20 3.27961 19.307 2.58668 18.4553 2.58668ZM12.5196 2.58668H7.4804V1.40966C7.4804 1.00169 7.81233 0.669755 8.2203 0.669755H11.7796C12.1876 0.669755 12.5195 1.00169 12.5195 1.40966L12.5196 2.58668Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,15 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.5419 20.2424C11.1182 19.3486 10.0545 18.9678 9.16647 19.3935L1.38334 23.1268C0.591819 23.3098 0 24.0197 0 24.8727V33.8466C0 34.8381 0.797668 35.6413 1.78229 35.6413C2.76668 35.6413 3.56412 34.8381 3.56412 33.8466V27.6644L9.16647 30.3516C9.41376 30.4704 9.67449 30.5264 9.93112 30.5264C10.5974 30.5264 11.2359 30.1484 11.5419 29.5025C11.9643 28.6076 11.5875 27.5367 10.699 27.1103L6.03295 24.8725L10.699 22.6346C11.5877 22.2085 11.9643 21.1376 11.5419 20.2424Z" fill="#D5D5D5"/>
<path d="M20.6084 17.6894C20.8655 17.6894 21.1258 17.6334 21.3738 17.5146L32.0481 12.3951C32.9366 11.9685 33.3142 10.8974 32.8911 10.0024C32.4683 9.10864 31.4053 8.72813 30.5156 9.15359L19.8408 14.2736C18.9523 14.6999 18.5754 15.7706 18.9981 16.6658C19.3039 17.3112 19.9424 17.6894 20.6084 17.6894Z" fill="#D5D5D5"/>
<path d="M42.7228 7.27445L48.1842 4.65449V10.9114C48.1842 11.9027 48.9818 12.7061 49.966 12.7061C50.9504 12.7061 51.7478 11.9027 51.7478 10.9114V4.62192L57.278 7.27445C57.526 7.39303 57.7862 7.44922 58.0433 7.44922C58.7091 7.44922 59.3479 7.07124 59.6535 6.42537C60.0763 5.53041 59.6994 4.45953 58.8107 4.03316L50.7664 0.174427C50.2814 -0.0581424 49.7189 -0.0581424 49.2339 0.174427L41.19 4.03316C40.3015 4.45953 39.9244 5.53018 40.3473 6.42537C40.7711 7.32101 41.8363 7.70198 42.7228 7.27445Z" fill="#D5D5D5"/>
<path d="M67.9532 12.3944L78.6281 17.5146C78.8749 17.6334 79.1361 17.6894 79.3932 17.6894C80.059 17.6894 80.6977 17.3114 81.0033 16.6655C81.4259 15.7706 81.0493 14.6997 80.1605 14.2733L69.4855 9.1529C68.5981 8.72721 67.5345 9.10726 67.1105 10.0018C66.6874 10.8967 67.0645 11.9676 67.9532 12.3944Z" fill="#D5D5D5"/>
<path d="M81.5391 34.8099C82.4276 34.3837 82.8047 33.3128 82.3816 32.4177C81.9587 31.5232 80.8947 31.1424 80.0066 31.5695L73.1671 34.8509L51.7478 24.577V16.5765C51.7478 15.5846 50.9503 14.7818 49.9659 14.7818C48.9818 14.7818 48.1841 15.5848 48.1841 16.5765V24.6096L26.8347 34.85L20.7 31.9073C19.8094 31.481 18.7483 31.8612 18.3245 32.7564C17.9016 33.6514 18.2787 34.7225 19.1673 35.1489L25.8032 38.3319V61.6684L19.0593 64.9031C18.1708 65.3295 17.7939 66.4001 18.2166 67.2955C18.5222 67.9412 19.1607 68.3192 19.8267 68.3192C20.0838 68.3192 20.3447 68.2632 20.5918 68.1444L26.8349 65.1499L48.1841 75.3903V81.5075C48.1841 82.4993 48.9818 83.3022 49.9659 83.3022C50.9503 83.3022 51.7478 82.499 51.7478 81.5075V75.4233L73.1657 65.1501L79.6525 68.2616C79.9002 68.3802 80.1607 68.4364 80.4176 68.4364C81.0834 68.4364 81.7222 68.0584 82.0277 67.4125C82.4508 66.5175 82.0735 65.4467 81.185 65.0201L74.1977 61.6687V38.3319L81.5391 34.8099ZM70.634 62.3879L51.748 71.4467V49.0994L70.634 40.0402V62.3879ZM29.4789 61.8939C29.4472 61.8269 29.4053 61.7691 29.3668 61.7081V40.0404L48.1841 49.0663V71.4141L29.641 62.5198C29.6239 62.3086 29.5745 62.0964 29.4789 61.8939ZM50.0003 27.7151L69.0207 36.8383L50.0003 45.9611L30.9799 36.8383L50.0003 27.7151Z" fill="#D5D5D5"/>
<path d="M78.6271 82.486L67.9525 87.6062C67.064 88.0328 66.6865 89.1036 67.1095 89.9979C67.4154 90.644 68.0541 91.0215 68.7199 91.0215C68.9768 91.0215 69.238 90.9656 69.485 90.8477L80.1598 85.7273C81.0484 85.3009 81.4252 84.2295 81.0026 83.3346C80.579 82.4401 79.515 82.0616 78.6271 82.486Z" fill="#D5D5D5"/>
<path d="M57.2782 92.7266L51.748 95.3793V88.227C51.748 87.2357 50.9506 86.4323 49.9662 86.4323C48.982 86.4323 48.1844 87.2357 48.1844 88.227V95.3468L42.723 92.7266C41.8335 92.3023 40.7713 92.6807 40.3475 93.5759C39.9246 94.4709 40.3015 95.5413 41.1903 95.9676L49.2346 99.8259C49.4769 99.9417 49.7387 100 50.0008 100C50.2629 100 50.5248 99.9417 50.7671 99.8259L58.8114 95.9676C59.6999 95.5413 60.077 94.4709 59.6541 93.5759C59.2304 92.6807 58.166 92.3032 57.2782 92.7266Z" fill="#D5D5D5"/>
<path d="M32.0477 87.6061L21.3729 82.4859C20.4864 82.0605 19.4219 82.4394 18.9976 83.3343C18.575 84.2293 18.9519 85.3006 19.8404 85.727L30.5154 90.8474C30.7623 90.9653 31.0235 91.0213 31.2803 91.0213C31.9461 91.0213 32.5849 90.6438 32.8905 89.9977C33.3133 89.1036 32.9362 88.0328 32.0477 87.6061Z" fill="#D5D5D5"/>
<path d="M11.5419 70.4974C11.1182 69.6029 10.0545 69.224 9.16647 69.6488L3.56412 72.3355V65.6178C3.56412 64.6265 2.76668 63.823 1.78229 63.823C0.797668 63.823 0 64.6265 0 65.6178V74.5919C0 74.8162 0.0457694 75.0284 0.120686 75.2263C0.156892 75.8784 0.53193 76.4651 1.12215 76.7486L9.16647 80.6073C9.41376 80.7254 9.67449 80.7818 9.93112 80.7818C10.5974 80.7818 11.2359 80.4038 11.5419 79.7582C11.9643 78.8632 11.5875 77.7924 10.699 77.3655L6.03295 75.1281L10.699 72.8903C11.5877 72.4637 11.9643 71.3923 11.5419 70.4974Z" fill="#D5D5D5"/>
<path d="M1.78229 56.8226C2.76668 56.8226 3.56412 56.0193 3.56412 55.0274V44.4374C3.56412 43.4461 2.76668 42.6427 1.78229 42.6427C0.797668 42.6427 0 43.4461 0 44.4374V55.0274C0.00022771 56.0193 0.797896 56.8226 1.78229 56.8226Z" fill="#D5D5D5"/>
<path d="M98.6174 23.1268L90.8342 19.3935C89.9444 18.9667 88.8825 19.3479 88.459 20.2424C88.0364 21.1378 88.4132 22.2084 89.3018 22.6351L93.9678 24.8729L89.3018 27.1108C88.4132 27.5371 88.0364 28.6078 88.459 29.503C88.7646 30.1488 89.4033 30.5268 90.0691 30.5268C90.3262 30.5268 90.5874 30.4709 90.8342 30.3521L96.4366 27.6649V33.847C96.4366 34.8385 97.234 35.6418 98.2184 35.6418C99.2028 35.6418 100 34.8385 100 33.847V24.8731C100 24.0197 99.4089 23.3098 98.6174 23.1268Z" fill="#D5D5D5"/>
<path d="M98.2184 42.642C97.2338 42.642 96.4366 43.4455 96.4366 44.4367V55.0267C96.4366 56.0187 97.234 56.8214 98.2184 56.8214C99.2028 56.8214 100 56.0184 100 55.0267V44.4367C100 43.4455 99.203 42.642 98.2184 42.642Z" fill="#D5D5D5"/>
<path d="M98.2184 63.8228C97.2338 63.8228 96.4366 64.6263 96.4366 65.6175V72.3352L90.8342 69.6485C89.9444 69.2231 88.8825 69.6022 88.459 70.4971C88.0364 71.3921 88.4132 72.4634 89.3018 72.8898L93.9678 75.1277L89.3018 77.3651C88.4132 77.7919 88.0364 78.8628 88.459 79.7577C88.7646 80.4034 89.4033 80.7814 90.0691 80.7814C90.3262 80.7814 90.5874 80.7249 90.8342 80.6068L98.8786 76.7481C99.4688 76.4646 99.8438 75.8779 99.88 75.2258C99.9547 75.0279 100 74.8157 100 74.5914V65.6173C100 64.6263 99.203 63.8228 98.2184 63.8228Z" fill="#D5D5D5"/>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -120,9 +120,60 @@ PODS:
- nanopb/encode (= 2.30909.1) - nanopb/encode (= 2.30909.1)
- nanopb/decode (2.30909.1) - nanopb/decode (2.30909.1)
- nanopb/encode (2.30909.1) - nanopb/encode (2.30909.1)
- onesignal_flutter (5.2.0):
- Flutter
- OneSignalXCFramework (= 5.2.0)
- OneSignalXCFramework (5.2.0):
- OneSignalXCFramework/OneSignalComplete (= 5.2.0)
- OneSignalXCFramework/OneSignal (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalExtension
- OneSignalXCFramework/OneSignalLiveActivities
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalComplete (5.2.0):
- OneSignalXCFramework/OneSignal
- OneSignalXCFramework/OneSignalInAppMessages
- OneSignalXCFramework/OneSignalLocation
- OneSignalXCFramework/OneSignalCore (5.2.0)
- OneSignalXCFramework/OneSignalExtension (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalInAppMessages (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalLiveActivities (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalLocation (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalNotifications (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalExtension
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalOSCore (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOutcomes (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalUser (5.2.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalOutcomes
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- PromisesObjC (2.3.1) - PromisesObjC (2.3.1)
- PromisesSwift (2.3.1): - PromisesSwift (2.3.1):
- PromisesObjC (= 2.3.1) - PromisesObjC (= 2.3.1)
@ -142,7 +193,9 @@ DEPENDENCIES:
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_localization (from `.symlinks/plugins/flutter_localization/ios`) - flutter_localization (from `.symlinks/plugins/flutter_localization/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- onesignal_flutter (from `.symlinks/plugins/onesignal_flutter/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`) - sqflite (from `.symlinks/plugins/sqflite/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@ -161,6 +214,7 @@ SPEC REPOS:
- GoogleDataTransport - GoogleDataTransport
- GoogleUtilities - GoogleUtilities
- nanopb - nanopb
- OneSignalXCFramework
- PromisesObjC - PromisesObjC
- PromisesSwift - PromisesSwift
@ -177,8 +231,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_localization/ios" :path: ".symlinks/plugins/flutter_localization/ios"
flutter_secure_storage: flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios" :path: ".symlinks/plugins/flutter_secure_storage/ios"
onesignal_flutter:
:path: ".symlinks/plugins/onesignal_flutter/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
shared_preferences_foundation: shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin" :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite: sqflite:
@ -205,7 +263,10 @@ SPEC CHECKSUMS:
GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34 GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
onesignal_flutter: 5ce68a29861960168e81101cb1bd685d264361de
OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265 PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695

View File

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 60; objectVersion = 54;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@ -202,6 +202,7 @@
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
315A05630CF83C532DBBCBF2 /* [CP] Embed Pods Frameworks */, 315A05630CF83C532DBBCBF2 /* [CP] Embed Pods Frameworks */,
0D61909C49A20C9AA28568EA /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, 0D61909C49A20C9AA28568EA /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
3724F7A126D8469D5B04D144 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@ -309,6 +310,23 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
3724F7A126D8469D5B04D144 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;

View File

@ -22,6 +22,7 @@ import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigation_service.dart'; import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
@ -198,7 +199,7 @@ class HomeCubit extends Cubit<HomeState> {
try { try {
spaces = await SpacesAPI.getUnitsByUserId(); spaces = await SpacesAPI.getUnitsByUserId();
} catch (failure) { } catch (failure) {
emitSafe(GetSpacesError(failure.toString())); emitSafe(GetSpacesError("No units found"));
return; return;
} }

View File

@ -19,11 +19,6 @@ class AuthCubit extends Cubit<AuthState> {
final TextEditingController emailController = TextEditingController(); final TextEditingController emailController = TextEditingController();
final TextEditingController passwordController = TextEditingController(); final TextEditingController passwordController = TextEditingController();
// final TextEditingController emailSignUpController = TextEditingController();
// final TextEditingController fullNameController = TextEditingController();
// final TextEditingController passwordSignUpController = TextEditingController();
// final TextEditingController reEnterPasswordSignUpController = TextEditingController();
String fullName = ''; String fullName = '';
String email = ''; String email = '';
String signUpPassword = ''; String signUpPassword = '';
@ -51,6 +46,10 @@ class AuthCubit extends Cubit<AuthState> {
static Token token = Token.emptyConstructor(); static Token token = Token.emptyConstructor();
setOtpCode(String value) {
otpCode = value;
}
/////////////////////////////////////VALIDATORS///////////////////////////////////// /////////////////////////////////////VALIDATORS/////////////////////////////////////
String? passwordValidator(String? value) { String? passwordValidator(String? value) {
if (value != null) { if (value != null) {
@ -64,9 +63,6 @@ class AuthCubit extends Cubit<AuthState> {
} }
} }
} }
if (signUpFormKey.currentState != null) {
signUpFormKey.currentState!.save();
}
return null; return null;
} }
@ -94,19 +90,16 @@ class AuthCubit extends Cubit<AuthState> {
if (parts.any((part) => part.length < 2 || part.length > 30)) { if (parts.any((part) => part.length < 2 || part.length > 30)) {
return 'Full name parts must be between 2 and 30 characters long'; return 'Full name parts must be between 2 and 30 characters long';
} }
if (signUpFormKey.currentState != null) {
signUpFormKey.currentState!.save();
}
return null; return null;
} }
String reEnterPasswordCheck(String? value) { String? reEnterPasswordCheck(String? value) {
passwordValidator(value); passwordValidator(value);
if (signUpPassword == value) { if (signUpPassword == value) {
if (signUpFormKey.currentState != null) { // if (signUpFormKey.currentState != null) {
signUpFormKey.currentState!.save(); // signUpFormKey.currentState!.save();
} // }
return ''; return null;
} else { } else {
return 'Passwords do not match'; return 'Passwords do not match';
} }
@ -115,9 +108,6 @@ class AuthCubit extends Cubit<AuthState> {
String? emailAddressValidator(String? value) { String? emailAddressValidator(String? value) {
if (value != null && value.isNotEmpty && value != "") { if (value != null && value.isNotEmpty && value != "") {
if (checkValidityOfEmail(value)) { if (checkValidityOfEmail(value)) {
if (signUpFormKey.currentState != null) {
signUpFormKey.currentState!.save();
}
return null; return null;
} else { } else {
return 'Please enter a valid email'; return 'Please enter a valid email';
@ -204,14 +194,47 @@ class AuthCubit extends Cubit<AuthState> {
} }
if (response) { if (response) {
maskedEmail = maskEmail(email); maskedEmail = maskEmail(email);
final response = await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'PASSWORD'}); await sendOtp();
otpCode = response['otp'];
emit(AuthSignUpSuccess());
} else { } else {
emit(AuthLoginError(message: 'Something went wrong')); emit(AuthLoginError(message: 'Something went wrong'));
} }
} }
sendOtp() async {
try {
final response =
await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
// otpCode = response['otp'];
emit(AuthSignUpSuccess());
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
}
}
verifyOtp() async {
emit(AuthLoginLoading());
try {
final response = await AuthenticationAPI.verifyPassCode(
body: {'email': email, 'type': 'VERIFICATION', 'otpCode': otpCode});
if (response['statusCode'] == 200) {
emailController.text = email;
passwordController.text = signUpPassword;
await login();
emit(AuthOtpSuccess());
} else {
emit(AuthLoginError(message: 'Something went wrong'));
}
// if (otpCode == '654321') {
// emit(AuthOtpSuccess());
// } else {
// emit(AuthLoginError(message: 'Otp is not correct'));
// }
} catch (failure) {
emit(AuthLoginError(message: failure.toString()));
return;
}
}
logout() async { logout() async {
emit(AuthLogoutLoading()); emit(AuthLogoutLoading());
try { try {

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
@ -18,6 +19,8 @@ class LoginView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarBrightness: Brightness.light, statusBarIconBrightness: Brightness.light));
return BlocConsumer<AuthCubit, AuthState>( return BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) { listener: (context, state) {
if (state is AuthError) { if (state is AuthError) {
@ -31,9 +34,9 @@ class LoginView extends StatelessWidget {
} }
}, },
builder: (context, state) { builder: (context, state) {
return SafeArea( return Scaffold(
child: Scaffold( body: SafeArea(
body: Stack( child: Stack(
children: [ children: [
Container( Container(
width: MediaQuery.sizeOf(context).width, width: MediaQuery.sizeOf(context).width,

View File

@ -1,35 +1,33 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:pin_code_fields/pin_code_fields.dart'; import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart'; import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
class OtpView extends StatelessWidget { class OtpView extends StatelessWidget {
const OtpView({super.key}); const OtpView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final formKey = AuthCubit.get(context).signUpFormKey; String maskedEmail = AuthCubit.get(context).maskEmail(AuthCubit.get(context).email);
return BlocConsumer<AuthCubit, AuthState>( return BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) { listener: (context, state) {
if (state is AuthError) { if (state is AuthOtpSuccess) {
} else if (state is AuthOtpSuccess) { Navigator.pushNamedAndRemoveUntil(context, Routes.homeRoute, (value) => false);
Navigator.popAndPushNamed(context, Routes.homeRoute);
} }
}, },
builder: (context, state) { builder: (context, state) {
return SafeArea( return Scaffold(
child: Scaffold( body: SafeArea(
body: Stack( child: Stack(
children: [ children: [
Container( Container(
width: MediaQuery.sizeOf(context).width, width: MediaQuery.sizeOf(context).width,
@ -96,7 +94,7 @@ class OtpView extends StatelessWidget {
), ),
children: [ children: [
TextSpan( TextSpan(
text: ' ex******e@email.com', text: ' $maskedEmail',
style: Theme.of(context).textTheme.titleSmall!.copyWith( style: Theme.of(context).textTheme.titleSmall!.copyWith(
color: Colors.black, color: Colors.black,
fontWeight: FontsManager.bold, fontWeight: FontsManager.bold,
@ -116,20 +114,19 @@ class OtpView extends StatelessWidget {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox( const SizedBox(
height: 40, height: 40,
), ),
PinCodeTextField( PinCodeTextField(
key: const Key('pin_code_text_field'), key: const Key('pin_code_text_field'),
appContext: context, appContext: context,
length: 4, length: 6,
obscuringCharacter: '-',
cursorHeight: 25, cursorHeight: 25,
backgroundColor: Colors.transparent,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
autoFocus: true, autoFocus: true,
backgroundColor: Colors.transparent,
animationDuration: const Duration(milliseconds: 30), animationDuration: const Duration(milliseconds: 30),
// controller: AuthCubit.get(context).emailController,
// cursorColor: KeysperColors.primaryBase,
beforeTextPaste: (text) { beforeTextPaste: (text) {
// Allow pasting only if all characters are numeric // Allow pasting only if all characters are numeric
return int.tryParse(text!) != null; return int.tryParse(text!) != null;
@ -137,11 +134,11 @@ class OtpView extends StatelessWidget {
textStyle: Theme.of(context) textStyle: Theme.of(context)
.textTheme .textTheme
.headlineMedium! .headlineMedium!
.copyWith(color: Colors.black), .copyWith(color: Colors.white),
hintStyle: Theme.of(context) hintStyle: Theme.of(context)
.textTheme .textTheme
.headlineMedium! .headlineMedium!
.copyWith(color: Colors.grey), .copyWith(color: Colors.white),
enablePinAutofill: true, enablePinAutofill: true,
pinTheme: PinTheme( pinTheme: PinTheme(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
@ -152,24 +149,28 @@ class OtpView extends StatelessWidget {
errorBorderWidth: 1, errorBorderWidth: 1,
borderWidth: 1, borderWidth: 1,
errorBorderColor: Colors.red, errorBorderColor: Colors.red,
activeColor: Colors.white, activeColor: state is AuthLoginError ? Colors.red : Colors.white,
inactiveColor: Colors.white, inactiveColor:
activeFillColor: Colors.white, state is AuthLoginError ? Colors.red : Colors.white,
inactiveFillColor: Colors.white, activeFillColor:
selectedFillColor: Colors.white, state is AuthLoginError ? Colors.red : Colors.white,
inactiveFillColor:
state is AuthLoginError ? Colors.red : Colors.white,
selectedFillColor:
state is AuthLoginError ? Colors.red : Colors.white,
disabledColor: Colors.white, disabledColor: Colors.white,
fieldHeight: 50, fieldHeight: 56,
fieldWidth: 50, fieldWidth: MediaQuery.sizeOf(context).width > 340 ? 40 : 20,
// fieldWidth: 40,
selectedColor: Colors.white, selectedColor: Colors.white,
shape: PinCodeFieldShape.box, shape: PinCodeFieldShape.box,
), ),
onChanged: (value) async { onChanged: (value) {
// otpCode = value; AuthCubit.get(context).setOtpCode(value);
// await bloc.onOTPChanged(value);
}, },
onCompleted: (value) {}, onCompleted: (value) {},
onSubmitted: (value) async { onSubmitted: (value) {
// await bloc.onOTPSubmitted(); // AuthCubit.get(context).setOtpCode(value);
}, },
), ),
const SizedBox(height: 40), const SizedBox(height: 40),
@ -192,11 +193,35 @@ class OtpView extends StatelessWidget {
'Verify', 'Verify',
), ),
onPressed: () { onPressed: () {
if (formKey.currentState!.validate()) { if ((state is! AuthLoading)) {
if ((state is! AuthLoading)) { AuthCubit.get(context).verifyOtp();
AuthCubit.get(context).signUp(); FocusScope.of(context).unfocus();
FocusScope.of(context).unfocus(); }
} },
),
),
const SizedBox(
width: 4,
),
Expanded(
child: DefaultButton(
isDone: state is AuthLoginSuccess,
isLoading: state is AuthLoading,
customButtonStyle: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Colors.black.withOpacity(.25),
),
foregroundColor: MaterialStateProperty.all(
Colors.white,
),
),
child: const Text(
'Resend',
),
onPressed: () async {
if ((state is! AuthLoading)) {
await AuthCubit.get(context).sendOtp();
FocusScope.of(context).unfocus();
} }
}, },
), ),

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/features/auth/view/widgets/login_form.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart'; import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
@ -26,13 +25,14 @@ class SignUpView extends StatelessWidget {
} }
}, },
builder: (context, state) { builder: (context, state) {
return SafeArea( return Scaffold(
child: Scaffold( body: SafeArea(
body: Stack( child: Stack(
children: [ children: [
Container( Container(
width: MediaQuery.sizeOf(context).width, width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height, height: MediaQuery.sizeOf(context).height,
padding: const EdgeInsets.symmetric(vertical: 24),
decoration: const BoxDecoration( decoration: const BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage( image: AssetImage(
@ -86,6 +86,7 @@ class SignUpView extends StatelessWidget {
), ),
Form( Form(
key: formKey, key: formKey,
autovalidateMode: AutovalidateMode.disabled,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -95,7 +96,7 @@ class SignUpView extends StatelessWidget {
fontColor: Colors.white, fontColor: Colors.white,
), ),
TextFormField( TextFormField(
// autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.disabled,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
keyboardType: TextInputType.name, keyboardType: TextInputType.name,
scrollPadding: EdgeInsets.zero, scrollPadding: EdgeInsets.zero,
@ -109,6 +110,7 @@ class SignUpView extends StatelessWidget {
onChanged: (value) { onChanged: (value) {
AuthCubit.get(context).fullName = value; AuthCubit.get(context).fullName = value;
}, },
onTap: () {},
decoration: defaultInputDecoration(context, hint: "Full Name"), decoration: defaultInputDecoration(context, hint: "Full Name"),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
@ -117,6 +119,7 @@ class SignUpView extends StatelessWidget {
fontColor: Colors.white, fontColor: Colors.white,
), ),
TextFormField( TextFormField(
autovalidateMode: AutovalidateMode.disabled,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
scrollPadding: EdgeInsets.zero, scrollPadding: EdgeInsets.zero,
@ -138,6 +141,7 @@ class SignUpView extends StatelessWidget {
fontColor: Colors.white, fontColor: Colors.white,
), ),
TextFormField( TextFormField(
autovalidateMode: AutovalidateMode.disabled,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
scrollPadding: EdgeInsets.zero, scrollPadding: EdgeInsets.zero,
@ -160,6 +164,7 @@ class SignUpView extends StatelessWidget {
fontColor: Colors.white, fontColor: Colors.white,
), ),
TextFormField( TextFormField(
autovalidateMode: AutovalidateMode.disabled,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
scrollPadding: EdgeInsets.zero, scrollPadding: EdgeInsets.zero,
@ -220,6 +225,5 @@ class SignUpView extends StatelessWidget {
); );
}, },
); );
;
} }
} }

View File

@ -1,9 +1,9 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/dashboard/view/widgets/carbon_emission.dart'; import 'package:syncrow_app/features/dashboard/view/widgets/carbon_emission.dart';
import 'package:syncrow_app/features/dashboard/view/widgets/consumption.dart'; import 'package:syncrow_app/features/dashboard/view/widgets/consumption.dart';
import 'package:syncrow_app/features/dashboard/view/widgets/live_monitor_tab.dart'; import 'package:syncrow_app/features/dashboard/view/widgets/live_monitor_tab.dart';
import 'package:syncrow_app/features/shared_widgets/create_unit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@ -14,37 +14,39 @@ class DashboardView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( return HomeCubit.getInstance().spaces?.isEmpty ?? true
child: Column( ? const CreateUnitWidget()
crossAxisAlignment: CrossAxisAlignment.stretch, : SingleChildScrollView(
children: [ child: Column(
const TitleMedium( crossAxisAlignment: CrossAxisAlignment.stretch,
text: StringsManager.dashboard,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
const LiveMonitorTab(),
const SizedBox(height: 10),
const EnergyUsage(),
Container(
padding: const EdgeInsets.only(top: 20),
constraints: const BoxConstraints(
minHeight: 220,
maxHeight: 240,
),
child: const Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Consumption(), const TitleMedium(
SizedBox(height: 20), text: StringsManager.dashboard,
CarbonEmission(), style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
const LiveMonitorTab(),
const SizedBox(height: 10),
const EnergyUsage(),
Container(
padding: const EdgeInsets.only(top: 20),
constraints: const BoxConstraints(
minHeight: 220,
maxHeight: 240,
),
child: const Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Consumption(),
SizedBox(height: 20),
CarbonEmission(),
],
),
),
], ],
), ),
), );
],
),
);
} }
} }

View File

@ -7,6 +7,7 @@ import 'package:syncrow_app/features/devices/view/widgets/devices_view_header.da
import 'package:syncrow_app/features/devices/view/widgets/room_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/room_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/rooms_slider.dart'; import 'package:syncrow_app/features/devices/view/widgets/rooms_slider.dart';
import 'package:syncrow_app/features/devices/view/widgets/wizard_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/wizard_page.dart';
import 'package:syncrow_app/features/shared_widgets/create_unit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
class DevicesViewBody extends StatelessWidget { class DevicesViewBody extends StatelessWidget {
@ -23,59 +24,56 @@ class DevicesViewBody extends StatelessWidget {
state is DevicesCategoriesLoading) { state is DevicesCategoriesLoading) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else { } else {
return Column( return HomeCubit.getInstance().spaces?.isEmpty ?? true
mainAxisAlignment: MainAxisAlignment.spaceBetween, ? const CreateUnitWidget()
children: [ : Column(
const DevicesViewHeader(), mainAxisAlignment: MainAxisAlignment.spaceBetween,
const RoomsSlider(),
const SizedBox(
height: 10,
),
Expanded(
child: PageView(
controller: HomeCubit.getInstance().devicesPageController,
onPageChanged: (index) {
HomeCubit.getInstance().devicesPageChanged(index);
},
children: [ children: [
const WizardPage(), const DevicesViewHeader(),
if (HomeCubit.getInstance().selectedSpace != null) const RoomsSlider(),
if (HomeCubit.getInstance().selectedSpace!.rooms != null) const SizedBox(
...HomeCubit.getInstance().selectedSpace!.rooms!.map( height: 10,
(room) {
return RoomPage(
room: room,
);
},
)
],
),
),
HomeCubit.getInstance().selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
),
child: SmoothPageIndicator(
controller:
HomeCubit.getInstance().devicesPageController,
count: HomeCubit.getInstance()
.selectedSpace!
.rooms!
.length +
1,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
), ),
], Expanded(
); child: PageView(
controller: HomeCubit.getInstance().devicesPageController,
onPageChanged: (index) {
HomeCubit.getInstance().devicesPageChanged(index);
},
children: [
const WizardPage(),
if (HomeCubit.getInstance().selectedSpace != null)
if (HomeCubit.getInstance().selectedSpace!.rooms != null)
...HomeCubit.getInstance().selectedSpace!.rooms!.map(
(room) {
return RoomPage(
room: room,
);
},
)
],
),
),
HomeCubit.getInstance().selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
),
child: SmoothPageIndicator(
controller: HomeCubit.getInstance().devicesPageController,
count: HomeCubit.getInstance().selectedSpace!.rooms!.length + 1,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
),
],
);
} }
}, },
); );

View File

@ -0,0 +1,42 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
List<String> rooms = [];
String unitName = '';
String locationName = '';
CreateUnitBloc() : super(InitialState()) {
on<CreateRoomEvent>(_createRoom);
on<RemoveRoomEvent>(_removeRoom);
}
void _createRoom(CreateRoomEvent event, Emitter<CreateUnitState> emit) async {
try {
emit(LoadingState());
if (rooms.contains(event.roomName)) {
emit(const ErrorState(message: 'This name is already exist'));
emit(CreateRoomState(roomList: rooms));
return;
}
rooms.add(event.roomName);
emit(CreateRoomState(roomList: rooms));
} catch (e) {
emit(const ErrorState(message: 'Something went wrong'));
return;
}
}
void _removeRoom(RemoveRoomEvent event, Emitter<CreateUnitState> emit) {
try {
emit(LoadingState());
rooms.removeWhere((element) => element == event.roomName);
emit(CreateRoomState(roomList: rooms));
} catch (e) {
emit(const ErrorState(message: 'Something went wrong'));
return;
}
}
}

View File

@ -0,0 +1,30 @@
import 'package:equatable/equatable.dart';
abstract class CreateUnitEvent extends Equatable {
const CreateUnitEvent();
@override
List<Object> get props => [];
}
class InitialEvent extends CreateUnitEvent {}
class LoadingEvent extends CreateUnitEvent {}
class CreateRoomEvent extends CreateUnitEvent {
final String roomName;
const CreateRoomEvent({required this.roomName});
@override
List<Object> get props => [roomName];
}
class RemoveRoomEvent extends CreateUnitEvent {
final String roomName;
const RemoveRoomEvent({required this.roomName});
@override
List<Object> get props => [roomName];
}

View File

@ -0,0 +1,30 @@
import 'package:equatable/equatable.dart';
abstract class CreateUnitState extends Equatable {
const CreateUnitState();
@override
List<Object> get props => [];
}
class InitialState extends CreateUnitState {}
class LoadingState extends CreateUnitState {}
class CreateRoomState extends CreateUnitState {
final List<String> roomList;
const CreateRoomState({required this.roomList});
@override
List<Object> get props => [roomList];
}
class ErrorState extends CreateUnitState {
final String message;
const ErrorState({required this.message});
@override
List<Object> get props => [message];
}

View File

@ -1,124 +1,247 @@
// ignore_for_file: unnecessary_const // ignore_for_file: unnecessary_const
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_bloc.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class CreateHomeView extends StatelessWidget { class CreateUnitView extends StatelessWidget {
const CreateHomeView({super.key}); const CreateUnitView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DefaultScaffold( String unitName = '';
actions: [ String location = '';
TextButton( TextEditingController textEditingController = TextEditingController();
onPressed: () {}, return BlocProvider(
child: const BodyLarge( create: (context) => CreateUnitBloc(),
text: 'Save', child: BlocConsumer<CreateUnitBloc, CreateUnitState>(listener: (context, state) {
fontWeight: FontWeight.bold, if (state is ErrorState) {
), CustomSnackBar.displaySnackBar(state.message);
), }
], }, builder: (context, state) {
title: 'Create Home', textEditingController.text = '';
child: Column( return DefaultScaffold(
children: [ actions: [
//Home Info TextButton(
DefaultContainer( onPressed: () {},
padding: const EdgeInsets.symmetric( child: const BodyLarge(
horizontal: 25, text: 'Save',
vertical: 5,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodyMedium(text: 'Home Name '),
Flexible(
child: TextField(
textAlign: TextAlign.end,
decoration: InputDecoration(
hintText: 'Enter Name',
hintStyle:
context.bodyMedium.copyWith(color: Colors.grey),
border: InputBorder.none,
),
),
),
],
),
//Divider
Container(
height: 1,
color: ColorsManager.greyColor,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodyMedium(text: 'Location '),
Flexible(
child: TextField(
textAlign: TextAlign.end,
decoration: InputDecoration(
hintText: 'Set',
hintStyle:
context.bodyMedium.copyWith(color: Colors.grey),
border: InputBorder.none,
),
),
),
],
),
],
),
),
//Rooms Info
const SizedBox(height: 10),
const Row(
children: [
SizedBox(
width: 25,
),
BodySmall(
text: 'Rooms',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
],
),
DefaultContainer(
padding: const EdgeInsets.symmetric(
horizontal: 25,
vertical: 5,
), ),
child: Column( ],
mainAxisSize: MainAxisSize.min, title: 'Create a Unit',
mainAxisAlignment: MainAxisAlignment.start, child: Container(
children: [ padding: const EdgeInsets.symmetric(vertical: 40),
TextButton( width: MediaQuery.sizeOf(context).width,
onPressed: () { height: MediaQuery.sizeOf(context).height,
//TODO add room child: SingleChildScrollView(
}, child: Column(
child: const Row( children: [
//Home Info
DefaultContainer(
padding: const EdgeInsets.symmetric(
horizontal: 25,
vertical: 5,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
BodyMedium( Row(
text: 'Add Room', mainAxisAlignment: MainAxisAlignment.spaceBetween,
fontColor: ColorsManager.primaryColor, children: [
const BodyMedium(text: 'Unit Name'),
Flexible(
child: TextField(
textAlign: TextAlign.end,
onChanged: (value) {
unitName = value;
},
decoration: InputDecoration(
hintText: 'Enter Name',
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
border: InputBorder.none,
),
),
),
],
),
const Divider(
color: ColorsManager.greyColor,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodyMedium(text: 'Location '),
Flexible(
child: TextField(
textAlign: TextAlign.end,
onChanged: (value) {
location = value;
},
decoration: InputDecoration(
hintText: 'Set',
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
border: InputBorder.none,
),
),
),
],
), ),
], ],
)) ),
], ),
//Rooms Info
const SizedBox(height: 10),
const Row(
children: [
SizedBox(
width: 25,
),
BodySmall(
text: 'Spaces',
fontWeight: FontWeight.bold,
),
],
),
const SizedBox(
height: 4,
),
DefaultContainer(
padding: const EdgeInsets.symmetric(
horizontal: 25,
vertical: 5,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (state is CreateRoomState)
if (state.roomList.isNotEmpty)
Column(
children: [
SizedBox(
height: (state.roomList.length) * 55,
child: ListView.separated(
physics:
const NeverScrollableScrollPhysics(), // Disable scrolling
separatorBuilder: (context, index) => const Divider(
color: ColorsManager.greyColor,
),
itemCount: state.roomList.length,
itemBuilder: (context, index) {
return Dismissible(
key: Key(state.roomList[index]),
background: Container(
padding: const EdgeInsets.only(right: 10),
alignment: AlignmentDirectional.centerEnd,
decoration: ShapeDecoration(
color: const Color(0xFFFF0000),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(index == 0 ? 20 : 0),
topRight: Radius.circular(index == 0 ? 20 : 0),
),
),
),
child: SvgPicture.asset(
Assets.assetsDeleteIcon,
width: 20,
height: 22,
),
),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
String removedUnit = state.roomList[index];
BlocProvider.of<CreateUnitBloc>(context)
.add(RemoveRoomEvent(roomName: removedUnit));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('$removedUnit removed')),
);
},
child: Container(
height: 50,
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text(
state.roomList[index],
style: const TextStyle(
color: Color(0xFF5D5D5D),
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
),
);
},
),
),
const Divider(
color: ColorsManager.greyColor,
),
],
),
Row(
children: [
TextButton(
onPressed: () {
if (textEditingController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please add the room name')),
);
return;
}
BlocProvider.of<CreateUnitBloc>(context)
.add(CreateRoomEvent(roomName: textEditingController.text));
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
BodyMedium(
text: 'Add Space',
fontColor: ColorsManager.primaryColor,
),
],
)),
Flexible(
child: TextField(
textAlign: TextAlign.end,
controller: textEditingController,
onChanged: (value) {
textEditingController.text = value;
},
decoration: InputDecoration(
hintText: 'Set',
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
border: InputBorder.none,
),
),
),
],
)
],
),
),
],
),
), ),
), ),
], );
), }),
); );
} }
} }

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/scene_cubit.dart'; import 'package:syncrow_app/features/scene/bloc/scene_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/create_unit.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
@ -17,100 +19,102 @@ class SceneView extends StatelessWidget {
create: (BuildContext context) => SceneCubit(), create: (BuildContext context) => SceneCubit(),
child: BlocBuilder<SceneCubit, SceneState>( child: BlocBuilder<SceneCubit, SceneState>(
builder: (context, state) { builder: (context, state) {
return Column( return HomeCubit.getInstance().spaces?.isEmpty ?? true
mainAxisAlignment: MainAxisAlignment.start, ? const CreateUnitWidget()
crossAxisAlignment: CrossAxisAlignment.stretch, : Column(
children: [ mainAxisAlignment: MainAxisAlignment.start,
const TitleMedium( crossAxisAlignment: CrossAxisAlignment.stretch,
text: StringsManager.routine, children: [
style: TextStyle( const TitleMedium(
fontSize: 32, text: StringsManager.routine,
fontWeight: FontWeight.bold, style: TextStyle(
), fontSize: 32,
), fontWeight: FontWeight.bold,
const SizedBox(height: 20),
const BodySmall(
text: StringsManager.tapToRunRoutine,
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: DefaultContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(
height: 50,
width: 50,
Assets.assetsIconsHot1,
fit: BoxFit.contain,
),
const Icon(
Icons.play_circle,
size: 40,
color: Colors.grey,
)
],
),
const BodyMedium(
text: StringsManager.summerMode,
fontWeight: FontWeight.bold,
fontSize: 16,
)
],
),
), ),
), ),
), const SizedBox(height: 20),
const SizedBox(width: 10), const BodySmall(
Expanded( text: StringsManager.tapToRunRoutine,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: DefaultContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(
height: 50,
width: 50,
Assets.assetsIconsWinter1,
fit: BoxFit.contain,
),
const Icon(
Icons.play_circle,
size: 40,
color: Colors.grey,
)
],
),
const BodyMedium(
text: StringsManager.winterMode,
fontWeight: FontWeight.bold,
fontSize: 16,
)
],
),
),
), ),
), Row(
], children: [
) Expanded(
], child: Padding(
); padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: DefaultContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(
height: 50,
width: 50,
Assets.assetsIconsHot1,
fit: BoxFit.contain,
),
const Icon(
Icons.play_circle,
size: 40,
color: Colors.grey,
)
],
),
const BodyMedium(
text: StringsManager.summerMode,
fontWeight: FontWeight.bold,
fontSize: 16,
)
],
),
),
),
),
const SizedBox(width: 10),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: DefaultContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(
height: 50,
width: 50,
Assets.assetsIconsWinter1,
fit: BoxFit.contain,
),
const Icon(
Icons.play_circle,
size: 40,
color: Colors.grey,
)
],
),
const BodyMedium(
text: StringsManager.winterMode,
fontWeight: FontWeight.bold,
fontSize: 16,
)
],
),
),
),
),
],
)
],
);
}, },
), ),
); );

View File

@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
class CreateUnitWidget extends StatelessWidget {
const CreateUnitWidget({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.noUnitsIconDashboard,
width: 100,
height: 100,
),
const SizedBox(
height: 50,
),
Flexible(
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, Routes.createUnit);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 34, vertical: 14),
decoration: ShapeDecoration(
color: const Color(0x99023DFE),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: const TitleMedium(
text: 'Create a unit',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.white),
),
),
),
),
],
),
);
}
}

View File

@ -221,6 +221,8 @@ class Assets {
/// assets/icons/dashboard.svg /// assets/icons/dashboard.svg
static const String assetsIconsDashboard = "assets/icons/dashboard.svg"; static const String assetsIconsDashboard = "assets/icons/dashboard.svg";
static const String noUnitsIconDashboard = "assets/icons/no_units_ic.svg";
/// Assets for assetsIconsDashboardFill /// Assets for assetsIconsDashboardFill
/// assets/icons/dashboard-fill.svg /// assets/icons/dashboard-fill.svg
static const String assetsIconsDashboardFill = "assets/icons/dashboard-fill.svg"; static const String assetsIconsDashboardFill = "assets/icons/dashboard-fill.svg";
@ -643,6 +645,8 @@ class Assets {
/// assets/icons/Winter_mode.svg /// assets/icons/Winter_mode.svg
static const String assetsIconsWinterMode = "assets/icons/Winter_mode.svg"; static const String assetsIconsWinterMode = "assets/icons/Winter_mode.svg";
static const String assetsDeleteIcon = "assets/icons/delete_room_ic.svg";
/// Assets for assetsImagesAutomation /// Assets for assetsImagesAutomation
/// assets/images/automation.jpg /// assets/images/automation.jpg
static const String assetsImagesAutomation = "assets/images/automation.jpg"; static const String assetsImagesAutomation = "assets/images/automation.jpg";

View File

@ -6,10 +6,10 @@ import 'package:syncrow_app/features/auth/view/sign_up_view.dart';
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart'; import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
import 'package:syncrow_app/features/layout/view/layout_view.dart'; import 'package:syncrow_app/features/layout/view/layout_view.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart'; import 'package:syncrow_app/features/menu/view/menu_view.dart';
import 'package:syncrow_app/features/menu/view/widgets/home%20management/create_home_view.dart';
import 'package:syncrow_app/features/menu/view/widgets/profile/profile_view.dart'; import 'package:syncrow_app/features/menu/view/widgets/profile/profile_view.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart'; import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/features/splash/view/splash_view.dart'; import 'package:syncrow_app/features/splash/view/splash_view.dart';
import 'routing_constants.dart'; import 'routing_constants.dart';
class Router { class Router {
@ -49,6 +49,8 @@ class Router {
case Routes.menuRoute: case Routes.menuRoute:
return MaterialPageRoute(builder: (_) => const MenuView(), settings: settings); return MaterialPageRoute(builder: (_) => const MenuView(), settings: settings);
case Routes.createUnit:
return MaterialPageRoute(builder: (_) => const CreateUnitView(), settings: settings);
default: default:
return MaterialPageRoute( return MaterialPageRoute(
builder: (_) => Scaffold( builder: (_) => Scaffold(

View File

@ -16,4 +16,5 @@ class Routes {
static const String policyRoute = '/policy'; static const String policyRoute = '/policy';
static const String termsRoute = '/terms'; static const String termsRoute = '/terms';
static const String otpRoute = '/otp'; static const String otpRoute = '/otp';
static const String createUnit = '/create-unit';
} }

View File

@ -1,17 +1,16 @@
import 'package:syncrow_app/features/auth/model/login_with_email_model.dart'; import 'package:syncrow_app/features/auth/model/login_with_email_model.dart';
import 'package:syncrow_app/features/auth/model/signup_model.dart'; import 'package:syncrow_app/features/auth/model/signup_model.dart';
import 'package:syncrow_app/features/auth/model/token.dart'; import 'package:syncrow_app/features/auth/model/token.dart';
import 'package:syncrow_app/features/auth/model/verify_code.dart';
import 'package:syncrow_app/services/api/api_links_endpoints.dart'; import 'package:syncrow_app/services/api/api_links_endpoints.dart';
import 'package:syncrow_app/services/api/http_service.dart'; import 'package:syncrow_app/services/api/http_service.dart';
class AuthenticationAPI { class AuthenticationAPI {
static Future<Token> verifyPassCode(VerifyPassCode data) async { static Future<Map<String, dynamic>> verifyPassCode({required Map<String, dynamic> body}) async {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.verifyOtp, path: ApiEndpoints.verifyOtp,
body: data.toJson(), body: body,
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => Token.fromJson(json)); expectedResponseModel: (json) => json);
return response; return response;
} }

View File

@ -251,17 +251,17 @@ List<Map<String, Object>> menuSections = [
'color': ColorsManager.primaryColor, 'color': ColorsManager.primaryColor,
'buttons': [ 'buttons': [
{ {
'title': 'Create a Home', 'title': 'Create a Unit',
'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsCreateHome, 'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsCreateHome,
'page': const CreateHomeView() 'page': const CreateUnitView()
}, },
{ {
'title': 'Join a Home', 'title': 'Join a Unit',
'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsJoinAHome, 'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsJoinAHome,
'page': const JoinHomeView() 'page': const JoinHomeView()
}, },
{ {
'title': 'Manage Your Home', 'title': 'Manage Your Units',
'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsManageYourHome, 'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsManageYourHome,
'page': const ManageHomeView() 'page': const ManageHomeView()
}, },