chore: 清理HarmonyOS平台无关的依赖文件并更新依赖配置

本次提交包含以下主要变更:
1. 删除所有packages/fluttertoast_ohos下的HarmonyOS原生模块文件与编译配置
2. 更新pubspec.yaml的SDK与Flutter最低版本要求
3. 修复多处代码细节问题:
   - 替换弃用的Share.shareXFiles为SharePlus新API
   - 修正ConnectivityResult判断逻辑,使用contains替代直接相等判断
   - 修复列表分隔符的unused参数命名
   - 调整条件渲染语法为更简洁的空值判断写法
   - 统一CupertinoButton的minSize参数写法
   - 简化空字符串默认值处理逻辑
4. 更新pubspec.lock依赖版本
This commit is contained in:
Developer
2026-06-16 04:08:02 +08:00
parent 3a056ca676
commit efe98f60e7
195 changed files with 230 additions and 28197 deletions

View File

@@ -223,7 +223,7 @@ class ComparisonController extends BaseController {
'ComparisonController: API返回: title=${apiRecipe.title}, '
'nutrition=${apiRecipe.nutrition != null ? "有(${apiRecipe.nutrition!.calories}kcal)" : "NULL"}, '
'meta=${apiRecipe.meta != null ? "" : "NULL"}, '
'ingredients=${apiRecipe.ingredients?.length ?? 0}',
'ingredients=${apiRecipe.ingredients.length}',
);
} on TimeoutException {
debugPrint('ComparisonController: fetchDetail超时5s使用源数据');
@@ -255,7 +255,7 @@ class ComparisonController extends BaseController {
RecipeModel _mergeRecipeData(RecipeModel original, RecipeModel api) {
return RecipeModel(
id: api.id > 0 ? api.id : original.id,
title: (api.title ?? '').isNotEmpty ? api.title : original.title,
title: api.title.isNotEmpty ? api.title : original.title,
intro: (api.intro ?? '').isNotEmpty ? api.intro : original.intro,
cover: (api.cover ?? '').isNotEmpty ? api.cover : original.cover,
categoryName: (api.categoryName ?? '').isNotEmpty
@@ -263,17 +263,15 @@ class ComparisonController extends BaseController {
: original.categoryName,
nutrition: api.nutrition ?? original.nutrition,
meta: api.meta ?? original.meta,
ingredients: (api.ingredients != null && api.ingredients!.isNotEmpty)
ingredients: api.ingredients.isNotEmpty
? api.ingredients
: original.ingredients,
categorizedIngredients:
api.categorizedIngredients ?? original.categorizedIngredients,
statistics: api.statistics ?? original.statistics,
rating: api.rating ?? original.rating,
tags: api.tags ?? original.tags,
allergens: (api.allergens != null && api.allergens!.isNotEmpty)
? api.allergens
: original.allergens,
tags: api.tags,
allergens: api.allergens.isNotEmpty ? api.allergens : original.allergens,
author: api.author ?? original.author,
content: (api.content ?? '').isNotEmpty ? api.content : original.content,
);
@@ -347,7 +345,9 @@ class ComparisonController extends BaseController {
);
} on TimeoutException {
debugPrint('ComparisonController: API超时5s使用源数据');
} catch (_) {}
} catch (_) {
// silently ignore - fall back to source data
}
}
} else {
IngredientModel apiIng = ingredient;
@@ -357,7 +357,9 @@ class ComparisonController extends BaseController {
.timeout(const Duration(seconds: 5));
} on TimeoutException {
debugPrint('ComparisonController: API超时5s使用源数据');
} catch (e) {}
} catch (e) {
// silently ignore - fall back to source data
}
result = IngredientModel(
id: apiIng.id > 0 ? apiIng.id : ingredient.id,
name: apiIng.name.isNotEmpty ? apiIng.name : ingredient.name,
@@ -751,7 +753,7 @@ class ComparisonSummary {
emoji: '⚠️',
title: '过敏原对比',
description: aAllergens != bAllergens
? '$fewer 过敏原更少 (${aAllergens} vs ${bAllergens})'
? '$fewer 过敏原更少 ($aAllergens vs $bAllergens)'
: '两者过敏原数量相同',
type: aAllergens != bAllergens
? ComparisonType.green
@@ -769,7 +771,7 @@ class ComparisonSummary {
ComparisonPoint(
emoji: '🥘',
title: '用料数量',
description: '${a.title} ${aIngCount} vs ${b.title} ${bIngCount}',
description: '${a.title} $aIngCount vs ${b.title} $bIngCount种',
type: ComparisonType.purple,
),
);
@@ -818,7 +820,7 @@ class ComparisonSummary {
emoji: '⚠️',
title: '过敏原对比',
description: aAllergens != bAllergens
? '$fewer 过敏原更少 (${aAllergens} vs ${bAllergens})'
? '$fewer 过敏原更少 ($aAllergens vs $bAllergens)'
: '两者过敏原数量相同',
type: aAllergens != bAllergens
? ComparisonType.green

View File

@@ -400,7 +400,7 @@ class WhatToEatController extends BaseController {
'title': recipe.title,
'categoryName': recipe.categoryName ?? '',
'time': DateTime.now().toIso8601String(),
'displayIntro': recipe.displayIntro ?? '',
'displayIntro': recipe.displayIntro,
};
eatHistory.insert(0, entry);
if (eatHistory.length > _maxHistorySize) {

View File

@@ -117,7 +117,7 @@ class BrowseHistorySection extends StatelessWidget {
return ListView.separated(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: DesignTokens.space1),
separatorBuilder: (_, __) => const SizedBox(width: DesignTokens.space2),
separatorBuilder: (_, _) => const SizedBox(width: DesignTokens.space2),
itemCount: history.length,
itemBuilder: (context, index) {
final item = history[index];

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: mini_card_image_view.dart
* 名称: 迷你卡片图片组件
* 作用: 迷你卡片的图片展示组件,包含液态玻璃效果、分类标签、操作按钮
@@ -94,7 +94,7 @@ class MiniCardImageView extends StatelessWidget {
maxHeightDiskCache: 800,
fadeInDuration: const Duration(milliseconds: 300),
fadeInCurve: Curves.easeOut,
errorWidget: (_, __, _) => Container(
errorWidget: (_, _, _) => Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
@@ -113,7 +113,7 @@ class MiniCardImageView extends StatelessWidget {
),
),
),
progressIndicatorBuilder: (_, __, progress) => Container(
progressIndicatorBuilder: (_, _, progress) => Container(
color: DesignTokens.background,
child: Center(
child: CupertinoActivityIndicator(

View File

@@ -402,7 +402,9 @@ class _MiniCardPageState extends State<MiniCardPage> {
final boundary =
_cardKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) {
Share.share('🍳 ${recipe.name} — 来自 小妈厨房 迷你卡片');
SharePlus.instance.share(
ShareParams(text: '🍳 ${recipe.name} — 来自 小妈厨房 迷你卡片'),
);
return;
}
@@ -411,7 +413,9 @@ class _MiniCardPageState extends State<MiniCardPage> {
image.dispose();
if (byteData == null || !mounted) {
Share.share('🍳 ${recipe.name} — 来自 小妈厨房 迷你卡片');
SharePlus.instance.share(
ShareParams(text: '🍳 ${recipe.name} — 来自 小妈厨房 迷你卡片'),
);
return;
}
@@ -425,16 +429,21 @@ class _MiniCardPageState extends State<MiniCardPage> {
);
if (!mounted) return;
await Share.shareXFiles([
XFile(filePath),
], text: '🍳 ${recipe.name} — 来自 小妈厨房');
await SharePlus.instance.share(
ShareParams(
text: '🍳 ${recipe.name} — 来自 小妈厨房',
files: [XFile(filePath)],
),
);
Future.delayed(const Duration(seconds: 5), () {
if (file.existsSync()) file.deleteSync();
});
} catch (e) {
debugPrint('MiniCardPage: share failed: $e');
Share.share('🍳 ${recipe.name} — 来自 小妈厨房 迷你卡片');
SharePlus.instance.share(
ShareParams(text: '🍳 ${recipe.name} — 来自 小妈厨房 迷你卡片'),
);
}
}

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: mini_card_viewer.dart
* 名称: 迷你卡片全屏查看器
* 作用: 迷你卡片的全屏图片查看基于公共ImageViewerPage增加液态玻璃信息层
@@ -48,7 +48,7 @@ class MiniCardViewer {
fadeInCurve: Curves.easeOut,
maxWidthDiskCache: 1200,
maxHeightDiskCache: 1200,
errorWidget: (_, __, _) => Container(
errorWidget: (_, _, _) => Container(
color: Colors.grey[900],
child: const Center(
child: Icon(
@@ -58,7 +58,7 @@ class MiniCardViewer {
),
),
),
progressIndicatorBuilder: (_, __, _) => Container(
progressIndicatorBuilder: (_, _, _) => Container(
color: Colors.grey[900],
child: const Center(
child: CupertinoActivityIndicator(radius: 16),

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: search_page.dart
* 名称: 搜索页面
* 作用: iOS 26 风格的菜谱搜索页面,支持多维度搜索+高级筛选
@@ -633,7 +633,7 @@ class _SearchPageState extends State<SearchPage> {
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: tabs.length,
separatorBuilder: (_, __) => SizedBox(width: DesignTokens.space2),
separatorBuilder: (_, _) => SizedBox(width: DesignTokens.space2),
itemBuilder: (context, index) {
final tab = tabs[index];
final isSelected =
@@ -744,7 +744,7 @@ class _SearchPageState extends State<SearchPage> {
vertical: DesignTokens.space2,
),
itemCount: recipes.length,
separatorBuilder: (_, __) => const SizedBox(height: DesignTokens.space2),
separatorBuilder: (_, _) => const SizedBox(height: DesignTokens.space2),
itemBuilder: (context, index) {
final recipe = recipes[index];
return _buildRecipeCard(recipe, isDark);
@@ -858,7 +858,7 @@ class _SearchPageState extends State<SearchPage> {
vertical: DesignTokens.space2,
),
itemCount: ingredients.length,
separatorBuilder: (_, __) => const SizedBox(height: DesignTokens.space2),
separatorBuilder: (_, _) => const SizedBox(height: DesignTokens.space2),
itemBuilder: (context, index) {
final ingredient = ingredients[index];
return GestureDetector(

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: cache_manage_page.dart
* 说明: 缓存管理页面
* 作用: 管理首页Discover缓存、菜品详情缓存、食材缓存、API缓存与图片缓存
@@ -842,7 +842,7 @@ class _CacheManagePageState extends State<CacheManagePage> {
child: Image.network(
item.cover!,
fit: BoxFit.cover,
errorBuilder: (_, __, _) => Icon(
errorBuilder: (_, _, _) => Icon(
CupertinoIcons.photo,
color: DesignTokens.dynamicPrimary,
),

View File

@@ -579,7 +579,7 @@ class _FeedbackPageState extends State<FeedbackPage> {
),
trailing: CupertinoButton(
padding: EdgeInsets.zero,
minSize: 36,
minimumSize: const Size(36, 36),
onPressed: _showInfoDialog,
child: Icon(
CupertinoIcons.info_circle,

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: favorites_item_builders.dart
* 名称: 收藏项构建器 Mixin
* 作用: 收藏页面中各类收藏项的构建方法,拆分自 favorites_page.dart
@@ -204,7 +204,7 @@ mixin FavoritesItemBuilders<T extends StatefulWidget> on State<T> {
? coverUrl
: 'https://eat.wktyl.com/api/assets/$coverUrl',
fit: BoxFit.cover,
errorBuilder: (_, __, _) => Container(
errorBuilder: (_, _, _) => Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: footprints_page.dart
* 说明: 浏览记录页面,展示用户浏览菜谱历史
* 作用: 展示用户足迹,支持管理、删除、清空
@@ -133,7 +133,7 @@ class FootprintsPage extends StatelessWidget {
child: ListView.separated(
padding: const EdgeInsets.all(DesignTokens.space4),
itemCount: history.length,
separatorBuilder: (_, __) =>
separatorBuilder: (_, _) =>
const SizedBox(height: DesignTokens.space3),
itemBuilder: (context, index) =>
_buildHistoryCard(context, controller, history[index], isDark),

View File

@@ -320,7 +320,7 @@ class DishComparisonPage extends StatelessWidget {
width: 48,
height: 48,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Text(
errorBuilder: (_, _, _) => Text(
_categoryEmoji(
recipe.categoryName ?? '',
),
@@ -832,7 +832,7 @@ class DishComparisonPage extends StatelessWidget {
Widget _buildIndicesSection(List<RecipeModel> slots, bool isDark) {
final allKeys = <String>{};
for (final r in slots) {
allKeys.addAll(r.meta?.indices?.keys ?? <String>[]);
allKeys.addAll(r.meta?.indices.keys ?? <String>[]);
}
if (allKeys.isEmpty) return const SizedBox.shrink();
@@ -846,8 +846,8 @@ class DishComparisonPage extends StatelessWidget {
child: Column(
children: sortedKeys.map((key) {
if (is1v1) {
final scoreA = slots[0].meta?.indices?[key] ?? 0;
final scoreB = slots[1].meta?.indices?[key] ?? 0;
final scoreA = slots[0].meta?.indices[key] ?? 0;
final scoreB = slots[1].meta?.indices[key] ?? 0;
final colorA = ComparisonController.slotColors[0];
final colorB = ComparisonController.slotColors[1];
return Padding(
@@ -901,7 +901,7 @@ class DishComparisonPage extends StatelessWidget {
...slots.asMap().entries.map((entry) {
final i = entry.key;
final recipe = entry.value;
final score = recipe.meta?.indices?[key] ?? 0;
final score = recipe.meta?.indices[key] ?? 0;
final color = ComparisonController
.slotColors[i % ComparisonController.slotColors.length];
return Padding(
@@ -1105,7 +1105,6 @@ class DishComparisonPage extends StatelessWidget {
final item = recipe.nutrition?.items
?.where((e) => e.name == name)
.firstOrNull;
final hasValue = item != null;
final value = item?.value ?? 0;
final unit = item?.unit ?? '';
final slotColor = ComparisonController
@@ -1390,8 +1389,9 @@ class DishComparisonPage extends StatelessWidget {
Widget _buildSummarySection(ComparisonController ctrl, bool isDark) {
final summary = ctrl.dishComparisonSummary;
if (summary == null || summary.points.isEmpty)
if (summary == null || summary.points.isEmpty) {
return const SizedBox.shrink();
}
return _buildSectionCard(
isDark,

View File

@@ -181,7 +181,7 @@ class IngredientComparisonPage extends StatelessWidget {
width: 48,
height: 48,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Text(
errorBuilder: (_, _, _) => Text(
ingredient.displayImage,
style: const TextStyle(fontSize: 24),
),
@@ -381,8 +381,9 @@ class IngredientComparisonPage extends StatelessWidget {
final ing = entry.value;
final color = ComparisonController
.slotColors[i % ComparisonController.slotColors.length];
if (ing.nutrition == null || ing.nutrition!.isEmpty)
if (ing.nutrition == null || ing.nutrition!.isEmpty) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.only(bottom: DesignTokens.space3),
child: _buildNutritionBlock(
@@ -627,8 +628,9 @@ class IngredientComparisonPage extends StatelessWidget {
final ing = entry.value;
final color = ComparisonController
.slotColors[i % ComparisonController.slotColors.length];
if (ing.usageTip == null || ing.usageTip!.isEmpty)
if (ing.usageTip == null || ing.usageTip!.isEmpty) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.only(bottom: DesignTokens.space3),
child: _buildTipBlock(
@@ -690,8 +692,9 @@ class IngredientComparisonPage extends StatelessWidget {
Widget _buildSummarySection(ComparisonController ctrl, bool isDark) {
final summary = ctrl.ingredientComparisonSummary;
if (summary == null || summary.points.isEmpty)
if (summary == null || summary.points.isEmpty) {
return const SizedBox.shrink();
}
return _buildSectionCard(
isDark,

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: order_assistant_page.dart
* 名称: 点餐助手主页面
* 作用: 点餐/推单主界面,支持菜品管理、账单生成、二维码分享、文本/图片分享
@@ -851,13 +851,11 @@ class _OrderAssistantPageState extends State<OrderAssistantPage> {
}
final text = _generateOrderText(order);
try {
final box = context.findRenderObject() as RenderBox?;
await Share.share(
text,
subject: '点餐助手 - ${order.orderNo}',
sharePositionOrigin: box != null
? box.localToGlobal(Offset.zero) & box.size
: null,
await SharePlus.instance.share(
ShareParams(
text: text,
subject: '点餐助手 - ${order.orderNo}',
),
);
} catch (e) {
debugPrint('[OrderPage] share text error: $e');
@@ -955,7 +953,7 @@ class _OrderAssistantPageState extends State<OrderAssistantPage> {
borderRadius: DesignTokens.borderRadiusMd,
onPressed: () async {
await _captureAndShare(previewKey, order);
if (context.mounted) Navigator.pop(context);
if (mounted) Navigator.pop(context);
},
child: const Row(
mainAxisSize: MainAxisSize.min,
@@ -1310,14 +1308,12 @@ class _OrderAssistantPageState extends State<OrderAssistantPage> {
await File(filePath).writeAsBytes(buffer.asUint8List());
final xFile = XFile(filePath);
if (!mounted) return;
final box = context.findRenderObject() as RenderBox?;
await Share.shareXFiles(
[xFile],
text: '点餐助手 - ${order.orderNo}',
subject: '点餐助手 - ${order.orderNo}',
sharePositionOrigin: box != null
? box.localToGlobal(Offset.zero) & box.size
: null,
await SharePlus.instance.share(
ShareParams(
text: '点餐助手 - ${order.orderNo}',
subject: '点餐助手 - ${order.orderNo}',
files: [xFile],
),
);
} catch (e) {
debugPrint('[OrderPage] capture and share error: $e');

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: browse_history_picker.dart
* 名称: 浏览记录选择器
* 作用: 展示本地浏览记录供用户选择菜品
@@ -140,7 +140,7 @@ class BrowseHistoryPicker extends StatelessWidget {
width: 44,
height: 44,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => _defaultFoodIcon(),
errorBuilder: (_, _, _) => _defaultFoodIcon(),
)
: _defaultFoodIcon(),
),

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: dish_pick_sheet.dart
* 名称: 菜品选择面板
* 作用: 底部弹出面板,支持从浏览记录/收藏/手动输入三种方式选择菜品加入Tier List
@@ -357,7 +357,7 @@ class _DishPickSheetState extends State<DishPickSheet> {
bottom: bottomPadding + DesignTokens.space3,
),
itemCount: items.length,
separatorBuilder: (_, __) => material.Divider(
separatorBuilder: (_, _) => material.Divider(
height: 1,
color: isDark ? material.Colors.white10 : const Color(0x0F000000),
),
@@ -390,7 +390,7 @@ class _DishPickSheetState extends State<DishPickSheet> {
bottom: bottomPadding + DesignTokens.space3,
),
itemCount: items.length,
separatorBuilder: (_, __) => material.Divider(
separatorBuilder: (_, _) => material.Divider(
height: 1,
color: isDark ? material.Colors.white10 : const Color(0x0F000000),
),
@@ -547,7 +547,7 @@ class _DishPickSheetState extends State<DishPickSheet> {
? Image.network(
coverUrl,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Center(
errorBuilder: (_, _, _) => Center(
child: Text(
emoji,
style: const TextStyle(fontSize: 22),

View File

@@ -1,4 +1,4 @@
/*
/*
* 文件: dish_ranking_page.dart
* 名称: 菜品排名页面
* 作用: Tier List主界面展示5个层级的菜品排名支持拖拽排序、跨层级移动、添加/删除
@@ -325,7 +325,7 @@ class _DishRankingPageState extends State<DishRankingPage>
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
itemCount: items.length,
separatorBuilder: (_, __) => const SizedBox(width: 8),
separatorBuilder: (_, _) => const SizedBox(width: 8),
itemBuilder: (context, index) {
return _DishCard(
item: items[index],
@@ -549,7 +549,7 @@ class _DishCard extends StatelessWidget {
item.coverImage!,
fit: BoxFit.cover,
width: double.infinity,
errorBuilder: (_, __, ___) => Center(
errorBuilder: (_, _, _) => Center(
child: Text(
item.emoji,
style: const TextStyle(fontSize: 32),

View File

@@ -235,7 +235,7 @@ class ApiService {
final result = await Connectivity().checkConnectivity().timeout(
const Duration(seconds: 3),
);
return result == ConnectivityResult.none;
return result.contains(ConnectivityResult.none);
} catch (_) {
return true;
}

View File

@@ -278,10 +278,12 @@ class DataExportService extends GetxService {
Future<void> shareExportedData(String filePath) async {
if (kIsWeb) return;
await Share.shareXFiles(
[XFile(filePath)],
subject: '小妈厨房 - 数据导出',
text: '小妈厨房导出的数据',
await SharePlus.instance.share(
ShareParams(
text: '小妈厨房导出的数据',
subject: '小妈厨房 - 数据导出',
files: [XFile(filePath)],
),
);
}

View File

@@ -13,7 +13,7 @@ typedef OnNetworkRestoredCallback = Future<void> Function();
class ConnectivityService extends GetxService with WidgetsBindingObserver {
final Connectivity _connectivity = Connectivity();
StreamSubscription<ConnectivityResult>? _subscription;
StreamSubscription<List<ConnectivityResult>>? _subscription;
final Rx<ConnectivityStatus> status = Rx<ConnectivityStatus>(
ConnectivityStatus.unknown,
@@ -91,8 +91,8 @@ class ConnectivityService extends GetxService with WidgetsBindingObserver {
_onChanged(result);
}
void _onChanged(ConnectivityResult result) {
final hasConnection = result != ConnectivityResult.none;
void _onChanged(List<ConnectivityResult> results) {
final hasConnection = !results.contains(ConnectivityResult.none);
final newStatus = hasConnection
? ConnectivityStatus.online
: ConnectivityStatus.offline;
@@ -122,8 +122,8 @@ class ConnectivityService extends GetxService with WidgetsBindingObserver {
Future<bool> checkConnection() async {
if (kIsWeb) return true;
final result = await _connectivity.checkConnectivity();
return result != ConnectivityResult.none;
final results = await _connectivity.checkConnectivity();
return !results.contains(ConnectivityResult.none);
}
@override

View File

@@ -366,7 +366,7 @@ class ThemeService extends GetxController {
}
ThemeData getThemeData() {
final _font = fontFamilyStyle.value == FontFamilyStyle.notoSansSC
final font = fontFamilyStyle.value == FontFamilyStyle.notoSansSC
? 'NotoSansSC'
: null;
return ThemeData(
@@ -379,42 +379,42 @@ class ThemeService extends GetxController {
bodyLarge: TextStyle(
fontSize: fontSize.value,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
bodyMedium: TextStyle(
fontSize: fontSize.value - 2,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
bodySmall: TextStyle(
fontSize: fontSize.value - 4,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
titleLarge: TextStyle(
fontSize: fontSize.value + 4,
fontWeight: FontWeight.w700,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
titleMedium: TextStyle(
fontSize: fontSize.value + 2,
fontWeight: FontWeight.w600,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
titleSmall: TextStyle(
fontSize: fontSize.value,
fontWeight: FontWeight.w500,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
),
);
}
CupertinoThemeData get cupertinoThemeData {
final _font = fontFamilyStyle.value == FontFamilyStyle.notoSansSC
final font = fontFamilyStyle.value == FontFamilyStyle.notoSansSC
? 'NotoSansSC'
: null;
return CupertinoThemeData(
@@ -428,14 +428,14 @@ class ThemeService extends GetxController {
inherit: false,
fontSize: fontSize.value,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
navTitleTextStyle: TextStyle(
inherit: false,
fontSize: fontSize.value + 2,
fontWeight: FontWeight.w600,
color: textColor.value,
fontFamily: _font,
fontFamily: font,
),
),
);

View File

@@ -33,7 +33,7 @@ class AppUtils {
}
static Future<void> shareContent(String text, {String? subject}) async {
await Share.share(text, subject: subject);
await SharePlus.instance.share(ShareParams(text: text, subject: subject));
}
static void copyToClipboard(BuildContext context, String text) {
@@ -153,14 +153,14 @@ class StringUtils {
class NetworkUtils {
static Future<bool> isConnected() async {
final connectivityResult = await Connectivity().checkConnectivity();
return connectivityResult != ConnectivityResult.none;
return !connectivityResult.contains(ConnectivityResult.none);
}
static Future<String> getConnectionType() async {
final connectivityResult = await Connectivity().checkConnectivity();
if (connectivityResult == ConnectivityResult.wifi) {
if (connectivityResult.contains(ConnectivityResult.wifi)) {
return 'WiFi';
} else if (connectivityResult == ConnectivityResult.mobile) {
} else if (connectivityResult.contains(ConnectivityResult.mobile)) {
return 'Mobile';
} else {
return 'No Connection';

View File

@@ -63,10 +63,11 @@ class FarmShareUtil {
await file.writeAsBytes(bytes);
// 分享
await Share.shareXFiles(
[XFile(file.path)],
text:
'🌾 我在小妈菜园的收获!\n等级: Lv.$level | 收获: $totalHarvest 次 | 金币: $gold 💰',
await SharePlus.instance.share(
ShareParams(
text: '🌾 我在小妈菜园的收获!\n等级: Lv.$level | 收获: $totalHarvest 次 | 金币: $gold 💰',
files: [XFile(file.path)],
),
);
// 清理临时文件

View File

@@ -1,4 +1,4 @@
// 2026-04-09 | AppPageScaffold | 全局可复用页面骨架组件 | 统一iOS26风格页面结构
// 2026-04-09 | AppPageScaffold | 全局可复用页面骨架组件 | 统一iOS26风格页面结构
// 2026-04-09 | 初始创建,提供导航栏/加载/空态/错误/内容五种状态
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
@@ -200,7 +200,7 @@ class AppSectionHeader extends StatelessWidget {
),
),
),
if (trailing != null) trailing!,
?trailing,
],
),
);

View File

@@ -225,7 +225,7 @@ class ComparisonLayout extends StatelessWidget {
),
const SizedBox(width: DesignTokens.space2),
Text(
'添加对比项 (${itemCount}/${ComparisonController.maxSlots})',
'添加对比项 ($itemCount/${ComparisonController.maxSlots})',
style: TextStyle(
fontSize: DesignTokens.fontSm,
fontWeight: FontWeight.w500,

View File

@@ -93,13 +93,13 @@ class MiniCardDiscoverCard extends StatelessWidget {
: CachedNetworkImage(
imageUrl: recipe.fullImageUrl,
fit: BoxFit.cover,
placeholder: (_, __) => Container(
placeholder: (_, _) => Container(
color: DesignTokens.background,
child: const Center(
child: CupertinoActivityIndicator(),
),
),
errorWidget: (_, __, _) => Container(
errorWidget: (_, _, _) => Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,

View File

@@ -215,7 +215,7 @@ class GlassFadeSwitch extends StatelessWidget {
alignment: alignment,
children: <Widget>[
...previousChildren,
if (currentChild != null) currentChild,
?currentChild,
],
);
},

View File

@@ -182,8 +182,9 @@ class _RecipeCoverImageState extends State<RecipeCoverImage> {
Color _getBadgeBgColor(RecipeRating ratingData) {
if (ratingData.isExcellent) return DesignTokens.gold.withValues(alpha: 0.9);
if (ratingData.isRecommended)
if (ratingData.isRecommended) {
return DesignTokens.dynamicPrimary.withValues(alpha: 0.9);
}
return DesignTokens.orange.withValues(alpha: 0.9);
}

View File

@@ -87,8 +87,9 @@ class RecipeExportButton extends StatelessWidget {
}
if (codeUnit == 0x7F) return true;
if (codeUnit >= 0x80 && codeUnit <= 0x9F) return true;
if ((codeUnit & 0xFFFE) == 0xFFFE || (codeUnit & 0xFFFE) == 0xFFFF)
if ((codeUnit & 0xFFFE) == 0xFFFE || (codeUnit & 0xFFFE) == 0xFFFF) {
return true;
}
if (codeUnit == 0xFFFD) return true;
if (codeUnit >= 0xFDD0 && codeUnit <= 0xFDEF) return true;
if (codeUnit >= 0xE000 && codeUnit <= 0xF8FF) return true;
@@ -591,17 +592,21 @@ class RecipeExportButton extends StatelessWidget {
return;
}
final fileSize = await file.length();
debugPrint('开始分享文件: $filePath (${fileSize} bytes)');
debugPrint('开始分享文件: $filePath ($fileSize bytes)');
final xFile = XFile(filePath);
await Share.shareXFiles([xFile], text: subject ?? '来自小妈厨房的菜谱');
await SharePlus.instance.share(
ShareParams(text: subject ?? '来自小妈厨房的菜谱', files: [xFile]),
);
} on PlatformException catch (e) {
debugPrint(
'分享PlatformException: code=${e.code} msg=${e.message} details=${e.details}',
);
try {
debugPrint('尝试 fallback 纯文本分享...');
await Share.share(subject ?? '来自小妈厨房的菜谱', sharePositionOrigin: null);
await SharePlus.instance.share(
ShareParams(text: subject ?? '来自小妈厨房的菜谱'),
);
} catch (e2) {
debugPrint('fallback 分享也失败: $e2');
ToastService.show(
@@ -1502,7 +1507,7 @@ class RecipeExportButton extends StatelessWidget {
const Spacer(),
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
minimumSize: const Size(30, 30),
onPressed: () => Navigator.pop(ctx),
child: Text(
'取消',