WT 1.1.7+2 SearchBar, Timer for ExerciseControl

This commit is contained in:
bossanyit
2021-02-28 17:03:47 +01:00
parent cf348cebb0
commit 6bea5e70e1
77 changed files with 1581 additions and 1008 deletions
+5 -1
View File
@@ -1,7 +1,8 @@
import 'dart:async';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/common.dart';
@@ -69,6 +70,8 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin, C
@override
Widget build(BuildContext context) {
menuBloc = BlocProvider.of<MenuBloc>(context);
// ignore: close_sinks
final TimerBloc timerBloc = BlocProvider.of<TimerBloc>(context);
return AppBar(
backgroundColor: Colors.black,
@@ -91,6 +94,7 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin, C
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => {
timerBloc.add(TimerEnd()),
if (widget.isMenu != null)
{
if (menuBloc.workoutItem != null)
+5
View File
@@ -1,7 +1,9 @@
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
// ignore: must_be_immutable
@@ -24,6 +26,8 @@ class _AppBarNav extends State<AppBarMin> with Common {
@override
Widget build(BuildContext context) {
// ignore: close_sinks
final TimerBloc timerBloc = BlocProvider.of<TimerBloc>(context);
return AppBar(
backgroundColor: Colors.black,
title: Row(
@@ -44,6 +48,7 @@ class _AppBarNav extends State<AppBarMin> with Common {
leading: IconButton(
icon: Icon(Icons.arrow_back, color: widget.back ? Colors.white : Colors.black),
onPressed: () => {
timerBloc.add(TimerEnd()),
if (widget.back) {Navigator.of(context).pop()}
},
));
+6 -3
View File
@@ -1,6 +1,8 @@
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
class AppBarProgress extends StatefulWidget implements PreferredSizeWidget {
@@ -23,14 +25,12 @@ class _AppBarNav extends State<AppBarProgress> with SingleTickerProviderStateMix
_animationController = AnimationController(
lowerBound: (widget.min).toDouble(),
upperBound: (widget.max).toDouble(),
//upperBound: (widget.value / 100).toDouble(),
vsync: this,
duration: Duration(seconds: 3),
);
_animationController.addListener(() => setState(() {}));
_animationController.forward();
//Future.delayed(Duration(seconds: 3)).then((value) => _animationController.repeat());
super.initState();
}
@@ -42,12 +42,15 @@ class _AppBarNav extends State<AppBarProgress> with SingleTickerProviderStateMix
@override
Widget build(BuildContext context) {
// ignore: close_sinks
final TimerBloc timerBloc = BlocProvider.of<TimerBloc>(context);
return AppBar(
backgroundColor: Colors.black,
title: getAnimatedWidget(),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => {Navigator.of(context).pop()},
onPressed: () => {timerBloc.add(TimerEnd()), Navigator.of(context).pop()},
));
}
+2 -2
View File
@@ -1,5 +1,5 @@
import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:animated_widgets/widgets/rotation_animated.dart';
import 'package:flutter/cupertino.dart';
@@ -73,7 +73,7 @@ class _BMIState extends State<BMI> with Trans {
double mediaWidth = MediaQuery.of(context).size.width * .8;
double mediaHeight = MediaQuery.of(context).size.height * .8;
//print("w " + mediaWidth.toString() + "h " + mediaHeight.toString());
widget.exerciseBloc.setMediaDimensions(mediaWidth, mediaHeight);
widget.exerciseBloc.customerRepository.setMediaDimensions(mediaWidth, mediaHeight);
widget.exerciseBloc.getBMI();
return Form(
child: Scaffold(
+1 -1
View File
@@ -1,5 +1,5 @@
import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/model/fitness_state.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/cupertino.dart';
+7 -2
View File
@@ -1,4 +1,4 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/common.dart';
@@ -94,7 +94,12 @@ class _NawDrawerWidget extends State<BottomNavigator> with Trans, Logging {
backgroundColor: bgrColor,
icon: Icon(Icons.settings, color: inactive),
activeIcon: Icon(Icons.settings, color: active),
title: Text(t("Settings"), style: TextStyle(fontSize: 12)))
title: Text(t("Settings"), style: TextStyle(fontSize: 12))),
/* BottomNavigationBarItem(
backgroundColor: bgrColor,
icon: Icon(Icons.multiple_stop, color: inactive),
activeIcon: Icon(Icons.multiple_stop, color: active),
title: Text(t("Multi test"), style: TextStyle(fontSize: 12))) */
],
onTap: (index) {
setState(() {
+48 -81
View File
@@ -3,8 +3,11 @@ import 'dart:ui';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/widgets/menu_search_bar.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/service/logging.dart';
@@ -233,86 +236,50 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
return sliverList;
}
SliverList getInfoWidget(BuildContext context, MenuBloc menuBloc) {
List<Widget> widgets = List();
SliverAppBar getInfoWidget(BuildContext context, MenuBloc menuBloc) {
menuBloc.setContext(context);
menuBloc.setMenuInfo();
if (context != null) {
menuBloc.setContext(context);
menuBloc.setMenuInfo();
widgets.add(SizedBox(
height: 10,
));
widgets.add(
GestureDetector(
onTap: () => {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return DialogCommon(
title: menuBloc.infoTitle,
descriptions: menuBloc.infoText,
description2: menuBloc.infoText2,
description3: menuBloc.infoText3,
text: "OK",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
);
})
},
child: Align(
alignment: Alignment.center,
child: SizedBox(
height: 35,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 800),
transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition(child: child, scale: animation);
},
child: isFirst && !wait
? Icon(
CustomIcon.question_circle,
color: Colors.yellow[300],
size: 40,
)
: Offstage())))),
);
}
SliverList sliverList = SliverList(delegate: SliverChildListDelegate(widgets));
return sliverList;
}
SliverGrid getInfoWidget2(BuildContext context, MenuBloc menuBloc) {
final List<Widget> _columnChildren = List();
if (context != null) {
menuBloc.setContext(context);
menuBloc.setMenuInfo();
Widget info = MenuInfoWidget(
title: menuBloc.infoTitle,
titleSize: 18,
titleWeight: FontWeight.bold,
titleColor: Colors.orangeAccent,
text: menuBloc.infoText,
textSize: 13,
textColor: Colors.yellowAccent,
text2: menuBloc.infoText2,
text3: menuBloc.infoText3,
link: menuBloc.infoLink,
bloc: menuBloc,
);
_columnChildren.add(info);
}
SliverGrid sliverList = SliverGrid(
delegate: SliverChildListDelegate(_columnChildren),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
childAspectRatio: 2,
));
return sliverList;
SliverAppBar sliverAppBar = SliverAppBar(
backgroundColor: Colors.transparent,
title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
SizedBox(
width: 10,
),
GestureDetector(
onTap: () => {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return DialogCommon(
title: menuBloc.infoTitle,
descriptions: menuBloc.infoText,
description2: menuBloc.infoText2,
description3: menuBloc.infoText3,
text: "OK",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
);
})
},
child: Icon(
CustomIcon.question_circle,
color: Colors.orange[400],
size: 40,
)),
MenuSearchBar(
listItems: menuBloc.menuTreeRepository.menuAsExercise,
onFind: (value) => {
Track().track(TrackingEvent.search, eventValue: value.exerciseType.name),
Navigator.of(context).pushNamed('exerciseNewPage', arguments: value.exerciseType)
},
),
SizedBox(
width: 10,
),
]));
return sliverAppBar;
}
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc, BuildContext context) {
+277
View File
@@ -0,0 +1,277 @@
import 'dart:async';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class SearchBarStream {
static final SearchBarStream _singleton = SearchBarStream._internal();
final StreamController<bool> streamController = StreamController<bool>.broadcast();
bool searching = false;
Stream get stream => streamController.stream;
StreamController getStreamController() => streamController;
factory SearchBarStream() => _singleton;
SearchBarStream._internal();
void dispose() {
streamController.close();
}
}
class MenuSearchBar extends StatelessWidget {
final List listItems;
final Function(WorkoutMenuTree) onFind;
const MenuSearchBar({@required this.listItems, this.onFind});
@override
Widget build(BuildContext context) {
return AnimatedSearch(
listItems: listItems,
onFind: onFind,
);
}
}
class AnimatedSearch extends StatefulWidget {
final List listItems;
final Function(WorkoutMenuTree) onFind;
AnimatedSearch({this.listItems, this.onFind});
@override
_AnimatedSearch createState() => _AnimatedSearch();
}
class _AnimatedSearch extends State<AnimatedSearch> {
bool isSearching = false;
final Stream stream = SearchBarStream().stream;
var subscription;
@override
void initState() {
super.initState();
}
@override
void didChangeDependencies() {
subscription = stream.listen((value) {
setState(() {
isSearching = SearchBarStream().searching;
});
});
super.didChangeDependencies();
}
@override
void dispose() {
subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 0),
child: Stack(
alignment: Alignment.center,
children: [
AnimateExpansion(
animate: !isSearching,
axisAlignment: 1.0,
child: IconButton(
onPressed: () => {
setState(() {
isSearching = !isSearching;
SearchBarStream().searching = isSearching;
SearchBarStream().getStreamController().add(true);
})
},
icon: Icon(
Icons.search,
color: Color(0xffb4f500),
size: 40,
),
)),
AnimateExpansion(
animate: isSearching,
axisAlignment: -1.0,
child: Search(
listItems: widget.listItems,
onFind: widget.onFind,
),
),
],
));
}
}
// ignore: must_be_immutable
class Search extends StatelessWidget with Trans {
final List listItems;
final Function(WorkoutMenuTree) onFind;
Search({this.listItems, this.onFind});
@override
Widget build(BuildContext context) {
setContext(context);
return SizedBox(
width: MediaQuery.of(context).size.width * .6,
child: DropdownSearch<WorkoutMenuTree>(
onPopupDismissed: () => {SearchBarStream().searching = false, SearchBarStream().getStreamController().add(false)},
showAsSuffixIcons: false,
showSearchBox: true,
mode: Mode.DIALOG,
showSelectedItem: false,
items: listItems,
onChanged: (value) => onFind(value),
dropdownSearchDecoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 0, bottom: 5),
labelStyle: GoogleFonts.inter(fontSize: 12, color: Colors.yellow[50]),
fillColor: Colors.black38,
filled: true,
border: OutlineInputBorder(
gapPadding: 8.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.white12, width: 0.4),
),
),
searchBoxController: TextEditingController(),
searchBoxDecoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 5, bottom: 5),
labelText: t("Search Exercises..."),
labelStyle: GoogleFonts.inter(fontSize: 14, color: Colors.grey[400]),
fillColor: Colors.white24,
filled: true,
border: OutlineInputBorder(
gapPadding: 8.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.white12, width: 0.4),
),
),
popupBackgroundColor: Colors.grey[700],
popupItemBuilder: (context, item, isSelected) {
return Container(
margin: EdgeInsets.all(3),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_G_background.jpg'),
fit: BoxFit.cover,
),
),
child: ListTile(
selected: isSelected,
title: Text(
item.name,
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 16),
),
subtitle: Text(
item.parentName,
maxLines: 1,
style: GoogleFonts.inter(color: Colors.grey[400]),
),
leading: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.asset(item.imageName),
),
),
);
},
emptyBuilder: (context, searchEntry) => Center(
child: Text(
t("No exercise found"),
textAlign: TextAlign.center,
style: GoogleFonts.inter(color: Colors.yellow[200], fontSize: 16),
)),
dropdownBuilder: (context, WorkoutMenuTree item, itemDesignation) => Container(
child: ListView(scrollDirection: Axis.vertical, shrinkWrap: true, children: [
(item == null)
? Container(
height: 15,
padding: EdgeInsets.all(0),
child: Text(
t("Search Exercises..."),
style: GoogleFonts.inter(color: Colors.grey[400], fontSize: 14),
),
)
: Container(
height: 15,
padding: EdgeInsets.all(0),
child: Text(
item.name,
maxLines: 3,
style: GoogleFonts.inter(color: Colors.yellow[400], fontSize: 14),
),
),
]))),
);
}
}
class AnimateExpansion extends StatefulWidget {
final Widget child;
final bool animate;
final double axisAlignment;
AnimateExpansion({
this.animate = false,
this.axisAlignment,
this.child,
});
@override
_AnimateExpansionState createState() => _AnimateExpansionState();
}
class _AnimateExpansionState extends State<AnimateExpansion> with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<double> _animation;
void prepareAnimations() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 350),
);
_animation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInCubic,
reverseCurve: Curves.easeOutCubic,
);
}
void _toggle() {
if (widget.animate) {
_animationController.forward();
} else {
_animationController.reverse();
}
}
@override
void initState() {
super.initState();
prepareAnimations();
_toggle();
}
@override
void didUpdateWidget(AnimateExpansion oldWidget) {
super.didUpdateWidget(oldWidget);
_toggle();
}
@override
Widget build(BuildContext context) {
return SizeTransition(axis: Axis.horizontal, axisAlignment: -1.0, sizeFactor: _animation, child: widget.child);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
+12 -9
View File
@@ -53,7 +53,7 @@ class _SizeState extends State<SizeWidget> with Trans {
double mediaWidth = MediaQuery.of(context).size.width * .8;
double mediaHeight = MediaQuery.of(context).size.height * .8;
//print("w " + mediaWidth.toString() + "h " + mediaHeight.toString());
widget.exerciseBloc.setMediaDimensions(mediaWidth, mediaHeight);
widget.exerciseBloc.customerRepository.setMediaDimensions(mediaWidth, mediaHeight);
List<Widget> list = List();
list.add(GestureDetector(
onTap: () => {print("Save"), widget.exerciseBloc.add(ExerciseNewSaveWeight())},
@@ -63,7 +63,7 @@ class _SizeState extends State<SizeWidget> with Trans {
)));
list.add(
widget.exerciseBloc.isMan
widget.exerciseBloc.customerRepository.isMan
? Image.asset(
"asset/image/man_sizes.png",
height: mediaHeight,
@@ -76,10 +76,13 @@ class _SizeState extends State<SizeWidget> with Trans {
),
);
list.add(Positioned(
top: widget.exerciseBloc.getWeightCoordinate(widget.exerciseBloc.isMan, isTop: true).toDouble(),
left: widget.exerciseBloc.getWeightCoordinate(widget.exerciseBloc.isMan, isTop: false, isLeft: true).toDouble() - 45,
top: widget.exerciseBloc.customerRepository.getWeightCoordinate(widget.exerciseBloc.customerRepository.isMan, isTop: true).toDouble(),
left: widget.exerciseBloc.customerRepository
.getWeightCoordinate(widget.exerciseBloc.customerRepository.isMan, isTop: false, isLeft: true)
.toDouble() -
45,
child: GestureDetector(
onTap: () => onPressed(widget.exerciseBloc.getPropertyByName("Weight")),
onTap: () => onPressed(widget.exerciseBloc.customerRepository.getPropertyByName("Weight")),
child: Image.asset(
"asset/image/merleg.png",
height: 120,
@@ -92,7 +95,7 @@ class _SizeState extends State<SizeWidget> with Trans {
list.add(
Positioned(
top: mediaHeight * .07,
left: widget.exerciseBloc.isMan ? mediaWidth * .62 : mediaWidth * .65,
left: widget.exerciseBloc.customerRepository.isMan ? mediaWidth * .62 : mediaWidth * .65,
child: Stack(
alignment: Alignment.topLeft,
children: [
@@ -129,7 +132,7 @@ class _SizeState extends State<SizeWidget> with Trans {
List<Widget> getSizeElements() {
List<Widget> list = List();
widget.exerciseBloc.manSizes.forEach((element) {
widget.exerciseBloc.customerRepository.manSizes.forEach((element) {
list.add(
Positioned(
top: element.top.toDouble(),
@@ -139,7 +142,7 @@ class _SizeState extends State<SizeWidget> with Trans {
width: 20,
height: 20,
decoration: BoxDecoration(
color: widget.exerciseBloc.isMan ? Colors.green[800] : Color(0xFFEA776C),
color: widget.exerciseBloc.customerRepository.isMan ? Colors.green[800] : Color(0xFFEA776C),
borderRadius: BorderRadius.all(
Radius.circular(20),
),
@@ -156,7 +159,7 @@ class _SizeState extends State<SizeWidget> with Trans {
height: 20,
padding: EdgeInsets.zero,
decoration: BoxDecoration(
color: widget.exerciseBloc.isMan ? Color(0xFF369fb9) : Color(0xFFEA776C),
color: widget.exerciseBloc.customerRepository.isMan ? Color(0xFF369fb9) : Color(0xFFEA776C),
borderRadius: BorderRadius.all(
Radius.circular(20),
),
+34
View File
@@ -0,0 +1,34 @@
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
import 'package:aitrainer_app/library/clock.dart';
import 'package:flutter/material.dart';
class TimerWidget extends StatelessWidget {
final TimerBloc bloc;
const TimerWidget({this.bloc});
@override
Widget build(BuildContext context) {
return Positioned(
left: MediaQuery.of(context).size.width - 95,
top: 28,
child: Stack(alignment: AlignmentDirectional.topEnd, children: [
digitalClock(),
]));
}
Widget digitalClock() {
return ClipRRect(
borderRadius: BorderRadius.circular(45.0),
child: Container(
width: 90,
height: 90,
color: Colors.transparent,
child: Overlay(initialEntries: <OverlayEntry>[
OverlayEntry(
opaque: true,
builder: (BuildContext context) {
return Container(color: Colors.transparent, child: Clock(bloc: bloc));
})
])));
}
}