diff --git a/lib/components/comic.dart b/lib/components/comic.dart index 344cab7..95c8818 100644 --- a/lib/components/comic.dart +++ b/lib/components/comic.dart @@ -235,110 +235,109 @@ class ComicTile extends StatelessWidget { } Widget _buildBriefMode(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8), - child: LayoutBuilder( - builder: (context, constraints) { - return InkWell( - borderRadius: BorderRadius.circular(8), - onTap: _onTap, - onLongPress: - enableLongPressed ? () => _onLongPressed(context) : null, - onSecondaryTapDown: (detail) => onSecondaryTap(detail, context), - child: Column( - children: [ - Expanded( - child: SizedBox( - child: Stack( - children: [ - Positioned.fill( - child: Container( - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .secondaryContainer, - borderRadius: BorderRadius.circular(8), - ), - clipBehavior: Clip.antiAlias, - child: buildImage(context), + return LayoutBuilder( + builder: (context, constraints) { + return InkWell( + borderRadius: BorderRadius.circular(8), + onTap: _onTap, + onLongPress: enableLongPressed ? () => _onLongPressed(context) : null, + onSecondaryTapDown: (detail) => onSecondaryTap(detail, context), + child: Column( + children: [ + Expanded( + child: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + color: context.colorScheme.secondaryContainer, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.black.toOpacity(0.2), + blurRadius: 2, + offset: const Offset(0, 2), ), - ), - Align( - alignment: Alignment.bottomRight, - child: (() { - final subtitle = - comic.subtitle?.replaceAll('\n', '').trim(); - final text = comic.description.isNotEmpty - ? comic.description.split('|').join('\n') - : (subtitle?.isNotEmpty == true - ? subtitle - : null); - final scale = - (appdata.settings['comicTileScale'] as num) - .toDouble(); - final fortSize = scale < 0.85 - ? 8.0 // 小尺寸 - : (scale < 1.0 ? 10.0 : 12.0); - - if (text == null) { - return const SizedBox - .shrink(); // 如果没有文本,则不显示任何内容 - } - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 2, vertical: 2), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(10.0), - ), - child: Container( - color: Colors.black.toOpacity(0.5), - child: Padding( - padding: - const EdgeInsets.fromLTRB(8, 6, 8, 6), - child: ConstrainedBox( - constraints: BoxConstraints( - maxWidth: constraints.maxWidth, - ), - child: Text( - text, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: fortSize, - color: Colors.white, - ), - textAlign: TextAlign.right, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - ), - ), - ), - ); - })(), - ), - ], + ], + ), + clipBehavior: Clip.antiAlias, + child: buildImage(context), ), ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(8, 4, 8, 0), - child: Text( - comic.title.replaceAll('\n', ''), - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, + Align( + alignment: Alignment.bottomRight, + child: (() { + final subtitle = + comic.subtitle?.replaceAll('\n', '').trim(); + final text = comic.description.isNotEmpty + ? comic.description.split('|').join('\n') + : (subtitle?.isNotEmpty == true ? subtitle : null); + final fortSize = constraints.maxWidth < 80 + ? 8.0 + : constraints.maxWidth < 150 + ? 10.0 + : 12.0; + + if (text == null) { + return const SizedBox(); + } + + var children = []; + for (var line in text.split('\n')) { + children.add(Container( + margin: const EdgeInsets.fromLTRB(2, 0, 2, 2), + padding: constraints.maxWidth < 80 + ? const EdgeInsets.fromLTRB(3, 1, 3, 1) + : constraints.maxWidth < 150 + ? const EdgeInsets.fromLTRB(4, 2, 4, 2) + : const EdgeInsets.fromLTRB(5, 2, 5, 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.black.toOpacity(0.5), + ), + constraints: BoxConstraints( + maxWidth: constraints.maxWidth, + ), + child: Text( + line, + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: fortSize, + color: Colors.white, + ), + textAlign: TextAlign.right, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + )); + } + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: children, + ); + })(), ), + ], + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(4, 4, 4, 0), + child: TextScroll( + comic.title.replaceAll('\n', ''), + mode: TextScrollMode.endless, + style: const TextStyle( + fontWeight: FontWeight.w500, ), - ], + delayBefore: Duration(milliseconds: 500), + velocity: const Velocity(pixelsPerSecond: Offset(40, 0)), + ), ), - ); - }, - )); + ], + ).paddingHorizontal(6).paddingVertical(8), + ); + }, + ); } List _splitText(String text) { @@ -807,7 +806,10 @@ class _SliverGridComics extends StatelessWidget { duration: const Duration(milliseconds: 150), decoration: BoxDecoration( color: isSelected - ? Theme.of(context).colorScheme.secondaryContainer.toOpacity(0.72) + ? Theme.of(context) + .colorScheme + .secondaryContainer + .toOpacity(0.72) : null, borderRadius: BorderRadius.circular(12), ), @@ -901,13 +903,13 @@ class ComicListState extends State { late bool enablePageStorage = widget.enablePageStorage; Map get state => { - 'maxPage': _maxPage, - 'data': _data, - 'page': _page, - 'error': _error, - 'loading': _loading, - 'nextUrl': _nextUrl, - }; + 'maxPage': _maxPage, + 'data': _data, + 'page': _page, + 'error': _error, + 'loading': _loading, + 'nextUrl': _nextUrl, + }; void restoreState(Map? state) { if (state == null || !enablePageStorage) { @@ -924,7 +926,7 @@ class ComicListState extends State { } void storeState() { - if(enablePageStorage) { + if (enablePageStorage) { PageStorage.of(context).writeState(context, state); } } @@ -1094,11 +1096,11 @@ class ComicListState extends State { while (_data[page] == null) { await _fetchNext(); } - if(mounted) { + if (mounted) { setState(() {}); } } catch (e) { - if(mounted) { + if (mounted) { setState(() { _error = e.toString(); }); diff --git a/lib/components/components.dart b/lib/components/components.dart index cef1056..420309f 100644 --- a/lib/components/components.dart +++ b/lib/components/components.dart @@ -9,6 +9,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:syntax_highlight/syntax_highlight.dart'; +import 'package:text_scroll/text_scroll.dart'; import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app_page_route.dart'; import 'package:venera/foundation/appdata.dart'; diff --git a/lib/foundation/favorites.dart b/lib/foundation/favorites.dart index 5353ad0..6671aba 100644 --- a/lib/foundation/favorites.dart +++ b/lib/foundation/favorites.dart @@ -73,6 +73,7 @@ class FavoriteItem implements Comic { @override String get description { + var time = this.time.substring(0, 10); return appdata.settings['comicDisplayMode'] == 'detailed' ? "$time | ${type == ComicType.local ? 'local' : type.comicSource?.name ?? "Unknown"}" : "${type.comicSource?.name ?? "Unknown"} | $time"; diff --git a/pubspec.lock b/pubspec.lock index fcac644..d6e8e6d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -968,6 +968,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.3" + text_scroll: + dependency: "direct main" + description: + name: text_scroll + sha256: "7869d86a6fdd725dee56bdd150216a99f0372b82fbfcac319214dbd5f36e1908" + url: "https://pub.dev" + source: hosted + version: "0.2.0" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4ada6b1..3c67428 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -72,6 +72,7 @@ dependencies: shimmer: ^3.0.0 flutter_memory_info: ^0.0.1 syntax_highlight: ^0.4.0 + text_scroll: ^0.2.0 dev_dependencies: flutter_test: