Code improvements, changed language to english, changed eeg from cubit to service
This commit is contained in:
parent
7158824ffa
commit
ff9cdc02d8
102
assets/lessons/cells.json
Normal file
102
assets/lessons/cells.json
Normal file
@ -0,0 +1,102 @@
|
||||
[
|
||||
{
|
||||
"question": "Which part of the cell is known as the 'powerhouse'?",
|
||||
"options": [
|
||||
"Nucleus",
|
||||
"Ribosome",
|
||||
"Mitochondria",
|
||||
"Golgi Apparatus"
|
||||
],
|
||||
"correctAnswer": 2
|
||||
},
|
||||
{
|
||||
"question": "What is the main function of ribosomes?",
|
||||
"options": [
|
||||
"DNA replication",
|
||||
"Protein synthesis",
|
||||
"Energy production",
|
||||
"Waste removal"
|
||||
],
|
||||
"correctAnswer": 1
|
||||
},
|
||||
{
|
||||
"question": "Which organelle is responsible for packaging and transporting proteins?",
|
||||
"options": [
|
||||
"Endoplasmic Reticulum",
|
||||
"Nucleus",
|
||||
"Golgi Apparatus",
|
||||
"Lysosome"
|
||||
],
|
||||
"correctAnswer": 2
|
||||
},
|
||||
{
|
||||
"question": "Which structure in the cell controls its activities and contains genetic material?",
|
||||
"options": [
|
||||
"Cytoplasm",
|
||||
"Nucleus",
|
||||
"Mitochondria",
|
||||
"Cell Membrane"
|
||||
],
|
||||
"correctAnswer": 1
|
||||
},
|
||||
{
|
||||
"question": "What is the semi-fluid substance inside the cell that contains the organelles?",
|
||||
"options": [
|
||||
"Cytoplasm",
|
||||
"Nucleoplasm",
|
||||
"Plasma",
|
||||
"Protoplasm"
|
||||
],
|
||||
"correctAnswer": 0
|
||||
},
|
||||
{
|
||||
"question": "Which organelle is responsible for breaking down waste materials and cellular debris?",
|
||||
"options": [
|
||||
"Ribosome",
|
||||
"Lysosome",
|
||||
"Mitochondria",
|
||||
"Endoplasmic Reticulum"
|
||||
],
|
||||
"correctAnswer": 1
|
||||
},
|
||||
{
|
||||
"question": "What is the function of the cell membrane?",
|
||||
"options": [
|
||||
"Protects the cell and controls what enters and exits",
|
||||
"Stores genetic information",
|
||||
"Produces energy",
|
||||
"Synthesizes proteins"
|
||||
],
|
||||
"correctAnswer": 0
|
||||
},
|
||||
{
|
||||
"question": "Which type of cell contains a nucleus?",
|
||||
"options": [
|
||||
"Prokaryotic",
|
||||
"Eukaryotic",
|
||||
"Both",
|
||||
"Neither"
|
||||
],
|
||||
"correctAnswer": 1
|
||||
},
|
||||
{
|
||||
"question": "Which organelle is involved in the synthesis of lipids and detoxification?",
|
||||
"options": [
|
||||
"Rough Endoplasmic Reticulum",
|
||||
"Smooth Endoplasmic Reticulum",
|
||||
"Golgi Apparatus",
|
||||
"Ribosome"
|
||||
],
|
||||
"correctAnswer": 1
|
||||
},
|
||||
{
|
||||
"question": "What is transported by vesicles that bud off from the Golgi apparatus?",
|
||||
"options": [
|
||||
"DNA",
|
||||
"Proteins",
|
||||
"RNA",
|
||||
"Lipids"
|
||||
],
|
||||
"correctAnswer": 1
|
||||
}
|
||||
]
|
47
assets/lessons/cells.md
Normal file
47
assets/lessons/cells.md
Normal file
@ -0,0 +1,47 @@
|
||||
Topic: Basics of Cell Structure and Function
|
||||
1. Introduction (5 Minutes)
|
||||
|
||||
Objective: Provide an overview of what the student will learn in the session.
|
||||
Engagement Question: "Have you ever wondered what the smallest unit of life looks like and how it functions?"
|
||||
|
||||
2. Overview of Cells (10 Minutes)
|
||||
|
||||
Definition: Explain what a cell is and its importance.
|
||||
Types of Cells: Differentiate between prokaryotic and eukaryotic cells with simple examples (e.g., bacteria vs. human cells).
|
||||
Scale and Visualization: Show images/diagrams of cells under a microscope.
|
||||
|
||||
3. Cell Structure (15 Minutes)
|
||||
|
||||
Cell Membrane: Describe its function as a protective barrier and its role in regulating what enters and leaves the cell.
|
||||
Cytoplasm: Explain it as the 'factory floor' where most cellular activities occur.
|
||||
Nucleus: Introduce it as the 'control center' of the cell, containing DNA.
|
||||
Mitochondria: Explain its role as the 'powerhouse' of the cell, generating energy.
|
||||
Ribosomes: Describe their function in protein synthesis.
|
||||
Other Organelles:
|
||||
Endoplasmic Reticulum (ER): Differentiate between rough ER and smooth ER.
|
||||
Golgi Apparatus: Explain its role in packaging and transporting proteins.
|
||||
Lysosomes: Describe their function in waste removal.
|
||||
|
||||
4. Interactive Activity (10 Minutes)
|
||||
|
||||
Virtual Tour: Use an interactive 3D model of a cell to explore different organelles.
|
||||
Quiz Questions:
|
||||
"What is the function of the mitochondria?"
|
||||
"Where are proteins synthesized in the cell?"
|
||||
Q&A: Allow the student to ask questions and clarify any doubts.
|
||||
|
||||
5. Real-World Application (5 Minutes)
|
||||
|
||||
Relate to Everyday Life: Discuss how understanding cells can help us learn about diseases, develop medicines, and comprehend how our bodies work.
|
||||
Current Research: Briefly mention exciting advancements in cell biology (e.g., stem cell research or cancer treatment).
|
||||
|
||||
6. Conclusion and Review (5 Minutes)
|
||||
|
||||
Summary: Recap the key points covered in the session.
|
||||
Take-Home Message: Emphasize the importance of cells as the building blocks of life.
|
||||
Homework/Next Steps: Suggest a short reading or video to reinforce the concepts learned.
|
||||
|
||||
7. Feedback (5 Minutes)
|
||||
|
||||
Student Reflection: Ask the student what they found most interesting or challenging.
|
||||
Tutor Feedback: Provide positive feedback and areas for improvement.
|
@ -1,103 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:gemini_app/config.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class EegState {
|
||||
final double mind_wandering;
|
||||
final double focus;
|
||||
|
||||
EegState({
|
||||
required this.mind_wandering,
|
||||
required this.focus,
|
||||
});
|
||||
|
||||
String getJsonString() {
|
||||
return '{"mind_wandering": $mind_wandering, "focus": $focus}';
|
||||
}
|
||||
}
|
||||
|
||||
class EegCubit extends Cubit<EegState> {
|
||||
EegCubit() : super(EegState(mind_wandering: 0.9, focus: 0.1)) {
|
||||
// Start the timer when the cubit is created
|
||||
if (!isDebug) {
|
||||
startPolling();
|
||||
}
|
||||
}
|
||||
|
||||
Timer? _timer;
|
||||
|
||||
void startPolling() {
|
||||
// Poll every 1 second (adjust the duration as needed)
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
|
||||
// Simulate getting new EEG data
|
||||
// In a real application, you would fetch this data from your EEG device or API
|
||||
// double newMindWandering = (DateTime.now().millisecondsSinceEpoch % 100) / 100;
|
||||
// double newFocus = 1 - newMindWandering;
|
||||
|
||||
fetchEegData().then((data) {
|
||||
double newMindWandering = data[0];
|
||||
double newFocus = data[1];
|
||||
// Update the state with the new EEG data
|
||||
updateEegData(newMindWandering, newFocus);
|
||||
});
|
||||
|
||||
// updateEegData(newMindWandering, newFocus);
|
||||
});
|
||||
}
|
||||
|
||||
Future<List<double>> fetchEegData() async {
|
||||
if (isDebug) {
|
||||
return [0.9, 0.1]; // Placeholder ret
|
||||
}
|
||||
|
||||
final url = Uri.parse('http://192.168.83.153:1234');
|
||||
|
||||
try {
|
||||
final response = await http.get(url);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Split the response body by newline and parse as floats
|
||||
List<String> values = response.body.trim().split('\n');
|
||||
if (values.length == 2) {
|
||||
return [
|
||||
double.parse(values[0]),
|
||||
double.parse(values[1]),
|
||||
];
|
||||
} else {
|
||||
throw Exception('Unexpected response format');
|
||||
}
|
||||
} else {
|
||||
throw Exception('Failed to load EEG data: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Error fetching EEG data: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void stopPolling() {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
}
|
||||
|
||||
void updateEegData(double mindWandering, double focus) {
|
||||
emit(EegState(mind_wandering: mindWandering, focus: focus));
|
||||
print('Mind Wandering: $mindWandering, Focus: $focus');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
stopPolling();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void toggleState() {
|
||||
// Toggle the state between mind_wandering and focus
|
||||
if (state.mind_wandering > state.focus) {
|
||||
updateEegData(state.focus, state.mind_wandering);
|
||||
} else {
|
||||
updateEegData(state.mind_wandering, state.focus);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,13 +4,14 @@ import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:gemini_app/config.dart';
|
||||
import 'package:gemini_app/bloc/eeg_state.dart';
|
||||
import 'package:gemini_app/eeg/eeg_service.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:google_generative_ai/google_generative_ai.dart';
|
||||
|
||||
const String systemPrmpt =
|
||||
"""You are an AI tutor helping students understand topics with help of biometric data. You will be supplied with a json containing data extracted from an EEG device, use that data to modify your approach and help the student learn more effectively.
|
||||
At the start you will be provided a script with a lesson to cover.
|
||||
Keep the analysis and responses short.
|
||||
Use language: POLISH
|
||||
|
||||
After completing the theoretical part there's a quiz, you can start it yourself at the appropriate time or react to users' request by including <QUIZ_START_TOKEN> at the start of your response
|
||||
|
||||
@ -42,18 +43,6 @@ class QuizMessage {
|
||||
});
|
||||
}
|
||||
|
||||
// class Message {
|
||||
// final String text;
|
||||
// final MessageType type;
|
||||
// final MessageSource source;
|
||||
|
||||
// Message({
|
||||
// required this.text,
|
||||
// required this.type,
|
||||
// required this.source,
|
||||
// });
|
||||
// }
|
||||
|
||||
enum MessageType { text, lessonScript, quizQuestion, quizAnswer }
|
||||
|
||||
class Message {
|
||||
@ -148,11 +137,7 @@ class GeminiState {
|
||||
|
||||
static GeminiState get initialState => GeminiState(
|
||||
status: GeminiStatus.initial,
|
||||
// messages: [Message(text: "Hello, I'm Gemini Pro. How can I help you?", type: MessageType.text, source: MessageSource.agent)],
|
||||
messages: [
|
||||
// Message.fromGeminiContent(Content.model(
|
||||
// [TextPart("Hello, I'm Gemini Pro. How can I help you?")]))
|
||||
],
|
||||
messages: [],
|
||||
error: '',
|
||||
);
|
||||
}
|
||||
@ -160,11 +145,13 @@ class GeminiState {
|
||||
class GeminiCubit extends Cubit<GeminiState> {
|
||||
GeminiCubit() : super(GeminiState.initialState);
|
||||
|
||||
void startLesson(EegState eegState) async {
|
||||
void startLesson() async {
|
||||
final quizQuestions = await loadQuizQuestions();
|
||||
final String rjp = await rootBundle.loadString('assets/lessons/rjp.md');
|
||||
final String prompt =
|
||||
"Jesteś nauczycielem/chatbotem prowadzącym zajęcia z jednym uczniem. Uczeń ma możliwość zadawania pytań w trakcie, natomiast jesteś odpowiedzialny za prowadzenie lekcji i przedstawienie tematu. Zacznij prowadzić lekcje dla jednego ucznia na podstawie poniszego skryptu:\n$rjp";
|
||||
final String lessonScript = await rootBundle.loadString('assets/lessons/cells.md');
|
||||
// final String prompt =
|
||||
// "Jesteś nauczycielem/chatbotem prowadzącym zajęcia z jednym uczniem. Uczeń ma możliwość zadawania pytań w trakcie, natomiast jesteś odpowiedzialny za prowadzenie lekcji i przedstawienie tematu. Zacznij prowadzić lekcje dla jednego ucznia na podstawie poniszego skryptu:\n$rjp";
|
||||
final String prompt =
|
||||
"You are a teacher/chatbot conducting a class with one student. The student has the ability to ask questions during the lesson, while you are responsible for leading the class and presenting the topic. Start conducting the lesson for one student based on the script below:\n$lessonScript";
|
||||
|
||||
final safetySettings = [
|
||||
SafetySetting(HarmCategory.harassment, HarmBlockThreshold.none),
|
||||
@ -197,7 +184,7 @@ class GeminiCubit extends Cubit<GeminiState> {
|
||||
try {
|
||||
final chat = state.model!.startChat(history: [Content.text(prompt)]);
|
||||
final stream = chat.sendMessageStream(Content.text(
|
||||
"EEG DATA:\n${eegState.getJsonString()}\nPytanie:\n$prompt"));
|
||||
"EEG DATA:\n${GetIt.instance<EegService>().state.getJsonString()}\nMessage:\n$prompt"));
|
||||
|
||||
String responseText = '';
|
||||
|
||||
@ -221,13 +208,9 @@ class GeminiCubit extends Cubit<GeminiState> {
|
||||
error: e.toString(),
|
||||
));
|
||||
}
|
||||
|
||||
// enterQuizMode();
|
||||
|
||||
// sendMessage(prompt, eegState);
|
||||
}
|
||||
|
||||
void sendMessage(String prompt, EegState eegState) async {
|
||||
void sendMessage(String prompt) async {
|
||||
List<Message> messagesWithoutPrompt = state.messages;
|
||||
var messagesWithPrompt = state.messages +
|
||||
[
|
||||
@ -246,7 +229,7 @@ class GeminiCubit extends Cubit<GeminiState> {
|
||||
.map((mess) => mess.toGeminiContent())
|
||||
.toList());
|
||||
final stream = chat.sendMessageStream(Content.text(
|
||||
"EEG DATA:\n${eegState.getJsonString()}\nWiadomość od ucznia:\n$prompt"));
|
||||
"EEG DATA:\n${GetIt.instance<EegService>().state.getJsonString()}\nUser message:\n$prompt"));
|
||||
|
||||
String responseText = '';
|
||||
|
||||
@ -298,7 +281,7 @@ class GeminiCubit extends Cubit<GeminiState> {
|
||||
|
||||
Future<List<QuizQuestion>> loadQuizQuestions() async {
|
||||
final String quizJson =
|
||||
await rootBundle.loadString('assets/lessons/rjp.json');
|
||||
await rootBundle.loadString('assets/lessons/cells.json');
|
||||
final List<dynamic> quizData = json.decode(quizJson);
|
||||
|
||||
return quizData
|
||||
|
99
lib/eeg/eeg_service.dart
Normal file
99
lib/eeg/eeg_service.dart
Normal file
@ -0,0 +1,99 @@
|
||||
import 'dart:async';
|
||||
import 'package:gemini_app/config.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class EegState {
|
||||
final double mind_wandering;
|
||||
final double focus;
|
||||
|
||||
EegState({
|
||||
required this.mind_wandering,
|
||||
required this.focus,
|
||||
});
|
||||
|
||||
String getJsonString() {
|
||||
return '{"mind_wandering": $mind_wandering, "focus": $focus}';
|
||||
}
|
||||
}
|
||||
|
||||
class EegService {
|
||||
EegState state;
|
||||
|
||||
EegService() : state = EegState(mind_wandering: 0.9, focus: 0.1) {
|
||||
// Start the timer when the cubit is created
|
||||
if (!isDebug) {
|
||||
startPolling();
|
||||
}
|
||||
}
|
||||
|
||||
Timer? _timer;
|
||||
|
||||
void startPolling() {
|
||||
// Poll every 1 second (adjust the duration as needed)
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
|
||||
// Simulate getting new EEG data
|
||||
// In a real application, you would fetch this data from your EEG device or API
|
||||
// double newMindWandering = (DateTime.now().millisecondsSinceEpoch % 100) / 100;
|
||||
// double newFocus = 1 - newMindWandering;
|
||||
|
||||
fetchEegData().then((data) {
|
||||
double newMindWandering = data[0];
|
||||
double newFocus = data[1];
|
||||
// Update the state with the new EEG data
|
||||
updateEegData(newMindWandering, newFocus);
|
||||
});
|
||||
|
||||
// updateEegData(newMindWandering, newFocus);
|
||||
});
|
||||
}
|
||||
|
||||
Future<List<double>> fetchEegData() async {
|
||||
if (isDebug) {
|
||||
return [0.9, 0.1]; // Placeholder ret
|
||||
}
|
||||
|
||||
final url = Uri.parse('http://192.168.83.153:1234');
|
||||
|
||||
try {
|
||||
final response = await http.get(url);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Split the response body by newline and parse as floats
|
||||
List<String> values = response.body.trim().split('\n');
|
||||
if (values.length == 2) {
|
||||
return [
|
||||
double.parse(values[0]),
|
||||
double.parse(values[1]),
|
||||
];
|
||||
} else {
|
||||
throw Exception('Unexpected response format');
|
||||
}
|
||||
} else {
|
||||
throw Exception('Failed to load EEG data: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Error fetching EEG data: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void stopPolling() {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
}
|
||||
|
||||
void updateEegData(double mindWandering, double focus) {
|
||||
state = EegState(mind_wandering: mindWandering, focus: focus);
|
||||
print('Mind Wandering: $mindWandering, Focus: $focus');
|
||||
}
|
||||
|
||||
void toggleState() {
|
||||
// Toggle the state between mind_wandering and focus
|
||||
if (state.mind_wandering > state.focus) {
|
||||
updateEegData(state.focus, state.mind_wandering);
|
||||
} else {
|
||||
updateEegData(state.mind_wandering, state.focus);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gemini_app/eeg/eeg_service.dart';
|
||||
import 'package:gemini_app/screens/gemini_chat_screen.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
void main() {
|
||||
GetIt.I.registerSingleton<EegService>(EegService());
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:gemini_app/bloc/eeg_state.dart';
|
||||
import 'package:gemini_app/bloc/gemini_state.dart';
|
||||
import 'package:google_generative_ai/google_generative_ai.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:gemini_app/eeg/eeg_service.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
class GeminiScreen extends StatelessWidget {
|
||||
const GeminiScreen({super.key});
|
||||
@ -14,7 +13,6 @@ class GeminiScreen extends StatelessWidget {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(create: (context) => GeminiCubit()),
|
||||
BlocProvider(create: (context) => EegCubit()),
|
||||
],
|
||||
child: const GeminiChat(),
|
||||
);
|
||||
@ -31,6 +29,7 @@ class GeminiChat extends StatefulWidget {
|
||||
class GeminiChatState extends State<GeminiChat> {
|
||||
final _textController = TextEditingController();
|
||||
bool _quizMode = false; // Add this line
|
||||
final EegService _eegService = GetIt.instance<EegService>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -50,23 +49,23 @@ class GeminiChatState extends State<GeminiChat> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
context.read<EegCubit>().stopPolling();
|
||||
_eegService.stopPolling();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _startConversation() async {
|
||||
context.read<GeminiCubit>().startLesson(context.read<EegCubit>().state);
|
||||
context.read<GeminiCubit>().startLesson();
|
||||
}
|
||||
|
||||
void _sendMessage() async {
|
||||
context
|
||||
.read<GeminiCubit>()
|
||||
.sendMessage(_textController.text, context.read<EegCubit>().state);
|
||||
.sendMessage(_textController.text);
|
||||
_textController.clear();
|
||||
}
|
||||
|
||||
void _toggleEegState() {
|
||||
context.read<EegCubit>().toggleState();
|
||||
_eegService.toggleState();
|
||||
}
|
||||
|
||||
void _resetConversation() {
|
||||
@ -93,23 +92,19 @@ class GeminiChatState extends State<GeminiChat> {
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
BlocBuilder<EegCubit, EegState>(
|
||||
builder: (context, eegState) {
|
||||
return Card(
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Mind Wandering: ${eegState.mind_wandering.toStringAsFixed(2)}'),
|
||||
Text('Focus: ${eegState.focus.toStringAsFixed(2)}'),
|
||||
'Mind Wandering: ${_eegService.state.mind_wandering.toStringAsFixed(2)}'),
|
||||
Text('Focus: ${_eegService.state.focus.toStringAsFixed(2)}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: BlocBuilder<GeminiCubit, GeminiState>(
|
||||
builder: (context, state) {
|
||||
|
@ -107,6 +107,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
get_it:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: get_it
|
||||
sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.7.0"
|
||||
google_generative_ai:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -41,6 +41,7 @@ dependencies:
|
||||
flutter_lints: ^3.0.0
|
||||
flutter_markdown: ^0.7.3
|
||||
flutter_bloc: ^8.0.1
|
||||
get_it: ^7.7.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -69,8 +70,7 @@ flutter:
|
||||
# - images/a_dot_ham.jpeg
|
||||
|
||||
assets:
|
||||
- assets/lessons/rjp.md
|
||||
- assets/lessons/rjp.json
|
||||
- assets/lessons/
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user