8 Commits
Author SHA1 Message Date
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
Zhou Weidong 8ec6df2be5 merge: 修复 iOS 系统分享面板
flutter-ci / test (push) Canceled after 0s
2026-10-31 13:40:14 +08:00
Zhou Weidong 5ec4db151a fix(ios): 修复分享面板并同步互动栏布局断言 2026-10-31 13:33:13 +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
5 changed files with 77 additions and 13 deletions

No files matched your search

+48 -6
View File
@@ -386,15 +386,29 @@ final class PipShadowCoordinator: NSObject, AVPictureInPictureControllerDelegate
guard call.method == "shareText", guard call.method == "shareText",
let arguments = call.arguments as? [String: Any], let arguments = call.arguments as? [String: Any],
let text = arguments["text"] as? String, let text = arguments["text"] as? String,
!text.isEmpty, !text.isEmpty else {
let controller = self?.window?.rootViewController else {
result(FlutterError(code: "share_unavailable", message: "Share sheet is unavailable", details: nil)) result(FlutterError(code: "share_unavailable", message: "Share sheet is unavailable", details: nil))
return return
} }
let activity = UIActivityViewController(activityItems: [text], applicationActivities: nil) DispatchQueue.main.async {
activity.popoverPresentationController?.sourceView = controller.view guard let controller = self?.sharePresenter() else {
activity.completionWithItemsHandler = { _, _, _, _ in result(nil) } result(FlutterError(code: "share_unavailable", message: "Share sheet is unavailable", details: nil))
controller.present(activity, animated: true) return
}
let activity = UIActivityViewController(activityItems: [text], applicationActivities: nil)
if let popover = activity.popoverPresentationController {
popover.sourceView = controller.view
popover.sourceRect = CGRect(
x: controller.view.bounds.midX,
y: controller.view.bounds.midY,
width: 0,
height: 0
)
popover.permittedArrowDirections = []
}
activity.completionWithItemsHandler = { _, _, _, _ in result(nil) }
controller.present(activity, animated: true)
}
} }
let thumbnailChannel = FlutterMethodChannel( let thumbnailChannel = FlutterMethodChannel(
@@ -459,6 +473,34 @@ final class PipShadowCoordinator: NSObject, AVPictureInPictureControllerDelegate
} }
} }
/// 当前前台 Scene 的根控制器之上,最适合展示系统分享面板的控制器。
private func sharePresenter() -> UIViewController? {
let keyWindow = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first { $0.activationState == .foregroundActive }?
.windows.first { $0.isKeyWindow }
guard let rootController = keyWindow?.rootViewController else { return nil }
let presenter = topPresentedController(from: rootController)
guard presenter.viewIfLoaded?.window != nil else { return nil }
return presenter
}
/// 解析已展示页面、导航栈和标签页中的当前可见控制器。
private func topPresentedController(from controller: UIViewController) -> UIViewController {
if let presented = controller.presentedViewController {
return topPresentedController(from: presented)
}
if let navigation = controller as? UINavigationController,
let visible = navigation.visibleViewController {
return topPresentedController(from: visible)
}
if let tabs = controller as? UITabBarController,
let selected = tabs.selectedViewController {
return topPresentedController(from: selected)
}
return controller
}
/// iOS 画中画:影子播放器通道,与 Android 共用同一 channel 名。 /// iOS 画中画:影子播放器通道,与 Android 共用同一 channel 名。
private func registerPipChannel(_ engineBridge: FlutterImplicitEngineBridge) { private func registerPipChannel(_ engineBridge: FlutterImplicitEngineBridge) {
let channel = FlutterMethodChannel( let channel = FlutterMethodChannel(
+5 -5
View File
@@ -1,5 +1,7 @@
// Author: fruit.com.cn // Author: fruit.com.cn
import 'package:flutter/foundation.dart';
import 'dev_config.dart'; import 'dev_config.dart';
import 'prod_config.dart'; import 'prod_config.dart';
@@ -9,12 +11,10 @@ import 'prod_config.dart';
/// - `dev_config.dart`:[DevConfig](本机联调) /// - `dev_config.dart`:[DevConfig](本机联调)
/// - `prod_config.dart`:[ProdConfig](生产) /// - `prod_config.dart`:[ProdConfig](生产)
/// ///
/// 切换环境只改下面这一个布尔值,不用传任何构建参数、也不做网络探测。 /// Debug 使用开发环境,Release 自动使用生产环境,不做网络探测。
abstract final class AppConfig { abstract final class AppConfig {
/// **环境开关**:true 用开发环境,false 用生产环境。 /// **环境开关**:Debug 使用开发环境,Release 使用生产环境。
/// static const bool useDevConfig = !kReleaseMode;
/// 打生产包前必须改成 false;release 构建若仍为 true 会在启动时直接报错。
static const bool useDevConfig = true;
/// 当前选中的环境地址。 /// 当前选中的环境地址。
static String get baseUrl => static String get baseUrl =>
@@ -27,6 +27,7 @@ const double _progressHeight = 2;
const double _progressHitHeight = 16; const double _progressHitHeight = 16;
const double _pageHorizontal = 20; const double _pageHorizontal = 20;
const double _railRight = 14; const double _railRight = 14;
const double _railShiftRight = 8;
const double _railGap = 12; const double _railGap = 12;
const double _railWidth = 56; const double _railWidth = 56;
const double _infoWatchAllGap = 2; const double _infoWatchAllGap = 2;
@@ -234,7 +235,10 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
bottom: _railBottomOffset, bottom: _railBottomOffset,
), ),
child: _rail(), child: Transform.translate(
offset: const Offset(_railShiftRight, 0),
child: _rail(),
),
), ),
), ),
], ],
@@ -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,
);
});
}
+1 -1
View File
@@ -373,7 +373,7 @@ void main() {
expect( expect(
tester.getRect(find.byKey(const Key('home-feed-action-rail'))).right, tester.getRect(find.byKey(const Key('home-feed-action-rail'))).right,
closeTo( closeTo(
tester.getRect(find.byKey(const Key('home-feed-gesture'))).right - 14, tester.getRect(find.byKey(const Key('home-feed-gesture'))).right - 6,
0.1, 0.1,
), ),
); );