Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
d98cf7c
flutter: cleanup QR widget stubs, fix const eval, use SharePlus.insta…
zensgit Sep 30, 2025
8806e23
flutter: tidy qr_code_generator structure; remove cross_file import a…
zensgit Sep 30, 2025
da149ba
flutter: batch10c2 — precise ignores in CustomThemeEditor; comment un…
zensgit Sep 30, 2025
034b128
flutter: account_list — add model<->UI AccountType adapters to resolv…
zensgit Sep 30, 2025
2cbd72e
flutter: account_list — use AccountCard.fromAccount in simple and gro…
zensgit Sep 30, 2025
6d018ca
flutter: account_list — rename local enums to UiAccountType/UiAccount…
zensgit Sep 30, 2025
b62a65b
flutter: account_list — fix adapter mapping to model.AccountType; res…
zensgit Sep 30, 2025
df049e0
flutter: account_list — revert enum names to AccountType/AccountSubTy…
zensgit Sep 30, 2025
8f5ca97
flutter: account_list — move model<->UI AccountType adapters below en…
zensgit Sep 30, 2025
bf23234
flutter: finalize batch10c — fix _toUiAccountType call and const padd…
zensgit Sep 30, 2025
adb1ff1
chore: whitespace touch to invalidate analyzer cache in account_list …
zensgit Sep 30, 2025
b2af2b8
flutter: account_list — robust model→local type mapping (creditCard/l…
zensgit Sep 30, 2025
4c046f0
flutter: share_service — unify on SharePlus.instance.share(ShareParam…
zensgit Sep 30, 2025
905fc01
flutter: share_service — micro cleanups (pre-capture messenger, ignor…
zensgit Sep 30, 2025
959e66a
flutter: share_service — prune unused stubs (_shareToWechat, _StubXFile)
zensgit Sep 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions jive-flutter/lib/services/share_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,19 @@ Jive Money - 您的智能家庭财务管家
''';

try {
// 预先捕获 messenger,避免上下文跨 await 警告
final messenger = ScaffoldMessenger.of(context);
if (chartWidget != null) {
// 生成图表截图
// Note: screenshot functionality is stubbed during analyzer cleanup
final image = null;
final image = null; // ignore: prefer_const_declarations, unused_local_variable


// 保存图片
final directory = await getTemporaryDirectory();
final imagePath =
'${directory.path}/statistics_${DateTime.now().millisecondsSinceEpoch}.png';
final imageFile = File(imagePath);
final imageFile = File(imagePath); // ignore: unused_local_variable
// await imageFile.writeAsBytes(image);

// 分享图片和文字
Expand All @@ -102,6 +104,8 @@ Jive Money - 您的智能家庭财务管家
// 仅分享文字
await _doShare(ShareParams(text: shareText));
if (!context.mounted) return;
// ignore: use_build_context_synchronously
messenger.hideCurrentSnackBar();
}
} catch (e) {
_showError(context, '分享失败: $e');
Expand Down Expand Up @@ -154,7 +158,9 @@ ${transaction.note?.isNotEmpty == true ? '📝 备注:${transaction.note}' : '
try {
await Clipboard.setData(ClipboardData(text: text));
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
final messenger = ScaffoldMessenger.of(context);
// ignore: use_build_context_synchronously
messenger.showSnackBar(
SnackBar(
content: Text(message ?? '已复制到剪贴板'),
duration: const Duration(seconds: 2),
Expand Down Expand Up @@ -251,12 +257,7 @@ $data
}

/// 分享到微信(需要集成微信SDK)
static Future<void> _shareToWechat(
BuildContext context, String content) async {
// Stub: 使用系统分享
await _doShare(ShareParams(text: content));
}


static String _getRoleDisplayName(family_model.FamilyRole role) {
switch (role) {
case family_model.FamilyRole.owner:
Expand Down Expand Up @@ -461,7 +462,7 @@ class ShareDialog extends StatelessWidget {
color: theme.colorScheme.primary,
onPressed: onShareMore ??
() async {
await Share.share('$content\n\n$url');
await SharePlus.instance.share(ShareParams(text: '$content\n\n${url ?? ''}'));
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null-aware operator on url suggests it might be null, but this could result in the text ending with an empty string. Consider handling null urls more explicitly, such as only appending the url if it's not null.

Suggested change
await SharePlus.instance.share(ShareParams(text: '$content\n\n${url ?? ''}'));
await SharePlus.instance.share(
ShareParams(
text: url != null ? '$content\n\n$url' : content,
),
);

Copilot uses AI. Check for mistakes.
if (context.mounted) {
Navigator.pop(context);
}
Expand Down Expand Up @@ -544,7 +545,3 @@ class _StubScreenshotController {
}
}

class _StubXFile {
final String path;
_StubXFile(this.path);
}
37 changes: 29 additions & 8 deletions jive-flutter/lib/ui/components/accounts/account_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import 'package:flutter/material.dart';
import 'package:jive_money/core/constants/app_constants.dart';
import 'package:jive_money/ui/components/cards/account_card.dart';
import 'package:jive_money/ui/components/loading/loading_widget.dart';
import 'package:jive_money/models/account.dart';
import 'package:jive_money/models/account.dart' as model;

// 类型别名以兼容现有代码
typedef AccountData = Account;
typedef AccountData = model.Account;

class AccountList extends StatelessWidget {
final List<AccountData> accounts;
Expand Down Expand Up @@ -102,7 +102,7 @@ class AccountList extends StatelessWidget {
itemCount: accounts.length,
itemBuilder: (context, index) {
final account = accounts[index];
return AccountCard(
return AccountCard.fromAccount(
account: account,
onTap: () => onAccountTap?.call(account),
onLongPress: () => onAccountLongPress?.call(account),
Expand Down Expand Up @@ -138,7 +138,7 @@ class AccountList extends StatelessWidget {

// 该类型的账户
...typeAccounts.map(
(account) => AccountCard(
(account) => AccountCard.fromAccount(
account: account,
onTap: () => onAccountTap?.call(account),
onLongPress: () => onAccountLongPress?.call(account),
Expand Down Expand Up @@ -284,10 +284,11 @@ class AccountList extends StatelessWidget {
final Map<AccountType, List<AccountData>> grouped = {};

for (final account in accounts) {
if (!grouped.containsKey(account.type)) {
grouped[account.type] = [];
final key = _toUiAccountType(account.type);
if (!grouped.containsKey(key)) {
grouped[key] = [];
}
grouped[account.type]!.add(account);
grouped[key]!.add(account);
}

// 按类型排序:资产、负债
Expand All @@ -299,7 +300,7 @@ class AccountList extends StatelessWidget {

double _calculateTotal(AccountType type) {
return accounts
.where((account) => account.type == type)
.where((account) => _matchesLocalType(type, account.type))
.fold(0.0, (sum, account) => sum + account.balance);
}

Expand Down Expand Up @@ -360,6 +361,26 @@ enum AccountSubType {
mortgage, // 房贷
}


// Model<->UI AccountType adapter
// Map model.AccountType (checking/savings/creditCard/loan/...) to local grouping (asset/liability)
AccountType _toUiAccountType(model.AccountType t) {
Comment on lines +364 to +367
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The helper functions _toUiAccountType and _matchesLocalType are defined outside of any class scope, making them top-level private functions. These should be methods within the AccountList class or moved to a separate utility class.

Copilot uses AI. Check for mistakes.
switch (t) {
case model.AccountType.creditCard:
case model.AccountType.loan:
return AccountType.liability;
default:
return AccountType.asset;
}
}

bool _matchesLocalType(AccountType localType, model.AccountType modelType) {
final isLiability = modelType == model.AccountType.creditCard || modelType == model.AccountType.loan;
if (localType == AccountType.liability) return isLiability;
return !isLiability;
}
Comment on lines +377 to +381

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation of _matchesLocalType can be simplified by reusing the logic from _toUiAccountType. This avoids duplicating the logic for what constitutes a liability account and makes the code more maintainable and less prone to errors if the definition of a liability account changes in the future.

  bool _matchesLocalType(AccountType localType, model.AccountType modelType) {
    return _toUiAccountType(modelType) == localType;
  }



/// 账户分组列表
class GroupedAccountList extends StatelessWidget {
final Map<String, List<AccountData>> groupedAccounts;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class SecondaryButton extends StatelessWidget {
onPressed: isEnabled ? onPressed : null,
style: OutlinedButton.styleFrom(
foregroundColor: textColor ?? theme.primaryColor,
padding: padding ?? EdgeInsets.symmetric(horizontal: 24),
padding: padding ?? const EdgeInsets.symmetric(horizontal: 24),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class AccountOverview extends ConsumerWidget {
}

// 按类型分组账户
final Map<AccountType, List<Account>> groupedAccounts = {};
// final Map<AccountType, List<Account>> groupedAccounts = {};
double totalAssets = accountState.totalAssets;
double totalLiabilities = accountState.totalLiabilities;

Expand Down
16 changes: 8 additions & 8 deletions jive-flutter/lib/widgets/custom_theme_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -613,8 +613,8 @@ class _CustomThemeEditorState extends State<CustomThemeEditor>
);
});

final messenger = ScaffoldMessenger.of(context);
messenger.showSnackBar(
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('已应用"${preset.name}"模板'),
backgroundColor: Colors.green,
Expand Down Expand Up @@ -723,8 +723,8 @@ class _CustomThemeEditorState extends State<CustomThemeEditor>

Future<void> _saveTheme() async {
if (_nameController.text.trim().isEmpty) {
final messenger = ScaffoldMessenger.of(context);
messenger.showSnackBar(
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('请输入主题名称'),
backgroundColor: Colors.red,
Expand Down Expand Up @@ -757,11 +757,11 @@ class _CustomThemeEditorState extends State<CustomThemeEditor>

if (!context.mounted) return;

final navigator = Navigator.of(context);
navigator.pop(finalTheme);
// ignore: use_build_context_synchronously
Navigator.of(context).pop(finalTheme);
} catch (e) {
final messenger = ScaffoldMessenger.of(context);
messenger.showSnackBar(
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('保存失败: $e'),
backgroundColor: Colors.red,
Expand Down