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 {
|
||||
namespace "com.example.syncrow.app"
|
||||
namespace "com.example.syncrow_application"
|
||||
compileSdkVersion 34
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
@ -46,7 +46,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
// 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.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion 21
|
||||
|
@ -9,7 +9,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
|
||||
"android_client_info": {
|
||||
"package_name": "com.example.syncrow.app"
|
||||
"package_name": "com.example.syncrow_application"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.example.syncrow.app
|
||||
package com.example.syncrow_application
|
||||
|
||||
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: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'));
|
||||
|
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_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: [
|
||||
|
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 {
|
||||
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';
|
||||
}
|
||||
|
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>(
|
||||
{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';
|
||||
|
56
pubspec.lock
56
pubspec.lock
@ -89,6 +89,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -197,10 +205,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: c8e1d59385eee98de63c92f961d2a7062c5d9a65e7f45bdc7f1b0b205aab2492
|
||||
sha256: "22fcb352744908224fc7be3caae254836099786acfe5df6e9fe901e9c2575a41"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.5"
|
||||
version: "2.17.1"
|
||||
firebase_crashlytics:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -377,10 +385,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -461,6 +469,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -645,6 +661,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -689,10 +721,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
|
||||
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.3.0"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -862,10 +894,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
|
||||
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
version: "2.3.1"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -926,10 +958,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.5.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -955,5 +987,5 @@ packages:
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
sdks:
|
||||
dart: ">=3.2.0 <4.0.0"
|
||||
flutter: ">=3.16.0"
|
||||
dart: ">=3.3.0 <4.0.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.
|
||||
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:
|
||||
sdk: ">=3.0.6 <4.0.0"
|
||||
@ -41,6 +41,7 @@ dependencies:
|
||||
onesignal_flutter: ^5.2.0
|
||||
permission_handler: ^11.3.1
|
||||
pin_code_fields: ^8.0.1
|
||||
share_plus: ^9.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Reference in New Issue
Block a user