| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  | import 'dart:io'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-14 13:34:01 -07:00
										 |  |  | import 'package:appflowy/generated/flowy_svgs.g.dart'; | 
					
						
							| 
									
										
										
										
											2023-07-02 23:37:30 +08:00
										 |  |  | import 'package:appflowy/workspace/application/settings/prelude.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  | import 'package:easy_localization/easy_localization.dart'; | 
					
						
							| 
									
										
										
										
											2023-07-03 04:07:11 -10:00
										 |  |  | import 'package:flowy_infra/file_picker/file_picker_service.dart'; | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  | import 'package:flowy_infra/size.dart'; | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  | import 'package:flowy_infra_ui/flowy_infra_ui.dart'; | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  | import 'package:flowy_infra_ui/widget/buttons/secondary_button.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:fluttertoast/fluttertoast.dart'; | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  | import 'package:google_fonts/google_fonts.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import '../../../generated/locale_keys.g.dart'; | 
					
						
							|  |  |  | import '../../../startup/startup.dart'; | 
					
						
							|  |  |  | import '../../../workspace/presentation/home/toast.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum _FolderPage { | 
					
						
							|  |  |  |   options, | 
					
						
							|  |  |  |   create, | 
					
						
							|  |  |  |   open, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FolderWidget extends StatefulWidget { | 
					
						
							|  |  |  |   const FolderWidget({ | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |     super.key, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |     required this.createFolderCallback, | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   final Future<void> Function() createFolderCallback; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<FolderWidget> createState() => _FolderWidgetState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _FolderWidgetState extends State<FolderWidget> { | 
					
						
							|  |  |  |   var page = _FolderPage.options; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |     return _mapIndexToWidget(context); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _mapIndexToWidget(BuildContext context) { | 
					
						
							|  |  |  |     switch (page) { | 
					
						
							|  |  |  |       case _FolderPage.options: | 
					
						
							|  |  |  |         return FolderOptionsWidget( | 
					
						
							|  |  |  |           onPressedOpen: () { | 
					
						
							|  |  |  |             _openFolder(); | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       case _FolderPage.create: | 
					
						
							|  |  |  |         return CreateFolderWidget( | 
					
						
							|  |  |  |           onPressedBack: () { | 
					
						
							|  |  |  |             setState(() => page = _FolderPage.options); | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           onPressedCreate: widget.createFolderCallback, | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       case _FolderPage.open: | 
					
						
							| 
									
										
										
										
											2024-01-25 16:37:36 +01:00
										 |  |  |         return const SizedBox.shrink(); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<void> _openFolder() async { | 
					
						
							| 
									
										
										
										
											2023-05-21 18:53:59 +08:00
										 |  |  |     final path = await getIt<FilePickerService>().getDirectoryPath(); | 
					
						
							|  |  |  |     if (path != null) { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:15:32 +08:00
										 |  |  |       await getIt<ApplicationDataStorage>().setCustomPath(path); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |       await widget.createFolderCallback(); | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |       setState(() {}); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FolderOptionsWidget extends StatelessWidget { | 
					
						
							|  |  |  |   const FolderOptionsWidget({ | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |     super.key, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |     required this.onPressedOpen, | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   final VoidCallback onPressedOpen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |     return FutureBuilder( | 
					
						
							| 
									
										
										
										
											2023-06-21 12:15:32 +08:00
										 |  |  |       future: getIt<ApplicationDataStorage>().getPath(), | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |       builder: (context, result) { | 
					
						
							|  |  |  |         final subtitle = result.hasData ? result.data! : ''; | 
					
						
							|  |  |  |         return _FolderCard( | 
					
						
							| 
									
										
										
										
											2023-08-14 13:34:01 -07:00
										 |  |  |           icon: const FlowySvg(FlowySvgs.archive_m), | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |           title: LocaleKeys.settings_files_defineWhereYourDataIsStored.tr(), | 
					
						
							|  |  |  |           subtitle: subtitle, | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |           trailing: _buildTextButton( | 
					
						
							|  |  |  |             context, | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |             LocaleKeys.settings_files_set.tr(), | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |             onPressedOpen, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |           ), | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CreateFolderWidget extends StatefulWidget { | 
					
						
							|  |  |  |   const CreateFolderWidget({ | 
					
						
							| 
									
										
										
										
											2023-09-11 21:32:26 -05:00
										 |  |  |     super.key, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |     required this.onPressedBack, | 
					
						
							|  |  |  |     required this.onPressedCreate, | 
					
						
							| 
									
										
										
										
											2023-09-11 21:32:26 -05:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   final VoidCallback onPressedBack; | 
					
						
							|  |  |  |   final Future<void> Function() onPressedCreate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<CreateFolderWidget> createState() => CreateFolderWidgetState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @visibleForTesting | 
					
						
							|  |  |  | class CreateFolderWidgetState extends State<CreateFolderWidget> { | 
					
						
							|  |  |  |   var _folderName = 'appflowy'; | 
					
						
							|  |  |  |   @visibleForTesting | 
					
						
							|  |  |  |   var directory = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   final _fToast = FToast(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     _fToast.init(context); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Column( | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         Align( | 
					
						
							|  |  |  |           alignment: Alignment.centerLeft, | 
					
						
							|  |  |  |           child: TextButton.icon( | 
					
						
							|  |  |  |             onPressed: widget.onPressedBack, | 
					
						
							|  |  |  |             icon: const Icon(Icons.arrow_back_rounded), | 
					
						
							|  |  |  |             label: const Text('Back'), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |         _FolderCard( | 
					
						
							|  |  |  |           title: LocaleKeys.settings_files_location.tr(), | 
					
						
							|  |  |  |           subtitle: LocaleKeys.settings_files_locationDesc.tr(), | 
					
						
							|  |  |  |           trailing: SizedBox( | 
					
						
							|  |  |  |             width: 120, | 
					
						
							|  |  |  |             child: FlowyTextField( | 
					
						
							|  |  |  |               hintText: LocaleKeys.settings_files_folderHintText.tr(), | 
					
						
							|  |  |  |               onChanged: (name) => _folderName = name, | 
					
						
							|  |  |  |               onSubmitted: (name) => setState( | 
					
						
							|  |  |  |                 () => _folderName = name, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |         _FolderCard( | 
					
						
							|  |  |  |           title: LocaleKeys.settings_files_folderPath.tr(), | 
					
						
							|  |  |  |           subtitle: _path, | 
					
						
							|  |  |  |           trailing: _buildTextButton( | 
					
						
							|  |  |  |             context, | 
					
						
							|  |  |  |             LocaleKeys.settings_files_browser.tr(), | 
					
						
							|  |  |  |             () async { | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |               final dir = await getIt<FilePickerService>().getDirectoryPath(); | 
					
						
							|  |  |  |               if (dir != null) { | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |                 setState(() => directory = dir); | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |             }, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |         const VSpace(4.0), | 
					
						
							|  |  |  |         Padding( | 
					
						
							|  |  |  |           padding: const EdgeInsets.symmetric(horizontal: 4.0), | 
					
						
							| 
									
										
										
										
											2023-07-31 10:01:12 -05:00
										 |  |  |           child: _buildTextButton( | 
					
						
							|  |  |  |             context, | 
					
						
							|  |  |  |             LocaleKeys.settings_files_create.tr(), | 
					
						
							|  |  |  |             () async { | 
					
						
							|  |  |  |               if (_path.isEmpty) { | 
					
						
							|  |  |  |                 _showToast( | 
					
						
							|  |  |  |                   LocaleKeys.settings_files_locationCannotBeEmpty.tr(), | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |               } else { | 
					
						
							|  |  |  |                 await getIt<ApplicationDataStorage>().setCustomPath(_path); | 
					
						
							|  |  |  |                 await widget.onPressedCreate(); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |           ), | 
					
						
							| 
									
										
										
										
											2023-11-14 22:33:07 +08:00
										 |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   String get _path { | 
					
						
							|  |  |  |     if (directory.isEmpty) return ''; | 
					
						
							|  |  |  |     final String path; | 
					
						
							|  |  |  |     if (Platform.isMacOS) { | 
					
						
							|  |  |  |       path = directory.replaceAll('/Volumes/Macintosh HD', ''); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       path = directory; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return '$path/$_folderName'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _showToast(String message) { | 
					
						
							|  |  |  |     _fToast.showToast( | 
					
						
							|  |  |  |       child: FlowyMessageToast(message: message), | 
					
						
							|  |  |  |       gravity: ToastGravity.CENTER, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Widget _buildTextButton( | 
					
						
							| 
									
										
										
										
											2023-04-10 15:10:42 +08:00
										 |  |  |   BuildContext context, | 
					
						
							|  |  |  |   String title, | 
					
						
							|  |  |  |   VoidCallback onPressed, | 
					
						
							|  |  |  | ) { | 
					
						
							| 
									
										
										
										
											2023-07-31 10:01:12 -05:00
										 |  |  |   return SecondaryTextButton( | 
					
						
							|  |  |  |     title, | 
					
						
							| 
									
										
										
										
											2023-08-17 23:46:39 +08:00
										 |  |  |     mode: TextButtonMode.small, | 
					
						
							| 
									
										
										
										
											2023-07-31 10:01:12 -05:00
										 |  |  |     onPressed: onPressed, | 
					
						
							| 
									
										
										
										
											2022-12-20 11:14:42 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _FolderCard extends StatelessWidget { | 
					
						
							|  |  |  |   const _FolderCard({ | 
					
						
							|  |  |  |     required this.title, | 
					
						
							|  |  |  |     required this.subtitle, | 
					
						
							|  |  |  |     this.trailing, | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |     this.icon, | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   final String title; | 
					
						
							|  |  |  |   final String subtitle; | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |   final Widget? icon; | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |   final Widget? trailing; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2023-07-31 10:01:12 -05:00
										 |  |  |     const cardSpacing = 16.0; | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |     return Card( | 
					
						
							|  |  |  |       child: Padding( | 
					
						
							|  |  |  |         padding: const EdgeInsets.symmetric( | 
					
						
							| 
									
										
										
										
											2023-07-31 10:01:12 -05:00
										 |  |  |           vertical: cardSpacing, | 
					
						
							|  |  |  |           horizontal: cardSpacing, | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |         ), | 
					
						
							|  |  |  |         child: Row( | 
					
						
							|  |  |  |           children: [ | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |             if (icon != null) | 
					
						
							|  |  |  |               Padding( | 
					
						
							| 
									
										
										
										
											2023-07-31 10:01:12 -05:00
										 |  |  |                 padding: const EdgeInsets.only(right: cardSpacing), | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |                 child: icon!, | 
					
						
							|  |  |  |               ), | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |             Expanded( | 
					
						
							|  |  |  |               child: Column( | 
					
						
							|  |  |  |                 crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |                 children: [ | 
					
						
							| 
									
										
										
										
											2023-11-20 20:54:47 +08:00
										 |  |  |                   Row( | 
					
						
							|  |  |  |                     children: [ | 
					
						
							| 
									
										
										
										
											2023-11-23 09:39:40 +08:00
										 |  |  |                       Flexible( | 
					
						
							|  |  |  |                         child: FlowyText.regular( | 
					
						
							|  |  |  |                           title, | 
					
						
							|  |  |  |                           fontSize: FontSizes.s14, | 
					
						
							|  |  |  |                           fontFamily: GoogleFonts.poppins( | 
					
						
							|  |  |  |                             fontWeight: FontWeight.w500, | 
					
						
							|  |  |  |                           ).fontFamily, | 
					
						
							|  |  |  |                           overflow: TextOverflow.ellipsis, | 
					
						
							|  |  |  |                         ), | 
					
						
							| 
									
										
										
										
											2023-11-20 20:54:47 +08:00
										 |  |  |                       ), | 
					
						
							|  |  |  |                       Tooltip( | 
					
						
							|  |  |  |                         decoration: BoxDecoration( | 
					
						
							|  |  |  |                           color: Theme.of(context).colorScheme.surface, | 
					
						
							|  |  |  |                           borderRadius: BorderRadius.circular(6), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                         preferBelow: false, | 
					
						
							|  |  |  |                         richMessage: WidgetSpan( | 
					
						
							|  |  |  |                           alignment: PlaceholderAlignment.baseline, | 
					
						
							|  |  |  |                           baseline: TextBaseline.alphabetic, | 
					
						
							|  |  |  |                           child: Container( | 
					
						
							|  |  |  |                             color: Theme.of(context).colorScheme.surface, | 
					
						
							|  |  |  |                             padding: const EdgeInsets.all(10), | 
					
						
							|  |  |  |                             constraints: const BoxConstraints(maxWidth: 450), | 
					
						
							|  |  |  |                             child: FlowyText( | 
					
						
							|  |  |  |                               LocaleKeys.settings_menu_customPathPrompt.tr(), | 
					
						
							|  |  |  |                               maxLines: null, | 
					
						
							|  |  |  |                             ), | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                         child: const FlowyIconButton( | 
					
						
							|  |  |  |                           icon: Icon( | 
					
						
							|  |  |  |                             Icons.warning_amber_rounded, | 
					
						
							|  |  |  |                             size: 20, | 
					
						
							|  |  |  |                             color: Colors.orangeAccent, | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2023-06-06 17:19:53 +08:00
										 |  |  |                   const VSpace(4), | 
					
						
							|  |  |  |                   FlowyText.regular( | 
					
						
							|  |  |  |                     subtitle, | 
					
						
							|  |  |  |                     overflow: TextOverflow.ellipsis, | 
					
						
							|  |  |  |                     fontSize: FontSizes.s12, | 
					
						
							|  |  |  |                     fontFamily: GoogleFonts.poppins( | 
					
						
							|  |  |  |                       fontWeight: FontWeight.w300, | 
					
						
							|  |  |  |                     ).fontFamily, | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |                   ), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             if (trailing != null) ...[ | 
					
						
							| 
									
										
										
										
											2023-07-31 10:01:12 -05:00
										 |  |  |               const HSpace(cardSpacing), | 
					
						
							| 
									
										
										
										
											2023-04-03 04:57:59 +02:00
										 |  |  |               trailing!, | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |