314 lines
9.3 KiB
Dart
314 lines
9.3 KiB
Dart
/*
|
|
This is wishlist page
|
|
we used AutomaticKeepAliveClientMixin to keep the state when moving from 1 navbar to another navbar, so the page is not refresh overtime
|
|
*/
|
|
|
|
import 'package:mobdr/config/global_style.dart';
|
|
import 'package:mobdr/main.dart';
|
|
import 'package:mobdr/ui/reusable/reusable_widget.dart';
|
|
import 'package:mobdr/network/api_provider.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:timelines/timelines.dart';
|
|
import 'dart:math';
|
|
|
|
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<TabSyncPage>
|
|
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<AnimatedListState> _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<Color> 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 {
|
|
///FRED
|
|
var apiResponseEtabs = await _apiProvider.SyncEtablissements();
|
|
var apiResponseVisites = await _apiProvider.SyncVisites();
|
|
var apiResponsePhotos = await _apiProvider.SyncPhotos();
|
|
|
|
if (apiResponseEtabs == 'OK') {
|
|
print("SyncEtablissements OK");
|
|
} else {
|
|
print("SyncEtablissements Error:" + apiResponseEtabs);
|
|
}
|
|
|
|
if (apiResponseVisites == 'OK') {
|
|
print("SyncVisites OK");
|
|
} else {
|
|
print("SyncVisites Error:" + apiResponseVisites);
|
|
}
|
|
|
|
if (apiResponsePhotos == 'OK') {
|
|
print("SyncPhotos OK");
|
|
} else {
|
|
print("SyncPhotos Error:" + apiResponsePhotos);
|
|
}
|
|
|
|
///
|
|
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;
|
|
}
|
|
}
|