mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-08-25 16:19:39 +00:00
Compare commits
18 Commits
release-to
...
3bc20a48c9
Author | SHA1 | Date | |
---|---|---|---|
3bc20a48c9 | |||
bae6a09a87 | |||
6f0e83b95b | |||
15b6d642ff | |||
99852464c7 | |||
4ac6077011 | |||
d5321a9ca0 | |||
9d507f30eb | |||
029e36ee3d | |||
dd55d5c082 | |||
09dc8cc330 | |||
76da7debfd | |||
f7245e5de9 | |||
42c8b776ec | |||
04352c980d | |||
228aee97e6 | |||
24c7bcef55 | |||
2ff34a07a7 |
10
assets/icons/booking_icon.svg
Normal file
10
assets/icons/booking_icon.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_11681_2046)">
|
||||
<path d="M20.615 14.4212L18.9717 5.10949C18.62 3.11866 16.89 1.66699 14.8684 1.66699H6.46502C3.58336 1.66699 2.57836 3.87949 2.36169 5.10949L0.726691 14.3703C0.625024 14.9487 0.646691 15.5512 0.848357 16.102C1.35502 17.4895 2.62252 18.3337 4.00086 18.3337C4.00086 18.3337 4.93586 18.3287 4.98752 18.3187C5.35502 18.2495 5.60836 17.9462 5.64919 17.5928C5.14919 16.9095 4.77586 16.122 4.61086 15.2453L3.61836 9.97616C3.47252 9.20199 3.47586 8.40866 3.62752 7.63532C3.86252 6.43866 4.20669 4.74033 4.29836 4.58199L6.24752 14.937C6.61836 16.9062 8.33836 18.3328 10.3425 18.3328H17.2109C17.9684 18.3328 18.7284 18.1287 19.3317 17.6695C20.3575 16.8895 20.83 15.6403 20.615 14.4212ZM8.16669 6.66699C8.16669 6.20699 8.54002 5.83366 9.00002 5.83366H14.8334C15.2934 5.83366 15.6667 6.20699 15.6667 6.66699C15.6667 7.12699 15.2934 7.50033 14.8334 7.50033H9.00002C8.54002 7.50033 8.16669 7.12699 8.16669 6.66699ZM8.77586 10.0003C8.77586 9.54033 9.14919 9.16699 9.60919 9.16699H15.4425C15.9025 9.16699 16.2759 9.54033 16.2759 10.0003C16.2759 10.4603 15.9025 10.8337 15.4425 10.8337H9.60919C9.14919 10.8337 8.77586 10.4603 8.77586 10.0003ZM16.0834 14.167H10.25C9.79002 14.167 9.41669 13.7945 9.41669 13.3337C9.41669 12.8728 9.79002 12.5003 10.25 12.5003H16.0834C16.5434 12.5003 16.9167 12.8728 16.9167 13.3337C16.9167 13.7945 16.5434 14.167 16.0834 14.167Z" fill="#999999"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_11681_2046">
|
||||
<rect width="20" height="20" fill="white" transform="translate(0.666687)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
3
assets/icons/delete_account_icon.svg
Normal file
3
assets/icons/delete_account_icon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 14 KiB |
@ -12,6 +12,7 @@ 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/project_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/user_model.dart';
|
||||
import 'package:syncrow_app/features/booking_system/presentation/screens/booking_system_page.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
|
||||
@ -32,6 +33,7 @@ import 'package:syncrow_app/services/api/spaces_api.dart';
|
||||
import 'package:syncrow_app/utils/constants/temp_const.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/font_manager.dart';
|
||||
part 'home_state.dart';
|
||||
|
||||
class HomeCubit extends Cubit<HomeState> {
|
||||
@ -479,7 +481,7 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
// onPressed: () {},
|
||||
// ),
|
||||
],
|
||||
'Routine': [
|
||||
'Automation': [
|
||||
// IconButton(
|
||||
// icon: Image.asset(
|
||||
// Assets.assetsIconsFilter,
|
||||
@ -538,6 +540,7 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
// onPressed: () {},
|
||||
// ),
|
||||
],
|
||||
'Booking': [],
|
||||
'Menu': [
|
||||
// IconButton(
|
||||
// icon: SvgPicture.asset(
|
||||
@ -553,7 +556,19 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
static Map<String, Widget?> appBarLeading = {
|
||||
// 'Dashboard': const AppBarHomeDropdown(),
|
||||
'Devices': const AppBarHomeDropdown(),
|
||||
'Routine': const AppBarHomeDropdown(),
|
||||
'Automation': const AppBarHomeDropdown(),
|
||||
'Booking': Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Text(
|
||||
'Booking',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontSize: 26,
|
||||
fontFamily: FontsManager.fontFamily,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
'Menu': Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Image.asset(
|
||||
@ -569,7 +584,9 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
// defaultBottomNavBarItem(icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
|
||||
// defaultBottomNavBarItem(icon: Assets.assetsIconslayout, label: 'Layout'),
|
||||
defaultBottomNavBarItem(icon: Assets.assetsIconsDevices, label: 'Devices'),
|
||||
defaultBottomNavBarItem(icon: Assets.assetsIconsRoutines, label: 'Routine'),
|
||||
defaultBottomNavBarItem(
|
||||
icon: Assets.assetsIconsRoutines, label: 'Automation'),
|
||||
defaultBottomNavBarItem(icon: Assets.bookingIcon, label: 'Booking'),
|
||||
defaultBottomNavBarItem(icon: Assets.assetsIconsMenu, label: 'Menu'),
|
||||
];
|
||||
|
||||
@ -581,6 +598,7 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
child: const DevicesViewBody(),
|
||||
),
|
||||
const RoutinesView(),
|
||||
const BookingSystemPage(),
|
||||
const MenuView(),
|
||||
];
|
||||
|
||||
@ -616,7 +634,6 @@ BottomNavigationBarItem defaultBottomNavBarItem(
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// class PermissionUtils {
|
||||
// // Check if the "VIEW" permission exists in "MANAGE_SUBSPACE"
|
||||
// static bool hasViewPermission(List<dynamic> permissions) {
|
||||
|
@ -3,9 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||
import 'package:syncrow_app/features/booking_system/data/booking_dummy_source.dart';
|
||||
import 'package:syncrow_app/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_bloc.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import '../blocs/past_bookings_bloc/past_bookings_bloc.dart';
|
||||
import '../widgets/booking_appbar_widget.dart';
|
||||
import '../widgets/current_balance_widget.dart';
|
||||
import '../widgets/past_booking_widget.dart';
|
||||
import '../widgets/upcoming_bookings_widget.dart';
|
||||
@ -26,41 +24,35 @@ class BookingSystemPage extends StatelessWidget {
|
||||
..add(GetPastBookingsEvent()),
|
||||
)
|
||||
],
|
||||
child: DefaultScaffold(
|
||||
appBar: BookingAppBar(),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: CurrentBalanceWidget(
|
||||
userBalance: HomeCubit.user!.points == null
|
||||
? '0'
|
||||
: HomeCubit.user!.points.toString(),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: CurrentBalanceWidget(
|
||||
userBalance: HomeCubit.user!.points == null
|
||||
? '0'
|
||||
: HomeCubit.user!.points.toString(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Expanded(
|
||||
flex: 8,
|
||||
child: Column(
|
||||
children: [
|
||||
UpcomingBookingsWidget(),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
PastBookingsWidget(),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Expanded(
|
||||
flex: 8,
|
||||
child: Column(
|
||||
children: [
|
||||
UpcomingBookingsWidget(),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
PastBookingsWidget(),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -10,10 +10,7 @@ class BookingAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
return AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
leading: IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: Icon(Icons.arrow_back_ios_new)),
|
||||
title: Text(
|
||||
leading: Text(
|
||||
'Booking',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.blueColor1,
|
||||
|
@ -39,7 +39,7 @@ class PastBookingsWidget extends StatelessWidget {
|
||||
);
|
||||
} else if (state is PastBookingLoadedState) {
|
||||
return SizedBox(
|
||||
height: deviceHeight(context) * 0.3,
|
||||
height: deviceHeight(context) * 0.22,
|
||||
child: state.pastBookings.isEmpty
|
||||
? Text('You Dont Have past Bookings')
|
||||
: ListView.separated(
|
||||
|
@ -45,18 +45,6 @@ class MenuCubit extends Cubit<MenuState> {
|
||||
}
|
||||
|
||||
List<Map<String, Object>> menuSections = [
|
||||
//Booking System
|
||||
{
|
||||
'title': 'Booking System',
|
||||
'color': const Color(0xFF8AB9FF),
|
||||
'buttons': [
|
||||
{
|
||||
'title': 'Booking',
|
||||
'Icon': Assets.assetsIconsMenuBookingSystem,
|
||||
'page': BookingSystemPage()
|
||||
},
|
||||
],
|
||||
},
|
||||
//Home Management
|
||||
{
|
||||
'title': 'Home Management',
|
||||
|
@ -262,6 +262,17 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
|
||||
if (parts.any((part) => part.length < 2 || part.length > 30)) {
|
||||
return 'Full name parts must be between 2 and 30 characters long';
|
||||
}
|
||||
if (RegExp(r"\s{2,}").hasMatch(value)) {
|
||||
return 'Only one space is allowed between first and last names';
|
||||
}
|
||||
// Check for leading or trailing spaces
|
||||
if (value != value.trim()) {
|
||||
return 'No leading or trailing spaces allowed';
|
||||
}
|
||||
// Check if only alphabetic characters and one space are used
|
||||
if (!RegExp(r'^[A-Za-z]+(?: [A-Za-z]+)?$').hasMatch(value)) {
|
||||
return 'Only alphabetic characters and a single space are allowed';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
|
||||
on<UpdateTimerEvent>(_onUpdateTimer);
|
||||
on<VerifyPassCodeEvent>(verifyCode);
|
||||
on<ChangePasswordEvent>(changePassword);
|
||||
on<DeleteAccountEvent>(onDeleteAccountEvent);
|
||||
}
|
||||
|
||||
void _onSetPassword(SetPassword event, Emitter<SecurityState> emit) {
|
||||
@ -180,7 +181,6 @@ class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
|
||||
ChangePasswordEvent event, Emitter<SecurityState> emit) async {
|
||||
emit(LoadingForgetState());
|
||||
try {
|
||||
|
||||
final response = await AuthenticationAPI.forgetPassword(
|
||||
email: HomeCubit.user!.email!,
|
||||
otpCode: event.otpCode,
|
||||
@ -195,5 +195,16 @@ class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
|
||||
emit(AuthInitialState());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Future<void> onDeleteAccountEvent(
|
||||
DeleteAccountEvent event, Emitter<SecurityState> emit) async {
|
||||
emit(LoadingForgetState());
|
||||
try {
|
||||
await AuthenticationAPI.deleteAccount();
|
||||
emit(ChangedPassState());
|
||||
} catch (e) {
|
||||
validate = e.toString();
|
||||
emit(AuthInitialState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,3 +29,5 @@ class ChangePasswordEvent extends SecurityEvent {
|
||||
}
|
||||
|
||||
class VerifyPassCodeEvent extends SecurityEvent {}
|
||||
|
||||
class DeleteAccountEvent extends SecurityEvent {}
|
||||
|
@ -0,0 +1,107 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_state.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/resource_manager/color_manager.dart';
|
||||
|
||||
class DeleteAccountPage extends StatelessWidget {
|
||||
const DeleteAccountPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocListener<SecurityBloc, SecurityState>(
|
||||
listener: (context, state) {
|
||||
if (state is ChangedPassState) {
|
||||
AuthCubit.get(context).logout();
|
||||
}
|
||||
},
|
||||
child: DefaultScaffold(
|
||||
title: 'Delete Account',
|
||||
bottomNavBar: SizedBox(
|
||||
height: 150,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: 'Thank you for using Syncrow',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
BlocBuilder<SecurityBloc, SecurityState>(
|
||||
builder: (context, state) {
|
||||
if (state is LoadingForgetState) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
context
|
||||
.read<SecurityBloc>()
|
||||
.add(DeleteAccountEvent());
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: ColorsManager.blueColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
fixedSize: Size(
|
||||
MediaQuery.sizeOf(context).width * 0.8,
|
||||
40,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Delete Account',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: ColorsManager.onPrimaryColor),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 80, bottom: 30),
|
||||
child: SvgPicture.asset(Assets.deleteAccountIcon),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: BodyMedium(
|
||||
text: 'Account Verification',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
const BodyMedium(
|
||||
text:
|
||||
'if you confirm to "delete account",the account will be deleted',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 16,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
||||
@ -24,13 +23,15 @@ class ChangePasswordPage extends StatelessWidget {
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
// In your parent widget or navigator
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BlocProvider(
|
||||
create: (_) => SecurityBloc(), // Provide the Bloc
|
||||
child: const VerificationCodePage(),
|
||||
create: (_) => SecurityBloc(),
|
||||
child: const VerificationCodePage(
|
||||
title: 'Change Password',
|
||||
isDeleteAccountMode: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,5 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/view/change_password_page.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/view/verification_code_page.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';
|
||||
@ -23,134 +27,34 @@ class SecurtyView extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
InkWell(
|
||||
SecurityListTileWidget(
|
||||
title: 'Change Password',
|
||||
onTap: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => const ChangePasswordPage(),
|
||||
));
|
||||
},
|
||||
child: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: 'Change Password',
|
||||
),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
// Container(
|
||||
// margin: const EdgeInsets.symmetric(vertical: 15),
|
||||
// height: 1,
|
||||
// color: ColorsManager.greyColor,
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
// InkWell(
|
||||
// onTap: () {},
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// const Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// BodyMedium(
|
||||
// text: 'App Lock',
|
||||
// ),
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios,
|
||||
// color: ColorsManager.greyColor,
|
||||
// size: 15,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// Container(
|
||||
// margin: const EdgeInsets.symmetric(vertical: 15),
|
||||
// height: 1,
|
||||
// color: ColorsManager.greyColor,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// InkWell(
|
||||
// onTap: () {},
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// const Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// BodyMedium(
|
||||
// text: 'User Code',
|
||||
// ),
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios,
|
||||
// color: ColorsManager.greyColor,
|
||||
// size: 15,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// Container(
|
||||
// margin: const EdgeInsets.symmetric(vertical: 15),
|
||||
// height: 1,
|
||||
// color: ColorsManager.greyColor,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// InkWell(
|
||||
// onTap: () {},
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// const Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// BodyMedium(
|
||||
// text: 'Delete Account',
|
||||
// ),
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios,
|
||||
// color: ColorsManager.greyColor,
|
||||
// size: 15,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// Container(
|
||||
// margin: const EdgeInsets.symmetric(vertical: 15),
|
||||
// height: 1,
|
||||
// color: ColorsManager.greyColor,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// InkWell(
|
||||
// onTap: () {},
|
||||
// child: const Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// BodyMedium(
|
||||
// text: 'Device Update',
|
||||
// ),
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios,
|
||||
// color: ColorsManager.greyColor,
|
||||
// size: 15,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 15),
|
||||
height: 1,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
SecurityListTileWidget(
|
||||
title: 'Delete Account',
|
||||
fontColor: ColorsManager.red,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => BlocProvider(
|
||||
create: (_) => SecurityBloc()..add(StartTimerEvent()),
|
||||
child: VerificationCodePage(
|
||||
title: '',
|
||||
isDeleteAccountMode: true,
|
||||
),
|
||||
),
|
||||
));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -159,3 +63,42 @@ class SecurtyView extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SecurityListTileWidget extends StatelessWidget {
|
||||
final String title;
|
||||
final void Function() onTap;
|
||||
final Color? fontColor;
|
||||
const SecurityListTileWidget({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.onTap,
|
||||
this.fontColor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: title,
|
||||
fontColor: fontColor,
|
||||
),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_state.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/delete_account/delete_account_page.dart';
|
||||
import 'package:syncrow_app/features/menu/view/widgets/securty/view/set_password_page.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
@ -11,7 +12,13 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
import 'package:pin_code_fields/pin_code_fields.dart';
|
||||
|
||||
class VerificationCodePage extends StatelessWidget {
|
||||
const VerificationCodePage({super.key});
|
||||
final String title;
|
||||
final bool isDeleteAccountMode;
|
||||
const VerificationCodePage({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.isDeleteAccountMode,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -20,19 +27,29 @@ class VerificationCodePage extends StatelessWidget {
|
||||
create: (context) => SecurityBloc()..add(StartTimerEvent()),
|
||||
child: BlocConsumer<SecurityBloc, SecurityState>(
|
||||
listener: (context, state) {
|
||||
final securityBloc = context.read<SecurityBloc>();
|
||||
if (state is SuccessForgetState) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => SetPasswordPage(
|
||||
otpCode: otp,
|
||||
),
|
||||
));
|
||||
if (isDeleteAccountMode) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: securityBloc,
|
||||
child: DeleteAccountPage(),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => SetPasswordPage(
|
||||
otpCode: otp,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
final _bloc = BlocProvider.of<SecurityBloc>(context);
|
||||
|
||||
return DefaultScaffold(
|
||||
title: 'Change Password',
|
||||
title: title,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 55),
|
||||
@ -86,8 +103,8 @@ class VerificationCodePage extends StatelessWidget {
|
||||
selectedFillColor: Colors.white70,
|
||||
activeFillColor: Colors.white,
|
||||
errorBorderColor: Colors.white,
|
||||
fieldHeight: 55.0,
|
||||
fieldWidth: 55.0,
|
||||
fieldHeight: 45.0,
|
||||
fieldWidth: 45.0,
|
||||
fieldOuterPadding: const EdgeInsets.only(right: 8),
|
||||
borderRadius: BorderRadius.circular(17),
|
||||
borderWidth: 1,
|
||||
@ -109,27 +126,35 @@ class VerificationCodePage extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap:
|
||||
state is TimerState && !state.isButtonEnabled && state.remainingTime != 1
|
||||
? null
|
||||
: () {
|
||||
_bloc.add(StartTimerEvent());
|
||||
},
|
||||
onTap: state is TimerState &&
|
||||
!state.isButtonEnabled &&
|
||||
state.remainingTime != 1
|
||||
? null
|
||||
: () {
|
||||
_bloc.add(StartTimerEvent());
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(right: 20, left: 20, top: 15, bottom: 15),
|
||||
padding: const EdgeInsets.only(
|
||||
right: 20, left: 20, top: 15, bottom: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: state is TimerState && !state.isButtonEnabled
|
||||
? ColorsManager.blueButton
|
||||
: ColorsManager.blueColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(20))),
|
||||
child: Center(
|
||||
child: Center(
|
||||
child: Text(
|
||||
'${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "${_bloc.formattedTime(state.remainingTime)} " : "Resend"}',
|
||||
state is TimerState &&
|
||||
!state.isButtonEnabled &&
|
||||
state.remainingTime != 1
|
||||
? "${_bloc.formattedTime(state.remainingTime)} "
|
||||
: "Resend",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: state is TimerState && !state.isButtonEnabled
|
||||
color: state is TimerState &&
|
||||
!state.isButtonEnabled
|
||||
? Colors.white
|
||||
: ColorsManager.onPrimaryColor,
|
||||
),
|
||||
@ -142,18 +167,24 @@ class VerificationCodePage extends StatelessWidget {
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.read<SecurityBloc>().add(VerifyPassCodeEvent());
|
||||
context
|
||||
.read<SecurityBloc>()
|
||||
.add(VerifyPassCodeEvent());
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(right: 20, left: 20, top: 15, bottom: 15),
|
||||
padding: const EdgeInsets.only(
|
||||
right: 20, left: 20, top: 15, bottom: 15),
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.blueColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(20))),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
"Verify",
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: Colors.white, fontWeight: FontWeight.w700),
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -27,12 +27,15 @@ class RoutinesView extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
final selectedSpace = HomeCubit.getInstance().selectedSpace;
|
||||
if (state is DeleteSceneSuccess) {
|
||||
if (state.success) _loadScenesAndAutomations(context, selectedSpace);
|
||||
if (state.success)
|
||||
_loadScenesAndAutomations(context, selectedSpace);
|
||||
}
|
||||
if (state is CreateSceneWithTasks) {
|
||||
if (state.success) {
|
||||
_loadScenesAndAutomations(context, selectedSpace);
|
||||
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent());
|
||||
context
|
||||
.read<SmartSceneSelectBloc>()
|
||||
.add(const SmartSceneClearEvent());
|
||||
}
|
||||
}
|
||||
return BlocListener<SceneBloc, SceneState>(
|
||||
@ -72,30 +75,28 @@ class RoutinesView extends StatelessWidget {
|
||||
data: Theme.of(context).copyWith(
|
||||
dividerColor: Colors.transparent,
|
||||
),
|
||||
child: Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
RoutinesExpansionTile(
|
||||
title: 'Tap to run routines',
|
||||
emptyRoutinesMessage:
|
||||
'No scenes have been added yet',
|
||||
routines: state.scenes,
|
||||
loadingStates: state.loadingStates,
|
||||
loadingSceneId: state.loadingSceneId,
|
||||
disablePlayButton: false,
|
||||
),
|
||||
RoutinesExpansionTile(
|
||||
title: 'Automation',
|
||||
emptyRoutinesMessage:
|
||||
'No automations have been added yet',
|
||||
routines: state.automationList,
|
||||
loadingStates: state.loadingStates,
|
||||
loadingSceneId: state.loadingSceneId,
|
||||
disablePlayButton: true,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
child: ListView(
|
||||
children: [
|
||||
RoutinesExpansionTile(
|
||||
title: 'Tap to run automations',
|
||||
emptyRoutinesMessage:
|
||||
'No scenes have been added yet',
|
||||
routines: state.scenes,
|
||||
loadingStates: state.loadingStates,
|
||||
loadingSceneId: state.loadingSceneId,
|
||||
disablePlayButton: false,
|
||||
),
|
||||
RoutinesExpansionTile(
|
||||
title: 'Automation',
|
||||
emptyRoutinesMessage:
|
||||
'No automations have been added yet',
|
||||
routines: state.automationList,
|
||||
loadingStates: state.loadingStates,
|
||||
loadingSceneId: state.loadingSceneId,
|
||||
disablePlayButton: true,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -111,7 +112,8 @@ class RoutinesView extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _loadScenesAndAutomations(BuildContext context, SpaceModel? selectedSpace) {
|
||||
void _loadScenesAndAutomations(
|
||||
BuildContext context, SpaceModel? selectedSpace) {
|
||||
context.read<SceneBloc>()
|
||||
..add(LoadScenes(selectedSpace!.id, selectedSpace, showInDevice: false))
|
||||
..add(LoadAutomation(selectedSpace.id, selectedSpace.community.uuid));
|
||||
|
@ -100,7 +100,7 @@ class SceneView extends StatelessWidget {
|
||||
initiallyExpanded: true,
|
||||
iconColor: ColorsManager.grayColor,
|
||||
title: const BodyMedium(
|
||||
text: 'Tap to run routines',
|
||||
text: 'Tap to run automations',
|
||||
),
|
||||
children: [
|
||||
if (scenes.isNotEmpty)
|
||||
|
@ -23,7 +23,7 @@ class DeleteRoutineDialog extends StatelessWidget {
|
||||
height: 10,
|
||||
),
|
||||
const BodyLarge(
|
||||
text: 'Delete Routine',
|
||||
text: 'Delete Automation',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: ColorsManager.red,
|
||||
fontSize: 16,
|
||||
@ -39,7 +39,7 @@ class DeleteRoutineDialog extends StatelessWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
Center(child: const Text('Are you sure you want to ')),
|
||||
Center(child: const Text('delete the routine?'))
|
||||
Center(child: const Text('delete the automation?'))
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -52,7 +52,7 @@ class DeleteRoutineButton extends StatelessWidget {
|
||||
},
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Remove Routine',
|
||||
'Remove Automation',
|
||||
style: TextStyle(color: ColorsManager.red),
|
||||
))
|
||||
// : SceneListTile(
|
||||
|
@ -9,7 +9,7 @@ class EmptyDevicesWidget extends StatelessWidget {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 48),
|
||||
child: Text(
|
||||
"No routines.\nEnable 'Show on Home Screen' to add routines",
|
||||
"No automations.\nEnable 'Show on Home Screen' to add automations",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: ColorsManager.grayColor,
|
||||
|
@ -23,7 +23,7 @@ class EmptyRoutinesWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
BodyMedium(
|
||||
text: 'No Routines yet',
|
||||
text: 'No automations yet',
|
||||
fontColor: ColorsManager.textGray,
|
||||
),
|
||||
],
|
||||
|
@ -1128,7 +1128,8 @@ class Assets {
|
||||
static const String editNameSetting = "assets/icons/edit_name_setting.svg";
|
||||
|
||||
static const String verificationIcon = "assets/icons/verification_icon.svg";
|
||||
|
||||
static const String deleteAccountIcon='assets/icons/delete_account_icon.svg';
|
||||
static const String bookingIcon='assets/icons/booking_icon.svg';
|
||||
static const String passwordUnvisibility =
|
||||
"assets/icons/password_unvisibility.svg";
|
||||
static const String passwordVisibility =
|
||||
|
@ -195,6 +195,7 @@ abstract class ApiEndpoints {
|
||||
static const String sendPicture = '/user/profile-picture/{userUuid}';
|
||||
static const String getRegion = '/region';
|
||||
static const String getTimezone = '/timezone';
|
||||
static const String deleteProfile = '/user';
|
||||
|
||||
//multiple-time offline
|
||||
static const String addMultipleTimeTemporaryPassword =
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:syncrow_app/features/auth/model/login_with_email_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/signup_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/token.dart';
|
||||
@ -83,4 +84,18 @@ class AuthenticationAPI {
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
static Future<void> deleteAccount() async {
|
||||
try {
|
||||
await HTTPService().delete(
|
||||
path: ApiEndpoints.deleteProfile,
|
||||
expectedResponseModel: (p0) {},
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage =
|
||||
errorData['error']['message'] ?? 'something went wrong';
|
||||
throw Exception(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ class StringsManager {
|
||||
|
||||
static const String dashboard = 'Dashboard';
|
||||
static const String devices = 'Devices';
|
||||
static const String routine = 'Routines';
|
||||
static const String tapToRunRoutine = 'Tap to run routine';
|
||||
static const String routine = 'Automation';
|
||||
static const String tapToRunRoutine = 'Tap to run automation';
|
||||
static const String wizard = 'Wizard';
|
||||
static const String active = 'Active';
|
||||
static const String current = 'Current';
|
||||
@ -39,6 +39,6 @@ class StringsManager {
|
||||
'Example: when an unusual activity is detected.';
|
||||
static const String functions = "Functions";
|
||||
static const String firstLaunch = "firstLaunch";
|
||||
static const String deleteScene = 'Remove Routine';
|
||||
static const String deleteScene = 'Remove Automation';
|
||||
static const String deleteAutomation = 'Delete Automation';
|
||||
}
|
||||
|
Reference in New Issue
Block a user