123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- import 'package:flutter/material.dart';
- import 'dart:async';
- import 'package:shuqi/public.dart';
- class ReaderMenu extends StatefulWidget {
- final List<Chapter> chapters;
- final int articleIndex;
- final VoidCallback onTap;
- final VoidCallback onPreviousArticle;
- final VoidCallback onNextArticle;
- final void Function(Chapter chapter) onToggleChapter;
- ReaderMenu({required this.chapters, required this.articleIndex, required this.onTap, required this.onPreviousArticle, required this.onNextArticle, required this.onToggleChapter});
- @override
- _ReaderMenuState createState() => _ReaderMenuState();
- }
- class _ReaderMenuState extends State<ReaderMenu> with SingleTickerProviderStateMixin {
- late AnimationController animationController;
- late Animation<double> animation;
- late double progressValue;
- bool isTipVisible = false;
- @override
- initState() {
- super.initState();
- progressValue = this.widget.articleIndex / (this.widget.chapters.length - 1);
- animationController = AnimationController(duration: const Duration(milliseconds: 200), vsync: this);
- animation = Tween(begin: 0.0, end: 1.0).animate(animationController);
- animation.addListener(() {
- setState(() {});
- });
- animationController.forward();
- }
- @override
- void didUpdateWidget(ReaderMenu oldWidget) {
- super.didUpdateWidget(oldWidget);
- progressValue = this.widget.articleIndex / (this.widget.chapters.length - 1);
- }
- @override
- void dispose() {
- animationController.dispose();
- super.dispose();
- }
- hide() {
- animationController.reverse();
- Timer(Duration(milliseconds: 200), () {
- this.widget.onTap();
- });
- setState(() {
- isTipVisible = false;
- });
- }
- buildTopView(BuildContext context) {
- return Positioned(
- top: -Screen.navigationBarHeight * (1 - animation.value),
- left: 0,
- right: 0,
- child: Container(
- decoration: BoxDecoration(color: SQColor.paper, boxShadow: Styles.borderShadow),
- height: Screen.navigationBarHeight,
- padding: EdgeInsets.fromLTRB(5, Screen.topSafeHeight, 5, 0),
- child: Row(
- children: <Widget>[
- Container(
- width: 44,
- child: GestureDetector(
- onTap: () {
- Navigator.pop(context);
- },
- child: Image.asset('assets/img/pub_back_gray.png'),
- ),
- ),
- Expanded(child: Container()),
- Container(
- width: 44,
- child: Image.asset('assets/img/read_icon_voice.png'),
- ),
- Container(
- width: 44,
- child: Image.asset('assets/img/read_icon_more.png'),
- ),
- ],
- ),
- ),
- );
- }
- int currentArticleIndex() {
- return ((this.widget.chapters.length - 1) * progressValue).toInt();
- }
- buildProgressTipView() {
- if (!isTipVisible) {
- return Container();
- }
- Chapter chapter = this.widget.chapters[currentArticleIndex()];
- double percentage = chapter.index / (this.widget.chapters.length - 1) * 100;
- return Container(
- decoration: BoxDecoration(color: Color(0xff00C88D), borderRadius: BorderRadius.circular(5)),
- margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
- padding: EdgeInsets.all(15),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: <Widget>[
- Text(chapter.title, style: TextStyle(color: Colors.white, fontSize: 16)),
- Text('${percentage.toStringAsFixed(1)}%', style: TextStyle(color: SQColor.lightGray, fontSize: 12)),
- ],
- ),
- );
- }
- previousArticle() {
- if (this.widget.articleIndex == 0) {
- Toast.show('已经是第一章了');
- return;
- }
- this.widget.onPreviousArticle();
- setState(() {
- isTipVisible = true;
- });
- }
- nextArticle() {
- if (this.widget.articleIndex == this.widget.chapters.length - 1) {
- Toast.show('已经是最后一章了');
- return;
- }
- this.widget.onNextArticle();
- setState(() {
- isTipVisible = true;
- });
- }
- buildProgressView() {
- return Container(
- padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
- child: Row(
- children: <Widget>[
- GestureDetector(
- onTap: previousArticle,
- child: Container(
- padding: EdgeInsets.all(20),
- child: Image.asset('assets/img/read_icon_chapter_previous.png'),
- ),
- ),
- Expanded(
- child: Slider(
- value: progressValue,
- onChanged: (double value) {
- setState(() {
- isTipVisible = true;
- progressValue = value;
- });
- },
- onChangeEnd: (double value) {
- Chapter chapter = this.widget.chapters[currentArticleIndex()];
- this.widget.onToggleChapter(chapter);
- },
- activeColor: SQColor.primary,
- inactiveColor: SQColor.gray,
- ),
- ),
- GestureDetector(
- onTap: nextArticle,
- child: Container(
- padding: EdgeInsets.all(20),
- child: Image.asset('assets/img/read_icon_chapter_next.png'),
- ),
- )
- ],
- ),
- );
- }
- buildBottomView() {
- return Positioned(
- bottom: -(Screen.bottomSafeHeight + 110) * (1 - animation.value),
- left: 0,
- right: 0,
- child: Column(
- children: <Widget>[
- buildProgressTipView(),
- Container(
- decoration: BoxDecoration(color: SQColor.paper, boxShadow: Styles.borderShadow),
- padding: EdgeInsets.only(bottom: Screen.bottomSafeHeight),
- child: Column(
- children: <Widget>[
- buildProgressView(),
- buildBottomMenus(),
- ],
- ),
- )
- ],
- ),
- );
- }
- buildBottomMenus() {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: <Widget>[
- buildBottomItem('目录', 'assets/img/read_icon_catalog.png'),
- buildBottomItem('亮度', 'assets/img/read_icon_brightness.png'),
- buildBottomItem('字体', 'assets/img/read_icon_font.png'),
- buildBottomItem('设置', 'assets/img/read_icon_setting.png'),
- ],
- );
- }
- buildBottomItem(String title, String icon) {
- return Container(
- padding: EdgeInsets.symmetric(vertical: 7),
- child: Column(
- children: <Widget>[
- Image.asset(icon),
- SizedBox(height: 5),
- Text(title, style: TextStyle(fontSize: fixedFontSize(12), color: SQColor.darkGray)),
- ],
- ),
- );
- }
- @override
- Widget build(BuildContext context) {
- return Container(
- child: Stack(
- children: <Widget>[
- GestureDetector(
- onTapDown: (_) {
- hide();
- },
- child: Container(color: Colors.transparent),
- ),
- buildTopView(context),
- buildBottomView(),
- ],
- ),
- );
- }
- }
|