浏览代码

上傳代碼

master
liwei1dao 2 个月前
父节点
当前提交
c191c5d99c
共有 51 个文件被更改,包括 2724 次插入429 次删除
  1. 二进制
      assets/icon/bottom_nav_home_select.png
  2. 二进制
      assets/icon/bottom_nav_home_unselect.gif
  3. 二进制
      assets/icon/bottom_nav_profile_select.png
  4. 二进制
      assets/icon/bottom_nav_profile_unselect.png
  5. 二进制
      assets/icon/bottom_nav_sleep_select.png
  6. 二进制
      assets/icon/bottom_nav_sleep_unselect.png
  7. 二进制
      assets/icon/home_ai_model.png
  8. 二进制
      assets/icon/home_bluetooth.png
  9. 二进制
      assets/icon/home_icon_fyjl.png
  10. 二进制
      assets/icon/home_icon_mdmfy.png
  11. 二进制
      assets/icon/home_icon_tcty.png
  12. 二进制
      assets/icon/home_icon_thyyfy.png
  13. 二进制
      assets/icon/home_img.png
  14. 二进制
      assets/icon/home_question.png
  15. 二进制
      assets/icon/icon.png
  16. 二进制
      assets/img/image_ai.png
  17. 二进制
      assets/img/image_bg_blur.png
  18. 二进制
      assets/img/image_user.png
  19. +197
    -0
      lib/gen/assets.gen.dart
  20. +67
    -0
      lib/generated/intl/messages_all.dart
  21. +29
    -0
      lib/generated/intl/messages_en.dart
  22. +29
    -0
      lib/generated/intl/messages_zh.dart
  23. +109
    -0
      lib/generated/l10n.dart
  24. +6
    -0
      lib/l10n/intl_en.arb
  25. +6
    -0
      lib/l10n/intl_zh.arb
  26. +119
    -6
      lib/main.dart
  27. +0
    -129
      lib/scenes/AIChatScene.dart
  28. +0
    -114
      lib/scenes/BluetoothScene.dart
  29. +92
    -0
      lib/scenes/home/home_logic.dart
  30. +23
    -0
      lib/scenes/home/home_state.dart
  31. +235
    -0
      lib/scenes/home/home_view.dart
  32. +105
    -0
      lib/scenes/login/login_logic.dart
  33. +32
    -0
      lib/scenes/login/login_state.dart
  34. +317
    -0
      lib/scenes/login/login_view.dart
  35. +20
    -0
      lib/scenes/login/model/data.dart
  36. +19
    -0
      lib/scenes/login/model/data.g.dart
  37. +26
    -0
      lib/scenes/login/model/login_model.dart
  38. +22
    -0
      lib/scenes/login/model/login_model.g.dart
  39. +37
    -0
      lib/scenes/login/model/user.dart
  40. +31
    -0
      lib/scenes/login/model/user.g.dart
  41. +14
    -0
      lib/scenes/public.dart
  42. +55
    -6
      lib/scenes/translate/TranslateLogic.dart
  43. +98
    -51
      lib/scenes/translate/TranslateScene.dart
  44. +52
    -0
      lib/tools/color_utils.dart
  45. +259
    -0
      lib/tools/http_utils.dart
  46. +32
    -0
      lib/tools/textStyle.dart
  47. +21
    -0
      lib/tools/widgets.dart
  48. +2
    -2
      lib/xunfei/xunfei_translate.dart
  49. +2
    -0
      macos/Flutter/GeneratedPluginRegistrant.swift
  50. +654
    -116
      pubspec.lock
  51. +14
    -5
      pubspec.yaml

二进制
assets/icon/bottom_nav_home_select.png 查看文件

之前 之后
宽度: 60  |  高度: 60  |  大小: 1.6 KiB

二进制
assets/icon/bottom_nav_home_unselect.gif 查看文件

之前 之后
宽度: 60  |  高度: 60  |  大小: 2.1 KiB

二进制
assets/icon/bottom_nav_profile_select.png 查看文件

之前 之后
宽度: 60  |  高度: 60  |  大小: 1.6 KiB

二进制
assets/icon/bottom_nav_profile_unselect.png 查看文件

之前 之后
宽度: 60  |  高度: 60  |  大小: 1.9 KiB

二进制
assets/icon/bottom_nav_sleep_select.png 查看文件

之前 之后
宽度: 60  |  高度: 60  |  大小: 2.0 KiB

二进制
assets/icon/bottom_nav_sleep_unselect.png 查看文件

之前 之后
宽度: 60  |  高度: 60  |  大小: 2.5 KiB

二进制
assets/icon/home_ai_model.png 查看文件

之前 之后
宽度: 1224  |  高度: 372  |  大小: 98 KiB

二进制
assets/icon/home_bluetooth.png 查看文件

之前 之后
宽度: 418  |  高度: 114  |  大小: 4.2 KiB

二进制
assets/icon/home_icon_fyjl.png 查看文件

之前 之后
宽度: 588  |  高度: 565  |  大小: 58 KiB

二进制
assets/icon/home_icon_mdmfy.png 查看文件

之前 之后
宽度: 588  |  高度: 565  |  大小: 42 KiB

二进制
assets/icon/home_icon_tcty.png 查看文件

之前 之后
宽度: 588  |  高度: 565  |  大小: 60 KiB

二进制
assets/icon/home_icon_thyyfy.png 查看文件

之前 之后
宽度: 588  |  高度: 565  |  大小: 55 KiB

二进制
assets/icon/home_img.png 查看文件

之前 之后
宽度: 628  |  高度: 589  |  大小: 157 KiB

二进制
assets/icon/home_question.png 查看文件

之前 之后
宽度: 72  |  高度: 72  |  大小: 3.0 KiB

二进制
assets/icon/icon.png 查看文件

之前 之后
宽度: 1024  |  高度: 1024  |  大小: 1.2 MiB

二进制
assets/img/image_ai.png 查看文件

之前 之后
宽度: 648  |  高度: 686  |  大小: 238 KiB

二进制
assets/img/image_bg_blur.png 查看文件

之前 之后
宽度: 854  |  高度: 746  |  大小: 246 KiB

二进制
assets/img/image_user.png 查看文件

之前 之后
宽度: 514  |  高度: 488  |  大小: 250 KiB

+ 197
- 0
lib/gen/assets.gen.dart 查看文件

@@ -0,0 +1,197 @@
/// GENERATED CODE - DO NOT MODIFY BY HAND
/// *****************************************************
/// FlutterGen
/// *****************************************************

// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use

import 'package:flutter/widgets.dart';

class $AssetsIconGen {
const $AssetsIconGen();

/// File path: assets/icon/bottom_nav_home_select.png
AssetGenImage get bottomNavHomeSelect =>
const AssetGenImage('assets/icon/bottom_nav_home_select.png');

/// File path: assets/icon/bottom_nav_home_unselect.gif
AssetGenImage get bottomNavHomeUnselect =>
const AssetGenImage('assets/icon/bottom_nav_home_unselect.gif');

/// File path: assets/icon/bottom_nav_profile_select.png
AssetGenImage get bottomNavProfileSelect =>
const AssetGenImage('assets/icon/bottom_nav_profile_select.png');

/// File path: assets/icon/bottom_nav_profile_unselect.png
AssetGenImage get bottomNavProfileUnselect =>
const AssetGenImage('assets/icon/bottom_nav_profile_unselect.png');

/// File path: assets/icon/bottom_nav_sleep_select.png
AssetGenImage get bottomNavSleepSelect =>
const AssetGenImage('assets/icon/bottom_nav_sleep_select.png');

/// File path: assets/icon/bottom_nav_sleep_unselect.png
AssetGenImage get bottomNavSleepUnselect =>
const AssetGenImage('assets/icon/bottom_nav_sleep_unselect.png');

/// File path: assets/icon/home_ai_model.png
AssetGenImage get homeAiModel =>
const AssetGenImage('assets/icon/home_ai_model.png');

/// File path: assets/icon/home_bluetooth.png
AssetGenImage get homeBluetooth =>
const AssetGenImage('assets/icon/home_bluetooth.png');

/// File path: assets/icon/home_icon_fyjl.png
AssetGenImage get homeIconFyjl =>
const AssetGenImage('assets/icon/home_icon_fyjl.png');

/// File path: assets/icon/home_icon_mdmfy.png
AssetGenImage get homeIconMdmfy =>
const AssetGenImage('assets/icon/home_icon_mdmfy.png');

/// File path: assets/icon/home_icon_tcty.png
AssetGenImage get homeIconTcty =>
const AssetGenImage('assets/icon/home_icon_tcty.png');

/// File path: assets/icon/home_icon_thyyfy.png
AssetGenImage get homeIconThyyfy =>
const AssetGenImage('assets/icon/home_icon_thyyfy.png');

/// File path: assets/icon/home_img.png
AssetGenImage get homeImg => const AssetGenImage('assets/icon/home_img.png');

/// File path: assets/icon/home_question.png
AssetGenImage get homeQuestion =>
const AssetGenImage('assets/icon/home_question.png');

/// File path: assets/icon/icon.png
AssetGenImage get icon => const AssetGenImage('assets/icon/icon.png');

/// List of all assets
List<AssetGenImage> get values => [
bottomNavHomeSelect,
bottomNavHomeUnselect,
bottomNavProfileSelect,
bottomNavProfileUnselect,
bottomNavSleepSelect,
bottomNavSleepUnselect,
homeAiModel,
homeBluetooth,
homeIconFyjl,
homeIconMdmfy,
homeIconTcty,
homeIconThyyfy,
homeImg,
homeQuestion,
icon
];
}

