Browse Source

Merge commit '8bc7569526b114660a1716e52396342c55cd078a' into lxm

newdev_shunjiawei
lxm 2 years ago
parent
commit
3755f9af00
  1. 104
      lib/data/models/user_Info.dart
  2. 25
      lib/data/services/login_service.dart
  3. 31
      lib/data/services/network/api.dart
  4. 65
      lib/data/services/network/auth_interceptor.dart
  5. 45
      lib/data/services/network/dio_manager.dart
  6. 17
      lib/data/services/network/entity/base_entity.dart
  7. 9
      lib/data/services/network/entity/entity_factory.dart
  8. 4
      lib/data/services/network/nw_api.dart
  9. 8
      lib/data/services/network/nw_method.dart
  10. 25
      lib/main.dart
  11. 12
      lib/modules/login/controllers/facebookLogin.dart
  12. 11
      lib/modules/login/controllers/googleLogin.dart
  13. 254
      lib/modules/login/controllers/login_controller.dart
  14. 126
      lib/modules/login/controllers/weixinLogin.dart
  15. 32
      lib/modules/login/entity/api.dart
  16. 45
      lib/modules/login/entity/dio_manager.dart
  17. 4
      lib/modules/login/entity/nw_api.dart
  18. 8
      lib/modules/login/entity/nw_method.dart
  19. 32
      lib/modules/login/views/login_view.dart
  20. 10
      lib/modules/meeting/bindings/meeting_record_binding.dart
  21. 17
      lib/modules/meeting/controllers/meeting_controller.dart
  22. 98
      lib/modules/meeting/controllers/meeting_record_controller.dart
  23. 26
      lib/modules/meeting/model/meeting_details_model.dart
  24. 29
      lib/modules/meeting/model/meeting_model.dart
  25. 320
      lib/modules/meeting/views/meeting_record_view.dart
  26. 428
      lib/modules/meeting/views/meeting_view.dart
  27. 738
      lib/modules/settings/views/settings_view.dart
  28. 12
      lib/routes/app_pages.dart
  29. 5
      lib/routes/app_routes.dart
  30. 4
      pubspec.yaml

104
lib/data/models/user_Info.dart

@ -0,0 +1,104 @@
import 'dart:convert';
import 'dart:ffi';
class User {
// 单例实例
static User? _instance;
// 单例访问器(增加空安全保护)
static User get instance {
if (_instance == null) {
throw Exception("User must be initialized first");
}
return _instance!;
}
// 最终属性(不可变)
String name;
String uid;
String avatar;
String deviceid;
String language;
String token;
String mail;
String phone;
String phonemac;
String password;
// final Int64 lastbettime;
// final Int64 createtime;
// final String wxopenid;
// final String googleopenid;
// final String facebookopenid;
// 私有构造函数
User._({
required this.name,
required this.uid,
required this.avatar,
required this.deviceid,
required this.language,
required this.token,
required this.mail,
required this.phone,
required this.phonemac,
required this.password,
// required this.lastbettime,
// required this.createtime,
// required this.wxopenid,
// required this.googleopenid,
// required this.facebookopenid,
});
factory User.fromJson(Map<String, dynamic> json) {
// 修复1:安全获取嵌套的 user 字段
final userData = json['data']['user'] as Map<String, dynamic>?; // 允许空值
final token = json['data']['token'] as String? ?? '';
// 更新单例实例
return _instance = User._(
token: token as String? ?? '',
name: (userData?['name'] as String?) ?? '默认名称', // 提供默认值
uid: (userData?['uid'] as String?) ?? '',
avatar: (userData?['avatar'] as String?) ?? '',
deviceid: (userData?['deviceid'] as String?) ?? '',
language: (userData?['language'] as String?) ?? 'en',
mail: (userData?['mail'] as String?) ?? '',
phone: (userData?['phone'] as String?) ?? '',
phonemac: (userData?['phonemac'] as String?) ?? '',
password: (userData?['password'] as String?) ?? '',
// lastbettime: _parseTimestamp(userData['lastbettime']),
// createtime: _parseTimestamp(userData['createtime']),
// wxopenid: (userData?['wxopenid'] as String?) ?? '',
// googleopenid: (userData?['googleopenid'] as String?) ?? '',
// facebookopenid: (userData?['facebookopenid'] as String?) ?? '',
);
}
// 完整的JSON序列化
Map<String, dynamic> toJson() => {
'user': {
'name': name,
'uid': uid,
'avatar': avatar,
'deviceid': deviceid,
'language': language,
'token': token,
'mail': mail,
'phone': phone,
'phonemac': phonemac,
'password': password,
// 'lastbettime': lastbettime,
// 'createtime': createtime,
// 'wxopenid': wxopenid,
// 'googleopenid': googleopenid,
// 'facebookopenid': facebookopenid,
}
};
// 获取用户名的快捷方法
static String getname() => instance.name;
static String getdeviceInfo() => instance.deviceid;
static String getuserId() => instance.uid;
static String getstanding() => "";
static String getnavatar() => instance.avatar;
}

25
lib/data/services/login_service.dart

@ -0,0 +1,25 @@
import '../../modules/login/controllers/weixinLogin.dart';
import 'package:firebase_core/firebase_core.dart';
import '/firebase_options.dart';
class LoginService {
LoginService() {
//微信
FlWX().register(
appSecret: '4cfde33bc22b6cc6b1f8b225dd97d255',
appId: 'wx5bbb7be9324f3e2d',
params: FlWXCallbackParams(onHttp: (url) async {
return '';
}));
if (Firebase.apps.isEmpty) {
Firebase.initializeApp(
name: 'DeepSound',
options: DefaultFirebaseOptions.currentPlatform,
//demoProjectId:'1:907754492821:android:2deffc5aa1037ae2145c9c'
).then((value) {
print('Firebase Initialized:${value.options}');
});
}
}
}

31
lib/data/services/network/api.dart

@ -0,0 +1,31 @@
import 'dio_manager.dart';
import 'nw_method.dart';
class Api {
// 登录
static login([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/user_sgin',
params: params,
);
}
// 获取验证码
static getCode([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/user_verification',
params: params,
);
}
// 获取阿里token
static getAliToken([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/auth_alitoken',
params: params,
);
}
}

65
lib/data/services/network/auth_interceptor.dart

@ -0,0 +1,65 @@
// import 'package:dio/dio.dart';
// import 'package:flutter_easyloading/flutter_easyloading.dart';
// import 'package:get/get.dart' hide Response;
// import '../scenes/start/start_logic.dart';
// import 'entity/base_entity.dart';
// class AuthInterceptor extends Interceptor {
// final state = Get.find<StartLogic>().state;
// @override
// void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// options.headers['Authorization'] = state.loginModel.token;
// handler.next(options);
// }
// @override
// void onResponse(Response response, ResponseInterceptorHandler handler) async {
// BaseEntity entity = BaseEntity.fromJson(response.data);
// if (entity.code == 0) {
// response.data = entity.data ?? {};
// handler.resolve(response);
// } else {
// response.data = null;
// handler.next(response);
// return EasyLoading.showError(entity.message ?? 'unknownError'.tr);
// }
// }
// @override
// void onError(DioException err, ErrorInterceptorHandler handler) {
// switch (err.type) {
// case DioExceptionType.cancel:
// {
// EasyLoading.showError('requestCancellation'.tr);
// }
// case DioExceptionType.connectionTimeout:
// {
// EasyLoading.showError('connectionTimeout'.tr);
// }
// case DioExceptionType.sendTimeout:
// {
// EasyLoading.showError('requestTimeout'.tr);
// }
// case DioExceptionType.receiveTimeout:
// {
// EasyLoading.showError('responseTimeout'.tr);
// }
// case DioExceptionType.badResponse:
// {
// try {
// String? errMsg = err.response?.statusMessage;
// EasyLoading.showError(errMsg ?? 'unknownError'.tr);
// } on Exception catch (_) {
// EasyLoading.showError('unknownError'.tr);
// }
// }
// default:
// {
// EasyLoading.showError(err.message ?? 'unknownError'.tr);
// }
// }
// handler.next(err);
// }
// }

45
lib/data/services/network/dio_manager.dart

@ -0,0 +1,45 @@
import 'package:dio/dio.dart';
import 'auth_interceptor.dart';
import 'nw_api.dart';
import 'nw_method.dart';
class DioManager {
static final DioManager _shared = DioManager._internal();
factory DioManager() => _shared;
late Dio dio;
DioManager._internal() {
BaseOptions options = BaseOptions(
baseUrl: NWApi.baseApi,
contentType: Headers.jsonContentType,
responseType: ResponseType.json,
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
);
dio = Dio(options);
// dio.interceptors.add(AuthInterceptor());
}
// 请求,返回参数为 T
// method:请求方法,NWMethod.POST等
// path:请求地址
// params:请求参数
Future request<T>(
NWMethod method,
String path, {
Map? params,
Map<String, dynamic>? queryParameters,
}) async {
Response response = await dio.request(
path,
data: params,
queryParameters: queryParameters,
options: Options(method: nwMethodValues[method]),
);
return response.data;
}
}

17
lib/data/services/network/entity/base_entity.dart

@ -0,0 +1,17 @@
import 'entity_factory.dart';
class BaseEntity<T> {
int? code;
String? message;
T? data;
BaseEntity({this.code, this.message, this.data});
factory BaseEntity.fromJson(json) {
return BaseEntity(
code: json["code"],
message: json["msg"],
data: EntityFactory.generateOBJ<T>(json["data"]),
);
}
}

9
lib/data/services/network/entity/entity_factory.dart

@ -0,0 +1,9 @@
class EntityFactory {
static T? generateOBJ<T>(json) {
if (json == null) {
return null;
} else {
return json as T;
}
}
}

4
lib/data/services/network/nw_api.dart

@ -0,0 +1,4 @@
class NWApi {
// static const baseApi = "https://www.deapsound.com";
static const baseApi = "https://www.deapsound.com";
}

8
lib/data/services/network/nw_method.dart

@ -0,0 +1,8 @@
enum NWMethod { get, post, delete, put }
const nwMethodValues = {
NWMethod.get: "get",
NWMethod.post: "post",
NWMethod.delete: "delete",
NWMethod.put: "put"
};

25
lib/main.dart

@ -12,9 +12,7 @@ import 'package:window_size/window_size.dart';
import 'core/translations/app_translations.dart'; import 'core/translations/app_translations.dart';
import 'core/themes/app_theme.dart'; import 'core/themes/app_theme.dart';
import 'core/themes/theme_service.dart'; import 'core/themes/theme_service.dart';
import 'modules/login/controllers/weixinLogin.dart'; import '../../data/services/login_service.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async { void main() async {
// 确保Flutter绑定初始化 // 确保Flutter绑定初始化
@ -25,26 +23,7 @@ void main() async {
// 初始化环境变量 // 初始化环境变量
await dotenv.load(); await dotenv.load();
LoginService();
FlWX().register(
appSecret: '4cfde33bc22b6cc6b1f8b225dd97d255',
appId: 'wx5bbb7be9324f3e2d',
params: FlWXCallbackParams(onHttp: (url) async {
return '';
}));
var err = FlWX().isInstalled;
String msg = err.toString() == 'false' ? '请先下载微信app' : '请授权登录';
print(msg);
if (Firebase.apps.isEmpty) {
await Firebase.initializeApp(
name: 'DeepSound',
options: DefaultFirebaseOptions.currentPlatform,
//demoProjectId:'1:907754492821:android:2deffc5aa1037ae2145c9c'
).then((value) {
// logger.i('Firebase Initialized:${value.options}');
print('Firebase Initialized:${value.options}');
});
}
// 设置窗口大小(仅在 macOS 下生效) // 设置窗口大小(仅在 macOS 下生效)
if (Platform.isMacOS) { if (Platform.isMacOS) {

12
lib/modules/login/controllers/facebookLogin.dart

@ -4,6 +4,12 @@ import 'package:get/get.dart';
class Facebook { class Facebook {
String token = ''; String token = '';
String name = '';
String email = '';
String pictureurl = '';
String id = '';
// FaceBook登录 // FaceBook登录
// 修改后的 signInWithFacebook // 修改后的 signInWithFacebook
Future<bool> signInWithFacebook() async { Future<bool> signInWithFacebook() async {
@ -19,7 +25,13 @@ class Facebook {
final credential = FacebookAuthProvider.credential(token); final credential = FacebookAuthProvider.credential(token);
print("Facebook Token: $credential"); print("Facebook Token: $credential");
final userData = await FacebookAuth.instance.getUserData(); final userData = await FacebookAuth.instance.getUserData();
name = userData["name"].toString();
email = userData["email"].toString();
pictureurl = userData["picture"]["data"]["url"].toString();
id = userData["id"].toString();
print("user login facebook ${userData..values}"); print("user login facebook ${userData..values}");
print("user login facebook ${email}${pictureurl}${name}${id}");
return true; return true;
} else { } else {

11
lib/modules/login/controllers/googleLogin.dart

@ -13,14 +13,19 @@ class Google {
Future<bool> signInWithGoogle() async { Future<bool> signInWithGoogle() async {
try { try {
// 确保用户已经登录,并获取当前用户的身份验证令牌 // 确保用户已经登录,并获取当前用户的身份验证令牌
final currentUser = FirebaseAuth.instance.currentUser; final currentUser = FirebaseAuth.instance.currentUser;
print('Future响应数据: $currentUser'); print('Future响应数据: $currentUser');
if (currentUser != null) { if (currentUser != null) {
// 这里处理您需要使用这个JWT令牌的逻辑,例如将它存储到本地存储中作为凭据。 // 这里处理您需要使用这个JWT令牌的逻辑,例如将它存储到本地存储中作为凭据。
email = currentUser.email;
token != await currentUser.getIdToken(); displayName = currentUser.displayName;
id = currentUser.uid;
token = await currentUser.getIdToken();
print('Future响应数据tokenResult: $token'); print('Future响应数据tokenResult: $token');
// IdTokenResult token1 = await currentUser.getIdTokenResult();
// print('Future响应数据token1: $token1');
return true; return true;
} else { } else {
@ -47,6 +52,8 @@ class Google {
id = googleUser?.id; id = googleUser?.id;
displayName = googleUser?.displayName; displayName = googleUser?.displayName;
print('loginGoogle: $googleUser'); print('loginGoogle: $googleUser');
print("user login loginGoogle ${email}${id}${displayName}");
// Obtain the auth details from the request // Obtain the auth details from the request
final GoogleSignInAuthentication? googleAuth = final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication; await googleUser?.authentication;

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

@ -1,15 +1,25 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../routes/app_routes.dart'; import '../../../routes/app_routes.dart';
import 'dart:convert';
import 'dart:ffi';
import '../../settings/controllers/settings_controller.dart';
import 'facebookLogin.dart';
import 'googleLogin.dart';
import 'weixinLogin.dart';
import '../entity/api.dart';
import '../../../../data/models/user_Info.dart';
//import 'package:shared_preferences/shared_preferences.dart';
import 'package:get_storage/get_storage.dart';
enum LoginViewState { enum LoginViewState {
welcome, // 欢迎页面 welcome, // 欢迎页面
verification // 验证码页面 verification // 验证码页面
} }
class LoginController extends GetxController { class LoginController extends GetxController {
static LoginController get to => Get.find(); static LoginController get to => Get.find();
final GetStorage _storage = GetStorage();
// 状态管理 // 状态管理
final _viewState = LoginViewState.welcome.obs; final _viewState = LoginViewState.welcome.obs;
final _isLoading = false.obs; final _isLoading = false.obs;
@ -17,7 +27,7 @@ class LoginController extends GetxController {
final _contactValue = ''.obs; final _contactValue = ''.obs;
final _displayContact = ''.obs; final _displayContact = ''.obs;
final _verificationCode = ['', '', '', ''].obs; final _verificationCode = ['', '', '', ''].obs;
int loginType = -1;
// Getters // Getters
LoginViewState get viewState => _viewState.value; LoginViewState get viewState => _viewState.value;
bool get isLoading => _isLoading.value; bool get isLoading => _isLoading.value;
@ -25,29 +35,29 @@ class LoginController extends GetxController {
String get contactValue => _contactValue.value; String get contactValue => _contactValue.value;
String get displayContact => _displayContact.value; String get displayContact => _displayContact.value;
List<String> get verificationCode => _verificationCode; List<String> get verificationCode => _verificationCode;
// 文本控制器 // 文本控制器
final contactController = TextEditingController(); final contactController = TextEditingController();
final verificationCodeController = TextEditingController(); final verificationCodeController = TextEditingController();
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
_viewState.value = LoginViewState.welcome; _viewState.value = LoginViewState.welcome;
} }
@override @override
void onClose() { void onClose() {
contactController.dispose(); contactController.dispose();
verificationCodeController.dispose(); verificationCodeController.dispose();
super.onClose(); super.onClose();
} }
// 获取验证码 // 获取验证码
void getVerificationCode() { void getVerificationCode() {
if (contactController.text.isEmpty) { if (contactController.text.isEmpty) {
Get.snackbar( Get.snackbar(
'提示', '提示',
'请输入手机号码或邮箱', '请输入手机号码或邮箱',
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1), backgroundColor: Colors.red.withOpacity(0.1),
@ -55,19 +65,19 @@ class LoginController extends GetxController {
); );
return; return;
} }
_contactValue.value = contactController.text; _contactValue.value = contactController.text;
_formatDisplayContact(); _formatDisplayContact();
_startCountdown(); _startCountdown();
_sendVerificationCode(); _sendVerificationCode();
} }
// 使用验证码直接登录 // 使用验证码直接登录
void loginWithVerificationCode() { void loginWithVerificationCode() {
//测试期间暂时关闭验证码登录 //测试期间暂时关闭验证码登录
// if (contactController.text.isEmpty) { // if (contactController.text.isEmpty) {
// Get.snackbar( // Get.snackbar(
// '提示', // '提示',
// '请输入手机号码或邮箱', // '请输入手机号码或邮箱',
// snackPosition: SnackPosition.TOP, // snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1), // backgroundColor: Colors.red.withOpacity(0.1),
@ -75,10 +85,10 @@ class LoginController extends GetxController {
// ); // );
// return; // return;
// } // }
// if (verificationCodeController.text.isEmpty) { // if (verificationCodeController.text.isEmpty) {
// Get.snackbar( // Get.snackbar(
// '提示', // '提示',
// '请输入验证码', // '请输入验证码',
// snackPosition: SnackPosition.TOP, // snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1), // backgroundColor: Colors.red.withOpacity(0.1),
@ -86,10 +96,10 @@ class LoginController extends GetxController {
// ); // );
// return; // return;
// } // }
// if (verificationCodeController.text.length < 6) { // if (verificationCodeController.text.length < 6) {
// Get.snackbar( // Get.snackbar(
// '提示', // '提示',
// '请输入完整的验证码', // '请输入完整的验证码',
// snackPosition: SnackPosition.TOP, // snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1), // backgroundColor: Colors.red.withOpacity(0.1),
@ -97,9 +107,9 @@ class LoginController extends GetxController {
// ); // );
// return; // return;
// } // }
_isLoading.value = true; _isLoading.value = true;
// 模拟验证过程 // 模拟验证过程
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
_isLoading.value = false; _isLoading.value = false;
@ -107,12 +117,12 @@ class LoginController extends GetxController {
Get.offAllNamed(Routes.pairing); Get.offAllNamed(Routes.pairing);
}); });
} }
// 切换到验证码页面 // 切换到验证码页面
void showVerificationView() { void showVerificationView() {
if (contactController.text.isEmpty) { if (contactController.text.isEmpty) {
Get.snackbar( Get.snackbar(
'提示', '提示',
'请输入手机号码或邮箱', '请输入手机号码或邮箱',
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1), backgroundColor: Colors.red.withOpacity(0.1),
@ -120,33 +130,38 @@ class LoginController extends GetxController {
); );
return; return;
} }
_contactValue.value = contactController.text; _contactValue.value = contactController.text;
_formatDisplayContact(); _formatDisplayContact();
_viewState.value = LoginViewState.verification; _viewState.value = LoginViewState.verification;
_startCountdown(); _startCountdown();
_sendVerificationCode(); _sendVerificationCode();
} }
// 返回欢迎页面 // 返回欢迎页面
void showWelcomeView() { void showWelcomeView() {
_viewState.value = LoginViewState.welcome; _viewState.value = LoginViewState.welcome;
_resetVerificationCode(); _resetVerificationCode();
} }
// 格式化显示的联系方式(隐藏部分字符) // 格式化显示的联系方式(隐藏部分字符)
void _formatDisplayContact() { void _formatDisplayContact() {
String contact = _contactValue.value; String contact = _contactValue.value;
if (contact.contains('@')) { // 邮箱 if (contact.contains('@')) {
// 邮箱
final parts = contact.split('@'); final parts = contact.split('@');
if (parts[0].length > 3) { if (parts[0].length > 3) {
_displayContact.value = parts[0].substring(0, 3) + '****@' + parts[1]; _displayContact.value = parts[0].substring(0, 3) + '****@' + parts[1];
} else { } else {
_displayContact.value = contact; _displayContact.value = contact;
} }
} else if (RegExp(r'^\d+$').hasMatch(contact)) { // 手机号 } else if (RegExp(r'^\d+$').hasMatch(contact)) {
// 手机号
if (contact.length > 7) { if (contact.length > 7) {
_displayContact.value = '+86 ' + contact.substring(0, 3) + '****' + contact.substring(contact.length - 4); _displayContact.value = '+86 ' +
contact.substring(0, 3) +
'****' +
contact.substring(contact.length - 4);
} else { } else {
_displayContact.value = contact; _displayContact.value = contact;
} }
@ -154,7 +169,7 @@ class LoginController extends GetxController {
_displayContact.value = contact; _displayContact.value = contact;
} }
} }
// 开始倒计时 // 开始倒计时
void _startCountdown() { void _startCountdown() {
_countdownSeconds.value = 60; _countdownSeconds.value = 60;
@ -164,20 +179,20 @@ class LoginController extends GetxController {
return _countdownSeconds.value > 0; return _countdownSeconds.value > 0;
}); });
} }
// 发送验证码 // 发送验证码
void _sendVerificationCode() { void _sendVerificationCode() {
// 这里应该是实际发送验证码的逻辑 // 这里应该是实际发送验证码的逻辑
// 为了演示,我们只是模拟发送 // 为了演示,我们只是模拟发送
} }
// 重新发送验证码 // 重新发送验证码
void resendVerificationCode() { void resendVerificationCode() {
if (_countdownSeconds.value > 0) return; if (_countdownSeconds.value > 0) return;
_startCountdown(); _startCountdown();
_sendVerificationCode(); _sendVerificationCode();
} }
// 更新验证码输入 // 更新验证码输入
void updateVerificationCode(int index, String value) { void updateVerificationCode(int index, String value) {
if (index >= 0 && index < 4) { if (index >= 0 && index < 4) {
@ -186,23 +201,23 @@ class LoginController extends GetxController {
_verificationCode.value = newList; _verificationCode.value = newList;
} }
} }
// 重置验证码 // 重置验证码
void _resetVerificationCode() { void _resetVerificationCode() {
_verificationCode.value = ['', '', '', '']; _verificationCode.value = ['', '', '', ''];
} }
// 检查验证码是否完整 // 检查验证码是否完整
bool isVerificationCodeComplete() { bool isVerificationCodeComplete() {
return !_verificationCode.contains(''); return !_verificationCode.contains('');
} }
// 登录 // 登录
Future<void> login() async { Future<void> login() async {
// 暂时关闭验证码验证 // 暂时关闭验证码验证
// if (!isVerificationCodeComplete()) { // if (!isVerificationCodeComplete()) {
// Get.snackbar( // Get.snackbar(
// '提示', // '提示',
// '请输入完整的验证码', // '请输入完整的验证码',
// snackPosition: SnackPosition.TOP, // snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1), // backgroundColor: Colors.red.withOpacity(0.1),
@ -210,18 +225,102 @@ class LoginController extends GetxController {
// ); // );
// return; // return;
// } // }
_isLoading.value = true; _isLoading.value = true;
try { try {
// 模拟验证过程 // 模拟验证过程
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
switch (loginType) {
// 验证成功,跳转到配对页面 case 1:
Get.offAllNamed(Routes.pairing); {
print("数据获取Facebook");
final facebook = Facebook();
bool authResult = await facebook.signInWithFacebook();
print("数据获取Facebook().token${authResult}");
if (authResult) {
print("数据获取_Facebook.token${facebook.token}");
// SettingsController().userName = Facebook().name;
// SettingsController().avatar = Facebook().pictureurl;
// SettingsController().userId = Facebook().id;
//SettingsController().avatar = Google().email;
// 验证成功,跳转到配对页面
requestLogin({
"email": facebook.email,
"name": facebook.name,
"avatar": facebook.pictureurl,
"stype": 4,
"ttoken": facebook.token,
});
}
break;
}
case 2:
{
print("数据获取_Google()");
final google = Google();
bool authResult = await google.signInWithGoogle();
print("数据获取_Google().token${authResult}");
if (authResult) {
// 验证成功,跳转到配对页面
// SettingsController().userName = Google().displayName!;
// //SettingsController().avatar = Google().email;
// SettingsController().userId = Google().id!;
requestLogin({
"name": google.displayName,
"email": google.email,
"stype": 3,
"ttoken": google.token,
});
}
break;
}
case 3:
{
print("数据获取_FlWX()");
bool authResult = await FlWX().authBy(
NormalAuth(
scope: "snsapi_userinfo",
state: "wechat_sdk_demo_test",
),
getUserInfo: true, // 按需获取用户信息
);
if (authResult) {
// 确保 FlWX() 返回的是同一个实例,并且 token 已经被设置
// 这里假设 FlWX().token 在 authBy 成功后被设置
print("数据获取_FlWX().token${FlWX().token}");
// SettingsController().userName = FlWX().nickname;
// SettingsController().avatar = FlWX().headimgurl;
// SettingsController().userId = FlWX().openid;
requestLogin({
"name": FlWX().nickname,
"avatar": FlWX().headimgurl,
"stype": 2,
"ttoken": FlWX().code,
});
// 验证成功,跳转到配对页面
}
break;
}
default:
{
Get.snackbar(
'错误',
'登录失败,请重试',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
break;
}
}
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
'错误', '错误',
'登录失败,请重试', '登录失败,请重试',
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1), backgroundColor: Colors.red.withOpacity(0.1),
@ -231,16 +330,87 @@ class LoginController extends GetxController {
_isLoading.value = false; _isLoading.value = false;
} }
} }
// 使用登陆请求服务器
Future<void> requestLogin(Map params) async {
// switch (loginType) {
// case 0: //邮箱
// {
// String verificationCode = verificationCodeController.text;
// String contactControll22er = contactController.text;
// }
// case 1: //手机号
// {
// String verificationCode = verificationCodeController.text;
// String contactContr22oller = contactController.text;
// }
// case 2: //微信
// {}
// case 3: //谷歌
// {}
// case 4: //facebook
// {}
// }
var response = await Api.login({
"mail": params?["mail"].toString() ?? "",
"phone": params?["phone"].toString() ?? "",
"stype": params["stype"],
"vcode": params?["vcode"].toString() ?? "",
"ttoken": params?["ttoken"].toString() ?? "",
"phonemodel": params?["phonemodel"].toString() ?? "",
"phonemac": params?["phonemac"].toString() ?? "",
"name": params?["name"].toString() ?? "",
"avatar": params?["avatar"].toString() ?? "",
});
if (response != null) {
print("请求后台数据login回复数据=${response}");
// final instance = await GetStorage();
await _storage.write('loginInfo', jsonEncode(response));
// 2. 将响应数据转换为User对象
try {
print('响应数据: ${response.toString()}'); // 调试输出原始数据
if (response['code'].toString() == '0' &&
response['msg'].toString() == "Success") {
// 新增:检查 user 字段是否存在且类型正确
if (response.containsKey('data') && response['data'] is Map) {
final user = User.fromJson(response);
print('用户初始化成功: ${user.name}');
// 存储到 SharedPreferences (仅存储用户数据)
//final prefs = await GetStorage();
await _storage.write(
'user', jsonEncode(user.toJson())); // 使用 user.toJson()
Get.offAllNamed(Routes.pairing);
} else {
throw FormatException('API 响应缺少 user 字段');
}
} else {
throw Exception('接口返回错误: ${response['msg']}');
}
} catch (e, stack) {
// 新增:打印堆栈跟踪
print('用户数据处理失败: $e');
print('堆栈跟踪: $stack');
Get.snackbar('错误', '用户数据解析失败,请检查网络');
}
// Get.offAll(() => IndexWidget());
}
}
// 使用密码登录 // 使用密码登录
void usePasswordLogin() { void usePasswordLogin() {
// 这里可以实现密码登录的逻辑 // 这里可以实现密码登录的逻辑
Get.snackbar( Get.snackbar(
'提示', '提示',
'密码登录功能尚未实现', '密码登录功能尚未实现',
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.blue.withOpacity(0.1), backgroundColor: Colors.blue.withOpacity(0.1),
colorText: Colors.blue, colorText: Colors.blue,
); );
} }
} }

126
lib/modules/login/controllers/weixinLogin.dart

@ -5,7 +5,6 @@ import 'dart:typed_data';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
export 'package:fluwx/fluwx.dart'; export 'package:fluwx/fluwx.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:get/get.dart';
typedef FlWeChatResponseCallback = void Function(WeChatResponse response); typedef FlWeChatResponseCallback = void Function(WeChatResponse response);
@ -76,8 +75,14 @@ class FlWX {
String _appName = ''; String _appName = '';
String token = ''; String token = '';
String code = '';
String refresh_token = ''; String refresh_token = '';
String openid = ''; String openid = '';
String nickname = '';
String sex = '';
String headimgurl = '';
String city = '';
// 参数 说明 // 参数 说明
// access_token 接口调用凭证 // access_token 接口调用凭证
// expires_in access_token 接口调用凭证超时时间,单位(秒) // expires_in access_token 接口调用凭证超时时间,单位(秒)
@ -257,68 +262,97 @@ class FlWX {
} }
} }
/// 调用微信登录 // graph TD
// A[开始] --> B{微信是否安装?}
// B -->|否| C[返回 false]
// B -->|是| D[注册监听器]
// D --> E[调起微信授权]
// E -->|失败| F[触发 completer(false)]
// E -->|成功| G[等待微信响应]
// G -->|用户取消/接口错误| H[触发 completer(false)]
// G -->|成功获取 code| I[获取 Token]
// I -->|Token 失败| H
// I -->|Token 成功| J[刷新 Token]
// J -->|刷新失败| H
// J -->|刷新成功| K{需用户信息?}
// K -->|是| L[获取用户信息]
// L -->|信息失败| H
// K -->|否| M[触发 completer(true)]
// L -->|信息成功| M
Future<bool> authBy( Future<bool> authBy(
AuthType which, { AuthType which, {
/// 原始数据回调
FlWeChatAuthResponseCallback? onResponse, FlWeChatAuthResponseCallback? onResponse,
/// 获取token回调
FlWeChatAuthResponseTokenCallback? onToken, FlWeChatAuthResponseTokenCallback? onToken,
/// 获取userinfo回调
FlWeChatAuthResponseUserinfoCallback? onUserinfo, FlWeChatAuthResponseUserinfoCallback? onUserinfo,
bool getUserInfo = false, bool getUserInfo = false,
}) async { }) async {
if (!await isInstalled) return false; if (!await isInstalled) {
final cancelable = _onListener((response) async { _params?.onToast?.call('微信未安装');
return false;
}
final completer = Completer<bool>(); // 创建 Completer 控制 Future 完成时机
FluwxCancelable? subscription; // 用于取消监听
subscription = _onListener((response) async {
if (response is WeChatAuthResponse) { if (response is WeChatAuthResponse) {
onResponse?.call(response); onResponse?.call(response);
print(
"用户点击事件${response.isSuccessful},${response.code},${response.lang},${response.state},${response.country}",
);
if (response.isSuccessful && response.code != null) { if (response.isSuccessful && response.code != null) {
print("数据获取失败${onToken},${onUserinfo}"); code = response.code!;
// if (onToken != null || onUserinfo != null) { completer.complete(true); // 所有操作成功时完成 Future
try {
var Istoken = await fetchData( // try {
_getTokenUrl(response.code!), // code = response.code!;
); // 触发GET请求 // // 获取 token
//token有效期是30天,30天后需要重新授权,需要看看API文档 // final tokenData = await fetchData(_getTokenUrl(response.code!));
print("数据获取fetchData${Istoken}"); // if (tokenData.isEmpty) {
// _params!.onLog?.call('Token 数据获取失败');
if (Istoken != {}) { // completer.complete(false); // 失败时完成 Future
token = Istoken["access_token"].toString(); // return;
refresh_token = Istoken["refresh_token"].toString(); // }
openid = Istoken["openid"].toString();
print("数据获取token=${token}"); // // 更新 token
print("数据获取openid=${openid}"); // token = tokenData["access_token"].toString();
print("数据获取refresh_token=${refresh_token}"); // openid = tokenData["openid"].toString();
Istoken = await fetchData(_getRefreshTokenUrl(response.code!)); // // Istoken = await fetchData(
print("数据获取_getUserTokenEffertive${Istoken}"); // // _getUserTokenEffertive(openId: openid, token: token),
Istoken = await fetchData( // // ); // 触发GET请求
_getUserTokenEffertive(openId: openid, token: token), // // print("数据获取_getUserTokenEffertive${Istoken}");
); // 触发GET请求 // // 可选:刷新 token 或获取用户信息
print("数据获取_getUserTokenEffertive${Istoken}"); // if (getUserInfo) {
Istoken = await fetchData( // final userInfo = await fetchData(
_getUserInfoUrl(openId: openid, token: token), // _getUserInfoUrl(openId: openid, token: token));
); // 触发GET请求 // List<int> bytes = latin1.encode(userInfo["nickname"].toString());
print("数据获取_getUserInfoUrl${Istoken}"); // print("ISO-8859-1 字节数组: $bytes");
} // nickname = String.fromCharCodes(bytes);
} catch (e) { // // nickname = userInfo["nickname"].toString();
_params!.onLog?.call('数据解析失败 $e'); // sex = userInfo["sex"].toString();
} // headimgurl = userInfo["headimgurl"].toString();
// city = userInfo["city"].toString();
// print("_getUserInfoUrl${nickname}");
// // onUserinfo?.call(userInfo);
// }
// completer.complete(true); // 所有操作成功时完成 Future
// } catch (e) {
// _params!.onLog?.call('授权流程异常: $e');
// completer.complete(false);
// } // }
} else {
completer.complete(false); // 用户取消授权或授权失败
} }
} else if (response is WeChatAuthByQRCodeFinishedResponse) {} }
}); });
// 调起微信授权
final result = await fluwx.authBy(which: which); final result = await fluwx.authBy(which: which);
print("authBy数据获取${result}");
if (!result) { if (!result) {
cancelable.cancel(); subscription.cancel(); // 调起失败时取消监听
_params!.onToast?.call('微信授权失败'); _params!.onToast?.call('微信授权失败');
completer.complete(false);
} }
return result;
return completer.future; // 返回由回调控制的 Future
} }
Future<bool> autoDeduct( Future<bool> autoDeduct(

32
lib/modules/login/entity/api.dart

@ -0,0 +1,32 @@
import 'dio_manager.dart';
import 'nw_method.dart';
class Api {
// 登录
static login([params]) {
print("请求后台数据params=${params}");
return DioManager().request(
NWMethod.post,
'/api/home/user_sgin',
params: params,
);
}
// 获取验证码
static getCode([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/user_verification',
params: params,
);
}
// 获取阿里token
static getAliToken([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/auth_alitoken',
params: params,
);
}
}

45
lib/modules/login/entity/dio_manager.dart

@ -0,0 +1,45 @@
import 'package:dio/dio.dart';
//import 'auth_interceptor.dart';
import 'nw_api.dart';
import 'nw_method.dart';
class DioManager {
static final DioManager _shared = DioManager._internal();
factory DioManager() => _shared;
late Dio dio;
DioManager._internal() {
BaseOptions options = BaseOptions(
baseUrl: NWApi.baseApi,
contentType: Headers.jsonContentType,
responseType: ResponseType.json,
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
);
dio = Dio(options);
//dio.interceptors.add(AuthInterceptor());
}
// 请求,返回参数为 T
// method:请求方法,NWMethod.POST等
// path:请求地址
// params:请求参数
Future request<T>(
NWMethod method,
String path, {
Map? params,
Map<String, dynamic>? queryParameters,
}) async {
Response response = await dio.request(
path,
data: params,
queryParameters: queryParameters,
options: Options(method: nwMethodValues[method]),
);
return response.data;
}
}

4
lib/modules/login/entity/nw_api.dart

@ -0,0 +1,4 @@
class NWApi {
// static const baseApi = "https://www.deapsound.com";
static const baseApi = "https://www.deapsound.com";
}

8
lib/modules/login/entity/nw_method.dart

@ -0,0 +1,8 @@
enum NWMethod { get, post, delete, put }
const nwMethodValues = {
NWMethod.get: "get",
NWMethod.post: "post",
NWMethod.delete: "delete",
NWMethod.put: "put"
};

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

@ -397,45 +397,21 @@ class LoginView extends GetView<LoginController> {
switch (icon) { switch (icon) {
case FontAwesomeIcons.facebook: case FontAwesomeIcons.facebook:
{ {
print("数据获取Facebook"); controller.loginType = 1;
bool authResult = await Facebook().signInWithFacebook();
print("数据获取Facebook().token${authResult}");
if (authResult) {
print("数据获取_Facebook.token${Facebook().token}");
controller.login();
}
break; break;
} }
case FontAwesomeIcons.google: case FontAwesomeIcons.google:
{ {
print("数据获取_Google()"); controller.loginType = 2;
bool authResult = await Google().signInWithGoogle();
print("数据获取_Google().token${authResult}");
if (authResult) {
controller.login();
}
break; break;
} }
case FontAwesomeIcons.weixin: case FontAwesomeIcons.weixin:
{ {
print("数据获取_FlWX()"); controller.loginType = 3;
bool authResult = await FlWX().authBy(
NormalAuth(
scope: "snsapi_userinfo",
state: "wechat_sdk_demo_test",
),
);
if (authResult) {
// 确保 FlWX() 返回的是同一个实例,并且 token 已经被设置
// 这里假设 FlWX().token 在 authBy 成功后被设置
print("数据获取_FlWX().token${FlWX().token}");
controller.login();
}
break; break;
} }
} }
controller.login();
} }
// 用户协议和隐私政策 // 用户协议和隐私政策

10
lib/modules/meeting/bindings/meeting_record_binding.dart

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import '../controllers/meeting_record_controller.dart';
class MeetingRecordBinding extends Bindings {
@override
void dependencies() {
// 注册控制器
Get.lazyPut<MeetingRecordController>(() => MeetingRecordController());
}
}

17
lib/modules/meeting/controllers/meeting_controller.dart

@ -1,19 +1,26 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
class MeetingController extends GetxController class MeetingController extends GetxController {
with GetSingleTickerProviderStateMixin { final ScrollController listController = ScrollController();
late AnimationController lottieController;
// 是否还有更多数据
bool isLoadingMore = true;
int page = 1;
TextEditingController titleController = TextEditingController(); // 录音标题
RxList dataList = [].obs;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
lottieController = AnimationController(vsync: this);
} }
@override @override
void onClose() { void onClose() {
lottieController.dispose(); listController.dispose();
titleController.dispose();
super.onClose(); super.onClose();
} }
} }

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

@ -0,0 +1,98 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../data/services/asr_service.dart';
class MeetingRecordController extends GetxController
with GetSingleTickerProviderStateMixin {
late AnimationController lottieController;
late AsrService _asrService;
Timer? timer;
RxBool isRecording = false.obs; //是否录音中
RxInt seconds = 0.obs;
RxString intermediateContent = ''.obs;
RxString finalContent = ''.obs;
StreamSubscription? _recognitionSubscription;
@override
void onInit() {
super.onInit();
lottieController = AnimationController(vsync: this);
_asrService = Get.find<AsrService>();
}
@override
void onClose() {
lottieController.dispose();
timer?.cancel();
_asrService.stopContinuousRecognition();
_recognitionSubscription?.cancel();
super.onClose();
}
// 点击开始、暂停按钮
void recorderHandle() {
if (isRecording.value) {
_pause();
} else {
_start();
}
}
// 开始
void _start() async {
await _startRecorder();
lottieController.repeat();
isRecording.value = true;
timer = Timer.periodic(const Duration(seconds: 1), (_) => seconds++);
}
// 暂停
void _pause() async {
await _stopRecorder();
lottieController.stop();
isRecording.value = false;
timer?.cancel();
}
//开始录音
Future<void> _startRecorder() async {
final recognitionStream = await _asrService.startContinuousRecognition();
_recognitionSubscription = recognitionStream.listen(
_handleRecognitionEvent,
);
}
//结束录音
Future<void> _stopRecorder() async {
await _asrService.stopContinuousRecognition();
_recognitionSubscription?.cancel();
}
// 处理语音识别事件
void _handleRecognitionEvent(RecognitionEvent event) {
switch (event.type) {
case RecognitionEventType.intermediateResult:
intermediateContent.value = event.text;
break;
case RecognitionEventType.finalResult:
finalContent.value += event.text;
intermediateContent.value = '';
break;
default:
// 不做任何处理
break;
}
}
// 完成
void complete() async {
Get.back();
}
}

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

@ -0,0 +1,26 @@
import 'dart:typed_data';
class MeetingDetailsModel {
MeetingDetailsModel();
late int id;
late int noteid;
late Uint8List audio;
late String content;
factory MeetingDetailsModel.fromJson(Map<String, dynamic> map) =>
MeetingDetailsModel()
..id = map["id"]
..noteid = map["noteid"]
..audio = map["audio"]
..content = map["content"];
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['id'] = id;
data['noteid'] = noteid;
data['audio'] = audio;
data['content'] = content;
return data;
}
}

29
lib/modules/meeting/model/meeting_model.dart

@ -0,0 +1,29 @@
class MeetingModel {
MeetingModel();
late int id;
late String title;
late String content;
late String language;
late int seconds;
late int creationtime;
factory MeetingModel.fromJson(Map<String, dynamic> map) => MeetingModel()
..id = map["id"]
..title = map["title"]
..content = map["content"]
..language = map["language"]
..seconds = map["seconds"]
..creationtime = map["creationtime"];
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['id'] = id;
data['title'] = title;
data['content'] = content;
data['language'] = language;
data['seconds'] = seconds;
data['creationtime'] = creationtime;
return data;
}
}

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

@ -0,0 +1,320 @@
import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:lottie/lottie.dart';
import '../../../core/theme/app_colors.dart';
import '../controllers/meeting_record_controller.dart';
class MeetingRecordView extends GetView<MeetingRecordController> {
const MeetingRecordView({super.key});
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
_showAlertDialog(isDarkMode);
},
child: Scaffold(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
appBar: _buildAppBar(isDarkMode),
body: _buildBody(isDarkMode),
),
);
}
// 构建应用栏
PreferredSizeWidget _buildAppBar(bool isDarkMode) {
return AppBar(
backgroundColor: isDarkMode ? Colors.black : Colors.white,
elevation: 0.5,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: isDarkMode ? Colors.white : Colors.black,
size: 20.sp,
),
onPressed: () {
_showAlertDialog(isDarkMode);
},
),
title: Padding(
padding: const EdgeInsets.only(right: 56),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(
() => Icon(
Icons.keyboard_voice,
color: isDarkMode
? controller.seconds.value > 0
? AppColors.primary
: Colors.white
: controller.seconds.value > 0
? Colors.blue
: Colors.black,
),
),
5.horizontalSpace,
Obx(
() => Text(
DateUtil.formatDateMs(
controller.seconds.value * 1000,
format: 'HH:mm:ss',
isUtc: true,
),
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
color: isDarkMode
? controller.seconds.value > 0
? AppColors.primary
: Colors.white
: controller.seconds.value > 0
? Colors.blue
: Colors.black,
),
),
),
],
),
),
centerTitle: true,
);
}
// 构建主体内容
Widget _buildBody(bool isDarkMode) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'2025-03-03 录音',
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 17.sp,
),
),
),
10.horizontalSpace,
Text(
'中文',
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 15.sp,
),
),
],
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.w),
child: Text(
'2025-03-03 16:18',
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,
),
),
Expanded(
child: Lottie.asset(
'assets/lottie/audio_wave.json',
controller: controller.lottieController,
fit: BoxFit.fill,
),
),
],
),
);
}
// 记录内容
Widget _recordContent(bool isDarkMode) {
return Expanded(
child: Container(
width: double.infinity,
padding: EdgeInsets.all(10.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: Align(
alignment: Alignment.topLeft,
child: SingleChildScrollView(
reverse: true,
child: Obx(
() => Text(
'${controller.finalContent.value}${controller.intermediateContent.value}',
),
),
),
),
),
);
}
// 底部按钮
Widget _bottomButton(bool isDarkMode) {
return Padding(
padding: EdgeInsets.only(top: 40.w, bottom: 30.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: controller.recorderHandle,
child: Container(
width: 130.w,
height: 60.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(60.w),
border: Border.all(
color: isDarkMode ? AppColors.primary : Colors.blue,
width: 2.w,
),
),
child: Obx(
() => Icon(
controller.isRecording.value ? Icons.pause : Icons.play_arrow,
color: isDarkMode ? AppColors.primary : Colors.blue,
size: 40.w,
),
),
),
),
GestureDetector(
onTap: () {
_showAlertDialog(isDarkMode);
},
child: Container(
width: 130.w,
height: 60.w,
decoration: BoxDecoration(
color: isDarkMode ? AppColors.primary : Colors.blue,
borderRadius: BorderRadius.circular(60.w),
),
child: Icon(
Icons.fiber_manual_record_outlined,
color: Colors.white,
size: 40.w,
),
),
),
],
),
);
}
// 显示对话框
void _showAlertDialog(bool isDarkMode) {
if (controller.seconds.value > 0) {
Get.dialog(
AlertDialog(
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white,
title: Text(
'注意',
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
),
),
content: Text(
'你想结束录音吗?',
style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr, // 取消
style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
),
TextButton(
onPressed: () {
Get.back();
controller.complete();
},
child: Text(
'confirm'.tr, // 确定
style: TextStyle(
color: isDarkMode ? Colors.red[300] : Colors.red[600],
),
),
),
],
),
);
} else {
Get.back();
}
}
}

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

