From 0903b9d7e341f6489be176295e0143363571dd5c Mon Sep 17 00:00:00 2001 From: Moustapha Kodjo Amadou <107993382+kodjodevf@users.noreply.github.com> Date: Tue, 11 Nov 2025 10:38:27 +0100 Subject: [PATCH] refactor: improve code structure and enhance UI elements in the code editor and manga detail view --- lib/modules/browse/extension/edit_code.dart | 1049 ++++++++++++----- .../manga/detail/manga_detail_view.dart | 7 +- macos/Podfile.lock | 4 +- 3 files changed, 750 insertions(+), 310 deletions(-) diff --git a/lib/modules/browse/extension/edit_code.dart b/lib/modules/browse/extension/edit_code.dart index c3ca0f6d..a589700b 100644 --- a/lib/modules/browse/extension/edit_code.dart +++ b/lib/modules/browse/extension/edit_code.dart @@ -1,9 +1,10 @@ import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:json_view/json_view.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mangayomi/eval/lib.dart'; +import 'package:mangayomi/eval/model/m_manga.dart'; +import 'package:mangayomi/eval/model/m_pages.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/source.dart'; @@ -11,12 +12,11 @@ import 'package:mangayomi/modules/manga/home/widget/filter_widget.dart'; import 'package:mangayomi/modules/more/settings/appearance/providers/app_font_family.dart'; import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; -import 'package:mangayomi/services/get_detail.dart'; import 'package:mangayomi/services/get_filter_list.dart'; -import 'package:mangayomi/services/get_latest_updates.dart'; -import 'package:mangayomi/services/get_popular.dart'; +import 'package:mangayomi/services/isolate_service.dart'; import 'package:mangayomi/services/search.dart'; import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; +import 'package:mangayomi/utils/language.dart'; import 'package:mangayomi/utils/log/log.dart'; import 'package:re_editor/re_editor.dart'; import 'package:re_highlight/languages/dart.dart'; @@ -50,6 +50,29 @@ class _CodeEditorPageState extends ConsumerState { if (source?.itemType == ItemType.novel) ("cleanHtmlContent", 7), ]; + IconData _getServiceIcon(int index) { + switch (index) { + case 0: + return Icons.star_rounded; + case 1: + return Icons.update_rounded; + case 2: + return Icons.search_rounded; + case 3: + return Icons.info_outline_rounded; + case 4: + return Icons.image_rounded; + case 5: + return Icons.video_library_rounded; + case 6: + return Icons.article_rounded; + case 7: + return Icons.cleaning_services_rounded; + default: + return Icons.code_rounded; + } + } + int _serviceIndex = 0; int _page = 1; String _query = ""; @@ -153,7 +176,37 @@ class _CodeEditorPageState extends ConsumerState { final appFontFamily = ref.watch(appFontFamilyProvider); return Scaffold( appBar: AppBar( - leading: BackButton( + elevation: 0, + title: Row( + children: [ + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + source?.name ?? 'Code Editor', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + if (source != null) + Text( + completeLanguageName(source!.lang ?? ''), + style: TextStyle( + fontSize: 12, + color: Colors.grey[600], + fontWeight: FontWeight.normal, + ), + ), + ], + ), + ), + ], + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back_rounded), onPressed: () { isar.writeTxnSync(() { isar.sources.putSync( @@ -172,227 +225,369 @@ class _CodeEditorPageState extends ConsumerState { children: [ Flexible( flex: 7, - child: CodeEditor( - style: CodeEditorStyle( - fontSize: 15, - fontFamily: appFontFamily, - codeTheme: CodeHighlightTheme( - languages: { - 'dart': CodeHighlightThemeMode(mode: langDart), - 'javascript': CodeHighlightThemeMode( - mode: langJavascript, - ), - }, - theme: vs2015Theme, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: context.primaryColor.withValues(alpha: 0.2), + width: 1, + ), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12), ), ), - controller: _controller, - onChanged: (_) { - source?.sourceCode = _controller.text; - if (source != null && context.mounted) { - isar.writeTxnSync(() { - isar.sources.putSync( - source! - ..updatedAt = - DateTime.now().millisecondsSinceEpoch, - ); - }); - } - }, - wordWrap: false, - indicatorBuilder: - ( - context, - editingController, - chunkController, - notifier, - ) { - return Row( - children: [ - DefaultCodeLineNumber( - controller: editingController, - notifier: notifier, + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12), + ), + child: CodeEditor( + style: CodeEditorStyle( + fontSize: 15, + fontFamily: appFontFamily, + codeTheme: CodeHighlightTheme( + languages: { + 'dart': CodeHighlightThemeMode(mode: langDart), + 'javascript': CodeHighlightThemeMode( + mode: langJavascript, ), - DefaultCodeChunkIndicator( - width: 20, - controller: chunkController, - notifier: notifier, - ), - ], - ); + }, + theme: vs2015Theme, + ), + ), + controller: _controller, + onChanged: (_) { + source?.sourceCode = _controller.text; + if (source != null && context.mounted) { + isar.writeTxnSync(() { + isar.sources.putSync( + source! + ..updatedAt = + DateTime.now().millisecondsSinceEpoch, + ); + }); + } }, - sperator: Container( - width: 1, - color: context.dynamicThemeColor, + wordWrap: false, + indicatorBuilder: + ( + context, + editingController, + chunkController, + notifier, + ) { + return Row( + children: [ + DefaultCodeLineNumber( + controller: editingController, + notifier: notifier, + ), + DefaultCodeChunkIndicator( + width: 20, + controller: chunkController, + notifier: notifier, + ), + ], + ); + }, + sperator: Container( + width: 1, + color: context.dynamicThemeColor.withValues( + alpha: 0.3, + ), + ), + ), ), ), ), if (context.isTablet) Flexible( flex: 3, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: DropdownButton<(String, int)>( - icon: const Icon(Icons.keyboard_arrow_down), - isExpanded: true, - value: _getServices(context).firstWhere( - (element) => element.$2 == _serviceIndex, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: context.primaryColor.withValues(alpha: 0.2), + width: 1, + ), + borderRadius: const BorderRadius.only( + topRight: Radius.circular(12), + bottomRight: Radius.circular(12), + ), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + context.primaryColor.withValues(alpha: 0.03), + Colors.transparent, + ], + ), + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(12), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: context.primaryColor.withValues( + alpha: 0.3, + ), + width: 1.5, + ), + color: context.primaryColor.withValues( + alpha: 0.05, + ), + ), + child: DropdownButton<(String, int)>( + icon: Icon( + Icons.keyboard_arrow_down_rounded, + color: context.primaryColor, + ), + isExpanded: true, + underline: const SizedBox.shrink(), + padding: const EdgeInsets.symmetric( + horizontal: 12, + ), + value: _getServices(context).firstWhere( + (element) => element.$2 == _serviceIndex, + ), + hint: Text( + _getServices(context) + .firstWhere( + (element) => + element.$2 == _serviceIndex, + ) + .$1, + style: const TextStyle(fontSize: 13), + ), + items: _getServices(context) + .map( + (e) => DropdownMenuItem( + value: e, + child: Row( + children: [ + Icon( + _getServiceIcon(e.$2), + size: 18, + color: context.primaryColor, + ), + const SizedBox(width: 10), + Text( + e.$1, + style: const TextStyle( + fontSize: 13, + ), + ), + ], + ), + ), + ) + .toList(), + onChanged: (v) { + setState(() { + _serviceIndex = v!.$2; + }); + }, + ), ), - hint: Text( - _getServices(context) - .firstWhere( - (element) => element.$2 == _serviceIndex, - ) - .$1, - style: const TextStyle(fontSize: 13), + ), + if (_serviceIndex == 0 || + _serviceIndex == 1 || + _serviceIndex == 2) + _textEditing("Page", context, "ex: 1", (v) { + _page = int.tryParse(v) ?? 1; + }), + if (_serviceIndex == 2) + _textEditing("Query", context, "ex: one piece", ( + v, + ) { + _query = v; + }), + if (_serviceIndex == 3 || + _serviceIndex == 4 || + _serviceIndex == 5 || + _serviceIndex == 6) + _textEditing( + "Url", + context, + "ex: url of the entry", + (v) { + _url = v; + }, ), - items: _getServices(context) - .map( - (e) => DropdownMenuItem( - value: e, - child: Text( - e.$1, - style: const TextStyle(fontSize: 13), + if (_serviceIndex == 7) + _textEditing("Html", context, "ex.