class $AssetsImgGen {
const $AssetsImgGen();

/// File path: assets/img/image_ai.png
AssetGenImage get imageAi => const AssetGenImage('assets/img/image_ai.png');

/// File path: assets/img/image_bg_blur.png
AssetGenImage get imageBgBlur =>
const AssetGenImage('assets/img/image_bg_blur.png');

/// File path: assets/img/image_user.png
AssetGenImage get imageUser =>
const AssetGenImage('assets/img/image_user.png');

/// List of all assets
List<AssetGenImage> get values => [imageAi, imageBgBlur, imageUser];
}

class Assets {
const Assets._();

static const $AssetsIconGen icon = $AssetsIconGen();
static const $AssetsImgGen img = $AssetsImgGen();
}

class AssetGenImage {
const AssetGenImage(
this._assetName, {
this.size,
this.flavors = const {},
});

final String _assetName;

final Size? size;
final Set<String> flavors;

Image image({
Key? key,
AssetBundle? bundle,
ImageFrameBuilder? frameBuilder,
ImageErrorWidgetBuilder? errorBuilder,
String? semanticLabel,
bool excludeFromSemantics = false,
double? scale,
double? width,
double? height,
Color? color,
Animation<double>? opacity,
BlendMode? colorBlendMode,
BoxFit? fit,
AlignmentGeometry alignment = Alignment.center,
ImageRepeat repeat = ImageRepeat.noRepeat,
Rect? centerSlice,
bool matchTextDirection = false,
bool gaplessPlayback = true,
bool isAntiAlias = false,
String? package,
FilterQuality filterQuality = FilterQuality.medium,
int? cacheWidth,
int? cacheHeight,
}) {
return Image.asset(
_assetName,
key: key,
bundle: bundle,
frameBuilder: frameBuilder,
errorBuilder: errorBuilder,
semanticLabel: semanticLabel,
excludeFromSemantics: excludeFromSemantics,
scale: scale,
width: width,
height: height,
color: color,
opacity: opacity,
colorBlendMode: colorBlendMode,
fit: fit,
alignment: alignment,
repeat: repeat,
centerSlice: centerSlice,
matchTextDirection: matchTextDirection,
gaplessPlayback: gaplessPlayback,
isAntiAlias: isAntiAlias,
package: package,
filterQuality: filterQuality,
cacheWidth: cacheWidth,
cacheHeight: cacheHeight,
);
}

ImageProvider provider({
AssetBundle? bundle,
String? package,
}) {
return AssetImage(
_assetName,
bundle: bundle,
package: package,
);
}

String get path => _assetName;

String get keyName => _assetName;
}

+ 67
- 0
lib/generated/intl/messages_all.dart 查看文件

@@ -0,0 +1,67 @@
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that looks up messages for specific locales by
// delegating to the appropriate library.

// Ignore issues from commonly used lints in this file.
// ignore_for_file:implementation_imports, file_names, unnecessary_new
// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering
// ignore_for_file:argument_type_not_assignable, invalid_assignment
// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases
// ignore_for_file:comment_references

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';

import 'messages_en.dart' as messages_en;
import 'messages_zh.dart' as messages_zh;

typedef Future<dynamic> LibraryLoader();
Map<String, LibraryLoader> _deferredLibraries = {
'en': () => new SynchronousFuture(null),
'zh': () => new SynchronousFuture(null),
};

MessageLookupByLibrary? _findExact(String localeName) {
switch (localeName) {
case 'en':
return messages_en.messages;
case 'zh':
return messages_zh.messages;
default:
return null;
}
}

/// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) {
var availableLocale = Intl.verifiedLocale(
localeName, (locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null);
if (availableLocale == null) {
return new SynchronousFuture(false);
}
var lib = _deferredLibraries[availableLocale];
lib == null ? new SynchronousFuture(false) : lib();
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
return new SynchronousFuture(true);
}

bool _messagesExistFor(String locale) {
try {
return _findExact(locale) != null;
} catch (e) {
return false;
}
}

MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
var actualLocale =
Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null);
if (actualLocale == null) return null;
return _findExact(actualLocale);
}

+ 29
- 0
lib/generated/intl/messages_en.dart 查看文件

@@ -0,0 +1,29 @@
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a en locale. All the
// messages from the main program should be duplicated here with the same
// function name.

// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes
// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes

import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';

final messages = new MessageLookup();

typedef String MessageIfAbsent(String messageStr, List<dynamic> args);

class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'en';

final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"bottomNavHome": MessageLookupByLibrary.simpleMessage("home"),
"bottomNavProfile": MessageLookupByLibrary.simpleMessage("profile"),
"bottomNavSleep": MessageLookupByLibrary.simpleMessage("sleep")
};
}

+ 29
- 0
lib/generated/intl/messages_zh.dart 查看文件

@@ -0,0 +1,29 @@
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a zh locale. All the
// messages from the main program should be duplicated here with the same
// function name.

// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes
// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes

import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';

final messages = new MessageLookup();

typedef String MessageIfAbsent(String messageStr, List<dynamic> args);

class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'zh';

final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"bottomNavHome": MessageLookupByLibrary.simpleMessage("首页"),
"bottomNavProfile": MessageLookupByLibrary.simpleMessage("我的"),
"bottomNavSleep": MessageLookupByLibrary.simpleMessage("睡眠")
};
}

+ 109
- 0
lib/generated/l10n.dart 查看文件

@@ -0,0 +1,109 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'intl/messages_all.dart';

// **************************************************************************
// Generator: Flutter Intl IDE plugin
// Made by Localizely
// **************************************************************************

// ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars
// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each
// ignore_for_file: avoid_redundant_argument_values, avoid_escaping_inner_quotes

class S {
S();

static S? _current;

static S get current {
assert(_current != null,
'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.');
return _current!;
}

static const AppLocalizationDelegate delegate = AppLocalizationDelegate();

static Future<S> load(Locale locale) {
final name = (locale.countryCode?.isEmpty ?? false)
? locale.languageCode
: locale.toString();
final localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;
final instance = S();
S._current = instance;

return instance;
});
}

static S of(BuildContext context) {
final instance = S.maybeOf(context);
assert(instance != null,
'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?');
return instance!;
}

static S? maybeOf(BuildContext context) {
return Localizations.of<S>(context, S);
}

/// `home`
String get bottomNavHome {
return Intl.message(
'home',
name: 'bottomNavHome',
desc: '',
args: [],
);
}

/// `sleep`
String get bottomNavSleep {
return Intl.message(
'sleep',
name: 'bottomNavSleep',
desc: '',
args: [],
);
}

/// `profile`
String get bottomNavProfile {
return Intl.message(
'profile',
name: 'bottomNavProfile',
desc: '',
args: [],
);
}
}

class AppLocalizationDelegate extends LocalizationsDelegate<S> {
const AppLocalizationDelegate();

List<Locale> get supportedLocales {
return const <Locale>[
Locale.fromSubtags(languageCode: 'en'),
Locale.fromSubtags(languageCode: 'zh'),
];
}

@override
bool isSupported(Locale locale) => _isSupported(locale);
@override
Future<S> load(Locale locale) => S.load(locale);
@override
bool shouldReload(AppLocalizationDelegate old) => false;

bool _isSupported(Locale locale) {
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode) {
return true;
}
}
return false;
}
}

