merge: 将 develop 同步到 release/v1.0.0
This commit is contained in:
commit
182b7e3ac2
5 files changed
+105
-65
No files matched your search
@@ -11,11 +11,10 @@ import 'package:flutter/foundation.dart';
|
|||||||
class AppConfig {
|
class AppConfig {
|
||||||
const AppConfig._();
|
const AppConfig._();
|
||||||
|
|
||||||
/// 真机默认使用的开发机局域网地址。
|
/// 开发调试默认服务地址,当前直接指向公网。
|
||||||
///
|
///
|
||||||
/// 这个地址跟着电脑所在的网络走,换网络后要用
|
/// 需要切换局域网联调时只改这一行,地址不要带结尾斜杠。
|
||||||
/// `ipconfig getifaddr en0` 重新确认。默认值只改这一行。
|
static const String devHostBaseUrl = 'http://39.162.50.99:8081';
|
||||||
static const String devHostBaseUrl = 'http://192.168.31.187:8081';
|
|
||||||
|
|
||||||
/// 本机后端地址:通过 `adb reverse tcp:8081 tcp:8081` 映射到开发机,
|
/// 本机后端地址:通过 `adb reverse tcp:8081 tcp:8081` 映射到开发机,
|
||||||
/// 探测可达时 App 直连本机服务;不可达时回落到公网地址。
|
/// 探测可达时 App 直连本机服务;不可达时回落到公网地址。
|
||||||
@@ -38,7 +37,7 @@ class AppConfig {
|
|||||||
static const List<String> _probeCandidates = [
|
static const List<String> _probeCandidates = [
|
||||||
lanBaseUrl,
|
lanBaseUrl,
|
||||||
devHostBaseUrl,
|
devHostBaseUrl,
|
||||||
publicBaseUrl,
|
if (devHostBaseUrl != publicBaseUrl) publicBaseUrl,
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Build-time server URL supplied through `--dart-define=API_BASE_URL`.
|
/// Build-time server URL supplied through `--dart-define=API_BASE_URL`.
|
||||||
|
|||||||
@@ -43,37 +43,35 @@ class AppBottomNav extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final bar = Container(
|
||||||
|
key: barKey,
|
||||||
|
height: AppDimens.navHeight,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: dark ? Colors.black : backgroundColor.withValues(alpha: 0.95),
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(color: dark ? Colors.white12 : AppColors.border),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
for (final item in items)
|
||||||
|
_NavDestination(
|
||||||
|
item: item,
|
||||||
|
unselectedColor: dark ? Colors.white70 : AppColors.navUnselected,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (dark) {
|
||||||
|
return ColoredBox(
|
||||||
|
color: Colors.black,
|
||||||
|
child: SafeArea(top: false, child: bar),
|
||||||
|
);
|
||||||
|
}
|
||||||
return ClipRect(
|
return ClipRect(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
|
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
|
||||||
child: SafeArea(
|
child: SafeArea(top: false, child: bar),
|
||||||
top: false,
|
|
||||||
child: Container(
|
|
||||||
key: barKey,
|
|
||||||
height: AppDimens.navHeight,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: dark
|
|
||||||
? const Color(0xE6000000)
|
|
||||||
: backgroundColor.withValues(alpha: 0.95),
|
|
||||||
border: Border(
|
|
||||||
top: BorderSide(
|
|
||||||
color: dark ? Colors.white12 : AppColors.border,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
for (final item in items)
|
|
||||||
_NavDestination(
|
|
||||||
item: item,
|
|
||||||
unselectedColor: dark
|
|
||||||
? Colors.white70
|
|
||||||
: AppColors.navUnselected,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should_use_the_configured_lan_address_for_device_default', () {
|
test('should_use_the_configured_public_address_for_device_default', () {
|
||||||
expect(AppConfig.devHostBaseUrl, 'http://192.168.31.187:8081');
|
expect(AppConfig.devHostBaseUrl, 'http://39.162.50.99:8081');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should_skip_probe_when_compiled_override_is_set', () async {
|
test('should_skip_probe_when_compiled_override_is_set', () async {
|
||||||
@@ -111,11 +111,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(attempts, [
|
expect(attempts, [AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl]);
|
||||||
AppConfig.lanBaseUrl,
|
|
||||||
AppConfig.devHostBaseUrl,
|
|
||||||
AppConfig.publicBaseUrl,
|
|
||||||
]);
|
|
||||||
expect(AppConfig.apiBaseUrl, AppConfig.publicBaseUrl);
|
expect(AppConfig.apiBaseUrl, AppConfig.publicBaseUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -133,7 +129,7 @@ void main() {
|
|||||||
attempts.add(baseUrl);
|
attempts.add(baseUrl);
|
||||||
active++;
|
active++;
|
||||||
if (active > maxActive) maxActive = active;
|
if (active > maxActive) maxActive = active;
|
||||||
if (active == 3) allStarted.complete();
|
if (active == 2) allStarted.complete();
|
||||||
await allStarted.future;
|
await allStarted.future;
|
||||||
active--;
|
active--;
|
||||||
return baseUrl == AppConfig.lanBaseUrl ||
|
return baseUrl == AppConfig.lanBaseUrl ||
|
||||||
@@ -143,17 +139,13 @@ void main() {
|
|||||||
|
|
||||||
await probing.timeout(const Duration(seconds: 1));
|
await probing.timeout(const Duration(seconds: 1));
|
||||||
|
|
||||||
expect(attempts, [
|
expect(attempts, [AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl]);
|
||||||
AppConfig.lanBaseUrl,
|
expect(maxActive, 2);
|
||||||
AppConfig.devHostBaseUrl,
|
|
||||||
AppConfig.publicBaseUrl,
|
|
||||||
]);
|
|
||||||
expect(maxActive, 3);
|
|
||||||
expect(AppConfig.apiBaseUrl, AppConfig.lanBaseUrl);
|
expect(AppConfig.apiBaseUrl, AppConfig.lanBaseUrl);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
test('should_probe_loopback_dev_host_then_public_in_order', () async {
|
test('should_probe_loopback_then_public_in_order', () async {
|
||||||
final attempts = <String>[];
|
final attempts = <String>[];
|
||||||
|
|
||||||
await AppConfig.probeAndApplyBaseUrl(
|
await AppConfig.probeAndApplyBaseUrl(
|
||||||
@@ -164,11 +156,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(attempts, [
|
expect(attempts, [AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl]);
|
||||||
AppConfig.lanBaseUrl,
|
|
||||||
AppConfig.devHostBaseUrl,
|
|
||||||
AppConfig.publicBaseUrl,
|
|
||||||
]);
|
|
||||||
expect(AppConfig.apiBaseUrl, AppConfig.publicBaseUrl);
|
expect(AppConfig.apiBaseUrl, AppConfig.publicBaseUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -183,11 +171,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(attempts, [
|
expect(attempts, [AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl]);
|
||||||
AppConfig.lanBaseUrl,
|
|
||||||
AppConfig.devHostBaseUrl,
|
|
||||||
AppConfig.publicBaseUrl,
|
|
||||||
]);
|
|
||||||
expect(AppConfig.apiBaseUrl, AppConfig.devHostBaseUrl);
|
expect(AppConfig.apiBaseUrl, AppConfig.devHostBaseUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -203,12 +187,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(attempts, [
|
expect(attempts, [custom, AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl]);
|
||||||
custom,
|
|
||||||
AppConfig.lanBaseUrl,
|
|
||||||
AppConfig.devHostBaseUrl,
|
|
||||||
AppConfig.publicBaseUrl,
|
|
||||||
]);
|
|
||||||
expect(AppConfig.apiBaseUrl, custom);
|
expect(AppConfig.apiBaseUrl, custom);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -82,4 +82,68 @@ void main() {
|
|||||||
await tester.tap(find.byKey(const Key('tab-theater')));
|
await tester.tap(find.byKey(const Key('tab-theater')));
|
||||||
expect(theaterTaps, 1);
|
expect(theaterTaps, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('should_fill_dark_bottom_safe_area_with_black_background', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
const barKey = Key('dark-nav-bar');
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: MediaQuery(
|
||||||
|
data: const MediaQueryData(padding: EdgeInsets.only(bottom: 34)),
|
||||||
|
child: Scaffold(
|
||||||
|
bottomNavigationBar: AppBottomNav(
|
||||||
|
dark: true,
|
||||||
|
barKey: barKey,
|
||||||
|
items: [
|
||||||
|
AppBottomNavItem(
|
||||||
|
tabKey: const Key('tab-home'),
|
||||||
|
icon: Icons.movie_outlined,
|
||||||
|
selectedIcon: Icons.movie_rounded,
|
||||||
|
label: 'Home',
|
||||||
|
selected: true,
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
AppBottomNavItem(
|
||||||
|
tabKey: const Key('tab-theater'),
|
||||||
|
icon: Icons.explore_outlined,
|
||||||
|
selectedIcon: Icons.explore_rounded,
|
||||||
|
label: 'Theater',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
AppBottomNavItem(
|
||||||
|
tabKey: const Key('tab-create'),
|
||||||
|
icon: Icons.add_box_outlined,
|
||||||
|
selectedIcon: Icons.add_box_rounded,
|
||||||
|
label: 'Create',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
AppBottomNavItem(
|
||||||
|
tabKey: const Key('tab-mine'),
|
||||||
|
icon: Icons.person_outline_rounded,
|
||||||
|
selectedIcon: Icons.person_rounded,
|
||||||
|
label: 'Me',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tester.getSize(find.byType(AppBottomNav)).height,
|
||||||
|
AppDimens.navHeight + 34,
|
||||||
|
);
|
||||||
|
expect(tester.getSize(find.byKey(barKey)).height, AppDimens.navHeight);
|
||||||
|
|
||||||
|
final coloredBox = tester.widget<ColoredBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(AppBottomNav),
|
||||||
|
matching: find.byType(ColoredBox),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(coloredBox.color, Colors.black);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ void main() {
|
|||||||
final decoration = bar.decoration as BoxDecoration;
|
final decoration = bar.decoration as BoxDecoration;
|
||||||
final border = decoration.border as Border;
|
final border = decoration.border as Border;
|
||||||
// 首页 feed 用深色导航。
|
// 首页 feed 用深色导航。
|
||||||
expect(decoration.color, const Color(0xE6000000));
|
expect(decoration.color, Colors.black);
|
||||||
expect(border.top.color, Colors.white12);
|
expect(border.top.color, Colors.white12);
|
||||||
expect(
|
expect(
|
||||||
tester
|
tester
|
||||||
|
|||||||
Reference in new issue
Block a user