mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2026-10-25 03:17:55 +00:00
Implemented home management and user invitation flows
This commit is contained in:
@@ -6,6 +6,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:onesignal_flutter/onesignal_flutter.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/view/widgets/app_bar_home_dropdown.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/services/api/spaces_api.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/constants.dart';
|
||||
|
||||
@@ -31,11 +33,12 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
HomeCubit._() : super(HomeInitial()) {
|
||||
checkIfNotificationPermissionGranted();
|
||||
if (selectedSpace == null) {
|
||||
fetchUnitsByUserId().then((value) {
|
||||
if (selectedSpace != null) {
|
||||
fetchRoomsByUnitId(selectedSpace!);
|
||||
}
|
||||
});
|
||||
fetchUnitsByUserId();
|
||||
// .then((value) {
|
||||
// if (selectedSpace != null) {
|
||||
// fetchRoomsByUnitId(selectedSpace!);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +146,7 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
changeSelectedSpace(SpaceModel space) {
|
||||
selectedSpace = space;
|
||||
emitSafe(SpaceSelected(space));
|
||||
fetchRoomsByUnitId(space);
|
||||
}
|
||||
|
||||
roomSliderPageChanged(int index) {
|
||||
@@ -193,6 +197,39 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
}
|
||||
|
||||
//////////////////////////////////////// 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 {
|
||||
emitSafe(GetSpacesLoading());
|
||||
try {
|
||||
@@ -204,8 +241,8 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
|
||||
if (spaces != null && spaces!.isNotEmpty) {
|
||||
selectedSpace = spaces!.first;
|
||||
await fetchRoomsByUnitId(selectedSpace!);
|
||||
emitSafe(GetSpacesSuccess(spaces!));
|
||||
// fetchRoomsByUnitId(selectedSpace!);
|
||||
} else {
|
||||
emitSafe(GetSpacesError("No spaces found"));
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
leadingWidth: 150,
|
||||
toolbarHeight: Constants.appBarHeight,
|
||||
leading: HomeCubit.getInstance().spaces!.isNotEmpty
|
||||
? HomeCubit.appBarLeading[
|
||||
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
|
||||
? HomeCubit.appBarLeading[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
|
||||
: null,
|
||||
actions: HomeCubit.appBarActions[
|
||||
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
|
||||
// actions: HomeCubit.appBarActions[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
|
||||
));
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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/routing_constants.dart';
|
||||
import 'package:syncrow_app/services/api/authentication_api.dart';
|
||||
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||
part 'auth_state.dart';
|
||||
|
||||
class AuthCubit extends Cubit<AuthState> {
|
||||
@@ -26,6 +26,7 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
final loginFormKey = GlobalKey<FormState>();
|
||||
final signUpFormKey = GlobalKey<FormState>();
|
||||
bool isPasswordVisible = false;
|
||||
bool showValidationMessage = false;
|
||||
|
||||
static GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
|
||||
@@ -58,7 +59,7 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
if (value.isNotEmpty) {
|
||||
if (!RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$')
|
||||
.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 {
|
||||
emit(AuthLoginLoading());
|
||||
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(
|
||||
model: LoginWithEmailModel(
|
||||
email: emailController.text.toLowerCase(),
|
||||
|
||||
@@ -86,7 +86,7 @@ class SignUpView extends StatelessWidget {
|
||||
),
|
||||
Form(
|
||||
key: formKey,
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
// autovalidateMode: AutovalidateMode.disabled,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -96,14 +96,15 @@ class SignUpView extends StatelessWidget {
|
||||
fontColor: Colors.white,
|
||||
),
|
||||
TextFormField(
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
// autovalidateMode: AutovalidateMode.disabled,
|
||||
textInputAction: TextInputAction.done,
|
||||
keyboardType: TextInputType.name,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
autocorrect: false,
|
||||
autofillHints: const [AutofillHints.name],
|
||||
// controller: AuthCubit.get(context).fullNameController,
|
||||
validator: AuthCubit.get(context).fullNameValidator,
|
||||
validator: (value) =>
|
||||
AuthCubit.get(context).fullNameValidator(value),
|
||||
onTapOutside: (event) {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
@@ -119,7 +120,7 @@ class SignUpView extends StatelessWidget {
|
||||
fontColor: Colors.white,
|
||||
),
|
||||
TextFormField(
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
// autovalidateMode: AutovalidateMode.disabled,
|
||||
textInputAction: TextInputAction.done,
|
||||
keyboardType: TextInputType.text,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
@@ -141,7 +142,7 @@ class SignUpView extends StatelessWidget {
|
||||
fontColor: Colors.white,
|
||||
),
|
||||
TextFormField(
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
// autovalidateMode: AutovalidateMode.disabled,
|
||||
textInputAction: TextInputAction.done,
|
||||
keyboardType: TextInputType.text,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
@@ -199,6 +200,7 @@ class SignUpView extends StatelessWidget {
|
||||
'Sign up',
|
||||
),
|
||||
onPressed: () {
|
||||
AuthCubit.get(context).showValidationMessage = true;
|
||||
if (formKey.currentState!.validate()) {
|
||||
if ((state is! AuthLoading)) {
|
||||
AuthCubit.get(context).signUp();
|
||||
|
||||
@@ -65,7 +65,7 @@ class LoginForm extends StatelessWidget {
|
||||
if (state is AuthTokenError && !pressed) {
|
||||
return null;
|
||||
}
|
||||
return AuthCubit.get(context).passwordValidator(value);
|
||||
// return AuthCubit.get(context).passwordValidator(value);
|
||||
},
|
||||
onTapOutside: (event) {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.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/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/services/api/home_creation_api.dart';
|
||||
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||
|
||||
class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
|
||||
List<String> rooms = [];
|
||||
@@ -45,11 +47,16 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
|
||||
|
||||
void _save(SaveRooms event, Emitter<CreateUnitState> emit) async {
|
||||
try {
|
||||
emit(LoadingState());
|
||||
if (rooms.isEmpty) {
|
||||
const ErrorState(message: 'Please add at least one room!');
|
||||
if (event.unitName.isEmpty) {
|
||||
CustomSnackBar.displaySnackBar('Please enter the unit name');
|
||||
return;
|
||||
}
|
||||
if (rooms.isEmpty) {
|
||||
CustomSnackBar.displaySnackBar('Please add at least one room!');
|
||||
return;
|
||||
}
|
||||
|
||||
emit(LoadingState());
|
||||
|
||||
var storage = const FlutterSecureStorage();
|
||||
var userId = await storage.read(key: UserModel.userUuidKey) ?? '';
|
||||
@@ -83,6 +90,7 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
|
||||
}
|
||||
// }
|
||||
}
|
||||
await HomeCubit.getInstance().fetchUnitsByUserId();
|
||||
emit(RoomsSavedSuccessfully());
|
||||
} catch (_) {
|
||||
emit(const ErrorState(message: 'Something went wrong'));
|
||||
|
||||
@@ -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_bloc/flutter_bloc.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_event.dart';
|
||||
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
|
||||
@@ -23,245 +23,257 @@ class CreateUnitView extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String unitName = '';
|
||||
String location = '';
|
||||
TextEditingController textEditingController = TextEditingController();
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => CreateUnitBloc(),
|
||||
child: BlocConsumer<CreateUnitBloc, CreateUnitState>(listener: (context, state) {
|
||||
if (state is RoomsSavedSuccessfully) {
|
||||
CustomSnackBar.displaySnackBar('Saved successfully');
|
||||
NavigationService.navigatorKey.currentState!.pushNamedAndRemoveUntil(
|
||||
Routes.homeRoute,
|
||||
(Route route) => false,
|
||||
);
|
||||
}
|
||||
child: BlocConsumer<CreateUnitBloc, CreateUnitState>(
|
||||
listener: (context, state) {
|
||||
if (state is RoomsSavedSuccessfully) {
|
||||
CustomSnackBar.displaySnackBar('Unit created successfully');
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
if (state is ErrorState) {
|
||||
CustomSnackBar.displaySnackBar(state.message);
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
textEditingController.text = '';
|
||||
return DefaultScaffold(
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (unitName.isNotEmpty) {
|
||||
if (state is ErrorState) {
|
||||
CustomSnackBar.displaySnackBar(state.message);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
textEditingController.text = '';
|
||||
return DefaultScaffold(
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
BlocProvider.of<CreateUnitBloc>(context).add(SaveRooms(
|
||||
communityName: 'Community Test',
|
||||
buildingName: 'Building Test',
|
||||
floorName: 'Floor Test',
|
||||
unitName: unitName));
|
||||
} else {
|
||||
CustomSnackBar.displaySnackBar('Please enter the unit name');
|
||||
}
|
||||
},
|
||||
child: const BodyLarge(
|
||||
text: 'Save',
|
||||
fontWeight: FontWeight.bold,
|
||||
communityName: 'Community Test',
|
||||
buildingName: 'Building Test',
|
||||
floorName: 'Floor Test',
|
||||
unitName: unitName,
|
||||
));
|
||||
},
|
||||
child: const BodyLarge(
|
||||
text: 'Save',
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
title: 'Create a Unit',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40),
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
//Home Info
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 25,
|
||||
vertical: 5,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodyMedium(text: 'Unit Name'),
|
||||
Flexible(
|
||||
child: TextField(
|
||||
textAlign: TextAlign.end,
|
||||
onChanged: (value) {
|
||||
unitName = value;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter Name',
|
||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
],
|
||||
title: 'Create a Unit',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40),
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
child: state is LoadingState
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// Home Info
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 25,
|
||||
vertical: 5,
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodyMedium(text: 'Location '),
|
||||
Flexible(
|
||||
child: TextField(
|
||||
textAlign: TextAlign.end,
|
||||
onChanged: (value) {
|
||||
location = value;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Set',
|
||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
//Rooms Info
|
||||
const SizedBox(height: 10),
|
||||
const Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 25,
|
||||
),
|
||||
BodySmall(
|
||||
text: 'Spaces',
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 25,
|
||||
vertical: 5,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
if (state is CreateRoomState)
|
||||
if (state.roomList.isNotEmpty)
|
||||
Column(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: (state.roomList.length) * 55,
|
||||
child: ListView.separated(
|
||||
physics:
|
||||
const NeverScrollableScrollPhysics(), // Disable scrolling
|
||||
separatorBuilder: (context, index) => const Divider(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
itemCount: state.roomList.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Dismissible(
|
||||
key: Key(state.roomList[index]),
|
||||
background: Container(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
decoration: ShapeDecoration(
|
||||
color: const Color(0xFFFF0000),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(index == 0 ? 20 : 0),
|
||||
topRight: Radius.circular(index == 0 ? 20 : 0),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets.assetsDeleteIcon,
|
||||
width: 20,
|
||||
height: 22,
|
||||
),
|
||||
),
|
||||
direction: DismissDirection.endToStart,
|
||||
onDismissed: (direction) {
|
||||
String removedUnit = state.roomList[index];
|
||||
|
||||
BlocProvider.of<CreateUnitBloc>(context)
|
||||
.add(RemoveRoomEvent(roomName: removedUnit));
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('$removedUnit removed')),
|
||||
);
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodyMedium(text: 'Unit Name'),
|
||||
Flexible(
|
||||
child: TextField(
|
||||
textAlign: TextAlign.end,
|
||||
onChanged: (value) {
|
||||
unitName = value;
|
||||
},
|
||||
child: Container(
|
||||
height: 50,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Text(
|
||||
state.roomList[index],
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF5D5D5D),
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter Name',
|
||||
hintStyle:
|
||||
context.bodyMedium.copyWith(color: Colors.grey),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (textEditingController.text.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Please add the room name')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
BlocProvider.of<CreateUnitBloc>(context)
|
||||
.add(CreateRoomEvent(roomName: textEditingController.text));
|
||||
},
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: 'Add Space',
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
const BodyMedium(text: 'Location '),
|
||||
Flexible(
|
||||
child: TextField(
|
||||
textAlign: TextAlign.end,
|
||||
onChanged: (value) {},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Set',
|
||||
hintStyle:
|
||||
context.bodyMedium.copyWith(color: Colors.grey),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Flexible(
|
||||
child: TextField(
|
||||
textAlign: TextAlign.end,
|
||||
controller: textEditingController,
|
||||
onChanged: (value) {
|
||||
textEditingController.text = value;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Set',
|
||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Rooms Info
|
||||
const SizedBox(height: 10),
|
||||
const Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 25,
|
||||
),
|
||||
BodySmall(
|
||||
text: 'Spaces',
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Container(
|
||||
// margin: EdgeInsets.zero,
|
||||
// margin: const EdgeInsets.symmetric(
|
||||
// horizontal: 25,
|
||||
// vertical: 5,
|
||||
// ),
|
||||
decoration: const ShapeDecoration(
|
||||
color: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
if (state is CreateRoomState)
|
||||
if (state.roomList.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
ListView.separated(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
separatorBuilder: (context, index) => const Divider(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
itemCount: state.roomList.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Dismissible(
|
||||
key: Key(state.roomList[index]),
|
||||
background: Container(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
decoration: ShapeDecoration(
|
||||
color: const Color(0xFFFF0000),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(index == 0 ? 20 : 0),
|
||||
topRight:
|
||||
Radius.circular(index == 0 ? 20 : 0),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets.assetsDeleteIcon,
|
||||
width: 20,
|
||||
height: 22,
|
||||
),
|
||||
),
|
||||
direction: DismissDirection.endToStart,
|
||||
onDismissed: (direction) {
|
||||
String removedUnit = state.roomList[index];
|
||||
|
||||
BlocProvider.of<CreateUnitBloc>(context)
|
||||
.add(RemoveRoomEvent(roomName: removedUnit));
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('$removedUnit removed')),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
height: 50,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16, horizontal: 25),
|
||||
child: Text(
|
||||
state.roomList[index],
|
||||
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) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Please add the room name')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
BlocProvider.of<CreateUnitBloc>(context).add(
|
||||
CreateRoomEvent(
|
||||
roomName: textEditingController.text));
|
||||
textEditingController.clear();
|
||||
},
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: 'Add custom 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import 'package:flutter/material.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_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||
|
||||
class JoinHomeView extends StatelessWidget {
|
||||
const JoinHomeView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
TextEditingController textEditingController = TextEditingController();
|
||||
return DefaultScaffold(
|
||||
title: "Join a Home",
|
||||
child: Column(
|
||||
@@ -38,16 +41,27 @@ class JoinHomeView extends StatelessWidget {
|
||||
children: [
|
||||
Flexible(
|
||||
child: TextField(
|
||||
controller: textEditingController,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Invitatoin code',
|
||||
hintStyle:
|
||||
context.bodyMedium.copyWith(color: Colors.grey),
|
||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
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(
|
||||
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/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/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_scaffold.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_small.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';
|
||||
|
||||
class HomeSettingsView extends StatelessWidget {
|
||||
@@ -38,8 +42,7 @@ class HomeSettingsView extends StatelessWidget {
|
||||
textAlign: TextAlign.end,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter Name',
|
||||
hintStyle:
|
||||
context.bodyMedium.copyWith(color: Colors.grey),
|
||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
@@ -52,16 +55,27 @@ class HomeSettingsView extends StatelessWidget {
|
||||
height: 1,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(text: 'Rooms'),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
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,
|
||||
children: [
|
||||
BodyMedium(text: 'Rooms'),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
//Divider
|
||||
Container(
|
||||
@@ -78,14 +92,39 @@ class HomeSettingsView extends StatelessWidget {
|
||||
textAlign: TextAlign.end,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Set',
|
||||
hintStyle:
|
||||
context.bodyMedium.copyWith(color: Colors.grey),
|
||||
hintStyle: context.bodyMedium.copyWith(color: Colors.grey),
|
||||
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,
|
||||
crossAxisSpacing: 10,
|
||||
),
|
||||
itemCount: 4,
|
||||
itemCount: 2,
|
||||
itemBuilder: (context, index) => Stack(
|
||||
alignment: Alignment.topCenter,
|
||||
children: [
|
||||
DefaultContainer(
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 15, horizontal: 40),
|
||||
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 40),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
||||
@@ -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 {
|
||||
const DefaultScaffold(
|
||||
{super.key,
|
||||
required this.child,
|
||||
this.title,
|
||||
this.actions,
|
||||
this.appBar,
|
||||
this.bottomNavBar});
|
||||
{super.key, required this.child, this.title, this.actions, this.appBar, this.bottomNavBar});
|
||||
|
||||
final Widget child;
|
||||
final String? title;
|
||||
@@ -46,8 +41,7 @@ class DefaultScaffold extends StatelessWidget {
|
||||
body: Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
|
||||
padding: const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
|
||||
@@ -647,6 +647,9 @@ class Assets {
|
||||
|
||||
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/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/layout/view/layout_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/scene/view/scene_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 unitParent = '$baseUrl/unit/parent/{unitUuid}';
|
||||
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
|
||||
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 addDeviceToGroup = '$baseUrl/device/group';
|
||||
static const String controlDevice = '$baseUrl/device/{deviceUuid}/control';
|
||||
static const String getDevicesByUserId = '$baseUrl/device/user/{userId}';
|
||||
|
||||
//GET
|
||||
static const String deviceByRoom = '$baseUrl/device/room';
|
||||
static const String deviceByUuid = '$baseUrl/device/{deviceUuid}';
|
||||
@@ -100,4 +105,6 @@ abstract class ApiEndpoints {
|
||||
static const String devicePermissionList = '$baseUrl/device-permission/list';
|
||||
//PUT
|
||||
static const String editDevicePermission = '$baseUrl/device-permission/edit/{userId}';
|
||||
|
||||
static const String assignDeviceToRoom = '$baseUrl/device/room';
|
||||
}
|
||||
|
||||
@@ -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>(
|
||||
{required String path,
|
||||
required String savePath,
|
||||
|
||||
@@ -9,8 +9,7 @@ class SpacesAPI {
|
||||
static final HTTPService _httpService = HTTPService();
|
||||
|
||||
static Future<List<SpaceModel>> getUnitsByUserId() async {
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
final response = await _httpService.get(
|
||||
path: "${ApiEndpoints.unitUser}$uuid",
|
||||
showServerMessage: false,
|
||||
@@ -34,4 +33,27 @@ class SpacesAPI {
|
||||
);
|
||||
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 '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/manage_home/manage_home_view.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/privacy/privacy_view.dart';
|
||||
|
||||
Reference in New Issue
Block a user