NIM_E31222534/Androidnya/lib/screens/dashboard/artikel_detail_screen.dart

328 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:posyandu/services/artikel_service.dart';
import 'package:share_plus/share_plus.dart';
import 'dart:async';
class ArtikelDetailScreen extends StatefulWidget {
final int artikelId;
final ArtikelModel? initialData;
const ArtikelDetailScreen({
Key? key,
required this.artikelId,
this.initialData,
}) : super(key: key);
@override
_ArtikelDetailScreenState createState() => _ArtikelDetailScreenState();
}
class _ArtikelDetailScreenState extends State<ArtikelDetailScreen> {
final ArtikelService _artikelService = ArtikelService();
late Future<ArtikelModel> _artikelFuture;
bool _isLoading = true;
String? _error;
// Flag untuk selalu menggunakan data initial
final bool _useInitialDataOnly = false;
@override
void initState() {
super.initState();
_loadArtikelDetail();
}
void _loadArtikelDetail() {
// Jika ada initial data, prioritaskan initial data
if (widget.initialData != null) {
_artikelFuture = Future.value(widget.initialData!);
return;
}
// Jika tidak ada initial data tapi flag aktif, buat dummy
if (_useInitialDataOnly) {
_artikelFuture = Future.value(_createDummyDetail(widget.artikelId));
return;
}
// Jika masih bisa ambil dari API, coba dengan timeout 5 detik
_artikelFuture = _artikelService.getArtikelDetail(widget.artikelId)
.timeout(
Duration(seconds: 5),
onTimeout: () {
print('Timeout saat mengambil detail artikel');
throw TimeoutException('Waktu habis saat mengambil detail artikel');
},
);
}
// Fungsi lokal untuk membuat model dummy sebagai fallback
ArtikelModel _createDummyDetail(int id) {
return ArtikelModel(
id: id,
judul: 'Artikel Tidak Tersedia',
isiArtikel: 'Maaf, artikel yang Anda cari tidak dapat diakses saat ini. Silakan coba lagi nanti.',
tanggal: DateTime.now(),
gambarUrl: null,
);
}
String _formatDate(DateTime date) {
final months = [
'', 'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni',
'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'
];
return '${date.day} ${months[date.month]} ${date.year}';
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<ArtikelModel>(
future: _artikelFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting && widget.initialData == null) {
return Center(
child: CircularProgressIndicator(
color: Colors.teal.shade700,
),
);
} else if (snapshot.hasError) {
// Jika error tapi ada initial data, gunakan initial data
if (widget.initialData != null) {
return _buildArtikelDetailBody(widget.initialData!);
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
color: Colors.red,
size: 48,
),
SizedBox(height: 16),
Text(
'Gagal memuat artikel',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
SizedBox(height: 8),
Text('${snapshot.error}'),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
setState(() {
_loadArtikelDetail();
});
},
child: Text('Coba Lagi'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal.shade700,
foregroundColor: Colors.white,
),
),
],
),
);
} else if (!snapshot.hasData) {
// Jika tidak ada data tapi ada initial data, gunakan initial data
if (widget.initialData != null) {
return _buildArtikelDetailBody(widget.initialData!);
}
return Center(
child: Text('Artikel tidak ditemukan'),
);
}
return _buildArtikelDetailBody(snapshot.data!);
},
),
);
}
Widget _buildArtikelDetailBody(ArtikelModel artikel) {
final screenSize = MediaQuery.of(context).size;
final gambarUrl = artikel.gambarUrl;
return CustomScrollView(
slivers: [
// Artikel header with image
SliverAppBar(
expandedHeight: screenSize.height * 0.3,
pinned: true,
backgroundColor: Colors.teal.shade700,
leading: IconButton(
icon: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black26,
shape: BoxShape.circle,
),
child: Icon(Icons.arrow_back),
),
onPressed: () => Navigator.pop(context),
),
actions: [
IconButton(
icon: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black26,
shape: BoxShape.circle,
),
child: Icon(Icons.share),
),
onPressed: () {
Share.share(
'Baca artikel "${artikel.judul}" di aplikasi Posyandu',
subject: artikel.judul,
);
},
),
],
flexibleSpace: FlexibleSpaceBar(
background: Stack(
fit: StackFit.expand,
children: [
// Image or placeholder
gambarUrl != null
? Image.network(
gambarUrl,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.network(
'https://img.freepik.com/free-photo/stethoscope-copy-space-medical-stilllife_23-2148854308.jpg',
fit: BoxFit.cover,
);
},
)
: Image.network(
'https://img.freepik.com/free-photo/stethoscope-copy-space-medical-stilllife_23-2148854308.jpg',
fit: BoxFit.cover,
),
// Gradient overlay
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.transparent,
Colors.black.withOpacity(0.7),
],
),
),
),
],
),
),
),
// Content
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title
Text(
artikel.judul,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.grey.shade800,
),
),
SizedBox(height: 8),
// Date
Row(
children: [
Icon(
Icons.calendar_today,
size: 16,
color: Colors.grey.shade600,
),
SizedBox(width: 4),
Text(
_formatDate(artikel.tanggal),
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 14,
),
),
],
),
SizedBox(height: 24),
// Content
Text(
artikel.isiArtikel,
style: TextStyle(
fontSize: 16,
height: 1.6,
color: Colors.grey.shade800,
),
),
SizedBox(height: 32),
// Footer
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Bagikan Artikel',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 8),
Text(
'Informasi kesehatan ini penting untuk dibagikan kepada keluarga dan teman Anda.',
style: TextStyle(
color: Colors.grey.shade700,
fontSize: 14,
),
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton.icon(
onPressed: () {
Share.share(
'Baca artikel: ${artikel.judul}\n\nBaca selengkapnya di aplikasi Posyandu.',
);
},
icon: Icon(Icons.share),
label: Text('Bagikan'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal.shade700,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
],
),
],
),
),
SizedBox(height: 50),
],
),
),
),
],
);
}
}