Compare commits

..

2 Commits

27 changed files with 469 additions and 408 deletions

View File

@ -1,9 +1,22 @@
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:go_router/go_router.dart';
import 'package:syncrow_web/firebase_options.dart'; import 'package:syncrow_web/firebase_options.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
import 'package:syncrow_web/services/locator.dart'; import 'package:syncrow_web/services/locator.dart';
import 'package:syncrow_web/syncrow_app.dart'; import 'package:syncrow_web/utils/app_routes.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
import 'package:syncrow_web/utils/navigation_service.dart';
import 'package:syncrow_web/utils/theme/theme.dart';
Future<void> main() async { Future<void> main() async {
try { try {
@ -20,5 +33,59 @@ Future<void> main() async {
); );
initialSetup(); initialSetup();
} catch (_) {} } catch (_) {}
runApp(const SyncrowApp()); runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final GoRouter _router = GoRouter(
initialLocation: RoutesConst.auth,
routes: AppRoutes.getRoutes(),
redirect: (context, state) async {
final checkToken = await AuthBloc.getTokenAndValidate();
final loggedIn = checkToken == 'Success';
final goingToLogin = state.uri.toString() == RoutesConst.auth;
if (!loggedIn && !goingToLogin) return RoutesConst.auth;
if (loggedIn && goingToLogin) return RoutesConst.home;
return null;
},
);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<CreateRoutineBloc>(
create: (context) => CreateRoutineBloc(),
),
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
BlocProvider<VisitorPasswordBloc>(
create: (context) => VisitorPasswordBloc(),
),
BlocProvider<RoutineBloc>(
create: (context) => RoutineBloc(),
),
BlocProvider<SpaceTreeBloc>(
create: (context) => SpaceTreeBloc(),
),
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
PointerDeviceKind.mouse,
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
},
),
key: NavigationService.navigatorKey,
// scaffoldMessengerKey: NavigationService.snackbarKey,
theme: myTheme,
routerConfig: _router,
));
}
} }

View File

@ -1,9 +1,22 @@
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:go_router/go_router.dart';
import 'package:syncrow_web/firebase_options.dart'; import 'package:syncrow_web/firebase_options.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
import 'package:syncrow_web/services/locator.dart'; import 'package:syncrow_web/services/locator.dart';
import 'package:syncrow_web/syncrow_app.dart'; import 'package:syncrow_web/utils/app_routes.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
import 'package:syncrow_web/utils/navigation_service.dart';
import 'package:syncrow_web/utils/theme/theme.dart';
Future<void> main() async { Future<void> main() async {
try { try {
@ -20,5 +33,59 @@ Future<void> main() async {
); );
initialSetup(); initialSetup();
} catch (_) {} } catch (_) {}
runApp(const SyncrowApp()); runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final GoRouter _router = GoRouter(
initialLocation: RoutesConst.auth,
routes: AppRoutes.getRoutes(),
redirect: (context, state) async {
final checkToken = await AuthBloc.getTokenAndValidate();
final loggedIn = checkToken == 'Success';
final goingToLogin = state.uri.toString() == RoutesConst.auth;
if (!loggedIn && !goingToLogin) return RoutesConst.auth;
if (loggedIn && goingToLogin) return RoutesConst.home;
return null;
},
);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<CreateRoutineBloc>(
create: (context) => CreateRoutineBloc(),
),
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
BlocProvider<VisitorPasswordBloc>(
create: (context) => VisitorPasswordBloc(),
),
BlocProvider<RoutineBloc>(
create: (context) => RoutineBloc(),
),
BlocProvider<SpaceTreeBloc>(
create: (context) => SpaceTreeBloc(),
),
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
PointerDeviceKind.mouse,
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
},
),
key: NavigationService.navigatorKey,
// scaffoldMessengerKey: NavigationService.snackbarKey,
theme: myTheme,
routerConfig: _router,
));
}
} }

View File

@ -1,16 +1,26 @@
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:go_router/go_router.dart';
import 'package:syncrow_web/firebase_options.dart'; import 'package:syncrow_web/firebase_options.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
import 'package:syncrow_web/services/locator.dart'; import 'package:syncrow_web/services/locator.dart';
import 'package:syncrow_web/syncrow_app.dart'; import 'package:syncrow_web/utils/app_routes.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
import 'package:syncrow_web/utils/navigation_service.dart';
import 'package:syncrow_web/utils/theme/theme.dart';
Future<void> main() async { Future<void> main() async {
try { try {
const environment = String.fromEnvironment( const environment = String.fromEnvironment('FLAVOR', defaultValue: 'staging');
'FLAVOR',
defaultValue: 'staging',
);
await dotenv.load(fileName: '.env.$environment'); await dotenv.load(fileName: '.env.$environment');
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp( await Firebase.initializeApp(
@ -20,5 +30,59 @@ Future<void> main() async {
); );
initialSetup(); initialSetup();
} catch (_) {} } catch (_) {}
runApp(const SyncrowApp()); runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final GoRouter _router = GoRouter(
initialLocation: RoutesConst.auth,
routes: AppRoutes.getRoutes(),
redirect: (context, state) async {
final checkToken = await AuthBloc.getTokenAndValidate();
final loggedIn = checkToken == 'Success';
final goingToLogin = state.uri.toString() == RoutesConst.auth;
if (!loggedIn && !goingToLogin) return RoutesConst.auth;
if (loggedIn && goingToLogin) return RoutesConst.home;
return null;
},
);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<CreateRoutineBloc>(
create: (context) => CreateRoutineBloc(),
),
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
BlocProvider<VisitorPasswordBloc>(
create: (context) => VisitorPasswordBloc(),
),
BlocProvider<RoutineBloc>(
create: (context) => RoutineBloc(),
),
BlocProvider<SpaceTreeBloc>(
create: (context) => SpaceTreeBloc(),
),
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
PointerDeviceKind.mouse,
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
},
),
key: NavigationService.navigatorKey,
// scaffoldMessengerKey: NavigationService.snackbarKey,
theme: myTheme,
routerConfig: _router,
));
}
} }

