Merged Auth branch & Curtains branch

This commit is contained in:
Mohammad Salameh
2024-03-10 15:06:04 +03:00
60 changed files with 1715 additions and 595 deletions

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24 12C24 17.9897 19.6116 22.9542 13.875 23.8542V15.4688H16.6711L17.2031 12H13.875V9.74906C13.875 8.79984 14.34 7.875 15.8306 7.875H17.3438V4.92188C17.3438 4.92188 15.9703 4.6875 14.6573 4.6875C11.9166 4.6875 10.125 6.34875 10.125 9.35625V12H7.07812V15.4688H10.125V23.8542C4.38844 22.9542 0 17.9897 0 12C0 5.37281 5.37281 0 12 0C18.6272 0 24 5.37281 24 12Z" fill="#1877F2"/>
<path d="M16.6711 15.4688L17.2031 12H13.875V9.74902C13.875 8.80003 14.3399 7.875 15.8306 7.875H17.3438V4.92188C17.3438 4.92188 15.9705 4.6875 14.6576 4.6875C11.9165 4.6875 10.125 6.34875 10.125 9.35625V12H7.07812V15.4688H10.125V23.8542C10.736 23.95 11.3621 24 12 24C12.6379 24 13.264 23.95 13.875 23.8542V15.4688H16.6711Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 825 B

8
assets/icons/Google.svg Normal file
View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.0938 9.91351L13.3045 9.91304C12.8722 9.91304 12.5218 10.2634 12.5218 10.6957V13.8229C12.5218 14.2551 12.8722 14.6055 13.3044 14.6055H18.8172C18.2135 16.1721 17.0868 17.4841 15.6494 18.3177L18 22.3869C21.7707 20.2061 24 16.3798 24 12.0965C24 11.4866 23.955 11.0506 23.8651 10.5597C23.7968 10.1867 23.473 9.91351 23.0938 9.91351Z" fill="#167EE6"/>
<path d="M11.9999 19.3043C9.30209 19.3043 6.94691 17.8303 5.68199 15.649L1.61298 17.9944C3.68367 21.5832 7.56275 23.9999 11.9999 23.9999C14.1767 23.9999 16.2306 23.4138 17.9999 22.3925V22.3869L15.6493 18.3177C14.5741 18.9413 13.3298 19.3043 11.9999 19.3043Z" fill="#12B347"/>
<path d="M17.9999 22.3925V22.3869L15.6493 18.3177C14.5741 18.9413 13.3299 19.3043 11.9999 19.3043V23.9999C14.1767 23.9999 16.2307 23.4138 17.9999 22.3925Z" fill="#0F993E"/>
<path d="M4.69564 12C4.69564 10.6702 5.05854 9.42607 5.68203 8.3509L1.61301 6.00557C0.586029 7.76933 0 9.81767 0 12C0 14.1823 0.586029 16.2306 1.61301 17.9944L5.68203 15.649C5.05854 14.5739 4.69564 13.3298 4.69564 12Z" fill="#FFD500"/>
<path d="M11.9999 4.69564C13.7592 4.69564 15.3751 5.32076 16.6373 6.36059C16.9487 6.61709 17.4013 6.59857 17.6865 6.31334L19.9023 4.09756C20.2259 3.77394 20.2029 3.24421 19.8572 2.9443C17.7424 1.10967 14.9909 0 11.9999 0C7.56275 0 3.68367 2.41673 1.61298 6.00556L5.68199 8.35089C6.94691 6.16967 9.30209 4.69564 11.9999 4.69564Z" fill="#FF4B26"/>
<path d="M16.6374 6.36059C16.9487 6.61709 17.4014 6.59857 17.6866 6.31334L19.9023 4.09756C20.2259 3.77394 20.2028 3.24421 19.8572 2.9443C17.7424 1.10962 14.9909 0 11.9999 0V4.69564C13.7592 4.69564 15.3752 5.32076 16.6374 6.36059Z" fill="#D93F21"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/icons/filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
assets/icons/qr_scan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/icons/settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

38
assets/images/Logo.svg Normal file
View File

@ -0,0 +1,38 @@
<svg width="244" height="170" viewBox="0 0 244 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Logo">
<g id="Group">
<path id="Vector" opacity="0.994" fill-rule="evenodd" clip-rule="evenodd" d="M88.4865 0C93.3554 0 98.2243 0 103.093 0C103.297 5.87195 105.878 10.3448 110.836 13.4187C116.54 16.4006 122.084 16.1366 127.467 12.6268C131.646 9.47548 133.816 5.26652 133.978 0C138.847 0 143.716 0 148.585 0C148.416 9.09403 144.97 16.6613 138.246 22.7019C138.187 22.7606 138.187 22.8192 138.246 22.8778C139.302 23.8165 140.299 24.8137 141.238 25.8696C147.311 19.0956 154.922 15.6346 164.071 15.4865C164.071 20.3554 164.071 25.2243 164.071 30.0932C158.685 30.2268 154.418 32.456 151.269 36.7805C148.468 41.0876 147.852 45.6926 149.421 50.5952C152.092 57.1491 156.975 60.6102 164.071 60.9783C164.071 65.8471 164.071 70.716 164.071 75.5849C154.944 75.4101 147.347 71.9491 141.282 65.2019C140.285 66.2714 139.244 67.2979 138.158 68.2816C138.099 68.3403 138.099 68.3989 138.158 68.4576C144.913 74.52 148.389 82.1166 148.585 91.2474C143.716 91.2474 138.847 91.2474 133.978 91.2474C133.669 84.8283 130.677 80.1501 125.003 77.2127C119.565 74.9302 114.403 75.4289 109.517 78.7086C105.388 81.8475 103.247 86.0271 103.093 91.2474C98.2243 91.2474 93.3554 91.2474 88.4865 91.2474C88.6521 82.1037 92.1278 74.5071 98.9136 68.4576C98.9722 68.3989 98.9722 68.3403 98.9136 68.2816C97.8273 67.2979 96.7861 66.2714 95.7899 65.2019C89.7121 71.9206 82.1155 75.3816 73 75.5849C73 70.716 73 65.8471 73 60.9783C79.3108 60.692 83.9597 57.7883 86.9467 52.2671C89.4059 46.7188 88.9366 41.4393 85.5388 36.4286C82.3891 32.3238 78.2094 30.212 73 30.0932C73 25.2243 73 20.3554 73 15.4865C82.1422 15.6518 89.7534 19.1129 95.8339 25.8696C96.2738 25.3709 96.7138 24.8724 97.1537 24.3737C97.7412 23.8595 98.3131 23.3315 98.8696 22.7899C92.1012 16.7305 88.6403 9.1338 88.4865 0ZM117.348 30.0932C123.083 29.8955 127.674 32.066 131.119 36.6046C134.686 42.1095 134.891 47.741 131.734 53.499C128.64 58.2444 124.241 60.7375 118.536 60.9783C112.831 60.7375 108.431 58.2444 105.337 53.499C102.381 48.238 102.351 42.9585 105.249 37.6605C108.071 33.2119 112.104 30.6895 117.348 30.0932Z" fill="#FEFFFE"/>
</g>
<g id="Group 172">
<g id="Group_2">
<path id="Vector_2" opacity="0.993" fill-rule="evenodd" clip-rule="evenodd" d="M26.8817 122.405C30.0418 122.319 33.2083 122.319 36.3806 122.405C39.2277 130.121 42.0934 137.827 44.9779 145.524C47.4296 137.803 49.8555 130.075 52.255 122.34C55.3462 122.319 58.4373 122.34 61.5285 122.405C57.3297 134.326 53.1115 146.24 48.874 158.146C47.6562 161.324 45.8209 164.083 43.3679 166.421C40.9735 168.444 38.2044 169.603 35.0604 169.899C33.9888 169.98 32.9153 170.013 31.8405 169.996C31.8405 167.312 31.8405 164.629 31.8405 161.946C33.8587 162.042 35.705 161.538 37.3788 160.432C38.1503 159.768 38.8052 159.006 39.343 158.146C39.8144 157.332 40.2117 156.484 40.5343 155.602C36.0071 144.521 31.4566 133.455 26.8817 122.405Z" fill="#FEFFFE"/>
</g>
<g id="Group_3">
<path id="Vector_3" opacity="0.994" fill-rule="evenodd" clip-rule="evenodd" d="M62.8802 122.34C65.757 122.34 68.633 122.34 71.5097 122.34C71.4988 123.886 71.5097 125.431 71.5419 126.977C73.338 124.484 75.7743 123.035 78.8512 122.63C81.5283 122.202 84.1262 122.481 86.6435 123.467C90.3517 125.223 92.6591 128.11 93.5665 132.129C93.7088 132.832 93.8163 133.54 93.8885 134.254C93.9831 142.088 94.0153 149.924 93.9851 157.76C91.1083 157.76 88.2323 157.76 85.3556 157.76C85.3665 150.762 85.3556 143.764 85.3234 136.766C85.1437 133.216 83.3083 131.145 79.8172 130.551C74.7001 130.271 71.9419 132.686 71.5419 137.796C71.5097 144.45 71.4988 151.105 71.5097 157.76C68.633 157.76 65.757 157.76 62.8802 157.76C62.8802 145.953 62.8802 134.147 62.8802 122.34Z" fill="#FEFFFE"/>
</g>
<g id="Group_4">
<path id="Vector_4" opacity="0.993" fill-rule="evenodd" clip-rule="evenodd" d="M131.724 122.34C134.6 122.34 137.476 122.34 140.353 122.34C140.342 124.53 140.353 126.719 140.385 128.909C141.3 126.534 142.921 124.828 145.247 123.789C146.907 123.052 148.646 122.697 150.464 122.727C150.464 125.925 150.464 129.124 150.464 132.322C147.747 132.019 145.278 132.652 143.058 134.222C141.617 135.418 140.769 136.952 140.514 138.826C140.453 139.232 140.41 139.64 140.385 140.05C140.353 145.953 140.342 151.856 140.353 157.76C137.476 157.76 134.6 157.76 131.724 157.76C131.724 145.953 131.724 134.147 131.724 122.34Z" fill="#FEFFFE"/>
</g>
<g id="Group_5">
<path id="Vector_5" opacity="0.993" fill-rule="evenodd" clip-rule="evenodd" d="M184.982 122.34C188.03 122.319 191.078 122.34 194.126 122.405C196.005 129.832 197.883 137.259 199.761 144.687C201.769 137.26 203.775 129.832 205.783 122.405C208.509 122.329 211.235 122.319 213.961 122.372C215.983 129.847 217.99 137.328 219.983 144.815C221.85 137.325 223.707 129.833 225.553 122.34C228.322 122.34 231.092 122.34 233.861 122.34C230.654 134.15 227.434 145.957 224.201 157.76C221.367 157.76 218.534 157.76 215.7 157.76C213.648 150.736 211.577 143.716 209.486 136.701C207.384 143.693 205.302 150.691 203.239 157.695C200.405 157.781 197.572 157.781 194.738 157.695C191.479 145.911 188.227 134.126 184.982 122.34Z" fill="#FEFFFE"/>
</g>
<g id="Group_6">
<path id="Vector_6" opacity="0.992" fill-rule="evenodd" clip-rule="evenodd" d="M13.1654 122.469C16.8452 122.181 20.2152 123.051 23.2761 125.077C24.9067 126.278 26.2159 127.759 27.2044 129.521C24.7946 130.903 22.3584 132.244 19.8951 133.546C18.3444 130.673 15.9726 129.632 12.779 130.422C11.974 130.67 11.3622 131.153 10.9436 131.871C10.4948 133.121 10.849 134.076 12.0062 134.737C12.6779 135.073 13.365 135.373 14.067 135.639C15.7729 136.172 17.4898 136.666 19.2189 137.12C20.5423 137.525 21.8303 138.019 23.0829 138.601C26.7298 140.796 28.3076 144.027 27.8162 148.293C27.5399 151.026 26.3054 153.205 24.1133 154.829C21.7691 156.434 19.1719 157.335 16.321 157.534C13.074 157.842 9.94029 157.391 6.91868 156.182C3.97435 154.804 1.82728 152.636 0.47876 149.678C2.95813 148.255 5.44844 146.849 7.94907 145.459C9.13079 148.419 11.3313 149.857 14.55 149.774C15.6068 149.789 16.6262 149.607 17.6089 149.227C19.0135 148.426 19.3677 147.299 18.6715 145.846C17.9754 145.138 17.1485 144.633 16.1922 144.332C14.0522 143.647 11.9058 142.982 9.75224 142.336C7.99865 141.824 6.40992 141.008 4.9867 139.889C2.88214 138.094 1.85175 135.808 1.89554 133.03C1.8949 129.241 3.50488 126.375 6.72548 124.433C8.72572 123.279 10.8728 122.624 13.1654 122.469Z" fill="#FEFFFE"/>
</g>
<g id="Group_7">
<path id="Vector_7" opacity="0.992" fill-rule="evenodd" clip-rule="evenodd" d="M113.049 122.469C117.971 122.132 122.308 123.538 126.057 126.687C127.445 127.924 128.562 129.362 129.406 131.002C129.389 131.083 129.346 131.147 129.277 131.195C126.862 132.585 124.458 133.991 122.064 135.413C120.148 132.179 117.293 130.709 113.499 131.002C110.157 131.389 107.763 133.096 106.319 136.122C105.46 138.382 105.353 140.679 105.997 143.012C107.461 146.891 110.274 148.909 114.433 149.066C117.188 149.062 119.463 148.031 121.259 145.975C121.554 145.535 121.834 145.084 122.097 144.622C124.565 146.039 127.034 147.456 129.503 148.873C129.546 148.937 129.546 149.001 129.503 149.066C126.885 153.44 123.075 156.177 118.072 157.277C114.056 158.017 110.192 157.545 106.48 155.86C101.019 152.94 97.8748 148.399 97.0453 142.24C96.3324 134.942 98.9618 129.221 104.934 125.077C107.431 123.552 110.136 122.682 113.049 122.469Z" fill="#FEFFFE"/>
</g>
<g id="Group_8">
<path id="Vector_8" opacity="0.993" fill-rule="evenodd" clip-rule="evenodd" d="M166.951 122.469C174.297 122.122 179.911 125.042 183.791 131.227C186.088 135.587 186.625 140.16 185.401 144.944C183.958 149.649 181.093 153.202 176.804 155.602C173.09 157.457 169.183 158.036 165.083 157.341C159.487 156.192 155.333 153.112 152.622 148.1C150.859 144.336 150.365 140.407 151.141 136.315C152.367 130.993 155.362 127.01 160.124 124.369C162.284 123.292 164.559 122.659 166.951 122.469ZM167.401 130.905C171.155 130.63 174.064 132.047 176.127 135.156C177.574 137.924 177.767 140.779 176.707 143.721C175.069 147.255 172.289 149.079 168.367 149.195C164.115 149.018 161.271 146.936 159.834 142.948C159.204 140.608 159.333 138.311 160.221 136.057C161.692 133.05 164.086 131.333 167.401 130.905Z" fill="#FEFFFE"/>
</g>
<g id="Group 173">
<g id="Group_9">
<path id="Vector_9" opacity="0.924" fill-rule="evenodd" clip-rule="evenodd" d="M236.887 122.34C237.767 122.34 238.647 122.34 239.527 122.34C239.527 122.576 239.527 122.812 239.527 123.048C239.226 123.048 238.926 123.048 238.626 123.048C238.626 123.972 238.626 124.895 238.626 125.818C238.347 125.818 238.067 125.818 237.788 125.818C237.788 124.895 237.788 123.972 237.788 123.048C237.488 123.048 237.188 123.048 236.887 123.048C236.887 122.812 236.887 122.576 236.887 122.34Z" fill="#FEFFFE"/>
</g>
<g id="Group_10">
<path id="Vector_10" opacity="0.932" fill-rule="evenodd" clip-rule="evenodd" d="M243.391 122.34C243.391 123.499 243.391 124.658 243.391 125.818C243.112 125.818 242.833 125.818 242.554 125.818C242.565 125.173 242.554 124.529 242.522 123.886C242.307 124.272 242.092 124.658 241.878 125.045C241.755 125.225 241.594 125.268 241.395 125.174C241.164 124.734 240.917 124.304 240.654 123.886C240.622 124.529 240.611 125.173 240.622 125.818C240.343 125.818 240.064 125.818 239.785 125.818C239.785 124.658 239.785 123.499 239.785 122.34C240.086 122.329 240.387 122.34 240.686 122.372C240.974 122.885 241.274 123.389 241.588 123.886C241.889 123.392 242.189 122.898 242.489 122.404C242.787 122.34 243.088 122.319 243.391 122.34Z" fill="#FEFFFE"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
assets/images/Vector.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

