import 'package:flutter/material.dart'; import 'package:timelines/timelines.dart'; import 'dart:math'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/ui/reusable/reusable_widget.dart'; import 'package:mobdr/network/api_provider.dart'; import 'package:mobdr/main.dart'; import 'package:mobdr/ui/home/tab_home.dart'; const completeColor = Color(0xff5e6172); const inProgressColor = Color(0xff5ec792); const todoColor = Color(0xffd1d2d7); const failedColor = Colors.red; class TabSyncPage extends StatefulWidget { @override _TabSyncPageState createState() => _TabSyncPageState(); } class _TabSyncPageState extends State with AutomaticKeepAliveClientMixin { // initialize global function and reusable widget //final _globalFunction = GlobalFunction(); final _reusableWidget = ReusableWidget(); final _processes = ['Btqs', 'Params', 'Visites', 'Photos', 'Logs']; final ApiProvider _apiProvider = ApiProvider(); // TODO: A voir si bien positionné // _listKey is used for AnimatedList //final GlobalKey _listKey = GlobalKey(); int _processIndex = 1; Color getColor(int index) { if (index == _processIndex) { return inProgressColor; } else if (index < _processIndex) { return completeColor; } else { return todoColor; } } // keep the state to do not refresh when switch navbar @override bool get wantKeepAlive => true; @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { // if we used AutomaticKeepAliveClientMixin, we must call super.build(context); super.build(context); return Scaffold( backgroundColor: Colors.white, appBar: AppBar( iconTheme: IconThemeData( color: GlobalStyle.appBarIconThemeColor, ), elevation: GlobalStyle.appBarElevation, title: Text( 'Synchronisation', style: GlobalStyle.appBarTitle, ), backgroundColor: GlobalStyle.appBarBackgroundColor, systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle, bottom: _reusableWidget.bottomAppBar(), ), body: Timeline.tileBuilder( theme: TimelineThemeData( direction: Axis.horizontal, connectorTheme: ConnectorThemeData( space: 30.0, thickness: 5.0, ), ), builder: TimelineTileBuilder.connected( connectionDirection: ConnectionDirection.before, itemExtentBuilder: (_, __) => MediaQuery.of(context).size.width / _processes.length, oppositeContentsBuilder: (context, index) { return Padding( padding: const EdgeInsets.only(bottom: 15.0), child: Image.asset( 'assets/images/process_timeline/status${index + 1}.png', width: 50.0, color: getColor(index), ), ); }, contentsBuilder: (context, index) { return Padding( padding: const EdgeInsets.only(top: 15.0), child: Text( _processes[index], style: TextStyle( fontWeight: FontWeight.bold, color: getColor(index), ), ), ); }, indicatorBuilder: (_, index) { var color; var child; if (index == _processIndex) { color = inProgressColor; child = Padding( padding: const EdgeInsets.all(8.0), child: CircularProgressIndicator( strokeWidth: 3.0, valueColor: AlwaysStoppedAnimation(Colors.white), ), ); } else if (index < _processIndex) { color = failedColor; child = Icon( Icons.cancel, color: Colors.white, size: 20.0, ); } else { color = todoColor; } if (index <= _processIndex) { return Stack( children: [ CustomPaint( size: Size(30.0, 30.0), painter: _BezierPainter( color: color, drawStart: index > 0, drawEnd: index < _processIndex, ), ), DotIndicator( size: 30.0, color: color, child: child, ), ], ); } else { return Stack( children: [ CustomPaint( size: Size(15.0, 15.0), painter: _BezierPainter( color: color, drawEnd: index < _processes.length - 1, ), ), OutlinedDotIndicator( borderWidth: 4.0, color: color, ), ], ); } }, connectorBuilder: (_, index, type) { if (index > 0) { if (index == _processIndex) { final prevColor = getColor(index - 1); final color = getColor(index); List gradientColors; if (type == ConnectorType.start) { gradientColors = [Color.lerp(prevColor, color, 0.5)!, color]; } else { gradientColors = [ prevColor, Color.lerp(prevColor, color, 0.5)! ]; } return DecoratedLineConnector( decoration: BoxDecoration( gradient: LinearGradient( colors: gradientColors, ), ), ); } else { return SolidLineConnector( color: getColor(index), ); } } else { return null; } }, itemCount: _processes.length, ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.chevron_right), onPressed: () async { var futures = [ _apiProvider.SyncEtablissements(), _apiProvider.SyncVisites(), _apiProvider.SyncPhotos(), ]; objectbox.etabBox.removeAll(); objectbox.etabCompetitorBox.removeAll(); objectbox.visitBox.removeAll(); objectbox.visitTagBox.removeAll(); objectbox.visitPhotoBox.removeAll(); objectbox.PhotoTypologyBox.removeAll(); var results = await Future.wait(futures); if (results[0] == 'OK') { print("SyncEtablissements OK"); } else { print("SyncEtablissements Error:" + results[0]); } if (results[1] == 'OK') { print("SyncVisites OK"); } else { print("SyncVisites Error:" + results[1]); } if (results[0] == 'OK') { print("SyncPhotos OK"); } else { print("SyncPhotos Error:" + results[0]); } /// setState(() { _processIndex = (_processIndex + 1) % _processes.length; }); }, backgroundColor: inProgressColor, ), ); } } /// hardcoded bezier painter class _BezierPainter extends CustomPainter { const _BezierPainter({ required this.color, this.drawStart = true, this.drawEnd = true, }); final Color color; final bool drawStart; final bool drawEnd; Offset _offset(double radius, double angle) { return Offset( radius * cos(angle) + radius, radius * sin(angle) + radius, ); } @override void paint(Canvas canvas, Size size) { final paint = Paint() ..style = PaintingStyle.fill ..color = color; final radius = size.width / 2; var angle; var offset1; var offset2; var path; if (drawStart) { angle = 3 * pi / 4; offset1 = _offset(radius, angle); offset2 = _offset(radius, -angle); path = Path() ..moveTo(offset1.dx, offset1.dy) ..quadraticBezierTo(0.0, size.height / 2, -radius, radius) ..quadraticBezierTo(0.0, size.height / 2, offset2.dx, offset2.dy) ..close(); canvas.drawPath(path, paint); } if (drawEnd) { angle = -pi / 4; offset1 = _offset(radius, angle); offset2 = _offset(radius, -angle); path = Path() ..moveTo(offset1.dx, offset1.dy) ..quadraticBezierTo( size.width, size.height / 2, size.width + radius, radius) ..quadraticBezierTo(size.width, size.height / 2, offset2.dx, offset2.dy) ..close(); canvas.drawPath(path, paint); } } @override bool shouldRepaint(_BezierPainter oldDelegate) { return oldDelegate.color != color || oldDelegate.drawStart != drawStart || oldDelegate.drawEnd != drawEnd; } }