Text

", ( + v, + ) { + _html = v; + }), + Padding( + padding: const EdgeInsets.all(12), + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.center, + children: [ + FilledButton.icon( + style: FilledButton.styleFrom( + backgroundColor: context.primaryColor, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + elevation: 2, + ), + icon: const Icon( + Icons.play_arrow_rounded, + size: 20, + ), + label: const Text( + "Execute", + style: TextStyle( + fontWeight: FontWeight.bold, ), ), - ) - .toList(), - onChanged: (v) { - setState(() { - _serviceIndex = v!.$2; - }); - }, - ), - ), - if (_serviceIndex == 0 || - _serviceIndex == 1 || - _serviceIndex == 2) - _textEditing("Page", context, "ex: 1", (v) { - _page = int.tryParse(v) ?? 1; - }), - if (_serviceIndex == 2) - _textEditing("Query", context, "ex: one piece", (v) { - _query = v; - }), - if (_serviceIndex == 3 || - _serviceIndex == 4 || - _serviceIndex == 5 || - _serviceIndex == 6) - _textEditing("Url", context, "ex: url of the entry", ( - v, - ) { - _url = v; - }), - if (_serviceIndex == 7) - _textEditing("Html", context, "ex.

Text

", (v) { - _html = v; - }), - Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - ElevatedButton( - onPressed: () async { - source?.sourceCode = _controller.text; - if (source != null && context.mounted) { - isar.writeTxnSync(() { - isar.sources.putSync( - source! - ..updatedAt = DateTime.now() - .millisecondsSinceEpoch, - ); + onPressed: () async { + source?.sourceCode = _controller.text; + if (source != null && context.mounted) { + isar.writeTxnSync(() { + isar.sources.putSync( + source! + ..updatedAt = DateTime.now() + .millisecondsSinceEpoch, + ); + }); + } + setState(() { + result = null; + _isLoading = true; + _error = false; + _errorText = ""; }); - } - setState(() { - result = null; - _isLoading = true; - _error = false; - _errorText = ""; - }); - if (source != null) { - final service = getExtensionService( - source!, - ref.read(androidProxyServerStateProvider), - ); + if (source != null) { + final proxyServer = ref.read( + androidProxyServerStateProvider, + ); + final service = getExtensionService( + source!, + proxyServer, + ); + try { + if (_serviceIndex == 0) { + final getManga = + await getIsolateService.get< + MPages? + >( + page: _page, + source: source, + serviceType: 'getPopular', + proxyServer: ref.read( + androidProxyServerStateProvider, + ), + ); + result = getManga!.toJson(); + } else if (_serviceIndex == 1) { + final getManga = + await getIsolateService.get< + MPages? + >( + page: _page, + source: source, + serviceType: 'getLatestUpdates', + proxyServer: ref.read( + androidProxyServerStateProvider, + ), + ); + result = getManga!.toJson(); + } else if (_serviceIndex == 2) { + final getManga = + await getIsolateService + .get( + query: _query, + filterList: filterList, + source: source, + page: _page, + serviceType: 'search', + proxyServer: proxyServer, + ); + result = getManga!.toJson(); + } else if (_serviceIndex == 3) { + final getManga = + await getIsolateService + .get( + url: _url, + source: source, + serviceType: 'getDetail', + proxyServer: proxyServer, + ); - try { - if (_serviceIndex == 0) { - final getManga = await ref.watch( - getPopularProvider( - source: source!, - page: _page, - ).future, - ); - result = getManga!.toJson(); - } else if (_serviceIndex == 1) { - final getManga = await ref.watch( - getLatestUpdatesProvider( - source: source!, - page: _page, - ).future, - ); - result = getManga!.toJson(); - } else if (_serviceIndex == 2) { - final getManga = await ref.watch( - searchProvider( - source: source!, - query: _query, - page: _page, - filterList: filterList, - ).future, - ); - result = getManga!.toJson(); - } else if (_serviceIndex == 3) { - final getManga = await ref.watch( - getDetailProvider( - source: source!, - url: _url, - ).future, - ); - result = getManga.toJson(); - } else if (_serviceIndex == 4) { - result = { - "pages": (await service.getPageList( + result = getManga.toJson(); + } else if (_serviceIndex == 4) { + result = { + "pages": (await service.getPageList( + _url, + )).map((e) => e.toJson()).toList(), + }; + } else if (_serviceIndex == 5) { + result = (await service.getVideoList( _url, - )).map((e) => e.toJson()).toList(), - }; - } else if (_serviceIndex == 5) { - result = (await service.getVideoList( - _url, - )).map((e) => e.toJson()).toList(); - } else if (_serviceIndex == 6) { - result = (await service.getHtmlContent( - "test", - _url, - )); - } else { - result = (await service - .cleanHtmlContent(_html)); - } - if (context.mounted) { - setState(() { - _isLoading = false; - }); - } - } catch (e) { - if (context.mounted) { - setState(() { - _error = true; - _errorText = e.toString(); - _isLoading = false; - }); + )).map((e) => e.toJson()).toList(); + } else if (_serviceIndex == 6) { + result = (await service + .getHtmlContent("test", _url)); + } else { + result = (await service + .cleanHtmlContent(_html)); + } + if (context.mounted) { + setState(() { + _isLoading = false; + }); + } + } catch (e) { + if (context.mounted) { + setState(() { + _error = true; + _errorText = e.toString(); + _isLoading = false; + }); + } } } - } - }, - child: const Text("Execute"), - ), - Padding( - padding: const EdgeInsets.all(10), - child: ElevatedButton( + }, + ), + OutlinedButton.icon( + style: OutlinedButton.styleFrom( + foregroundColor: context.primaryColor, + side: BorderSide( + color: context.primaryColor.withValues( + alpha: 0.5, + ), + width: 1.5, + ), + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + icon: const Icon( + Icons.refresh_rounded, + size: 20, + ), + label: Text( + context.l10n.reset, + style: const TextStyle( + fontWeight: FontWeight.w600, + ), + ), onPressed: () { setState(() { result = null; @@ -402,117 +597,330 @@ class _CodeEditorPageState extends ConsumerState { filters = []; }); }, - child: Text(context.l10n.reset), ), - ), - if (_serviceIndex == 2 && filterList.isNotEmpty) - ElevatedButton( - onPressed: () async { - if (source != null) { - setState(() { - filterList = getFilterList( - source: source!, - ); - }); - try { - if (filters.isEmpty) { - filters = filterList; - } - final res = await filterDialog(context); - if (res == 'filter' && - context.mounted) { - setState(() { - result = null; - _isLoading = true; - _error = false; - _errorText = ""; - }); - final getManga = await ref.watch( - searchProvider( - source: source!, - query: _query, - page: _page, - filterList: filters, - ).future, + if (_serviceIndex == 2 && filterList.isNotEmpty) + FilledButton.tonalIcon( + style: FilledButton.styleFrom( + backgroundColor: context.primaryColor + .withValues(alpha: 0.15), + foregroundColor: context.primaryColor, + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + icon: const Icon( + Icons.filter_alt_rounded, + size: 20, + ), + label: Text( + context.l10n.filter, + style: const TextStyle( + fontWeight: FontWeight.w600, + ), + ), + onPressed: () async { + if (source != null) { + setState(() { + filterList = getFilterList( + source: source!, ); - result = getManga!.toJson(); + }); + try { + if (filters.isEmpty) { + filters = filterList; + } + final res = await filterDialog( + context, + ); + if (res == 'filter' && + context.mounted) { + setState(() { + result = null; + _isLoading = true; + _error = false; + _errorText = ""; + }); + final getManga = await ref.watch( + searchProvider( + source: source!, + query: _query, + page: _page, + filterList: filters, + ).future, + ); + result = getManga!.toJson(); + setState(() { + _isLoading = false; + }); + } + } catch (e) { setState(() { + _error = true; + _errorText = e.toString(); _isLoading = false; }); } - } catch (e) { - setState(() { - _error = true; - _errorText = e.toString(); - _isLoading = false; - }); } - } - }, - child: Text(context.l10n.filter), - ), - ], + }, + ), + ], + ), ), - ), - Expanded( - child: _error - ? SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [Text(_errorText)], - ), - ) - : _isLoading - ? const Center(child: CircularProgressIndicator()) - : result != null - ? JsonConfig( - data: JsonConfigData( - gap: 100, - style: const JsonStyleScheme( - quotation: JsonQuotation.same('"'), - openAtStart: false, - arrow: Icon(Icons.arrow_forward), - depth: 4, + const Divider(height: 1), + Expanded( + child: _error + ? Container( + padding: const EdgeInsets.all(20), + child: Center( + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.red.withValues( + alpha: 0.1, + ), + borderRadius: BorderRadius.circular( + 12, + ), + border: Border.all( + color: Colors.red.withValues( + alpha: 0.3, + ), + width: 1, + ), + ), + child: SelectableText( + _errorText, + style: const TextStyle( + fontSize: 12, + fontFamily: 'monospace', + ), + ), + ), + ), + ) + : _isLoading + ? Center( + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + CircularProgressIndicator( + color: context.primaryColor, + ), + const SizedBox(height: 16), + Text( + 'Executing...', + style: TextStyle( + color: context.primaryColor, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ) + : result != null + ? Container( + padding: const EdgeInsets.all(12), + child: JsonConfig( + data: JsonConfigData( + gap: 100, + style: const JsonStyleScheme( + quotation: JsonQuotation.same('"'), + openAtStart: false, + arrow: Icon( + Icons.arrow_forward_rounded, + ), + depth: 4, + ), + color: const JsonColorScheme(), + ), + child: JsonView(json: result), + ), + ) + : Center( + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Icon( + Icons.data_object_rounded, + size: 64, + color: Colors.grey.withValues( + alpha: 0.5, + ), + ), + const SizedBox(height: 16), + Text( + 'No results yet', + style: TextStyle( + color: Colors.grey.withValues( + alpha: 0.7, + ), + fontSize: 15, + ), + ), + const SizedBox(height: 8), + Text( + 'Execute a service to see results', + style: TextStyle( + color: Colors.grey.withValues( + alpha: 0.5, + ), + fontSize: 12, + ), + ), + ], ), - color: const JsonColorScheme(), ), - child: JsonView(json: result), - ) - : const SizedBox.shrink(), - ), - ], + ), + ], + ), ), ), ], ), ), if (context.isTablet) - Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.white, width: 0.5), - borderRadius: BorderRadius.circular(5), - color: Colors.black, - ), - width: context.width(1), - height: 200, - child: ValueListenableBuilder( - valueListenable: _logsNotifier, - builder: (context, logs, child) => SuperListView.separated( - separatorBuilder: (context, index) => const Divider(), - controller: _scrollController, - padding: const EdgeInsets.all(10), - itemCount: logs.length, - itemBuilder: (context, index) { - final value = logs[index]; - return SelectableText( - value.$2, - style: TextStyle( - color: value.$1 == LoggerLevel.info - ? Colors.yellow - : Colors.blueAccent, + Padding( + padding: const EdgeInsets.all(12), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: context.primaryColor.withValues(alpha: 0.3), + width: 1.5, + ), + borderRadius: BorderRadius.circular(12), + color: Colors.black, + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.2), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + height: 200, + child: Column( + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 10, ), - ); - }, + decoration: BoxDecoration( + color: Colors.grey[900], + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(12), + topRight: Radius.circular(12), + ), + border: Border( + bottom: BorderSide( + color: context.primaryColor.withValues(alpha: 0.3), + width: 1, + ), + ), + ), + child: Row( + children: [ + Icon( + Icons.terminal_rounded, + size: 18, + color: context.primaryColor, + ), + const SizedBox(width: 8), + Text( + 'Console Logs', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: context.primaryColor, + ), + ), + const Spacer(), + IconButton( + icon: const Icon( + Icons.clear_all_rounded, + size: 18, + color: Colors.grey, + ), + tooltip: 'Clear logs', + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + onPressed: () { + setState(() { + _logsNotifier.value.clear(); + }); + }, + ), + ], + ), + ), + Expanded( + child: ValueListenableBuilder( + valueListenable: _logsNotifier, + builder: (context, logs, child) => logs.isEmpty + ? Center( + child: Text( + 'No logs yet', + style: TextStyle( + color: Colors.grey.withValues(alpha: 0.5), + fontSize: 12, + ), + ), + ) + : SuperListView.separated( + separatorBuilder: (context, index) => Divider( + height: 1, + color: Colors.grey.withValues(alpha: 0.2), + ), + controller: _scrollController, + padding: const EdgeInsets.all(12), + itemCount: logs.length, + itemBuilder: (context, index) { + final value = logs[index]; + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 4, + ), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Icon( + value.$1 == LoggerLevel.info + ? Icons.info_outline_rounded + : Icons.bug_report_rounded, + size: 14, + color: value.$1 == LoggerLevel.info + ? Colors.yellow + : Colors.blueAccent, + ), + const SizedBox(width: 8), + Expanded( + child: SelectableText( + value.$2, + style: TextStyle( + fontSize: 11, + fontFamily: 'monospace', + color: + value.$1 == LoggerLevel.info + ? Colors.yellow + : Colors.blueAccent, + ), + ), + ), + ], + ), + ); + }, + ), + ), + ), + ], ), ), ), @@ -529,24 +937,53 @@ Widget _textEditing( void Function(String)? onChanged, ) { return Padding( - padding: const EdgeInsets.all(4), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), child: TextFormField( keyboardType: label == "Page" ? TextInputType.number : TextInputType.text, onChanged: onChanged, + style: const TextStyle(fontSize: 13), decoration: InputDecoration( hintText: hintText, labelText: label, isDense: true, filled: true, - fillColor: Colors.transparent, + fillColor: context.primaryColor.withValues(alpha: 0.05), + prefixIcon: Icon( + label == "Page" + ? Icons.numbers_rounded + : label == "Query" + ? Icons.search_rounded + : label == "Url" + ? Icons.link_rounded + : Icons.code_rounded, + size: 20, + color: context.primaryColor, + ), enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: context.dynamicThemeColor), + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: context.dynamicThemeColor.withValues(alpha: 0.3), + width: 1.5, + ), ), focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: context.dynamicThemeColor), + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: context.primaryColor, width: 2), ), border: OutlineInputBorder( - borderSide: BorderSide(color: context.dynamicThemeColor), + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: context.dynamicThemeColor.withValues(alpha: 0.3), + width: 1.5, + ), + ), + labelStyle: TextStyle( + fontSize: 12, + color: context.primaryColor.withValues(alpha: 0.7), + ), + hintStyle: TextStyle( + fontSize: 12, + color: Colors.grey.withValues(alpha: 0.5), ), ), ), diff --git a/lib/modules/manga/detail/manga_detail_view.dart b/lib/modules/manga/detail/manga_detail_view.dart index 033e6be7..8b333209 100644 --- a/lib/modules/manga/detail/manga_detail_view.dart +++ b/lib/modules/manga/detail/manga_detail_view.dart @@ -661,8 +661,9 @@ class _MangaDetailViewState extends ConsumerState widget.manga!.source!, widget.manga!.sourceId, ); + if (source == null) return; final url = - "${source!.baseUrl}${widget.manga!.link!.getUrlWithoutDomain}"; + "${source.baseUrl}${widget.manga!.link!.getUrlWithoutDomain}"; final box = context.findRenderObject() as RenderBox?; SharePlus.instance.share( @@ -683,6 +684,7 @@ class _MangaDetailViewState extends ConsumerState widget.manga!.source!, widget.manga!.sourceId, ); + if (source == null) return; context.push( '/extension_detail', extra: source, @@ -1954,8 +1956,9 @@ class _MangaDetailViewState extends ConsumerState widget.manga!.source!, widget.manga!.sourceId, ); + if (source == null) return; final url = - "${source!.baseUrl}${widget.manga!.link!.getUrlWithoutDomain}"; + "${source.baseUrl}${widget.manga!.link!.getUrlWithoutDomain}"; Map data = { 'url': url, diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 25d9880d..263c041e 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -140,12 +140,12 @@ SPEC CHECKSUMS: media_kit_video: fa6564e3799a0a28bff39442334817088b7ca758 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 package_info_plus: f0052d280d17aa382b932f399edf32507174e870 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 rust_lib_mangayomi: 4cbf39f5d158ad8eb0f17fd8e52d88514d435cd8 screen_brightness_macos: 2a3ee243f8051c340381e8e51bcedced8360f421 screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc - url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd volume_controller: 5c068e6d085c80dadd33fc2c918d2114b775b3dd wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b window_manager: b729e31d38fb04905235df9ea896128991cad99e