View File

@ -10,7 +10,7 @@ part 'events_event.dart';
part 'events_state.dart'; part 'events_state.dart';
class CalendarEventsBloc extends Bloc<CalendarEventsEvent, CalendarEventState> { class CalendarEventsBloc extends Bloc<CalendarEventsEvent, CalendarEventState> {
EventController eventController = EventController(); final EventController eventController = EventController();
final CalendarSystemService calendarService; final CalendarSystemService calendarService;
CalendarEventsBloc({ CalendarEventsBloc({
@ -20,9 +20,7 @@ class CalendarEventsBloc extends Bloc<CalendarEventsEvent, CalendarEventState> {
on<AddEvent>(_onAddEvent); on<AddEvent>(_onAddEvent);
on<DisposeResources>(_onDisposeResources); on<DisposeResources>(_onDisposeResources);
on<GoToWeek>(_onGoToWeek); on<GoToWeek>(_onGoToWeek);
on<ResetEvents>(_onResetEvents);
} }
Future<void> _onLoadEvents( Future<void> _onLoadEvents(
LoadEvents event, LoadEvents event,
Emitter<CalendarEventState> emit, Emitter<CalendarEventState> emit,
@ -128,18 +126,4 @@ class CalendarEventsBloc extends Bloc<CalendarEventsEvent, CalendarEventState> {
eventController.dispose(); eventController.dispose();
return super.close(); return super.close();
} }
void _onResetEvents(
ResetEvents event,
Emitter<CalendarEventState> emit,
) {
if (calendarService is MemoryCalendarServiceWithRemoteFallback) {
(calendarService as MemoryCalendarServiceWithRemoteFallback)
.memoryService
.clear();
}
eventController.dispose();
eventController = EventController();
emit(EventsInitial());
}
} }

View File

@ -29,10 +29,3 @@ class CheckWeekHasEvents extends CalendarEventsEvent {
final DateTime weekStart; final DateTime weekStart;
const CheckWeekHasEvents(this.weekStart); const CheckWeekHasEvents(this.weekStart);
} }
class ResetEvents extends CalendarEventsEvent {
const ResetEvents();
@override
List<Object?> get props => [];
}

View File

@ -26,33 +26,7 @@ class BookingPage extends StatefulWidget {
} }
class _BookingPageState extends State<BookingPage> { class _BookingPageState extends State<BookingPage> {
@override late final EventController _eventController;
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(create: (_) => SelectedBookableSpaceBloc()),
BlocProvider(create: (_) => DateSelectionBloc()),
BlocProvider(
create: (_) => CalendarEventsBloc(
calendarService: MemoryCalendarServiceWithRemoteFallback(
remoteService: RemoteCalendarService(HTTPService()),
memoryService: MemoryCalendarService(),
),
),
),
],
child: _BookingPageContent(),
);
}
}
class _BookingPageContent extends StatefulWidget {
@override
State<_BookingPageContent> createState() => _BookingPageContentState();
}
class _BookingPageContentState extends State<_BookingPageContent> {
late EventController _eventController;
@override @override
void initState() { void initState() {
@ -66,7 +40,7 @@ class _BookingPageContentState extends State<_BookingPageContent> {
super.dispose(); super.dispose();
} }
void _loadEvents(BuildContext context) { void _dispatchLoadEvents(BuildContext context) {
final selectedRoom = final selectedRoom =
context.read<SelectedBookableSpaceBloc>().state.selectedBookableSpace; context.read<SelectedBookableSpaceBloc>().state.selectedBookableSpace;
final dateState = context.read<DateSelectionBloc>().state; final dateState = context.read<DateSelectionBloc>().state;
@ -86,168 +60,186 @@ class _BookingPageContentState extends State<_BookingPageContent> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocListener<SelectedBookableSpaceBloc, SelectedBookableSpaceState>( return MultiBlocProvider(
listener: (context, state) { providers: [
if (state.selectedBookableSpace != null) { BlocProvider(create: (_) => SelectedBookableSpaceBloc()),
context.read<CalendarEventsBloc>().add(const ResetEvents()); BlocProvider(create: (_) => DateSelectionBloc()),
_loadEvents(context); BlocProvider(
} create: (_) => CalendarEventsBloc(
}, calendarService: MemoryCalendarServiceWithRemoteFallback(
child: BlocListener<DateSelectionBloc, DateSelectionState>( remoteService: RemoteCalendarService(
listener: (context, state) { HTTPService(),
_loadEvents(context); ),
}, memoryService: MemoryCalendarService(),
child: BlocListener<CalendarEventsBloc, CalendarEventState>( ),
)),
],
child: Builder(
builder: (context) =>
BlocListener<CalendarEventsBloc, CalendarEventState>(
listenWhen: (prev, curr) => curr is EventsLoaded,
listener: (context, state) { listener: (context, state) {
if (state is EventsLoaded) { if (state is EventsLoaded) {
_eventController.removeWhere((_) => true); _eventController.removeWhere((_) => true);
_eventController.addAll(state.events); _eventController.addAll(state.events);
} }
}, },
child: Row( child: BlocListener<SelectedBookableSpaceBloc,
crossAxisAlignment: CrossAxisAlignment.start, SelectedBookableSpaceState>(
children: [ listener: (context, state) => _dispatchLoadEvents(context),
Expanded( child: BlocListener<DateSelectionBloc, DateSelectionState>(
child: Container( listener: (context, state) => _dispatchLoadEvents(context),
decoration: BoxDecoration( child: Row(
color: ColorsManager.whiteColors, crossAxisAlignment: CrossAxisAlignment.start,
boxShadow: [ children: [
BoxShadow( Expanded(
color: ColorsManager.blackColor.withOpacity(0.1), child: Container(
offset: const Offset(3, 0), decoration: BoxDecoration(
blurRadius: 6, color: ColorsManager.whiteColors,
spreadRadius: 0, boxShadow: [
), BoxShadow(
], color: ColorsManager.blackColor.withOpacity(0.1),
), offset: const Offset(3, 0),
child: Column( blurRadius: 6,
children: [ spreadRadius: 0,
Expanded(
flex: 2,
child: BlocBuilder<SelectedBookableSpaceBloc,
SelectedBookableSpaceState>(
builder: (context, state) {
return BookingSidebar(
onRoomSelected: (selectedRoom) {
context
.read<SelectedBookableSpaceBloc>()
.add(SelectBookableSpace(selectedRoom));
},
);
},
),
),
Expanded(
child:
BlocBuilder<DateSelectionBloc, DateSelectionState>(
builder: (context, dateState) {
return CustomCalendarPage(
selectedDate: dateState.selectedDate,
onDateChanged: (day, month, year) {
final newDate = DateTime(year, month, day);
context
.read<DateSelectionBloc>()
.add(SelectDate(newDate));
context.read<DateSelectionBloc>().add(
SelectDateFromSidebarCalendar(newDate));
},
);
},
),
),
],
),
),
),
Expanded(
flex: 5,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgTextButton(
svgAsset: Assets.homeIcon,
label: 'Manage Bookable Spaces',
onPressed: () {},
),
const SizedBox(width: 20),
SvgTextButton(
svgAsset: Assets.groupIcon,
label: 'Manage Users',
onPressed: () {},
),
],
),
BlocBuilder<DateSelectionBloc, DateSelectionState>(
builder: (context, state) {
final weekStart = state.weekStart;
final weekEnd =
weekStart.add(const Duration(days: 6));
return WeekNavigation(
weekStart: weekStart,
weekEnd: weekEnd,
onPreviousWeek: () {
context
.read<DateSelectionBloc>()
.add(PreviousWeek());
},
onNextWeek: () {
context
.read<DateSelectionBloc>()
.add(NextWeek());
},
);
},
), ),
], ],
), ),
const SizedBox(height: 20), child: Column(
Expanded( children: [
flex: 5, Expanded(
child: BlocBuilder<SelectedBookableSpaceBloc, flex: 2,
SelectedBookableSpaceState>( child: BlocBuilder<SelectedBookableSpaceBloc,
builder: (context, roomState) { SelectedBookableSpaceState>(
final selectedRoom = builder: (context, state) {
roomState.selectedBookableSpace; return BookingSidebar(
return BlocBuilder<DateSelectionBloc, onRoomSelected: (selectedRoom) {
context
.read<SelectedBookableSpaceBloc>()
.add(SelectBookableSpace(selectedRoom));
},
);
},
),
),
Expanded(
child: BlocBuilder<DateSelectionBloc,
DateSelectionState>( DateSelectionState>(
builder: (context, dateState) { builder: (context, dateState) {
return BlocBuilder<CalendarEventsBloc, return CustomCalendarPage(
CalendarEventState>( selectedDate: dateState.selectedDate,
builder: (context, eventState) { onDateChanged: (day, month, year) {
return WeeklyCalendarPage( final newDate = DateTime(year, month, day);
key: ValueKey( context
selectedRoom?.uuid ?? 'no-room'), .read<DateSelectionBloc>()
startTime: selectedRoom .add(SelectDate(newDate));
?.bookableConfig.startTime, context.read<DateSelectionBloc>().add(
endTime: SelectDateFromSidebarCalendar(newDate));
selectedRoom?.bookableConfig.endTime, },
weekStart: dateState.weekStart, );
selectedDate: dateState.selectedDate, },
eventController: _eventController, ),
selectedDateFromSideBarCalender: context ),
.watch<DateSelectionBloc>() ],
.state ),
.selectedDateFromSideBarCalender, ),
),
Expanded(
flex: 5,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgTextButton(
svgAsset: Assets.homeIcon,
label: 'Manage Bookable Spaces',
onPressed: () {},
),
const SizedBox(width: 20),
SvgTextButton(
svgAsset: Assets.groupIcon,
label: 'Manage Users',
onPressed: () {},
),
],
),
BlocBuilder<DateSelectionBloc,
DateSelectionState>(
builder: (context, state) {
final weekStart = state.weekStart;
final weekEnd =
weekStart.add(const Duration(days: 6));
return WeekNavigation(
weekStart: weekStart,
weekEnd: weekEnd,
onPreviousWeek: () {
context
.read<DateSelectionBloc>()
.add(PreviousWeek());
},
onNextWeek: () {
context
.read<DateSelectionBloc>()
.add(NextWeek());
},
);
},
),
],
),
Expanded(
flex: 5,
child: BlocBuilder<SelectedBookableSpaceBloc,
SelectedBookableSpaceState>(
builder: (context, roomState) {
final selectedRoom =
roomState.selectedBookableSpace;
return BlocBuilder<DateSelectionBloc,
DateSelectionState>(
builder: (context, dateState) {
return BlocListener<CalendarEventsBloc,
CalendarEventState>(
listenWhen: (prev, curr) =>
curr is EventsLoaded,
listener: (context, state) {
if (state is EventsLoaded) {
_eventController
.removeWhere((_) => true);
_eventController.addAll(state.events);
}
},
child: WeeklyCalendarPage(
startTime: selectedRoom
?.bookableConfig.startTime,
endTime: selectedRoom
?.bookableConfig.endTime,
weekStart: dateState.weekStart,
selectedDate: dateState.selectedDate,
eventController: _eventController,
selectedDateFromSideBarCalender: context
.watch<DateSelectionBloc>()
.state
.selectedDateFromSideBarCalender,
),
); );
}, },
); );
}, },
); ),
}, ),
), ],
), ),
], ),
), ),
), ],
), ),
], ),
), ),
), ),
), ),

