feat(mobile-next): 导入官方 openim-flutter-demo 固定基线 3.8.3-patch.3 并完成双构建
- 上游: github.com/OpenIMSDK/openim-flutter-demo tag 3.8.3-patch.3 commit b3dfdb1e8aaeaaf6f0793e10cadd20d5c184a31f - 并行目录 mobile-next/ 原样导入(含 LICENSE),不覆盖现网 mobile/ - 锁定 Flutter 3.24.5 / Dart 3.5.4 / JDK 17 / Gradle 7.6.3 / AGP 7.3.1 - 实测 Android debug 与 release 构建均成功(见 docs/mobile-next-baseline-import.md) - 本提交可单独回退:git revert 1db1229(重写前) Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:focus_detector_v2/focus_detector_v2.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
import '../core/controller/app_controller.dart';
|
||||
|
||||
class AppView extends StatelessWidget {
|
||||
const AppView({Key? key, required this.builder}) : super(key: key);
|
||||
final Widget Function(Locale? locale, TransitionBuilder builder) builder;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<AppController>(
|
||||
init: AppController(),
|
||||
builder: (ctrl) => FocusDetector(
|
||||
onForegroundGained: () => ctrl.runningBackground(false),
|
||||
onForegroundLost: () => ctrl.runningBackground(true),
|
||||
child: ScreenUtilInit(
|
||||
designSize: const Size(Config.uiW, Config.uiH),
|
||||
minTextAdapt: true,
|
||||
splitScreenMode: true,
|
||||
fontSizeResolver: (fontSize, _) => fontSize.toDouble(),
|
||||
builder: (_, child) => builder(ctrl.getLocale(), _builder()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static TransitionBuilder _builder() {
|
||||
final builder = EasyLoading.init(
|
||||
builder: (context, widget) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaleFactor: Config.textScaleFactor,
|
||||
),
|
||||
child: widget!,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
EasyLoading.instance
|
||||
..userInteractions = false
|
||||
..indicatorSize = 50
|
||||
..backgroundColor = Styles.c_0C1C33
|
||||
..indicatorColor = CupertinoColors.systemGrey2
|
||||
..progressColor = CupertinoColors.systemGrey2
|
||||
..progressWidth = 6.0
|
||||
..textColor = Colors.white
|
||||
..loadingStyle = EasyLoadingStyle.custom
|
||||
..indicatorType = EasyLoadingIndicatorType.fadingCircle;
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_download_manager/flutter_download_manager.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
class FileDownloadProgressView extends StatelessWidget {
|
||||
FileDownloadProgressView(this.message, {Key? key}) : super(key: key);
|
||||
final Message message;
|
||||
final logic = Get.find<DownloadController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final url = message.fileElem?.sourceUrl;
|
||||
return Obx(() => SizedBox(
|
||||
width: 38.w,
|
||||
height: 44.h,
|
||||
child: message.isFileType && null != logic.downloadTaskList[url]
|
||||
? ValueListenableBuilder(
|
||||
valueListenable: logic.downloadTaskList[url]!.status,
|
||||
builder: (_, status, child) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: logic.downloadTaskList[url]!.progress,
|
||||
builder: (_, progress, child) {
|
||||
return (status == DownloadStatus.downloading || status == DownloadStatus.paused || status == DownloadStatus.queued)
|
||||
? Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
ImageRes.fileMask.toImage
|
||||
..width = 38.w
|
||||
..height = 44.h,
|
||||
SizedBox(
|
||||
width: 22.w,
|
||||
height: 22.w,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
backgroundColor: Styles.c_FFFFFF,
|
||||
color: Styles.c_0089FF,
|
||||
strokeWidth: 1.5,
|
||||
value: progress,
|
||||
),
|
||||
if (status == DownloadStatus.downloading)
|
||||
ImageRes.progressPause.toImage
|
||||
..width = 16.w
|
||||
..height = 16.h,
|
||||
if (status == DownloadStatus.paused)
|
||||
ImageRes.progressGoing.toImage
|
||||
..width = 16.w
|
||||
..height = 16.h,
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: const SizedBox();
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
: null,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
class RegisterBgView extends StatelessWidget {
|
||||
const RegisterBgView({
|
||||
Key? key,
|
||||
required this.child,
|
||||
}) : super(key: key);
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Material(
|
||||
child: TouchCloseSoftKeyboard(
|
||||
isGradientBg: true,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
54.verticalSpace,
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 22.w),
|
||||
child: ImageRes.backBlack.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h
|
||||
..onTap = () => Get.back(),
|
||||
),
|
||||
38.verticalSpace,
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 32.w),
|
||||
child: child,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
class ScreenLockTitle extends StatelessWidget {
|
||||
const ScreenLockTitle({
|
||||
Key? key,
|
||||
required this.stream,
|
||||
}) : super(key: key);
|
||||
|
||||
final Stream<String> stream;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(children: [
|
||||
Text(StrRes.plsEnterPassword, style: Styles.ts_FFFFFF_17sp),
|
||||
StreamBuilder(
|
||||
builder: (context, AsyncSnapshot<String?> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Text(
|
||||
sprintf(StrRes.lockPwdErrorHint, [snapshot.data]),
|
||||
style: Styles.ts_FF381F_17sp,
|
||||
);
|
||||
}
|
||||
return const SizedBox();
|
||||
},
|
||||
stream: stream,
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
class UpgradeViewV2 extends StatefulWidget {
|
||||
final Function()? onLater;
|
||||
final Function()? onIgnore;
|
||||
final Function() onNow;
|
||||
final UpgradeInfoV2 upgradeInfo;
|
||||
final PackageInfo packageInfo;
|
||||
final PublishSubject? subject;
|
||||
|
||||
const UpgradeViewV2({
|
||||
super.key,
|
||||
this.onLater,
|
||||
this.onIgnore,
|
||||
required this.onNow,
|
||||
required this.upgradeInfo,
|
||||
required this.packageInfo,
|
||||
this.subject,
|
||||
});
|
||||
|
||||
@override
|
||||
State<UpgradeViewV2> createState() => _UpgradeViewV2State();
|
||||
}
|
||||
|
||||
class _UpgradeViewV2State extends State<UpgradeViewV2> {
|
||||
double _progress = 0.0;
|
||||
bool _showProgress = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
widget.subject?.stream.listen((progress) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_progress = progress;
|
||||
});
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _startDownload() {
|
||||
if (Platform.isAndroid) {
|
||||
Get.back();
|
||||
} else {
|
||||
if (!widget.upgradeInfo.needForceUpdate!) {
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
widget.onNow.call();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return !widget.upgradeInfo.needForceUpdate!;
|
||||
},
|
||||
child: Center(
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 46.w),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 12.w,
|
||||
vertical: 12.h,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
StrRes.upgradeFind,
|
||||
style: TextStyle(
|
||||
color: const Color(0xFF333333),
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10.h,
|
||||
),
|
||||
Text(
|
||||
sprintf(StrRes.upgradeVersion, [
|
||||
'${widget.upgradeInfo.buildVersion!} + ${widget.upgradeInfo.buildVersionNo!}',
|
||||
'${widget.packageInfo.version} + ${widget.packageInfo.buildNumber}'
|
||||
]),
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: const Color(0xFF333333),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10.h,
|
||||
),
|
||||
Text(
|
||||
StrRes.upgradeDescription,
|
||||
style: TextStyle(
|
||||
color: const Color(0xFF333333),
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 4.h,
|
||||
),
|
||||
Text(
|
||||
widget.upgradeInfo.buildUpdateDescription ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: const Color(0xFF333333),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10.h,
|
||||
),
|
||||
if (!widget.upgradeInfo.needForceUpdate! && !_showProgress)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
_buildButton(
|
||||
text: StrRes.upgradeIgnore,
|
||||
onTap: widget.onIgnore ?? () => Get.back(),
|
||||
),
|
||||
_buildButton(
|
||||
text: StrRes.upgradeLater,
|
||||
onTap: widget.onLater ?? () => Get.back(),
|
||||
),
|
||||
_buildButton(
|
||||
text: StrRes.upgradeNow,
|
||||
onTap: _startDownload,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.upgradeInfo.needForceUpdate! && !_showProgress)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
_buildButton(
|
||||
text: StrRes.upgradeNow,
|
||||
onTap: _startDownload,
|
||||
)
|
||||
],
|
||||
),
|
||||
if (_showProgress)
|
||||
SizedBox(
|
||||
height: 44.h,
|
||||
child: Center(
|
||||
child: LinearPercentIndicator(
|
||||
lineHeight: 20.h,
|
||||
percent: _progress,
|
||||
center: "${(_progress * 100).toInt()}%".toText..style = TextStyle(fontSize: 12.sp),
|
||||
linearStrokeCap: LinearStrokeCap.roundAll,
|
||||
backgroundColor: Colors.grey.withOpacity(0.5),
|
||||
progressColor: Colors.blueAccent,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildButton({required String text, Function()? onTap}) => Ink(
|
||||
height: 44.h,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 14.w,
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
color: const Color(0xFF1B72EC),
|
||||
fontSize: 16.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user