+ 6
- 0
lib/l10n/intl_en.arb 查看文件

@@ -0,0 +1,6 @@
{
"@@locale": "en",
"bottomNavHome": "home",
"bottomNavSleep": "sleep",
"bottomNavProfile": "profile"
}

+ 6
- 0
lib/l10n/intl_zh.arb 查看文件

@@ -0,0 +1,6 @@
{
"@@locale": "zh",
"bottomNavHome": "首页",
"bottomNavSleep": "睡眠",
"bottomNavProfile": "我的"
}

+ 119
- 6
lib/main.dart 查看文件

@@ -1,8 +1,27 @@
import 'package:demo001/gen/assets.gen.dart';
import 'package:demo001/generated/l10n.dart';
import 'package:demo001/scenes/home/home_view.dart';
import 'package:demo001/scenes/translate/TranslateScene.dart';
import 'package:demo001/tools/color_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';

import 'scenes/login/login_view.dart';

void main() {
WidgetsFlutterBinding.ensureInitialized();
EasyLoading.instance
..indicatorType = EasyLoadingIndicatorType.threeBounce
..maskType = EasyLoadingMaskType.black
..progressColor = Colors.white
..backgroundColor = const Color.fromRGBO(38, 38, 38, 1)
..indicatorColor = Colors.white
..textColor = Colors.white
..userInteractions = false
..displayDuration = 1.5.seconds
..dismissOnTap = false;
runApp(const MyApp());
}

@@ -12,13 +31,107 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
return GetMaterialApp(
locale: Get.deviceLocale,
fallbackLocale: Get.deviceLocale,
title: '智能耳机',
debugShowCheckedModeBanner: false,
defaultTransition: Transition.rightToLeft,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: TranslateScene(),
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
appBarTheme: const AppBarTheme(
centerTitle: true,
iconTheme: IconThemeData(color: whiteGrey),
surfaceTintColor: white,
shape: Border(bottom: BorderSide(color: lightBlue, width: 1)),
backgroundColor: bgColor,
),
scaffoldBackgroundColor: bgColor,
splashColor: clean,
highlightColor: clean,
switchTheme: SwitchThemeData(
trackOutlineColor: const WidgetStatePropertyAll(blue),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return blue;
} else {
return silver.withOpacity(0.5);
}
}),
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return white;
} else {
return silver;
}
}),
trackOutlineWidth: const WidgetStatePropertyAll(0)),
navigationBarTheme: NavigationBarThemeData()),
localizationsDelegates: {
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
},
supportedLocales: S.delegate.supportedLocales,
home: LoginScene(),
builder: (context, widget) {
final easyload = EasyLoading.init();
var child = easyload(context, widget);
return MediaQuery(
data:
MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling),
child: child,
);
},
);
}
}

S? s;

class IndexWidget extends StatelessWidget {
final RxInt _currentIndex = 0.obs;

final List<Widget> _pages = [HomePage()];

@override
Widget build(BuildContext context) {
return Scaffold(
body: Obx(() => _pages[_currentIndex.value]),
bottomNavigationBar: Builder(builder: (context) {
s = S.of(context);
return Obx(() => BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: bottomNavBg,
currentIndex: _currentIndex.value,
selectedItemColor: white,
unselectedItemColor: grey,
items: [
BottomNavigationBarItem(
icon: Assets.icon.bottomNavHomeUnselect
.image(width: 20, height: 20),
activeIcon: Assets.icon.bottomNavHomeSelect
.image(width: 20, height: 20),
label: s?.bottomNavHome),
BottomNavigationBarItem(
icon: Assets.icon.bottomNavSleepUnselect
.image(width: 20, height: 20),
activeIcon: Assets.icon.bottomNavSleepSelect
.image(width: 20, height: 20),
label: s?.bottomNavSleep),
BottomNavigationBarItem(
icon: Assets.icon.bottomNavProfileUnselect
.image(width: 20, height: 20),
activeIcon: Assets.icon.bottomNavProfileSelect
.image(width: 20, height: 20),
label: s?.bottomNavProfile),
],
onTap: (index) {
_currentIndex.value = index;
},
));
}));
}
}

+ 0
- 129
lib/scenes/AIChatScene.dart 查看文件

@@ -1,129 +0,0 @@
/*
AI测试场景
*/
import 'package:flutter/material.dart';
import 'package:demo001/doubao/DouBao.dart';

class ChatItem {
String msg = "";
int state = 0;

ChatItem({required this.msg});

void append(String _msg) {
msg += _msg;
}

void end() {
state = 1;
}
}

class AIChatScene extends StatefulWidget {
@override
_AIChatSceneState createState() => _AIChatSceneState();
}

class _AIChatSceneState extends State<AIChatScene> {
// final String apiKey = "sk-3adfd188a3134e718bbf704f525aff17";
final Doubao doubao = Doubao(
apiKey: "418ec475-e2dc-4b76-8aca-842d81bc3466",
modelId: "ep-20250203161136-9lrxg");

final List<ChatItem> _chats = [ChatItem(msg: "我是测试代码")];
ChatItem? _currchat;
final TextEditingController _textController = TextEditingController();

//发送消息
_sendMessage() async {
_currchat = ChatItem(msg: "");
setState(() {
_chats.add(_currchat!);
});
var stream = doubao.chat(_textController.text);
_textController.text = "";
await for (final content in stream) {
setState(() {
_currchat?.append(content);
});
print('实时更新: $content');
}
print('结束恢复');
_currchat?.end();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("AI测试")),
body: ListView.builder(
itemCount: _chats.length,
itemBuilder: (context, index) {
var item = _chats[index];
return _buildAudioMessage(item);
},
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200], // 背景颜色
borderRadius: BorderRadius.circular(30), // 圆角
),
padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 10), // 输入框和按钮的内边距
child: Row(
children: [
Expanded(
child: TextField(
controller: _textController, // 用于获取输入的文本
decoration: InputDecoration(
hintText: '输入消息...', // 提示文本
border: InputBorder.none, // 去除默认边框
contentPadding:
EdgeInsets.symmetric(vertical: 12), // 调整内边距
),
),
),
IconButton(
icon: Icon(Icons.send, color: Colors.blue), // 发送按钮图标
onPressed: _sendMessage, // 发送按钮点击事件
),
],
),
),
));
}

// 构建语音消息
Widget _buildAudioMessage(ChatItem data) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 音频播放按钮
GestureDetector(
onTap: () {},
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(30),
),
child: Row(
children: [
Text(
data.msg,
style: TextStyle(color: Colors.white),
),
],
),
),
),
SizedBox(height: 5),
],
),
);
}
}

+ 0
- 114
lib/scenes/BluetoothScene.dart 查看文件

@@ -1,114 +0,0 @@
// /*
// 蓝牙测试场景
// */
// import 'package:flutter/material.dart';
// import 'package:flutter_blue/flutter_blue.dart';

// class BluetoothScene extends StatefulWidget {
// @override
// _BluetoothSceneState createState() => _BluetoothSceneState();
// }

// class _BluetoothSceneState extends State<BluetoothScene> {
// FlutterBlue flutterBlue = FlutterBlue.instance;
// List<BluetoothDevice> devicesList = [];
// BluetoothDevice? connectedDevice;
// BluetoothState? bluetoothState;

// @override
// void initState() {
// super.initState();
// flutterBlue.state.listen((state) {
// setState(() {
// bluetoothState = state;
// });
// });

// flutterBlue.scanResults.listen((results) {
// setState(() {
// devicesList = results
// .where((result) => result.device.name.isNotEmpty)
// .map((result) => result.device)
// .toList();
// });
// });
// }

// void startScan() {
// flutterBlue.startScan(timeout: Duration(seconds: 4));
// }

// void stopScan() {
// flutterBlue.stopScan();
// }

// void connectToDevice(BluetoothDevice device) async {
// await device.connect();
// setState(() {
// connectedDevice = device;
// });
// listenToDeviceEvents(device);
// }

// void listenToDeviceEvents(BluetoothDevice device) {
// device.state.listen((state) {
// if (state == BluetoothDeviceState.connected) {
// print('Device connected');
// } else if (state == BluetoothDeviceState.disconnected) {
// print('Device disconnected');
// }
// });

// device.discoverServices().then((services) {
// services.forEach((service) {
// service.characteristics.forEach((characteristic) {
// characteristic.setNotifyValue(true);
// characteristic.value.listen((value) {
// print('Received value: $value');
// });
// });
// });
// });
// }

// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: AppBar(title: Text('Flutter Bluetooth Demo')),
// body: Column(
// children: [
// if (bluetoothState == BluetoothState.off)
// Text('Bluetooth is off, please turn it on'),
// if (bluetoothState == BluetoothState.on)
// Column(
// children: [
// ElevatedButton(
// onPressed: startScan,
// child: Text('Start Scan'),
// ),
// ElevatedButton(
// onPressed: stopScan,
// child: Text('Stop Scan'),
// ),
// ListView.builder(
// shrinkWrap: true,
// itemCount: devicesList.length,
// itemBuilder: (context, index) {
// return ListTile(
// title: Text(devicesList[index].name),
// subtitle: Text(devicesList[index].id.toString()),
// onTap: () {
// connectToDevice(devicesList[index]);
// },
// );
// },
// ),
// if (connectedDevice != null)
// Text('Connected to: ${connectedDevice?.name}')
// ],
// ),
// ],
// ),
// );
// }
// }

+ 92
- 0
lib/scenes/home/home_logic.dart 查看文件

@@ -0,0 +1,92 @@
import 'dart:convert';

import 'package:demo001/scenes/login/login_view.dart';
import 'package:demo001/scenes/public.dart';
import 'package:demo001/tools/http_utils.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:logger/logger.dart';
import 'package:permission_handler/permission_handler.dart';
import 'home_state.dart';

/// @description:
/// @author
/// @date: 2025-01-07 15:51:34
class HomeLogic extends GetxController {
final state = HomeState();

//1.已连接到的蓝牙,2.失去连接的蓝牙
final String _bluetoothConnectStateKey = "bluetoothConnected";
final String _bluetoothDisConnectStateKey = "bluetoothDisConnect";
//1.已经连接的蓝牙
final String _bluetoothAlreadyConnectKey = "bluetoothAlreadyConnected";

@override
void onInit() {
super.onInit();
_getLoginInfo();
_checkPermission();
_checkConnectDevice();
_checkBluetoothStatus();
}

void _checkPermission() {
Permission.microphone.request();
state.methodChannel.invokeMethod("bluetoothPermissionRequest");
}

void _checkBluetoothStatus() {}

///获取登录信息
void _getLoginInfo() async {
final info = await getSharedLoginInfo();
if (info != null) {
state.loginModel = info;
_getAliToken();
} else {
EasyLoading.showError('登录过期');
Get.offAll(() => LoginScene());
}
}

void _getAliToken() {
ApiClient.post(
url: '/api/home/auth_alitoken',
token: state.loginModel!.data!.token!,
param: {},
onSuccess: (data) {
// Logger().i('---------_getAliToken--------token-:${data.runtimeType}');
// Logger().i('---------_getAliToken--------token-:${data['data']['token']}');
state.loginModel?.ali_appkey = data['data']['appkey'];
state.loginModel?.ali_token = data['data']['token'];
},
onFailed: (msg) {
Logger().e('-------_getAliToken-------error-$msg');
});
}

///原生传回的数据监听
void _phoneCallRecordingListenner() {
state.eventChannel.receiveBroadcastStream((data) {});
}

//开始监听蓝牙连接设备状态
void _checkConnectDevice() {
state.methodChannel.invokeMethod('checkConnectedBluetooth');
}

///通话翻译按钮点击
void startPhoneCallRecording() {
state.methodChannel.invokeMethod('startPhoneCallRecording');
}

///停止通讯录音
void stopPhoneCallRecording() {
state.methodChannel.invokeMethod('stopPhoneCallRecording');
}

//打开蓝牙扫描界面
void toBonding() {}

///**************通话录音翻译*************** */
}

+ 23
- 0
lib/scenes/home/home_state.dart 查看文件

@@ -0,0 +1,23 @@
import 'package:demo001/scenes/login/model/login_model.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';

/// @description:
/// @author
/// @date: 2025-01-07 15:51:34
class HomeState {
HomeState() {
///Initialize variables
}

EventChannel eventChannel = EventChannel('eventChannel');

MethodChannel methodChannel = MethodChannel('methodChannel');

RxString originText = 'english'.obs;
RxString translationText = '英语'.obs;

RxString phoneNum = ''.obs;

LoginModel? loginModel;
}

+ 235
- 0
lib/scenes/home/home_view.dart 查看文件

@@ -0,0 +1,235 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:audioplayers/audioplayers.dart';
import 'package:demo001/gen/assets.gen.dart';
import 'package:demo001/generated/l10n.dart';
import 'package:demo001/main.dart';
import 'package:demo001/tools/color_utils.dart';
import 'package:demo001/tools/textStyle.dart';
import 'package:demo001/tools/widgets.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:logger/logger.dart';
import 'package:path_provider/path_provider.dart';

import 'home_logic.dart';
import 'home_state.dart';

/// @description:
/// @author
/// @date: 2025-01-07 15:51:34
class HomePage extends StatelessWidget {
final HomeLogic logic = Get.put(HomeLogic());
final HomeState state = Get.find<HomeLogic>().state;

double width = 0;
double height = 0;

@override
Widget build(BuildContext context) {
s = S.of(context);
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
return Scaffold(
backgroundColor: bgColor,
body: SafeArea(
child: Container(
padding: EdgeInsets.all(10),
alignment: Alignment.center,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
alignment: Alignment.center,
child: Obx(() => Text(
state.phoneNum.value,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: white),
)),
),
const Gap(12),
Center(
child: Image.asset(
'assets/icon/home_img.png',
width: width * 0.5,
fit: BoxFit.fitWidth,
),
),
const Gap(20),
GestureDetector(
onTap: logic.toBonding,
child: Center(
child: Container(
height: 40,
decoration: BoxDecoration(
color: white,
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Gap(20),
Container(
width: 20,
height: 20,
alignment: Alignment.center,
decoration: BoxDecoration(
color: blue,
borderRadius: BorderRadius.circular(4)),
child: Icon(
Icons.bluetooth,
color: white,
size: 15,
),
),
Gap(5),
Obx(() => Text(
'请连接耳机',
style: TextStyle(fontSize: 14, color: black),
)),
const Gap(20),
],
),
),
),
),
const Gap(10),
Text(
'智能工具',
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold, color: white),
),
const Gap(10),
GestureDetector(
onTap: () {
//Get.to(() => AiChatPage(loginModel: state.loginModel!));
},
child: Stack(
children: [
Assets.icon.homeAiModel.image(fit: BoxFit.fitHeight),
Positioned(
left: 20,
top: 120 * 0.5 -
textSize('AI对话模式', Style.homeItemTextStyle).height *
0.5,
child: Text(
'AI对话模式',
style: Style.homeItemTextStyle,
),
)
],
),
),
const Gap(10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
//Get.to(() => Tcty_chatPage());
},
child: Stack(
children: [
Assets.icon.homeIconTcty.image(
width: (width - 30) * 0.5, fit: BoxFit.fitWidth),
Positioned(
left: (width - 30) * 0.25 -
textSize('同声传译', Style.homeItemTextStyle)
.width *
0.5,
top: (width - 30) * 0.5 - 50,
child: Text(
'同声传译',
style: Style.homeItemTextStyle,
),
)
],
),
),
GestureDetector(
onTap: () async {},
child: Stack(
children: [
Assets.icon.homeIconMdmfy.image(
width: (width - 30) * 0.5, fit: BoxFit.fitWidth),
Positioned(
left: (width - 30) * 0.25 -
textSize('面对面翻译', Style.homeItemTextStyle)
.width *
0.5,
top: (width - 30) * 0.5 - 50,
child: Text(
'面对面翻译',
style: Style.homeItemTextStyle,
),
)
],
),
),
],
),
const Gap(10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
// Get.to(() => PhonecallAudioTranslatePage());
// state.methodChannel
// .invokeMethod('googleRealTimeSpeechToText');
},
child: Stack(
children: [
Assets.icon.homeIconThyyfy.image(
width: (width - 30) * 0.5, fit: BoxFit.fitWidth),
Positioned(
left: (width - 30) * 0.25 -
textSize('通话语音翻译', Style.homeItemTextStyle)
.width *
0.5,
top: (width - 30) * 0.5 - 50,
child: Text(
'通话语音翻译',
style: Style.homeItemTextStyle,
),
)
],
),
),
GestureDetector(
onTap: () {
// Get.to(() => TransRecordsPage());
},
child: Stack(
children: [
Assets.icon.homeIconFyjl.image(
width: (width - 30) * 0.5, fit: BoxFit.fitWidth),
Positioned(
left: (width - 30) * 0.25 -
textSize('翻译记录', Style.homeItemTextStyle)
.width *
0.5,
top: (width - 30) * 0.5 - 50,
child: Text(
'翻译记录',
style: Style.homeItemTextStyle,
),
)
],
),
),
],
)
],
),
),
),
),
);
}
}