BIN
assets/images/blind.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
assets/images/curtain.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

@ -1,6 +1,7 @@
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:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.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/devices/view/widgets/devices_view_body.dart'; import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart'; import 'package:syncrow_app/features/menu/view/menu_view.dart';
@ -17,13 +18,117 @@ class NavCubit extends Cubit<NavState> {
static NavCubit of(context) => BlocProvider.of<NavCubit>(context); static NavCubit of(context) => BlocProvider.of<NavCubit>(context);
static int pageIndex = 0; static int pageIndex = 0;
int get getPageIndex => pageIndex; static Map<String, List<Widget>> appBarActions = {
'Dashboard': [
IconButton(
icon: const Icon(
Icons.add,
size: 25,
),
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
),
onPressed: () {},
),
],
'Devices': [
IconButton(
icon: Image.asset(
Assets.iconsFilter,
height: 20,
width: 20,
),
onPressed: () {},
),
IconButton(
icon: const Icon(
Icons.add,
size: 25,
),
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
),
onPressed: () {},
),
IconButton(
icon: const Icon(
Icons.more_vert,
size: 25,
),
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
),
onPressed: () {},
),
],
'Routine': [
IconButton(
icon: Image.asset(
Assets.iconsFilter,
height: 20,
width: 20,
),
onPressed: () {},
),
IconButton(
icon: const Icon(
Icons.add,
size: 25,
),
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
),
onPressed: () {},
),
IconButton(
icon: const Icon(
Icons.more_vert,
size: 25,
),
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
),
onPressed: () {},
),
],
'Menu': [
IconButton(
icon: Image.asset(
Assets.iconsQrScan,
height: 20,
width: 20,
),
onPressed: () {},
),
IconButton(
icon: Image.asset(
Assets.iconsSettings,
height: 20,
width: 20,
),
onPressed: () {},
),
],
};
Map<String, List<Widget>> appBarActions = { static Map<String, Widget?> appBarLeading = {
'Home': [], 'Dashboard': const AppBarHomeDropdown(),
'Scene': [], 'Devices': const AppBarHomeDropdown(),
'Smart': [], 'Routine': const AppBarHomeDropdown(),
'Profile': [], 'Menu': Padding(
padding: const EdgeInsets.only(left: 15),
child: Image.asset(
Assets.imagesLogoHorizontal,
height: 15,
width: 100,
fit: BoxFit.scaleDown,
),
),
}; };
var bottomNavItems = [ var bottomNavItems = [

View File

@ -0,0 +1,270 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/curtain_model.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/light_model.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/lights_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_view.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
part 'spaces_state.dart';
class SpacesCubit extends Cubit<SpacesState> {
SpacesCubit() : super(SpacesInitial());
static SpacesCubit get(context) => BlocProvider.of(context);
static List<SpaceModel> spaces = [
SpaceModel(
id: '0',
name: 'Home',
rooms: [
RoomModel(id: '0', name: 'Living Room', categories: [
DevicesCategoryModel(
devices: [
ACModel(
name: "Living Room AC",
id: '0',
status: false,
temperature: 20,
fanSpeed: 0,
tempMode: 0,
coolTo: 20,
type: DeviceType.AC,
image: '',
timer: null,
bounds: Bounds(
min: 20,
max: 30,
),
),
],
icon: Assets.iconsAC,
name: 'ACs',
type: DeviceType.AC,
page: const ACsView(),
),
DevicesCategoryModel(
devices: [
LightModel(
name: "Living Room Light",
id: '0',
status: false,
color: 0,
brightness: 20,
lightingMode: 1,
timer: null,
type: DeviceType.Lights,
image: '',
recentColors: [
0xFF83D9FF,
0xFFFC3E81,
0xFFC0FF66,
0xFFFDC242,
],
),
],
icon: Assets.iconsLight,
name: 'Lights',
type: DeviceType.Lights,
page: const LightsView(),
),
DevicesCategoryModel(
devices: [],
icon: Assets.iconsDoorLock,
name: 'Doors',
type: DeviceType.Door,
page: const DoorView(),
),
DevicesCategoryModel(
devices: [
CurtainModel(
openPercentage: 10,
id: "1",
name: "Living Room Curtain",
status: false,
type: DeviceType.Curtain,
image: '',
timer: null,
),
],
icon: Assets.iconsCurtain,
name: 'Curtains',
type: DeviceType.Curtain,
page: const CurtainView(),
),
DevicesCategoryModel(
devices: [],
icon: Assets.iconsGateway,
name: 'Gateway',
type: DeviceType.Gateway,
page: const GateWayView(),
),
]),
RoomModel(id: '1', name: 'Bedroom', categories: [
DevicesCategoryModel(
devices: [
ACModel(
name: "Living Room AC",
id: '0',
status: false,
temperature: 20,
fanSpeed: 0,
tempMode: 0,
coolTo: 20,
type: DeviceType.AC,
image: '',
timer: null,
bounds: Bounds(
min: 20,
max: 30,
),
),
],
icon: Assets.iconsAC,
name: 'ACs',
type: DeviceType.AC,
page: const ACsView(),
),
DevicesCategoryModel(
devices: [
LightModel(
name: "Living Room Light",
id: '0',
status: false,
color: 0,
brightness: 20,
lightingMode: 1,
timer: null,
type: DeviceType.Lights,
image: '',
recentColors: [
0xFF83D9FF,
0xFFFC3E81,
0xFFC0FF66,
0xFFFDC242,
],
),
],
icon: Assets.iconsLight,
name: 'Lights',
type: DeviceType.Lights,
page: const LightsView(),
),
DevicesCategoryModel(
devices: [],
icon: Assets.iconsDoorLock,
name: 'Doors',
type: DeviceType.Door,
page: const DoorView(),
),
DevicesCategoryModel(
devices: [
CurtainModel(
openPercentage: 10,
id: "1",
name: "Living Room Curtain",
status: false,
type: DeviceType.Curtain,
image: '',
timer: null,
),
],
icon: Assets.iconsCurtain,
name: 'Curtains',
type: DeviceType.Curtain,
page: const CurtainView(),
),
DevicesCategoryModel(
devices: [],
icon: Assets.iconsGateway,
name: 'Gateway',
type: DeviceType.Gateway,
page: const GateWayView(),
),
]),
],
),
SpaceModel(
id: '1',
name: 'Office',
rooms: [],
),
SpaceModel(
id: '2',
name: 'Parent\'s House',
rooms: [],
),
];
SpaceModel selectedSpace = spaces.first;
RoomModel? selectedRoom;
PageController devicesPageController = PageController();
PageController roomsPageController = PageController();
var duration = const Duration(milliseconds: 300);
selectSpace(SpaceModel space) {
selectedSpace = space;
emit(SpacesSelected(space));
}
roomSliderPageChanged(int index) {
devicesPageController.animateToPage(
index,
duration: duration,
curve: Curves.linear,
);
if (index == 0) {
unselectRoom();
} else {
selectedRoom = selectedSpace.rooms[index - 1];
}
emit(RoomSelected(selectedRoom!));
}
devicesPageChanged(int index) {
roomsPageController.animateToPage(
index,
duration: const Duration(milliseconds: 300),
curve: Curves.linear,
);
if (index == 0) {
unselectRoom();
} else {
selectedRoom = selectedSpace.rooms[index - 1];
}
emit(RoomSelected(selectedRoom!));
}
unselectRoom() {
selectedRoom = null;
devicesPageController.animateToPage(
0,
duration: duration,
curve: Curves.linear,
);
roomsPageController.animateToPage(
0,
duration: duration,
curve: Curves.linear,
);
emit(RoomUnSelected());
}
//TODO implement the methods to fetch the spaces from the API
}

View File

@ -0,0 +1,27 @@
part of 'spaces_cubit.dart';
abstract class SpacesState {}
class SpacesInitial extends SpacesState {}
class SpacesLoading extends SpacesState {}
class SpacesLoaded extends SpacesState {
final List<SpaceModel> spaces;
SpacesLoaded(this.spaces);
}
class SpacesSelected extends SpacesState {
final SpaceModel space;
SpacesSelected(this.space);
}
class RoomSelected extends SpacesState {
final RoomModel room;
RoomSelected(this.room);
}
class RoomUnSelected extends SpacesState {}

View File

@ -0,0 +1,29 @@
import 'package:syncrow_app/features/devices/model/room_model.dart';
class SpaceModel {
final String id;
final String name;
final List<RoomModel> rooms;
SpaceModel({
required this.id,
required this.name,
required this.rooms,
});
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'rooms': rooms,
};
}
factory SpaceModel.fromJson(Map<String, dynamic> json) {
return SpaceModel(
id: json['id'],
name: json['name'],
rooms: json['rooms'],
);
}
}

