Browse Source

Merge commit 'ccb3b5be56a2bf18c0922298aefc4854ee95d274'

newdev_shunjiawei
lxm 2 years ago
parent
commit
ec8676230e
  1. 110
      lib/core/translations/language/en_us.dart
  2. 113
      lib/core/translations/language/zh_cn.dart
  3. 2
      lib/data/services/db/database_helper.dart
  4. 18
      lib/modules/common/webview_page.dart
  5. 76
      lib/modules/login/controllers/login_controller.dart
  6. 18
      lib/modules/login/views/login_view.dart
  7. 3
      lib/modules/meeting/controllers/meeting_details_controller.dart
  8. 4
      lib/modules/meeting/controllers/meeting_edit_controller.dart
  9. 38
      lib/modules/meeting/controllers/meeting_record_controller.dart
  10. 4
      lib/modules/meeting/model/meeting_details_model.dart
  11. 246
      lib/modules/meeting/views/meeting_record_view.dart
  12. 6
      lib/modules/meeting/views/meeting_view.dart
  13. 4
      lib/modules/profile/views/profile_view.dart
  14. 136
      lib/modules/settings/views/settings_view.dart

110
lib/core/translations/language/en_us.dart

@ -44,6 +44,8 @@ const Map<String, String> enUS = {
"userAgreement": "User Agreement", "userAgreement": "User Agreement",
"privacyPolicy": "Privacy Policy", "privacyPolicy": "Privacy Policy",
'selectCountry':'Select Country/Region', 'selectCountry':'Select Country/Region',
"email": "email",
"phoneNumber": "phoneNumber",
// 首页 // 首页
"deviceStatus": "Device Status", "deviceStatus": "Device Status",
@ -172,4 +174,112 @@ const Map<String, String> enUS = {
"editProfile": "Edit Profile", "editProfile": "Edit Profile",
"nickname": "Nickname", "nickname": "Nickname",
"save": "Save", "save": "Save",
//国家列表
"邮箱": "Email",
"中国": "China",
"美国": "United States",
"加拿大": "Canada",
"俄罗斯": "Russia",
"英国": "United Kingdom",
"德国": "Germany",
"意大利": "Italy",
"法国": "France",
"西班牙": "Spain",
"南非": "South Africa",
"沙特阿拉伯": "Saudi Arabia",
"土耳其": "Turkey",
"日本": "Japan",
"韩国": "South Korea",
"新加坡": "Singapore",
"马来西亚": "Malaysia",
"泰国": "Thailand",
"越南": "Vietnam",
"印度": "India",
"巴基斯坦": "Pakistan",
"菲律宾": "Philippines",
"印度尼西亚": "Indonesia",
"阿联酋": "United Arab Emirates",
"墨西哥": "Mexico",
"巴西": "Brazil",
"阿根廷": "Argentina",
"澳大利亚": "Australia",
"新西兰": "New Zealand",
"中国香港": "Hong Kong, China",
"中国澳门": "Macau, China",
"中国台湾": "Taiwan, China",
"埃及": "Egypt",
"希腊": "Greece",
"荷兰": "Netherlands",
"比利时": "Belgium",
"匈牙利": "Hungary",
"罗马尼亚": "Romania",
"瑞士": "Switzerland",
"奥地利": "Austria",
"丹麦": "Denmark",
"瑞典": "Sweden",
"挪威": "Norway",
"波兰": "Poland",
"秘鲁": "Peru",
"智利": "Chile",
"哥伦比亚": "Colombia",
"委内瑞拉": "Venezuela",
"葡萄牙": "Portugal",
"卢森堡": "Luxembourg",
"爱尔兰": "Ireland",
"冰岛": "Iceland",
"阿尔巴尼亚": "Albania",
"马耳他": "Malta",
"塞浦路斯": "Cyprus",
"芬兰": "Finland",
"保加利亚": "Bulgaria",
"立陶宛": "Lithuania",
"拉脱维亚": "Latvia",
"爱沙尼亚": "Estonia",
"乌克兰": "Ukraine",
"塞尔维亚": "Serbia",
"克罗地亚": "Croatia",
"斯洛文尼亚": "Slovenia",
"捷克": "Czech Republic",
"斯洛伐克": "Slovakia",
"危地马拉": "Guatemala",
"萨尔瓦多": "El Salvador",
"洪都拉斯": "Honduras",
"尼加拉瓜": "Nicaragua",
"哥斯达黎加": "Costa Rica",
"巴拿马": "Panama",
"海地": "Haiti",
"玻利维亚": "Bolivia",
"厄瓜多尔": "Ecuador",
"巴拉圭": "Paraguay",
"乌拉圭": "Uruguay",
"摩洛哥": "Morocco",
"阿尔及利亚": "Algeria",
"突尼斯": "Tunisia",
"尼日利亚": "Nigeria",
"加纳": "Ghana",
"埃塞俄比亚": "Ethiopia",
"肯尼亚": "Kenya",
"坦桑尼亚": "Tanzania",
"乌干达": "Uganda",
"孟加拉国": "Bangladesh",
"以色列": "Israel",
"黎巴嫩": "Lebanon",
"约旦": "Jordan",
"伊拉克": "Iraq",
"科威特": "Kuwait",
"巴林": "Bahrain",
"卡塔尔": "Qatar",
"阿曼": "Oman",
"阿富汗": "Afghanistan",
"斯里兰卡": "Sri Lanka",
"缅甸": "Myanmar",
"尼泊尔": "Nepal",
"蒙古": "Mongolia",
"柬埔寨": "Cambodia",
"老挝": "Laos",
"文莱": "Brunei",
"东帝汶": "East Timor",
"斐济": "Fiji",
"所罗门群岛": "Solomon Islands",
}; };