@ -1,10 +1,12 @@
import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:lottie/lottie.dart';
import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_colors.dart';
import '../../../routes/app_routes.dart';
import '../controllers/meeting_controller.dart'; import '../controllers/meeting_controller.dart';
import '../model/meeting_model.dart';
class MeetingView extends GetView<MeetingController> { class MeetingView extends GetView<MeetingController> {
const MeetingView({super.key}); const MeetingView({super.key});
@ -16,7 +18,7 @@ class MeetingView extends GetView<MeetingController> {
return Scaffold( return Scaffold(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
appBar: _buildAppBar(isDarkMode), appBar: _buildAppBar(isDarkMode),
body: _buildBody(isDarkMode), body: _buildBody(context, isDarkMode),
); );
} }
@ -33,25 +35,12 @@ class MeetingView extends GetView<MeetingController> {
), ),
onPressed: () => Get.back(), onPressed: () => Get.back(),
), ),
title: Padding( title: Text(
padding: const EdgeInsets.only(right: 56), 'conferenceAssistant'.tr, // 商务会议助手
child: Row( style: TextStyle(
mainAxisAlignment: MainAxisAlignment.center, fontSize: 17.sp,
children: [ fontWeight: FontWeight.w600,
Icon( color: isDarkMode ? Colors.white : Colors.black,
Icons.keyboard_voice,
color: isDarkMode ? Colors.white : Colors.black,
),
5.horizontalSpace,
Text(
'00:00:00',
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black,
),
),
],
), ),
), ),
centerTitle: true, centerTitle: true,
@ -59,107 +48,57 @@ class MeetingView extends GetView<MeetingController> {
} }
// 构建主体内容 // 构建主体内容
Widget _buildBody(bool isDarkMode) { Widget _buildBody(BuildContext context, bool isDarkMode) {
return Padding( return Stack(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.w), children: [
child: Column( Obx(
crossAxisAlignment: CrossAxisAlignment.start, () => ListView.builder(
children: [ itemCount: controller.dataList.length,
Row( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.w),
children: [ itemBuilder: (BuildContext context, int index) {
Expanded( // MeetingModel data =
child: Text( // MeetingModel.fromJson(controller.dataList[index]);
'2025-03-03 录音', return _item(context, isDarkMode);
style: TextStyle( },
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 17.sp,
),
),
),
10.horizontalSpace,
Text(
'中文',
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 15.sp,
),
),
],
), ),
Padding( ),
padding: EdgeInsets.symmetric(vertical: 5.w), Align(
child: Text( alignment: Alignment.bottomCenter,
'2025-03-03 16:18', child: GestureDetector(
style: TextStyle( onTap: () {
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], _bottomSheet(context, isDarkMode);
fontSize: 14.sp, },
child: Container(
width: 130.w,
height: 48.w,
margin: EdgeInsets.symmetric(vertical: 20.w),
decoration: BoxDecoration(
color: isDarkMode ? AppColors.primary : Colors.blue,
borderRadius: BorderRadius.circular(12.w),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.keyboard_voice, color: Colors.white),
5.horizontalSpace,
Text(
'录音',
style: TextStyle(color: Colors.white, fontSize: 16.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,
),
),
Expanded(
child: Lottie.asset(
'assets/lottie/audio_wave.json',
controller: controller.lottieController,
fit: BoxFit.fill,
),
),
],
),
); );
} }
// 记录内容 Widget _item(BuildContext context, bool isDarkMode) {
Widget _recordContent(bool isDarkMode) { return GestureDetector(
return Expanded( onTap: () {},
child: Container( child: Container(
width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w),
padding: EdgeInsets.all(10.w),
margin: EdgeInsets.symmetric(vertical: 5.w), margin: EdgeInsets.symmetric(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,
@ -174,54 +113,235 @@ class MeetingView extends GetView<MeetingController> {
), ),
], ],
), ),
), child: Row(
); children: [
} Expanded(
child: Column(
// 底部按钮 crossAxisAlignment: CrossAxisAlignment.start,
Widget _bottomButton(bool isDarkMode) { children: [
return Padding( Text(
padding: EdgeInsets.only(top: 40.w, bottom: 30.w), 'data.title',
child: Row( style: TextStyle(
mainAxisAlignment: MainAxisAlignment.spaceBetween, color: isDarkMode ? Colors.white : Colors.black87,
children: [ fontSize: 16.sp,
GestureDetector( ),
onTap: () {}, overflow: TextOverflow.ellipsis,
child: Container( ),
width: 130.w, Text(
height: 60.w, '无内容',
decoration: BoxDecoration( style: TextStyle(
borderRadius: BorderRadius.circular(60.w), color: isDarkMode ? Colors.white70 : Colors.black54,
border: Border.all( fontSize: 12.sp,
color: isDarkMode ? AppColors.primary : Colors.blue, ),
width: 2.w, overflow: TextOverflow.ellipsis,
), ),
), Text(
child: Icon( '12-13',
Icons.pause, style: TextStyle(
color: isDarkMode ? AppColors.primary : Colors.blue, color: isDarkMode ? Colors.white70 : Colors.black54,
size: 40.w, fontSize: 12.sp,
),
),
],
), ),
), ),
), Container(
GestureDetector( width: 76.w,
onTap: () {}, height: 28.w,
child: Container( margin: EdgeInsets.only(left: 10.w),
width: 130.w, alignment: Alignment.center,
height: 60.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? AppColors.primary : Colors.blue, color: isDarkMode ? AppColors.primary : Colors.blue,
borderRadius: BorderRadius.circular(60.w), borderRadius: BorderRadius.circular(28.w),
), ),
child: Icon( child: Text(
Icons.fiber_manual_record_outlined, '00:00:00',
color: Colors.white, style: TextStyle(color: Colors.white, fontSize: 14.sp),
size: 40.w,
), ),
), ),
), ],
], ),
), ),
); );
} }
void _bottomSheet(BuildContext context, bool isDarkMode) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
clipBehavior: Clip.hardEdge,
builder: (BuildContext context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 20.w),
color: isDarkMode ? AppColors.darkBackground : Colors.grey[50],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'录音语言转换',
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 17.sp,
),
),
Container(
height: 48.w,
margin: EdgeInsets.only(top: 10.w, bottom: 20.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: GestureDetector(
onTap: () {},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.w),
child: Row(
children: [
Expanded(
child: Text(
'中文',
style: TextStyle(
color:
isDarkMode ? Colors.white : Colors.black87,
fontSize: 16.sp,
),
),
),
Icon(
Icons.keyboard_arrow_right,
color: isDarkMode ? Colors.white : Colors.black87,
),
],
),
),
),
),
Text(
'录音标题(非必填)',
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 16.sp,
),
),
Container(
height: 48.w,
margin: EdgeInsets.only(top: 10.w, bottom: 20.w),
alignment: Alignment.center,
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: TextField(
controller: controller.titleController,
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 16.sp,
),
decoration: InputDecoration(
hintText: '最多50个字符',
hintStyle: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54,
fontSize: 16.sp,
),
fillColor: Colors.transparent,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 10.w),
),
),
),
Padding(
padding: EdgeInsets.only(top: 30.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
Get.back();
},
child: Container(
width: 120.w,
height: 40.w,
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(
width: 2.w,
color:
isDarkMode ? AppColors.primary : Colors.blue,
),
borderRadius: BorderRadius.circular(12.w),
),
child: Text(
'取消',
style: TextStyle(
fontSize: 14.sp,
color:
isDarkMode ? AppColors.primary : Colors.blue,
),
),
),
),
GestureDetector(
onTap: () {
int time = DateTime.now().millisecondsSinceEpoch;
if (controller.titleController.text.isEmpty) {
controller.titleController.text =
'${DateUtil.formatDateMs(time, format: DateFormats.y_mo_d)} 录音';
}
Get.back();
Get.toNamed(Routes.meetingRecord);
},
child: Container(
width: 120.w,
height: 40.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: isDarkMode ? AppColors.primary : Colors.blue,
borderRadius: BorderRadius.circular(12.w),
),
child: Text(
'确定',
style: TextStyle(
color: Colors.white,
fontSize: 14.sp,
),
),
),
),
],
),
),
],
),
),
);
},
).then((value) {
controller.titleController.text = '';
});
}
} }

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