View File

@ -19,14 +19,14 @@ class AppLayout extends StatelessWidget {
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light, statusBarIconBrightness: Brightness.light,
), ),
child: const SafeArea( child: SafeArea(
child: Scaffold( child: Scaffold(
backgroundColor: ColorsManager.backgroundColor, backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
extendBody: true, extendBody: true,
appBar: DefaultAppBar(), appBar: DefaultAppBar(context),
body: AppBody(), body: const AppBody(),
bottomNavigationBar: DefaultNavBar(), bottomNavigationBar: const DefaultNavBar(),
), ),
), ),
); );

View File

@ -1,9 +1,12 @@
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:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/spaces_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import '../../../../generated/assets.dart'; import '../../../../generated/assets.dart';
import '../../../shared_widgets/text_widgets/body_large.dart';
class AppBarHomeDropdown extends StatelessWidget { class AppBarHomeDropdown extends StatelessWidget {
const AppBarHomeDropdown({ const AppBarHomeDropdown({
@ -12,13 +15,28 @@ class AppBarHomeDropdown extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return TextButton( return BlocBuilder<SpacesCubit, SpacesState>(
onPressed: () {}, builder: (context, state) {
return Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: DropdownButton(
icon: const Icon(
Icons.expand_more,
color: Colors.black,
size: 25,
),
underline: const SizedBox.shrink(),
padding: const EdgeInsets.all(0),
borderRadius: BorderRadius.circular(20),
value: SpacesCubit.get(context).selectedSpace,
items: SpacesCubit.spaces.map((space) {
return DropdownMenuItem(
value: space,
child: SizedBox( child: SizedBox(
width: 150, width: 100,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
SvgPicture.asset( SvgPicture.asset(
Assets.iconsHome, Assets.iconsHome,
@ -30,15 +48,27 @@ class AppBarHomeDropdown extends StatelessWidget {
), ),
), ),
const SizedBox(width: 5), const SizedBox(width: 5),
const BodyLarge(text: 'Home'), Expanded(
const SizedBox(width: 5), child: BodyMedium(
const Icon( text: space.name,
Icons.expand_more, style: context.bodyMedium.copyWith(
color: Colors.black, fontSize: 15,
) color: ColorsManager.textPrimaryColor,
overflow: TextOverflow.ellipsis,
),
),
),
], ],
), ),
), ),
); );
}).toList(),
onChanged: (value) {
SpacesCubit.get(context).selectSpace(value!);
},
),
);
},
);
} }
} }

View File

@ -25,11 +25,7 @@ class AppBody extends StatelessWidget {
opacity: 0.4, opacity: 0.4,
), ),
), ),
child: Padding(
padding:
const EdgeInsets.only(top: 60, right: 15, left: 15, bottom: 80),
child: NavCubit.of(context).currentPage, child: NavCubit.of(context).currentPage,
),
); );
}, },
); );

View File