113
lib/core/translations/language/zh_cn.dart

@ -43,6 +43,9 @@ const Map<String, String> zhCN = {
"and": " 和 ", "and": " 和 ",
"userAgreement": "《用户协议》", "userAgreement": "《用户协议》",
"privacyPolicy": "《隐私政策》", "privacyPolicy": "《隐私政策》",
'selectCountry': '选择国家/地区',
"email": "邮箱",
"phoneNumber": "手机号码",
// 首页 // 首页
"deviceStatus": "设备状态", "deviceStatus": "设备状态",
@ -150,7 +153,7 @@ const Map<String, String> zhCN = {
'defaultTimbre': '默认音色', 'defaultTimbre': '默认音色',
'microsoftCloudTimbreService': '微软云端音色服务', 'microsoftCloudTimbreService': '微软云端音色服务',
'voiceClone': '声音复刻', 'voiceClone': '声音复刻',
'selectCountry': '选择国家/地区',
// 聊天页 // 聊天页
"clearChatHistory": "清空聊天记录", "clearChatHistory": "清空聊天记录",
@ -167,4 +170,112 @@ const Map<String, String> zhCN = {
"editProfile": "编辑个人信息", "editProfile": "编辑个人信息",
"nickname": "昵称", "nickname": "昵称",
"save": "保存", "save": "保存",
//国家列表
"邮箱": "邮箱",
"中国": "中国",
"美国": "美国",
"加拿大": "加拿大",
"俄罗斯": "俄罗斯",
"英国": "英国",
"德国": "德国",
"意大利": "意大利",
"法国": "法国",
"西班牙": "西班牙",
"南非": "南非",
"沙特阿拉伯": "沙特阿拉伯",
"土耳其": "土耳其",
"日本": "日本",
"韩国": "韩国",
"新加坡": "新加坡",
"马来西亚": "马来西亚",
"泰国": "泰国",
"越南": "越南",
"印度": "印度",
"巴基斯坦": "巴基斯坦",
"菲律宾": "菲律宾",
"印度尼西亚": "印度尼西亚",
"阿联酋": "阿联酋",
"墨西哥": "墨西哥",
"巴西": "巴西",
"阿根廷": "阿根廷",
"澳大利亚": "澳大利亚",
"新西兰": "新西兰",
"中国香港": "中国香港",
"中国澳门": "中国澳门",
"中国台湾": "中国台湾",
"埃及": "埃及",
"希腊": "希腊",
"荷兰": "荷兰",
"比利时": "比利时",
"匈牙利": "匈牙利",
"罗马尼亚": "罗马尼亚",
"瑞士": "瑞士",
"奥地利": "奥地利",
"丹麦": "丹麦",
"瑞典": "瑞典",
"挪威": "挪威",
"波兰": "波兰",
"秘鲁": "秘鲁",
"智利": "智利",
"哥伦比亚": "哥伦比亚",
"委内瑞拉": "委内瑞拉",
"葡萄牙": "葡萄牙",
"卢森堡": "卢森堡",
"爱尔兰": "爱尔兰",
"冰岛": "冰岛",
"阿尔巴尼亚": "阿尔巴尼亚",
"马耳他": "马耳他",
"塞浦路斯": "塞浦路斯",
"芬兰": "芬兰",
"保加利亚": "保加利亚",
"立陶宛": "立陶宛",
"拉脱维亚": "拉脱维亚",
"爱沙尼亚": "爱沙尼亚",
"乌克兰": "乌克兰",
"塞尔维亚": "塞尔维亚",
"克罗地亚": "克罗地亚",
"斯洛文尼亚": "斯洛文尼亚",
"捷克": "捷克",
"斯洛伐克": "斯洛伐克",
"危地马拉": "危地马拉",
"萨尔瓦多": "萨尔瓦多",
"洪都拉斯": "洪都拉斯",
"尼加拉瓜": "尼加拉瓜",
"哥斯达黎加": "哥斯达黎加",
"巴拿马": "巴拿马",
"海地": "海地",
"玻利维亚": "玻利维亚",
"厄瓜多尔": "厄瓜多尔",
"巴拉圭": "巴拉圭",
"乌拉圭": "乌拉圭",
"摩洛哥": "摩洛哥",
"阿尔及利亚": "阿尔及利亚",
"突尼斯": "突尼斯",
"尼日利亚": "尼日利亚",
"加纳": "加纳",
"埃塞俄比亚": "埃塞俄比亚",
"肯尼亚": "肯尼亚",
"坦桑尼亚": "坦桑尼亚",
"乌干达": "乌干达",
"孟加拉国": "孟加拉国",
"以色列": "以色列",
"黎巴嫩": "黎巴嫩",
"约旦": "约旦",
"伊拉克": "伊拉克",
"科威特": "科威特",
"巴林": "巴林",
"卡塔尔": "卡塔尔",
"阿曼": "阿曼",
"阿富汗": "阿富汗",
"斯里兰卡": "斯里兰卡",
"缅甸": "缅甸",
"尼泊尔": "尼泊尔",
"蒙古": "蒙古",
"柬埔寨": "柬埔寨",
"老挝": "老挝",
"文莱": "文莱",
"东帝汶": "东帝汶",
"斐济": "斐济",
"所罗门群岛": "所罗门群岛",
}; };

2
lib/data/services/db/database_helper.dart

@ -40,7 +40,7 @@ class DatabaseHelper {
CREATE TABLE IF NOT EXISTS meetingdetails ( CREATE TABLE IF NOT EXISTS meetingdetails (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
meetingid INTEGER, meetingid INTEGER,
audio BLOB, audio TEXT,
content TEXT content TEXT
) )
'''); ''');

18
lib/modules/common/webview_page.dart

@ -12,19 +12,31 @@ class WebViewPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
final controller = WebViewController() final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted) ..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadRequest(Uri.parse(url)); ..loadRequest(Uri.parse(url));
return Scaffold( return Scaffold(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
appBar: AppBar( appBar: AppBar(
centerTitle: true,
title: Text(title), title: Text(title),
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back), icon: Icon(
onPressed: () => Get.back(), Icons.arrow_back_ios,
color: isDarkMode ? Colors.white : Colors.black,
size: 20.sp,
), ),
onPressed: () => Get.back(),
),
backgroundColor: isDarkMode ? Colors.black : Colors.white,
foregroundColor: isDarkMode ? Colors.white : Colors.black,
elevation: 0,
),
body: WebViewWidget(
controller: controller,
), ),
body: WebViewWidget(controller: controller),
); );
} }
} }

