mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-15 17:47:28 +00:00
Implemented home management and user invitation flows
This commit is contained in:
@ -27,7 +27,7 @@ if (flutterVersionName == null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace "com.example.syncrow.app"
|
namespace "com.example.syncrow_application"
|
||||||
compileSdkVersion 34
|
compileSdkVersion 34
|
||||||
ndkVersion flutter.ndkVersion
|
ndkVersion flutter.ndkVersion
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "com.example.syncrow.app"
|
applicationId "com.example.syncrow_application"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"client_info": {
|
"client_info": {
|
||||||
"mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
|
"mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
|
||||||
"android_client_info": {
|
"android_client_info": {
|
||||||
"package_name": "com.example.syncrow.app"
|
"package_name": "com.example.syncrow_application"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"oauth_client": [],
|
"oauth_client": [],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.syncrow.app
|
package com.example.syncrow_application
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
3
assets/icons/blue_checkbox_ic.svg
Normal file
3
assets/icons/blue_checkbox_ic.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 20.3799C5.52381 20.3799 1 15.8561 1 10.3799C1 4.90369 5.51613 0.379883 10.9923 0.379883C16.4685 0.379883 21 4.90369 21 10.3799C21 15.8561 16.4762 20.3799 11 20.3799ZM9.77112 15.4029C10.0553 15.4029 10.3011 15.2724 10.4854 14.9882L15.6467 6.90062C15.7619 6.73165 15.8618 6.52428 15.8618 6.33994C15.8618 5.93288 15.5008 5.67942 15.1244 5.67942C14.9017 5.67942 14.679 5.80999 14.51 6.07113L9.73272 13.6671L7.19048 10.4797C6.99078 10.2263 6.78341 10.1341 6.53763 10.1341C6.16129 10.1341 5.84639 10.4336 5.84639 10.8407C5.84639 11.0327 5.9232 11.2401 6.05376 11.4014L9.01843 14.9959C9.25653 15.2877 9.48694 15.4029 9.77112 15.4029Z" fill="#023DFE" fill-opacity="0.6"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 820 B |
3
assets/icons/empty_checkbox_ic.svg
Normal file
3
assets/icons/empty_checkbox_ic.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="0.5" y="0.5" width="20.62" height="20.62" rx="10.31" stroke="#AEAEB2"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 184 B |
@ -6,6 +6,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:onesignal_flutter/onesignal_flutter.dart';
|
import 'package:onesignal_flutter/onesignal_flutter.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
||||||
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart';
|
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart';
|
||||||
import 'package:syncrow_app/features/auth/model/user_model.dart';
|
import 'package:syncrow_app/features/auth/model/user_model.dart';
|
||||||
@ -22,6 +23,7 @@ import 'package:syncrow_app/generated/assets.dart';
|
|||||||
import 'package:syncrow_app/navigation/navigation_service.dart';
|
import 'package:syncrow_app/navigation/navigation_service.dart';
|
||||||
import 'package:syncrow_app/services/api/spaces_api.dart';
|
import 'package:syncrow_app/services/api/spaces_api.dart';
|
||||||
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
|
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
|
||||||
|
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||||
|
|
||||||
@ -31,11 +33,12 @@ class HomeCubit extends Cubit<HomeState> {
|
|||||||
HomeCubit._() : super(HomeInitial()) {
|
HomeCubit._() : super(HomeInitial()) {
|
||||||
checkIfNotificationPermissionGranted();
|
checkIfNotificationPermissionGranted();
|
||||||
if (selectedSpace == null) {
|
if (selectedSpace == null) {
|
||||||
fetchUnitsByUserId().then((value) {
|
fetchUnitsByUserId();
|
||||||
if (selectedSpace != null) {
|
// .then((value) {
|
||||||
fetchRoomsByUnitId(selectedSpace!);
|
// if (selectedSpace != null) {
|
||||||
}
|
// fetchRoomsByUnitId(selectedSpace!);
|
||||||
});
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +146,7 @@ class HomeCubit extends Cubit<HomeState> {
|
|||||||
changeSelectedSpace(SpaceModel space) {
|
changeSelectedSpace(SpaceModel space) {
|
||||||
selectedSpace = space;
|
selectedSpace = space;
|
||||||
emitSafe(SpaceSelected(space));
|
emitSafe(SpaceSelected(space));
|
||||||
|
fetchRoomsByUnitId(space);
|
||||||
}
|
}
|
||||||
|
|
||||||
roomSliderPageChanged(int index) {
|
roomSliderPageChanged(int index) {
|
||||||
@ -193,6 +197,39 @@ class HomeCubit extends Cubit<HomeState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////// API ////////////////////////////////////////
|
//////////////////////////////////////// API ////////////////////////////////////////
|
||||||
|
generateInvitation(String unitId) async {
|
||||||
|
try {
|
||||||
|
final invitationCode = await SpacesAPI.generateInvitationCode(unitId);
|
||||||
|
if (invitationCode.isNotEmpty) {
|
||||||
|
Share.share('The invitation code is $invitationCode');
|
||||||
|
CustomSnackBar.displaySnackBar(
|
||||||
|
'Invitation code generated successfully the code is: $invitationCode');
|
||||||
|
} else {
|
||||||
|
CustomSnackBar.displaySnackBar('Please try again!');
|
||||||
|
}
|
||||||
|
} catch (failure) {
|
||||||
|
CustomSnackBar.displaySnackBar('Something went wrong');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> joinAUnit(String code) async {
|
||||||
|
try {
|
||||||
|
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
|
||||||
|
Map<String, String> body = {'userUuid': uuid, 'inviteCode': code};
|
||||||
|
|
||||||
|
final success = await SpacesAPI.joinUnit(body);
|
||||||
|
if (success) {
|
||||||
|
await fetchUnitsByUserId();
|
||||||
|
CustomSnackBar.displaySnackBar('Done successfully');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (failure) {
|
||||||
|
CustomSnackBar.displaySnackBar('Something went wrong');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fetchUnitsByUserId() async {
|
fetchUnitsByUserId() async {
|
||||||
emitSafe(GetSpacesLoading());
|
emitSafe(GetSpacesLoading());
|
||||||
try {
|
try {
|
||||||
@ -204,8 +241,8 @@ class HomeCubit extends Cubit<HomeState> {
|
|||||||
|
|
||||||
if (spaces != null && spaces!.isNotEmpty) {
|
if (spaces != null && spaces!.isNotEmpty) {
|
||||||
selectedSpace = spaces!.first;
|
selectedSpace = spaces!.first;
|
||||||
|
await fetchRoomsByUnitId(selectedSpace!);
|
||||||
emitSafe(GetSpacesSuccess(spaces!));
|
emitSafe(GetSpacesSuccess(spaces!));
|
||||||
// fetchRoomsByUnitId(selectedSpace!);
|
|
||||||
} else {
|
} else {
|
||||||
emitSafe(GetSpacesError("No spaces found"));
|
emitSafe(GetSpacesError("No spaces found"));
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,9 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
leadingWidth: 150,
|
leadingWidth: 150,
|
||||||
toolbarHeight: Constants.appBarHeight,
|
toolbarHeight: Constants.appBarHeight,
|
||||||
leading: HomeCubit.getInstance().spaces!.isNotEmpty
|
leading: HomeCubit.getInstance().spaces!.isNotEmpty
|
||||||
? HomeCubit.appBarLeading[
|
? HomeCubit.appBarLeading[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
|
||||||
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
|
|
||||||
: null,
|
: null,
|
||||||
actions: HomeCubit.appBarActions[
|
// actions: HomeCubit.appBarActions[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
|
||||||
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
|
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:dio/dio.dart';
|
|
||||||
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_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
@ -9,6 +8,7 @@ import 'package:syncrow_app/features/auth/model/user_model.dart';
|
|||||||
import 'package:syncrow_app/navigation/navigation_service.dart';
|
import 'package:syncrow_app/navigation/navigation_service.dart';
|
||||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||||
import 'package:syncrow_app/services/api/authentication_api.dart';
|
import 'package:syncrow_app/services/api/authentication_api.dart';
|
||||||
|
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||||
part 'auth_state.dart';
|
part 'auth_state.dart';
|
||||||
|
|
||||||
class AuthCubit extends Cubit<AuthState> {
|
class AuthCubit extends Cubit<AuthState> {
|
||||||
@ -26,6 +26,7 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
final loginFormKey = GlobalKey<FormState>();
|
final loginFormKey = GlobalKey<FormState>();
|
||||||
final signUpFormKey = GlobalKey<FormState>();
|
final signUpFormKey = GlobalKey<FormState>();
|
||||||
bool isPasswordVisible = false;
|
bool isPasswordVisible = false;
|
||||||
|
bool showValidationMessage = false;
|
||||||
|
|
||||||
static GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
static GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
if (value.isNotEmpty) {
|
if (value.isNotEmpty) {
|
||||||
if (!RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$')
|
if (!RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$')
|
||||||
.hasMatch(value)) {
|
.hasMatch(value)) {
|
||||||
return 'Password must contain at least one uppercase letter, one lowercase letter, one number and one special character';
|
return 'Password must contain at least:\n - one uppercase letter.\n - one lowercase letter.\n - one number. \n - special character';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,6 +148,12 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
login() async {
|
login() async {
|
||||||
emit(AuthLoginLoading());
|
emit(AuthLoginLoading());
|
||||||
try {
|
try {
|
||||||
|
if (emailController.text.isEmpty || passwordController.text.isEmpty) {
|
||||||
|
CustomSnackBar.displaySnackBar('Please enter your credentials');
|
||||||
|
emit(AuthLoginError(message: 'Something went wrong'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
token = await AuthenticationAPI.loginWithEmail(
|
token = await AuthenticationAPI.loginWithEmail(
|
||||||
model: LoginWithEmailModel(
|
model: LoginWithEmailModel(
|
||||||
email: emailController.text.toLowerCase(),
|
email: emailController.text.toLowerCase(),
|
||||||
|
@ -86,7 +86,7 @@ class SignUpView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Form(
|
Form(
|
||||||
key: formKey,
|
key: formKey,
|
||||||
autovalidateMode: AutovalidateMode.disabled,
|
// autovalidateMode: AutovalidateMode.disabled,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -96,14 +96,15 @@ class SignUpView extends StatelessWidget {
|
|||||||
fontColor: Colors.white,
|
fontColor: Colors.white,
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autovalidateMode: AutovalidateMode.disabled,
|
// autovalidateMode: AutovalidateMode.disabled,
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.name,
|
keyboardType: TextInputType.name,
|
||||||
scrollPadding: EdgeInsets.zero,
|
scrollPadding: EdgeInsets.zero,
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
autofillHints: const [AutofillHints.name],
|
autofillHints: const [AutofillHints.name],
|
||||||
// controller: AuthCubit.get(context).fullNameController,
|
// controller: AuthCubit.get(context).fullNameController,
|
||||||
validator: AuthCubit.get(context).fullNameValidator,
|
validator: (value) =>
|
||||||
|
AuthCubit.get(context).fullNameValidator(value),
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
@ -119,7 +120,7 @@ class SignUpView extends StatelessWidget {
|
|||||||
fontColor: Colors.white,
|
fontColor: Colors.white,
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autovalidateMode: AutovalidateMode.disabled,
|
// autovalidateMode: AutovalidateMode.disabled,
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
scrollPadding: EdgeInsets.zero,
|
scrollPadding: EdgeInsets.zero,
|
||||||
@ -141,7 +142,7 @@ class SignUpView extends StatelessWidget {
|
|||||||
fontColor: Colors.white,
|
fontColor: Colors.white,
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autovalidateMode: AutovalidateMode.disabled,
|
// autovalidateMode: AutovalidateMode.disabled,
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
scrollPadding: EdgeInsets.zero,
|
scrollPadding: EdgeInsets.zero,
|
||||||
@ -199,6 +200,7 @@ class SignUpView extends StatelessWidget {
|
|||||||
'Sign up',
|
'Sign up',
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
AuthCubit.get(context).showValidationMessage = true;
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
if ((state is! AuthLoading)) {
|
if ((state is! AuthLoading)) {
|
||||||
AuthCubit.get(context).signUp();
|
AuthCubit.get(context).signUp();
|
||||||
|
@ -65,7 +65,7 @@ class LoginForm extends StatelessWidget {
|
|||||||
if (state is AuthTokenError && !pressed) {
|
if (state is AuthTokenError && !pressed) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return AuthCubit.get(context).passwordValidator(value);
|
// return AuthCubit.get(context).passwordValidator(value);
|
||||||
},
|
},
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||||
import 'package:syncrow_app/features/auth/model/user_model.dart';
|
import 'package:syncrow_app/features/auth/model/user_model.dart';
|
||||||
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
|
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
|
||||||
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
|
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
|
||||||
import 'package:syncrow_app/services/api/home_creation_api.dart';
|
import 'package:syncrow_app/services/api/home_creation_api.dart';
|
||||||
|
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||||
|
|
||||||
class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
|
class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
|
||||||
List<String> rooms = [];
|
List<String> rooms = [];
|
||||||
@ -45,11 +47,16 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
|
|||||||
|
|
||||||
void _save(SaveRooms event, Emitter<CreateUnitState> emit) async {
|
void _save(SaveRooms event, Emitter<CreateUnitState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(LoadingState());
|
if (event.unitName.isEmpty) {
|
||||||
if (rooms.isEmpty) {
|
CustomSnackBar.displaySnackBar('Please enter the unit name');
|
||||||
const ErrorState(message: 'Please add at least one room!');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (rooms.isEmpty) {
|
||||||
|
CustomSnackBar.displaySnackBar('Please add at least one room!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(LoadingState());
|
||||||
|
|
||||||
var storage = const FlutterSecureStorage();
|
var storage = const FlutterSecureStorage();
|
||||||
var userId = await storage.read(key: UserModel.userUuidKey) ?? '';
|
var userId = await storage.read(key: UserModel.userUuidKey) ?? '';
|
||||||
@ -83,6 +90,7 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
|
|||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
await HomeCubit.getInstance().fetchUnitsByUserId();
|
||||||
emit(RoomsSavedSuccessfully());
|
emit(RoomsSavedSuccessfully());
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
emit(const ErrorState(message: 'Something went wrong'));
|
emit(const ErrorState(message: 'Something went wrong'));
|
||||||
|
112
lib/features/menu/bloc/manage_unit_bloc/manage_unit_bloc.dart
Normal file
112
lib/features/menu/bloc/manage_unit_bloc/manage_unit_bloc.dart
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_event.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_state.dart';
|
||||||
|
import 'package:syncrow_app/services/api/devices_api.dart';
|
||||||
|
import 'package:syncrow_app/services/api/home_creation_api.dart';
|
||||||
|
import 'package:syncrow_app/services/api/home_management_api.dart';
|
||||||
|
import 'package:syncrow_app/services/api/spaces_api.dart';
|
||||||
|
|
||||||
|
class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
|
||||||
|
List<DeviceModel> allDevices = [];
|
||||||
|
String unitName = '';
|
||||||
|
|
||||||
|
ManageUnitBloc() : super(InitialState()) {
|
||||||
|
on<FetchRoomsEvent>(_fetchRoomsAndDevices);
|
||||||
|
on<FetchDevicesByRoomIdEvent>(_fetchDevicesByRoomId);
|
||||||
|
on<AssignRoomEvent>(_assignDevice);
|
||||||
|
on<AddNewRoom>(_addNewRoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _fetchRoomsAndDevices(FetchRoomsEvent event, Emitter<ManageUnitState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(LoadingState());
|
||||||
|
final roomsList = await SpacesAPI.getRoomsBySpaceId(event.unitId);
|
||||||
|
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
|
||||||
|
} catch (e) {
|
||||||
|
emit(const ErrorState(message: 'Something went wrong'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _fetchDevicesByRoomId(FetchDevicesByRoomIdEvent event, Emitter<ManageUnitState> emit) async {
|
||||||
|
try {
|
||||||
|
Map<String, bool> roomDevicesId = {};
|
||||||
|
emit(LoadingState());
|
||||||
|
final devicesList = await DevicesAPI.getDevicesByRoomId(event.roomId);
|
||||||
|
allDevices = await HomeManagementAPI.fetchDevicesByUserId();
|
||||||
|
|
||||||
|
List<String> allDevicesIds = [];
|
||||||
|
|
||||||
|
allDevices.forEach((element) {
|
||||||
|
allDevicesIds.add(element.uuid!);
|
||||||
|
});
|
||||||
|
|
||||||
|
devicesList.forEach((e) {
|
||||||
|
if (allDevicesIds.contains(e.uuid!)) {
|
||||||
|
roomDevicesId[e.uuid!] = true;
|
||||||
|
} else {
|
||||||
|
roomDevicesId[e.uuid!] = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emit(FetchDeviceByRoomIdState(
|
||||||
|
roomDevices: devicesList,
|
||||||
|
allDevices: allDevices,
|
||||||
|
roomDevicesId: roomDevicesId,
|
||||||
|
roomId: event.roomId));
|
||||||
|
} catch (e) {
|
||||||
|
emit(const ErrorState(message: 'Something went wrong'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _assignDevice(AssignRoomEvent event, Emitter<ManageUnitState> emit) async {
|
||||||
|
try {
|
||||||
|
Map<String, bool> roomDevicesId = {};
|
||||||
|
emit(LoadingState());
|
||||||
|
Map<String, String> body = {"deviceUuid": event.deviceId, "roomUuid": event.roomId};
|
||||||
|
await HomeManagementAPI.assignDeviceToRoom(body);
|
||||||
|
final devicesList = await DevicesAPI.getDevicesByRoomId(event.roomId);
|
||||||
|
|
||||||
|
List<String> allDevicesIds = [];
|
||||||
|
|
||||||
|
allDevices.forEach((element) {
|
||||||
|
allDevicesIds.add(element.uuid!);
|
||||||
|
});
|
||||||
|
|
||||||
|
devicesList.forEach((e) {
|
||||||
|
if (allDevicesIds.contains(e.uuid!)) {
|
||||||
|
roomDevicesId[e.uuid!] = true;
|
||||||
|
} else {
|
||||||
|
roomDevicesId[e.uuid!] = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emit(FetchDeviceByRoomIdState(
|
||||||
|
roomDevices: devicesList,
|
||||||
|
allDevices: allDevices,
|
||||||
|
roomDevicesId: roomDevicesId,
|
||||||
|
roomId: event.roomId));
|
||||||
|
} catch (e) {
|
||||||
|
emit(const ErrorState(message: 'Something went wrong'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_addNewRoom(AddNewRoom event, Emitter<ManageUnitState> emit) async {
|
||||||
|
Map<String, String> body = {'roomName': event.roomName, 'unitUuid': event.unitId};
|
||||||
|
try {
|
||||||
|
emit(LoadingState());
|
||||||
|
final response = await HomeCreation.createRoom(body);
|
||||||
|
if (response['data']['uuid'] != '') {
|
||||||
|
final roomsList = await SpacesAPI.getRoomsBySpaceId(event.unitId);
|
||||||
|
allDevices = await HomeManagementAPI.fetchDevicesByUserId();
|
||||||
|
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
|
||||||
|
} else {
|
||||||
|
emit(const ErrorState(message: 'Something went wrong'));
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
emit(const ErrorState(message: 'Something went wrong'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
abstract class ManageUnitEvent extends Equatable {
|
||||||
|
const ManageUnitEvent();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class InitialEvent extends ManageUnitEvent {}
|
||||||
|
|
||||||
|
class LoadingEvent extends ManageUnitEvent {}
|
||||||
|
|
||||||
|
class FetchRoomsEvent extends ManageUnitEvent {
|
||||||
|
final String unitId;
|
||||||
|
|
||||||
|
const FetchRoomsEvent({required this.unitId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [unitId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class FetchDevicesByRoomIdEvent extends ManageUnitEvent {
|
||||||
|
final String roomId;
|
||||||
|
|
||||||
|
const FetchDevicesByRoomIdEvent({required this.roomId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [roomId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddNewRoom extends ManageUnitEvent {
|
||||||
|
final String roomName;
|
||||||
|
final String unitId;
|
||||||
|
|
||||||
|
const AddNewRoom({required this.roomName, required this.unitId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [roomName, unitId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssignRoomEvent extends ManageUnitEvent {
|
||||||
|
final String roomId;
|
||||||
|
final String deviceId;
|
||||||
|
|
||||||
|
const AssignRoomEvent({required this.roomId, required this.deviceId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [roomId];
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/room_model.dart';
|
||||||
|
|
||||||
|
abstract class ManageUnitState extends Equatable {
|
||||||
|
const ManageUnitState();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class InitialState extends ManageUnitState {}
|
||||||
|
|
||||||
|
class LoadingState extends ManageUnitState {}
|
||||||
|
|
||||||
|
class FetchRoomsState extends ManageUnitState {
|
||||||
|
final List<RoomModel> roomsList;
|
||||||
|
final List<DeviceModel> devicesList;
|
||||||
|
|
||||||
|
const FetchRoomsState({required this.devicesList, required this.roomsList});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [devicesList];
|
||||||
|
}
|
||||||
|
|
||||||
|
class FetchDeviceByRoomIdState extends ManageUnitState {
|
||||||
|
final List<DeviceModel> roomDevices;
|
||||||
|
final List<DeviceModel> allDevices;
|
||||||
|
final Map<String, bool> roomDevicesId;
|
||||||
|
final String roomId;
|
||||||
|
|
||||||
|
const FetchDeviceByRoomIdState(
|
||||||
|
{required this.roomDevices,
|
||||||
|
required this.allDevices,
|
||||||
|
required this.roomDevicesId,
|
||||||
|
required this.roomId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [roomDevices, allDevices, roomDevicesId, roomId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssignRoomState extends ManageUnitState {}
|
||||||
|
|
||||||
|
class ErrorState extends ManageUnitState {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const ErrorState({required this.message});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [message];
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// ignore_for_file: unnecessary_const
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_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/home_cubit.dart';
|
||||||
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_bloc.dart';
|
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_bloc.dart';
|
||||||
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
|
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
|
||||||
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
|
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
|
||||||
@ -23,37 +23,33 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
String unitName = '';
|
String unitName = '';
|
||||||
String location = '';
|
|
||||||
TextEditingController textEditingController = TextEditingController();
|
TextEditingController textEditingController = TextEditingController();
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => CreateUnitBloc(),
|
create: (context) => CreateUnitBloc(),
|
||||||
child: BlocConsumer<CreateUnitBloc, CreateUnitState>(listener: (context, state) {
|
child: BlocConsumer<CreateUnitBloc, CreateUnitState>(
|
||||||
|
listener: (context, state) {
|
||||||
if (state is RoomsSavedSuccessfully) {
|
if (state is RoomsSavedSuccessfully) {
|
||||||
CustomSnackBar.displaySnackBar('Saved successfully');
|
CustomSnackBar.displaySnackBar('Unit created successfully');
|
||||||
NavigationService.navigatorKey.currentState!.pushNamedAndRemoveUntil(
|
Navigator.of(context).pop();
|
||||||
Routes.homeRoute,
|
|
||||||
(Route route) => false,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state is ErrorState) {
|
if (state is ErrorState) {
|
||||||
CustomSnackBar.displaySnackBar(state.message);
|
CustomSnackBar.displaySnackBar(state.message);
|
||||||
}
|
}
|
||||||
}, builder: (context, state) {
|
},
|
||||||
|
builder: (context, state) {
|
||||||
textEditingController.text = '';
|
textEditingController.text = '';
|
||||||
return DefaultScaffold(
|
return DefaultScaffold(
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (unitName.isNotEmpty) {
|
|
||||||
BlocProvider.of<CreateUnitBloc>(context).add(SaveRooms(
|
BlocProvider.of<CreateUnitBloc>(context).add(SaveRooms(
|
||||||
communityName: 'Community Test',
|
communityName: 'Community Test',
|
||||||
buildingName: 'Building Test',
|
buildingName: 'Building Test',
|
||||||
floorName: 'Floor Test',
|
floorName: 'Floor Test',
|
||||||
unitName: unitName));
|
unitName: unitName,
|
||||||
} else {
|
));
|
||||||
CustomSnackBar.displaySnackBar('Please enter the unit name');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
child: const BodyLarge(
|
child: const BodyLarge(
|
||||||
text: 'Save',
|
text: 'Save',
|
||||||
@ -66,7 +62,11 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.symmetric(vertical: 40),
|
padding: const EdgeInsets.symmetric(vertical: 40),
|
||||||
width: MediaQuery.sizeOf(context).width,
|
width: MediaQuery.sizeOf(context).width,
|
||||||
height: MediaQuery.sizeOf(context).height,
|
height: MediaQuery.sizeOf(context).height,
|
||||||
child: SingleChildScrollView(
|
child: state is LoadingState
|
||||||
|
? const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
)
|
||||||
|
: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// Home Info
|
// Home Info
|
||||||
@ -91,7 +91,8 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Enter Name',
|
hintText: 'Enter Name',
|
||||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
hintStyle:
|
||||||
|
context.bodyMedium.copyWith(color: Colors.grey),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -108,12 +109,11 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
Flexible(
|
Flexible(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
onChanged: (value) {
|
onChanged: (value) {},
|
||||||
location = value;
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Set',
|
hintText: 'Set',
|
||||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
hintStyle:
|
||||||
|
context.bodyMedium.copyWith(color: Colors.grey),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -140,10 +140,17 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
DefaultContainer(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
// margin: EdgeInsets.zero,
|
||||||
horizontal: 25,
|
// margin: const EdgeInsets.symmetric(
|
||||||
vertical: 5,
|
// horizontal: 25,
|
||||||
|
// vertical: 5,
|
||||||
|
// ),
|
||||||
|
decoration: const ShapeDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -153,11 +160,9 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
if (state.roomList.isNotEmpty)
|
if (state.roomList.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
ListView.separated(
|
||||||
height: (state.roomList.length) * 55,
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
child: ListView.separated(
|
shrinkWrap: true,
|
||||||
physics:
|
|
||||||
const NeverScrollableScrollPhysics(), // Disable scrolling
|
|
||||||
separatorBuilder: (context, index) => const Divider(
|
separatorBuilder: (context, index) => const Divider(
|
||||||
color: ColorsManager.greyColor,
|
color: ColorsManager.greyColor,
|
||||||
),
|
),
|
||||||
@ -173,7 +178,8 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(index == 0 ? 20 : 0),
|
topLeft: Radius.circular(index == 0 ? 20 : 0),
|
||||||
topRight: Radius.circular(index == 0 ? 20 : 0),
|
topRight:
|
||||||
|
Radius.circular(index == 0 ? 20 : 0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -196,7 +202,8 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 16, horizontal: 25),
|
||||||
child: Text(
|
child: Text(
|
||||||
state.roomList[index],
|
state.roomList[index],
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@ -209,50 +216,54 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
const Divider(
|
const Divider(
|
||||||
color: ColorsManager.greyColor,
|
color: ColorsManager.greyColor,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 5),
|
||||||
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (textEditingController.text.isEmpty) {
|
if (textEditingController.text.isEmpty) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Please add the room name')),
|
const SnackBar(
|
||||||
|
content: Text('Please add the room name')),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BlocProvider.of<CreateUnitBloc>(context)
|
BlocProvider.of<CreateUnitBloc>(context).add(
|
||||||
.add(CreateRoomEvent(roomName: textEditingController.text));
|
CreateRoomEvent(
|
||||||
|
roomName: textEditingController.text));
|
||||||
|
textEditingController.clear();
|
||||||
},
|
},
|
||||||
child: const Row(
|
child: const Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
BodyMedium(
|
BodyMedium(
|
||||||
text: 'Add Space',
|
text: 'Add custom Space',
|
||||||
fontColor: ColorsManager.primaryColor,
|
fontColor: ColorsManager.primaryColor,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
controller: textEditingController,
|
controller: textEditingController,
|
||||||
onChanged: (value) {
|
|
||||||
textEditingController.text = value;
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Set',
|
hintText: 'Set',
|
||||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
hintStyle:
|
||||||
|
context.bodyMedium.copyWith(color: Colors.grey),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -261,7 +272,8 @@ class CreateUnitView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
import 'package:syncrow_app/generated/assets.dart';
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
import 'package:syncrow_app/utils/context_extension.dart';
|
import 'package:syncrow_app/utils/context_extension.dart';
|
||||||
|
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||||
|
|
||||||
class JoinHomeView extends StatelessWidget {
|
class JoinHomeView extends StatelessWidget {
|
||||||
const JoinHomeView({super.key});
|
const JoinHomeView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
TextEditingController textEditingController = TextEditingController();
|
||||||
return DefaultScaffold(
|
return DefaultScaffold(
|
||||||
title: "Join a Home",
|
title: "Join a Home",
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -38,16 +41,27 @@ class JoinHomeView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
|
controller: textEditingController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Invitatoin code',
|
hintText: 'Invitatoin code',
|
||||||
hintStyle:
|
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||||
context.bodyMedium.copyWith(color: Colors.grey),
|
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {},
|
onPressed: () async {
|
||||||
|
if (textEditingController.text.isEmpty) {
|
||||||
|
CustomSnackBar.displaySnackBar('Please enter the invitation code');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (await HomeCubit.getInstance().joinAUnit(textEditingController.text)) {
|
||||||
|
CustomSnackBar.displaySnackBar('Done successfully');
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
} else {
|
||||||
|
CustomSnackBar.displaySnackBar('Wrong code!');
|
||||||
|
}
|
||||||
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.arrow_right_alt,
|
Icons.arrow_right_alt,
|
||||||
),
|
),
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_event.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_state.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
|
|
||||||
|
class AssignDeviceView extends StatelessWidget {
|
||||||
|
final String unitId;
|
||||||
|
final String roomId;
|
||||||
|
const AssignDeviceView({super.key, required this.unitId, required this.roomId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider(
|
||||||
|
create: (context) => ManageUnitBloc()..add(FetchDevicesByRoomIdEvent(roomId: roomId)),
|
||||||
|
child: BlocConsumer<ManageUnitBloc, ManageUnitState>(
|
||||||
|
listener: (context, state) {},
|
||||||
|
builder: (context, state) {
|
||||||
|
return DefaultScaffold(
|
||||||
|
title: 'Space Setting',
|
||||||
|
child: state is LoadingState
|
||||||
|
? const Center(child: RefreshProgressIndicator())
|
||||||
|
: state is FetchDeviceByRoomIdState
|
||||||
|
? Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
height: MediaQuery.sizeOf(context).height,
|
||||||
|
child: GridView.builder(
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2,
|
||||||
|
crossAxisSpacing: 10.0,
|
||||||
|
mainAxisSpacing: 10.0,
|
||||||
|
childAspectRatio: 1.0,
|
||||||
|
),
|
||||||
|
itemCount: state.allDevices.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
state.allDevices[index].icon!,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (state.roomDevicesId[
|
||||||
|
state.allDevices[index].uuid!] ??
|
||||||
|
false == false) {
|
||||||
|
BlocProvider.of<ManageUnitBloc>(context).add(
|
||||||
|
AssignRoomEvent(
|
||||||
|
deviceId:
|
||||||
|
state.allDevices[index].uuid ??
|
||||||
|
'',
|
||||||
|
roomId: roomId));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
state.roomDevicesId[
|
||||||
|
state.allDevices[index].uuid!] ??
|
||||||
|
false
|
||||||
|
? Assets.blueCheckboxIcon
|
||||||
|
: Assets.emptyCheckboxIcon,
|
||||||
|
width: 22,
|
||||||
|
height: 22,
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(state.allDevices[index].name ?? ''),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
: Container());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||||
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/manage_home/room_screen.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||||
import 'package:syncrow_app/utils/context_extension.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/color_manager.dart';
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
|
||||||
class HomeSettingsView extends StatelessWidget {
|
class HomeSettingsView extends StatelessWidget {
|
||||||
@ -38,8 +42,7 @@ class HomeSettingsView extends StatelessWidget {
|
|||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Enter Name',
|
hintText: 'Enter Name',
|
||||||
hintStyle:
|
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||||
context.bodyMedium.copyWith(color: Colors.grey),
|
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -52,7 +55,16 @@ class HomeSettingsView extends StatelessWidget {
|
|||||||
height: 1,
|
height: 1,
|
||||||
color: ColorsManager.greyColor,
|
color: ColorsManager.greyColor,
|
||||||
),
|
),
|
||||||
const Row(
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(CustomPageRoute(
|
||||||
|
builder: (context) => RoomsView(
|
||||||
|
unitId: space?.id ?? '',
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
child: const Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
BodyMedium(text: 'Rooms'),
|
BodyMedium(text: 'Rooms'),
|
||||||
@ -63,6 +75,8 @@ class HomeSettingsView extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
//Divider
|
//Divider
|
||||||
Container(
|
Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
@ -78,14 +92,39 @@ class HomeSettingsView extends StatelessWidget {
|
|||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Set',
|
hintText: 'Set',
|
||||||
hintStyle:
|
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||||
context.bodyMedium.copyWith(color: Colors.grey),
|
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
//Divider
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(bottom: 10),
|
||||||
|
height: 1,
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
padding: const EdgeInsets.only(bottom: 10),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () async {
|
||||||
|
await HomeCubit.getInstance().generateInvitation(space?.id ?? '');
|
||||||
|
},
|
||||||
|
child: const Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
BodyMedium(text: 'Invite a member'),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
size: 15,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -104,14 +143,13 @@ class HomeSettingsView extends StatelessWidget {
|
|||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
crossAxisSpacing: 10,
|
crossAxisSpacing: 10,
|
||||||
),
|
),
|
||||||
itemCount: 4,
|
itemCount: 2,
|
||||||
itemBuilder: (context, index) => Stack(
|
itemBuilder: (context, index) => Stack(
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
children: [
|
children: [
|
||||||
DefaultContainer(
|
DefaultContainer(
|
||||||
margin: const EdgeInsets.only(top: 20),
|
margin: const EdgeInsets.only(top: 20),
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 40),
|
||||||
const EdgeInsets.symmetric(vertical: 15, horizontal: 40),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
137
lib/features/menu/view/widgets/manage_home/room_screen.dart
Normal file
137
lib/features/menu/view/widgets/manage_home/room_screen.dart
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_event.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_state.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/manage_home/assign_devices.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.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/helpers/snack_bar.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
|
||||||
|
class RoomsView extends StatelessWidget {
|
||||||
|
final String unitId;
|
||||||
|
const RoomsView({super.key, required this.unitId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
TextEditingController textEditingController = TextEditingController();
|
||||||
|
return BlocProvider(
|
||||||
|
create: (context) => ManageUnitBloc()..add(FetchRoomsEvent(unitId: unitId)),
|
||||||
|
child: BlocConsumer<ManageUnitBloc, ManageUnitState>(
|
||||||
|
listener: (context, state) {},
|
||||||
|
builder: (context, state) {
|
||||||
|
return DefaultScaffold(
|
||||||
|
title: 'Space Management',
|
||||||
|
child: state is LoadingState
|
||||||
|
? const Center(child: RefreshProgressIndicator())
|
||||||
|
: Container(
|
||||||
|
margin: const EdgeInsets.only(top: 32),
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
height: MediaQuery.sizeOf(context).height,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (state is FetchRoomsState)
|
||||||
|
Container(
|
||||||
|
decoration: const ShapeDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (state.roomsList.isNotEmpty)
|
||||||
|
ListView.separated(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
separatorBuilder: (context, index) => const Divider(
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
),
|
||||||
|
itemCount: state.roomsList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// BlocProvider.of<ManageUnitBloc>(context).add(
|
||||||
|
// FetchDevicesByRoomIdEvent(roomId: roomId));
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => AssignDeviceView(
|
||||||
|
roomId: state.roomsList[index].id ?? '',
|
||||||
|
unitId: unitId,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 50,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 16, horizontal: 25),
|
||||||
|
child: Text(
|
||||||
|
state.roomsList[index].name ?? '',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xFF5D5D5D),
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 25, vertical: 5),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (textEditingController.text.isEmpty) {
|
||||||
|
CustomSnackBar.displaySnackBar(
|
||||||
|
'Please add the room name');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlocProvider.of<ManageUnitBloc>(context).add(
|
||||||
|
AddNewRoom(
|
||||||
|
roomName: textEditingController.text,
|
||||||
|
unitId: unitId));
|
||||||
|
textEditingController.clear();
|
||||||
|
},
|
||||||
|
child: const Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
BodyMedium(
|
||||||
|
text: 'Add Space',
|
||||||
|
fontColor: ColorsManager.primaryColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: TextField(
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
controller: textEditingController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Set',
|
||||||
|
hintStyle:
|
||||||
|
context.bodyMedium.copyWith(color: Colors.grey),
|
||||||
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
@ -8,12 +8,7 @@ import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
|||||||
|
|
||||||
class DefaultScaffold extends StatelessWidget {
|
class DefaultScaffold extends StatelessWidget {
|
||||||
const DefaultScaffold(
|
const DefaultScaffold(
|
||||||
{super.key,
|
{super.key, required this.child, this.title, this.actions, this.appBar, this.bottomNavBar});
|
||||||
required this.child,
|
|
||||||
this.title,
|
|
||||||
this.actions,
|
|
||||||
this.appBar,
|
|
||||||
this.bottomNavBar});
|
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final String? title;
|
final String? title;
|
||||||
@ -46,8 +41,7 @@ class DefaultScaffold extends StatelessWidget {
|
|||||||
body: Container(
|
body: Container(
|
||||||
width: MediaQuery.sizeOf(context).width,
|
width: MediaQuery.sizeOf(context).width,
|
||||||
height: MediaQuery.sizeOf(context).height,
|
height: MediaQuery.sizeOf(context).height,
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
|
||||||
const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
|
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: AssetImage(
|
image: AssetImage(
|
||||||
|
@ -647,6 +647,9 @@ class Assets {
|
|||||||
|
|
||||||
static const String assetsDeleteIcon = "assets/icons/delete_room_ic.svg";
|
static const String assetsDeleteIcon = "assets/icons/delete_room_ic.svg";
|
||||||
|
|
||||||
|
static const String blueCheckboxIcon = "assets/icons/blue_checkbox_ic.svg";
|
||||||
|
static const String emptyCheckboxIcon = "assets/icons/empty_checkbox_ic.svg";
|
||||||
|
|
||||||
/// Assets for assetsImagesAutomation
|
/// Assets for assetsImagesAutomation
|
||||||
/// assets/images/automation.jpg
|
/// assets/images/automation.jpg
|
||||||
static const String assetsImagesAutomation = "assets/images/automation.jpg";
|
static const String assetsImagesAutomation = "assets/images/automation.jpg";
|
||||||
|
@ -6,7 +6,7 @@ import 'package:syncrow_app/features/auth/view/sign_up_view.dart';
|
|||||||
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
|
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
|
||||||
import 'package:syncrow_app/features/layout/view/layout_view.dart';
|
import 'package:syncrow_app/features/layout/view/layout_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/menu_view.dart';
|
import 'package:syncrow_app/features/menu/view/menu_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/home%20management/create_home_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/create_home/create_home_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/profile/profile_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/profile/profile_view.dart';
|
||||||
import 'package:syncrow_app/features/scene/view/scene_view.dart';
|
import 'package:syncrow_app/features/scene/view/scene_view.dart';
|
||||||
import 'package:syncrow_app/features/splash/view/splash_view.dart';
|
import 'package:syncrow_app/features/splash/view/splash_view.dart';
|
||||||
|
@ -57,6 +57,9 @@ abstract class ApiEndpoints {
|
|||||||
static const String unitChild = '$baseUrl/unit/child/';
|
static const String unitChild = '$baseUrl/unit/child/';
|
||||||
static const String unitParent = '$baseUrl/unit/parent/{unitUuid}';
|
static const String unitParent = '$baseUrl/unit/parent/{unitUuid}';
|
||||||
static const String unitUser = '$baseUrl/unit/user/';
|
static const String unitUser = '$baseUrl/unit/user/';
|
||||||
|
static const String invitationCode = '$baseUrl/unit/{unitUuid}/invitation-code';
|
||||||
|
static const String verifyInvitationCode = '$baseUrl/unit/user/verify-code';
|
||||||
|
|
||||||
//PUT
|
//PUT
|
||||||
static const String renameUnit = '$baseUrl/unit/rename/{unitUuid}';
|
static const String renameUnit = '$baseUrl/unit/rename/{unitUuid}';
|
||||||
|
|
||||||
@ -87,6 +90,8 @@ abstract class ApiEndpoints {
|
|||||||
static const String addDeviceToRoom = '$baseUrl/device/room';
|
static const String addDeviceToRoom = '$baseUrl/device/room';
|
||||||
static const String addDeviceToGroup = '$baseUrl/device/group';
|
static const String addDeviceToGroup = '$baseUrl/device/group';
|
||||||
static const String controlDevice = '$baseUrl/device/{deviceUuid}/control';
|
static const String controlDevice = '$baseUrl/device/{deviceUuid}/control';
|
||||||
|
static const String getDevicesByUserId = '$baseUrl/device/user/{userId}';
|
||||||
|
|
||||||
//GET
|
//GET
|
||||||
static const String deviceByRoom = '$baseUrl/device/room';
|
static const String deviceByRoom = '$baseUrl/device/room';
|
||||||
static const String deviceByUuid = '$baseUrl/device/{deviceUuid}';
|
static const String deviceByUuid = '$baseUrl/device/{deviceUuid}';
|
||||||
@ -100,4 +105,6 @@ abstract class ApiEndpoints {
|
|||||||
static const String devicePermissionList = '$baseUrl/device-permission/list';
|
static const String devicePermissionList = '$baseUrl/device-permission/list';
|
||||||
//PUT
|
//PUT
|
||||||
static const String editDevicePermission = '$baseUrl/device-permission/edit/{userId}';
|
static const String editDevicePermission = '$baseUrl/device-permission/edit/{userId}';
|
||||||
|
|
||||||
|
static const String assignDeviceToRoom = '$baseUrl/device/room';
|
||||||
}
|
}
|
||||||
|
40
lib/services/api/home_management_api.dart
Normal file
40
lib/services/api/home_management_api.dart
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:syncrow_app/features/auth/model/user_model.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||||
|
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
|
||||||
|
import 'package:syncrow_app/services/api/http_service.dart';
|
||||||
|
|
||||||
|
class HomeManagementAPI {
|
||||||
|
static final HTTPService _httpService = HTTPService();
|
||||||
|
|
||||||
|
static Future<List<DeviceModel>> fetchDevicesByUserId() async {
|
||||||
|
var storage = const FlutterSecureStorage();
|
||||||
|
var userId = await storage.read(key: UserModel.userUuidKey) ?? '';
|
||||||
|
|
||||||
|
List<DeviceModel> list = [];
|
||||||
|
await _httpService.get(
|
||||||
|
path: ApiEndpoints.getDevicesByUserId.replaceAll("{userId}", userId),
|
||||||
|
showServerMessage: false,
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
json.forEach((value) {
|
||||||
|
list.add(DeviceModel.fromJson(value));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, dynamic>> assignDeviceToRoom(Map<String, String> body) async {
|
||||||
|
try {
|
||||||
|
final response = await _httpService.put(
|
||||||
|
path: ApiEndpoints.assignDeviceToRoom,
|
||||||
|
body: body,
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
return json;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -79,6 +79,23 @@ class HTTPService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<T> put<T>(
|
||||||
|
{required String path,
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
dynamic body,
|
||||||
|
required T Function(dynamic) expectedResponseModel}) async {
|
||||||
|
try {
|
||||||
|
final response = await client.put(
|
||||||
|
path,
|
||||||
|
data: body,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
return expectedResponseModel(response.data);
|
||||||
|
} catch (error) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<T> download<T>(
|
Future<T> download<T>(
|
||||||
{required String path,
|
{required String path,
|
||||||
required String savePath,
|
required String savePath,
|
||||||
|
@ -9,8 +9,7 @@ class SpacesAPI {
|
|||||||
static final HTTPService _httpService = HTTPService();
|
static final HTTPService _httpService = HTTPService();
|
||||||
|
|
||||||
static Future<List<SpaceModel>> getUnitsByUserId() async {
|
static Future<List<SpaceModel>> getUnitsByUserId() async {
|
||||||
var uuid =
|
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
|
||||||
final response = await _httpService.get(
|
final response = await _httpService.get(
|
||||||
path: "${ApiEndpoints.unitUser}$uuid",
|
path: "${ApiEndpoints.unitUser}$uuid",
|
||||||
showServerMessage: false,
|
showServerMessage: false,
|
||||||
@ -34,4 +33,27 @@ class SpacesAPI {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<String> generateInvitationCode(
|
||||||
|
String unitId,
|
||||||
|
) async {
|
||||||
|
final response = await _httpService.get(
|
||||||
|
path: ApiEndpoints.invitationCode.replaceAll('{unitUuid}', unitId),
|
||||||
|
showServerMessage: false,
|
||||||
|
expectedResponseModel: (json) => json['invitationCode'],
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> joinUnit(
|
||||||
|
Map<String, String> body,
|
||||||
|
) async {
|
||||||
|
final response = await _httpService.post(
|
||||||
|
path: ApiEndpoints.verifyInvitationCode,
|
||||||
|
showServerMessage: false,
|
||||||
|
body: body,
|
||||||
|
expectedResponseModel: (json) => json['success'],
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:syncrow_app/features/devices/model/function_model.dart';
|
import 'package:syncrow_app/features/devices/model/function_model.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/home%20management/create_home_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/create_home/create_home_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/join_home/join_home_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/join_home/join_home_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/manage_home/manage_home_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/manage_home/manage_home_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/privacy/privacy_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/privacy/privacy_view.dart';
|
||||||
|
56
pubspec.lock
56
pubspec.lock
@ -89,6 +89,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.18.0"
|
version: "1.18.0"
|
||||||
|
cross_file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4+1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -197,10 +205,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_web
|
name: firebase_core_web
|
||||||
sha256: c8e1d59385eee98de63c92f961d2a7062c5d9a65e7f45bdc7f1b0b205aab2492
|
sha256: "22fcb352744908224fc7be3caae254836099786acfe5df6e9fe901e9c2575a41"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.5"
|
version: "2.17.1"
|
||||||
firebase_crashlytics:
|
firebase_crashlytics:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -377,10 +385,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.1"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -461,6 +469,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.5"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -645,6 +661,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.27.7"
|
version: "0.27.7"
|
||||||
|
share_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: share_plus
|
||||||
|
sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.0"
|
||||||
|
share_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_plus_platform_interface
|
||||||
|
sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -689,10 +721,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
|
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.3.0"
|
||||||
shared_preferences_windows:
|
shared_preferences_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -862,10 +894,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
|
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.3"
|
version: "2.3.1"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -926,10 +958,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0"
|
version: "0.5.1"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -955,5 +987,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "6.5.0"
|
version: "6.5.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.16.0"
|
flutter: ">=3.19.0"
|
||||||
|
@ -4,7 +4,7 @@ description: This is the mobile application project, developed with Flutter for
|
|||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
version: 1.0.1+2
|
version: 1.0.2+4
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.6 <4.0.0"
|
sdk: ">=3.0.6 <4.0.0"
|
||||||
@ -41,6 +41,7 @@ dependencies:
|
|||||||
onesignal_flutter: ^5.2.0
|
onesignal_flutter: ^5.2.0
|
||||||
permission_handler: ^11.3.1
|
permission_handler: ^11.3.1
|
||||||
pin_code_fields: ^8.0.1
|
pin_code_fields: ^8.0.1
|
||||||
|
share_plus: ^9.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user