+ 105
- 0
lib/scenes/login/login_logic.dart 查看文件

@@ -0,0 +1,105 @@
import 'dart:async';
import 'dart:convert';

import 'package:demo001/main.dart';
import 'package:demo001/scenes/public.dart';
import 'package:demo001/tools/http_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:demo001/tools/widgets.dart';

import 'login_state.dart';

/// @description:
/// @author
/// @date: 2025-01-11 17:25:10
class LoginLogic extends GetxController {
final state = LoginState();

@override
void onInit() {
super.onInit();
}

@override
void onReady() {
super.onReady();
_getLoginInfo();
_checkPermission();
}

void _checkPermission() {
state.methodChannel.invokeMethod("bluetoothPermissionRequest");
}

void _getLoginInfo() async {
EasyLoading.show();
final info = await getSharedLoginInfo();
if (info != null) {
state.emailContr.text = info.data?.user?.mail ?? '';
Future.delayed(1.seconds, () {
EasyLoading.dismiss();
Get.offAll(() => IndexWidget());
});
} else {
EasyLoading.dismiss();
}
}

void getEmailPin() {
if (state.countDown.value != 60) return;
state.pinCodeTimer = Timer.periodic(1.seconds, (t) {
if (state.countDown.value <= 0) {
t.cancel();
state.pinCodeTimer?.cancel();
state.pinCodeTimer = null;
state.countDown.value = 60;
} else {
state.countDown.value = state.countDown.value - 1;
}
});
EasyLoading.show();
ApiClient.post(
url: ApiClient.getPin,
param: {"addr": state.emailContr.text, "vtype": 0},
onSuccess: (data) {
EasyLoading.showInfo('验证码已发送,请到邮箱查看!');
},
onFailed: (msg) {
EasyLoading.showError(msg);
});
}

void login() {
FocusScope.of(Get.context!).unfocus();
if (!isEmail(state.emailContr.text)) {
EasyLoading.showError('邮箱错误!');
return;
}
if (state.pinContr.text.length != 4) {
EasyLoading.showError('验证码错误!');
return;
}
EasyLoading.show();
ApiClient.post(
url: ApiClient.login,
param: {
"mail": state.emailContr.text,
"openid": "",
"phone": "",
"stype": 0,
"vcode": state.pinContr.text
},
onSuccess: (data) async {
EasyLoading.dismiss();
final instance = await SharedPreferences.getInstance();
await instance.setString('loginInfo', jsonEncode(data));
Get.offAll(() => IndexWidget());
},
onFailed: (msg) {
EasyLoading.showError(msg);
});
}
}

+ 32
- 0
lib/scenes/login/login_state.dart 查看文件

@@ -0,0 +1,32 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';

/// @description:
/// @author
/// @date: 2025-01-11 17:25:10
class LoginState {
TextEditingController phoneContr = TextEditingController();
TextEditingController pinContr = TextEditingController();
TextEditingController emailContr = TextEditingController();

MethodChannel methodChannel = MethodChannel('methodChannel');

FocusNode phoneNode = FocusNode();
FocusNode emailNode = FocusNode();
FocusNode pinNode = FocusNode();

// RxString phoneNumber = ''.obs;

RxString countryCode = '86'.obs;

RxBool protocolCheck = false.obs;

Timer? pinCodeTimer;

RxInt countDown = 60.obs;

RxBool isWechatLogin = false.obs;
}

+ 317
- 0
lib/scenes/login/login_view.dart 查看文件

@@ -0,0 +1,317 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:demo001/tools/color_utils.dart';
import 'package:demo001/tools/textStyle.dart';
import 'package:demo001/tools/widgets.dart';

import 'login_logic.dart';
import 'login_state.dart';

/// @description:
/// @author
/// @date: 2025-01-11 17:25:10
class LoginScene extends StatelessWidget {
final LoginLogic logic = Get.put(LoginLogic());
final LoginState state = Get.find<LoginLogic>().state;

LoginScene({Key? key}) : super(key: key);

double width = 0;
double height = 0;

@override
Widget build(BuildContext context) {
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
return Scaffold(
backgroundColor: Color.fromARGB(255, 18, 19, 24),
body: KeyboardDismissOnTap(
child: Container(
height: height,
padding: EdgeInsets.all(8),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Gap(45),
topWidget,
Gap(50),
logo,
Gap(15),
emailInput,
Gap(15),
pinInput,
Gap(30),
loginBtn,
Gap(80),
otherLogin,
Gap(180),
protocolWidget,
Gap(15),
],
),
),
),
),
);
}

Widget get topWidget => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'联系客服',
style: Style.clean,
),
Text(
'登录/注册账号',
style: Style.navTitle,
),
Text(
'联系客服',
style: Style.normalWhiteGrey,
)
],
);

Widget get logo => Container(
child: Icon(
Icons.logo_dev,
size: 100,
color: white,
),
);

Widget get phoneInput => SizedBox(
width: width * 0.9,
child: Container(
height: 45,
decoration: BoxDecoration(
color: inputBgColor, borderRadius: BorderRadius.circular(8)),
child: Obx(() => TextField(
controller: state.phoneContr,
focusNode: state.phoneNode,
textInputAction: TextInputAction.next,
style: Style.normalBold,
keyboardType: TextInputType.phone,
inputFormatters: state.countryCode.value == '86'
? [
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
LengthLimitingTextInputFormatter(11),
]
: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
],
decoration: InputDecoration(
border: InputBorder.none,
hintText: '请输入手机号',
contentPadding: EdgeInsets.symmetric(horizontal: 8),
),
onSubmitted: (value) {
if (value.length != 11) {
EasyLoading.showError('手机号码错误!');
} else {
state.emailNode.nextFocus();
}
},
)),
),
);

Widget get emailInput => SizedBox(
width: width * 0.9,
child: Container(
height: 45,
decoration: BoxDecoration(
color: inputBgColor, borderRadius: BorderRadius.circular(8)),
child: TextField(
controller: state.emailContr,
focusNode: state.emailNode,
style: Style.normalBold,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
border: InputBorder.none,
hintText: '请输入邮箱',
contentPadding: EdgeInsets.symmetric(horizontal: 8),
),
onSubmitted: (value) {
final emailRegex =
RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$');
if (!emailRegex.hasMatch(state.emailContr.text)) {
EasyLoading.showError('邮箱输入错误,请重新输入!');
} else {
state.pinNode.nextFocus();
}
},
),
),
);

Widget get pinInput => SizedBox(
width: width * 0.9,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 45,
width: width * 0.5,
decoration: BoxDecoration(
color: inputBgColor, borderRadius: BorderRadius.circular(8)),
child: Obx(() => TextField(
controller: state.pinContr,
focusNode: state.pinNode,
style: Style.normalBold,
textInputAction: TextInputAction.send,
keyboardType: TextInputType.phone,
inputFormatters: state.countryCode.value == '86'
? [
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
LengthLimitingTextInputFormatter(4),
]
: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
],
decoration: InputDecoration(
border: InputBorder.none,
hintText: '请输入验证码',
contentPadding: EdgeInsets.symmetric(horizontal: 8),
),
onSubmitted: (value) {
if (value.length != 4) {
EasyLoading.showError("验证码错误");
} else {
logic.login();
}
},
)),
),
GestureDetector(
onTap: () {
if (!isEmail(state.emailContr.text)) {
EasyLoading.showError('邮箱输入错误,请重新输入!');
} else {
logic.getEmailPin();
}
},
child: Container(
height: 45,
width: width * 0.35,
alignment: Alignment.center,
decoration: BoxDecoration(
color: lightBlue, borderRadius: BorderRadius.circular(8)),
child: Obx(() => Text(
state.countDown.value == 60
? '获取验证码'
: '${state.countDown.value}S后重新获取',
style: Style.normalWhiteGrey,
)),
),
)
],
),
);

Widget get loginBtn => GestureDetector(
onTap: logic.login,
child: Container(
height: 45,
width: width * 0.9,
alignment: Alignment.center,
decoration: BoxDecoration(
color: blue, borderRadius: BorderRadius.circular(8)),
child: Obx(() => Text(
state.isWechatLogin.value ? '确定绑定' : '登录',
style: Style.normalBold,
)),
),
);

