feat: integrate api latihan & menambahkan base_url
This commit is contained in:
parent
363d216f21
commit
76710e8216
|
@ -1,4 +1,4 @@
|
|||
// lib/config.dart
|
||||
class BaseUrl {
|
||||
static const String baseUrl = 'http://192.168.100.45:8000/api';
|
||||
static const String baseUrl = 'http://192.168.100.13:8000/api';
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ final router = GoRouter(
|
|||
builder: (BuildContext context, GoRouterState state) {
|
||||
final Map<String, dynamic> extra = state.extra as Map<String, dynamic>;
|
||||
return SubMateriPage(
|
||||
id: extra['id'],
|
||||
title: extra['title'],
|
||||
description: extra['description'],
|
||||
videoLink: extra['videoLink'],
|
||||
|
@ -52,33 +53,34 @@ final router = GoRouter(
|
|||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/latihan',
|
||||
builder: (context, state) => LatihanPage(),
|
||||
),
|
||||
// GoRoute(
|
||||
// path: '/pelafalan',
|
||||
// builder: (context, state) {
|
||||
// final Map<String, dynamic> extra = state.extra as Map<String, dynamic>;
|
||||
// return PelafalanPage(
|
||||
// Rute untuk halaman Latihan
|
||||
GoRoute(
|
||||
path: '/latihan',
|
||||
builder: (BuildContext context, GoRouterState state) {
|
||||
final Map<String, dynamic> extra = state.extra as Map<String, dynamic>;
|
||||
return LatihanPage(
|
||||
id: extra['id'],
|
||||
currentStep: extra['currentStep'] ?? 0, // Menambahkan parameter currentStep
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
GoRoute(
|
||||
path: '/pelafalan',
|
||||
builder: (context, state) {
|
||||
// Ambil data dari state.extra yang dikirim melalui context.go()
|
||||
final Map<String, dynamic> extra = state.extra as Map<String, dynamic>;
|
||||
final int currentStep = extra['currentStep']; // Ambil currentStep
|
||||
// Rute untuk halaman Pelafalan
|
||||
GoRoute(
|
||||
path: '/pelafalan',
|
||||
builder: (context, state) {
|
||||
final Map<String, dynamic> extra = state.extra as Map<String, dynamic>;
|
||||
final int currentStep = extra['currentStep'];
|
||||
final List<dynamic> latihanData = extra['latihanData'];
|
||||
|
||||
return PelafalanPage(
|
||||
id: extra['id'],
|
||||
currentStep: currentStep,
|
||||
latihanData: latihanData,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
// Kirim data ke PelafalanPage
|
||||
return PelafalanPage(
|
||||
currentStep:
|
||||
currentStep, // Mengirim currentStep ke halaman PelafalanPage
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/kemajuan',
|
||||
builder: (context, state) {
|
||||
|
|
|
@ -6,6 +6,7 @@ double spacing = 8;
|
|||
|
||||
Color primaryColor = const Color(0xffFE0E46);
|
||||
Color secondPrimaryColor = const Color(0xff08CACA);
|
||||
Color secondPrimaryColor1 = const Color.fromARGB(255, 189, 211, 211);
|
||||
Color thirdPrimaryColor = const Color(0xffF2C98A);
|
||||
Color blueBorderChat = const Color(0xffE0F6CA);
|
||||
Color primaryColorW = const Color(0xff003299).withOpacity(0.2);
|
||||
|
|
|
@ -1,40 +1,98 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:flame_audio/flame_audio.dart'; // Import Flame Audio
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:ta_tahsin/core/baseurl/base_url.dart';
|
||||
import 'package:ta_tahsin/core/theme.dart';
|
||||
import '../materi/model/model_data_materi.dart';
|
||||
import 'model/model_data_latihan.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert'; // Untuk parsing JSON
|
||||
import 'dart:async'; // Untuk timer
|
||||
import 'package:audioplayers/audioplayers.dart'; // Tambahkan audioplayers
|
||||
|
||||
class LatihanPage extends StatefulWidget {
|
||||
const LatihanPage({super.key});
|
||||
final int id; // ID yang diteruskan dari halaman sebelumnya
|
||||
final int currentStep; // Menambahkan parameter currentStep
|
||||
|
||||
const LatihanPage({super.key, required this.id, required this.currentStep});
|
||||
|
||||
@override
|
||||
_LatihanPageState createState() => _LatihanPageState();
|
||||
}
|
||||
|
||||
class _LatihanPageState extends State<LatihanPage> {
|
||||
int currentStep = 0; // Start with the first step
|
||||
late Future<List<dynamic>> latihanData; // Data latihan berdasarkan id_submateri
|
||||
bool isRecording = false; // Menandakan apakah sedang merekam
|
||||
int timer = 10; // Timer dimulai dari 10 detik
|
||||
late Timer countdownTimer; // Timer untuk countdown
|
||||
String timerText = "10"; // Menampilkan countdown timer dalam teks
|
||||
final AudioPlayer _audioPlayer = AudioPlayer(); // Inisialisasi Audioplayer
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
latihanData = fetchLatihanData(widget.id); // Ambil data latihan berdasarkan id_submateri yang diteruskan
|
||||
}
|
||||
|
||||
// Fungsi untuk mengambil data latihan dari API
|
||||
Future<List<dynamic>> fetchLatihanData(int id_submateri) async {
|
||||
final response = await http.get(
|
||||
Uri.parse('${BaseUrl.baseUrl}/latihan/$id_submateri'), // Gantilah dengan URL API yang sesuai
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return json.decode(response.body)['data']; // Parse data latihan dari API
|
||||
} else {
|
||||
throw Exception('Failed to load latihan');
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi untuk mulai countdown timer
|
||||
void startTimer() {
|
||||
setState(() {
|
||||
isRecording = true; // Set to true when starting to record
|
||||
timer = 10; // Reset timer to 10 seconds
|
||||
timerText = timer.toString();
|
||||
});
|
||||
|
||||
countdownTimer = Timer.periodic(Duration(seconds: 1), (timer) {
|
||||
if (this.timer > 0) {
|
||||
setState(() {
|
||||
this.timer--;
|
||||
timerText = this.timer.toString();
|
||||
});
|
||||
} else {
|
||||
countdownTimer.cancel();
|
||||
setState(() {
|
||||
isRecording = false; // Stop recording after timer ends
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fungsi untuk menghentikan timer dan reset ke kondisi semula
|
||||
void stopTimer() {
|
||||
countdownTimer.cancel();
|
||||
setState(() {
|
||||
isRecording = false; // Stop recording
|
||||
timer = 10; // Reset timer
|
||||
timerText = timer.toString();
|
||||
});
|
||||
}
|
||||
|
||||
// Fungsi untuk memutar audio dari asset berdasarkan URL yang diterima
|
||||
void playAudio(String audioUrl) async {
|
||||
// Menggunakan AssetSource untuk memutar audio dari asset
|
||||
await _audioPlayer.play(AssetSource(audioUrl)); // Gunakan AssetSource untuk audio lokal
|
||||
print("Audio playing...");
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (currentStep >= latihanList.length) {
|
||||
currentStep = latihanList.length - 1; // Stay at last step if out of bounds
|
||||
}
|
||||
|
||||
final arabicText = latihanList[currentStep]['arabicText'];
|
||||
final latinText = latihanList[currentStep]['latinText'];
|
||||
final audioFile = latihanList[currentStep]['audioFile']; // Get the audio file from data
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
context.go('/materi', extra: {
|
||||
'title': 'Makharijul Huruf',
|
||||
'description': 'tempat keluarnya huruf',
|
||||
'subMateri': materiList[0]['subMateri'],
|
||||
});
|
||||
context.go('/navigasi'); // Navigasi kembali ke halaman utama
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
|
@ -42,12 +100,12 @@ class _LatihanPageState extends State<LatihanPage> {
|
|||
child: Center(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: List.generate(4, (index) {
|
||||
children: List.generate(3, (index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
child: CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundColor: index <= currentStep
|
||||
backgroundColor: index <= widget.currentStep
|
||||
? secondPrimaryColor
|
||||
: Colors.grey,
|
||||
),
|
||||
|
@ -58,155 +116,182 @@ class _LatihanPageState extends State<LatihanPage> {
|
|||
),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
body: FutureBuilder<List<dynamic>>(
|
||||
future: latihanData,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Center(child: CircularProgressIndicator()); // Tampilkan loading selama data dimuat
|
||||
} else if (snapshot.hasError) {
|
||||
return Center(child: Text('Error: ${snapshot.error}')); // Menampilkan pesan error
|
||||
} else if (!snapshot.hasData || snapshot.data == null || snapshot.data!.isEmpty) {
|
||||
return Center(child: Text('Tidak ada latihan tersedia')); // Menampilkan pesan jika tidak ada data latihan
|
||||
}
|
||||
|
||||
// Ambil data latihan berdasarkan currentStep
|
||||
final latihanList = snapshot.data!;
|
||||
final latihan = latihanList[widget.currentStep]; // Ambil data latihan untuk currentStep
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.lightbulb,
|
||||
color: secondPrimaryColor,
|
||||
size: 40,
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: Colors.grey,
|
||||
width: 1,
|
||||
SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.lightbulb,
|
||||
color: secondPrimaryColor,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Dengarkan, ikuti dan rekam',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: blackColor,
|
||||
const SizedBox(width: 5),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: Colors.grey,
|
||||
width: 1,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
Text(
|
||||
'pelafalanmu terhadap lafadz ini',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: blackColor,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Dengarkan, ikuti dan rekam',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: blackColor,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
Text(
|
||||
'pelafalanmu terhadap lafadz ini',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: blackColor,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 35.0, vertical: 40.0),
|
||||
margin: const EdgeInsets.symmetric(vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
spreadRadius: 5,
|
||||
blurRadius: 10,
|
||||
),
|
||||
],
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 40.0),
|
||||
child: Text(
|
||||
"Ucapkan potongan kata ini",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
latihan['potongan_ayat'], // Menampilkan potongan ayat dari data latihan
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
latihan['latin_text'], // Menampilkan teks latin dari data latihan
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: Colors.black,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
// Memutar audio dari asset sesuai dengan URL yang ada pada `correct_audio`
|
||||
playAudio('audio/${latihan['correct_audio']}');
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.volume_up,
|
||||
size: 50,
|
||||
color: secondPrimaryColor,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 5.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
if (!isRecording) {
|
||||
startTimer(); // Start timer and change to stop icon
|
||||
} else {
|
||||
stopTimer(); // Stop timer and reset the button
|
||||
// Pass data to PelafalanPage after recording
|
||||
context.go(
|
||||
'/pelafalan',
|
||||
extra: {
|
||||
'id': widget.id,
|
||||
'currentStep': widget.currentStep,
|
||||
'latihanData': snapshot.data, // Mengirimkan data latihan yang sudah di-fetch
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: secondPrimaryColor,
|
||||
shape: const CircleBorder(),
|
||||
padding: const EdgeInsets.all(16),
|
||||
),
|
||||
child: Icon(
|
||||
isRecording ? Icons.stop : Icons.mic, // Toggle between mic and stop icon
|
||||
size: 40,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 35.0, vertical: 40.0),
|
||||
margin: const EdgeInsets.symmetric(vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
spreadRadius: 5,
|
||||
blurRadius: 10,
|
||||
),
|
||||
],
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 40.0),
|
||||
child: Text(
|
||||
"Ucapkan potongan kata ini",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
arabicText,
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
latinText,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: Colors.black,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
// Play the audio file when the icon is clicked
|
||||
FlameAudio.play(audioFile); // Play the audio using flame_audio
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.volume_up,
|
||||
size: 50,
|
||||
color: secondPrimaryColor,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 5.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
if (currentStep < latihanList.length - 1) {
|
||||
currentStep++;
|
||||
}
|
||||
});
|
||||
|
||||
context.go(
|
||||
'/pelafalan',
|
||||
extra: {
|
||||
'currentStep': currentStep,
|
||||
},
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: secondPrimaryColor,
|
||||
shape: const CircleBorder(),
|
||||
padding: const EdgeInsets.all(16),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.mic,
|
||||
size: 40,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_audioPlayer.dispose(); // Jangan lupa untuk melepaskan player
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,25 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:ta_tahsin/core/theme.dart';
|
||||
import 'model/model_data_pelafalan.dart';
|
||||
|
||||
class PelafalanPage extends StatelessWidget {
|
||||
final int id;
|
||||
final int currentStep;
|
||||
final List<dynamic> latihanData; // Menerima semua data latihan
|
||||
|
||||
const PelafalanPage({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.currentStep,
|
||||
required this.latihanData,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Ensure that currentStep is within the bounds of pelafalanList
|
||||
if (currentStep >= pelafalanList.length) {
|
||||
return Center(child: Text("End of List"));
|
||||
}
|
||||
// Ambil data latihan berdasarkan currentStep
|
||||
final latihan = latihanData[currentStep];
|
||||
|
||||
final arabicText = pelafalanList[currentStep]['arabicText'];
|
||||
final latinText = pelafalanList[currentStep]['latinText'];
|
||||
final materiDescription = pelafalanList[currentStep]['materiDescription'];
|
||||
final correctAudio = pelafalanList[currentStep]['correctAudio'];
|
||||
final recordedAudio = pelafalanList[currentStep]['recordedAudio'];
|
||||
|
||||
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
|
@ -59,7 +56,7 @@ class PelafalanPage extends StatelessWidget {
|
|||
const SizedBox(height: 20),
|
||||
Center(
|
||||
child: Text(
|
||||
arabicText,
|
||||
latihan['potongan_ayat'],
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
color: Colors.red,
|
||||
|
@ -154,7 +151,7 @@ class PelafalanPage extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
materiDescription,
|
||||
latihan['materi_description'],
|
||||
style: TextStyle(fontSize: 14, color: Colors.black),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
|
@ -164,11 +161,17 @@ class PelafalanPage extends StatelessWidget {
|
|||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Update the progress and navigate back to LatihanPage
|
||||
context.go(
|
||||
'/latihan',
|
||||
extra: {'currentStep': currentStep + 1}, // Move to next step
|
||||
);
|
||||
if (currentStep < latihanData.length - 1) {
|
||||
context.go(
|
||||
'/latihan',
|
||||
extra: {
|
||||
'id': id, // ganti sesuai kebutuhan
|
||||
'currentStep': currentStep + 1,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
context.go('/navigasi');
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: secondPrimaryColor,
|
||||
|
@ -179,7 +182,7 @@ class PelafalanPage extends StatelessWidget {
|
|||
minimumSize: Size(double.infinity, 50),
|
||||
),
|
||||
child: Text(
|
||||
'Lanjut',
|
||||
currentStep == latihanData.length - 1 ? 'Selesai' : 'Lanjut',
|
||||
style: TextStyle(
|
||||
color: whiteColor,
|
||||
fontSize: 16,
|
||||
|
@ -190,7 +193,14 @@ class PelafalanPage extends StatelessWidget {
|
|||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
context.go(
|
||||
'/latihan',
|
||||
extra: {
|
||||
'id': 1, // Ganti sesuai kebutuhan
|
||||
'currentStep': currentStep,
|
||||
'latihanData': latihanData, // Mengirimkan data latihan yang sesuai
|
||||
},
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
|
@ -219,4 +229,3 @@ class PelafalanPage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,25 +59,32 @@ class _MateriPageState extends State<MateriPage> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: secondPrimaryColor,
|
||||
title: Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: whiteColor,
|
||||
appBar: PreferredSize(
|
||||
preferredSize: Size.fromHeight(50), // Ukuran tinggi AppBar
|
||||
child: Card(
|
||||
elevation: 4, // Menambahkan shadow
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.zero, // Tidak ada radius, sudut tajam
|
||||
),
|
||||
margin: EdgeInsets.zero, // Menghilangkan margin Card
|
||||
child: AppBar(
|
||||
backgroundColor: secondPrimaryColor, // Warna AppBar (sesuaikan dengan secondPrimaryColor)
|
||||
title: Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
color: Colors.white,
|
||||
onPressed: () {
|
||||
context.go('/navigasi');
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back), color: whiteColor,
|
||||
onPressed: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/navigasi');
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
body: isLoading
|
||||
|
@ -193,6 +200,7 @@ class _MateriPageState extends State<MateriPage> {
|
|||
context.push(
|
||||
'/submateri', // Gantilah dengan rute yang sesuai
|
||||
extra: {
|
||||
'id': submateri['id'],
|
||||
'title': submateri['title'],
|
||||
'description': submateri['subtitle'],
|
||||
'videoLink': submateri['video_url'],
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:ta_tahsin/core/theme.dart';
|
|||
import 'package:youtube_player_flutter/youtube_player_flutter.dart'; // Import youtube_player_flutter
|
||||
|
||||
class SubMateriPage extends StatefulWidget {
|
||||
final int id;
|
||||
final String title;
|
||||
final String description;
|
||||
final String videoLink;
|
||||
|
@ -11,6 +12,7 @@ class SubMateriPage extends StatefulWidget {
|
|||
|
||||
const SubMateriPage({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.videoLink,
|
||||
|
@ -29,34 +31,40 @@ class _SubMateriPageState extends State<SubMateriPage> {
|
|||
super.initState();
|
||||
_controller = YoutubePlayerController(
|
||||
initialVideoId: YoutubePlayer.convertUrlToId(widget.videoLink)!,
|
||||
flags: const YoutubePlayerFlags(
|
||||
autoPlay: false,
|
||||
mute: false,
|
||||
),
|
||||
flags: const YoutubePlayerFlags(autoPlay: false, mute: false),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
appBar: PreferredSize(
|
||||
preferredSize: Size.fromHeight(50), // Ukuran tinggi AppBar
|
||||
child: Card(
|
||||
elevation: 4, // Menambahkan shadow
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.zero, // Tidak ada radius, sudut tajam
|
||||
),
|
||||
margin: EdgeInsets.zero, // Menghilangkan margin Card
|
||||
child: AppBar(
|
||||
backgroundColor:
|
||||
secondPrimaryColor, // Warna AppBar (sesuaikan dengan secondPrimaryColor)
|
||||
title: Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: blackColor,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/');
|
||||
}
|
||||
},
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
color: Colors.white,
|
||||
onPressed: () {
|
||||
Navigator.pop(context); // Aksi kembali
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
|
@ -75,7 +83,7 @@ class _SubMateriPageState extends State<SubMateriPage> {
|
|||
),
|
||||
),
|
||||
Container(
|
||||
color: secondPrimaryColor,
|
||||
color: secondPrimaryColor1,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 10),
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
|
@ -83,7 +91,7 @@ class _SubMateriPageState extends State<SubMateriPage> {
|
|||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: whiteColor,
|
||||
color: blackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -92,32 +100,47 @@ class _SubMateriPageState extends State<SubMateriPage> {
|
|||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Text(
|
||||
widget.intro,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: blackColor,
|
||||
),
|
||||
style: TextStyle(fontSize: 16, color: blackColor),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20),
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: secondPrimaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
minimumSize: Size(double.infinity, 50),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 20,
|
||||
),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: secondPrimaryColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
offset: Offset(0, -4),
|
||||
blurRadius: 6,
|
||||
),
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
context.go('/latihan');
|
||||
},
|
||||
child: Text(
|
||||
"Mulai Berlatih",
|
||||
style: TextStyle(fontSize: 16,color: whiteColor),
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
context.go(
|
||||
'/latihan', // Gantilah dengan rute yang sesuai
|
||||
extra: {'id': widget.id}, // Mengirimkan id dari halaman sebelumnya
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
"Mulai Berlatih",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue