Commit 2eb67dd4fdb548124043dfb1c9d37a681b349ea4

Authored by liangchengyou
1 parent 4b2c2f07

feat:调整代码

ios/Runner.xcodeproj/project.pbxproj
... ... @@ -10,6 +10,7 @@
10 10 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 11 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
12 12 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
  13 + 525E171A2A4BD03900104CDF /* VoiceXSMessageChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525E17192A4BD03900104CDF /* VoiceXSMessageChannel.swift */; };
13 14 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
14 15 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
15 16 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
... ... @@ -51,6 +52,7 @@
51 52 3563EC8D55A646823FD26A83 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
52 53 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
53 54 48BCA0827DCB98991774F5AC /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
  55 + 525E17192A4BD03900104CDF /* VoiceXSMessageChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceXSMessageChannel.swift; sourceTree = "<group>"; };
54 56 6DEBBC1D861BE053F3ECE0B9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
55 57 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
56 58 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
... ... @@ -150,6 +152,7 @@
150 152 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
151 153 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
152 154 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
  155 + 525E17192A4BD03900104CDF /* VoiceXSMessageChannel.swift */,
153 156 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
154 157 );
155 158 path = Runner;
... ... @@ -393,6 +396,7 @@
393 396 isa = PBXSourcesBuildPhase;
394 397 buildActionMask = 2147483647;
395 398 files = (
  399 + 525E171A2A4BD03900104CDF /* VoiceXSMessageChannel.swift in Sources */,
396 400 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
397 401 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
398 402 );
... ...
ios/Runner/AppDelegate.swift
... ... @@ -3,11 +3,13 @@ import Flutter
3 3  
4 4 @UIApplicationMain
5 5 @objc class AppDelegate: FlutterAppDelegate {
6   - override func application(
7   - _ application: UIApplication,
8   - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9   - ) -> Bool {
10   - GeneratedPluginRegistrant.register(with: self)
11   - return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12   - }
  6 + override func application(
  7 + _ application: UIApplication,
  8 + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  9 + ) -> Bool {
  10 + GeneratedPluginRegistrant.register(with: self)
  11 + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
  12 + _ = VoiceXSMessageChannel(messager: controller.binaryMessenger)
  13 + return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  14 + }
13 15 }
... ...
ios/Runner/Runner-Bridging-Header.h
1 1 #import "GeneratedPluginRegistrant.h"
  2 +#import <SingSound/SSOralEvaluatingManager.h>
... ...
ios/Runner/VoiceXSMessageChannel.swift 0 → 100644
  1 +//
  2 +// VoiceXSMessageChannel.swift
  3 +// Runner
  4 +//
  5 +// Created by MacBook Pro on 2023/6/28.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +class VoiceXSMessageChannel: NSObject,SSOralEvaluatingManagerDelegate {
  11 + var resultData:Dictionary<String, Any>?
  12 + var channel:FlutterBasicMessageChannel?
  13 + init(messager:FlutterBinaryMessenger) {
  14 + super.init()
  15 + resultData = Dictionary()
  16 + self.setEvaluateConfig()
  17 + channel = FlutterBasicMessageChannel(name: "com.owEnglish.voiceXs.BasicMessageChannel", binaryMessenger: messager)
  18 + channel!.setMessageHandler { message, reply in
  19 + if let dict = message as? Dictionary<String, Any> {
  20 + self.evaluateVioce(dict: dict);
  21 + }
  22 + }
  23 + }
  24 +
  25 + //配置评测信息
  26 + func setEvaluateConfig() {
  27 + let config = SSOralEvaluatingManagerConfig.init()
  28 + config.appKey = "a418"
  29 + config.secretKey = "1a16f31f2611bf32fb7b3fc38f5b2c81"
  30 + config.vad = true
  31 + config.frontTime = 3
  32 + config.backTime = 3
  33 + config.isOutputLog = false
  34 + SSOralEvaluatingManager.register(config)
  35 + SSOralEvaluatingManager.share().register(.line, userId: "321")
  36 + SSOralEvaluatingManager.share().delegate = self
  37 + }
  38 +
  39 + //开始评测
  40 + func evaluateVioce(dict:Dictionary<String, Any>) {
  41 + let text = dict["word"] as! String
  42 + let type = dict["type"] as! Int
  43 + let userId = dict["userId"] as! String
  44 + let config = SSOralEvaluatingConfig()
  45 + config.oralContent = text
  46 + if (type == 0) {
  47 + config.oralType = .word
  48 + } else {
  49 + config.oralType = .sentence
  50 + }
  51 + config.userId = userId
  52 + SSOralEvaluatingManager.share().startEvaluateOral(with: config)
  53 + }
  54 +
  55 + //评测结果回调
  56 + func evaluateResult() {
  57 + channel!.sendMessage(resultData) {(reply) in
  58 + self.resultData?.removeAll()
  59 + }
  60 + }
  61 +
  62 + //SSOralEvaluatingManagerDelegate
  63 + /**
  64 + 评测开始
  65 + */
  66 + func oralEvaluatingDidStart() {
  67 + print("评测开始")
  68 + }
  69 +
  70 + /**
  71 + 评测停止
  72 + */
  73 + func oralEvaluatingDidStop() {
  74 + print("评测结束")
  75 + }
  76 +
  77 + /**
  78 + 评测完成后的结果
  79 + */
  80 + func oralEvaluatingDidEnd(withResult result: [AnyHashable : Any]?, requestId request_id: String?) {
  81 + print("评测完成结果")
  82 + let resultDict:Dictionary<String, Any> = result?["result"] as! Dictionary
  83 + resultData!["result"] = "1"
  84 + //分数
  85 + resultData!["overall"] = resultDict["overall"]
  86 + self.evaluateResult()
  87 + }
  88 +
  89 + /**
  90 + 评测失败回调
  91 + */
  92 + func oralEvaluatingDidEndError(_ error: Error?, requestId request_id: String?) {
  93 + print("评测失败")
  94 + resultData!["result"] = "0"
  95 + self.evaluateResult()
  96 + }
  97 +
  98 + /**
  99 + VAD(前置时间)超时回调
  100 + */
  101 + func oralEvaluatingDidVADFrontTimeOut() {
  102 + print("前置超时--->取消")
  103 + SSOralEvaluatingManager.share().cancelEvaluate()
  104 + if(resultData?.keys.count == 0) {
  105 + resultData!["result"] = "0"
  106 + self.evaluateResult();
  107 + }
  108 + }
  109 +
  110 + /**
  111 + VAD(后置时间)超时回调
  112 + */
  113 + func oralEvaluatingDidVADBackTimeOut() {
  114 + print("后置超时--->结束")
  115 + ///结束回调
  116 + SSOralEvaluatingManager.share().stopEvaluate();
  117 + }
  118 +}
... ...
lib/common/request/dao/listen_dao.dart
1 1 import 'package:wow_english/common/request/request_client.dart';
  2 +import 'package:wow_english/models/course_process_entity.dart';
2 3 import 'package:wow_english/models/follow_read_entity.dart';
3 4 import 'package:wow_english/models/listen_entity.dart';
4 5  
... ... @@ -14,4 +15,10 @@ class ListenDao {
14 15 var data = await requestClient.get<List<FollowReadEntity?>>(Apis.followRead);
15 16 return data;
16 17 }
  18 +
  19 + ///课程内容
  20 + static Future<CourseProcessEntity?> process(courseLessonId) async {
  21 + var data = await requestClient.get<CourseProcessEntity>(Apis.process,queryParameters: {'courseLessonId':courseLessonId});
  22 + return data;
  23 + }
17 24 }
... ...
lib/generated/json/base/json_convert_content.dart
... ... @@ -4,9 +4,10 @@
4 4  
5 5 // This file is automatically generated. DO NOT EDIT, all your changes would be lost.
6 6 import 'package:flutter/material.dart' show debugPrint;
7   -import 'package:wow_english/models/follow_read_entity.dart';
8 7 import 'package:wow_english/models/course_entity.dart';
9 8 import 'package:wow_english/models/course_module_entity.dart';
  9 +import 'package:wow_english/models/course_process_entity.dart';
  10 +import 'package:wow_english/models/follow_read_entity.dart';