76
lib/modules/login/controllers/login_controller.dart

@ -64,6 +64,82 @@ class LoginController extends GetxController {
{'name': '中国香港', 'code': '+852', 'flag': '🇭🇰'}, {'name': '中国香港', 'code': '+852', 'flag': '🇭🇰'},
{'name': '中国澳门', 'code': '+853', 'flag': '🇲🇴'}, {'name': '中国澳门', 'code': '+853', 'flag': '🇲🇴'},
{'name': '中国台湾', 'code': '+886', 'flag': '🇹🇼'}, {'name': '中国台湾', 'code': '+886', 'flag': '🇹🇼'},
// 添加的其他主要国家
{'name': '埃及', 'code': '+20', 'flag': '🇪🇬'},
{'name': '希腊', 'code': '+30', 'flag': '🇬🇷'},
{'name': '荷兰', 'code': '+31', 'flag': '🇳🇱'},
{'name': '比利时', 'code': '+32', 'flag': '🇧🇪'},
{'name': '匈牙利', 'code': '+36', 'flag': '🇭🇺'},
{'name': '罗马尼亚', 'code': '+40', 'flag': '🇷🇴'},
{'name': '瑞士', 'code': '+41', 'flag': '🇨🇭'},
{'name': '奥地利', 'code': '+43', 'flag': '🇦🇹'},
{'name': '丹麦', 'code': '+45', 'flag': '🇩🇰'},
{'name': '瑞典', 'code': '+46', 'flag': '🇸🇪'},
{'name': '挪威', 'code': '+47', 'flag': '🇳🇴'},
{'name': '波兰', 'code': '+48', 'flag': '🇵🇱'},
{'name': '秘鲁', 'code': '+51', 'flag': '🇵🇪'},
{'name': '智利', 'code': '+56', 'flag': '🇨🇱'},
{'name': '哥伦比亚', 'code': '+57', 'flag': '🇨🇴'},
{'name': '委内瑞拉', 'code': '+58', 'flag': '🇻🇪'},
{'name': '葡萄牙', 'code': '+351', 'flag': '🇵🇹'},
{'name': '卢森堡', 'code': '+352', 'flag': '🇱🇺'},
{'name': '爱尔兰', 'code': '+353', 'flag': '🇮🇪'},
{'name': '冰岛', 'code': '+354', 'flag': '🇮🇸'},
{'name': '阿尔巴尼亚', 'code': '+355', 'flag': '🇦🇱'},
{'name': '马耳他', 'code': '+356', 'flag': '🇲🇹'},
{'name': '塞浦路斯', 'code': '+357', 'flag': '🇨🇾'},
{'name': '芬兰', 'code': '+358', 'flag': '🇫🇮'},
{'name': '保加利亚', 'code': '+359', 'flag': '🇧🇬'},
{'name': '立陶宛', 'code': '+370', 'flag': '🇱🇹'},
{'name': '拉脱维亚', 'code': '+371', 'flag': '🇱🇻'},
{'name': '爱沙尼亚', 'code': '+372', 'flag': '🇪🇪'},
{'name': '乌克兰', 'code': '+380', 'flag': '🇺🇦'},
{'name': '塞尔维亚', 'code': '+381', 'flag': '🇷🇸'},
{'name': '克罗地亚', 'code': '+385', 'flag': '🇭🇷'},
{'name': '斯洛文尼亚', 'code': '+386', 'flag': '🇸🇮'},
{'name': '捷克', 'code': '+420', 'flag': '🇨🇿'},
{'name': '斯洛伐克', 'code': '+421', 'flag': '🇸🇰'},
{'name': '危地马拉', 'code': '+502', 'flag': '🇬🇹'},
{'name': '萨尔瓦多', 'code': '+503', 'flag': '🇸🇻'},
{'name': '洪都拉斯', 'code': '+504', 'flag': '🇭🇳'},
{'name': '尼加拉瓜', 'code': '+505', 'flag': '🇳🇮'},
{'name': '哥斯达黎加', 'code': '+506', 'flag': '🇨🇷'},
{'name': '巴拿马', 'code': '+507', 'flag': '🇵🇦'},
{'name': '海地', 'code': '+509', 'flag': '🇭🇹'},
{'name': '玻利维亚', 'code': '+591', 'flag': '🇧🇴'},
{'name': '厄瓜多尔', 'code': '+593', 'flag': '🇪🇨'},
{'name': '巴拉圭', 'code': '+595', 'flag': '🇵🇾'},
{'name': '乌拉圭', 'code': '+598', 'flag': '🇺🇾'},
{'name': '摩洛哥', 'code': '+212', 'flag': '🇲🇦'},
{'name': '阿尔及利亚', 'code': '+213', 'flag': '🇩🇿'},
{'name': '突尼斯', 'code': '+216', 'flag': '🇹🇳'},
{'name': '尼日利亚', 'code': '+234', 'flag': '🇳🇬'},
{'name': '加纳', 'code': '+233', 'flag': '🇬🇭'},
{'name': '埃塞俄比亚', 'code': '+251', 'flag': '🇪🇹'},
{'name': '肯尼亚', 'code': '+254', 'flag': '🇰🇪'},
{'name': '坦桑尼亚', 'code': '+255', 'flag': '🇹🇿'},
{'name': '乌干达', 'code': '+256', 'flag': '🇺🇬'},
{'name': '孟加拉国', 'code': '+880', 'flag': '🇧🇩'},
{'name': '以色列', 'code': '+972', 'flag': '🇮🇱'},
{'name': '黎巴嫩', 'code': '+961', 'flag': '🇱🇧'},
{'name': '约旦', 'code': '+962', 'flag': '🇯🇴'},
{'name': '伊拉克', 'code': '+964', 'flag': '🇮🇶'},
{'name': '科威特', 'code': '+965', 'flag': '🇰🇼'},
{'name': '巴林', 'code': '+973', 'flag': '🇧🇭'},
{'name': '卡塔尔', 'code': '+974', 'flag': '🇶🇦'},
{'name': '阿曼', 'code': '+968', 'flag': '🇴🇲'},
{'name': '阿富汗', 'code': '+93', 'flag': '🇦🇫'},
{'name': '斯里兰卡', 'code': '+94', 'flag': '🇱🇰'},
{'name': '缅甸', 'code': '+95', 'flag': '🇲🇲'},
{'name': '尼泊尔', 'code': '+977', 'flag': '🇳🇵'},
{'name': '蒙古', 'code': '+976', 'flag': '🇲🇳'},
{'name': '柬埔寨', 'code': '+855', 'flag': '🇰🇭'},
{'name': '老挝', 'code': '+856', 'flag': '🇱🇦'},
{'name': '文莱', 'code': '+673', 'flag': '🇧🇳'},
{'name': '东帝汶', 'code': '+670', 'flag': '🇹🇱'},
{'name': '斐济', 'code': '+679', 'flag': '🇫🇯'},
{'name': '所罗门群岛', 'code': '+677', 'flag': '🇸🇧'},
]; ];
// 状态管理 // 状态管理

