8 Commits
Author SHA1 Message Date
Vicky e8b9a090e0 chore(release): 合并 develop 到 main
flutter-ci / test (push) Failing after 19m28s
2026-11-02 14:54:00 +08:00
Zhou Weidong c4adbd0665 chore(release): 发布 v1.0.1 客户端 UI 优化
flutter-ci / test (push) Canceled after 0s
2026-10-31 14:39:52 +08:00
Zhou Weidong 66c03ee245 chore(release): 发布 iOS 分享面板修复
flutter-ci / test (push) Canceled after 0s
# Conflicts:
#	lib/core/config/app_config.dart
2026-10-31 14:02:40 +08:00
Zhou Weidong a3ac007759 fix(config): release 构建自动使用生产环境 2026-10-31 14:00:33 +08:00
Vicky 525f58c150 chore(release): 合并 develop 到 main
flutter-ci / test (push) Canceled after 0s
2026-10-31 09:49:54 +08:00
Vicky 0a02620564 chore(release): 合并 develop 到 main
flutter-ci / test (push) Canceled after 0s
2026-10-31 00:02:59 +08:00
Vicky 78a33cd4f1 chore(release): 合并 develop 到 main
flutter-ci / test (push) Canceled after 0s
2026-10-30 22:56:52 +08:00
Vicky e8610b7aed chore(release): 生产包切换为生产环境地址
flutter-ci / test (push) Canceled after 0s
2026-10-30 17:20:48 +08:00
6 changed files with 38 additions and 35 deletions

No files matched your search

+5 -5
View File
@@ -1,5 +1,7 @@
// Author: fruit.com.cn
import 'package:flutter/foundation.dart';
import 'dev_config.dart';
import 'prod_config.dart';
@@ -9,12 +11,10 @@ import 'prod_config.dart';
/// - `dev_config.dart`:[DevConfig](本机联调)
/// - `prod_config.dart`:[ProdConfig](生产)
///
/// 切换环境只改下面这一个布尔值,不用传任何构建参数、也不做网络探测。
/// Debug 使用开发环境,Release 自动使用生产环境,不做网络探测。
abstract final class AppConfig {
/// **环境开关**:true 用开发环境,false 用生产环境。
///
/// 打生产包前必须改成 false;release 构建若仍为 true 会在启动时直接报错。
static const bool useDevConfig = true;
/// **环境开关**:Debug 使用开发环境,Release 使用生产环境。
static const bool useDevConfig = !kReleaseMode;
/// 当前选中的环境地址。
static String get baseUrl =>
@@ -12,9 +12,9 @@ const double _defaultIconSize = 32;
const double _defaultCountFont = 12;
const double _defaultIconCountGap = 2;
const double _defaultItemGap = 24;
const _tapDuration = Duration(milliseconds: 220);
const double _popScale = 1.14;
const double _cancelScale = 0.86;
const _tapDuration = Duration(milliseconds: 360);
const double _popScale = 1.34;
const double _cancelScale = 0.68;
const double _popWeight = 40;
const double _settleWeight = 60;
final _growTween = _tapTween(_popScale);
@@ -39,7 +39,7 @@ class PlayerTapGestureRegion extends StatefulWidget {
}
class _PlayerTapGestureRegionState extends State<PlayerTapGestureRegion> {
static const Duration _singleTapDelay = Duration(milliseconds: 240);
static const Duration _singleTapDelay = Duration(milliseconds: 320);
Timer? _singleTapTimer;
DateTime? _lastDownAt;
@@ -0,0 +1,18 @@
// Author: fruit.com.cn
// 应用环境选择测试。
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/config/app_config.dart';
import 'package:fruitshorts/core/config/dev_config.dart';
import 'package:fruitshorts/core/config/prod_config.dart';
void main() {
test('should_use_environment_matching_build_mode', () {
expect(AppConfig.useDevConfig, !kReleaseMode);
expect(
AppConfig.baseUrl,
kReleaseMode ? ProdConfig.baseUrl : DevConfig.baseUrl,
);
});
}
+7 -9
View File
@@ -16,10 +16,8 @@ import '../support/fake_haptics.dart';
import '../support/fake_interaction_repositories.dart';
void main() {
testWidgets('should_like_without_pausing_when_double_tap_within_240ms', (
tester,
) async {
for (final delay in [80, 160, 220]) {
testWidgets('double tap within 320ms never pauses', (tester) async {
for (final delay in [120, 250, 300]) {
final repository = FakeInteractionRepository();
final haptics = FakeHaptics();
final key = GlobalKey<_HarnessState>();
@@ -55,7 +53,7 @@ void main() {
}
});
testWidgets('should_toggle_twice_when_taps_are_260ms_apart', (tester) async {
testWidgets('taps 500ms apart toggle playback twice', (tester) async {
final key = GlobalKey<_HarnessState>();
final clock = _TestClock();
await _pumpHarness(
@@ -69,15 +67,15 @@ void main() {
await tester.tapAt(
tester.getCenter(find.byKey(const Key('home-feed-gesture'))),
);
clock.advance(const Duration(milliseconds: 260));
await tester.pump(const Duration(milliseconds: 260));
clock.advance(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
expect(key.currentState!.pauseToggles, 1);
await tester.tapAt(
tester.getCenter(find.byKey(const Key('home-feed-gesture'))),
);
clock.advance(const Duration(milliseconds: 260));
await tester.pump(const Duration(milliseconds: 260));
clock.advance(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
expect(key.currentState!.pauseToggles, 2);
});
+4 -17
View File
@@ -14,13 +14,11 @@ const _popFrame = Duration(milliseconds: 100);
const _buttonSize = 48.0;
const _compactGap = 6.0;
const _epsilon = 0.01;
const _cancelledMinimum = 0.8;
const _popMinimum = 1.03;
const _popMaximum = 1.18;
const _cancelledMaximum = 0.8;
const _popMinimum = 1.22;
const _burstKey = Key('rail-tap-burst');
const _directionFrame = Duration(milliseconds: 60);
const _directionFrames = 2;
const _motionCompletion = Duration(milliseconds: 230);
const _directionFrames = 4;
Future<void> _pumpRail(
WidgetTester tester, {
@@ -117,9 +115,7 @@ void main() {
await tester.pump(_popFrame);
expect(
_scale(tester, key),
selected
? allOf(greaterThan(_cancelledMinimum), lessThan(1))
: allOf(greaterThan(_popMinimum), lessThan(_popMaximum)),
selected ? lessThan(_cancelledMaximum) : greaterThan(_popMinimum),
);
_expectBurst(tester, key, selected);
expect(tester.getRect(_button(key)), rect);
@@ -159,15 +155,6 @@ void main() {
},
);
testWidgets('should_finish_feedback_within_230ms', (tester) async {
await _pumpRail(tester, onTap: () {});
await tester.tap(_button(_likeKey));
await tester.pump();
await tester.pump(_motionCompletion);
expect(find.byKey(_burstKey), findsNothing);
expect(_scale(tester, _likeKey), closeTo(1, _epsilon));
});
testWidgets('should_keep_callbacks_without_motion_when_reduced', (
tester,
) async {