Skip to content

Instantly share code, notes, and snippets.

@moses-nganga
Created June 28, 2019 13:22
Show Gist options
  • Save moses-nganga/3d578a58f50a9c15e5ccda2ae7e598e1 to your computer and use it in GitHub Desktop.
Save moses-nganga/3d578a58f50a9c15e5ccda2ae7e598e1 to your computer and use it in GitHub Desktop.
Code from Poa! Ops Mobile Solution
import 'dart:math';
import 'dart:ui';
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:intl/intl.dart';
import 'package:poa/src/models/surveys.dart';
import 'package:poa/src/repository/api_provider.dart';
import 'package:poa/src/screens/survey/activation.dart';
import 'package:poa/src/screens/survey/materials_report.dart';
import 'package:poa/src/screens/survey/post_install_survey.dart';
import 'package:poa/src/screens/survey/quality_control.dart';
import 'package:poa/src/screens/survey/survey_task.dart';
import 'package:poa/src/utilities/CustomIcons.dart';
import 'package:poa/src/utilities/todo.dart';
import 'package:url_launcher/url_launcher.dart';
class ColorChoices {
static const List<Color> colors = [
const Color(0xFF5A89E6),
const Color(0xFF702082),
const Color(0xFFF77B67),
const Color(0xFF4EC5AC),
];
}
double numOfItems;
class Task extends StatefulWidget {
Task({Key key, this.title}) : super(key: key);
final String title;
@override
createState() => new TaskState();
}
class TaskState extends State<Task> with TickerProviderStateMixin {
ScrollController scrollController;
Color backgroundColor;
Tween<Color> colorTween;
int currentPage = 0;
Color constBackColor;
List<RfSurvey> surveys;
Future<List<RfSurvey>> surveyList;
TextEditingController controller = new TextEditingController();
List<RfSurvey> _filteredList;
List<RfSurvey> _surveyList;
double numOfItems;
var api_provider = ApiProvider();
@override
void initState() {
super.initState();
//Setup the Surveys
getSurveys();
surveyList = api_provider.getPendingSurveys();
final _random = new Random();
colorTween = new ColorTween(
begin: ColorChoices.colors[0], end: ColorChoices.colors[1]);
backgroundColor = ColorChoices.colors[1];
}
@override
Widget build(BuildContext context) {
final double _width = MediaQuery.of(context).size.width;
final double _ratioW = _width / 375.0;
final double _height = MediaQuery.of(context).size.height;
final double _ratioH = _height / 812.0;
return new Container(
decoration: new BoxDecoration(color: backgroundColor),
child: new Scaffold(
backgroundColor: Colors.transparent,
appBar: new AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
title: new Text(
"Poa! Tech Ops",
style: TextStyle(color: Colors.white),
),
leading: new IconButton(
icon: new Icon(
CustomIcons.menu,
color: Colors.white,
),
onPressed: () {},
),
),
body: new Container(
child: new Stack(
children: <Widget>[
new Container(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
padding: const EdgeInsets.only(
top: 20.0, bottom: 20.0, left: 50.0, right: 60.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(bottom: 25.0),
child: new Container(
decoration: new BoxDecoration(
boxShadow: [
new BoxShadow(
color: Colors.black38,
offset: new Offset(5.0, 5.0),
blurRadius: 15.0)
],
shape: BoxShape.circle,
),
),
),
new Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: new Text(
"Hello, John.",
style: new TextStyle(
color: Colors.white, fontSize: 30.0),
),
),
new Text(
surveys == null
? ''
: (surveys.length > 5
? "Quite a busy day we have today."
: "We have an easy day today"),
style: new TextStyle(color: Colors.white70),
),
new Text(
"You have " +
(surveys == null
? ''
: surveys.length.toString()) +
" installs to do today.",
style: new TextStyle(color: Colors.white70),
),
],
),
),
new Container(
height: 350.0,
width: _width,
child: FutureBuilder(
future: surveyList,
builder:
(BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
);
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else if (snapshot.hasData)
return _createScrollView(context, snapshot);
else
return Text('No Pending Surveys Found');
}
}),
)
],
),
),
],
),
)),
);
}
Widget _createScrollView(BuildContext, AsyncSnapshot snapshot) {
List<RfSurvey> surveys = snapshot.data;
return ListView.builder(
padding: const EdgeInsets.only(left: 40.0, right: 40.0),
scrollDirection: Axis.horizontal,
physics: new CustomScrollPhysics(),
controller: scrollController,
itemExtent: MediaQuery.of(context).size.width - 80,
itemCount: surveys.length,
itemBuilder: (context, index) {
return new Padding(
padding: EdgeInsets.only(
left: 10.0, right: 10.0, top: 20.0, bottom: 30.0),
child: new InkWell(
onTap: () {
Navigator.of(context).push(new PageRouteBuilder(
pageBuilder: (context, Animation<double> animation,
Animation<double> secondaryAnimation) =>
new DetailPage(survey: surveys[index]),
transitionsBuilder: (
context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return new SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),
child: new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, 1.0),
).animate(secondaryAnimation),
child: child,
),
);
},
transitionDuration: const Duration(milliseconds: 1000)));
},
child: new Container(
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(10.0),
boxShadow: [
new BoxShadow(
color: Colors.black.withAlpha(70),
offset: const Offset(3.0, 10.0),
blurRadius: 15.0)
]),
height: 250.0,
child: new Stack(
children: <Widget>[
new Hero(
tag: surveys[index].uid + "_background",
child: new Container(
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.circular(10.0),
),
),
),
new Padding(
padding: const EdgeInsets.all(16.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Hero(
tag: surveys[index].uid + "_icon",
child: new Container(
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(
color: Colors.grey.withAlpha(70),
style: BorderStyle.solid,
width: 1.0),
),
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Icon(Icons.group,
color: Colors.cyan),
),
),
),
new Expanded(
child: new Container(
alignment: Alignment.topRight,
child: new Hero(
tag: surveys[index].uid +
"_more_vert",
child: new Material(
color: Colors.transparent,
type: MaterialType.transparency,
child: new IconButton(
icon: new Icon(
Icons.phone_in_talk,
color: Colors.grey,
),
onPressed: () => launch('tel:' +
surveys[index]
.primaryPhone),
),
),
)),
)
],
),
),
new Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: new Align(
alignment: Alignment.bottomLeft,
child: new Hero(
tag: surveys[index].uid + "_title",
child: new Material(
color: Colors.transparent,
child: new Text(
surveys[index].username,
style: new TextStyle(fontSize: 30.0),
),
),
)),
),
new Align(
alignment: Alignment.bottomLeft,
child: new Hero(
tag: surveys[index].uid + "_progress_bar",
child: new Material(
color: Colors.transparent,
child: new Row(
children: <Widget>[
new Expanded(
child:
new LinearProgressIndicator(
value: 30,
backgroundColor:
Colors.grey.withAlpha(50),
valueColor:
new AlwaysStoppedAnimation<
Color>(
ColorChoices.colors[1]),
),
),
new Padding(
padding: const EdgeInsets.only(
left: 5.0),
child: Container()),
],
),
)))
],
),
),
],
)),
));
});
}
List<RfSurvey> getSurveys() {
api_provider.getPendingSurveys().then((surveyList) {
setState(() {
surveys = surveyList;
numOfItems = surveys.length.toDouble();
});
});
}
}
class DetailPage extends StatefulWidget {
DetailPage({@required this.survey, Key key}) : super(key: key);
final RfSurvey survey;
@override
_DetailPageState createState() => new _DetailPageState();
}
class _DetailPageState extends State<DetailPage> with TickerProviderStateMixin {
double percentComplete;
AnimationController animationBar;
double barPercent = 0.0;
Tween<double> animT;
AnimationController scaleAnimation;
TodoObject todoObject = new TodoObject.import(
"1", "Custom", 1, ColorChoices.colors[1], Icons.camera_front, {
new DateTime.now(): [
new TaskObject("RF Survey", SurveyTask(), new DateTime.now()),
new TaskObject("Materials Report", MaterialsReport(), new DateTime.now()),
new TaskObject("Activation", Activation(), new DateTime.now()),
new TaskObject(
"Post Install Survey", PostInstallSurvey(), new DateTime.now()),
new TaskObject("Quality Control", QualityControl(), new DateTime.now()),
],
});
@override
void initState() {
scaleAnimation = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1000),
lowerBound: 0.0,
upperBound: 1.0);
percentComplete = 3.0;
barPercent = percentComplete;
animationBar = new AnimationController(
vsync: this, duration: const Duration(milliseconds: 100))
..addListener(() {
setState(() {
barPercent = animT.lerp(animationBar.value);
});
});
;
animT = new Tween<double>(begin: percentComplete, end: percentComplete);
scaleAnimation.forward();
super.initState();
}
void updateBarPercent() async {
double newPercentComplete = 30.0;
if (animationBar.status == AnimationStatus.forward ||
animationBar.status == AnimationStatus.completed) {
animT.begin = newPercentComplete;
await animationBar.reverse();
} else if (animationBar.status == AnimationStatus.reverse ||
animationBar.status == AnimationStatus.dismissed) {
animT.end = newPercentComplete;
await animationBar.forward();
} else {
print("wtf");
}
percentComplete = newPercentComplete;
}
@override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
new Hero(
tag: widget.survey.uid + "_background",
child: new Container(
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.circular(0.0),
),
),
),
new Scaffold(
backgroundColor: Colors.transparent,
appBar: new AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
leading: new IconButton(
icon: new Icon(
Icons.arrow_back,
color: Colors.grey,
),
onPressed: () {
Navigator.of(context).pop();
},
),
actions: <Widget>[
new Hero(
tag: widget.survey.uid + "_more_vert",
child: new Material(
color: Colors.transparent,
type: MaterialType.transparency,
child: new IconButton(
icon: new Icon(
Icons.more_vert,
color: Colors.grey,
),
onPressed: () {},
),
),
)
],
),
body: new Padding(
padding: const EdgeInsets.only(left: 40.0, right: 40.0, top: 35.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(bottom: 30.0),
child: new Align(
alignment: Alignment.bottomLeft,
child: new Hero(
tag: widget.survey.uid + "_icon",
child: new Container(
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(
color: Colors.grey.withAlpha(70),
style: BorderStyle.solid,
width: 1.0),
),
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Icon(
Icons.group,
color: ColorChoices.colors[3],
),
),
),
),
),
),
new Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: new Align(
alignment: Alignment.bottomLeft,
child: new Hero(
tag: widget.survey.uid + "_title",
child: new Material(
color: Colors.transparent,
child: new Text(
widget.survey.username,
style: new TextStyle(fontSize: 30.0),
),
),
)),
),
new Padding(
padding: const EdgeInsets.only(bottom: 30.0),
child: new Align(
alignment: Alignment.bottomLeft,
child: new Hero(
tag: widget.survey.uid + "_progress_bar",
child: new Material(
color: Colors.transparent,
child: new Row(
children: <Widget>[
new Expanded(
child: new LinearProgressIndicator(
value: barPercent,
backgroundColor: Colors.grey.withAlpha(50),
valueColor:
new AlwaysStoppedAnimation<Color>(
ColorChoices.colors[3]),
),
),
new Padding(
padding: const EdgeInsets.only(left: 5.0),
child: new Text(
(barPercent * 100).round().toString() +
"%"),
)
],
),
))),
),
new Expanded(
child: new ScaleTransition(
scale: scaleAnimation,
child: new ListView.builder(
padding: const EdgeInsets.all(0.0),
itemBuilder: (BuildContext context, int index) {
DateTime currentDate =
todoObject.tasks.keys.toList()[index];
DateTime _now = new DateTime.now();
DateTime today =
new DateTime(_now.year, _now.month, _now.day);
String dateString;
if (currentDate.isBefore(today)) {
dateString = "Previous - " +
new DateFormat.E().format(currentDate);
} else if (currentDate.isAtSameMomentAs(today)) {
dateString = "Today";
} else if (currentDate.isAtSameMomentAs(
today.add(const Duration(days: 1)))) {
dateString = "Tomorrow";
} else {
dateString =
new DateFormat.yMMMEd().format(currentDate);
}
List<Widget> tasks = [new Text(dateString)];
todoObject.tasks[currentDate].forEach((task) {
tasks.add(
ListTile(
leading: IconButton(
icon: Icon(Icons.camera_front),
onPressed: null),
title: new Text(task.task),
trailing: IconButton(
icon: Icon(
Icons.play_arrow,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => task.destination),
);
},
),
),
);
});
return new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: tasks,
);
},
itemCount: todoObject.tasks.length,
),
))
],
),
),
)
],
);
}
}
class CustomScrollPhysics extends ScrollPhysics {
CustomScrollPhysics({
ScrollPhysics parent,
}) : super(parent: parent);
final double numOfItems = 300;
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return new CustomScrollPhysics(parent: buildParent(ancestor));
}
double _getPage(ScrollPosition position) {
return position.pixels / (position.maxScrollExtent / numOfItems);
// return position.pixels / position.viewportDimension;
}
double _getPixels(ScrollPosition position, double page) {
// return page * position.viewportDimension;
return page * (position.maxScrollExtent / numOfItems);
}
double _getTargetPixels(
ScrollPosition position, Tolerance tolerance, double velocity) {
double page = _getPage(position);
if (velocity < -tolerance.velocity)
page -= 0.5;
else if (velocity > tolerance.velocity) page += 0.5;
return _getPixels(position, page.roundToDouble());
}
@override
Simulation createBallisticSimulation(
ScrollMetrics position, double velocity) {
if ((velocity <= 0.0 && position.pixels <= position.minScrollExtent) ||
(velocity >= 0.0 && position.pixels >= position.maxScrollExtent))
return super.createBallisticSimulation(position, velocity);
final Tolerance tolerance = this.tolerance;
final double target = _getTargetPixels(position, tolerance, velocity);
if (target != position.pixels)
return new ScrollSpringSimulation(
spring, position.pixels, target, velocity,
tolerance: tolerance);
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment