Update menu style.

This commit is contained in:
stonegate 2020-08-16 01:31:07 +08:00
parent 6f8b671acb
commit 631b03609a
5 changed files with 294 additions and 337 deletions

View File

@ -25,6 +25,7 @@ import '../util/audiopanel.dart';
import '../util/custom_widget.dart';
import '../util/episodegrid.dart';
import '../util/extension_helper.dart';
import '../util/general_dialog.dart';
import 'podcast_settings.dart';
class PodcastDetail extends StatefulWidget {
@ -331,13 +332,10 @@ class _PodcastDetailState extends State<PodcastDetail> {
widget.podcastLocal.rssUrl.launchUrl;
break;
case 2:
Navigator.push(
generalSheet(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) =>
PodcastSetting(podcastLocal: widget.podcastLocal),
),
title: s.settings,
child: PodcastSetting(podcastLocal: widget.podcastLocal),
);
break;
}

View File

@ -3,7 +3,6 @@ import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:image/image.dart' as img;
@ -118,7 +117,8 @@ class _PodcastSettingState extends State<PodcastSetting> {
}
if (imageUrl != null &&
imageUrl.contains('http') &&
imageUrl != widget.podcastLocal.imageUrl) {
(imageUrl != widget.podcastLocal.imageUrl ||
!File(widget.podcastLocal.imageUrl).existsSync())) {
try {
img.Image thumbnail;
var imageResponse = await Dio().get<List<int>>(imageUrl,
@ -173,13 +173,13 @@ class _PodcastSettingState extends State<PodcastSetting> {
Widget _getRefreshStatusIcon(RefreshCoverStatus status) {
switch (status) {
case RefreshCoverStatus.none:
return Icon(Icons.refresh);
return Center();
break;
case RefreshCoverStatus.start:
return CircularProgressIndicator(strokeWidth: 2);
break;
case RefreshCoverStatus.complete:
return Icon(Icons.refresh);
return Icon(Icons.done);
break;
case RefreshCoverStatus.complete:
return Icon(Icons.refresh, color: Colors.red);
@ -192,121 +192,128 @@ class _PodcastSettingState extends State<PodcastSetting> {
@override
Widget build(BuildContext context) {
final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
systemNavigationBarColor: Theme.of(context).primaryColor,
systemNavigationBarIconBrightness:
Theme.of(context).accentColorBrightness,
),
child: Scaffold(
appBar: AppBar(
title: Text(s.settings),
elevation: 0,
backgroundColor: Theme.of(context).primaryColor,
),
body: Container(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FutureBuilder<bool>(
future: _getAutoDownload(widget.podcastLocal.id),
initialData: false,
builder: (context, snapshot) {
return ListTile(
onTap: () => _setAutoDownload(!snapshot.data),
contentPadding: EdgeInsets.fromLTRB(70.0, 10, 20, 10),
title: Text(s.autoDownload),
trailing: Transform.scale(
scale: 0.9,
child: Switch(
value: snapshot.data,
onChanged: _setAutoDownload),
),
);
}),
Divider(height: 2),
FutureBuilder<int>(
future: _getSkipSecond(widget.podcastLocal.id),
initialData: 0,
builder: (context, snapshot) => ListTile(
onTap: () => generalDialog(
context,
title: Text(s.skipSecondsAtStart, maxLines: 2),
content: DurationPicker(
duration: Duration(seconds: snapshot.data),
onChange: (value) => _seconds = value.inSeconds,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
_seconds = 0;
},
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
_saveSkipSeconds(_seconds);
},
child: Text(
s.confirm,
style: TextStyle(color: context.accentColor),
),
)
],
return Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FutureBuilder<bool>(
future: _getAutoDownload(widget.podcastLocal.id),
initialData: false,
builder: (context, snapshot) {
return ListTile(
onTap: () => _setAutoDownload(!snapshot.data),
leading: SizedBox(
height: 18,
width: 18,
child: CustomPaint(
painter: DownloadPainter(
color: context.brightness == Brightness.light
? Colors.grey[600]
: Colors.white,
fraction: 0,
progressColor: context.accentColor,
),
contentPadding: EdgeInsets.fromLTRB(70.0, 10, 40, 10),
title: Text(s.skipSecondsAtStart),
trailing: Text(snapshot.data.toTime),
),
),
Divider(height: 2),
ListTile(
onTap: () {
if (_markStatus != MarkStatus.start) {
_confirmMarkListened(context);
}
title: Text(s.autoDownload),
trailing: Transform.scale(
scale: 0.9,
child: Switch(
value: snapshot.data, onChanged: _setAutoDownload),
),
);
}),
Divider(height: 1),
FutureBuilder<int>(
future: _getSkipSecond(widget.podcastLocal.id),
initialData: 0,
builder: (context, snapshot) => ListTile(
onTap: () {
generalDialog(
context,
title: Text(s.skipSecondsAtStart, maxLines: 2),
content: DurationPicker(
duration: Duration(seconds: snapshot.data),
onChange: (value) => _seconds = value.inSeconds,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
_seconds = 0;
},
contentPadding: EdgeInsets.fromLTRB(70.0, 10, 40, 10),
title: Text(s.menuMarkAllListened),
// subtitle: Text(s.settingsAutoPlayDes),
trailing: SizedBox(
height: 20,
width: 20,
child: _markStatus == MarkStatus.none
? CustomPaint(
painter: ListenedAllPainter(context.textColor,
stroke: 2),
)
: _markStatus == MarkStatus.start
? CircularProgressIndicator(strokeWidth: 2)
: Icon(Icons.done))),
Divider(height: 2),
ListTile(
onTap: () {
if (_coverStatus != RefreshCoverStatus.start) {
_refreshArtWork();
}
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
_saveSkipSeconds(_seconds);
},
contentPadding: EdgeInsets.fromLTRB(70.0, 10, 40, 10),
title: Text(s.refreshArtwork),
trailing: SizedBox(
height: 20,
width: 20,
child: _getRefreshStatusIcon(_coverStatus))),
Divider(height: 2),
]),
child: Text(
s.confirm,
style: TextStyle(color: context.accentColor),
),
)
],
).then((value) => setState(() {}));
},
leading: Icon(Icons.fast_forward),
title: Text(s.skipSecondsAtStart),
trailing: Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Text(snapshot.data.toTime),
),
),
),
),
),
);
Divider(height: 1),
ListTile(
onTap: () {
if (_markStatus != MarkStatus.start) {
_confirmMarkListened(context);
}
},
title: Text(s.menuMarkAllListened),
leading: SizedBox(
height: 20,
width: 20,
child: CustomPaint(
painter: ListenedAllPainter(
context.brightness == Brightness.light
? Colors.grey[600]
: Colors.white,
stroke: 2),
),
),
trailing: Padding(
padding: const EdgeInsets.only(right: 10.0),
child: SizedBox(
height: 20,
width: 20,
child: _markStatus == MarkStatus.none
? Center()
: _markStatus == MarkStatus.start
? CircularProgressIndicator(strokeWidth: 2)
: Icon(Icons.done)),
)),
Divider(height: 1),
ListTile(
onTap: () {
if (_coverStatus != RefreshCoverStatus.start) {
_refreshArtWork();
}
},
title: Text(s.refreshArtwork),
leading: Icon(Icons.refresh),
trailing: SizedBox(
height: 20,
width: 20,
child: Padding(
padding: const EdgeInsets.only(right: 10.0),
child: _getRefreshStatusIcon(_coverStatus)))),
Divider(height: 1),
]);
}
}

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:intl/intl_standalone.dart';
import 'package:url_launcher/url_launcher.dart';
import '../generated/l10n.dart';
import '../local_storage/key_value_storage.dart';
@ -16,14 +15,6 @@ class LanguagesSetting extends StatefulWidget {
}
class _LanguagesSettingState extends State<LanguagesSetting> {
_launchUrl(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
_setLocale(Locale locale, {bool systemDefault = false}) async {
var localeStorage = KeyValueStorage(localeKey);
if (systemDefault) {
@ -61,94 +52,77 @@ class _LanguagesSettingState extends State<LanguagesSetting> {
@override
Widget build(BuildContext context) {
final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
systemNavigationBarColor: Theme.of(context).primaryColor,
systemNavigationBarIconBrightness:
Theme.of(context).accentColorBrightness,
),
child: Scaffold(
appBar: AppBar(
title: Text(s.settingsLanguages),
elevation: 0,
backgroundColor: Theme.of(context).primaryColor,
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
ListTile(
title: Text(
s.systemDefault,
style: TextStyle(
color: Intl.systemLocale.contains(Intl.getCurrentLocale())
? context.accentColor
: null),
),
onTap: () =>
_setLocale(Locale(Intl.systemLocale), systemDefault: true),
contentPadding: const EdgeInsets.only(left: 70, right: 20),
),
Divider(height: 2),
ListTile(
title: Text('English'),
onTap: () => _setLocale(Locale('en')),
contentPadding: const EdgeInsets.only(left: 70, right: 20),
trailing: Radio<Locale>(
value: Locale('en'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale)),
Divider(height: 2),
ListTile(
title: Text('简体中文'),
onTap: () => _setLocale(Locale('zh_Hans')),
contentPadding: const EdgeInsets.only(left: 70, right: 20),
trailing: Radio<Locale>(
value: Locale('zh_Hans'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale,
)),
Divider(height: 2),
ListTile(
title: Text('Français'),
onTap: () => _setLocale(Locale('fr')),
contentPadding: const EdgeInsets.only(left: 70, right: 20),
trailing: Radio<Locale>(
value: Locale('fr'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale),
),
Divider(height: 2),
ListTile(
title: Text('Español'),
onTap: () => _setLocale(Locale('es')),
contentPadding: const EdgeInsets.only(left: 70, right: 20),
trailing: Radio<Locale>(
value: Locale('es'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale),
),
Divider(height: 2),
ListTile(
onTap: () => _launchUrl(
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop localization project'),
contentPadding: const EdgeInsets.only(left: 70, right: 20),
title: Align(
alignment: Alignment.centerLeft,
child: Image(
image: Theme.of(context).brightness == Brightness.light
? AssetImage('assets/localizely_logo.png')
: AssetImage('assets/localizely_logo_light.png'),
height: 20),
),
subtitle: Text(
"If you'd like to contribute to localization project, please contact me."),
),
],
return Column(
children: [
ListTile(
title: Text(
s.systemDefault,
style: TextStyle(
color: Intl.systemLocale.contains(Intl.getCurrentLocale())
? context.accentColor
: null),
),
onTap: () =>
_setLocale(Locale(Intl.systemLocale), systemDefault: true),
contentPadding: const EdgeInsets.only(left: 20, right: 20),
),
),
Divider(height: 1),
ListTile(
title: Text('English'),
onTap: () => _setLocale(Locale('en')),
contentPadding: const EdgeInsets.only(left: 20, right: 20),
trailing: Radio<Locale>(
value: Locale('en'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale)),
Divider(height: 1),
ListTile(
title: Text('简体中文'),
onTap: () => _setLocale(Locale('zh_Hans')),
contentPadding: const EdgeInsets.only(left: 20, right: 20),
trailing: Radio<Locale>(
value: Locale('zh_Hans'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale,
)),
Divider(height: 1),
ListTile(
title: Text('Français'),
onTap: () => _setLocale(Locale('fr')),
contentPadding: const EdgeInsets.only(left: 20, right: 20),
trailing: Radio<Locale>(
value: Locale('fr'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale),
),
Divider(height: 1),
ListTile(
title: Text('Español'),
onTap: () => _setLocale(Locale('es')),
contentPadding: const EdgeInsets.only(left: 20, right: 20),
trailing: Radio<Locale>(
value: Locale('es'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: _setLocale),
),
Divider(height: 1),
ListTile(
onTap: () =>
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop localization project'
.launchUrl,
contentPadding: const EdgeInsets.only(left: 20, right: 20),
title: Align(
alignment: Alignment.centerLeft,
child: Image(
image: Theme.of(context).brightness == Brightness.light
? AssetImage('assets/localizely_logo.png')
: AssetImage('assets/localizely_logo_light.png'),
height: 20),
),
subtitle: Text(
"If you'd like to contribute to localization project, please contact me."),
),
],
);
}
}

View File

@ -1,16 +1,14 @@
import 'dart:math' as math;
import 'package:feature_discovery/feature_discovery.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:line_icons/line_icons.dart';
import 'package:url_launcher/url_launcher.dart';
import '../home/home.dart';
import '../intro_slider/app_intro.dart';
import '../podcasts/podcast_manage.dart';
import '../util/extension_helper.dart';
import '../util/general_dialog.dart';
import 'data_backup.dart';
import 'history.dart';
import 'languages.dart';
@ -26,58 +24,19 @@ class Settings extends StatefulWidget {
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings>
with SingleTickerProviderStateMixin {
_launchUrl(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
bool _showFeedback;
Animation _animation;
AnimationController _controller;
double _value;
@override
void initState() {
super.initState();
_showFeedback = false;
_value = 0;
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller)
..addListener(() {
setState(() {
_value = _animation.value;
});
});
}
Widget _feedbackItem(IconData icon, String name, String url) => Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _launchUrl(url),
child: Container(
padding: EdgeInsets.all(5),
alignment: Alignment.center,
child: Column(
children: <Widget>[
Icon(
icon,
size: 20 * _value,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5),
),
Text(
name,
maxLines: 2,
)
],
),
),
class _SettingsState extends State<Settings> {
Widget _feedbackItem(IconData icon, String name, String url) => ListTile(
onTap: () {
url.launchUrl;
Navigator.pop(context);
},
leading: Icon(
icon,
size: 20,
),
title: Text(
name,
maxLines: 2,
),
);
@ -139,7 +98,7 @@ class _SettingsState extends State<Settings>
title: Text(s.settingsAppearance),
subtitle: Text(s.settingsAppearanceDes),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () => Navigator.push(
context,
@ -152,7 +111,7 @@ class _SettingsState extends State<Settings>
title: Text(s.settingsLayout),
subtitle: Text(s.settingsLayoutDes),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () => Navigator.push(
context,
@ -165,7 +124,7 @@ class _SettingsState extends State<Settings>
title: Text(s.play),
subtitle: Text(s.settingsPlayDes),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () => Navigator.push(
context,
@ -177,7 +136,7 @@ class _SettingsState extends State<Settings>
color: Colors.yellow[700]),
title: Text(s.settingsSyncing),
subtitle: Text(s.settingsSyncingDes)),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () => Navigator.push(
context,
@ -190,7 +149,7 @@ class _SettingsState extends State<Settings>
title: Text(s.settingStorage),
subtitle: Text(s.settingsStorageDes),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () => Navigator.push(
context,
@ -203,12 +162,12 @@ class _SettingsState extends State<Settings>
title: Text(s.settingsHistory),
subtitle: Text(s.settingsHistoryDes),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LanguagesSetting())),
onTap: () => generalSheet(context,
title: s.settingsLanguages,
child: LanguagesSetting())
.then((value) => setState(() {})),
contentPadding:
EdgeInsets.symmetric(horizontal: 25.0),
leading: Icon(LineIcons.language_solid,
@ -216,7 +175,7 @@ class _SettingsState extends State<Settings>
title: Text(s.settingsLanguages),
subtitle: Text(s.settingsLanguagesDes),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () {
//_exportOmpl(context);
@ -232,7 +191,7 @@ class _SettingsState extends State<Settings>
title: Text(s.settingsBackup),
subtitle: Text(s.settingsBackupDes),
),
Divider(height: 2),
Divider(height: 1),
],
),
],
@ -271,57 +230,45 @@ class _SettingsState extends State<Settings>
title: Text(s.settingsLibraries),
subtitle: Text(s.settingsLibrariesDes),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () async {
if (_value == 0) {
_showFeedback = !_showFeedback;
_controller.forward();
} else {
await _controller.reverse();
_showFeedback = !_showFeedback;
}
},
onTap: () => generalSheet(
context,
title: s.settingsFeedback,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
_feedbackItem(
LineIcons.github,
s.feedbackGithub,
'https://github.com/stonega/tsacdop/issues'),
Divider(height: 1),
_feedbackItem(
LineIcons.telegram,
s.feedbackTelegram,
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
Divider(height: 1),
_feedbackItem(
LineIcons.envelope_open_text_solid,
s.feedbackEmail,
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop Feedback'),
Divider(height: 1),
_feedbackItem(
LineIcons.google_play,
s.feedbackPlay,
'https://play.google.com/store/apps/details?id=com.stonegate.tsacdop'),
Divider(height: 1),
],
),
),
contentPadding:
EdgeInsets.symmetric(horizontal: 25.0),
leading: Icon(LineIcons.bug_solid,
color: Colors.pink[700]),
title: Text(s.settingsFeedback),
subtitle: Text(s.settingsFeedbackDes),
trailing: Transform.rotate(
angle: math.pi * _value,
child: Icon(Icons.keyboard_arrow_down),
),
),
_showFeedback
? SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(width: 45),
_feedbackItem(
LineIcons.github,
s.feedbackGithub,
'https://github.com/stonega/tsacdop/issues'),
_feedbackItem(
LineIcons.telegram,
s.feedbackTelegram,
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
_feedbackItem(
LineIcons.envelope_open_text_solid,
s.feedbackEmail,
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop Feedback'),
_feedbackItem(
LineIcons.google_play,
s.feedbackPlay,
'https://play.google.com/store/apps/details?id=com.stonegate.tsacdop')
],
),
)
: Center(),
Divider(
height: 2,
),
@ -349,7 +296,7 @@ class _SettingsState extends State<Settings>
color: Colors.pinkAccent),
title: Text(s.settingsDiscovery),
),
Divider(height: 2),
Divider(height: 1),
ListTile(
onTap: () => Navigator.push(
context,
@ -362,7 +309,7 @@ class _SettingsState extends State<Settings>
color: Colors.blueGrey),
title: Text(s.settingsAppIntro),
),
Divider(height: 2),
Divider(height: 1),
],
),
Padding(

View File

@ -3,9 +3,9 @@ import 'package:flutter/services.dart';
import 'extension_helper.dart';
generalDialog(BuildContext context,
{Widget title, Widget content, List<Widget> actions}) =>
showGeneralDialog(
Future generalDialog(BuildContext context,
{Widget title, Widget content, List<Widget> actions}) async =>
await showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
@ -15,20 +15,51 @@ generalDialog(BuildContext context,
AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light,
systemNavigationBarColor:
Theme.of(context).brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1)
: Color.fromRGBO(15, 15, 15, 1),
systemNavigationBarColor: context.brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1)
: Color.fromRGBO(15, 15, 15, 1),
),
child: AlertDialog(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))),
borderRadius: BorderRadius.circular(10.0)),
titlePadding: EdgeInsets.all(20),
title: SizedBox(width: context.width - 160, child: title),
title: SizedBox(width: context.width - 120, child: title),
content: content,
contentPadding: EdgeInsets.fromLTRB(20, 0, 20, 0),
actionsPadding: EdgeInsets.fromLTRB(10, 0, 10, 0),
actions: actions),
),
);
Future generalSheet(BuildContext context, {Widget child, String title}) async =>
await showModalBottomSheet(
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0)),
),
elevation: 2,
context: context,
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.only(top: 10.0, bottom: 2.0),
child: Container(
height: 4,
width: 25,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2.0),
color: context.primaryColorDark),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 6.0),
child: Text(title, style: context.textTheme.headline6),
),
Divider(height: 1),
child,
],
);
});