Commit 8c7326afc7a83bad58d3d7e57231cada6daf725e

Authored by 权海
1 parent 2bf8d2c5

feat(ui):完善watch主题

... ... @@ -3,9 +3,7 @@ import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
import 'package:doublefeel_flutter/core/network/api/health_api.dart';
import 'package:doublefeel_flutter/core/network/api/pay_api.dart';
import 'package:doublefeel_flutter/core/network/api/vip_api.dart';
import 'package:doublefeel_flutter/core/services/health_kit_upload_service.dart';
import 'package:doublefeel_flutter/core/services/user_state_service.dart';
import 'package:doublefeel_flutter/app/apple_health_upload/apple_health_upload_tool.dart';
import 'package:doublefeel_flutter/data/models/friend/friend_models.dart';
import 'package:get/get.dart';
... ... @@ -20,8 +18,6 @@ class FriendHomeBinding extends Bindings {
Get.find<HealthApi>(),
Get.find<FriendApi>(),
Get.find<UserStateService>(),
Get.find<HealthKitUploadService>(),
Get.find<AppleHealthUploadTool>(),
friendInfo: args,
),
tag: 'friend_${args.friendUserId}', // 动态 tag,支持多个好友同时在路由栈中
... ...
... ... @@ -12,6 +12,7 @@ import 'package:doublefeel_flutter/core/util/app_toast.dart';
import 'package:doublefeel_flutter/data/models/health/health_v2_models.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart';
import 'package:get/get.dart';
import '../data/friends_repository.dart';
... ... @@ -28,7 +29,7 @@ class FriendsController extends GetxController {
_selfHealthRepository = selfHealthRepository ??
SelfHealthRepositoryImpl(Get.find<HealthApi>()),
_updateWatchOtherUserInfo = updateWatchOtherUserInfo ??
((info) => PlatformHostApi().refreshWatchAppAndWidgets());
((info) => WearEngineHostApi().sendWatchSyncPayload(''));
static const maxFriends = 10;
... ...
... ... @@ -42,6 +42,10 @@ class SelectFriendLogic {
if (index < 0 || index >= friends.length) return null;
final selectedFriend = friends[index];
if (selectedFriend.isOnWatchFace) {
return null;
}
final userId = selectedFriend.userId;
if (userId == null) return null;
... ...
... ... @@ -95,7 +95,7 @@ class _SelectFriendViewState extends State<SelectFriendView> {
Future<void> _syncSelectedFriend() async {
final selectedFriend = await _logic.syncSelectedFriendToWatchFace();
if (selectedFriend != null) Get.back(result: selectedFriend);
Get.back(result: selectedFriend);
}
}
... ...
... ... @@ -26,8 +26,6 @@ class HomeBinding extends Bindings {
Get.find<HealthApi>(),
Get.find<FriendApi>(),
Get.find<UserStateService>(),
Get.find<HealthKitUploadService>(),
Get.find<AppleHealthUploadTool>(),
),
fenix: true,
);
... ...
import 'dart:async';
import 'dart:math';
import 'package:doublefeel_flutter/app/apple_health_upload/apple_health_upload_tool.dart';
import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_controller.dart';
import 'package:doublefeel_flutter/app/modules/home/controllers/home_controller.dart';
import 'package:doublefeel_flutter/app/modules/home/controllers/trend/trend_controller.dart';
... ... @@ -14,7 +13,6 @@ import 'package:doublefeel_flutter/core/network/api/health_api.dart';
import 'package:doublefeel_flutter/core/network/api/pay_api.dart';
import 'package:doublefeel_flutter/core/network/api/vip_api.dart';
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/core/services/health_kit_upload_service.dart';
import 'package:doublefeel_flutter/core/services/user_state_service.dart';
import 'package:doublefeel_flutter/core/util/app_toast.dart';
import 'package:doublefeel_flutter/data/local/user_account_storage.dart';
... ... @@ -59,9 +57,7 @@ class TodayController extends GetMaterialController {
this._vipApi,
this._healthApi,
this._friendApi,
this._userStateService,
this._healthKitUploadService,
this._appleHealthUploadTool, {
this._userStateService, {
FriendItem? friendInfo, // null = 自己,非 null = 好友
}) : _initialFriendInfo = friendInfo;
... ... @@ -70,8 +66,6 @@ class TodayController extends GetMaterialController {
final HealthApi _healthApi;
final FriendApi _friendApi;
final UserStateService _userStateService;
final HealthKitUploadService _healthKitUploadService;
final AppleHealthUploadTool _appleHealthUploadTool;
final HealthKitHostApi _hostApi = HealthKitHostApi();
/// 好友的信息;null 表示查看自己的数据,非 null 表示查看好友的数据。
... ... @@ -265,7 +259,7 @@ class TodayController extends GetMaterialController {
Future<void> _performDataUpload() async {
try {
final result =
await _appleHealthUploadTool.uploadAllNewDataFromHealthKit();
await _hostApi.performHealthUpload();
// AppLogger.i(
// 'Apple Health upload finished: '
// 'common=${result.commonUploadSuccess}(${result.commonCount}), '
... ...
... ... @@ -54,7 +54,7 @@ class MyTab extends GetView<MyController> {
: _UnlockPremiumCard(controller),
const SizedBox(height: 12),
_WatchThemeCard(
themes: controller.officialWatchThemes,
themes: controller.watchThemeItems,
isLoading: controller.isLoadingWatchThemes.value,
onTap: () => controller.goWatchThemePage(),
),
... ...
... ... @@ -213,6 +213,7 @@ class CreateWatchThemeController extends GetxController {
),
barrierDismissible: true,
);
Get.back();
if (abandon == true) {
Get.back();
}
... ... @@ -259,7 +260,7 @@ class CreateWatchThemeController extends GetxController {
}
final createdTheme = await _loadCreatedTheme();
await Get.toNamed(
await Get.offAndToNamed(
Routes.WATCH_THEME_CUSTOM_PREVIEW,
arguments: {
'theme': createdTheme ?? _buildThemeItem(uploadedImageUrls),
... ...
... ... @@ -4,10 +4,13 @@ import 'dart:convert';
import 'package:doublefeel_flutter/core/network/api/theme_api.dart';
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/core/util/app_toast.dart';
import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../friends/models/friend_health_data.dart';
import '../../friends/views/select_friend_view.dart';
import '../models/watch_theme_models.dart';
import '../widgets/watch_theme_dialogs.dart';
import '../widgets/watch_theme_no_watch_dialog.dart';
... ... @@ -108,8 +111,25 @@ class CustomWatchThemePreviewController extends GetxController {
}
}
void changeFriend() {
//TODO: - bottomSheet 的方式展示出 SelectFriendView
Future<void> changeFriend() async {
final selectedFriend = await Get.bottomSheet<FriendHealthData>(
SizedBox(
height: Get.height * 0.9,
child: const SelectFriendView(),
),
ignoreSafeArea: false,
isScrollControlled: true,
backgroundColor: Colors.transparent,
barrierColor: const Color(0xB3000000),
);
if (selectedFriend == null) return;
await loadFriendTheme();
try {
await WearEngineHostApi().sendWatchSyncPayload('');
} catch (_) {
// The selected friend is saved on the server; native refresh can retry.
}
}
Future<void> addWatchFace() async {
... ... @@ -120,20 +140,20 @@ class CustomWatchThemePreviewController extends GetxController {
device = null;
}
if (device == null) {
await Get.dialog<void>(
await Get.bottomSheet<void>(
const WatchThemeNoWatchDialog(),
barrierDismissible: true,
backgroundColor: Colors.transparent,
barrierColor: const Color(0xB3000000),
);
return;
}
await Get.dialog<void>(
await Get.bottomSheet<void>(
WatchThemeSyncDialog(
themeImageUrl: themeItem.energeticImage,
onSync: applyAndSyncWatchFace,
),
barrierDismissible: false,
backgroundColor: Colors.transparent,
barrierColor: const Color(0xB3000000),
);
}
... ...
... ... @@ -4,10 +4,13 @@ import 'dart:convert';
import 'package:doublefeel_flutter/core/network/api/theme_api.dart';
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/core/util/app_toast.dart';
import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../friends/models/friend_health_data.dart';
import '../../friends/views/select_friend_view.dart';
import '../models/watch_theme_models.dart';
import '../widgets/watch_theme_no_watch_dialog.dart';
import '../widgets/watch_theme_sync_dialog.dart';
... ... @@ -86,26 +89,43 @@ class WatchThemePreviewController extends GetxController {
device = null;
}
if (device == null) {
await Get.dialog<void>(
await Get.bottomSheet<void>(
const WatchThemeNoWatchDialog(),
barrierDismissible: true,
backgroundColor: Colors.transparent,
barrierColor: const Color(0xB3000000),
);
return;
}
await Get.dialog<void>(
await Get.bottomSheet<void>(
WatchThemeSyncDialog(
themeImageUrl: themeItem.energeticImage,
onSync: applyAndSyncWatchFace,
),
barrierDismissible: false,
backgroundColor: Colors.transparent,
barrierColor: const Color(0xB3000000),
);
}
void changeFriend() {
//TODO: - bottomSheet 的方式展示出 SelectFriendView
Future<void> changeFriend() async {
final selectedFriend = await Get.bottomSheet<FriendHealthData>(
SizedBox(
height: Get.height * 0.9,
child: const SelectFriendView(),
),
ignoreSafeArea: false,
isScrollControlled: true,
backgroundColor: Colors.transparent,
barrierColor: const Color(0xB3000000),
);
if (selectedFriend == null) return;
await loadFriendTheme();
try {
await WearEngineHostApi().sendWatchSyncPayload('');
} catch (_) {
// The selected friend is saved on the server; native refresh can retry.
}
}
Future<bool> applyAndSyncWatchFace() async {
... ...
... ... @@ -124,7 +124,7 @@ class _EditorCard extends StatelessWidget {
),
SizedBox(height: 4),
Text(
'支持上传图片、视频、Live图、Gif、最长5秒',
'仅支持上传图片',
style: TextStyle(
color: WatchThemeColors.textSecondary,
fontSize: 12,
... ...
... ... @@ -63,9 +63,9 @@ class CustomWatchThemePreviewView
style: TextStyle(
color: const Color(0xFFFC4447),
fontSize: 14,
fontWeight: FontWeight.w500,
fontWeight: FontWeight.w600,
),
),
).paddingOnly(left: 4, right: 4, top: 4, bottom: 4),
),
),
Expanded(
... ... @@ -88,6 +88,7 @@ class CustomWatchThemePreviewView
controller.themeItem.energeticImage,
themeImageUrl2:
controller.friendThemeItem.value?.normalImage,
switchFriend: controller.changeFriend,
);
}),
],
... ...
... ... @@ -73,6 +73,7 @@ class WatchThemePreviewView extends GetView<WatchThemePreviewController> {
controller.themeItem.energeticImage,
themeImageUrl2: controller
.friendThemeItem.value?.normalImage,
switchFriend: controller.changeFriend,
);
},
),
... ...
import 'package:flutter/material.dart';
import 'package:get/utils.dart';
import '../models/watch_theme_models.dart';
import 'watch_theme_character_avatar.dart';
... ... @@ -47,24 +48,30 @@ class CustomThemeCard extends StatelessWidget {
),
SizedBox(height: 14),
_CreateThemeButton(onTap: onCreateTap),
if (customThemes.isEmpty) ...[
SizedBox(height: 12),
Row(
children: [
for (var index = 0; index < customThemes.length; index++) ...[
_CustomThemeItem(
customThemes.isEmpty
? SizedBox(height: 0)
: SizedBox(
height: 112,
child: ListView.separated(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.zero,
itemBuilder: (context, index) {
return _CustomThemeItem(
item: customThemes[index],
selected: customThemes[index].id != null &&
customThemes[index].id == activeThemeId,
onTap: onThemeTap == null
? null
: () => onThemeTap!(customThemes[index]),
),
if (index != customThemes.length - 1) SizedBox(width: 20),
],
],
),
],
);
},
separatorBuilder: (context, index) {
return SizedBox(
width: 20,
);
},
itemCount: customThemes.length),
).paddingOnly(top: 12),
],
),
);
... ...
... ... @@ -9,11 +9,13 @@ class DialPreviewCard extends StatelessWidget {
bool showFriend;
final String? themeImageUrl;
final String? themeImageUrl2;
final Function()? switchFriend;
DialPreviewCard(
{super.key,
required this.showFriend,
this.themeImageUrl,
this.themeImageUrl2});
this.themeImageUrl2,
this.switchFriend});
@override
Widget build(BuildContext context) {
... ... @@ -41,6 +43,7 @@ class DialPreviewCard extends StatelessWidget {
type: WatchFacePreviewType.coupleSmall,
themeImageUrl: themeImageUrl,
themeImageUrl2: themeImageUrl2,
switchFriend: switchFriend,
);
}
return WatchFacePreview(
... ...