@ -1,17 +1,22 @@
import 'package:app_settings/app_settings.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'dart:ui'; import 'dart:ui';
import '../../../core/theme/app_colors.dart';
import '../controllers/settings_controller.dart'; import '../controllers/settings_controller.dart';
import '../../../core/widgets/common_bottom_nav.dart'; import '../../../core/widgets/common_bottom_nav.dart';
import '../../../routes/app_routes.dart'; import '../../../routes/app_routes.dart';
import 'dart:io'; import '../../../data/models/user_Info.dart';
class SettingsView extends GetView<SettingsController> { class SettingsView extends GetView<SettingsController> {
const SettingsView({Key? key}) : super(key: key); const SettingsView({Key? key}) : super(key: key);
// 正确获取用户名方式
String get userName => User.getname();
String get deviceInfo => User.getdeviceInfo();
String get userId => User.getuserId();
String get standing => User.getstanding();
String get avatar => User.getnavatar();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// 直接使用 Theme.of(context) 获取当前主题 // 直接使用 Theme.of(context) 获取当前主题
@ -23,7 +28,7 @@ class SettingsView extends GetView<SettingsController> {
backgroundColor: isDarkMode ? Colors.black : Colors.white, backgroundColor: isDarkMode ? Colors.black : Colors.white,
elevation: 0.5, elevation: 0.5,
title: Text( title: Text(
'settings'.tr, // 设置 '设置',
style: TextStyle( style: TextStyle(
fontSize: 17.sp, fontSize: 17.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -73,7 +78,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
], ],
), ),
child: ClipRRect(//裁剪圆角矩形 child: ClipRRect(
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
child: BackdropFilter( child: BackdropFilter(
filter: isDarkMode filter: isDarkMode
@ -81,9 +86,7 @@ class SettingsView extends GetView<SettingsController> {
: ImageFilter.blur(sigmaX: 0, sigmaY: 0), : ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Row( child: Row(
children: [ children: [
Obx(()=>GestureDetector( Container(
//onTap: ()=>controller.updateUserAvatar(),
child:Container(//用户头像部分
width: 60.w, width: 60.w,
height: 60.w, height: 60.w,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -96,33 +99,26 @@ class SettingsView extends GetView<SettingsController> {
), ),
], ],
), ),
child: ClipRRect(// 裁剪圆形头像 child: ClipRRect(
borderRadius: BorderRadius.circular(30.r), borderRadius: BorderRadius.circular(30.r),
child: controller.userInfo.value.avatar.isEmpty child: Image.network(
? Image.network( avatar,
'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,// 图片填充方式 ),
)
:Image.file(
File(controller.userInfo.value.avatar),
fit: BoxFit.cover,// 图片填充方式
)
), ),
), ),
)),
SizedBox(width: 16.w), SizedBox(width: 16.w),
Expanded(// 占据剩余空间 Expanded(
child: Obx(()=>Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start,// 左对齐 crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(//用户名 Text(
controller.userInfo.value.name, userName,
style: TextStyle( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode ? Colors.white : Colors.black87,
), ),
overflow: TextOverflow.ellipsis,
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Row( Row(
@ -135,7 +131,7 @@ class SettingsView extends GetView<SettingsController> {
borderRadius: BorderRadius.circular(10.r), borderRadius: BorderRadius.circular(10.r),
), ),
child: Text( child: Text(
controller.userInfo.value.membershipLevel, standing,
style: TextStyle( style: TextStyle(
fontSize: 10.sp, fontSize: 10.sp,
color: Colors.white, color: Colors.white,
@ -145,7 +141,7 @@ class SettingsView extends GetView<SettingsController> {
SizedBox(width: 8.w), SizedBox(width: 8.w),
Flexible( Flexible(
child: Text( child: Text(
'${'joinDevice'.tr} DeepSound Pro', // 已连接设备: deviceInfo,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: color:
@ -158,7 +154,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
controller.userInfo.value.id, userId,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54, color: isDarkMode ? Colors.white70 : Colors.black54,
@ -166,8 +162,8 @@ class SettingsView extends GetView<SettingsController> {
), ),
], ],
), ),
),), ),
Container(// 编辑按钮 Container(
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -183,15 +179,11 @@ class SettingsView extends GetView<SettingsController> {
), ),
], ],
), ),
child: InkWell( child: Icon(
onTap: () => Get.toNamed(Routes.editProfile), Icons.edit,
child: Icon( size: 16.w,
Icons.edit, color: isDarkMode ? Colors.white70 : Colors.grey[600],
size: 16.w, ),
color: isDarkMode ? Colors.white70 : Colors.grey[600],
),
)
), ),
], ],
), ),
@ -208,7 +200,7 @@ class SettingsView extends GetView<SettingsController> {
Padding( Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h), padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text( child: Text(
'systemSetting'.tr, // 系统设置 '系统设置',
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -239,25 +231,22 @@ class SettingsView extends GetView<SettingsController> {
: ImageFilter.blur(sigmaX: 0, sigmaY: 0), : ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Column( child: Column(
children: [ children: [
// 语言设置 // 通知设置
Obx( _buildSimpleNavigationSetting(
() => _buildSimpleNavigationSetting( title: '通知设置',
title: 'languageSetting'.tr, // 语言设置 subtitle: '管理应用推送和提醒',
subtitle: controller.language.value.name.tr, icon: Icons.notifications_none,
icon: Icons.language, iconBgColor: isDarkMode
iconBgColor: isDarkMode ? Colors.indigo[900]!.withOpacity(0.3)
? Colors.indigo[900]!.withOpacity(0.3) : Colors.indigo[100]!,
: Colors.indigo[100]!, iconColor:
iconColor: isDarkMode isDarkMode ? Colors.indigo[300]! : Colors.indigo[600]!,
? Colors.indigo[300]! titleColor: isDarkMode ? Colors.white : null,
: Colors.indigo[600]!, subtitleColor: isDarkMode ? Colors.white70 : null,
titleColor: isDarkMode ? Colors.white : null, onTap: () {
subtitleColor: isDarkMode ? Colors.white70 : null, // 打开通知设置页面
onTap: () { },
_showLanguageSelectionDialog(isDarkMode); isDarkMode: isDarkMode,
},
isDarkMode: isDarkMode,
),
), ),
Divider( Divider(
height: 1, height: 1,
@ -267,8 +256,8 @@ class SettingsView extends GetView<SettingsController> {
// 主题设置 // 主题设置
_buildToggleSetting( _buildToggleSetting(
title: 'darkMode'.tr, // 暗黑模式 title: '暗黑模式',
subtitle: 'darkModeInfo'.tr, // 切换应用的明暗主题 subtitle: '切换应用的明暗主题',
icon: isDarkMode ? Icons.dark_mode : Icons.light_mode, icon: isDarkMode ? Icons.dark_mode : Icons.light_mode,
iconBgColor: isDarkMode iconBgColor: isDarkMode
? Colors.indigo[900]!.withOpacity(0.3) ? Colors.indigo[900]!.withOpacity(0.3)
@ -289,15 +278,15 @@ class SettingsView extends GetView<SettingsController> {
// 备份与恢复 // 备份与恢复
_buildNavigationSetting( _buildNavigationSetting(
title: 'backups'.tr, // 备份与恢复 title: '备份与恢复',
subtitle: 'backupsInfo'.tr, // 备份设置和AI互动历史 subtitle: '备份设置和AI互动历史',
icon: Icons.cloud_upload_outlined, icon: Icons.cloud_upload_outlined,
iconBgColor: isDarkMode iconBgColor: isDarkMode
? Colors.cyan[900]!.withOpacity(0.3) ? Colors.cyan[900]!.withOpacity(0.3)
: Colors.cyan[100]!, : Colors.cyan[100]!,
iconColor: iconColor:
isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!, isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!,
value: '${'lastBackup'.tr} 今天', // 上次备份: value: '上次备份: 今天',
valueStyle: TextStyle( valueStyle: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[500], color: isDarkMode ? Colors.white70 : Colors.grey[500],
@ -307,15 +296,6 @@ class SettingsView extends GetView<SettingsController> {
}, },
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
), ),
Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 语音服务选择
_buildSpeechServiceSetting(isDarkMode),
Divider( Divider(
height: 1, height: 1,
color: isDarkMode color: isDarkMode
@ -324,8 +304,8 @@ class SettingsView extends GetView<SettingsController> {
// 隐私设置 // 隐私设置
_buildSimpleNavigationSetting( _buildSimpleNavigationSetting(
title: 'privacySettings'.tr, // 隐私设置 title: '隐私设置',
subtitle: 'privacySettingsInfo'.tr, // 管理数据收集和权限 subtitle: '管理数据收集和权限',
icon: Icons.shield_outlined, icon: Icons.shield_outlined,
iconBgColor: isDarkMode iconBgColor: isDarkMode
? Colors.purple[900]!.withOpacity(0.3) ? Colors.purple[900]!.withOpacity(0.3)
@ -335,7 +315,7 @@ class SettingsView extends GetView<SettingsController> {
titleColor: isDarkMode ? Colors.white : null, titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null, subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () { onTap: () {
AppSettings.openAppSettings(); // 打开隐私设置页面
}, },
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
), ),
@ -347,7 +327,7 @@ class SettingsView extends GetView<SettingsController> {
// 退出登录 // 退出登录
_buildSimpleNavigationSetting( _buildSimpleNavigationSetting(
title: 'logout'.tr, // 退出登录 title: '退出登录',
icon: Icons.logout, icon: Icons.logout,
iconBgColor: isDarkMode iconBgColor: isDarkMode
? Colors.red[900]!.withOpacity(0.3) ? Colors.red[900]!.withOpacity(0.3)
@ -362,13 +342,13 @@ class SettingsView extends GetView<SettingsController> {
backgroundColor: backgroundColor:
isDarkMode ? Colors.grey[900] : Colors.white, isDarkMode ? Colors.grey[900] : Colors.white,
title: Text( title: Text(
'logout'.tr, // 退出登录 '退出登录',
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode ? Colors.white : Colors.black87,
), ),
), ),
content: Text( content: Text(
'logoutTips'.tr, // 确定要退出当前账号吗? '确定要退出当前账号吗?',
style: TextStyle( style: TextStyle(
color: color:
isDarkMode ? Colors.white70 : Colors.black54, isDarkMode ? Colors.white70 : Colors.black54,
@ -378,7 +358,7 @@ class SettingsView extends GetView<SettingsController> {
TextButton( TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: Text( child: Text(
'cancel'.tr, // 取消 '取消',
style: TextStyle( style: TextStyle(
color: isDarkMode color: isDarkMode
? Colors.white70 ? Colors.white70
@ -392,7 +372,7 @@ class SettingsView extends GetView<SettingsController> {
controller.signOut(); controller.signOut();
}, },
child: Text( child: Text(
'confirm'.tr, // 确定 '确定',
style: TextStyle( style: TextStyle(
color: isDarkMode color: isDarkMode
? Colors.red[300] ? Colors.red[300]
@ -423,7 +403,7 @@ class SettingsView extends GetView<SettingsController> {
Padding( Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h), padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text( child: Text(
'aboutApplication'.tr, // 关于应用 '关于应用',
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -485,7 +465,7 @@ class SettingsView extends GetView<SettingsController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'DeepSound', 'DeepVoice',
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -494,7 +474,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
SizedBox(height: 2.h), SizedBox(height: 2.h),
Text( Text(
'${'versions'.tr} 2.4.1 (Build 87)', // 版本 '版本 2.4.1 (Build 87)',
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: color:
@ -515,7 +495,7 @@ class SettingsView extends GetView<SettingsController> {
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Text( child: Text(
'checkUpdates'.tr, // 检查更新 '检查更新',
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.blue[300] : Colors.blue[600], color: isDarkMode ? Colors.blue[300] : Colors.blue[600],
@ -532,7 +512,7 @@ class SettingsView extends GetView<SettingsController> {
child: Column( child: Column(
children: [ children: [
Text( Text(
'© 2025 DeepSound Technologies', '© 2023 DeepVoice Technologies',
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
@ -540,7 +520,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
'homeSlogan'.tr, // 连接世界,超越声音 '连接世界,超越声音',
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
@ -569,51 +549,45 @@ class SettingsView extends GetView<SettingsController> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Row(
child: Row( children: [
children: [ Container(
Container( width: 32.w,
width: 32.w, height: 32.w,
height: 32.w, decoration: BoxDecoration(
decoration: BoxDecoration( color: iconBgColor,
color: iconBgColor, borderRadius: BorderRadius.circular(16.r),
borderRadius: BorderRadius.circular(16.r),
),
child: Icon(
icon,
size: 16.w,
color: iconColor,
),
), ),
SizedBox(width: 12.w), child: Icon(
Flexible( icon,
child: Column( size: 16.w,
crossAxisAlignment: CrossAxisAlignment.start, color: iconColor,
children: [
Text(
title,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
overflow: TextOverflow.ellipsis,
),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
overflow: TextOverflow.ellipsis,
),
],
),
), ),
], ),
), SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
),
],
), ),
Switch( Switch(
value: value, value: value,
@ -644,66 +618,55 @@ class SettingsView extends GetView<SettingsController> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Row(
child: Row( children: [
children: [ Container(
Container( width: 32.w,
width: 32.w, height: 32.w,
height: 32.w, decoration: BoxDecoration(
decoration: BoxDecoration( color: iconBgColor,
color: iconBgColor, borderRadius: BorderRadius.circular(16.r),
borderRadius: BorderRadius.circular(16.r),
),
child: Icon(
icon,
size: 16.w,
color: iconColor,
),
), ),
SizedBox(width: 12.w), child: Icon(
Flexible( icon,
child: Column( size: 16.w,
crossAxisAlignment: CrossAxisAlignment.start, color: iconColor,
children: [
Text(
title,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
overflow: TextOverflow.ellipsis,
),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
style: TextStyle(
fontSize: 12.sp,
color:
isDarkMode ? Colors.white70 : Colors.black54,
),
overflow: TextOverflow.ellipsis,
),
],
),
), ),
], ),
), SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
),
],
), ),
Row( Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
Flexible( Text(
child: Text( value,
value, style: valueStyle ??
style: valueStyle ?? TextStyle(
TextStyle( fontSize: 14.sp,
fontSize: 14.sp, color: isDarkMode ? Colors.white : Colors.black87,
color: isDarkMode ? Colors.white : Colors.black87, ),
),
overflow: TextOverflow.ellipsis,
),
), ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Container( Container(
@ -748,391 +711,64 @@ class SettingsView extends GetView<SettingsController> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded(
child: Row(
children: [
Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: iconBgColor,
borderRadius: BorderRadius.circular(16.r),
),
child: Icon(
icon,
size: 16.w,
color: iconColor,
),
),
SizedBox(width: 12.w),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: titleColor ??
(isDarkMode ? Colors.white : Colors.black87),
),
overflow: TextOverflow.ellipsis,
),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: subtitleColor ??
(isDarkMode
? Colors.white70
: Colors.black54),
),
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r),
),
child: Icon(
Icons.chevron_right,
size: 16.w,
color: isDarkMode ? Colors.white70 : Colors.grey[500],
),
),
],
),
),
);
}
// 语音服务设置项
Widget _buildSpeechServiceSetting(bool isDarkMode) {
return InkWell(
onTap: () {
_showSpeechServiceSelectionDialog(isDarkMode);
},
child: Padding(
padding: EdgeInsets.all(16.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.teal[900]!.withOpacity(0.3)
: Colors.teal[100]!,
borderRadius: BorderRadius.circular(16.r),
),
child: Icon(
Icons.record_voice_over,
size: 16.w,
color: isDarkMode ? Colors.teal[300]! : Colors.teal[600]!,
),
),
SizedBox(width: 12.w),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'voiceService'.tr, // 语音服务
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
),
SizedBox(height: 2.h),
Text(
'voiceServiceInfo'.tr, // 选择语音识别和合成服务
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
Row( Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
Obx(() {
final serviceType = controller.speechServiceType.value;
final serviceName = controller.availableSpeechServices
.firstWhere(
(service) => service['type'] == serviceType)['name'];
return Flexible(
child: Text(
'$serviceName'.tr,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600],
),
overflow: TextOverflow.ellipsis,
),
);
}),
SizedBox(width: 8.w),
Container( Container(
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode color: iconBgColor,
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Icon( child: Icon(
Icons.chevron_right, icon,
size: 16.w, size: 16.w,
color: isDarkMode ? Colors.white70 : Colors.grey[500], color: iconColor,
), ),
), ),
], SizedBox(width: 12.w),
), Column(
], crossAxisAlignment: CrossAxisAlignment.start,
), children: [
), Text(
); title,
}
// 显示语音服务选择对话框
void _showSpeechServiceSelectionDialog(bool isDarkMode) {
Get.dialog(
Dialog(
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r),
),
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'selectVoiceService'.tr, // 选择语音服务
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black87,
),
),
SizedBox(height: 16.h),
...controller.availableSpeechServices.map((service) {
return Obx(() {
final isSelected =
controller.speechServiceType.value == service['type'];
return InkWell(
onTap: () {
controller.setSpeechServiceType(service['type']);
Get.back();
},
child: Container(
margin: EdgeInsets.only(bottom: 12.h),
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: isSelected
? (isDarkMode
? Colors.teal[900]!.withOpacity(0.3)
: Colors.teal[50]!)
: (isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100]!),
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color: isSelected
? (isDarkMode
? Colors.teal[300]!
: Colors.teal[600]!)
: Colors.transparent,
width: 1,
),
),
child: Row(
children: [
Container(
width: 24.w,
height: 24.w,
decoration: BoxDecoration(
color: isSelected
? (isDarkMode
? Colors.teal[300]
: Colors.teal[600])
: (isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[300]),
shape: BoxShape.circle,
),
child: isSelected
? Icon(
Icons.check,
size: 16.w,
color: Colors.white,
)
: null,
),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${service['name']}'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode
? Colors.white
: Colors.black87,
),
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 4.h),
Text(
'${service['description']}'.tr,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode
? Colors.white70
: Colors.black54,
),
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
],
),
),
],
),
),
);
});
}).toList(),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr, // 取消
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54, fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: titleColor ??
(isDarkMode ? Colors.white : Colors.black87),
), ),
), ),
), if (subtitle != null) SizedBox(height: 2.h),
], if (subtitle != null)
), Text(
], subtitle,
), style: TextStyle(
), fontSize: 12.sp,
), color: subtitleColor ??
); (isDarkMode ? Colors.white70 : Colors.black54),
}
// 显示语言选择对话框
void _showLanguageSelectionDialog(bool isDarkMode) {
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24.r),
),
insetPadding: EdgeInsets.symmetric(horizontal: 20.w),
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
child: Container(
width: 0.9.sw,
padding: EdgeInsets.only(top: 32.h, bottom: 16.h),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: Text(
'selectLanguage'.tr, // 选择语言
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
),
SizedBox(height: 16.h),
Container(
constraints: BoxConstraints(maxHeight: 0.5.sh),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: controller.languageList.map((language) {
return ListTile(
title: Text(
language.name.tr,
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black,
),
), ),
trailing:
controller.language.value.value == language.value
? Icon(
Icons.check_circle,
color: isDarkMode
? AppColors.primary
: Colors.blue,
)
: const SizedBox.shrink(),
onTap: () {
controller.setLanguage(language);
},
);
}).toList(),
),
),
),
SizedBox(height: 16.h),
Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(right: 24.w),
child: TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr, // 取消
style: TextStyle(
color: isDarkMode ? AppColors.primary : Colors.blue,
fontSize: 16.sp,
), ),
), ],
),
), ),
],
),
Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r),
), ),
], child: Icon(
), Icons.chevron_right,
size: 16.w,
color: isDarkMode ? Colors.white70 : Colors.grey[500],
),
),
],
), ),
), ),
); );

