demo
This commit is contained in:
113
lib/features/lesson/lesson_screen.dart
Normal file
113
lib/features/lesson/lesson_screen.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'dart:convert';
|
||||
import 'package:base_flutter/features/lesson/record_dialog.dart';
|
||||
import 'package:record/record.dart';
|
||||
|
||||
import 'package:base_flutter/features/home/models.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_tts/flutter_tts.dart';
|
||||
|
||||
FlutterTts flutterTts = FlutterTts();
|
||||
|
||||
enum PositionEnum {
|
||||
topLeft('top_left'),
|
||||
topRight('top_right'),
|
||||
bottomLeft('bottom_left'),
|
||||
bottomRight('bottom_right');
|
||||
|
||||
final String value;
|
||||
const PositionEnum(this.value);
|
||||
}
|
||||
|
||||
class LessonScreen extends StatefulWidget {
|
||||
const LessonScreen({super.key, required this.lessonResponse});
|
||||
|
||||
final LessonResponse lessonResponse;
|
||||
|
||||
@override
|
||||
State<LessonScreen> createState() => _LessonScreenState();
|
||||
}
|
||||
|
||||
class _LessonScreenState extends State<LessonScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
final record = AudioRecorder();
|
||||
|
||||
|
||||
|
||||
Widget containerText(String text) {
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
var result = await flutterTts.speak(text);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
margin: const EdgeInsets.all(16.0),
|
||||
width: 300,
|
||||
height: 120,
|
||||
color: Colors.black54,
|
||||
child: Text(text, style: const TextStyle(color: Colors.white, fontSize: 16)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTapToRecordWidget(String position, String content) {
|
||||
switch (position) {
|
||||
case 'top_left':
|
||||
return Align(alignment: Alignment.topLeft, child: containerText(content));
|
||||
case 'top_right':
|
||||
return Align(alignment: Alignment.topRight, child: containerText(content));
|
||||
case 'bottom_left':
|
||||
return Align(alignment: Alignment.bottomLeft, child: containerText(content));
|
||||
case 'bottom_right':
|
||||
return Align(alignment: Alignment.bottomRight, child: containerText(content));
|
||||
default:
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
|
||||
),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: MemoryImage(base64Decode(widget.lessonResponse.image)),
|
||||
fit: BoxFit.cover, // Optional: Adjust as needed
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: kToolbarHeight,),
|
||||
Text(widget.lessonResponse.widget.tapToRecordWidget.position),
|
||||
buildTapToRecordWidget(
|
||||
widget.lessonResponse.widget.tapToRecordWidget.position,
|
||||
widget.lessonResponse.widget.tapToRecordWidget.content,
|
||||
),
|
||||
Spacer(),
|
||||
Text(widget.lessonResponse.widget.tapToSpeechWidget.position),
|
||||
buildTapToRecordWidget(
|
||||
widget.lessonResponse.widget.tapToSpeechWidget.position,
|
||||
widget.lessonResponse.widget.tapToSpeechWidget.content,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
content: RecordDialog(),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: Icon(Icons.mic, size: 48),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
79
lib/features/lesson/record_dialog.dart
Normal file
79
lib/features/lesson/record_dialog.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:record/record.dart';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
|
||||
class RecordDialog extends StatefulWidget {
|
||||
const RecordDialog({super.key});
|
||||
|
||||
@override
|
||||
State<RecordDialog> createState() => _RecordDialogState();
|
||||
}
|
||||
|
||||
class _RecordDialogState extends State<RecordDialog> {
|
||||
final AudioRecorder _recorder = AudioRecorder();
|
||||
final AudioPlayer _player = AudioPlayer();
|
||||
String? _recordedPath;
|
||||
bool _isRecording = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_recorder.dispose();
|
||||
_player.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _toggleRecord() async {
|
||||
if (!_isRecording) {
|
||||
if (await _recorder.hasPermission()) {
|
||||
await _recorder.start(const RecordConfig(), path: 'myFile.m4a');
|
||||
setState(() => _isRecording = true);
|
||||
}
|
||||
} else {
|
||||
final path = await _recorder.stop();
|
||||
setState(() {
|
||||
_isRecording = false;
|
||||
_recordedPath = path;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _playRecording() async {
|
||||
if (_recordedPath != null) {
|
||||
await _player.play(DeviceFileSource(_recordedPath!));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 300,
|
||||
height: 400,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 150),
|
||||
IconButton(
|
||||
icon: Icon(_isRecording ? Icons.stop : Icons.mic_none_sharp, size: 96),
|
||||
onPressed: _toggleRecord,
|
||||
),
|
||||
if (_recordedPath != null && !_isRecording)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.play_arrow, size: 48),
|
||||
onPressed: _playRecording,
|
||||
),
|
||||
const Spacer(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
TextButton(onPressed: () => Navigator.pop(context), child: const Text('Close')),
|
||||
// Add more buttons as needed
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Usage in your code:
|
||||
|
||||
Reference in New Issue
Block a user