mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2026-10-25 13:47:55 +00:00
garage door
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garagedialog.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class CreateGarageSchedule extends StatefulWidget {
|
||||
final List<Map<String, String>> days;
|
||||
final void Function(List<String> selectedDays)?
|
||||
selectDays;
|
||||
final Function(DateTime) onDateTimeChanged;
|
||||
final void Function(bool isOn)? onToggleChanged;
|
||||
|
||||
const CreateGarageSchedule({
|
||||
Key? key,
|
||||
required this.days,
|
||||
required this.selectDays,
|
||||
required this.onDateTimeChanged,
|
||||
this.onToggleChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_CreateGarageScheduleState createState() => _CreateGarageScheduleState();
|
||||
}
|
||||
|
||||
class _CreateGarageScheduleState extends State<CreateGarageSchedule> {
|
||||
List<String> selectedDays = [];
|
||||
bool isOn = true;
|
||||
String selectedControlOption = 'Open';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
const Divider(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
SizedBox(
|
||||
height: 110,
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.time,
|
||||
initialDateTime: DateTime.now(),
|
||||
onDateTimeChanged: widget.onDateTimeChanged,
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.08,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: widget.days.map((day) {
|
||||
bool isSelected = selectedDays.contains(day['day']);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (isSelected) {
|
||||
selectedDays.remove(day['day']);
|
||||
} else {
|
||||
selectedDays.add(day['day']!);
|
||||
}
|
||||
if (widget.selectDays != null) {
|
||||
widget.selectDays!(selectedDays);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
width: 50,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8, horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Colors.black
|
||||
: ColorsManager.grayColor,
|
||||
),
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
day['day']!,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: isSelected
|
||||
? Colors.black
|
||||
: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
DefaultContainer(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: 'Notification',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
trailing: Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: true,
|
||||
onChanged: (value) {
|
||||
},
|
||||
applyTheme: true,
|
||||
)),
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return GarageDialog(
|
||||
label2: 'Close',
|
||||
initialSelectedLabel: selectedControlOption,
|
||||
cancelTab: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
confirmTab: () {
|
||||
setState(() {});
|
||||
if (selectedControlOption == "Open") {
|
||||
widget.onToggleChanged!(true);
|
||||
} else if (selectedControlOption == 'Close') {
|
||||
widget.onToggleChanged!(false);
|
||||
}
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
title: 'Control',
|
||||
label1: 'Open',
|
||||
onTapLabel1: (selected) {
|
||||
setState(() {
|
||||
selectedControlOption = 'Open';
|
||||
});
|
||||
},
|
||||
onTapLabel2: (selected) {
|
||||
setState(() {
|
||||
selectedControlOption = 'Close';
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: 'Control',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
trailing: SizedBox(
|
||||
width: 70,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(
|
||||
fontColor: ColorsManager.textGray,
|
||||
text: selectedControlOption,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.textGray,
|
||||
size: 17,
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/garage_door_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_preferences_settings.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_records_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/garage_door/schedule_garage_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/garage_door/timer_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_small.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
|
||||
class GarageDoorScreen extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
|
||||
const GarageDoorScreen({super.key, this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Garage Door Opener',
|
||||
child: BlocProvider(
|
||||
create: (context) => GarageDoorBloc(GDId: device?.uuid ?? '')
|
||||
..add(const GarageDoorInitial()),
|
||||
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||
builder: (context, state) {
|
||||
final garageBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||
GarageDoorModel model = GarageDoorModel(
|
||||
tr_timecon: 0,
|
||||
countdown1: 0,
|
||||
countdownAlarm: 0,
|
||||
doorContactState: false,
|
||||
doorControl1: '',
|
||||
doorState1: '',
|
||||
switch1: false,
|
||||
voiceControl1: false,
|
||||
batteryPercentage: 0,
|
||||
);
|
||||
|
||||
if (state is LoadingNewSate) {
|
||||
model = state.doorSensor;
|
||||
} else if (state is UpdateState) {
|
||||
model = state.garageSensor;
|
||||
}
|
||||
return state is GarageDoorLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
garageBloc.add(const GarageDoorInitial());
|
||||
},
|
||||
child: ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.sizeOf(context).height * 0.8,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: InkWell(
|
||||
overlayColor: WidgetStateProperty.all(
|
||||
Colors.transparent),
|
||||
onTap: () {},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.circular(890),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.white
|
||||
.withOpacity(0.1),
|
||||
blurRadius: 24,
|
||||
offset: const Offset(-5, -5),
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Colors.black
|
||||
.withOpacity(0.11),
|
||||
blurRadius: 25,
|
||||
offset: const Offset(5, 5),
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Colors.black
|
||||
.withOpacity(0.13),
|
||||
blurRadius: 30,
|
||||
offset: const Offset(5, 5),
|
||||
blurStyle: BlurStyle.inner,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
garageBloc.add(ToggleDoorEvent(
|
||||
toggle:
|
||||
garageBloc.toggleDoor));
|
||||
},
|
||||
child: GradientWidget(
|
||||
doorStatus: garageBloc.toggleDoor,
|
||||
seconds:
|
||||
garageBloc.secondSelected,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DefaultContainer(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
TimerScheduleScreen(
|
||||
device: device!,
|
||||
switchCode: 'switch_1',
|
||||
deviceCode: 'countdown_1',
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 46, maxWidth: 50),
|
||||
child: SvgPicture.asset(
|
||||
Assets.garageSchedule),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Flexible(
|
||||
child: FittedBox(
|
||||
child: BodySmall(
|
||||
text: 'Schedule',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: DefaultContainer(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => TimerPage(
|
||||
device: device!,
|
||||
switchCode: 'switch_1',
|
||||
deviceCode: 'countdown_1',
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 46, maxWidth: 50),
|
||||
child: SvgPicture.asset(
|
||||
Assets.garageCountdown),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Flexible(
|
||||
child: FittedBox(
|
||||
child: BodySmall(
|
||||
text: 'Countdown',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DefaultContainer(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
GarageRecordsScreen(
|
||||
GDId: device!.uuid!)),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 46, maxWidth: 50),
|
||||
child: SvgPicture.asset(
|
||||
Assets.doorRecordsIcon),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Flexible(
|
||||
child: FittedBox(
|
||||
child: BodySmall(
|
||||
text: 'Records',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: DefaultContainer(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
PreferencesPage(
|
||||
GDId: device!.uuid!)),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 46, maxWidth: 50),
|
||||
child: SvgPicture.asset(
|
||||
Assets.garagePreferencesIcon),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Flexible(
|
||||
child: FittedBox(
|
||||
child: BodySmall(
|
||||
text: 'Preferences',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GradientWidget extends StatefulWidget {
|
||||
const GradientWidget({required this.seconds, required this.doorStatus});
|
||||
final int seconds;
|
||||
final bool doorStatus;
|
||||
|
||||
@override
|
||||
State<GradientWidget> createState() => _GradientWidgetState();
|
||||
}
|
||||
|
||||
class _GradientWidgetState extends State<GradientWidget>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late ScrollController _scrollController;
|
||||
late AnimationController _animationController;
|
||||
late Animation<double> _itemExtentAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController = ScrollController();
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(seconds: widget.seconds),
|
||||
);
|
||||
_itemExtentAnimation = Tween<double>(
|
||||
begin: widget.doorStatus ? 0 : 15, end: widget.doorStatus ? 15 : 0)
|
||||
.animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
)..addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (widget.doorStatus) {
|
||||
_openAnimation();
|
||||
} else {
|
||||
_closeAnimation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _openAnimation() {
|
||||
_animationController.forward();
|
||||
}
|
||||
|
||||
void _closeAnimation() {
|
||||
_animationController.reverse();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 300,
|
||||
height: 300,
|
||||
padding: EdgeInsets.only(right: 10),
|
||||
child: Stack(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.openGarageIcon,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(child: Container()),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 104,
|
||||
child: ListView.builder(
|
||||
itemExtent: _itemExtentAnimation.value,
|
||||
controller: _scrollController,
|
||||
itemCount: 4,
|
||||
itemBuilder: (context, index) {
|
||||
return Center(child: GradientWidget1());
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GradientWidget1 extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 97,
|
||||
height: 15,
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0xFF017297),
|
||||
Color(0xFF024C67),
|
||||
],
|
||||
stops: [0.0, 1.0],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.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/resource_manager/color_manager.dart';
|
||||
|
||||
class PreferencesPage extends StatelessWidget {
|
||||
final String GDId;
|
||||
const PreferencesPage({super.key, required this.GDId});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Preferences',
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
GarageDoorBloc(GDId: GDId)..add(const GarageDoorInitial()),
|
||||
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||
builder: (context, state) {
|
||||
final garageDoorBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||
|
||||
return state is GarageDoorLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
const Row(
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: 'Warnings',
|
||||
fontColor: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
],
|
||||
),
|
||||
DefaultContainer(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: 'Alarm when door is open',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
trailing: Container(
|
||||
width: 100,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
height: 30,
|
||||
width: 1,
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value:
|
||||
garageDoorBloc.lowBattery,
|
||||
onChanged: (value) {
|
||||
// context
|
||||
// .read<GarageDoorBloc>()
|
||||
// .add(
|
||||
// ToggleLowBatteryEvent(
|
||||
// value));
|
||||
},
|
||||
applyTheme: true,
|
||||
)),
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: 'Other Settings',
|
||||
fontColor: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
],
|
||||
),
|
||||
DefaultContainer(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SecondDialog(
|
||||
label2: 'Close',
|
||||
initialSelectedLabel: garageDoorBloc
|
||||
.secondSelected
|
||||
.toString(),
|
||||
cancelTab: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
confirmTab: (v) {
|
||||
garageDoorBloc
|
||||
.add(SelectSecondsEvent(seconds: v));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
title: 'Control',
|
||||
label1: 'Open',
|
||||
onTapLabel1: (selected) {},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: 'Opening and Closing Time',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
trailing: Container(
|
||||
height: 90,
|
||||
width: 120,
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(
|
||||
fontColor: ColorsManager.textGray,
|
||||
text:
|
||||
'${garageDoorBloc.secondSelected.toString()} Seconds',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 15,
|
||||
color: ColorsManager.textGray,
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class SecondDialog extends StatefulWidget {
|
||||
final String label1;
|
||||
final String label2;
|
||||
final String title;
|
||||
|
||||
final Function(String)? onTapLabel1;
|
||||
final Function()? cancelTab;
|
||||
final Function(int selectedSecond)? confirmTab;
|
||||
|
||||
final String? initialSelectedLabel;
|
||||
|
||||
SecondDialog({
|
||||
required this.label1,
|
||||
required this.label2,
|
||||
required this.title,
|
||||
this.onTapLabel1,
|
||||
required this.cancelTab,
|
||||
required this.confirmTab,
|
||||
this.initialSelectedLabel,
|
||||
});
|
||||
|
||||
@override
|
||||
_SecondDialogState createState() => _SecondDialogState();
|
||||
}
|
||||
|
||||
class _SecondDialogState extends State<SecondDialog> {
|
||||
late String _selectedOption;
|
||||
late int selectedSecond;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Parse the initialSelectedLabel as an integer. Default to 10 if invalid or not provided.
|
||||
selectedSecond = int.tryParse(widget.initialSelectedLabel ?? '10') ?? 10;
|
||||
_selectedOption = widget.initialSelectedLabel ?? '';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
BodyLarge(
|
||||
text: widget.title,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 15),
|
||||
child: Divider(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 15, right: 15, bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Center(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 100,
|
||||
child: CupertinoPicker(
|
||||
itemExtent: 40.0,
|
||||
scrollController: FixedExtentScrollController(
|
||||
// Set the initial position based on selectedSecond
|
||||
initialItem: selectedSecond - 10,
|
||||
),
|
||||
onSelectedItemChanged: (int index) {
|
||||
setState(() {
|
||||
selectedSecond = index + 10;
|
||||
});
|
||||
},
|
||||
children: List<Widget>.generate(111, (int index) {
|
||||
return Center(
|
||||
child: BodyLarge(
|
||||
text: (index + 10).toString().padLeft(2, '0'),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 30,
|
||||
color: Colors.blue),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
const Text('Sec'),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: SizedBox(
|
||||
child: InkWell(
|
||||
onTap: widget.cancelTab,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
widget.confirmTab?.call(selectedSecond);
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Confirm',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.primaryColor,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_report_model.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/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class GarageRecordsScreen extends StatelessWidget {
|
||||
final String GDId;
|
||||
const GarageRecordsScreen({super.key, required this.GDId});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Records',
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
GarageDoorBloc(GDId: GDId)..add(const ReportLogsInitial()),
|
||||
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||
builder: (context, state) {
|
||||
final garageDoorBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||
final Map<String, List<DeviceEvent>> groupedRecords = {};
|
||||
|
||||
if (state is GarageDoorLoadingState) {
|
||||
return const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50, height: 50, child: CircularProgressIndicator()),
|
||||
);
|
||||
} else if (state is UpdateState) {
|
||||
for (var record in garageDoorBloc.recordGroups.data!) {
|
||||
final DateTime eventDateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
|
||||
final String formattedDate =
|
||||
DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
|
||||
|
||||
// Group by formatted date
|
||||
if (groupedRecords.containsKey(formattedDate)) {
|
||||
groupedRecords[formattedDate]!.add(record);
|
||||
} else {
|
||||
groupedRecords[formattedDate] = [record];
|
||||
}
|
||||
}
|
||||
}
|
||||
return ListView.builder(
|
||||
itemCount: groupedRecords.length,
|
||||
itemBuilder: (context, index) {
|
||||
final String date = groupedRecords.keys.elementAt(index);
|
||||
final List<DeviceEvent> recordsForDate = groupedRecords[date]!;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 5, top: 10),
|
||||
child: Text(
|
||||
date,
|
||||
style: const TextStyle(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
DefaultContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
...recordsForDate.asMap().entries.map((entry) {
|
||||
final int idx = entry.key;
|
||||
final DeviceEvent record = entry.value;
|
||||
final DateTime eventDateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
record.eventTime!);
|
||||
final String formattedTime =
|
||||
DateFormat('HH:mm:ss').format(eventDateTime);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
record.value == 'true'
|
||||
? Icons.radio_button_checked
|
||||
: Icons.radio_button_unchecked,
|
||||
color: record.value == 'true'
|
||||
? Colors.blue
|
||||
: Colors.grey,
|
||||
),
|
||||
title: Text(
|
||||
record.value == 'true'
|
||||
? "Opened"
|
||||
: "Closed",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
subtitle: Text('$formattedTime'),
|
||||
),
|
||||
),
|
||||
if (idx != recordsForDate.length - 1)
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
import 'package:flutter/material.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/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class GarageDialog extends StatefulWidget {
|
||||
final String label1;
|
||||
final String label2;
|
||||
final String title;
|
||||
|
||||
final Function(String)? onTapLabel1;
|
||||
final Function(String)? onTapLabel2;
|
||||
final Function()? cancelTab;
|
||||
final Function()? confirmTab;
|
||||
|
||||
final String? initialSelectedLabel;
|
||||
|
||||
GarageDialog({
|
||||
required this.label1,
|
||||
required this.label2,
|
||||
required this.title,
|
||||
this.onTapLabel1,
|
||||
this.onTapLabel2,
|
||||
required this.cancelTab,
|
||||
required this.confirmTab,
|
||||
this.initialSelectedLabel,
|
||||
});
|
||||
|
||||
@override
|
||||
_GarageDialogState createState() => _GarageDialogState();
|
||||
}
|
||||
|
||||
class _GarageDialogState extends State<GarageDialog> {
|
||||
late String _selectedOption;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_selectedOption = widget.initialSelectedLabel ?? '';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
BodyLarge(
|
||||
text: widget.title,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 15),
|
||||
child: Divider(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildCheckboxOption(
|
||||
label: widget.label1,
|
||||
onTap: widget.onTapLabel1,
|
||||
),
|
||||
_buildCheckboxOption(
|
||||
label: widget.label2,
|
||||
onTap: widget.onTapLabel2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: SizedBox(
|
||||
child: InkWell(
|
||||
onTap: widget.cancelTab,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: InkWell(
|
||||
onTap: widget.confirmTab,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Confirm',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.primaryColor,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCheckboxOption(
|
||||
{required String label, Function(String)? onTap}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10, top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: label,
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400),
|
||||
),
|
||||
CircularCheckbox(
|
||||
value: _selectedOption == label,
|
||||
onChanged: (bool? value) {
|
||||
if (value == true) {
|
||||
setState(() {
|
||||
_selectedOption = label;
|
||||
});
|
||||
if (onTap != null) {
|
||||
onTap(label);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CircularCheckbox extends StatefulWidget {
|
||||
final bool value;
|
||||
final ValueChanged<bool?> onChanged;
|
||||
|
||||
CircularCheckbox({required this.value, required this.onChanged});
|
||||
|
||||
@override
|
||||
_CircularCheckboxState createState() => _CircularCheckboxState();
|
||||
}
|
||||
|
||||
class _CircularCheckboxState extends State<CircularCheckbox> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
widget.onChanged(!widget.value);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: widget.value
|
||||
? ColorsManager.primaryColorWithOpacity.withOpacity(0.01)
|
||||
: Colors.grey,
|
||||
width: 2.0,
|
||||
),
|
||||
color: widget.value
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: Colors.transparent,
|
||||
),
|
||||
width: 24.0,
|
||||
height: 24.0,
|
||||
child: widget.value
|
||||
? const Icon(
|
||||
Icons.check,
|
||||
color: Colors.white,
|
||||
size: 16.0,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/garage_door/create_schedule_garage.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/schedule_list.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||
|
||||
class TimerScheduleScreen extends StatelessWidget {
|
||||
final DeviceModel device;
|
||||
final String deviceCode;
|
||||
final String switchCode;
|
||||
const TimerScheduleScreen(
|
||||
{required this.device,
|
||||
required this.deviceCode,
|
||||
required this.switchCode,
|
||||
super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
),
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
GarageDoorBloc(GDId: device.uuid ?? '')..add(GetScheduleEvent()),
|
||||
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||
builder: (context, state) {
|
||||
final garageBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||
Duration duration = Duration.zero;
|
||||
int countNum = 0;
|
||||
if (state is UpdateTimerState) {
|
||||
countNum = state.seconds;
|
||||
} else if (state is TimerRunInProgress) {
|
||||
countNum = state.remainingTime;
|
||||
} else if (state is TimerRunComplete) {
|
||||
countNum = 0;
|
||||
} else if (state is LoadingNewSate) {
|
||||
countNum = 0;
|
||||
}
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) {
|
||||
if (!didPop) {
|
||||
garageBloc.add(OnClose());
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: DefaultTabController(
|
||||
length: 2,
|
||||
child: DefaultScaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: const BodyLarge(
|
||||
text: 'Schedule',
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
actions: [
|
||||
garageBloc.createSchedule == true
|
||||
? TextButton(
|
||||
onPressed: () {
|
||||
garageBloc.add(ScheduleSaveapp());
|
||||
},
|
||||
child: const Text('Save'))
|
||||
: IconButton(
|
||||
onPressed: () {
|
||||
garageBloc.add(
|
||||
const ToggleCreateScheduleEvent(
|
||||
index: 1));
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
)
|
||||
],
|
||||
),
|
||||
child: state is GarageDoorLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: const ShapeDecoration(
|
||||
color: ColorsManager.onPrimaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(30)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child: garageBloc.createSchedule == true
|
||||
? CreateGarageSchedule(
|
||||
|
||||
onToggleChanged: (bool value) {
|
||||
garageBloc.toggleSchedule = value;
|
||||
},
|
||||
onDateTimeChanged:
|
||||
(DateTime dateTime) {
|
||||
garageBloc.selectedTime =
|
||||
dateTime;
|
||||
},
|
||||
days: garageBloc.days,
|
||||
selectDays:
|
||||
(List<String> selectedDays) {
|
||||
garageBloc.selectedDays =
|
||||
selectedDays;
|
||||
},
|
||||
)
|
||||
: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 10),
|
||||
child: ScheduleListView(
|
||||
listSchedule:
|
||||
garageBloc.listSchedule,
|
||||
onDismissed: (scheduleId) {
|
||||
garageBloc.listSchedule
|
||||
.removeWhere((schedule) =>
|
||||
schedule.scheduleId ==
|
||||
scheduleId);
|
||||
garageBloc.add(
|
||||
DeleteScheduleEvent(
|
||||
id: scheduleId));
|
||||
},
|
||||
onToggleSchedule:
|
||||
(scheduleId, isEnabled) {
|
||||
garageBloc
|
||||
.add(ToggleScheduleEvent(
|
||||
id: scheduleId,
|
||||
toggle: isEnabled,
|
||||
));
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _formatDuration(int seconds) {
|
||||
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
|
||||
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
|
||||
final secs = (seconds % 60).toString().padLeft(2, '0');
|
||||
return '$hours:$minutes:$secs';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.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/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||
|
||||
class TimerPage extends StatelessWidget {
|
||||
final DeviceModel device;
|
||||
final String deviceCode;
|
||||
final String switchCode;
|
||||
const TimerPage(
|
||||
{required this.device,
|
||||
required this.deviceCode,
|
||||
required this.switchCode,
|
||||
super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
),
|
||||
child: BlocProvider(
|
||||
create: (context) => GarageDoorBloc(GDId: device.uuid ?? '')
|
||||
..add(GetCounterEvent(deviceCode: deviceCode)),
|
||||
child: BlocBuilder<GarageDoorBloc, GarageDoorSensorState>(
|
||||
builder: (context, state) {
|
||||
final oneGangBloc = BlocProvider.of<GarageDoorBloc>(context);
|
||||
Duration duration = Duration.zero;
|
||||
int countNum = 0;
|
||||
if (state is UpdateTimerState) {
|
||||
countNum = state.seconds;
|
||||
} else if (state is TimerRunInProgress) {
|
||||
countNum = state.remainingTime;
|
||||
} else if (state is TimerRunComplete) {
|
||||
countNum = 0;
|
||||
} else if (state is LoadingNewSate) {
|
||||
countNum = 0;
|
||||
}
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) {
|
||||
if (!didPop) {
|
||||
oneGangBloc.add(OnClose());
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: DefaultTabController(
|
||||
length: 2,
|
||||
child: DefaultScaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: const BodyLarge(
|
||||
text: 'Countdown',
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
child: state is GarageDoorLoadingState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: const ShapeDecoration(
|
||||
color: ColorsManager.onPrimaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(30)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
countNum > 0
|
||||
? BodyLarge(
|
||||
text: _formatDuration(countNum),
|
||||
fontColor: ColorsManager
|
||||
.slidingBlueColor,
|
||||
fontSize: 40,
|
||||
)
|
||||
: CupertinoTimerPicker(
|
||||
mode:
|
||||
CupertinoTimerPickerMode.hm,
|
||||
onTimerDurationChanged:
|
||||
(Duration newDuration) {
|
||||
duration = newDuration;
|
||||
},
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (state is LoadingNewSate) {
|
||||
return;
|
||||
}
|
||||
if (countNum > 0) {
|
||||
oneGangBloc.add(
|
||||
const SetCounterValue(
|
||||
deviceCode:
|
||||
'countdown_1',
|
||||
duration:
|
||||
Duration.zero));
|
||||
} else if (duration !=
|
||||
Duration.zero) {
|
||||
oneGangBloc.add(SetCounterValue(
|
||||
deviceCode: 'countdown_1',
|
||||
duration: duration));
|
||||
}
|
||||
},
|
||||
child: SvgPicture.asset(countNum > 0
|
||||
? Assets.pauseIcon
|
||||
: Assets.playIcon)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _formatDuration(int seconds) {
|
||||
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
|
||||
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
|
||||
final secs = (seconds % 60).toString().padLeft(2, '0');
|
||||
return '$hours:$minutes:$secs';
|
||||
}
|
||||
}
|
||||
@@ -142,8 +142,7 @@ class OneTouchSetting extends StatelessWidget {
|
||||
bottom: 10, top: 10),
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
oneTouchBloc.optionSelected =
|
||||
'light_mode';
|
||||
oneTouchBloc.optionSelected = 'light_mode';
|
||||
final result = await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_sensor_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_door_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
|
||||
@@ -187,6 +188,14 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
ThreeTouchInterface(touchSwitch: device)));
|
||||
|
||||
case DeviceType.GarageDoor:
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
GarageDoorScreen(device: device)));
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user