Widget get otherLogin => Container(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
color: white.withAlpha(30),
height: 1,
width: width * 0.25,
),
Text(
' 其他登录方式 ',
style: Style.normalSmallWhiteGrey,
),
Container(
color: white.withAlpha(30),
height: 1,
width: width * 0.25,
),
],
),
Gap(15),
GestureDetector(
onTap: () {
state.isWechatLogin.value = !state.isWechatLogin.value;
},
child: Icon(
Icons.wechat,
size: 60,
color: green,
),
),
],
),
);

Widget get protocolWidget => Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
state.protocolCheck.value = !state.protocolCheck.value;
},
child: Row(
children: [
Obx(() => Container(
child: Icon(
state.protocolCheck.value
? Icons.check_circle
: Icons.radio_button_unchecked,
color: state.protocolCheck.value ? blue : white,
size: 16,
),
)),
Text(
' 我已阅读并同意',
style: Style.normalSmall2,
),
],
),
),
GestureDetector(
onTap: () {},
child: Text(
'《用户服务协议》',
style: Style.normalBlueSmall2,
),
),
Text(
'和',
style: Style.normalSmall2,
),
GestureDetector(
onTap: () {},
child: Text(
'《用户服务协议》',
style: Style.normalBlueSmall2,
),
)
],
);
}

+ 20
- 0
lib/scenes/login/model/data.dart 查看文件

@@ -0,0 +1,20 @@
import 'package:json_annotation/json_annotation.dart';

import 'user.dart';

part 'data.g.dart';

@JsonSerializable()
class Data {
String? token;
User? user;

Data({this.token, this.user});

@override
String toString() => 'Data(token: $token, user: $user)';

factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json);

Map<String, dynamic> toJson() => _$DataToJson(this);
}

+ 19
- 0
lib/scenes/login/model/data.g.dart 查看文件

@@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'data.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Data _$DataFromJson(Map<String, dynamic> json) => Data(
token: json['token'] as String?,
user: json['user'] == null
? null
: User.fromJson(json['user'] as Map<String, dynamic>),
);

Map<String, dynamic> _$DataToJson(Data instance) => <String, dynamic>{
'token': instance.token,
'user': instance.user,
};

+ 26
- 0
lib/scenes/login/model/login_model.dart 查看文件

@@ -0,0 +1,26 @@
import 'package:json_annotation/json_annotation.dart';

import 'data.dart';

part 'login_model.g.dart';

@JsonSerializable()
class LoginModel {
int? code;
Data? data;
String? msg;

String? ali_token;
String? ali_appkey;

LoginModel({this.code, this.data, this.msg});

@override
String toString() => 'LoginModel(code: $code, data: $data, msg: $msg)';

factory LoginModel.fromJson(Map<String, dynamic> json) {
return _$LoginModelFromJson(json);
}

Map<String, dynamic> toJson() => _$LoginModelToJson(this);
}

+ 22
- 0
lib/scenes/login/model/login_model.g.dart 查看文件

@@ -0,0 +1,22 @@
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'login_model.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

LoginModel _$LoginModelFromJson(Map<String, dynamic> json) => LoginModel(
code: (json['code'] as num?)?.toInt(),
data: json['data'] == null
? null
: Data.fromJson(json['data'] as Map<String, dynamic>),
msg: json['msg'] as String?,
);

Map<String, dynamic> _$LoginModelToJson(LoginModel instance) =>
<String, dynamic>{
'code': instance.code,
'data': instance.data,
'msg': instance.msg,
};

+ 37
- 0
lib/scenes/login/model/user.dart 查看文件

@@ -0,0 +1,37 @@
import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
String? avatar;
int? createtime;
String? language;
int? lastbettime;
String? mail;
String? name;
String? phone;
String? uid;
String? wxopenid;

User({
this.avatar,
this.createtime,
this.language,
this.lastbettime,
this.mail,
this.name,
this.phone,
this.uid,
this.wxopenid,
});

@override
String toString() {
return 'User(avatar: $avatar, createtime: $createtime, language: $language, lastbettime: $lastbettime, mail: $mail, name: $name, phone: $phone, uid: $uid, wxopenid: $wxopenid)';
}

factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

Map<String, dynamic> toJson() => _$UserToJson(this);
}

+ 31
- 0
lib/scenes/login/model/user.g.dart 查看文件

@@ -0,0 +1,31 @@
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'user.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

User _$UserFromJson(Map<String, dynamic> json) => User(
avatar: json['avatar'] as String?,
createtime: (json['createtime'] as num?)?.toInt(),
language: json['language'] as String?,
lastbettime: (json['lastbettime'] as num?)?.toInt(),
mail: json['mail'] as String?,
name: json['name'] as String?,
phone: json['phone'] as String?,
uid: json['uid'] as String?,
wxopenid: json['wxopenid'] as String?,
);

Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'avatar': instance.avatar,
'createtime': instance.createtime,
'language': instance.language,
'lastbettime': instance.lastbettime,
'mail': instance.mail,
'name': instance.name,
'phone': instance.phone,
'uid': instance.uid,
'wxopenid': instance.wxopenid,
};

+ 14
- 0
lib/scenes/public.dart 查看文件

@@ -0,0 +1,14 @@
import 'dart:convert';

import 'package:demo001/scenes/login/model/login_model.dart';
import 'package:shared_preferences/shared_preferences.dart';

Future<LoginModel?> getSharedLoginInfo() async {
final instance = await SharedPreferences.getInstance();
final loginInfoStr = instance.getString('loginInfo');
if (loginInfoStr != null && loginInfoStr != '') {
return LoginModel.fromJson(jsonDecode(loginInfoStr));
} else {
return null;
}
}

+ 55
- 6
lib/scenes/translate/TranslateLogic.dart 查看文件

@@ -4,6 +4,7 @@ import 'dart:typed_data';