10 11 import 'package:wow_english/models/listen_entity.dart';
11 12 import 'package:wow_english/models/user_entity.dart';
12 13  
... ... @@ -16,10 +17,15 @@ typedef EnumConvertFunction&lt;T&gt; = T Function(String value);
16 17  
17 18 class JsonConvert {
18 19 static final Map<String, JsonConvertFunction> convertFuncMap = {
19   - (FollowReadEntity).toString(): FollowReadEntity.fromJson,
20 20 (CourseEntity).toString(): CourseEntity.fromJson,
21 21 (CourseCourseLessons).toString(): CourseCourseLessons.fromJson,
22 22 (CourseModuleEntity).toString(): CourseModuleEntity.fromJson,
  23 + (CourseProcessEntity).toString(): CourseProcessEntity.fromJson,
  24 + (CourseProcessReadings).toString(): CourseProcessReadings.fromJson,
  25 + (CourseProcessTopics).toString(): CourseProcessTopics.fromJson,
  26 + (CourseProcessTopicsTopicAnswerList).toString(): CourseProcessTopicsTopicAnswerList.fromJson,
  27 + (CourseProcessVideos).toString(): CourseProcessVideos.fromJson,
  28 + (FollowReadEntity).toString(): FollowReadEntity.fromJson,
23 29 (ListenEntity).toString(): ListenEntity.fromJson,
24 30 (UserEntity).toString(): UserEntity.fromJson,
25 31 };
... ... @@ -100,9 +106,6 @@ List&lt;T&gt;? convertListNotNull&lt;T&gt;(dynamic value, {EnumConvertFunction? enumConvert}
100 106  
101 107 //list is returned by type
102 108 static M? _getListChildType<M>(List<Map<String, dynamic>> data) {
103   - if(<FollowReadEntity>[] is M){
104   - return data.map<FollowReadEntity>((Map<String, dynamic> e) => FollowReadEntity.fromJson(e)).toList() as M;
105   - }
106 109 if(<CourseEntity>[] is M){
107 110 return data.map<CourseEntity>((Map<String, dynamic> e) => CourseEntity.fromJson(e)).toList() as M;
108 111 }
... ... @@ -112,6 +115,24 @@ List&lt;T&gt;? convertListNotNull&lt;T&gt;(dynamic value, {EnumConvertFunction? enumConvert}
112 115 if(<CourseModuleEntity>[] is M){
113 116 return data.map<CourseModuleEntity>((Map<String, dynamic> e) => CourseModuleEntity.fromJson(e)).toList() as M;
114 117 }
  118 + if(<CourseProcessEntity>[] is M){
  119 + return data.map<CourseProcessEntity>((Map<String, dynamic> e) => CourseProcessEntity.fromJson(e)).toList() as M;
  120 + }
  121 + if(<CourseProcessReadings>[] is M){
  122 + return data.map<CourseProcessReadings>((Map<String, dynamic> e) => CourseProcessReadings.fromJson(e)).toList() as M;
  123 + }
  124 + if(<CourseProcessTopics>[] is M){
  125 + return data.map<CourseProcessTopics>((Map<String, dynamic> e) => CourseProcessTopics.fromJson(e)).toList() as M;
  126 + }
  127 + if(<CourseProcessTopicsTopicAnswerList>[] is M){
  128 + return data.map<CourseProcessTopicsTopicAnswerList>((Map<String, dynamic> e) => CourseProcessTopicsTopicAnswerList.fromJson(e)).toList() as M;
  129 + }
  130 + if(<CourseProcessVideos>[] is M){
  131 + return data.map<CourseProcessVideos>((Map<String, dynamic> e) => CourseProcessVideos.fromJson(e)).toList() as M;
  132 + }
  133 + if(<FollowReadEntity>[] is M){
  134 + return data.map<FollowReadEntity>((Map<String, dynamic> e) => FollowReadEntity.fromJson(e)).toList() as M;
  135 + }
115 136 if(<ListenEntity>[] is M){
116 137 return data.map<ListenEntity>((Map<String, dynamic> e) => ListenEntity.fromJson(e)).toList() as M;
117 138 }
... ...
lib/generated/json/course_process_entity.g.dart 0 → 100644
  1 +import 'package:wow_english/generated/json/base/json_convert_content.dart';
  2 +import 'package:wow_english/models/course_process_entity.dart';
  3 +
  4 +CourseProcessEntity $CourseProcessEntityFromJson(Map<String, dynamic> json) {
  5 + final CourseProcessEntity courseProcessEntity = CourseProcessEntity();
  6 + final int? currentStep = jsonConvert.convert<int>(json['currentStep']);
  7 + if (currentStep != null) {
  8 + courseProcessEntity.currentStep = currentStep;
  9 + }
  10 + final int? currentTime = jsonConvert.convert<int>(json['currentTime']);
  11 + if (currentTime != null) {
  12 + courseProcessEntity.currentTime = currentTime;
  13 + }
  14 + final List<CourseProcessReadings>? readings = jsonConvert.convertListNotNull<CourseProcessReadings>(json['readings']);
  15 + if (readings != null) {
  16 + courseProcessEntity.readings = readings;
  17 + }
  18 + final List<CourseProcessTopics>? topics = jsonConvert.convertListNotNull<CourseProcessTopics>(json['topics']);
  19 + if (topics != null) {
  20 + courseProcessEntity.topics = topics;
  21 + }
  22 + final CourseProcessVideos? videos = jsonConvert.convert<CourseProcessVideos>(json['videos']);
  23 + if (videos != null) {
  24 + courseProcessEntity.videos = videos;
  25 + }
  26 + return courseProcessEntity;
  27 +}
  28 +
  29 +Map<String, dynamic> $CourseProcessEntityToJson(CourseProcessEntity entity) {
  30 + final Map<String, dynamic> data = <String, dynamic>{};
  31 + data['currentStep'] = entity.currentStep;
  32 + data['currentTime'] = entity.currentTime;
  33 + data['readings'] = entity.readings?.map((v) => v.toJson()).toList();
  34 + data['topics'] = entity.topics?.map((v) => v.toJson()).toList();
  35 + data['videos'] = entity.videos?.toJson();
  36 + return data;
  37 +}
  38 +
  39 +CourseProcessReadings $CourseProcessReadingsFromJson(Map<String, dynamic> json) {
  40 + final CourseProcessReadings courseProcessReadings = CourseProcessReadings();
  41 + final String? auditUrl = jsonConvert.convert<String>(json['auditUrl']);
  42 + if (auditUrl != null) {
  43 + courseProcessReadings.auditUrl = auditUrl;
  44 + }
  45 + final int? courseLessonId = jsonConvert.convert<int>(json['courseLessonId']);
  46 + if (courseLessonId != null) {
  47 + courseProcessReadings.courseLessonId = courseLessonId;
  48 + }
  49 + final String? createTime = jsonConvert.convert<String>(json['createTime']);
  50 + if (createTime != null) {
  51 + courseProcessReadings.createTime = createTime;
  52 + }
  53 + final String? deleted = jsonConvert.convert<String>(json['deleted']);
  54 + if (deleted != null) {
  55 + courseProcessReadings.deleted = deleted;
  56 + }
  57 + final String? id = jsonConvert.convert<String>(json['id']);
  58 + if (id != null) {
  59 + courseProcessReadings.id = id;
  60 + }
  61 + final String? modifyTime = jsonConvert.convert<String>(json['modifyTime']);
  62 + if (modifyTime != null) {
  63 + courseProcessReadings.modifyTime = modifyTime;
  64 + }
  65 + final String? padPicUrl = jsonConvert.convert<String>(json['padPicUrl']);
  66 + if (padPicUrl != null) {
  67 + courseProcessReadings.padPicUrl = padPicUrl;
  68 + }
  69 + final String? picUrl = jsonConvert.convert<String>(json['picUrl']);
  70 + if (picUrl != null) {
  71 + courseProcessReadings.picUrl = picUrl;
  72 + }
  73 + final int? sortOrder = jsonConvert.convert<int>(json['sortOrder']);
  74 + if (sortOrder != null) {
  75 + courseProcessReadings.sortOrder = sortOrder;
  76 + }
  77 + final String? word = jsonConvert.convert<String>(json['word']);
  78 + if (word != null) {
  79 + courseProcessReadings.word = word;
  80 + }
  81 + return courseProcessReadings;
  82 +}
  83 +
  84 +Map<String, dynamic> $CourseProcessReadingsToJson(CourseProcessReadings entity) {
  85 + final Map<String, dynamic> data = <String, dynamic>{};
  86 + data['auditUrl'] = entity.auditUrl;
  87 + data['courseLessonId'] = entity.courseLessonId;
  88 + data['createTime'] = entity.createTime;
  89 + data['deleted'] = entity.deleted;
  90 + data['id'] = entity.id;
  91 + data['modifyTime'] = entity.modifyTime;
  92 + data['padPicUrl'] = entity.padPicUrl;
  93 + data['picUrl'] = entity.picUrl;
  94 + data['sortOrder'] = entity.sortOrder;
  95 + data['word'] = entity.word;
  96 + return data;
  97 +}
  98 +
  99 +CourseProcessTopics $CourseProcessTopicsFromJson(Map<String, dynamic> json) {
  100 + final CourseProcessTopics courseProcessTopics = CourseProcessTopics();
  101 + final String? audioUrl = jsonConvert.convert<String>(json['audioUrl']);
  102 + if (audioUrl != null) {
  103 + courseProcessTopics.audioUrl = audioUrl;
  104 + }
  105 + final int? courseLessonId = jsonConvert.convert<int>(json['courseLessonId']);
  106 + if (courseLessonId != null) {
  107 + courseProcessTopics.courseLessonId = courseLessonId;
  108 + }
  109 + final String? createTime = jsonConvert.convert<String>(json['createTime']);
  110 + if (createTime != null) {
  111 + courseProcessTopics.createTime = createTime;
  112 + }
  113 + final String? deleted = jsonConvert.convert<String>(json['deleted']);
  114 + if (deleted != null) {
  115 + courseProcessTopics.deleted = deleted;
  116 + }
  117 + final String? id = jsonConvert.convert<String>(json['id']);
  118 + if (id != null) {
  119 + courseProcessTopics.id = id;
  120 + }
  121 + final String? keyWord = jsonConvert.convert<String>(json['keyWord']);
  122 + if (keyWord != null) {
  123 + courseProcessTopics.keyWord = keyWord;
  124 + }
  125 + final String? modifyTime = jsonConvert.convert<String>(json['modifyTime']);
  126 + if (modifyTime != null) {
  127 + courseProcessTopics.modifyTime = modifyTime;
  128 + }
  129 + final String? picUrl = jsonConvert.convert<String>(json['picUrl']);
  130 + if (picUrl != null) {
  131 + courseProcessTopics.picUrl = picUrl;
  132 + }
  133 + final int? sortOrder = jsonConvert.convert<int>(json['sortOrder']);
  134 + if (sortOrder != null) {
  135 + courseProcessTopics.sortOrder = sortOrder;
  136 + }
  137 + final int? status = jsonConvert.convert<int>(json['status']);
  138 + if (status != null) {
  139 + courseProcessTopics.status = status;
  140 + }
  141 + final List<CourseProcessTopicsTopicAnswerList>? topicAnswerList = jsonConvert.convertListNotNull<CourseProcessTopicsTopicAnswerList>(json['topicAnswerList']);
  142 + if (topicAnswerList != null) {
  143 + courseProcessTopics.topicAnswerList = topicAnswerList;
  144 + }
  145 + final int? type = jsonConvert.convert<int>(json['type']);
  146 + if (type != null) {
  147 + courseProcessTopics.type = type;
  148 + }
  149 + final String? word = jsonConvert.convert<String>(json['word']);
  150 + if (word != null) {
  151 + courseProcessTopics.word = word;
  152 + }
  153 + return courseProcessTopics;
  154 +}
  155 +
  156 +Map<String, dynamic> $CourseProcessTopicsToJson(CourseProcessTopics entity) {
  157 + final Map<String, dynamic> data = <String, dynamic>{};
  158 + data['audioUrl'] = entity.audioUrl;
  159 + data['courseLessonId'] = entity.courseLessonId;
  160 + data['createTime'] = entity.createTime;
  161 + data['deleted'] = entity.deleted;
  162 + data['id'] = entity.id;
  163 + data['keyWord'] = entity.keyWord;
  164 + data['modifyTime'] = entity.modifyTime;
  165 + data['picUrl'] = entity.picUrl;
  166 + data['sortOrder'] = entity.sortOrder;
  167 + data['status'] = entity.status;
  168 + data['topicAnswerList'] = entity.topicAnswerList?.map((v) => v.toJson()).toList();
  169 + data['type'] = entity.type;
  170 + data['word'] = entity.word;
  171 + return data;
  172 +}
  173 +
  174 +CourseProcessTopicsTopicAnswerList $CourseProcessTopicsTopicAnswerListFromJson(Map<String, dynamic> json) {
  175 + final CourseProcessTopicsTopicAnswerList courseProcessTopicsTopicAnswerList = CourseProcessTopicsTopicAnswerList();
  176 + final int? correct = jsonConvert.convert<int>(json['correct']);
  177 + if (correct != null) {
  178 + courseProcessTopicsTopicAnswerList.correct = correct;
  179 + }
  180 + final String? createTime = jsonConvert.convert<String>(json['createTime']);
  181 + if (createTime != null) {
  182 + courseProcessTopicsTopicAnswerList.createTime = createTime;
  183 + }
  184 + final String? deleted = jsonConvert.convert<String>(json['deleted']);
  185 + if (deleted != null) {
  186 + courseProcessTopicsTopicAnswerList.deleted = deleted;
  187 + }
  188 + final String? id = jsonConvert.convert<String>(json['id']);
  189 + if (id != null) {
  190 + courseProcessTopicsTopicAnswerList.id = id;
  191 + }
  192 + final String? modifyTime = jsonConvert.convert<String>(json['modifyTime']);
  193 + if (modifyTime != null) {
  194 + courseProcessTopicsTopicAnswerList.modifyTime = modifyTime;
  195 + }
  196 + final String? picUrl = jsonConvert.convert<String>(json['picUrl']);
  197 + if (picUrl != null) {
  198 + courseProcessTopicsTopicAnswerList.picUrl = picUrl;
  199 + }
  200 + final int? sortOrder = jsonConvert.convert<int>(json['sortOrder']);
  201 + if (sortOrder != null) {
  202 + courseProcessTopicsTopicAnswerList.sortOrder = sortOrder;
  203 + }
  204 + final int? topicId = jsonConvert.convert<int>(json['topicId']);
  205 + if (topicId != null) {
  206 + courseProcessTopicsTopicAnswerList.topicId = topicId;
  207 + }
  208 + final String? word = jsonConvert.convert<String>(json['word']);
  209 + if (word != null) {
  210 + courseProcessTopicsTopicAnswerList.word = word;
  211 + }
  212 + return courseProcessTopicsTopicAnswerList;
  213 +}
  214 +
  215 +Map<String, dynamic> $CourseProcessTopicsTopicAnswerListToJson(CourseProcessTopicsTopicAnswerList entity) {
  216 + final Map<String, dynamic> data = <String, dynamic>{};
  217 + data['correct'] = entity.correct;
  218 + data['createTime'] = entity.createTime;
  219 + data['deleted'] = entity.deleted;
  220 + data['id'] = entity.id;
  221 + data['modifyTime'] = entity.modifyTime;
  222 + data['picUrl'] = entity.picUrl;
  223 + data['sortOrder'] = entity.sortOrder;
  224 + data['topicId'] = entity.topicId;
  225 + data['word'] = entity.word;
  226 + return data;
  227 +}
  228 +
  229 +CourseProcessVideos $CourseProcessVideosFromJson(Map<String, dynamic> json) {
  230 + final CourseProcessVideos courseProcessVideos = CourseProcessVideos();
  231 + final int? courseLessonId = jsonConvert.convert<int>(json['courseLessonId']);
  232 + if (courseLessonId != null) {
  233 + courseProcessVideos.courseLessonId = courseLessonId;
  234 + }
  235 + final String? createTime = jsonConvert.convert<String>(json['createTime']);
  236 + if (createTime != null) {
  237 + courseProcessVideos.createTime = createTime;
  238 + }
  239 + final String? deleted = jsonConvert.convert<String>(json['deleted']);
  240 + if (deleted != null) {
  241 + courseProcessVideos.deleted = deleted;
  242 + }
  243 + final String? id = jsonConvert.convert<String>(json['id']);
  244 + if (id != null) {
  245 + courseProcessVideos.id = id;
  246 + }
  247 + final String? modifyTime = jsonConvert.convert<String>(json['modifyTime']);
  248 + if (modifyTime != null) {
  249 + courseProcessVideos.modifyTime = modifyTime;
  250 + }
  251 + final int? sortOrder = jsonConvert.convert<int>(json['sortOrder']);
  252 + if (sortOrder != null) {
  253 + courseProcessVideos.sortOrder = sortOrder;
  254 + }
  255 + final String? subtitleUrl = jsonConvert.convert<String>(json['subtitleUrl']);
  256 + if (subtitleUrl != null) {
  257 + courseProcessVideos.subtitleUrl = subtitleUrl;
  258 + }
  259 + final String? videoUrl = jsonConvert.convert<String>(json['videoUrl']);
  260 + if (videoUrl != null) {
  261 + courseProcessVideos.videoUrl = videoUrl;
  262 + }
  263 + return courseProcessVideos;
  264 +}
  265 +
  266 +Map<String, dynamic> $CourseProcessVideosToJson(CourseProcessVideos entity) {
  267 + final Map<String, dynamic> data = <String, dynamic>{};
  268 + data['courseLessonId'] = entity.courseLessonId;
  269 + data['createTime'] = entity.createTime;
  270 + data['deleted'] = entity.deleted;
  271 + data['id'] = entity.id;
  272 + data['modifyTime'] = entity.modifyTime;
  273 + data['sortOrder'] = entity.sortOrder;
  274 + data['subtitleUrl'] = entity.subtitleUrl;
  275 + data['videoUrl'] = entity.videoUrl;
  276 + return data;
  277 +}
0 278 \ No newline at end of file
... ...
lib/generated/json/user_entity.g.dart
... ... @@ -59,4 +59,4 @@ Map&lt;String, dynamic&gt; $UserEntityToJson(UserEntity entity) {
59 59 data['nowCourseModuleId'] = entity.nowCourseModuleId;
60 60 data['effectiveDate'] = entity.effectiveDate;
61 61 return data;
62 62 -}
  63 +}
63 64 \ No newline at end of file
... ...
lib/models/course_process_entity.dart 0 → 100644
  1 +import 'package:wow_english/generated/json/base/json_field.dart';
  2 +import 'package:wow_english/generated/json/course_process_entity.g.dart';
  3 +import 'dart:convert';
  4 +
  5 +@JsonSerializable()
  6 +class CourseProcessEntity {
  7 + int? currentStep;
  8 + int? currentTime;
  9 + List<CourseProcessReadings>? readings;
  10 + List<CourseProcessTopics>? topics;
  11 + CourseProcessVideos? videos;
  12 +
  13 + CourseProcessEntity();
  14 +
  15 + factory CourseProcessEntity.fromJson(Map<String, dynamic> json) => $CourseProcessEntityFromJson(json);
  16 +
  17 + Map<String, dynamic> toJson() => $CourseProcessEntityToJson(this);
  18 +
  19 + @override
  20 + String toString() {
  21 + return jsonEncode(this);
  22 + }
  23 +}
  24 +
  25 +@JsonSerializable()
  26 +class CourseProcessReadings {
  27 + String? auditUrl;
  28 + int? courseLessonId;
  29 + String? createTime;
  30 + String? deleted;
  31 + String? id;
  32 + String? modifyTime;
  33 + String? padPicUrl;
  34 + String? picUrl;
  35 + int? sortOrder;
  36 + String? word;
  37 +
  38 + CourseProcessReadings();
  39 +
  40 + factory CourseProcessReadings.fromJson(Map<String, dynamic> json) => $CourseProcessReadingsFromJson(json);
  41 +
  42 + Map<String, dynamic> toJson() => $CourseProcessReadingsToJson(this);
  43 +
  44 + @override
  45 + String toString() {
  46 + return jsonEncode(this);
  47 + }
  48 +}
  49 +
  50 +@JsonSerializable()
  51 +class CourseProcessTopics {
  52 + String? audioUrl;
  53 + int? courseLessonId;
  54 + String? createTime;
  55 + String? deleted;
  56 + String? id;
  57 + String? keyWord;
  58 + String? modifyTime;
  59 + String? picUrl;
  60 + int? sortOrder;
  61 + int? status;
  62 + List<CourseProcessTopicsTopicAnswerList>? topicAnswerList;
  63 + int? type;
  64 + String? word;
  65 +
  66 + CourseProcessTopics();
  67 +
  68 + factory CourseProcessTopics.fromJson(Map<String, dynamic> json) => $CourseProcessTopicsFromJson(json);
  69 +
  70 + Map<String, dynamic> toJson() => $CourseProcessTopicsToJson(this);
  71 +
  72 + @override
  73 + String toString() {
  74 + return jsonEncode(this);
  75 + }
  76 +}
  77 +
  78 +@JsonSerializable()
  79 +class CourseProcessTopicsTopicAnswerList {
  80 + int? correct;
  81 + String? createTime;
  82 + String? deleted;
  83 + String? id;
  84 + String? modifyTime;
  85 + String? picUrl;
  86 + int? sortOrder;
  87 + int? topicId;
  88 + String? word;
  89 +
  90 + CourseProcessTopicsTopicAnswerList();
  91 +
  92 + factory CourseProcessTopicsTopicAnswerList.fromJson(Map<String, dynamic> json) => $CourseProcessTopicsTopicAnswerListFromJson(json);
  93 +
  94 + Map<String, dynamic> toJson() => $CourseProcessTopicsTopicAnswerListToJson(this);
  95 +
  96 + @override
  97 + String toString() {
  98 + return jsonEncode(this);
  99 + }
  100 +}
  101 +
  102 +@JsonSerializable()
  103 +class CourseProcessVideos {
  104 + int? courseLessonId;
  105 + String? createTime;
  106 + String? deleted;
  107 + String? id;
  108 + String? modifyTime;
  109 + int? sortOrder;
  110 + String? subtitleUrl;
  111 + String? videoUrl;
  112 +
  113 + CourseProcessVideos();
  114 +
  115 + factory CourseProcessVideos.fromJson(Map<String, dynamic> json) => $CourseProcessVideosFromJson(json);
  116 +
  117 + Map<String, dynamic> toJson() => $CourseProcessVideosToJson(this);
  118 +
  119 + @override
  120 + String toString() {
  121 + return jsonEncode(this);
  122 + }
  123 +}
0 124 \ No newline at end of file
... ...
lib/pages/practice/bloc/topic_picture_bloc.dart
  1 +import 'package:audioplayers/audioplayers.dart';
1 2 import 'package:flutter/cupertino.dart';
  3 +import 'package:flutter/foundation.dart';
  4 +import 'package:flutter/services.dart';
2 5 import 'package:flutter_bloc/flutter_bloc.dart';
  6 +import 'package:flutter_easyloading/flutter_easyloading.dart';
  7 +import 'package:wow_english/common/request/dao/listen_dao.dart';
  8 +import 'package:wow_english/common/request/exception.dart';
  9 +import 'package:wow_english/models/course_process_entity.dart';
  10 +import 'package:wow_english/utils/loading.dart';
3 11  
4 12 part 'topic_picture_event.dart';
5 13 part 'topic_picture_state.dart';
... ... @@ -12,25 +20,70 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
12 20  
13 21 int _currentPage = 0;
14 22  
15   - int _selectItem = 0;
  23 + int _selectItem = -1;
  24 +
  25 + CourseProcessEntity? _entity;
  26 +
  27 + ///正在评测
  28 + bool _isVoicing = false;
  29 +
  30 + CourseProcessEntity? get entity => _entity;
16 31  
17 32 int get currentPage => _currentPage + 1;
18 33  
19 34 int get selectItem => _selectItem;
20 35  
  36 + bool get isVoicing => _isVoicing;
  37 +
  38 + var messageChannel = const BasicMessageChannel('com.owEnglish.voiceXs.BasicMessageChannel', StandardMessageCodec());
  39 +
  40 + final audioPlayer = AudioPlayer();
  41 +
21 42 TopicPictureBloc(this.pageController, this.modelCount) : super(TopicPictureInitial()) {
22 43 on<CurrentPageIndexChangeEvent>(_pageControllerChange);
  44 + on<InitMessageChannelEvent>(_initMessageChannelCall);
  45 + on<RequestDataEvent>(_requestData);
23 46 on<SelectItemEvent>(_selectItemLoad);
  47 + on<VoiceXsTestEvent>(_voiceXsTest);
  48 + on<VoiceResultEvent>(_voiceResult);
  49 + on<TopicPictureEvent>((event, emit) {
  50 +
  51 + });
24 52 }
25 53  
26 54 @override
27 55 Future<void> close() {
28 56 pageController.dispose();
  57 + audioPlayer.dispose();
29 58 return super.close();
30 59 }
31 60  
  61 + void _requestData(RequestDataEvent event,Emitter<TopicPictureState> emitter) async {
  62 + try {
  63 + await loading(() async {
  64 + _entity = await ListenDao.process('8');
  65 + emitter(RequestDataState());
  66 + });
  67 + } catch (e) {
  68 + if (e is ApiException) {
  69 + EasyLoading.showToast(e.message??'请求失败,请检查网络连接');
  70 + }
  71 + }
  72 + }
  73 +
32 74 void _pageControllerChange(CurrentPageIndexChangeEvent event,Emitter<TopicPictureState> emitter) async {
33 75 _currentPage = event.pageIndex;
  76 + final topics = _entity?.topics?[_currentPage];
  77 + if (topics?.type == 1 || topics?.type == 2) {
  78 + if (topics?.audioUrl != null) {
  79 + final urlStr = topics?.audioUrl??'';
  80 + if (urlStr.isNotEmpty) {
  81 + audioPlayer.play(UrlSource(urlStr));
  82 + }
  83 + }
  84 + } else {
  85 + audioPlayer.stop();
  86 + }
34 87 emitter(CurrentPageIndexState());
35 88 }
36 89  
... ... @@ -38,4 +91,47 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
38 91 _selectItem = event.selectIndex;
39 92 emitter(SelectItemChangeState());
40 93 }
  94 +
  95 + ///messageChannel回调
  96 + Future messageResultHandler(message,Emitter<TopicPictureState> emitter) async {
  97 + EasyLoading.dismiss();
  98 + final Map args = message as Map;
  99 + final result = args['result'] as String;
  100 + if (result == '1') {
  101 + final overall = args['overall'].toString();
  102 + EasyLoading.showToast('测评成功,分数是$overall',duration: const Duration(seconds: 10));
  103 + } else {
  104 + EasyLoading.showToast('测评失败',duration: const Duration(seconds: 10));
  105 + }
  106 + if (kDebugMode) {
  107 + print('是否被移除>>>>>$emitter');
  108 + }
  109 + _isVoicing = false;
  110 + }
  111 +
  112 + Future _initMessageChannelCall(InitMessageChannelEvent event,Emitter<TopicPictureState> emitter) async {
  113 + messageChannel.setMessageHandler((message) =>
  114 + messageResultHandler(message, emitter)
  115 + );
  116 +
  117 + audioPlayer.onPlayerStateChanged.listen((event) {
  118 + if (event == PlayerState.stopped) {
  119 + if (kDebugMode) {
  120 + print('播放结束');
  121 + }
  122 + }
  123 + });
  124 + }
  125 +
  126 + void _voiceXsTest(VoiceXsTestEvent event,Emitter<TopicPictureState> emitter) async {
  127 + EasyLoading.show(status: '录音中....');
  128 + messageChannel.send({'word':event.testWord,'type':event.type,'userId':event.userId.toString()});
  129 + _isVoicing = true;
  130 + emitter(VoiceXsTestState());
  131 + }
  132 +
  133 + void _voiceResult(VoiceResultEvent event,Emitter<TopicPictureState> emitter) async {
  134 + _isVoicing = false;
  135 + emitter(VoiceXsTestState());
  136 + }
41 137 }
... ...
lib/pages/practice/bloc/topic_picture_event.dart
... ... @@ -3,6 +3,21 @@ part of &#39;topic_picture_bloc.dart&#39;;
3 3 @immutable
4 4 abstract class TopicPictureEvent {}
5 5  
  6 +class RequestDataEvent extends TopicPictureEvent {}
  7 +
  8 +///初始化消息回调
  9 +class InitMessageChannelEvent extends TopicPictureEvent {}
  10 +
  11 +class VoiceResultEvent extends TopicPictureEvent {}
  12 +
  13 +///先声测试
  14 +class VoiceXsTestEvent extends TopicPictureEvent {
  15 + final String testWord;
  16 + final int type;
  17 + final int userId;
  18 + VoiceXsTestEvent(this.testWord,this.type,this.userId);
  19 +}
  20 +
6 21 class CurrentPageIndexChangeEvent extends TopicPictureEvent {
7 22 final int pageIndex;
8 23 CurrentPageIndexChangeEvent(this.pageIndex);
... ...
lib/pages/practice/bloc/topic_picture_state.dart
... ... @@ -3,6 +3,10 @@ part of &#39;topic_picture_bloc.dart&#39;;
3 3 @immutable
4 4 abstract class TopicPictureState {}
5 5  
  6 +class RequestDataState extends TopicPictureState {}
  7 +
  8 +class VoiceXsTestState extends TopicPictureState {}
  9 +
6 10 class TopicPictureInitial extends TopicPictureState {}
7 11  
8 12 class CurrentPageIndexState extends TopicPictureState {}
... ...
lib/pages/practice/topic_picture_page.dart
1 1 import 'package:flutter/material.dart';
2 2 import 'package:flutter_bloc/flutter_bloc.dart';
3 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
  4 +import 'package:wow_english/common/blocs/cachebloc/cache_bloc.dart';
4 5 import 'package:wow_english/common/extension/string_extension.dart';
5 6 import 'package:wow_english/common/widgets/ow_image_widget.dart';
  7 +import 'package:wow_english/models/course_process_entity.dart';
6 8  
7 9 import 'bloc/topic_picture_bloc.dart';
8 10 import 'widgets/practice_header_widget.dart';
... ... @@ -13,7 +15,12 @@ class TopicPicturePage extends StatelessWidget {
13 15 @override
14 16 Widget build(BuildContext context) {
15 17 return BlocProvider(
16   - create: (context) => TopicPictureBloc(PageController(),3),
  18 + create: (context) => TopicPictureBloc(
  19 + PageController(),
  20 + 3
  21 + )
  22 + ..add(RequestDataEvent())
  23 + ..add(InitMessageChannelEvent()),
17 24 child: _TopicPicturePage(),
18 25 );
19 26 }
... ... @@ -23,13 +30,16 @@ class _TopicPicturePage extends StatelessWidget {
23 30 @override
24 31 Widget build(BuildContext context) {
25 32 return BlocListener<TopicPictureBloc,TopicPictureState>(
26   - listener: (context, state){},
  33 + listener: (context, state){
  34 + if (state is RequestDataState) {
  35 + context.read<TopicPictureBloc>().add(CurrentPageIndexChangeEvent(0));
  36 + }
  37 + },
27 38 child: _topicPictureView(),
28 39 );
29 40 }
30 41  
31 42 Widget _topicPictureView() => BlocBuilder<TopicPictureBloc,TopicPictureState>(
32   - buildWhen: (_,s) => s is CurrentPageIndexState,
33 43 builder: (context,state){
34 44 final bloc = BlocProvider.of<TopicPictureBloc>(context);
35 45 return Container(
... ... @@ -39,28 +49,29 @@ class _TopicPicturePage extends StatelessWidget {
39 49 Column(
40 50 children: [
41 51 PracticeHeaderWidget(
42   - title: '${bloc.currentPage}/8',
  52 + title: '${bloc.currentPage}/${bloc.entity?.topics?.length}',
43 53 onTap: (){Navigator.pop(context);},
44 54 ),
45 55 Expanded(
46 56 child: PageView.builder(
47   - itemCount: 8,
  57 + itemCount: bloc.entity?.topics?.length,
48 58 scrollDirection: Axis.horizontal,
49 59 controller: bloc.pageController,
50 60 onPageChanged: (int index) {
51 61 bloc.add(CurrentPageIndexChangeEvent(index));
52 62 },
53 63 itemBuilder: (BuildContext context,int index){
54   - if (index % 5 == 0) {
55   - return _pageViewWordItemWidget();
56   - } else if (index % 5 == 1) {
57   - return _pageViewItemWidget();
58   - } else if (index % 5 == 2){
59   - return _pageViewVoicePictureItemWidget();
60   - } else if (index % 5 == 3){
61   - return _voiceAnswerItem();
62   - } else {
63   - return _pageViewVoiceWordItemWidget();
  64 + CourseProcessTopics? topics = bloc.entity?.topics![index];
  65 + if (topics?.type == 1) {//听音选图
  66 + return _pageViewVoicePictureItemWidget(topics);
  67 + } else if (topics?.type == 2) {//听音选字
  68 + return _pageViewVoiceWordItemWidget(topics);
  69 + } else if (topics?.type == 3) {//看题选字
  70 + return _pageViewWordItemWidget(topics);
  71 + } else if (topics?.type == 4) {//看题选图
  72 + return _pageViewItemWidget(topics);
  73 + } else {//语音问答
  74 + return _voiceAnswerItem(topics);
64 75 }
65 76 }),
66 77 )
... ... @@ -78,9 +89,8 @@ class _TopicPicturePage extends StatelessWidget {
78 89 });
79 90  
80 91 ///看题选图
81   - Widget _pageViewItemWidget() => BlocBuilder<TopicPictureBloc,TopicPictureState>(
  92 + Widget _pageViewItemWidget(CourseProcessTopics? topics) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
82 93 builder: (context, state){
83   - final bloc = BlocProvider.of<TopicPictureBloc>(context);
84 94 return SafeArea(
85 95 child: Column(
86 96 children: [
... ... @@ -93,27 +103,16 @@ class _TopicPicturePage extends StatelessWidget {
93 103 )
94 104 ),
95 105 26.verticalSpace,
96   - Row(
97   - mainAxisAlignment: MainAxisAlignment.center,
98   - children: [
99   - Offstage(
100   - offstage: (bloc.modelCount < 1),
101   - child: _decodeImageWidget(1),
102   - ),
103   - Offstage(
104   - offstage: (bloc.modelCount < 2),
105   - child: _decodeImageWidget(2),
106   - ),
107   - Offstage(
108   - offstage: (bloc.modelCount < 3),
109   - child: _decodeImageWidget(3),
110   - ),
111   - Offstage(
112   - offstage: (bloc.modelCount < 4),
113   - child: _decodeImageWidget(4),
114   - )
115   - ],
116   - )
  106 + SizedBox(
  107 + height: 143.h,
  108 + width: 143.w * (topics?.topicAnswerList?.length??0),
  109 + child: ListView.builder(
  110 + itemCount: topics?.topicAnswerList?.length??0,
  111 + scrollDirection: Axis.horizontal,
  112 + itemBuilder: (context,index){
  113 + return _decodeImageWidget(index);
  114 + }),
  115 + ),
117 116 ],
118 117 ),
119 118 );
... ... @@ -123,28 +122,31 @@ class _TopicPicturePage extends StatelessWidget {
123 122 buildWhen: (_, s) => s is SelectItemChangeState,
124 123 builder: (context,state){
125 124 final bloc = BlocProvider.of<TopicPictureBloc>(context);
126   - return GestureDetector(
127   - onTap: () => bloc.add(SelectItemEvent(index)),
128   - child: Container(
129   - padding: const EdgeInsets.all(4.5),
130   - decoration: BoxDecoration(
131   - color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
132   - borderRadius: BorderRadius.circular(15),
133   - ),
134   - height: 143.h,
135   - width: 143.w,
  125 + return Container(
  126 + padding: EdgeInsets.symmetric(horizontal: 10.w),
  127 + child: GestureDetector(
  128 + onTap: () => bloc.add(SelectItemEvent(index)),
136 129 child: Container(
  130 + padding: const EdgeInsets.all(4.5),
137 131 decoration: BoxDecoration(
138   - color: Colors.white,
139   - borderRadius: BorderRadius.circular(15),
140   - border: Border.all(
141   - width: 1.0,
142   - color: const Color(0xFF140C10)
143   - ),
144   - image: const DecorationImage(
145   - fit: BoxFit.fitWidth,
146   - image: NetworkImage('https://img1.baidu.com/it/u=3392591833,1640391553&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714')
147   - )
  132 + color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
  133 + borderRadius: BorderRadius.circular(15),
  134 + ),
  135 + height: 143.h,
  136 + width: 143.w,
  137 + child: Container(
  138 + decoration: BoxDecoration(
  139 + color: Colors.white,
  140 + borderRadius: BorderRadius.circular(15),
  141 + border: Border.all(
  142 + width: 1.0,
  143 + color: const Color(0xFF140C10)
  144 + ),
  145 + image: const DecorationImage(
  146 + fit: BoxFit.fitWidth,
  147 + image: NetworkImage('https://img1.baidu.com/it/u=3392591833,1640391553&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714')
  148 + )
  149 + ),
148 150 ),
149 151 ),
150 152 ),
... ... @@ -152,7 +154,7 @@ class _TopicPicturePage extends StatelessWidget {
152 154 });
153 155  
154 156 ///看题选字
155   - Widget _pageViewWordItemWidget() => BlocBuilder<TopicPictureBloc,TopicPictureState>(
  157 + Widget _pageViewWordItemWidget(CourseProcessTopics? topics) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
156 158 builder: (context, state){
157 159 final bloc = BlocProvider.of<TopicPictureBloc>(context);
158 160 return SafeArea(
... ... @@ -167,27 +169,16 @@ class _TopicPicturePage extends StatelessWidget {
167 169 )
168 170 ),
169 171 26.verticalSpace,
170   - Row(
171   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
172   - children: [
173   - Offstage(
174   - offstage: (bloc.modelCount < 1),
175   - child: _decodeWordWidget(1),
176   - ),
177   - Offstage(
178   - offstage: (bloc.modelCount < 2),
179   - child: _decodeWordWidget(2),
180   - ),
181   - Offstage(
182   - offstage: (bloc.modelCount < 3),
183   - child: _decodeWordWidget(3),
184   - ),
185   - Offstage(
186   - offstage: (bloc.modelCount < 4),
187   - child: _decodeWordWidget(4),
188   - )
189   - ],
190   - )
  172 + SizedBox(
  173 + height: 143.h,
  174 + width: 143.w * (topics?.topicAnswerList?.length??0),
  175 + child: ListView.builder(
  176 + itemCount: topics?.topicAnswerList?.length??0,
  177 + scrollDirection: Axis.horizontal,
  178 + itemBuilder: (context,index){
  179 + return _decodeWordWidget(index);
  180 + }),
  181 + ),
191 182 ],
192 183 ),
193 184 );
... ... @@ -197,57 +188,60 @@ class _TopicPicturePage extends StatelessWidget {
197 188 buildWhen: (_, s) => s is SelectItemChangeState,
198 189 builder: (context,state){
199 190 final bloc = BlocProvider.of<TopicPictureBloc>(context);
200   - return GestureDetector(
201   - onTap: () => bloc.add(SelectItemEvent(index)),
202   - child: Container(
203   - width: 143.w,
204   - height: 143.h,
205   - padding: EdgeInsets.only(left: 13.w,right: 13.w,top: 13.h,bottom: 13.h),
206   - decoration: BoxDecoration(
207   - color: Colors.white,
208   - borderRadius: BorderRadius.circular(15),
209   - border: Border.all(
210   - width: 1.0,
211   - color: const Color(0xFF140C10)
  191 + return Container(
  192 + padding: EdgeInsets.symmetric(horizontal: 10.w),
  193 + child: GestureDetector(
  194 + onTap: () => bloc.add(SelectItemEvent(index)),
  195 + child: Container(
  196 + width: 143.w,
  197 + height: 143.h,
  198 + padding: EdgeInsets.only(left: 13.w,right: 13.w,top: 13.h,bottom: 13.h),
  199 + decoration: BoxDecoration(
  200 + color: Colors.white,
  201 + borderRadius: BorderRadius.circular(15),
  202 + border: Border.all(
  203 + width: 1.0,
  204 + color: const Color(0xFF140C10)
  205 + ),
212 206 ),
213   - ),
214   - child: Column(
215   - mainAxisAlignment: MainAxisAlignment.end,
216   - children: [
217   - Expanded(
218   - child: Container(
219   - alignment: Alignment.center,
220   - child: Text(
221   - 'yellow',
222   - style: TextStyle(
223   - fontSize: 20.sp,
224   - color: const Color(0xFF333333)
225   - )
  207 + child: Column(
  208 + mainAxisAlignment: MainAxisAlignment.end,
  209 + children: [
  210 + Expanded(
  211 + child: Container(
  212 + alignment: Alignment.center,
  213 + child: Text(
  214 + 'yellow',
  215 + style: TextStyle(
  216 + fontSize: 20.sp,
  217 + color: const Color(0xFF333333)
  218 + )
  219 + ),
226 220 ),
227 221 ),
228   - ),
229   - Container(
230   - height: 30.h,
231   - width: double.infinity,
232   - decoration: BoxDecoration(
233   - color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
234   - borderRadius: BorderRadius.circular(15.r),
235   - border: Border.all(
236   - width: 1.5,
237   - color: const Color(0xFF140C10)
  222 + Container(
  223 + height: 30.h,
  224 + width: double.infinity,
  225 + decoration: BoxDecoration(
  226 + color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
  227 + borderRadius: BorderRadius.circular(15.r),
  228 + border: Border.all(
  229 + width: 1.5,
  230 + color: const Color(0xFF140C10)
  231 + ),
238 232 ),
239   - ),
240   - alignment: Alignment.center,
241   - child: Image.asset('choose'.assetPng),
242   - )
243   - ],
  233 + alignment: Alignment.center,
  234 + child: Image.asset('choose'.assetPng),
  235 + )
  236 + ],
  237 + ),
244 238 ),
245 239 ),
246 240 );
247 241 });
248 242  
249 243 ///听音选图
250   - Widget _pageViewVoicePictureItemWidget() => BlocBuilder<TopicPictureBloc,TopicPictureState>(
  244 + Widget _pageViewVoicePictureItemWidget(CourseProcessTopics? topics) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
251 245 builder: (context, state){
252 246 final bloc = BlocProvider.of<TopicPictureBloc>(context);
253 247 return SafeArea(
... ... @@ -268,58 +262,51 @@ class _TopicPicturePage extends StatelessWidget {
268 262 ],
269 263 ),
270 264 26.verticalSpace,
271   - Row(
272   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
273   - children: [
274   - Offstage(
275   - offstage: (bloc.modelCount < 1),
276   - child: _decodeVoiceImageWidget(1),
277   - ),
278   - Offstage(
279   - offstage: (bloc.modelCount < 2),
280   - child: _decodeVoiceImageWidget(2),
281   - ),
282   - Offstage(
283   - offstage: (bloc.modelCount < 3),
284   - child: _decodeVoiceImageWidget(3),
285   - ),
286   - Offstage(
287   - offstage: (bloc.modelCount < 4),
288   - child: _decodeVoiceImageWidget(4),
289   - )
290   - ],
  265 + SizedBox(
  266 + height: 143.h,
  267 + width: 163.w * (topics?.topicAnswerList?.length??0),
  268 + child: ListView.builder(
  269 + scrollDirection: Axis.horizontal,
  270 + itemCount: topics?.topicAnswerList?.length??0,
  271 + itemBuilder: (BuildContext context,int index){
  272 + return _decodeVoiceImageWidget(1,topics?.topicAnswerList?[index]);
  273 + })
  274 + ,
291 275 )
292 276 ],
293 277 ),
294 278 );
295 279 });
296 280  
297   - Widget _decodeVoiceImageWidget(int index) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
  281 + Widget _decodeVoiceImageWidget(int index,CourseProcessTopicsTopicAnswerList? answerList) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
298 282 buildWhen: (_, s) => s is SelectItemChangeState,
299 283 builder: (context,state){
300 284 final bloc = BlocProvider.of<TopicPictureBloc>(context);
301   - return GestureDetector(
302   - onTap: () => bloc.add(SelectItemEvent(index)),
303   - child: Container(
304   - padding: const EdgeInsets.all(4.5),
305   - decoration: BoxDecoration(
306   - color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
307   - borderRadius: BorderRadius.circular(15),
308   - ),
309   - height: 143.h,
310   - width: 143.w,
  285 + return Container(
  286 + padding: EdgeInsets.symmetric(horizontal: 10.w),
  287 + child: GestureDetector(
  288 + onTap: () => bloc.add(SelectItemEvent(index)),
311 289 child: Container(
  290 + padding: const EdgeInsets.all(4.5),
312 291 decoration: BoxDecoration(
313   - color: Colors.white,
314   - borderRadius: BorderRadius.circular(15),
315   - border: Border.all(
316   - width: 1.0,
317   - color: const Color(0xFF140C10)
318   - ),
319   - image: const DecorationImage(
320   - fit: BoxFit.fitWidth,
321   - image: NetworkImage('https://img1.baidu.com/it/u=3392591833,1640391553&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714')
322   - )
  292 + color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
  293 + borderRadius: BorderRadius.circular(15),
  294 + ),
  295 + height: 143.h,
  296 + width: 143.w,
  297 + child: Container(
  298 + decoration: BoxDecoration(
  299 + color: Colors.white,
  300 + borderRadius: BorderRadius.circular(15),
  301 + border: Border.all(
  302 + width: 1.0,
  303 + color: const Color(0xFF140C10)
  304 + ),
  305 + image: const DecorationImage(
  306 + fit: BoxFit.fitWidth,
  307 + image: NetworkImage('https://img1.baidu.com/it/u=3392591833,1640391553&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714')
  308 + )
  309 + ),
323 310 ),
324 311 ),
325 312 ),
... ... @@ -327,7 +314,7 @@ class _TopicPicturePage extends StatelessWidget {
327 314 });
328 315  
329 316 ///听音选字
330   - Widget _pageViewVoiceWordItemWidget() => BlocBuilder<TopicPictureBloc,TopicPictureState>(
  317 + Widget _pageViewVoiceWordItemWidget(CourseProcessTopics? topics) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
331 318 builder: (context, state){
332 319 final bloc = BlocProvider.of<TopicPictureBloc>(context);
333 320 return SafeArea(
... ... @@ -335,114 +322,138 @@ class _TopicPicturePage extends StatelessWidget {
335 322 children: [
336 323 Image.asset('voice'.assetPng,height: 33.h,width: 30.w,),
337 324 26.verticalSpace,
338   - Row(
339   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
340   - children: [
341   - Offstage(
342   - offstage: (bloc.modelCount < 1),
343   - child: _decodeVoiceWordImageWidget(1),
344   - ),
345   - Offstage(
346   - offstage: (bloc.modelCount < 2),
347   - child: _decodeVoiceWordImageWidget(2),
348   - ),
349   - Offstage(
350   - offstage: (bloc.modelCount < 3),
351   - child: _decodeVoiceWordImageWidget(3),
352   - ),
353   - Offstage(
354   - offstage: (bloc.modelCount < 4),
355   - child: _decodeVoiceWordImageWidget(4),
356   - )
357   - ],
358   - )
  325 + SizedBox(
  326 + width: 163.w * (topics?.topicAnswerList?.length??0),
  327 + height: 143.h,
  328 + child: ListView.builder(
  329 + itemCount: topics?.topicAnswerList?.length,
  330 + scrollDirection: Axis.horizontal,
  331 + itemBuilder: (BuildContext context,int index){
  332 + return _decodeVoiceWordImageWidget(index, topics!.topicAnswerList![index]);
  333 + }),
  334 + ),
  335 + // Row(
  336 + // mainAxisAlignment: MainAxisAlignment.spaceBetween,
  337 + // children: [
  338 + // Offstage(
  339 + // offstage: topics.topicAnswerList!.length <= 1,
  340 + // child: _decodeVoiceWordImageWidget(1,topics.topicAnswerList![0]),
  341 + // ),
  342 + // Offstage(
  343 + // offstage: topics.topicAnswerList!.length <= 2,
  344 + // child: _decodeVoiceWordImageWidget(2,topics.topicAnswerList![1]),
  345 + // ),
  346 + // // Offstage(
  347 + // // offstage: topics.topicAnswerList!.length <= 3,
  348 + // // child: _decodeVoiceWordImageWidget(3,topics.topicAnswerList![2]),
  349 + // // ),
  350 + // // Offstage(
  351 + // // offstage: topics.topicAnswerList!.length <= 4,
  352 + // // child: _decodeVoiceWordImageWidget(4,topics.topicAnswerList![3]),
  353 + // // )
  354 + // ],
  355 + // )
359 356 ],
360 357 ),
361 358 );
362 359 });
363 360  
364   - Widget _decodeVoiceWordImageWidget(int index) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
  361 + Widget _decodeVoiceWordImageWidget(int index,CourseProcessTopicsTopicAnswerList answerList) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
365 362 buildWhen: (_, s) => s is SelectItemChangeState,
366 363 builder: (context,state){
367 364 final bloc = BlocProvider.of<TopicPictureBloc>(context);
368 365 return GestureDetector(
369 366 onTap: () => bloc.add(SelectItemEvent(index)),
370 367 child: Container(
371   - width: 143.w,
  368 + width: 163.w,
372 369 height: 143.h,
373   - padding: EdgeInsets.only(left: 13.w,right: 13.w,top: 13.h,bottom: 13.h),
374   - decoration: BoxDecoration(
375   - color: Colors.white,
376   - borderRadius: BorderRadius.circular(15),
377   - border: Border.all(
378   - width: 1.0,
379   - color: const Color(0xFF140C10)
  370 + padding: EdgeInsets.symmetric(horizontal: 10.w),
  371 + child: Container(
  372 + width: 143.w,
  373 + height: 143.h,
  374 + padding: EdgeInsets.only(left: 13.w,right: 13.w,top: 13.h,bottom: 13.h),
  375 + decoration: BoxDecoration(
  376 + color: Colors.white,
  377 + borderRadius: BorderRadius.circular(15),
  378 + border: Border.all(
  379 + width: 1.0,
  380 + color: const Color(0xFF140C10)
  381 + ),
380 382 ),
381   - ),
382   - child: Column(
383   - mainAxisAlignment: MainAxisAlignment.end,
384   - children: [
385   - Expanded(
386   - child: Container(
387   - alignment: Alignment.center,
388   - child: Text(
389   - 'yellow',
390   - style: TextStyle(
391   - fontSize: 20.sp,
392   - color: const Color(0xFF333333)
393   - )
  383 + child: Column(
  384 + mainAxisAlignment: MainAxisAlignment.end,
  385 + children: [
  386 + Expanded(
  387 + child: Container(
  388 + alignment: Alignment.center,
  389 + child: Text(
  390 + answerList.word??'',
  391 + style: TextStyle(
  392 + fontSize: 20.sp,
  393 + color: const Color(0xFF333333)
  394 + )
  395 + ),
394 396 ),
395 397 ),
396   - ),
397   - Container(
398   - height: 30.h,
399   - width: double.infinity,
400   - decoration: BoxDecoration(
401   - color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
402   - borderRadius: BorderRadius.circular(15.r),
403   - border: Border.all(
404   - width: 1.5,
405   - color: const Color(0xFF140C10)
  398 + Container(
  399 + height: 30.h,
  400 + width: double.infinity,
  401 + decoration: BoxDecoration(
  402 + color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
  403 + borderRadius: BorderRadius.circular(15.r),
  404 + border: Border.all(
  405 + width: 1.5,
  406 + color: const Color(0xFF140C10)
  407 + ),
406 408 ),
407   - ),
408   - alignment: Alignment.center,
409   - child: Image.asset('choose'.assetPng),
410   - )
411   - ],
  409 + alignment: Alignment.center,
  410 + child: Image.asset('choose'.assetPng),
  411 + )
  412 + ],
  413 + ),
412 414 ),
413 415 ),
414 416 );
415 417 });
416 418  
417 419 ///语音问答
418   - Widget _voiceAnswerItem() => BlocBuilder<TopicPictureBloc,TopicPictureState>(
  420 + Widget _voiceAnswerItem(CourseProcessTopics? topics) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
419 421 builder: (context, state) {
  422 + final bloc = BlocProvider.of<TopicPictureBloc>(context);
420 423 return Row(
421   - mainAxisAlignment: MainAxisAlignment.center,
422   - children: [
423   - OwImageWidget(
424   - name:'https://up.enterdesk.com/edpic_source/16/e7/0d/16e70d550daff77cbac31fae5e1651d4.jpg',
425   - height: 186.h,
426   - width: 186.w,
427   - ),
428   - 160.horizontalSpace,
429   - Column(
430 424 mainAxisAlignment: MainAxisAlignment.center,
431 425 children: [
432   - Image.asset(
433   - 'voice'.assetPng,
434   - height: 52.h,
435   - width: 46.w,
  426 + OwImageWidget(
  427 + name:'https://up.enterdesk.com/edpic_source/16/e7/0d/16e70d550daff77cbac31fae5e1651d4.jpg',
  428 + height: 186.h,
  429 + width: 186.w,
436 430 ),
437   - 70.verticalSpace,
438   - Image.asset(
439   - 'micro_phone'.assetPng,
440   - height: 75.w,
441   - width: 75.w,
  431 + 160.horizontalSpace,
  432 + Column(
  433 + mainAxisAlignment: MainAxisAlignment.center,
  434 + children: [
  435 + Image.asset(
  436 + 'voice'.assetPng,
  437 + height: 52.h,
  438 + width: 46.w,
  439 + ),
  440 + 70.verticalSpace,
  441 + GestureDetector(
  442 + onTap: () {
  443 + if (bloc.isVoicing) {
  444 + return;
  445 + }
  446 + bloc.add(VoiceXsTestEvent('Hello', 0,context.read<CacheBloc>().userEntity!.id));
  447 + },
  448 + child: Image.asset(
  449 + 'micro_phone'.assetPng,
  450 + height: 75.w,
  451 + width: 75.w,
  452 + ),
  453 + )
  454 + ],
442 455 )
443 456 ],
444   - )
445   - ],
446   - );
447   - });
  457 + );
  458 + });
448 459 }
449 460 \ No newline at end of file
... ...