MIF_E31222888/lib/pages/n4/kamus/detail_kamus.dart

349 lines
12 KiB
Dart

import 'package:bahasajepang/pages/n5/kamus/kamus_service.dart';
import 'package:bahasajepang/service/API_config.dart';
import 'package:flutter/material.dart';
import 'package:bahasajepang/theme.dart';
import 'package:audioplayers/audioplayers.dart';
class DetailKamus4Page extends StatefulWidget {
final int kamusId;
final AudioPlayer audioPlayer = AudioPlayer();
DetailKamus4Page({super.key, required this.kamusId});
@override
State<DetailKamus4Page> createState() => _DetailKamus4PageState();
}
class _DetailKamus4PageState extends State<DetailKamus4Page>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
late Future<dynamic> _kamusFuture;
final KamusService _kamusService = KamusService();
@override
void initState() {
super.initState();
_kamusFuture = _kamusService.fetchKamusById(widget.kamusId);
widget.audioPlayer.onPlayerStateChanged.listen((state) {
setState(() {});
});
}
@override
void dispose() {
widget.audioPlayer.dispose();
super.dispose();
}
Future<void> _playAudio(String? audioUrl) async {
if (audioUrl == null || audioUrl.isEmpty) return;
try {
final fullUrl = "${ApiConfig.url}/$audioUrl";
await widget.audioPlayer.play(UrlSource(fullUrl));
if (!mounted) return;
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Audio Tidak Tersedia'),
backgroundColor: bgColor3,
),
);
}
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
backgroundColor: bgColor1.withValues(alpha: 0.95),
appBar: AppBar(
title: const Text(
'Detail Kamus N4',
style: TextStyle(
color: Colors.black, fontWeight: FontWeight.bold, fontSize: 18),
),
backgroundColor: bgColor3,
elevation: 4,
shadowColor: bgColor2.withValues(alpha: 0.5),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(15),
),
),
iconTheme: const IconThemeData(color: Colors.black),
),
body: FutureBuilder<dynamic>(
future: _kamusFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(bgColor2),
),
);
} else if (snapshot.hasError) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 50),
const SizedBox(height: 16),
Text(
'Error: ${snapshot.error}',
style: const TextStyle(fontSize: 16),
textAlign: TextAlign.center,
),
],
),
);
} else if (!snapshot.hasData) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.search_off, color: Colors.grey, size: 50),
const SizedBox(height: 16),
const Text(
'Data tidak ditemukan',
style: TextStyle(fontSize: 16),
),
],
),
);
}
final item = snapshot.data!;
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Informasi Utama Kamus
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: bgColor2.withValues(alpha: 0.9),
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.2),
shape: BoxShape.circle,
),
child: const Icon(
Icons.menu_book,
color: Colors.white,
size: 24,
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
'Informasi Kamus',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
const SizedBox(height: 16),
_buildDetailRow('Judul', item["judul"]),
_buildDetailRow('Nama', item["nama"]),
_buildDetailRow('Baca', item["baca"]),
],
),
),
const SizedBox(height: 24),
// Contoh Penggunaan
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: bgColor2,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.8),
shape: BoxShape.circle,
),
child: Icon(
Icons.format_quote,
color: bgColor2,
size: 24,
),
),
const SizedBox(width: 12),
Text(
'Contoh Penggunaan',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
const SizedBox(height: 16),
if (item["detail_kamuses"] != null &&
(item["detail_kamuses"] as List).isNotEmpty)
...(item["detail_kamuses"] as List<dynamic>)
.map<Widget>((kamus) {
return _buildExampleCard(kamus);
})
else
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
'Tidak ada contoh penggunaan',
style: TextStyle(
color: Colors.grey[600],
fontStyle: FontStyle.italic,
),
),
),
],
),
),
],
),
);
},
),
);
}
Widget _buildDetailRow(String label, String? value) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 16,
color: Colors.white.withValues(alpha: 0.8),
),
),
const SizedBox(height: 4),
Text(
value ?? '-',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
const SizedBox(height: 8),
const Divider(
color: Colors.white24,
height: 1,
),
],
),
);
}
Widget _buildExampleCard(Map<String, dynamic> kamus) {
return Card(
color: bgColor1,
margin: const EdgeInsets.only(bottom: 12),
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
kamus["kanji"] ?? '-',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
if (kamus["romaji"] != null && kamus["romaji"].isNotEmpty)
Text(
kamus["romaji"],
style: TextStyle(
fontSize: 16,
color: Colors.white.withOpacity(0.7),
),
),
],
),
),
IconButton(
icon: Icon(
Icons.volume_up,
color: bgColor2,
size: 30,
),
onPressed: () => _playAudio(kamus["voice_record"]),
),
],
),
const SizedBox(height: 8),
Text(
kamus["arti"] ?? '-',
style: TextStyle(
fontSize: 16,
color: Colors.white,
),
),
],
),
),
);
}
}