import 'package:demo001/scenes/translate/TranslateState.dart';
import 'package:demo001/tools/audio_tool.dart';
import 'package:demo001/xunfei/phonetic_dictation/phonetic_dictaion_model/w.dart';
import 'package:demo001/xunfei/recognition_result/recognition_content/recognition_content.dart';
import 'package:demo001/xunfei/xunfei_translate.dart';
import 'package:get/get.dart';
@@ -103,22 +104,66 @@ class TranslateLogic extends GetxController {

void _handleRecognaitionData(result) {
KDXFSentenceModel model;
String text = "";
try {
final index = state.kdxfSentenceList.indexWhere((KDXFSentenceModel e) {
return e.sid == result.header?.sid;
});
if (index != -1) {
model = state.kdxfSentenceList[index];
final recogContextStr = utf8.decode(
base64Decode(result.payload?.recognitionResults?.text ?? ''));
final ctx = RecognitionContent.fromJson(jsonDecode(recogContextStr));
if (ctx.pgs == 'apd') {
String text = state.kdxfSentenceList[index].content;
state.kdxfSentenceList[index].contentList.add(ctx);
ctx.ws!.forEach((e) {
e.cw?.forEach((e2) {
text = text + (e2.w ?? '');
});
});
if (text.trim() == '') return;
state.kdxfSentenceList[index].content = text;
state.kdxfSentenceList.refresh();
} else if (ctx.pgs == 'rpl') {
String text = '';
for (var i = ctx.rg?[0]; i! <= ctx.rg![1]; i++) {
state.kdxfSentenceList[index].contentList.removeWhere((ee) {
return ee.sn == i;
});
}
state.kdxfSentenceList[index].contentList.add(ctx);
state.kdxfSentenceList[index].contentList.forEach((e) {
e.ws?.forEach((ee) {
ee.cw?.forEach((e2) {
text = text + (e2.w ?? '');
});
});
});
if (text.trim() == '') return;
state.kdxfSentenceList[index].content = text;
state.kdxfSentenceList.refresh();
// }
}
} else {
final recogContextStr = utf8.decode(
base64Decode(result.payload?.recognitionResults?.text ?? ''));
final model = RecognitionContent.fromJson(jsonDecode(recogContextStr));
final ctx = RecognitionContent.fromJson(jsonDecode(recogContextStr));
ctx.ws!.forEach((e) {
e.cw?.forEach((e2) {
text = text + (e2.w ?? '');
});
});
if (text == '') return;
model = KDXFSentenceModel(
content: "",
sid: result.header?.sid ?? '',
transResult: '',
audioPath: '',
perviousWs: model.ws ?? []);
content: text,
sid: result.header?.sid ?? '',
transResult: '',
audioPath: '',
perviousWs: (ctx.ws ?? []) as List<W>,
);
state.kdxfSentenceList.add(model);
state.kdxfSentenceList.refresh();
}
} catch (e) {
print("接收识别结果异常 $e");
@@ -129,6 +174,10 @@ class TranslateLogic extends GetxController {

void _handleAudioData(AudioModel model) {}

void kdxfPlayAudio(KDXFSentenceModel model) async {
model.playerController.startPlayer();
}

void _log(String msg) {
Logger().f("LIWEI---------------:$msg");
}


+ 98
- 51
lib/scenes/translate/TranslateScene.dart 查看文件

@@ -1,3 +1,8 @@
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:demo001/gen/assets.gen.dart';
import 'package:demo001/tools/color_utils.dart';
import 'package:demo001/tools/textStyle.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'TranslateLogic.dart';
@@ -6,21 +11,30 @@ import 'TranslateState.dart';
/*
录音测试场景
*/
// ignore: must_be_immutable
class TranslateScene extends StatelessWidget {
final TranslateLogic logic = Get.put(TranslateLogic());
final TranslateState state = Get.find<TranslateLogic>().state;
TranslateScene({super.key});
double width = 0;
double height = 0;
@override
Widget build(BuildContext context) {
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(title: Text("录音测试")),
// body: ListView.builder(
// itemCount: _records.length,
// itemBuilder: (context, index) {
// var audio = _records[index];
// return _buildAudioMessage(audio);
// },
// ),
appBar: AppBar(
title: Text(
"同声传译",
style: Style.navTitle,
)),
body: ListView.builder(
itemCount: state.kdxfSentenceList.length,
itemBuilder: (context, index) {
var audio = state.kdxfSentenceList[index];
return _buildAudioMessage(audio);
},
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(20.0),
child: InkWell(
@@ -59,47 +73,80 @@ class TranslateScene extends StatelessWidget {
}

// 构建语音消息
// Widget _buildAudioMessage(RecordData data) {
// Color buttColor = data.state == 0 ? Colors.red : Colors.green;
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// // 音频播放按钮
// GestureDetector(
// onTap: () {
// // _playRecording(data);
// },
// child: Container(
// padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
// decoration: BoxDecoration(
// color: buttColor,
// borderRadius: BorderRadius.circular(30),
// ),
// child: Row(
// children: [
// Icon(
// Icons.play_arrow,
// color: Colors.white,
// ),
// SizedBox(width: 10),
// Text(
// '播放音频',
// style: TextStyle(color: Colors.white),
// ),
// ],
// ),
// ),
// ),
// SizedBox(height: 5),
// // 文字内容
// // Text(
// // message['text'],
// // style: TextStyle(fontSize: 16),
// // ),
// ],
// ),
// );
// }
Widget _buildAudioMessage(KDXFSentenceModel model) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
child: Row(
children: [
const Gap(10),
Assets.img.imageAi.image(width: 25, height: 25),
const Gap(10),
Flexible(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: width * 0.7),
child: Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(top: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: bottomNavBg,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
textAlign: TextAlign.start,
model.content,
style: Style.normal,
maxLines: 1000,
),
Obx(() => Visibility(
visible: model.transResult != '', child: Gap(5))),
Obx(() => Visibility(
visible: model.transResult != '',
child: Text(
textAlign: TextAlign.start,
model.transResult,
style: Style.normal,
maxLines: 1000,
),
)),
Obx(() => Visibility(
visible: model.audioDuration > 0,
child: const Gap(10),
)),
Obx(
() => Visibility(
visible: model.audioDuration > 0,
child: GestureDetector(
onTap: () {
logic.kdxfPlayAudio(model);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: AudioFileWaveforms(
size: Size(165, 30),
decoration: BoxDecoration(
border: Border.all(color: orange, width: 0.5),
borderRadius: BorderRadius.circular(5),
),
enableSeekGesture: false,
waveformType: WaveformType.fitWidth,
playerWaveStyle: PlayerWaveStyle(
waveThickness: 2, scaleFactor: 50),
playerController: model.playerController,
),
),
),
),
)
],
),
),
),
),
],
),
);
}
}

+ 52
- 0
lib/tools/color_utils.dart 查看文件

@@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
import 'dart:math';

MaterialColor createMaterialColor(Color color) {
List strengths = <double>[.05];
Map<int, Color> swatch = <int, Color>{};
final int r = color.red, g = color.green, b = color.blue;

for (int i = 1; i < 10; i++) {
strengths.add(0.1 * i);
}
for (var strength in strengths) {
final double ds = 0.5 - strength;
swatch[(strength * 1000).round()] = Color.fromRGBO(
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
g + ((ds < 0 ? g : (255 - g)) * ds).round(),
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
1,
);
}
return MaterialColor(color.value, swatch);
}

Color randomColor() {
return Color.fromARGB(
255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256));
}

const Color bottomNavBg = Color.fromARGB(255, 31, 33, 39);
const Color silver = Color.fromARGB(255, 194, 195, 197);
const Color white = Colors.white;
const Color whiteGrey = Color.fromARGB(255, 224, 224, 224);
const Color inputBgColor = Color.fromARGB(255, 44, 46, 53);

const Color chatBlue = Color.fromARGB(255, 80, 158, 171);

// const Color white = Colors.black;
const Color bgColor = Color.fromARGB(255, 18, 19, 24);
// const Color bgColor = Colors.grey;
const Color blue = Color.fromARGB(255, 72, 90, 255);
const Color lightBlue = Color.fromARGB(255, 55, 56, 110);
const Color deepBlue = Color.fromARGB(255, 18, 19, 41);
const Color black = Color.fromARGB(255, 31, 32, 35);
const Color red = Color.fromARGB(255, 225, 118, 129);
const Color lightRed = Color.fromARGB(255, 224, 143, 152);
const Color orange = Color.fromARGB(255, 235, 176, 41);
const Color lightOrange = Color.fromARGB(255, 234, 200, 120);
const Color clean = Colors.transparent;
const Color grey = Color.fromARGB(255, 129, 129, 130);
const Color lightGrey = Color.fromARGB(255, 228, 228, 228);
const Color green = Color.fromARGB(255, 41, 196, 72);
const Color lightGreen = Color.fromARGB(255, 137, 214, 153);

+ 259
- 0
lib/tools/http_utils.dart 查看文件

@@ -0,0 +1,259 @@
import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:logger/logger.dart';
import 'package:http/http.dart' as http;

