Initial commit

This commit is contained in:
kihong.kim
2026-01-24 19:41:19 +09:00
commit 807df3d678
90 changed files with 6411 additions and 0 deletions

View File

@@ -0,0 +1,169 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/announcement.dart';
import '../services/announcement_service.dart';
class AnnouncementWidget extends StatefulWidget {
const AnnouncementWidget({super.key});
@override
State<AnnouncementWidget> createState() => _AnnouncementWidgetState();
}
class _AnnouncementWidgetState extends State<AnnouncementWidget> {
final PageController _pageController = PageController();
Timer? _timer;
int _currentPage = 0;
List<Announcement> _announcements = [];
@override
void initState() {
super.initState();
_fetchAnnouncements();
}
void _fetchAnnouncements() async {
try {
final data = await Provider.of<AnnouncementService>(
context,
listen: false,
).fetchAnnouncements(activeOnly: true);
if (mounted) {
setState(() {
_announcements = data;
});
_startAutoScroll();
}
} catch (e) {
// Handle error
}
}
void _startAutoScroll() {
_timer?.cancel();
if (_announcements.length > 1) {
_timer = Timer.periodic(const Duration(seconds: 10), (timer) {
if (_pageController.hasClients) {
_currentPage++;
if (_currentPage >= _announcements.length) {
_currentPage = 0;
}
_pageController.animateToPage(
_currentPage,
duration: const Duration(milliseconds: 800),
curve: Curves.easeInOut,
);
}
});
}
}
@override
void dispose() {
_timer?.cancel();
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (_announcements.isEmpty) {
// Show default placeholder if no announcements
return Container(
decoration: BoxDecoration(
color: Theme.of(context).cardTheme.color,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.white10),
),
padding: const EdgeInsets.all(16),
child: const Center(
child: Text(
'Welcome Home! Have a great day.',
style: TextStyle(color: Colors.white70, fontSize: 18),
),
),
);
}
return Container(
decoration: BoxDecoration(
color: Theme.of(
context,
).cardTheme.color, // Slightly lighter/distinct background
borderRadius: BorderRadius.circular(16),
),
child: Stack(
children: [
PageView.builder(
controller: _pageController,
itemCount: _announcements.length,
itemBuilder: (context, index) {
final item = _announcements[index];
return Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.campaign,
color: Theme.of(context).colorScheme.secondary,
size: 32,
),
const SizedBox(width: 12),
Text(
item.title,
style: Theme.of(context)
.textTheme
.headlineSmall
?.copyWith(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12),
Text(
item.content,
style: Theme.of(
context,
).textTheme.bodyLarge?.copyWith(color: Colors.white),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
],
),
);
},
),
// Page Indicator
if (_announcements.length > 1)
Positioned(
bottom: 16,
right: 16,
child: Row(
children: List.generate(_announcements.length, (index) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.symmetric(horizontal: 4),
width: 8,
height: 8,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _currentPage == index
? Theme.of(context).colorScheme.secondary
: Colors.white24,
),
);
}),
),
),
],
),
);
}
}