View File

@ -76,29 +76,21 @@ class __SidebarContentState extends State<_SidebarContent> {
builder: (context, state) { builder: (context, state) {
return Column( return Column(
children: [ children: [
Padding( const _SidebarHeader(title: 'Spaces'),
padding: const EdgeInsets.only(top: 10.0, bottom: 10.0),
child: Container(
decoration: BoxDecoration(
color: ColorsManager.whiteColors,
boxShadow: [
BoxShadow(
color: ColorsManager.blackColor.withOpacity(0.1),
offset: const Offset(0, 4),
blurRadius: 4,
spreadRadius: 0,
),
],
),
child: _SidebarHeader(title: 'Spaces')),
),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: ColorsManager.whiteColors, color: ColorsManager.whiteColors,
borderRadius: BorderRadius.circular(8.0),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: ColorsManager.blackColor.withOpacity(0.1), color: ColorsManager.blackColor.withOpacity(0.1),
offset: const Offset(0, 4), offset: const Offset(0, -2),
blurRadius: 4,
spreadRadius: 0,
),
BoxShadow(
color: ColorsManager.blackColor.withOpacity(0.1),
offset: const Offset(0, 2),
blurRadius: 4, blurRadius: 4,
spreadRadius: 0, spreadRadius: 0,
), ),
@ -228,7 +220,7 @@ class _SidebarHeader extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(16.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [

View File

@ -66,28 +66,18 @@ class _CustomCalendarPageState extends State<CustomCalendarPage> {
weekdayLabels: const ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'], weekdayLabels: const ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
); );
return Container( return CalendarDatePicker2(
decoration: const BoxDecoration( config: config,
border: Border( value: [_selectedDate],
top: BorderSide( onValueChanged: (dates) {
color: ColorsManager.textGray, final picked = dates.first;
width: 1.0, if (picked != null) {
), setState(() {
), _selectedDate = picked;
), });
child: CalendarDatePicker2( widget.onDateChanged(picked.day, picked.month, picked.year);
config: config, }
value: [_selectedDate], },
onValueChanged: (dates) {
final picked = dates.first;
if (picked != null) {
setState(() {
_selectedDate = picked;
});
widget.onDateChanged(picked.day, picked.month, picked.year);
}
},
),
); );
} }
} }

View File

@ -32,17 +32,15 @@ class EventTileWidget extends StatelessWidget {
return Expanded( return Expanded(
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.all(5), padding: EdgeInsets.all(5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isEventEnded color: isEventEnded
? ColorsManager.grayColor.withOpacity(0.1) ? ColorsManager.grayColor.withOpacity(0.1)
: ColorsManager.blue1.withOpacity(0.1), : ColorsManager.blue1.withOpacity(0.1),
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
border: Border( border: const Border(
left: BorderSide( left: BorderSide(
color: isEventEnded color: ColorsManager.grayColor,
? ColorsManager.grayColor
: ColorsManager.secondaryColor,
width: 4, width: 4,
), ),
), ),

View File

@ -21,7 +21,7 @@ class RoomListItem extends StatelessWidget {
groupValue: isSelected ? room.uuid : null, groupValue: isSelected ? room.uuid : null,
visualDensity: const VisualDensity(vertical: -4), visualDensity: const VisualDensity(vertical: -4),
onChanged: (value) => onTap(), onChanged: (value) => onTap(),
activeColor: ColorsManager.secondaryColor, activeColor: ColorsManager.primaryColor,
title: Text( title: Text(
room.spaceName, room.spaceName,
maxLines: 2, maxLines: 2,

View File

@ -14,33 +14,26 @@ class WeekDayHeader extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ColoredBox( return Column(
color: isSelectedDay children: [
? ColorsManager.secondaryColor.withOpacity(0.1) Text(
: Colors.transparent, DateFormat('EEE').format(date).toUpperCase(),
child: Column( style: TextStyle(
children: [ fontWeight: FontWeight.w400,
const SizedBox( fontSize: 14,
height: 10, color: isSelectedDay ? Colors.blue : Colors.black,
), ),
Text( ),
DateFormat('EEE').format(date).toUpperCase(), Text(
style: const TextStyle( DateFormat('d').format(date),
fontWeight: FontWeight.w400, style: TextStyle(
fontSize: 14, fontWeight: FontWeight.w700,
color: ColorsManager.blackColor, fontSize: 20,
), color:
isSelectedDay ? ColorsManager.blue1 : ColorsManager.blackColor,
), ),
Text( ),
DateFormat('d').format(date), ],
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 30,
color: ColorsManager.blackColor,
),
),
],
),
); );
} }
} }

View File

@ -19,7 +19,6 @@ class WeekNavigation extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: 250,
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: ColorsManager.circleRolesBackground, color: ColorsManager.circleRolesBackground,
@ -33,8 +32,6 @@ class WeekNavigation extends StatelessWidget {
], ],
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
IconButton( IconButton(
iconSize: 15, iconSize: 15,
@ -43,16 +40,12 @@ class WeekNavigation extends StatelessWidget {
onPressed: onPreviousWeek, onPressed: onPreviousWeek,
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
SizedBox( Text(
width: 120, _getMonthYearText(weekStart, weekEnd),
child: Text( style: const TextStyle(
_getMonthYearText(weekStart, weekEnd), color: ColorsManager.lightGrayColor,
style: const TextStyle( fontSize: 14,
color: ColorsManager.lightGrayColor, fontWeight: FontWeight.w400,
fontSize: 14,
fontWeight: FontWeight.w400,
),
textAlign: TextAlign.center,
), ),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),

View File

@ -24,7 +24,7 @@ class WeeklyCalendarPage extends StatelessWidget {
}); });
static const double timeLineWidth = 65; static const double timeLineWidth = 65;
static const int totalDays = 7; static const int totalDays = 7;
static const double dayColumnWidth = 220; static const double dayColumnWidth = 220;
final double calendarContentWidth = final double calendarContentWidth =
timeLineWidth + (totalDays * dayColumnWidth); timeLineWidth + (totalDays * dayColumnWidth);
@ -57,10 +57,13 @@ class WeeklyCalendarPage extends StatelessWidget {
); );
} }
const double timeLineWidth = 90;
const double timeLineWidth = 65;
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
bool isInRange(DateTime date, DateTime start, DateTime end) { bool isInRange(DateTime date, DateTime start, DateTime end) {
!date.isBefore(start) && !date.isAfter(end); !date.isBefore(start) && !date.isAfter(end);
// remove this line and Check if the date is within the range // remove this line and Check if the date is within the range
@ -97,6 +100,7 @@ class WeeklyCalendarPage extends StatelessWidget {
width: width, width: width,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.orange.withOpacity(0.13), color: Colors.orange.withOpacity(0.13),
borderRadius: BorderRadius.circular(8),
), ),
); );
} else if (isSelected) { } else if (isSelected) {
@ -106,6 +110,7 @@ class WeeklyCalendarPage extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: color:
ColorsManager.spaceColor.withOpacity(0.07), ColorsManager.spaceColor.withOpacity(0.07),
borderRadius: BorderRadius.circular(8),
), ),
); );
} }
@ -138,7 +143,7 @@ class WeeklyCalendarPage extends StatelessWidget {
heightPerMinute: 1.7, heightPerMinute: 1.7,
showLiveTimeLineInAllDays: false, showLiveTimeLineInAllDays: false,
showVerticalLines: true, showVerticalLines: true,
emulateVerticalOffsetBy: -95, emulateVerticalOffsetBy: -80,
startDay: WeekDays.monday, startDay: WeekDays.monday,
liveTimeIndicatorSettings: liveTimeIndicatorSettings:
const LiveTimeIndicatorSettings( const LiveTimeIndicatorSettings(
@ -156,7 +161,7 @@ class WeeklyCalendarPage extends StatelessWidget {
}, },
timeLineWidth: timeLineWidth, timeLineWidth: timeLineWidth,
weekPageHeaderBuilder: (start, end) => Container(), weekPageHeaderBuilder: (start, end) => Container(),
weekTitleHeight: 90, weekTitleHeight: 60,
weekNumberBuilder: (firstDayOfWeek) => Padding( weekNumberBuilder: (firstDayOfWeek) => Padding(
padding: const EdgeInsets.only(right: 15, bottom: 10), padding: const EdgeInsets.only(right: 15, bottom: 10),
child: Column( child: Column(
@ -203,6 +208,8 @@ class WeeklyCalendarPage extends StatelessWidget {
}, },
); );
} }
} }
bool isSameDay(DateTime d1, DateTime d2) { bool isSameDay(DateTime d1, DateTime d2) {

View File

@ -6,7 +6,6 @@ import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_
import 'package:syncrow_web/pages/device_managment/garage_door/helper/garage_door_helper.dart'; import 'package:syncrow_web/pages/device_managment/garage_door/helper/garage_door_helper.dart';
import 'package:syncrow_web/pages/device_managment/garage_door/models/garage_door_model.dart'; import 'package:syncrow_web/pages/device_managment/garage_door/models/garage_door_model.dart';
import 'package:syncrow_web/pages/device_managment/garage_door/schedule_view/schedule_garage_view.dart'; import 'package:syncrow_web/pages/device_managment/garage_door/schedule_view/schedule_garage_view.dart';
import 'package:syncrow_web/pages/device_managment/schedule_device/schedule_widgets/schedual_view.dart';
import 'package:syncrow_web/pages/device_managment/shared/icon_name_status_container.dart'; import 'package:syncrow_web/pages/device_managment/shared/icon_name_status_container.dart';
import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dart'; import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dart';
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
@ -95,18 +94,11 @@ class GarageDoorControlView extends StatelessWidget
FetchGarageDoorSchedulesEvent( FetchGarageDoorSchedulesEvent(
deviceId: deviceId, category: 'doorcontact_state'), deviceId: deviceId, category: 'doorcontact_state'),
); );
showDialog(
showDialog<void>(
context: context, context: context,
builder: (ctx) => BlocProvider.value( builder: (ctx) => BlocProvider.value(
value: BlocProvider.of<GarageDoorBloc>(context), value: BlocProvider.of<GarageDoorBloc>(context),
child: BuildScheduleView( child: BuildGarageDoorScheduleView(status: status),
deviceUuid: deviceId,
category: 'Timer',
code: 'doorcontact_state',
countdownCode: 'Timer',
deviceType: 'GD',
),
)); ));
}, },
name: 'Scheduling', name: 'Scheduling',