class ApiClient {
static final _client = Dio();

static String _baseUrl = 'https://www.aitoyyun.com';

static get(
{String baseUrl = 'https://www.aitoyyun.com',
required String url,
required Map<String, dynamic> param,
required Function(Map<String, dynamic>) onSuccess,
required Function(String) onFailed}) async {
_baseUrl = baseUrl;
try {
Response response = await _client.get(
_baseUrl + url.trim(),
options: Options(
headers: {"Accept": 'application/json'},
sendTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10)),
queryParameters: param,
);
final jsonData = response.data;
_progressData(
jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
} on DioException catch (e) {
_progressError(response: e.response, onFailed: onFailed);
}
}

static post(
{required String url,
String? token,
required Map<String, dynamic> param,
required Function(Map<String, dynamic>) onSuccess,
required Function(String) onFailed}) async {
try {
// Logger().i('---url: ${_baseUrl + url.trim()}---param: $param-----token: $token');
Response response = await _client.post(
_baseUrl + url.trim(),
options: Options(
headers: {'Authorization': token ?? ''},
sendTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10)),
queryParameters: param,
data: param,
);
final jsonData = response.data;
_progressData(
jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
} on DioException catch (e) {
_progressError(response: e.response, onFailed: onFailed);
}
}

static put(
{required String url,
required Map<String, dynamic> param,
required Function(Map<String, dynamic>) onSuccess,
required Function(String) onFailed}) async {
try {
Response response = await _client.put(
_baseUrl + url.trim(),
options: Options(
headers: {"Accept": 'application/json'},
sendTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10)),
queryParameters: param,
data: param,
);
final jsonData = response.data;
_progressData(
jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
} on DioException catch (e) {
_progressError(response: e.response, onFailed: onFailed);
}
}

static delete(
{required String url,
required Map<String, dynamic> param,
required Function(Map<String, dynamic>) onSuccess,
required Function(String) onFailed}) async {
try {
Response response = await _client.delete(
_baseUrl + url.trim(),
options: Options(
headers: {"Accept": 'application/json'},
sendTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10)),
queryParameters: param,
data: param,
);
final jsonData = response.data;
_progressData(
jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
} on DioException catch (e) {
_progressError(response: e.response, onFailed: onFailed);
}
}

static void _progressData(
{required Map<String, dynamic> jsonData,
required Function(Map<String, dynamic>) onSuccess,
required Function(String) onFailed}) {
// Logger().i('--_progressData------${jsonData}');
if (jsonData['code'] == 0) {
onSuccess(jsonData);
} else {
onFailed(jsonData['msg'].toString());
}
}

static void _progressError(
{Response? response, required Function(String) onFailed}) {
if (response != null && response.data != null) {
Logger().i('_progressError---------${response.data}');
if (response.data.runtimeType == String) {
onFailed('返回数据格式错误');
} else {
if (response.data['errCode'] != null) {
final jsonData = response.data;
onFailed(jsonData['errMsg'].toString());
} else {
final jsonData = response.data;
onFailed(jsonData['state']['msg'].toString());
}
}
} else {
onFailed('请求失败');
}
}

static final String login = '/api/home/user_sgin';

static final String getPin = '/api/home/user_verification';

// static final String aiChat = '/api/home/ai_chat';

static final String deepseekApiKey = 'sk-3adfd188a3134e718bbf704f525aff17';
static Stream<String> aiChat(String prompt) async* {
final client = HttpClient();
try {
final request = await client
.postUrl(Uri.parse('https://api.deepseek.com/chat/completions'));

// 设置流式请求头
request.headers
..set('Content-Type', 'application/json')
..set('Authorization', 'Bearer $deepseekApiKey')
..set('Accept', 'text/event-stream');

// 构建请求体
final requestBody = jsonEncode({
'model': 'deepseek-chat',
'stream': true,
'messages': [
{'role': 'user', 'content': prompt}
]
});

// 写入请求体
request.add(utf8.encode(requestBody));
final response = await request.close();

// 检查状态码
if (response.statusCode != 200) {
throw Exception('API请求失败: ${response.statusCode}');
}

// 处理流数据
String buffer = '';
await for (final chunk in response.transform(utf8.decoder)) {
buffer += chunk;

// 分割完整事件(假设使用SSE格式)
while (buffer.contains('\n\n')) {
final eventEnd = buffer.indexOf('\n\n');
final event = buffer.substring(0, eventEnd);
buffer = buffer.substring(eventEnd + 2);

if (event.startsWith('data: ')) {
final dataContent = event.substring(6);
// 增加有效性检查
if (dataContent == '[DONE]') {
// print('流式传输结束');
continue; // 跳过特殊结束标记
}
final jsonData = jsonDecode(event.substring(6));
yield jsonData['choices'][0]['delta']['content'];
}
}
}
} finally {
client.close();
}
}

static final String dbAppkey = '418ec475-e2dc-4b76-8aca-842d81bc3466';
static final String dbModelId = 'ep-20250203161136-9lrxg';
static Stream<String> dbChat(String userMessage) async* {
final client = http.Client();
final url =
Uri.parse('https://ark.cn-beijing.volces.com/api/v3/chat/completions');

final headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer $dbAppkey',
};

final requestBody = {
"model": dbModelId,
"messages": [
{"role": "system", "content": "你是豆包,是由字节跳动开发的 AI 人工智能助手."},
{"role": "user", "content": userMessage}
],
"stream": true,
};

try {
final request = http.Request('POST', url)
..headers.addAll(headers)
..body = jsonEncode(requestBody);

final response = await client.send(request);
//流式处理响应数据
await for (final chunk in response.stream
.transform(utf8.decoder)
.transform(const LineSplitter())) {
if (chunk.isEmpty) continue;

// 假设豆包API使用类似OpenAI的流式格式(data: {...})
if (chunk.startsWith('data:')) {
final jsonStr = chunk.substring(5).trim();
if (jsonStr == '[DONE]') break; // 流结束标志

try {
final data = jsonDecode(jsonStr);
final content = data['choices'][0]['delta']['content'] ?? '';
if (content.isNotEmpty) {
yield content; // 逐块返回生成的文本
}
} catch (e) {
// print('JSON解析错误: $e');
}
// print('请求成功: $jsonStr');
}
}
} catch (e) {
print('请求异常: $e');
}
}
}

+ 32
- 0
lib/tools/textStyle.dart 查看文件

@@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:demo001/tools/color_utils.dart';

class Style {
static final greenBold =
TextStyle(color: green, fontSize: 18, fontWeight: FontWeight.bold);
static final navTitle =
TextStyle(color: white, fontSize: 18, fontWeight: FontWeight.bold);
static final normalWhiteGrey =
TextStyle(color: whiteGrey, fontSize: 14, fontWeight: FontWeight.bold);
static final normalBold =
TextStyle(color: white, fontSize: 16, fontWeight: FontWeight.bold);
static final normal = TextStyle(color: white, fontSize: 16);
static final normalGrey =
TextStyle(color: const Color.fromARGB(255, 92, 92, 92), fontSize: 16);
static final normalSmall = TextStyle(color: white, fontSize: 14);
static final normalGreySmall =
TextStyle(color: const Color.fromARGB(255, 92, 92, 92), fontSize: 14);
static final normalSmall2 = TextStyle(color: white, fontSize: 12);
static final normalGreySmall2 =
TextStyle(color: const Color.fromARGB(255, 92, 92, 92), fontSize: 12);
static final normalBlueSmall2 = TextStyle(color: blue, fontSize: 12);
static final normalSmallWhiteGrey = TextStyle(color: whiteGrey, fontSize: 14);
static final normalSmallBoldWhiteGrey =
TextStyle(color: whiteGrey, fontSize: 14, fontWeight: FontWeight.bold);
static final clean = TextStyle(
color: Colors.transparent, fontSize: 14, fontWeight: FontWeight.bold);

static final homeItemTextStyle =
TextStyle(fontSize: 14, color: white, fontWeight: FontWeight.bold);
static final hintStyle = TextStyle(fontSize: 14, color: grey);
}

+ 21
- 0
lib/tools/widgets.dart 查看文件

@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';

Widget circleCheckBox() {
return Container(
child: Icon(Icons.check),
);
}

Size textSize(String text, TextStyle style) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
textDirection: TextDirection.ltr,
)..layout(); // 布局文本
return textPainter.size; // 返回文本的尺寸
}

bool isEmail(String email) {
final emailRegex =
RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$');
return emailRegex.hasMatch(email);
}

+ 2
- 2
lib/xunfei/xunfei_translate.dart 查看文件

@@ -296,8 +296,8 @@ class XunFeiTranslateTask {
onDone: () {
isconnected = false;
print('WebSocket 连接已关闭');
print('Close code: ${_channel?.closeCode}');
print('Close reason: ${_channel?.closeReason}');
print('Close code: ${_channel.closeCode}');
print('Close reason: ${_channel.closeReason}');
},
cancelOnError: true,
);


+ 2
- 0
macos/Flutter/GeneratedPluginRegistrant.swift 查看文件

@@ -9,10 +9,12 @@ import audio_session
import audioplayers_darwin
import path_provider_foundation
import record_darwin
import shared_preferences_foundation

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

+ 654
- 116
pubspec.lock
文件差异内容过多而无法显示
查看文件


+ 14
- 5
pubspec.yaml 查看文件

@@ -31,7 +31,8 @@ dependencies:
flutter:
sdk: flutter


flutter_localizations:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
@@ -40,13 +41,20 @@ dependencies:
logger: ^2.5.0
path_provider: ^2.1.5
record: ^5.2.0
intl: ^0.20.2
intl: ^0.19.0
web_socket_channel: ^3.0.2
http: ^1.3.0
get: ^4.6.6
json_annotation: ^4.9.0
audioplayers: ^6.1.1
audio_waveforms: ^1.2.0
gap: ^3.0.1
flutter_gen_runner: ^5.9.0
build_runner: ^2.4.13
flutter_easyloading: ^3.0.5
flutter_keyboard_visibility: ^6.0.0
shared_preferences: ^2.5.1
dio: ^5.8.0+1

dev_dependencies:
flutter_test:
@@ -58,6 +66,7 @@ dev_dependencies:
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^5.0.0
intl_utils: ^2.8.5

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
@@ -70,9 +79,9 @@ flutter:
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/icon/
- assets/img/

# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images


正在加载...
取消
保存