18
lib/modules/login/views/login_view.dart

@ -171,7 +171,7 @@ class LoginView extends GetView<LoginController> {
); );
} }
// 输入框 // 输入框
Widget _buildInputField(bool isDarkMode) { Widget _buildInputField(bool isDarkMode) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -224,13 +224,13 @@ class LoginView extends GetView<LoginController> {
Expanded( Expanded(
child: TextField( child: TextField(
controller: controller.contactController, controller: controller.contactController,
// keyboardType: controller.selectedCountryFlag == '✉️' // keyboardType: controller.selectedCountryFlag == '✉️'
// ? TextInputType.emailAddress // ? TextInputType.emailAddress
// : TextInputType.phone, // : TextInputType.phone,
decoration: InputDecoration( decoration: InputDecoration(
hintText: controller.selectedCountryFlag == '✉️' hintText: controller.selectedCountryFlag == '✉️'
? 'email'.tr // 需要在翻译文件中添加 ? 'email'.tr // 需要在翻译文件中添加
: 'phoneNumber'.tr, // 需要在翻译文件中添加 : 'phoneNumber'.tr, // 需要在翻译文件中添加
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[600] : Colors.black38, color: isDarkMode ? Colors.grey[600] : Colors.black38,
@ -293,7 +293,7 @@ class LoginView extends GetView<LoginController> {
style: TextStyle(fontSize: 24.sp), style: TextStyle(fontSize: 24.sp),
), ),
title: Text( title: Text(
country['name']!, '${country['name']}'.tr,
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black, color: isDarkMode ? Colors.white : Colors.black,
), ),
@ -530,8 +530,8 @@ class LoginView extends GetView<LoginController> {
GestureDetector( GestureDetector(
onTap: () { onTap: () {
String url = 'https://www.deepsoud.com/yhxy.html'; String url = 'https://www.deepsoud.com/yhxy.html';
//print('----------${Get.locale?.toString()}'); print('----------${Get.locale?.toString()}');
if (Get.locale?.toString() != 'zh_Hans_CN') { if (Get.locale?.toString() != 'zh_CN') {
url = 'https://www.deepsoud.com/yhxy_en.html'; url = 'https://www.deepsoud.com/yhxy_en.html';
} }
Get.to(() => WebViewPage( Get.to(() => WebViewPage(
@ -557,7 +557,7 @@ class LoginView extends GetView<LoginController> {
GestureDetector( GestureDetector(
onTap: () { onTap: () {
String url = 'https://www.deepsoud.com/ysxy.html'; String url = 'https://www.deepsoud.com/ysxy.html';
if (Get.locale?.toString() != 'zh_Hans_CN') { if (Get.locale?.toString() != 'zh_CN') {
url = 'https://www.deepsoud.com/ysxy_en.html'; url = 'https://www.deepsoud.com/ysxy_en.html';
} }
Get.to(() => WebViewPage( Get.to(() => WebViewPage(

3
lib/modules/meeting/controllers/meeting_details_controller.dart

@ -3,7 +3,6 @@ import 'package:get/get.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import '../../../data/services/db/sqflite_api.dart'; import '../../../data/services/db/sqflite_api.dart';
import '../../../data/services/speech_impl/volcano_tts_api_service.dart';
import '../model/meeting_details_model.dart'; import '../model/meeting_details_model.dart';
import '../model/meeting_model.dart'; import '../model/meeting_model.dart';
@ -42,7 +41,7 @@ class MeetingDetailsController extends GetxController
final data = await SqfliteApi.getMeetingDetails(id); final data = await SqfliteApi.getMeetingDetails(id);
meetingData.value = MeetingModel.fromJson(data); meetingData.value = MeetingModel.fromJson(data);
dataDetails.value = MeetingDetailsModel.fromJson(data['details']); dataDetails.value = MeetingDetailsModel.fromJson(data['details']);
audioPlayer.setAudioSource(BytesAudioSource(dataDetails.value.audio)); audioPlayer.setAudioSource(AudioSource.file(dataDetails.value.audio));
audioPlayer.playerStateStream.listen((state) async { audioPlayer.playerStateStream.listen((state) async {
if (state.processingState == ProcessingState.completed) { if (state.processingState == ProcessingState.completed) {
await audioPlayer.seek(Duration.zero); await audioPlayer.seek(Duration.zero);

4
lib/modules/meeting/controllers/meeting_edit_controller.dart

@ -3,7 +3,6 @@ import 'package:get/get.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import '../../../data/services/db/sqflite_api.dart'; import '../../../data/services/db/sqflite_api.dart';
import '../../../data/services/speech_impl/volcano_tts_api_service.dart';
import 'meeting_controller.dart'; import 'meeting_controller.dart';
import 'meeting_details_controller.dart'; import 'meeting_details_controller.dart';
@ -53,7 +52,7 @@ class MeetingEditController extends GetxController
); );
creationTime = meetingDetailsController.meetingData.value.creationtime; creationTime = meetingDetailsController.meetingData.value.creationtime;
audioPlayer.setAudioSource( audioPlayer.setAudioSource(
BytesAudioSource(meetingDetailsController.dataDetails.value.audio)); AudioSource.file(meetingDetailsController.dataDetails.value.audio));
audioPlayer.playerStateStream.listen((state) async { audioPlayer.playerStateStream.listen((state) async {
if (state.processingState == ProcessingState.completed) { if (state.processingState == ProcessingState.completed) {
await audioPlayer.seek(Duration.zero); await audioPlayer.seek(Duration.zero);
@ -71,7 +70,6 @@ class MeetingEditController extends GetxController
isPlay.value = false; isPlay.value = false;
} else { } else {
lottieController.repeat(); lottieController.repeat();
await audioPlayer.seek(Duration.zero);
audioPlayer.play(); audioPlayer.play();
isPlay.value = true; isPlay.value = true;
} }

38
lib/modules/meeting/controllers/meeting_record_controller.dart

@ -1,9 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../../core/utils/logger.dart';
import '../../../data/services/asr_service.dart'; import '../../../data/services/asr_service.dart';
import '../../../data/services/db/sqflite_api.dart'; import '../../../data/services/db/sqflite_api.dart';
import '../../../data/services/speech_impl/xunfei_asr_service.dart'; import '../../../data/services/speech_impl/xunfei_asr_service.dart';
@ -34,6 +38,7 @@ class MeetingRecordController extends GetxController
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
Permission.storage.request();
lottieController = AnimationController(vsync: this); lottieController = AnimationController(vsync: this);
Get.put(XunfeiAsrService()); Get.put(XunfeiAsrService());
_asrService = Get.find<XunfeiAsrService>(); _asrService = Get.find<XunfeiAsrService>();
@ -144,6 +149,20 @@ class MeetingRecordController extends GetxController
// 完成 // 完成
void complete() async { void complete() async {
if (await Permission.storage.request().isGranted) {
_save();
} else {
Get.snackbar(
'error'.tr, // 错误
'请开启文件存储权限',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
}
}
void _save() async {
String firstContent = finalContent.value.length >= 30 String firstContent = finalContent.value.length >= 30
? finalContent.value.substring(0, 30) ? finalContent.value.substring(0, 30)
: finalContent.value; : finalContent.value;
@ -155,12 +174,15 @@ class MeetingRecordController extends GetxController
dataLength: audio.length, dataLength: audio.length,
); );
Uint8List wavData = Uint8List.fromList([...wavHeader, ...audio]); Uint8List wavData = Uint8List.fromList([...wavHeader, ...audio]);
String audiopPath =
await _saveAudioToFile(wavData, 'meeting_$creationTime.wav');
if (audiopPath.isEmpty) return;
Map<String, Object?> data = { Map<String, Object?> data = {
'title': title, 'title': title,
'firstContent': firstContent.replaceAll("\n", ""), 'firstContent': firstContent.replaceAll("\n", ""),
'seconds': seconds.value, 'seconds': seconds.value,
'creationTime': creationTime, 'creationTime': creationTime,
'audio': wavData, 'audio': audiopPath,
'content': finalContent.value, 'content': finalContent.value,
}; };
final result = await SqfliteApi.insertMeeting(data); final result = await SqfliteApi.insertMeeting(data);
@ -176,6 +198,20 @@ class MeetingRecordController extends GetxController
} }
} }
Future<String> _saveAudioToFile(Uint8List audioData, String fileName) async {
try {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/$fileName');
// 写入文件
await file.writeAsBytes(audioData);
return file.path;
} catch (e) {
Logger.error('保存失败: $e');
return '';
}
}
Uint8List generateWavHeader({ Uint8List generateWavHeader({
required int sampleRate, required int sampleRate,
required int numberOfChannels, required int numberOfChannels,

4
lib/modules/meeting/model/meeting_details_model.dart

@ -1,11 +1,9 @@
import 'dart:typed_data';
class MeetingDetailsModel { class MeetingDetailsModel {
MeetingDetailsModel(); MeetingDetailsModel();
late int id; late int id;
late int meetingid; late int meetingid;
late Uint8List audio; late String audio;
late String content; late String content;
factory MeetingDetailsModel.fromJson(Map<String, dynamic> map) => factory MeetingDetailsModel.fromJson(Map<String, dynamic> map) =>

246
lib/modules/meeting/views/meeting_record_view.dart

@ -90,86 +90,36 @@ class MeetingRecordView extends GetView<MeetingRecordController> {
// 构建主体内容 // 构建主体内容
Widget _buildBody(bool isDarkMode) { Widget _buildBody(bool isDarkMode) {
return Padding( return Column(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.w), crossAxisAlignment: CrossAxisAlignment.start,
child: Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, 10.verticalSpace,
children: [ Padding(
Text( padding: EdgeInsets.symmetric(horizontal: 12.w),
child: Text(
controller.title, controller.title,
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 17.sp, fontSize: 17.sp,
), ),
), ),
Padding( ),
padding: EdgeInsets.symmetric(vertical: 5.w), Padding(
child: Text( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.w),
DateUtil.formatDateMs( child: Text(
controller.creationTime, DateUtil.formatDateMs(
format: DateFormats.y_mo_d_h_m, controller.creationTime,
), format: DateFormats.y_mo_d_h_m,
style: TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
fontSize: 14.sp,
),
),
),
_audioWave(isDarkMode),
_recordContent(isDarkMode),
_bottomButton(isDarkMode),
],
),
);
}
// 音波
Widget _audioWave(bool isDarkMode) {
return Container(
width: double.infinity,
height: 70.w,
margin: EdgeInsets.symmetric(vertical: 5.w),
decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white,
borderRadius: BorderRadius.circular(12.w),
boxShadow: [
BoxShadow(
color: isDarkMode
? Colors.black.withOpacity(0.2)
: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
Expanded(
child: Lottie.asset(
'assets/lottie/audio_wave.json',
controller: controller.lottieController,
fit: BoxFit.fill,
onLoaded: (composition) {
controller.lottieController.duration = composition.duration;
},
),
),
Expanded(
child: Lottie.asset(
'assets/lottie/audio_wave.json',
controller: controller.lottieController,
fit: BoxFit.fill,
), ),
), style: TextStyle(
Expanded( color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
child: Lottie.asset( fontSize: 14.sp,
'assets/lottie/audio_wave.json',
controller: controller.lottieController,
fit: BoxFit.fill,
), ),
), ),
], ),
), _recordContent(isDarkMode),
_bottomButton(isDarkMode),
],
); );
} }
@ -179,7 +129,7 @@ class MeetingRecordView extends GetView<MeetingRecordController> {
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: EdgeInsets.all(10.w), padding: EdgeInsets.all(10.w),
margin: EdgeInsets.symmetric(vertical: 5.w), margin: EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white,
borderRadius: BorderRadius.circular(12.w), borderRadius: BorderRadius.circular(12.w),
@ -210,51 +160,121 @@ class MeetingRecordView extends GetView<MeetingRecordController> {
// 底部按钮 // 底部按钮
Widget _bottomButton(bool isDarkMode) { Widget _bottomButton(bool isDarkMode) {
return Padding( return Container(
padding: EdgeInsets.only(top: 40.w, bottom: 30.w), margin: EdgeInsets.only(top: 10.h),
child: Row( decoration: BoxDecoration(
mainAxisAlignment: MainAxisAlignment.spaceBetween, color: isDarkMode ? AppColors.cardBackground : Colors.white,
children: [ boxShadow: [
GestureDetector( BoxShadow(
onTap: controller.recorderHandle, color: Colors.black.withOpacity(0.05),
child: Container( blurRadius: 3,
width: 130.w, offset: const Offset(0, -1),
height: 60.w, ),
decoration: BoxDecoration( ],
borderRadius: BorderRadius.circular(60.w), ),
border: Border.all( child: SafeArea(
color: isDarkMode ? AppColors.primary : Colors.blue, child: SizedBox(
width: 2.w, height: 80.h,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// 语音录制按钮
Container(
width: 60.r,
height: 60.r,
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.white,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
spreadRadius: 1,
),
],
),
child: Center(
child: Obx(
() => IconButton(
icon: Icon(
controller.isRecording.value
? Icons.mic
: Icons.mic_none,
),
color: controller.isRecording.value
? AppColors.primary
: Colors.grey.shade400,
iconSize: 28.r,
padding: EdgeInsets.zero,
onPressed: controller.recorderHandle,
),
),
),
), ),
), 10.horizontalSpace,
child: Obx( Expanded(
() => Icon( child: Lottie.asset(
controller.isRecording.value ? Icons.pause : Icons.play_arrow, 'assets/lottie/audio_wave.json',
color: isDarkMode ? AppColors.primary : Colors.blue, controller: controller.lottieController,
size: 40.w, fit: BoxFit.fill,
onLoaded: (composition) {
controller.lottieController.duration =
composition.duration;
},
),
), ),
), Expanded(
), child: Lottie.asset(
), 'assets/lottie/audio_wave.json',
GestureDetector( controller: controller.lottieController,
onTap: () { fit: BoxFit.fill,
_showAlertDialog(isDarkMode); onLoaded: (composition) {
}, controller.lottieController.duration =
child: Container( composition.duration;
width: 130.w, },
height: 60.w, ),
decoration: BoxDecoration( ),
color: isDarkMode ? AppColors.primary : Colors.blue, 10.horizontalSpace,
borderRadius: BorderRadius.circular(60.w), // 关闭按钮
), Container(
child: Icon( width: 60.r,
Icons.fiber_manual_record_outlined, height: 60.r,
color: Colors.white, decoration: BoxDecoration(
size: 40.w, color: isDarkMode
), ? Colors.white.withOpacity(0.1)
: Colors.white,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
spreadRadius: 1,
),
],
),
child: Center(
child: IconButton(
icon: Icon(
Icons.close,
color: isDarkMode ? Colors.white : Colors.grey.shade600,
size: 28.r,
),
padding: EdgeInsets.zero,
onPressed: () {
_showAlertDialog(isDarkMode);
},
),
),
),
],
), ),
), ),
], ),
), ),
); );
} }

6
lib/modules/meeting/views/meeting_view.dart

@ -82,7 +82,7 @@ class MeetingView extends GetView<MeetingController> {
const Icon(Icons.keyboard_voice, color: Colors.white), const Icon(Icons.keyboard_voice, color: Colors.white),
5.horizontalSpace, 5.horizontalSpace,
Text( Text(
'录音', '开始会议',
style: TextStyle(color: Colors.white, fontSize: 16.sp), style: TextStyle(color: Colors.white, fontSize: 16.sp),
), ),
], ],
@ -264,7 +264,7 @@ class MeetingView extends GetView<MeetingController> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
id != null ? '修改录音标题(非必填)' : '录音标题(非必填)', id != null ? '修改会议标题(非必填)' : '会议标题(非必填)',
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 16.sp, fontSize: 16.sp,
@ -347,7 +347,7 @@ class MeetingView extends GetView<MeetingController> {
} else { } else {
if (title.isEmpty) { if (title.isEmpty) {
title = title =
'${DateUtil.formatDateMs(time, format: DateFormats.y_mo_d)} 录音'; '${DateUtil.formatDateMs(time, format: DateFormats.y_mo_d)} 会议';
} }
Get.back(); Get.back();
Get.toNamed(Routes.meetingRecord, arguments: { Get.toNamed(Routes.meetingRecord, arguments: {

4
lib/modules/profile/views/profile_view.dart

@ -150,8 +150,8 @@ class EditProfileView extends GetView<ProfileController> {
backgroundColor: isDarkMode ? Colors.black : Colors.white, backgroundColor: isDarkMode ? Colors.black : Colors.white,
leading: IconButton( leading: IconButton(
icon: Icon( icon: Icon(
Icons.arrow_back, Icons.arrow_back_ios,
size: 24.sp, size: 20.sp,
color: isDarkMode? Colors.white : Colors.black, color: isDarkMode? Colors.white : Colors.black,
), ),
onPressed: () => Get.back(), onPressed: () => Get.back(),

136
lib/modules/settings/views/settings_view.dart

@ -45,6 +45,8 @@ class SettingsView extends GetView<SettingsController> {
children: [ children: [
_buildUserInfoCard(isDarkMode), _buildUserInfoCard(isDarkMode),
SizedBox(height: 20.h), SizedBox(height: 20.h),
_buildAISettingsSection(isDarkMode),
SizedBox(height: 20.h),
_buildSystemSettingsSection(isDarkMode), _buildSystemSettingsSection(isDarkMode),
SizedBox(height: 20.h), SizedBox(height: 20.h),
_buildAboutSection(isDarkMode), _buildAboutSection(isDarkMode),
@ -110,12 +112,12 @@ class SettingsView extends GetView<SettingsController> {
// 裁剪圆形头像 // 裁剪圆形头像
borderRadius: BorderRadius.circular(30.r), borderRadius: BorderRadius.circular(30.r),
child: controller.userInfo.value.avatar.isEmpty child: controller.userInfo.value.avatar.isEmpty
? ?
// Image.network( // Image.network(
// 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80', // 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80',
// fit: BoxFit.cover, // 图片填充方式 // fit: BoxFit.cover, // 图片填充方式
// ) // )
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blue[600], color: Colors.blue[600],
borderRadius: BorderRadius.circular(30.r), borderRadius: BorderRadius.circular(30.r),
@ -142,12 +144,15 @@ class SettingsView extends GetView<SettingsController> {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blue[600], color: Colors.blue[600],
borderRadius: BorderRadius.circular(30.r), borderRadius:
BorderRadius.circular(30.r),
), ),
child: Center( child: Center(
child: Text( child: Text(
controller.userInfo.value.name.isNotEmpty controller.userInfo.value.name
? controller.userInfo.value.name[0] .isNotEmpty
? controller
.userInfo.value.name[0]
.toUpperCase() .toUpperCase()
: '?', : '?',
style: TextStyle( style: TextStyle(
@ -266,6 +271,82 @@ class SettingsView extends GetView<SettingsController> {
); );
} }
// AI设置
Widget _buildAISettingsSection(bool isDarkMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text(
'AI设置',
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.blue[400] : Colors.blue[600],
letterSpacing: 1,
),
),
),
Container(
decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white,
borderRadius: BorderRadius.circular(16.r),
boxShadow: [
BoxShadow(
color: isDarkMode
? Colors.black.withOpacity(0.2)
: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16.r),
child: BackdropFilter(
filter: isDarkMode
? ImageFilter.blur(sigmaX: 5, sigmaY: 5)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Column(
children: [
// 语音服务选择
_buildSpeechServiceSetting(isDarkMode),
Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
Obx(
() => _buildNavigationSetting(
title: 'timbreService'.tr, // 音色服务
subtitle: 'timbreServiceInfo'.tr, // 选择音色服务
icon: Icons.photo_camera_front_outlined,
iconBgColor: isDarkMode
? Colors.cyan[900]!.withOpacity(0.3)
: Colors.cyan[100]!,
iconColor:
isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!,
value: controller.timbreName.value.tr,
valueStyle: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[500],
),
onTap: () {
Get.toNamed(Routes.timbre);
},
isDarkMode: isDarkMode,
),
),
],
),
),
),
),
],
);
}
// 系统设置部分 // 系统设置部分
Widget _buildSystemSettingsSection(bool isDarkMode) { Widget _buildSystemSettingsSection(bool isDarkMode) {
return Column( return Column(
@ -370,46 +451,13 @@ class SettingsView extends GetView<SettingsController> {
), ),
onTap: () { onTap: () {
// 打开备份设置页面 // 打开备份设置页面
print('---------用户头像-${controller.userInfo.value.avatar}'); print(
'---------用户头像-${controller.userInfo.value.avatar}');
print('---------用户名-${controller.userInfo.value.name}'); print('---------用户名-${controller.userInfo.value.name}');
//print('user${User.instance.value}'); //print('user${User.instance.value}');
}, },
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
), ),
Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 语音服务选择
_buildSpeechServiceSetting(isDarkMode),
Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
Obx(
() => _buildNavigationSetting(
title: 'timbreService'.tr, // 音色服务
subtitle: 'timbreServiceInfo'.tr, // 选择音色服务
icon: Icons.photo_camera_front_outlined,
iconBgColor: isDarkMode
? Colors.cyan[900]!.withOpacity(0.3)
: Colors.cyan[100]!,
iconColor:
isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!,
value: controller.timbreName.value.tr,
valueStyle: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[500],
),
onTap: () {
Get.toNamed(Routes.timbre);
},
isDarkMode: isDarkMode,
),
),
Divider( Divider(
height: 1, height: 1,
color: isDarkMode color: isDarkMode

Loading…
Cancel
Save