View File

@ -287,8 +287,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
try { try {
if (state is ScheduleLoaded) { if (state is ScheduleLoaded) {
Status status = Status(code: '', value: ''); Status status = Status(code: '', value: '');
if (event.deviceType == 'CUR_2' || if (event.deviceType == 'CUR_2') {
event.deviceType == 'GD' ) {
status = status.copyWith( status = status.copyWith(
code: 'control', code: 'control',
value: event.functionOn == true ? 'open' : 'close'); value: event.functionOn == true ? 'open' : 'close');

View File

@ -69,7 +69,7 @@ class CountdownModeButtons extends StatelessWidget {
countDownCode: countDownCode), countDownCode: countDownCode),
); );
}, },
backgroundColor: ColorsManager.secondaryColor, backgroundColor: ColorsManager.primaryColorWithOpacity,
child: const Text('Save'), child: const Text('Save'),
), ),
), ),

View File

@ -63,7 +63,7 @@ class InchingModeButtons extends StatelessWidget {
), ),
); );
}, },
backgroundColor: ColorsManager.secondaryColor, backgroundColor: ColorsManager.primaryColor,
child: const Text('Save'), child: const Text('Save'),
), ),
), ),

View File

@ -31,12 +31,11 @@ class BuildScheduleView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (_) => ScheduleBloc( create: (_) => ScheduleBloc(deviceId: deviceUuid,)
deviceId: deviceUuid,
)
..add(ScheduleGetEvent(category: category)) ..add(ScheduleGetEvent(category: category))
..add(ScheduleFetchStatusEvent( ..add(ScheduleFetchStatusEvent(
deviceId: deviceUuid, countdownCode: countdownCode ?? '')), deviceId: deviceUuid,
countdownCode: countdownCode ?? '')),
child: Dialog( child: Dialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
insetPadding: const EdgeInsets.all(20), insetPadding: const EdgeInsets.all(20),
@ -57,7 +56,7 @@ class BuildScheduleView extends StatelessWidget {
children: [ children: [
const ScheduleHeader(), const ScheduleHeader(),
const SizedBox(height: 20), const SizedBox(height: 20),
if (deviceType == 'CUR_2' || deviceType == 'GD') if (deviceType == 'CUR_2')
const SizedBox() const SizedBox()
else else
ScheduleModeSelector( ScheduleModeSelector(
@ -77,7 +76,8 @@ class BuildScheduleView extends StatelessWidget {
category: category, category: category,
time: '', time: '',
function: Status( function: Status(
code: code.toString(), value: true), code: code.toString(),
value: true),
days: [], days: [],
), ),
isEdit: false, isEdit: false,
@ -96,7 +96,7 @@ class BuildScheduleView extends StatelessWidget {
} }
}, },
), ),
if (deviceType != 'CUR_2'|| deviceType != 'GD') if (deviceType != 'CUR_2')
if (state.scheduleMode == ScheduleModes.countdown || if (state.scheduleMode == ScheduleModes.countdown ||
state.scheduleMode == ScheduleModes.inching) state.scheduleMode == ScheduleModes.inching)
CountdownInchingView( CountdownInchingView(

View File

@ -24,13 +24,12 @@ class ScheduleManagementUI extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox( SizedBox(
width: 177, width: 170,
height: 40, height: 40,
child: DefaultButton( child: DefaultButton(
borderWidth: 4, borderColor: ColorsManager.grayColor.withOpacity(0.5),
borderColor: ColorsManager.neutralGray, padding: 2,
padding: 8, backgroundColor: ColorsManager.graysColor,
backgroundColor: ColorsManager.textFieldGreyColor,
borderRadius: 15, borderRadius: 15,
onPressed: onAddSchedule, onPressed: onAddSchedule,
child: Row( child: Row(

View File

@ -39,7 +39,7 @@ class ScheduleModeButtons extends StatelessWidget {
borderRadius: 8, borderRadius: 8,
height: 40, height: 40,
onPressed: onSave, onPressed: onSave,
backgroundColor: ColorsManager.secondaryColor, backgroundColor: ColorsManager.primaryColorWithOpacity,
child: const Text('Save'), child: const Text('Save'),
), ),
), ),

View File

@ -194,7 +194,7 @@ class _ScheduleTableView extends StatelessWidget {
child: Text(_getSelectedDays( child: Text(_getSelectedDays(
ScheduleModel.parseSelectedDays(schedule.days)))), ScheduleModel.parseSelectedDays(schedule.days)))),
Center(child: Text(formatIsoStringToTime(schedule.time, context))), Center(child: Text(formatIsoStringToTime(schedule.time, context))),
if (deviceType == 'CUR_2' || deviceType == 'GD') if (deviceType == 'CUR_2')
Center( Center(
child: Text(schedule.function.value == true ? 'open' : 'close')) child: Text(schedule.function.value == true ? 'open' : 'close'))
else else

View File

@ -23,7 +23,7 @@ class ScheduleDialogHelper {
required String deviceType, required String deviceType,
}) { }) {
bool temp; bool temp;
if (deviceType == 'CUR_2' || deviceType == 'GD') { if (deviceType == 'CUR_2') {
temp = schedule!.function.value == 'open' ? true : false; temp = schedule!.function.value == 'open' ? true : false;
} else { } else {
temp = schedule!.function.value; temp = schedule!.function.value;
@ -116,7 +116,7 @@ class ScheduleDialogHelper {
ScheduleModeButtons( ScheduleModeButtons(
onSave: () { onSave: () {
dynamic temp; dynamic temp;
if (deviceType == 'CUR_2' || deviceType == 'GD') { if (deviceType == 'CUR_2') {
temp = functionOn! ? 'open' : 'close'; temp = functionOn! ? 'open' : 'close';
} else { } else {
temp = functionOn; temp = functionOn;
@ -202,23 +202,18 @@ class ScheduleDialogHelper {
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Radio<bool>( Radio<bool>(
activeColor: ColorsManager.secondaryColor,
focusColor: ColorsManager.secondaryColor,
value: true, value: true,
groupValue: isOn, groupValue: isOn,
onChanged: (val) => onChanged(true), onChanged: (val) => onChanged(true),
), ),
Text(categor == 'CUR_2' || categor == 'GD' ? 'open' : 'On'), Text(categor == 'CUR_2' ? 'open' : 'On'),
const SizedBox(width: 10), const SizedBox(width: 10),
Radio<bool>( Radio<bool>(
activeColor: ColorsManager.secondaryColor,
focusColor: ColorsManager.secondaryColor,
value: false, value: false,
groupValue: isOn, groupValue: isOn,
onChanged: (val) => onChanged(false), onChanged: (val) => onChanged(false),
), ),
Text(categor == 'CUR_2' || categor == 'GD' ? 'close' : 'Off'), Text(categor == 'CUR_2' ? 'close' : 'Off'),
], ],
); );
} }

View File

@ -475,8 +475,8 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
horizontal: context.screenWidth * 0.3, horizontal: context.screenWidth * 0.3,
vertical: context.screenHeight * 0.3, vertical: context.screenHeight * 0.3,
), ),
minScale: 0.5, minScale: 0.1,
maxScale: 3.0, maxScale: 4.0,
constrained: false, constrained: false,
child: SizedBox( child: SizedBox(
width: context.screenWidth * 5, width: context.screenWidth * 5,

View File

@ -4,7 +4,9 @@ import 'package:syncrow_web/services/api/http_interceptor.dart';
import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
final GetIt serviceLocator = GetIt.instance; final GetIt serviceLocator = GetIt.instance;
void initialSetup() { //setupLocator() // to search for dependency injection in flutter
initialSetup() {
serviceLocator.registerSingleton<HTTPInterceptor>(HTTPInterceptor()); serviceLocator.registerSingleton<HTTPInterceptor>(HTTPInterceptor());
//Base classes
serviceLocator.registerSingleton<Dio>(HTTPService.setupDioClient()); serviceLocator.registerSingleton<Dio>(HTTPService.setupDioClient());
} }

View File

@ -1,53 +0,0 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
import 'package:syncrow_web/utils/app_routes.dart';
import 'package:syncrow_web/utils/navigation_service.dart';
import 'package:syncrow_web/utils/theme/theme.dart';
class SyncrowApp extends StatelessWidget {
const SyncrowApp({super.key});
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<CreateRoutineBloc>(
create: (context) => CreateRoutineBloc(),
),
BlocProvider(
create: (context) => HomeBloc()..add(const FetchUserInfo()),
),
BlocProvider<VisitorPasswordBloc>(
create: (context) => VisitorPasswordBloc(),
),
BlocProvider<RoutineBloc>(
create: (context) => RoutineBloc(),
),
BlocProvider<SpaceTreeBloc>(
create: (context) => SpaceTreeBloc(),
),
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
PointerDeviceKind.mouse,
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
},
),
key: NavigationService.navigatorKey,
theme: myTheme,
routerConfig: AppRoutes.router,
),
);
}
}

View File

@ -1,31 +1,17 @@
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:syncrow_web/pages/access_management/view/access_management.dart'; import 'package:syncrow_web/pages/access_management/view/access_management.dart';
import 'package:syncrow_web/pages/analytics/modules/analytics/views/analytics_page.dart'; import 'package:syncrow_web/pages/analytics/modules/analytics/views/analytics_page.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
import 'package:syncrow_web/pages/auth/view/login_page.dart'; import 'package:syncrow_web/pages/auth/view/login_page.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/view/device_managment_page.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/view/device_managment_page.dart';
import 'package:syncrow_web/pages/home/view/home_page.dart'; import 'package:syncrow_web/pages/home/view/home_page.dart';
import 'package:syncrow_web/pages/roles_and_permission/view/roles_and_permission_page.dart'; import 'package:syncrow_web/pages/roles_and_permission/view/roles_and_permission_page.dart';
import 'package:syncrow_web/pages/space_management_v2/main_module/views/space_management_page.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/view/spaces_management_page.dart';
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart'; import 'package:syncrow_web/utils/constants/routes_const.dart';
abstract final class AppRoutes { class AppRoutes {
const AppRoutes._(); static List<GoRoute> getRoutes() {
return [
static final GoRouter router = GoRouter(
initialLocation: RoutesConst.auth,
redirect: (context, state) async {
final checkToken = await AuthBloc.getTokenAndValidate();
final loggedIn = checkToken == 'Success';
final goingToLogin = state.uri.toString() == RoutesConst.auth;
if (!loggedIn && !goingToLogin) return RoutesConst.auth;
if (loggedIn && goingToLogin) return RoutesConst.home;
return null;
},
routes: [
GoRoute( GoRoute(
path: RoutesConst.auth, path: RoutesConst.auth,
builder: (context, state) => const LoginPage(), builder: (context, state) => const LoginPage(),
@ -57,6 +43,6 @@ abstract final class AppRoutes {
name: 'analytics', name: 'analytics',
builder: (context, state) => const AnalyticsPage(), builder: (context, state) => const AnalyticsPage(),
), ),
], ];
); }
} }

View File

@ -140,5 +140,6 @@ abstract class ApiEndpoints {
static const String saveSchedule = '/schedule/{deviceUuid}'; static const String saveSchedule = '/schedule/{deviceUuid}';
static const String getBookableSpaces = '/bookable-spaces'; static const String getBookableSpaces = '/bookable-spaces';
static const String getBookings = '/bookings?month={mm}-{yyyy}&space={space}'; static const String getBookings =
'/bookings?month={mm}%2F{yyyy}&space={space}';
} }