12
lib/routes/app_pages.dart

@ -4,6 +4,8 @@ import '../modules/home/bindings/home_binding.dart';
import '../modules/explore/views/explore_view.dart'; import '../modules/explore/views/explore_view.dart';
import '../modules/explore/bindings/explore_binding.dart'; import '../modules/explore/bindings/explore_binding.dart';
import '../modules/meeting/bindings/meeting_binding.dart'; import '../modules/meeting/bindings/meeting_binding.dart';
import '../modules/meeting/bindings/meeting_record_binding.dart';
import '../modules/meeting/views/meeting_record_view.dart';
import '../modules/meeting/views/meeting_view.dart'; import '../modules/meeting/views/meeting_view.dart';
import '../modules/profile/views/profile_view.dart'; import '../modules/profile/views/profile_view.dart';
import '../modules/profile/bindings/profile_binding.dart'; import '../modules/profile/bindings/profile_binding.dart';
@ -58,7 +60,7 @@ abstract class AppPages {
), ),
GetPage( GetPage(
name: Routes.chat, name: Routes.chat,
page: () => ChatView(), page: () => const ChatView(),
binding: ChatBinding(), binding: ChatBinding(),
), ),
GetPage( GetPage(
@ -70,8 +72,7 @@ abstract class AppPages {
name: Routes.editProfile, name: Routes.editProfile,
page: () => const EditProfileView(), page: () => const EditProfileView(),
binding: ProfileBinding(), binding: ProfileBinding(),
), ),
GetPage( GetPage(
name: Routes.translation, name: Routes.translation,
page: () => const TranslationView(), page: () => const TranslationView(),
@ -87,6 +88,11 @@ abstract class AppPages {
page: () => const MeetingView(), page: () => const MeetingView(),
binding: MeetingBinding(), binding: MeetingBinding(),
), ),
GetPage(
name: Routes.meetingRecord,
page: () => const MeetingRecordView(),
binding: MeetingRecordBinding(),
),
GetPage( GetPage(
name: Routes.settings, name: Routes.settings,
page: () => const SettingsView(), page: () => const SettingsView(),

5
lib/routes/app_routes.dart

@ -8,6 +8,7 @@ abstract class Routes {
static const chat = '/chat'; static const chat = '/chat';
static const profile = '/profile'; static const profile = '/profile';
static const meeting = '/meeting'; static const meeting = '/meeting';
static const meetingRecord = '/meetingRecord';
static const settings = '/settings'; static const settings = '/settings';
static const speechDemo = '/speech_demo'; static const speechDemo = '/speech_demo';
static const TTS_TEST = '/tts_test'; static const TTS_TEST = '/tts_test';
@ -19,5 +20,5 @@ abstract class Routes {
static const translationHistory = '/translation_history'; static const translationHistory = '/translation_history';
static const FLUTTER_TTS_TEST = '/flutter_tts_test'; static const FLUTTER_TTS_TEST = '/flutter_tts_test';
static const FLUTTER_ASR_TEST = '/flutter_asr_test'; static const FLUTTER_ASR_TEST = '/flutter_asr_test';
static const editProfile='/edit_profile'; static const editProfile = '/edit_profile';
} }

4
pubspec.yaml

@ -55,9 +55,11 @@ dependencies:
firebase_auth: ^5.5.0 firebase_auth: ^5.5.0
google_sign_in: ^6.2.2 google_sign_in: ^6.2.2
flutter_facebook_auth: ^7.1.1 flutter_facebook_auth: ^7.1.1
common_utils: ^2.1.0
flutter_image_compress: ^2.4.0 flutter_image_compress: ^2.4.0
# image_cropper: ^9.0.0 # image_cropper: ^9.0.0
dio: ^5.8.0+1
flutter_easyloading: ^3.0.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter

Loading…
Cancel
Save