292 lines
10 KiB
Dart
292 lines
10 KiB
Dart
import 'dart:convert';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:yumi/shared/tools/sc_pick_utils.dart';
|
||
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
|
||
import 'package:provider/provider.dart';
|
||
import 'package:tencent_cloud_chat_sdk/enum/conversation_type.dart';
|
||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
|
||
import 'package:webview_flutter/webview_flutter.dart';
|
||
import 'package:yumi/app/constants/sc_global_config.dart';
|
||
import 'package:yumi/app/constants/sc_screen.dart';
|
||
import 'package:yumi/app/routes/sc_fluro_navigator.dart';
|
||
import 'package:yumi/shared/tools/sc_deviceId_utils.dart';
|
||
import 'package:yumi/shared/tools/sc_room_utils.dart';
|
||
import 'package:yumi/main.dart';
|
||
import 'package:yumi/services/audio/rtm_manager.dart';
|
||
import 'package:yumi/modules/index/main_route.dart';
|
||
|
||
import '../chat/chat_route.dart';
|
||
|
||
class WebViewPage extends StatefulWidget {
|
||
final String title;
|
||
final String url;
|
||
final String showTitle;
|
||
|
||
const WebViewPage({
|
||
Key? key,
|
||
this.title = "",
|
||
this.showTitle = "true",
|
||
required this.url,
|
||
}) : super(key: key);
|
||
|
||
@override
|
||
_WebViewPageState createState() => _WebViewPageState();
|
||
}
|
||
|
||
class _WebViewPageState extends State<WebViewPage> {
|
||
late WebViewController _controller;
|
||
String _title = "";
|
||
double _progress = 0.0;
|
||
bool _isLoading = true;
|
||
String urlLink = "";
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
if (widget.url.split("?").length > 1) {
|
||
urlLink = "${widget.url}&";
|
||
} else {
|
||
urlLink = "${widget.url}?";
|
||
}
|
||
urlLink = "${urlLink}lang=${SCGlobalConfig.lang}";
|
||
// 初始化 WebViewController
|
||
_controller =
|
||
WebViewController()
|
||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||
..addJavaScriptChannel(
|
||
"FlutterPageControl",
|
||
onMessageReceived: (sjMessage) async {
|
||
String msg = sjMessage.message;
|
||
if (sjMessage.message == "close_page") {
|
||
SCNavigatorUtils.goBack(context);
|
||
} else if (msg.startsWith("view_user_info")) {
|
||
//跳转个人信息
|
||
if (msg.contains(":")) {
|
||
var sli = msg.split(":");
|
||
if (sli.length > 1) {
|
||
String userId = sli[1];
|
||
SCNavigatorUtils.push(
|
||
context,
|
||
"${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == userId}&tageId=$userId",
|
||
);
|
||
}
|
||
}
|
||
} else if (msg.startsWith("go_to_room")) {
|
||
//跳转房间
|
||
if (msg.contains(":")) {
|
||
var sli = msg.split(":");
|
||
if (sli.length > 1) {
|
||
String roomId = sli[1];
|
||
SCRoomUtils.goRoom(
|
||
roomId,
|
||
navigatorKey.currentState!.context,
|
||
);
|
||
}
|
||
}
|
||
} else if (msg.startsWith("private_chat")) {
|
||
//打开私聊
|
||
if (msg.contains(":")) {
|
||
var sli = msg.split(":");
|
||
if (sli.length > 1) {
|
||
String userId = sli[1];
|
||
var conversation = V2TimConversation(
|
||
type: ConversationType.V2TIM_C2C,
|
||
userID: userId,
|
||
conversationID: '',
|
||
);
|
||
var bool = await Provider.of<RtmProvider>(
|
||
context,
|
||
listen: false,
|
||
).startConversation(conversation);
|
||
if (!bool) return;
|
||
var json = jsonEncode(conversation.toJson());
|
||
SCNavigatorUtils.push(
|
||
context,
|
||
"${SCChatRouter.chat}?conversation=${Uri.encodeComponent(json)}",
|
||
);
|
||
}
|
||
}
|
||
} else if (msg.startsWith("uploadImgFile")) {
|
||
picImage();
|
||
} else if (msg.startsWith("editingRoom")) {
|
||
SCNavigatorUtils.push(context, SCMainRoute.editRoomSearchAdmin);
|
||
} else if (msg.startsWith("editingUser")) {
|
||
SCNavigatorUtils.push(context, SCMainRoute.editUserSearchAdmin);
|
||
}
|
||
},
|
||
)
|
||
..setNavigationDelegate(
|
||
NavigationDelegate(
|
||
onProgress: (int progress) {
|
||
setState(() {
|
||
_progress = progress / 100.0;
|
||
});
|
||
},
|
||
onPageStarted: (String url) {
|
||
setState(() {
|
||
_isLoading = true;
|
||
});
|
||
},
|
||
onPageFinished: (String url) {
|
||
// 延迟500毫秒注入,等待Vue3初始化
|
||
Future.delayed(Duration(milliseconds: 550), () {
|
||
_injectJavaScriptInterface();
|
||
});
|
||
setState(() {
|
||
_isLoading = false;
|
||
_getPageTitle();
|
||
});
|
||
},
|
||
onWebResourceError: (WebResourceError error) {
|
||
_onWebResourceError(error);
|
||
},
|
||
),
|
||
)
|
||
..loadRequest(Uri.parse(urlLink));
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_controller.loadRequest(Uri.parse('about:blank'));
|
||
super.dispose();
|
||
}
|
||
|
||
void _injectJavaScriptInterface() async {
|
||
String imei = await SCDeviceIdUtils.getDeviceId();
|
||
// 注入JavaScript对象和方法
|
||
_controller.runJavaScript('''
|
||
window.app = window.app || {};
|
||
// 注入获取访问信息的方法
|
||
window.app.getAccessOrigin = function() {
|
||
// 获取认证信息(这里可以从Flutter传递)
|
||
return JSON.stringify({
|
||
'Authorization': 'Bearer ${AccountStorage().token}',
|
||
'Req-Lang': '${SCGlobalConfig.lang}',
|
||
'Req-App-Intel': 'build=${SCGlobalConfig.build};version=${SCGlobalConfig.version};model=${SCGlobalConfig.model};channel=${SCGlobalConfig.channel};Req-Imei=$imei',
|
||
'Req-Sys-Origin': 'origin=${SCGlobalConfig.origin};originChild=${SCGlobalConfig.originChild}'
|
||
});
|
||
};
|
||
|
||
// 注入其他可能需要的方法
|
||
window.app.getAuth = function() {
|
||
return window.app.getAccessOrigin();
|
||
};
|
||
|
||
// 可以通过这个方法向Flutter发送消息
|
||
window.app.sendToFlutter = function(data) {
|
||
FlutterApp.postMessage(data);
|
||
};
|
||
''');
|
||
}
|
||
|
||
void picImage() async {
|
||
SCPickUtils.pickImage(context, (b, path) {
|
||
_controller.runJavaScript('''
|
||
window.app = window.app || {};
|
||
// 注入获取访问信息的方法
|
||
window.app.getImagePath = function() {
|
||
// 获取认证信息(这里可以从Flutter传递)
|
||
return JSON.stringify({
|
||
'path': '$path',
|
||
});
|
||
};
|
||
|
||
// 注入其他可能需要的方法
|
||
window.app.getAuth = function() {
|
||
return window.app.getImagePath();
|
||
};
|
||
|
||
// 可以通过这个方法向Flutter发送消息
|
||
window.app.sendToFlutter = function(data) {
|
||
FlutterApp.postMessage(data);
|
||
};
|
||
''');
|
||
}, neeCrop: false);
|
||
}
|
||
|
||
// 获取页面标题
|
||
Future<void> _getPageTitle() async {
|
||
try {
|
||
final title =
|
||
await _controller.runJavaScriptReturningResult("document.title")
|
||
as String?;
|
||
if (title != null) {
|
||
setState(() {
|
||
_title = title.replaceAll("\"", "");
|
||
});
|
||
}
|
||
} catch (e) {
|
||
print("获取标题失败: $e");
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar:
|
||
widget.showTitle == "true"
|
||
? AppBar(
|
||
elevation: 0,
|
||
backgroundColor: SCGlobalConfig.businessLogicStrategy.getWebViewPageAppBarBackgroundColor(),
|
||
centerTitle: true,
|
||
title: Text(
|
||
_title.isNotEmpty ? _title : widget.title,
|
||
style: TextStyle(
|
||
fontSize: sp(18),
|
||
color: SCGlobalConfig.businessLogicStrategy.getWebViewPageTitleTextColor(),
|
||
),
|
||
),
|
||
leading: GestureDetector(
|
||
behavior: HitTestBehavior.opaque,
|
||
onTap: () {
|
||
SCNavigatorUtils.goBack(context);
|
||
},
|
||
child: Container(
|
||
padding: EdgeInsets.only(left: width(15), right: width(15)),
|
||
child: Center(
|
||
child: Icon(Icons.arrow_back_ios, size: 20.w, color: SCGlobalConfig.businessLogicStrategy.getWebViewPageBackArrowColor()),
|
||
),
|
||
),
|
||
),
|
||
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
||
)
|
||
: null,
|
||
body: SafeArea(
|
||
top: false,
|
||
child: Stack(
|
||
children: [
|
||
WebViewWidget(controller: _controller),
|
||
|
||
// 加载指示器
|
||
// if (_isLoading)
|
||
// Center(
|
||
// child: CircularProgressIndicator(
|
||
// valueColor: AlwaysStoppedAnimation<Color>(Color(0xffFF6000)),
|
||
// ),
|
||
// ),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _progressBar(double progress, BuildContext context) {
|
||
return progress < 1.0
|
||
? LinearProgressIndicator(
|
||
value: progress,
|
||
backgroundColor: SCGlobalConfig.businessLogicStrategy.getWebViewPageProgressBarBackgroundColor(),
|
||
minHeight: 1.0,
|
||
valueColor: AlwaysStoppedAnimation<Color>(SCGlobalConfig.businessLogicStrategy.getWebViewPageProgressBarActiveColor()),
|
||
)
|
||
: const SizedBox.shrink();
|
||
}
|
||
|
||
void _onWebResourceError(WebResourceError error) {
|
||
print('_onWebResourceError:${error.description}');
|
||
// 可以在这里添加错误处理逻辑,比如显示错误页面
|
||
}
|
||
|
||
}
|