@ -1,10 +1,12 @@
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/nav_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/nav_cubit.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
const DefaultAppBar({super.key}); const DefaultAppBar(this.context, {super.key});
final BuildContext context;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -17,16 +19,10 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
child: AppBar( child: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
leadingWidth: 150, leadingWidth: 150,
leading: const AppBarHomeDropdown(), leading: NavCubit.appBarLeading[
actions: <Widget>[ NavCubit().bottomNavItems[NavCubit.pageIndex].label],
IconButton( actions: NavCubit.appBarActions[
icon: const Icon( NavCubit().bottomNavItems[NavCubit.pageIndex].label],
Icons.add,
size: 35,
),
onPressed: () {},
),
],
), ),
); );
}, },
@ -34,5 +30,5 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
} }
@override @override
Size get preferredSize => const Size.fromHeight(100); Size get preferredSize => Size.fromHeight(Constants.appBarHeight);
} }

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/nav_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/nav_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.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';
class DefaultNavBar extends StatelessWidget { class DefaultNavBar extends StatelessWidget {
const DefaultNavBar({ const DefaultNavBar({
@ -14,8 +15,8 @@ class DefaultNavBar extends StatelessWidget {
return BlocBuilder<NavCubit, NavState>( return BlocBuilder<NavCubit, NavState>(
builder: (context, state) { builder: (context, state) {
var cubit = NavCubit.of(context); var cubit = NavCubit.of(context);
return Padding( return SizedBox(
padding: const EdgeInsets.only(bottom: 27), height: Constants.bottomNavBarHeight,
child: BottomNavigationBar( child: BottomNavigationBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
onTap: (int index) { onTap: (int index) {
@ -24,7 +25,7 @@ class DefaultNavBar extends StatelessWidget {
DevicesCubit().clearCategoriesSelection(context); DevicesCubit().clearCategoriesSelection(context);
} }
}, },
currentIndex: cubit.getPageIndex, currentIndex: NavCubit.pageIndex,
selectedItemColor: ColorsManager.primaryColor, selectedItemColor: ColorsManager.primaryColor,
selectedLabelStyle: const TextStyle( selectedLabelStyle: const TextStyle(
color: ColorsManager.primaryColor, color: ColorsManager.primaryColor,

View File

@ -5,6 +5,7 @@ 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/text_widgets/title_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
import 'widgets/energy_usage.dart'; import 'widgets/energy_usage.dart';
@ -14,7 +15,14 @@ class DashboardView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( return Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
bottom: Constants.bottomNavBarHeight,
),
child: SingleChildScrollView(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
@ -46,6 +54,7 @@ class DashboardView extends StatelessWidget {
), ),
], ],
), ),
),
); );
} }
} }

View File

@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart'; import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
part 'ac_state.dart'; part 'ac_state.dart';
@ -11,8 +12,10 @@ class AcCubit extends Cubit<AcState> {
static AcCubit get(context) => BlocProvider.of(context); static AcCubit get(context) => BlocProvider.of(context);
static DevicesCategoryModel category = DevicesCubit.allCategories[0];
ACModel? getSelectedAC() { ACModel? getSelectedAC() {
for (var ac in DevicesCubit.categories[0].devices) { for (var ac in category.devices) {
if (ac is ACModel && ac.isSelected) { if (ac is ACModel && ac.isSelected) {
return ac; return ac;
} }
@ -21,11 +24,15 @@ class AcCubit extends Cubit<AcState> {
} }
void setTempToAll(double temperature) { void setTempToAll(double temperature) {
for (DeviceModel ac in DevicesCubit.categories[0].devices) { for (DeviceModel ac in category.devices) {
if (ac is ACModel) { if (ac is ACModel) {
if (ac.temperature != temperature &&
ac.bounds.min <= temperature &&
temperature <= ac.bounds.max) {
setACTemp(ac, temperature); setACTemp(ac, temperature);
} }
} }
}
universalACTemp = temperature; universalACTemp = temperature;
emit(ACsTempChanged(temperature)); emit(ACsTempChanged(temperature));
} }
@ -38,7 +45,7 @@ class AcCubit extends Cubit<AcState> {
} }
double getTemp(int index) { double getTemp(int index) {
var device = DevicesCubit.categories[0].devices[index]; var device = category.devices[index];
if (device is ACModel) { if (device is ACModel) {
return device.temperature; return device.temperature;
} }

View File

@ -0,0 +1,13 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
part 'curtains_state.dart';
class CurtainsCubit extends Cubit<CurtainsState> {
CurtainsCubit() : super(CurtainsInitial());
static CurtainsCubit get(context) => BlocProvider.of(context);
static DevicesCategoryModel category = DevicesCubit.allCategories[3];
}

View File

@ -0,0 +1,5 @@
part of 'curtains_cubit.dart';
abstract class CurtainsState {}
class CurtainsInitial extends CurtainsState {}

View File

@ -1,17 +1,18 @@
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/devices/model/ac_model.dart'; import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/curtain_model.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/light_model.dart'; import 'package:syncrow_app/features/devices/model/light_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/lights_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/screens/screens_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/screens/screens_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_view.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../model/device_category_model.dart';
import '../view/widgets/ACs/acs_view.dart';
import '../view/widgets/lights/lights_view.dart';
part 'devices_state.dart'; part 'devices_state.dart';
@ -20,7 +21,7 @@ class DevicesCubit extends Cubit<DevicesState> {
static DevicesCubit get(context) => BlocProvider.of(context); static DevicesCubit get(context) => BlocProvider.of(context);
static List<DevicesCategoryModel> categories = [ static List<DevicesCategoryModel> allCategories = [
DevicesCategoryModel( DevicesCategoryModel(
devices: [ devices: [
ACModel( ACModel(
@ -31,8 +32,7 @@ class DevicesCubit extends Cubit<DevicesState> {
fanSpeed: 0, fanSpeed: 0,
tempMode: 0, tempMode: 0,
coolTo: 20, coolTo: 20,
type: '', type: DeviceType.AC,
location: '',
image: '', image: '',
timer: null, timer: null,
bounds: Bounds( bounds: Bounds(
@ -48,8 +48,7 @@ class DevicesCubit extends Cubit<DevicesState> {
fanSpeed: 0, fanSpeed: 0,
tempMode: 0, tempMode: 0,
coolTo: 20, coolTo: 20,
type: '', type: DeviceType.AC,
location: '',
image: '', image: '',
timer: null, timer: null,
bounds: Bounds( bounds: Bounds(
@ -65,8 +64,7 @@ class DevicesCubit extends Cubit<DevicesState> {
fanSpeed: 0, fanSpeed: 0,
tempMode: 0, tempMode: 0,
coolTo: 20, coolTo: 20,
type: '', type: DeviceType.AC,
location: '',
image: '', image: '',
timer: null, timer: null,
bounds: Bounds( bounds: Bounds(
@ -82,8 +80,7 @@ class DevicesCubit extends Cubit<DevicesState> {
fanSpeed: 0, fanSpeed: 0,
tempMode: 0, tempMode: 0,
coolTo: 20, coolTo: 20,
type: '', type: DeviceType.AC,
location: '',
image: '', image: '',
timer: null, timer: null,
bounds: Bounds( bounds: Bounds(
@ -107,8 +104,7 @@ class DevicesCubit extends Cubit<DevicesState> {
brightness: 20, brightness: 20,
lightingMode: 1, lightingMode: 1,
timer: null, timer: null,
type: '', type: DeviceType.Lights,
location: '',
image: '', image: '',
recentColors: [ recentColors: [
0xFF83D9FF, 0xFF83D9FF,
@ -125,8 +121,7 @@ class DevicesCubit extends Cubit<DevicesState> {
brightness: 40, brightness: 40,
lightingMode: 1, lightingMode: 1,
timer: null, timer: null,
type: '', type: DeviceType.Lights,
location: '',
image: '', image: '',
recentColors: [ recentColors: [
0xFF83D9FF, 0xFF83D9FF,
@ -143,8 +138,7 @@ class DevicesCubit extends Cubit<DevicesState> {
brightness: 60, brightness: 60,
lightingMode: 1, lightingMode: 1,
timer: null, timer: null,
type: '', type: DeviceType.Lights,
location: '',
image: '', image: '',
recentColors: [ recentColors: [
0xFF83D9FF, 0xFF83D9FF,
@ -161,8 +155,7 @@ class DevicesCubit extends Cubit<DevicesState> {
brightness: 80, brightness: 80,
lightingMode: 1, lightingMode: 1,
timer: null, timer: null,
type: '', type: DeviceType.Lights,
location: '',
image: '', image: '',
recentColors: [ recentColors: [
0xFF83D9FF, 0xFF83D9FF,
@ -179,8 +172,7 @@ class DevicesCubit extends Cubit<DevicesState> {
brightness: 100, brightness: 100,
lightingMode: 1, lightingMode: 1,
timer: null, timer: null,
type: '', type: DeviceType.Lights,
location: '',
image: '', image: '',
recentColors: [ recentColors: [
0xFF83D9FF, 0xFF83D9FF,
@ -203,7 +195,26 @@ class DevicesCubit extends Cubit<DevicesState> {
page: const DoorView(), page: const DoorView(),
), ),
DevicesCategoryModel( DevicesCategoryModel(
devices: [], devices: [
CurtainModel(
openPercentage: 10,
id: "1",
name: "Living Room Curtain",
status: false,
type: DeviceType.Curtain,
image: '',
timer: null,
),
CurtainModel(
openPercentage: 20,
id: "2",
name: "Master Bedroom Curtain",
status: false,
type: DeviceType.Curtain,
image: '',
timer: null,
),
],
icon: Assets.iconsCurtain, icon: Assets.iconsCurtain,
name: 'Curtains', name: 'Curtains',
type: DeviceType.Curtain, type: DeviceType.Curtain,
@ -226,25 +237,25 @@ class DevicesCubit extends Cubit<DevicesState> {
]; ];
selectCategory(int index) { selectCategory(int index) {
for (var i = 0; i < categories.length; i++) { for (var i = 0; i < allCategories.length; i++) {
if (i == index) { if (i == index) {
categories[i].isSelected = true; allCategories[i].isSelected = true;
} else { } else {
categories[i].isSelected = false; allCategories[i].isSelected = false;
} }
} }
emit(DevicesCategoryChanged()); emit(DevicesCategoryChanged());
} }
unselectAllCategories() { unselectAllCategories() {
for (var category in categories) { for (var category in allCategories) {
category.isSelected = false; category.isSelected = false;
} }
emit(DevicesCategoryChanged()); emit(DevicesCategoryChanged());
} }
Widget? get chosenCategoryView { Widget? get chosenCategoryView {
for (var category in categories) { for (var category in allCategories) {
if (category.isSelected) { if (category.isSelected) {
return category.page; return category.page;
} }
@ -253,7 +264,7 @@ class DevicesCubit extends Cubit<DevicesState> {
} }
selectDevice(DeviceModel device) { selectDevice(DeviceModel device) {
for (var category in categories) { for (var category in allCategories) {
for (var device in category.devices) { for (var device in category.devices) {
if (device.isSelected) { if (device.isSelected) {
category.isSelected = false; category.isSelected = false;
@ -267,7 +278,7 @@ class DevicesCubit extends Cubit<DevicesState> {
} }
DeviceModel? getSelectedDevice() { DeviceModel? getSelectedDevice() {
for (var category in categories) { for (var category in allCategories) {
for (var device in category.devices) { for (var device in category.devices) {
if (device.isSelected) { if (device.isSelected) {
return device; return device;
@ -296,13 +307,14 @@ class DevicesCubit extends Cubit<DevicesState> {
turnOnOffDevice(DeviceModel device) { turnOnOffDevice(DeviceModel device) {
device.status = !device.status!; device.status = !device.status!;
DevicesCategoryModel category = DevicesCategoryModel category = allCategories
categories.firstWhere((category) => category.devices.contains(device)); .firstWhere((category) => category.devices.contains(device));
updateDevicesStatus(category); updateDevicesStatus(category);
emit(DeviceSwitchChanged()); emit(DeviceSwitchChanged());
} }
updateDevicesStatus(DevicesCategoryModel category) { updateDevicesStatus(DevicesCategoryModel category) {
if (category.devices.isNotEmpty) {
bool? tempStatus = category.devices[0].status; bool? tempStatus = category.devices[0].status;
for (var ac in category.devices) { for (var ac in category.devices) {
//check if there any ac have a different status than the initial ==> turn off the universal switch //check if there any ac have a different status than the initial ==> turn off the universal switch
@ -314,9 +326,14 @@ class DevicesCubit extends Cubit<DevicesState> {
category.devicesStatus = tempStatus; category.devicesStatus = tempStatus;
emit(DeviceSwitchChanged()); emit(DeviceSwitchChanged());
} }
} else {
category.devicesStatus = null;
emit(DeviceSwitchChanged());
}
} }
turnAllDevicesOff(DevicesCategoryModel category) { turnAllDevicesOff(DevicesCategoryModel category) {
if (category.devices.isNotEmpty) {
for (var device in category.devices) { for (var device in category.devices) {
device.status = false; device.status = false;
} }
@ -324,8 +341,10 @@ class DevicesCubit extends Cubit<DevicesState> {
updateDevicesStatus(category); updateDevicesStatus(category);
emit(CategorySwitchChanged()); emit(CategorySwitchChanged());
} }
}
turnAllDevicesOn(DevicesCategoryModel category) { turnAllDevicesOn(DevicesCategoryModel category) {
if (category.devices.isNotEmpty) {
for (var device in category.devices) { for (var device in category.devices) {
device.status = true; device.status = true;
} }
@ -333,6 +352,7 @@ class DevicesCubit extends Cubit<DevicesState> {
updateDevicesStatus(category); updateDevicesStatus(category);
emit(CategorySwitchChanged()); emit(CategorySwitchChanged());
} }
}
areAllDevicesOff(DevicesCategoryModel category) { areAllDevicesOff(DevicesCategoryModel category) {
for (var device in category.devices) { for (var device in category.devices) {
@ -345,7 +365,7 @@ class DevicesCubit extends Cubit<DevicesState> {
} }
clearCategoriesSelection(BuildContext context) { clearCategoriesSelection(BuildContext context) {
for (var category in categories) { for (var category in allCategories) {
category.isSelected = false; category.isSelected = false;
for (var device in category.devices) { for (var device in category.devices) {
device.isSelected = false; device.isSelected = false;

View File

@ -21,7 +21,6 @@ class ACModel extends DeviceModel {
required super.name, required super.name,
required super.type, required super.type,
required super.status, required super.status,
required super.location,
required super.image, required super.image,
required super.timer, required super.timer,
}); });
@ -36,7 +35,6 @@ class ACModel extends DeviceModel {
'name': name, 'name': name,
'status': status, 'status': status,
'type': type, 'type': type,
'location': location,
'image': image, 'image': image,
}; };
} }
@ -50,7 +48,6 @@ class ACModel extends DeviceModel {
fanSpeed: json['fanSpeed'], fanSpeed: json['fanSpeed'],
tempMode: json['tempMode'], tempMode: json['tempMode'],
type: json['type'], type: json['type'],
location: json['location'],
image: json['image'], image: json['image'],
timer: json['timer'], timer: json['timer'],
coolTo: json['coolTo'], coolTo: json['coolTo'],

View File

@ -0,0 +1,39 @@
import 'package:syncrow_app/features/devices/model/device_model.dart';
class CurtainModel extends DeviceModel {
late int openPercentage;
CurtainModel({
required this.openPercentage,
required super.id,
required super.name,
required super.type,
required super.status,
required super.image,
required super.timer,
});
Map<String, dynamic> toJson() {
return {
'openPercentage': openPercentage,
'timer': timer,
'id': id,
'name': name,
'status': status,
'type': type,
'image': image,
};
}
factory CurtainModel.fromJson(Map<String, dynamic> json) {
return CurtainModel(
id: json['id'],
name: json['name'],
status: json['status'],
openPercentage: json['openPercentage'],
timer: json['timer'],
type: json['type'],
image: json['image'],
);
}
}

View File

@ -2,6 +2,7 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class DevicesCategoryModel { class DevicesCategoryModel {
final String name; final String name;
@ -9,7 +10,7 @@ class DevicesCategoryModel {
final Widget page; final Widget page;
bool? devicesStatus = false; bool? devicesStatus;
final List<DeviceModel> devices; final List<DeviceModel> devices;
final DeviceType type; final DeviceType type;
@ -32,17 +33,6 @@ class DevicesCategoryModel {
} }
} }
devicesStatus = tempStatus; devicesStatus = tempStatus;
} else {
devicesStatus = false;
} }
} }
} }
enum DeviceType {
AC,
Lights,
Door,
Curtain,
Screens,
Gateway,
}

View File

@ -1,11 +1,15 @@
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
abstract class DeviceModel { abstract class DeviceModel {
final String? id; final String? id;
final String? name; final String? name;
final String? type; final DeviceType? type;
bool? status; bool? status;
final String? location;
final String? image; final String? image;
final double? timer; final double? timer;
late final String icon;
bool isSelected = false; bool isSelected = false;
DeviceModel({ DeviceModel({
@ -13,8 +17,27 @@ abstract class DeviceModel {
required this.name, required this.name,
required this.type, required this.type,
required this.status, required this.status,
required this.location,
required this.image, required this.image,
required this.timer, required this.timer,
}); }) {
switch (type) {
case DeviceType.AC:
icon = Assets.iconsAC;
break;
case DeviceType.Lights:
icon = Assets.iconsLight;
break;
case DeviceType.Door:
icon = Assets.iconsDoorLock;
break;
case DeviceType.Curtain:
icon = Assets.iconsCurtain;
break;
case DeviceType.Gateway:
icon = Assets.iconsGateway;
break;
default:
icon = '';
}
}
} }

View File

@ -17,7 +17,6 @@ class LightModel extends DeviceModel {
required super.name, required super.name,
required super.type, required super.type,
required super.status, required super.status,
required super.location,
required super.image, required super.image,
required super.timer, required super.timer,
}); });
@ -33,7 +32,6 @@ class LightModel extends DeviceModel {
'name': name, 'name': name,
'status': status, 'status': status,
'type': type, 'type': type,
'location': location,
'image': image, 'image': image,
}; };
} }
@ -48,7 +46,6 @@ class LightModel extends DeviceModel {
lightingMode: json['lightingMode'], lightingMode: json['lightingMode'],
timer: json['timer'], timer: json['timer'],
type: json['type'], type: json['type'],
location: json['location'],
image: json['image'], image: json['image'],
recentColors: json['recentColors'], recentColors: json['recentColors'],
); );

View File

@ -0,0 +1,30 @@
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
class RoomModel {
final String id;
final String name;
final List<DevicesCategoryModel> categories;
RoomModel({
required this.id,
required this.name,
required this.categories,
});
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'devices': categories,
};
}
factory RoomModel.fromJson(Map<String, dynamic> json) {
return RoomModel(
id: json['id'],
name: json['name'],
categories: json['devices'],
);
}
}

View File

@ -1,9 +1,13 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/services.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart'; import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_controls.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_controls.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.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/font_manager.dart';
class AcInterface extends StatelessWidget { class AcInterface extends StatelessWidget {
const AcInterface({super.key, required this.acModel}); const AcInterface({super.key, required this.acModel});
@ -12,22 +16,61 @@ class AcInterface extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: SafeArea(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: acModel.name ?? "",
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.imagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
),
child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
const SizedBox(height: 20),
ConstrainedBox( ConstrainedBox(
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxHeight: 400, maxHeight: 380,
), ),
child: AcInterfaceTempUnit( child: AcInterfaceTempUnit(
acModel: acModel, acModel: acModel,
), ),
), ),
const SizedBox(
height: 10,
),
ConstrainedBox( ConstrainedBox(
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxHeight: 130, maxHeight: 120,
), ),
child: AcInterfaceControls( child: AcInterfaceControls(
acModel: acModel, acModel: acModel,
@ -35,6 +78,11 @@ class AcInterface extends StatelessWidget {
), ),
], ],
), ),
),
),
),
),
),
); );
} }
} }

View File

@ -18,12 +18,11 @@ class AcInterfaceControls extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
const SizedBox(height: 10),
ACModeControlUnit(model: acModel), ACModeControlUnit(model: acModel),
const SizedBox(height: 10), const SizedBox(height: 10),
Row( Row(
children: [ children: [
Expanded( Flexible(
child: InkWell( child: InkWell(
onTap: () {}, onTap: () {},
child: DefaultContainer( child: DefaultContainer(
@ -35,7 +34,7 @@ class AcInterfaceControls extends StatelessWidget {
), ),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Flexible(
child: InkWell( child: InkWell(
onTap: () {}, onTap: () {},
child: DefaultContainer( child: DefaultContainer(

View File

@ -23,9 +23,9 @@ class AcInterfaceTempUnit extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
//TODO: use the coolTo value from the model return BlocProvider(
double coolTo = acModel.temperature; create: (context) => AcCubit(),
return BlocBuilder<AcCubit, AcState>( child: BlocBuilder<AcCubit, AcState>(
builder: (context, state) { builder: (context, state) {
return DefaultContainer( return DefaultContainer(
child: Column( child: Column(
@ -48,6 +48,7 @@ class AcInterfaceTempUnit extends StatelessWidget {
dotColor: Colors.transparent, dotColor: Colors.transparent,
), ),
infoProperties: InfoProperties( infoProperties: InfoProperties(
//TODO: move to strings manager
bottomLabelText: 'CURRENT TEMP', bottomLabelText: 'CURRENT TEMP',
bottomLabelStyle: context.bodyLarge.copyWith( bottomLabelStyle: context.bodyLarge.copyWith(
color: Colors.grey, color: Colors.grey,
@ -71,17 +72,15 @@ class AcInterfaceTempUnit extends StatelessWidget {
), ),
), ),
), ),
min: 20, min: acModel.bounds.min,
max: 30, max: acModel.bounds.max,
initialValue: 20, initialValue: acModel.temperature,
onChange: (value) { onChange: (value) {
String valueAsString = value.toStringAsFixed(1); String valueAsString = value.toStringAsFixed(1);
if (valueAsString.endsWith(".0") || if (valueAsString.endsWith(".0") ||
valueAsString.endsWith(".5")) { valueAsString.endsWith(".5")) {
value = double.parse(valueAsString); value = double.parse(valueAsString);
if (value != acModel.temperature) { AcCubit.get(context).setACTemp(acModel, value);
AcCubit.get(context).setTempToAll(value);
}
} }
}, },
), ),
@ -96,9 +95,9 @@ class AcInterfaceTempUnit extends StatelessWidget {
dimension: 24, dimension: 24,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
// AcCubit.get(context).setACTemp(acModel, coolTo - .5); AcCubit.get(context)
AcCubit.get(context).setACTemp(acModel, coolTo); .setACTemp(acModel, acModel.coolTo);
coolTo = coolTo - .5; acModel.coolTo -= .5;
}, },
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.iconsMinus, Assets.iconsMinus,
@ -108,7 +107,7 @@ class AcInterfaceTempUnit extends StatelessWidget {
Column( Column(
children: [ children: [
BodyLarge( BodyLarge(
text: "$coolTo° C", text: "${acModel.coolTo}° C",
style: context.bodyLarge.copyWith( style: context.bodyLarge.copyWith(
color: color:
ColorsManager.primaryColor.withOpacity(0.6), ColorsManager.primaryColor.withOpacity(0.6),
@ -126,9 +125,9 @@ class AcInterfaceTempUnit extends StatelessWidget {
dimension: 24, dimension: 24,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
// AcCubit.get(context).setACTemp(acModel, coolTo + .5); AcCubit.get(context)
AcCubit.get(context).setACTemp(acModel, coolTo); .setACTemp(acModel, acModel.coolTo);
coolTo = coolTo + .5; acModel.coolTo += .5;
}, },
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.iconsPlus, Assets.iconsPlus,
@ -144,6 +143,7 @@ class AcInterfaceTempUnit extends StatelessWidget {
), ),
); );
}, },
),
); );
} }
} }

View File

@ -36,7 +36,7 @@ class _ACModeControlUnitState extends State<ACModeControlUnit> {
//TODO Move the fanSpeeds and tempModes to the Cubit //TODO Move the fanSpeeds and tempModes to the Cubit
return Row( return Row(
children: [ children: [
Expanded( Flexible(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
setState(() { setState(() {
@ -53,7 +53,7 @@ class _ACModeControlUnitState extends State<ACModeControlUnit> {
), ),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Flexible(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
setState(() { setState(() {

View File

@ -1,7 +1,7 @@
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/devices/bloc/AC/ac_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_mode_control_unit.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_mode_control_unit.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_temp_widget.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_temp_widget.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/universal_ac_temp.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/universal_ac_temp.dart';
@ -18,7 +18,6 @@ class ACsList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
DevicesCategoryModel category = DevicesCubit.categories[0];
return BlocBuilder<DevicesCubit, DevicesState>( return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) { builder: (context, state) {
return SingleChildScrollView( return SingleChildScrollView(
@ -30,7 +29,7 @@ class ACsList extends StatelessWidget {
const BodySmall(text: "All ACs"), const BodySmall(text: "All ACs"),
const SizedBox(height: 5), const SizedBox(height: 5),
UniversalSwitch( UniversalSwitch(
category: category, category: AcCubit.category,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
const UniversalACTemp(), const UniversalACTemp(),
@ -41,9 +40,9 @@ class ACsList extends StatelessWidget {
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
itemCount: category.devices.length, itemCount: AcCubit.category.devices.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
ACModel ac = category.devices[index] as ACModel; ACModel ac = AcCubit.category.devices[index] as ACModel;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -51,7 +50,8 @@ class ACsList extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
BodySmall(text: category.devices[index].name ?? ""), BodySmall(
text: AcCubit.category.devices[index].name ?? ""),
IconButton( IconButton(
onPressed: () { onPressed: () {
DevicesCubit.get(context).selectDevice(ac); DevicesCubit.get(context).selectDevice(ac);
@ -70,7 +70,7 @@ class ACsList extends StatelessWidget {
], ],
), ),
const SizedBox(height: 5), const SizedBox(height: 5),
if (category.devices[index] is ACModel) if (AcCubit.category.devices[index] is ACModel)
DevicesDefaultSwitch( DevicesDefaultSwitch(
model: ac, model: ac,
), ),
@ -79,7 +79,7 @@ class ACsList extends StatelessWidget {
ac, ac,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
if (category.devices[index] is ACModel) if (AcCubit.category.devices[index] is ACModel)
ACModeControlUnit( ACModeControlUnit(
model: ac, model: ac,
), ),

View File

@ -2,12 +2,12 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/default_nav_bar.dart';
import 'package:syncrow_app/features/devices/bloc/AC/ac_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/AC/ac_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart'; import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_list.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_list.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../../../../../generated/assets.dart'; import '../../../../../generated/assets.dart';
import '../../../../../utils/resource_manager/color_manager.dart'; import '../../../../../utils/resource_manager/color_manager.dart';
@ -38,7 +38,7 @@ class ACsView extends StatelessWidget {
backgroundColor: ColorsManager.backgroundColor, backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
extendBody: true, extendBody: true,
appBar: const DefaultAppBar(), appBar: DefaultAppBar(context),
body: Container( body: Container(
width: MediaQuery.sizeOf(context).width, width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height, height: MediaQuery.sizeOf(context).height,
@ -52,8 +52,11 @@ class ACsView extends StatelessWidget {
), ),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: EdgeInsets.only(
top: 60, right: 15, left: 15, bottom: 80), top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
),
child: SizedBox.expand( child: SizedBox.expand(
child: selectedAC != null child: selectedAC != null
? AcInterface(acModel: selectedAC) ? AcInterface(acModel: selectedAC)
@ -61,7 +64,6 @@ class ACsView extends StatelessWidget {
), ),
), ),
), ),
bottomNavigationBar: const DefaultNavBar(),
), ),
), ),
); );

View File

@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/curtains/curtains_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/curtain_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/universal_switch.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class CurtainList extends StatelessWidget {
const CurtainList({
super.key,
});
@override
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// universal AC controller
const SizedBox(height: 10),
//TODO: move to strings manager
const BodySmall(text: "All Curtains"),
const SizedBox(height: 5),
UniversalSwitch(
category: CurtainsCubit.category,
),
// other ACs controls
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount: CurtainsCubit.category.devices.length,
itemBuilder: (context, index) {
CurtainModel curtain =
CurtainsCubit.category.devices[index] as CurtainModel;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
BodySmall(
text:
CurtainsCubit.category.devices[index].name ?? ""),
const SizedBox(height: 5),
if (CurtainsCubit.category.devices[index] is CurtainModel)
DevicesDefaultSwitch(
model: curtain,
),
],
);
},
),
],
),
);
},
);
}
}

View File

@ -1,10 +1,64 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart';
import 'package:syncrow_app/features/devices/bloc/curtains/curtains_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_list.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class CurtainView extends StatelessWidget { class CurtainView extends StatelessWidget {
const CurtainView({super.key}); const CurtainView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Placeholder(); return BlocProvider(
create: (context) => CurtainsCubit(),
child: BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return BlocBuilder<CurtainsCubit, CurtainsState>(
builder: (context, state) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: SafeArea(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: DefaultAppBar(context),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.imagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
),
child: const CurtainList(),
),
),
),
),
);
},
);
},
),
);
} }
} }

View File

@ -1,55 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_mode_tab.dart';
import 'package:syncrow_app/features/devices/view/widgets/switches.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class DevicesCategoriesView extends StatelessWidget {
const DevicesCategoriesView({
super.key,
});
@override
Widget build(BuildContext context) {
return const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitleMedium(
text: StringsManager.devices,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
DevicesModeTab(),
],
),
),
Expanded(
flex: 11,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitleMedium(
text: StringsManager.wizard,
style: TextStyle(
fontSize: 28,
),
),
Switches(),
],
),
),
)
],
);
}
}

View File

@ -1,12 +1,14 @@
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:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_categories_view.dart'; import 'package:syncrow_app/features/app_layout/bloc/spaces_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart'; import 'package:syncrow_app/features/devices/view/widgets/devices_view_header.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/wizard_page.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../../../../utils/resource_manager/strings_manager.dart';
import '../../bloc/devices_cubit.dart'; import '../../bloc/devices_cubit.dart';
import 'switches.dart';
class DevicesViewBody extends StatelessWidget { class DevicesViewBody extends StatelessWidget {
const DevicesViewBody({ const DevicesViewBody({
@ -20,109 +22,59 @@ class DevicesViewBody extends StatelessWidget {
child: BlocBuilder<DevicesCubit, DevicesState>( child: BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) { builder: (context, state) {
//TODO : move to NavigationCubit //TODO : move to NavigationCubit
PageController pageController = PageController();
return state is DevicesLoading return state is DevicesLoading
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: Column( : Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
bottom: Constants.bottomNavBarHeight,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const DevicesViewHeader(),
const RoomsSlider(),
const SizedBox(
height: 10,
),
Expanded( Expanded(
child: PageView( child: PageView(
controller: pageController, controller:
children: const [ SpacesCubit.get(context).devicesPageController,
DevicesCategoriesView(), onPageChanged: (index) {
Column( SpacesCubit.get(context).devicesPageChanged(index);
crossAxisAlignment: CrossAxisAlignment.start, },
children: [ children: [
Expanded( const WizardPage(),
child: Column( ...SpacesCubit.get(context).selectedSpace.rooms.map(
crossAxisAlignment: CrossAxisAlignment.start, (room) {
children: [ return RoomPage(
TitleMedium( room: room,
text: "Home", );
style: TextStyle( },
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
],
),
),
Expanded(
flex: 3,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
TitleMedium(
text: StringsManager.wizard,
style: TextStyle(
fontSize: 28,
),
),
Switches(),
],
),
),
) )
], ],
), ),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitleMedium(
text: "Office",
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
), ),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
), ),
], child: SmoothPageIndicator(
), controller:
), SpacesCubit.get(context).devicesPageController,
Expanded(
flex: 3,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
TitleMedium(
text: StringsManager.wizard,
style: TextStyle(
fontSize: 28,
),
),
Switches(),
],
),
),
)
],
),
],
),
),
SmoothPageIndicator(
controller: pageController,
count: 3, count: 3,
effect: const WormEffect( effect: const WormEffect(
dotHeight: 8, dotHeight: 8,
dotWidth: 8, dotWidth: 8,
), ),
onDotClicked: (index) { onDotClicked: (index) {
pageController.animateToPage( SpacesCubit.get(context).unselectRoom();
index, },
duration: const Duration(milliseconds: 300), ),
curve: Curves.ease, ),
);
}),
], ],
),
); );
}, },
), ),

View File

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_mode_tab.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.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/strings_manager.dart';
class DevicesViewHeader extends StatelessWidget {
const DevicesViewHeader({
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: Constants.defaultPadding,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitleMedium(
text: StringsManager.devices,
style: context.titleMedium.copyWith(
fontSize: 25,
),
),
const DevicesModeTab(),
const SizedBox(
height: 20,
),
],
),
);
}
}

View File

@ -39,7 +39,7 @@ class LightInterfaceSwitch extends StatelessWidget {
width: 35, width: 35,
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: light.status ?? false color: light.status ?? false
? ColorsManager.primaryWithOpacity ? ColorsManager.primaryColorWithOpacity
: Colors.grey, : Colors.grey,
shape: const CircleBorder(), shape: const CircleBorder(),
), ),

View File

@ -6,7 +6,6 @@ import 'package:syncrow_app/features/devices/view/widgets/lights/lights_view_lis
import '../../../../../generated/assets.dart'; import '../../../../../generated/assets.dart';
import '../../../../../utils/resource_manager/color_manager.dart'; import '../../../../../utils/resource_manager/color_manager.dart';
import '../../../../app_layout/view/widgets/default_app_bar.dart'; import '../../../../app_layout/view/widgets/default_app_bar.dart';
import '../../../../app_layout/view/widgets/default_nav_bar.dart';
import '../../../bloc/devices_cubit.dart'; import '../../../bloc/devices_cubit.dart';
import '../../../bloc/lights/lights_cubit.dart'; import '../../../bloc/lights/lights_cubit.dart';
import '../../../model/light_model.dart'; import '../../../model/light_model.dart';
@ -29,7 +28,7 @@ class LightsView extends StatelessWidget {
DevicesCubit.get(context).getSelectedDevice() as LightModel; DevicesCubit.get(context).getSelectedDevice() as LightModel;
} }
List<LightModel> lights = []; List<LightModel> lights = [];
for (var device in DevicesCubit.categories[1].devices) { for (var device in DevicesCubit.allCategories[1].devices) {
if (device is LightModel) { if (device is LightModel) {
lights.add(device); lights.add(device);
} }
@ -44,7 +43,7 @@ class LightsView extends StatelessWidget {
backgroundColor: ColorsManager.backgroundColor, backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
extendBody: true, extendBody: true,
appBar: const DefaultAppBar(), appBar: DefaultAppBar(context),
body: Container( body: Container(
width: MediaQuery.sizeOf(context).width, width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height, height: MediaQuery.sizeOf(context).height,
@ -61,7 +60,6 @@ class LightsView extends StatelessWidget {
? LightInterface(light: selectedLight) ? LightInterface(light: selectedLight)
: LightsViewList(lights: lights), : LightsViewList(lights: lights),
), ),
bottomNavigationBar: const DefaultNavBar(),
), ),
), ),
); );

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/lights_list.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/lights_list.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../../../../shared_widgets/text_widgets/body_small.dart'; import '../../../../shared_widgets/text_widgets/body_small.dart';
import '../../../bloc/devices_cubit.dart'; import '../../../bloc/devices_cubit.dart';
@ -17,7 +18,11 @@ class LightsViewList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 70, right: 15, left: 15, bottom: 80), padding: EdgeInsets.only(
top: Constants.appBarHeight,
right: Constants.defaultPadding,
left: Constants.defaultPadding,
),
child: SizedBox.expand( child: SizedBox.expand(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
@ -25,7 +30,7 @@ class LightsViewList extends StatelessWidget {
children: [ children: [
const BodySmall(text: "All Lights"), const BodySmall(text: "All Lights"),
UniversalSwitch( UniversalSwitch(
category: DevicesCubit.categories[1], category: DevicesCubit.allCategories[1],
), ),
LightsList(lights: lights), LightsList(lights: lights),
], ],

View File

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class RoomPage extends StatelessWidget {
const RoomPage({super.key, required this.room});
final RoomModel room;
@override
Widget build(BuildContext context) {
List<DeviceModel> devices = [];
for (var category in room.categories) {
devices.addAll(category.devices);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
child: SingleChildScrollView(
child: BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1.5,
),
padding: const EdgeInsets.only(top: 10),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: devices.length,
itemBuilder: (_, index) {
return RoomPageSwitch(device: devices[index]);
},
);
},
),
),
);
}
}

View File

@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart';
import 'package:syncrow_app/features/shared_widgets/custom_switch.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class RoomPageSwitch extends StatelessWidget {
const RoomPageSwitch({
super.key,
required this.device,
});
final DeviceModel device;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
//Navigate to the chosen category view without animation
// Navigator.push(
// context,
// CustomPageRoute(
// builder: (context) {
// return DevicesCubit.get(context)
// .chosenCategoryView!;
// },
// ),
// );
if (device.type == DeviceType.AC) {
Navigator.push(
context,
CustomPageRoute(
builder: (context) => AcInterface(acModel: device as ACModel),
),
);
}
},
child: DefaultContainer(
child: Padding(
padding: const EdgeInsets.only(top: 10, right: 10, left: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
device.icon,
fit: BoxFit.contain,
),
CustomSwitch(
device: device,
),
],
),
Expanded(
child: FittedBox(
fit: BoxFit.scaleDown,
child: BodyLarge(
text: device.name ?? "",
style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
height: 0,
fontSize: 24,
color: Colors.grey,
),
),
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,125 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/spaces_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class RoomsSlider extends StatelessWidget {
const RoomsSlider({
super.key,
});
@override
Widget build(BuildContext context) {
return BlocBuilder<SpacesCubit, SpacesState>(
builder: (context, state) {
return SizedBox(
height: 40,
child: PageView(
controller: SpacesCubit.get(context).roomsPageController,
onPageChanged: (index) {
SpacesCubit.get(context).roomSliderPageChanged(index);
},
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () {
SpacesCubit.get(context).unselectRoom();
},
child: TitleMedium(
text: StringsManager.wizard,
style: context.titleMedium.copyWith(
fontSize: 25,
color: SpacesCubit.get(context).selectedRoom == null
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor.withOpacity(.2),
),
),
),
),
...SpacesCubit.get(context).selectedSpace.rooms.map(
(room) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () {
SpacesCubit.get(context).roomSliderPageChanged(
SpacesCubit.get(context)
.selectedSpace
.rooms
.indexOf(room));
},
child: TitleMedium(
text: room.name,
style: context.titleMedium.copyWith(
fontSize: 25,
color: SpacesCubit.get(context).selectedRoom == room
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor
.withOpacity(.2),
),
),
),
),
)
],
),
);
// SingleChildScrollView(
// controller: SpacesCubit.get(context).roomsScrollController,
// scrollDirection: Axis.horizontal,
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Padding(
// padding: const EdgeInsets.symmetric(horizontal: 15),
// child: InkWell(
// onTap: () {
// SpacesCubit.get(context).unselectRoom();
// },
// child: TitleMedium(
// text: StringsManager.wizard,
// style: context.titleMedium.copyWith(
// fontSize: 25,
// color: SpacesCubit.get(context).selectedRoom == null
// ? ColorsManager.textPrimaryColor
// : ColorsManager.textPrimaryColor.withOpacity(.2),
// ),
// ),
// ),
// ),
// ...SpacesCubit.get(context).selectedSpace.rooms.map(
// (room) => Padding(
// padding: const EdgeInsets.symmetric(horizontal: 15),
// child: InkWell(
// onTap: () {
// SpacesCubit.get(context).selectRoom(room);
// },
// child: TitleMedium(
// text: room.name,
// style: context.titleMedium.copyWith(
// fontSize: 25,
// color: SpacesCubit.get(context).selectedRoomIndex ==
// SpacesCubit.get(context)
// .selectedSpace
// .rooms
// .indexOf(room) +
// 1
// ? ColorsManager.textPrimaryColor
// : ColorsManager.textPrimaryColor
// .withOpacity(.2),
// ),
// ),
// ),
// ),
// )
// ],
// ),
// );
},
);
}
}

View File

@ -0,0 +1,21 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:syncrow_app/features/devices/view/widgets/wizard_switches.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class WizardPage extends StatelessWidget {
const WizardPage({
super.key,
});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
child: SingleChildScrollView(
child: WizartSwitches(),
),
);
}
}

View File

@ -9,8 +9,8 @@ import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import '../../bloc/devices_cubit.dart'; import '../../bloc/devices_cubit.dart';
class Switches extends StatelessWidget { class WizartSwitches extends StatelessWidget {
const Switches({ const WizartSwitches({
super.key, super.key,
}); });
@ -28,7 +28,7 @@ class Switches extends StatelessWidget {
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemCount: DevicesCubit.categories.length, itemCount: DevicesCubit.allCategories.length,
itemBuilder: (_, index) { itemBuilder: (_, index) {
return InkWell( return InkWell(
onTap: () { onTap: () {
@ -51,11 +51,11 @@ class Switches extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
DevicesCubit.categories[index].icon, DevicesCubit.allCategories[index].icon,
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
CustomSwitch( CustomSwitch(
category: DevicesCubit.categories[index], category: DevicesCubit.allCategories[index],
), ),
], ],
), ),
@ -63,11 +63,12 @@ class Switches extends StatelessWidget {
child: FittedBox( child: FittedBox(
fit: BoxFit.scaleDown, fit: BoxFit.scaleDown,
child: BodyLarge( child: BodyLarge(
text: DevicesCubit.categories[index].name, text: DevicesCubit.allCategories[index].name,
style: context.bodyLarge.copyWith( style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
height: 0, height: 0,
fontSize: 24, fontSize: 24,
color: Colors.grey,
), ),
), ),
), ),

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart'; import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart';
import 'package:syncrow_app/features/menu/view/widgets/menu_list.dart'; import 'package:syncrow_app/features/menu/view/widgets/menu_list.dart';
import 'package:syncrow_app/features/menu/view/widgets/profile_tab.dart'; import 'package:syncrow_app/features/menu/view/widgets/profile_tab.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class MenuView extends StatelessWidget { class MenuView extends StatelessWidget {
const MenuView({super.key}); const MenuView({super.key});
@ -13,7 +14,14 @@ class MenuView extends StatelessWidget {
create: (BuildContext context) => MenuCubit(), create: (BuildContext context) => MenuCubit(),
child: BlocBuilder<MenuCubit, MenuState>( child: BlocBuilder<MenuCubit, MenuState>(
builder: (context, state) { builder: (context, state) {
return SingleChildScrollView( return Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
bottom: Constants.bottomNavBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
),
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
child: Column( child: Column(
children: [ children: [
@ -25,6 +33,7 @@ class MenuView extends StatelessWidget {
), ),
], ],
), ),
),
); );
}, },
), ),

View File

@ -6,6 +6,7 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dar
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/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/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class SceneView extends StatelessWidget { class SceneView extends StatelessWidget {
@ -17,7 +18,14 @@ 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 Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
bottom: Constants.bottomNavBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -45,7 +53,8 @@ class SceneView extends StatelessWidget {
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Image.asset( Image.asset(
height: 50, height: 50,
@ -82,7 +91,8 @@ class SceneView extends StatelessWidget {
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Image.asset( Image.asset(
height: 50, height: 50,
@ -110,6 +120,7 @@ class SceneView extends StatelessWidget {
], ],
) )
], ],
),
); );
}, },
), ),

View File

@ -2,28 +2,42 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart'; import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class CustomSwitch extends StatelessWidget { class CustomSwitch extends StatelessWidget {
const CustomSwitch({super.key, required this.category}); const CustomSwitch({super.key, this.category, this.device})
: assert(category != null || device != null);
final DevicesCategoryModel category; final DevicesCategoryModel? category;
final DeviceModel? device;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>( return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) { builder: (context, state) {
bool? status;
if (device != null) {
status = device!.status;
} else if (category != null) {
status = category!.devicesStatus;
}
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
DevicesCubit.get(context).changeCategorySwitchValue(category); if (device != null) {
DevicesCubit.get(context).turnOnOffDevice(device!);
} else if (category != null) {
DevicesCubit.get(context).changeCategorySwitchValue(category!);
}
}, },
child: Container( child: Container(
width: 45.0, width: 45.0,
height: 28.0, height: 28.0,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0), borderRadius: BorderRadius.circular(24.0),
color: category.devicesStatus != null color: status != null
? category.devicesStatus! ? status
? ColorsManager.primaryColor ? ColorsManager.primaryColor
: const Color(0xFFD9D9D9) : const Color(0xFFD9D9D9)
: const Color(0xFFD9D9D9), : const Color(0xFFD9D9D9),
@ -39,8 +53,8 @@ class CustomSwitch extends StatelessWidget {
child: Padding( child: Padding(
padding: const EdgeInsets.all(2.0), padding: const EdgeInsets.all(2.0),
child: Container( child: Container(
alignment: category.devicesStatus != null alignment: status != null
? category.devicesStatus! ? status
? Alignment.centerRight ? Alignment.centerRight
: Alignment.centerLeft : Alignment.centerLeft
: Alignment.centerLeft, : Alignment.centerLeft,
@ -49,8 +63,8 @@ class CustomSwitch extends StatelessWidget {
height: 20.0, height: 20.0,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: category.devicesStatus != null color: status != null
? category.devicesStatus! ? status
? ColorsManager.primaryColor ? ColorsManager.primaryColor
: Colors.grey : Colors.grey
: Colors.grey, : Colors.grey,

View File

@ -28,12 +28,13 @@ class CustomText extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SelectableText( //was SelectableText
return Text(
text, text,
style: style, style: style,
textAlign: textAlign, textAlign: textAlign,
onTap: onTap, // onTap: onTap,
minLines: minLines, // minLines: minLines,
maxLines: maxLines, maxLines: maxLines,
textDirection: textDirection, textDirection: textDirection,
); );

View File

@ -2,6 +2,8 @@
class Assets { class Assets {
Assets._(); Assets._();
static const String assetsIconsQrScan = 'assets/icons/qr_scan.svg';
static const String assetsIconsSettings = 'assets/icons/settings.svg';
static const String fontsAftikaRegular = 'assets/fonts/AftikaRegular.ttf'; static const String fontsAftikaRegular = 'assets/fonts/AftikaRegular.ttf';
static const String iconsAC = 'assets/icons/AC.svg'; static const String iconsAC = 'assets/icons/AC.svg';
static const String iconsActive = 'assets/icons/active.svg'; static const String iconsActive = 'assets/icons/active.svg';
@ -20,6 +22,7 @@ class Assets {
static const String iconsFan1 = 'assets/icons/fan-1.svg'; static const String iconsFan1 = 'assets/icons/fan-1.svg';
static const String iconsFan2 = 'assets/icons/fan-2.svg'; static const String iconsFan2 = 'assets/icons/fan-2.svg';
static const String iconsFan3 = 'assets/icons/fan-3.svg'; static const String iconsFan3 = 'assets/icons/fan-3.svg';
static const String iconsFilter = 'assets/icons/filter.png';
static const String iconsFrequency = 'assets/icons/frequency.svg'; static const String iconsFrequency = 'assets/icons/frequency.svg';
static const String iconsGateway = 'assets/icons/Gateway.svg'; static const String iconsGateway = 'assets/icons/Gateway.svg';
static const String iconsGoogle = 'assets/icons/Google.svg'; static const String iconsGoogle = 'assets/icons/Google.svg';
@ -35,11 +38,11 @@ class Assets {
static const String iconsMenuFill = 'assets/icons/Menu-fill.svg'; static const String iconsMenuFill = 'assets/icons/Menu-fill.svg';
static const String iconsMinus = 'assets/icons/minus.svg'; static const String iconsMinus = 'assets/icons/minus.svg';
static const String iconsPlus = 'assets/icons/plus.svg'; static const String iconsPlus = 'assets/icons/plus.svg';
static const String iconsQrScan = 'assets/icons/qr_scan.svg'; static const String iconsQrScan = 'assets/icons/qr_scan.png';
static const String iconsRoutines = 'assets/icons/Routines.svg'; static const String iconsRoutines = 'assets/icons/Routines.svg';
static const String iconsRoutinesFill = 'assets/icons/Routines-fill.svg'; static const String iconsRoutinesFill = 'assets/icons/Routines-fill.svg';
static const String iconsScreen = 'assets/icons/Screen.svg'; static const String iconsScreen = 'assets/icons/Screen.svg';
static const String iconsSettings = 'assets/icons/settings.svg'; static const String iconsSettings = 'assets/icons/settings.png';
static const String iconsSummer = 'assets/icons/Summer.svg'; static const String iconsSummer = 'assets/icons/Summer.svg';
static const String iconsSummerMode = 'assets/icons/summer_mode.svg'; static const String iconsSummerMode = 'assets/icons/summer_mode.svg';
static const String iconsSunnyMode = 'assets/icons/sunnyMode.svg'; static const String iconsSunnyMode = 'assets/icons/sunnyMode.svg';
@ -52,8 +55,12 @@ class Assets {
static const String imagesAutomation = 'assets/images/automation.jpg'; static const String imagesAutomation = 'assets/images/automation.jpg';
static const String imagesBackground = 'assets/images/Background.png'; static const String imagesBackground = 'assets/images/Background.png';
static const String imagesBlackLogo = 'assets/images/black-logo.png'; static const String imagesBlackLogo = 'assets/images/black-logo.png';
static const String imagesBlind = 'assets/images/blind.png';
static const String imagesBoxEmpty = 'assets/images/box-empty.jpg'; static const String imagesBoxEmpty = 'assets/images/box-empty.jpg';
static const String imagesCurtain = 'assets/images/curtain.png';
static const String imagesLogo = 'assets/images/Logo.svg'; static const String imagesLogo = 'assets/images/Logo.svg';
static const String imagesLogoHorizontal =
'assets/images/logo_horizontal.png';
static const String imagesTestDash = 'assets/images/test_dash.png'; static const String imagesTestDash = 'assets/images/test_dash.png';
static const String imagesTestDash2 = 'assets/images/test_dash2.png'; static const String imagesTestDash2 = 'assets/images/test_dash2.png';
static const String imagesVector = 'assets/images/Vector.png'; static const String imagesVector = 'assets/images/Vector.png';

View File

@ -1,8 +1,10 @@
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/nav_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/nav_cubit.dart';
import 'package:syncrow_app/features/app_layout/bloc/spaces_cubit.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/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/theme_manager.dart'; import 'package:syncrow_app/utils/resource_manager/theme_manager.dart';
import 'features/devices/bloc/devices_cubit.dart'; import 'features/devices/bloc/devices_cubit.dart';
@ -16,6 +18,10 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Constants.appBarHeight =
MediaQuery.sizeOf(context).height * Constants.appBarHeightPercentage;
Constants.bottomNavBarHeight = MediaQuery.sizeOf(context).height *
Constants.bottomNavBarHeightPercentage;
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider( BlocProvider(
@ -24,6 +30,9 @@ class MyApp extends StatelessWidget {
BlocProvider( BlocProvider(
create: (context) => NavCubit(), create: (context) => NavCubit(),
), ),
BlocProvider(
create: (context) => SpacesCubit(),
),
BlocProvider( BlocProvider(
create: (context) => DevicesCubit(), create: (context) => DevicesCubit(),
), ),

View File

@ -9,6 +9,7 @@ import 'package:syncrow_app/features/auth/view/widgets/user_agreement/user_agree
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/devices/view/devices_view.dart'; import 'package:syncrow_app/features/devices/view/devices_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/profile/view/profile_view.dart'; import 'package:syncrow_app/features/profile/view/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';
@ -70,6 +71,10 @@ class Router {
return MaterialPageRoute( return MaterialPageRoute(
builder: (_) => const AppLayout(), settings: settings); builder: (_) => const AppLayout(), settings: settings);
case Routes.menuRoute:
return MaterialPageRoute(
builder: (_) => const MenuView(), settings: settings);
default: default:
return MaterialPageRoute( return MaterialPageRoute(
builder: (_) => Scaffold( builder: (_) => Scaffold(

View File

@ -6,6 +6,7 @@ class Routes {
static const String sceneRoute = '/scene'; static const String sceneRoute = '/scene';
static const String layoutRoute = '/layout'; static const String layoutRoute = '/layout';
static const String profileRoute = '/profile'; static const String profileRoute = '/profile';
static const String menuRoute = '/menu';
static const String authRoute = '/auth'; static const String authRoute = '/auth';
static const String authLogin = '$authRoute/login'; static const String authLogin = '$authRoute/login';
static const String authSignUp = '$authRoute/signup'; static const String authSignUp = '$authRoute/signup';

View File

@ -3,13 +3,15 @@ import 'package:flutter/material.dart';
abstract class ColorsManager { abstract class ColorsManager {
static const Color textPrimaryColor = Color(0xFF5D5D5D); static const Color textPrimaryColor = Color(0xFF5D5D5D);
static const Color primaryColor = Color(0xFF0030CB); static const Color primaryColor = Color(0xFF0030CB);
static Color primaryWithOpacity = const Color(0xFF023DFE).withOpacity(0.6); static Color primaryColorWithOpacity =
const Color(0xFF023DFE).withOpacity(0.6);
static const Color onPrimaryColor = Colors.white; static const Color onPrimaryColor = Colors.white;
static const Color secondaryColor = Color(0xFF023DFE); static const Color secondaryColor = Color(0xFF023DFE);
static const Color onSecondaryColor = Color(0xFF023DFE); static const Color onSecondaryColor = Color(0xFF023DFE);
static const Color primaryTextColor = Colors.black; static const Color primaryTextColor = Colors.black;
static const Color greyColor = Color(0xFFd5d5d5); static const Color greyColor = Color(0xFFd5d5d5);
static const Color backgroundColor = Color(0xFFececec); static const Color backgroundColor = Color(0xFFececec);
static const Color dozeColor = Color(0xFFFEC258); static const Color dozeColor = Color(0xFFFEC258);
static const Color relaxColor = Color(0xFFFBD288); static const Color relaxColor = Color(0xFFFBD288);

View File

@ -1,9 +1,24 @@
//ignore_for_file: constant_identifier_names
abstract class Constants { abstract class Constants {
static const String languageCode = "en"; static const String languageCode = "en";
static const String countryCode = "US"; static const String countryCode = "US";
static const double defaultPadding = 16.0; static const double appBarHeightPercentage = 0.1175;
static const double bottomNavBarHeightPercentage = 0.1175;
static late double appBarHeight;
static late double bottomNavBarHeight;
static const double defaultPadding = 16;
static const String tokenKey = 'userToken'; static const String tokenKey = 'userToken';
} }
enum DeviceType {
AC,
Lights,
Door,
Curtain,
Screens,
Gateway,
}

View File

@ -140,6 +140,38 @@ abstract class ThemeManager {
// ), // ),
// ), // ),
dropdownMenuTheme: const DropdownMenuThemeData(
textStyle: TextStyle(
fontFamily: FontsManager.fontFamily,
fontSize: FontSize.s16,
fontWeight: FontsManager.regular,
color: ColorsManager.textPrimaryColor,
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(8)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: ColorsManager.primaryColor),
borderRadius: BorderRadius.all(Radius.circular(8)),
),
labelStyle: TextStyle(
fontFamily: FontsManager.fontFamily,
color: Colors.grey,
fontSize: FontSize.s16,
fontWeight: FontsManager.regular,
),
),
menuStyle: MenuStyle(
backgroundColor: MaterialStatePropertyAll(Colors.white),
padding: MaterialStatePropertyAll(EdgeInsets.all(8)),
),
),
///input decoration theme ///input decoration theme
inputDecorationTheme: InputDecorationTheme( inputDecorationTheme: InputDecorationTheme(
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(