Skip to content

Commit

Permalink
buillding the front-end features
Browse files Browse the repository at this point in the history
  • Loading branch information
njogubless committed Feb 4, 2025
1 parent 0fb2f06 commit eb333c5
Show file tree
Hide file tree
Showing 12 changed files with 777 additions and 687 deletions.
71 changes: 39 additions & 32 deletions lib/core/common/navigation/main_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,57 @@ class MainLayout extends StatefulWidget {
MainLayoutState createState() => MainLayoutState();
}

class MainLayoutState extends State<MainLayout> {
class MainLayoutState extends State<MainLayout> with SingleTickerProviderStateMixin {
int _selectedIndex = 0;

final List<Widget> _screens = [
const HomeScreen(),
const AudioScreen(),
const DevotionPage(),
ArticleScreen(),
ArticleScreen(),
BookScreen(),
const QuestionPage(),
];

late AnimationController _animationController;
late Animation<double> _animation;

@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_animation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
);
}

void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
_animationController.forward(from: 0.0);
});
}

@override
void dispose() {
_animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: _screens[_selectedIndex],
body: FadeTransition(
opacity: _animation,
child: IndexedStack(
index: _selectedIndex,
children: _screens,
),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
Expand All @@ -50,34 +79,8 @@ class MainLayoutState extends State<MainLayout> {
icon: Icon(Icons.mic),
label: 'Devotion',
),
BottomNavigationBarItem(
icon: Stack(
children: [
const Icon(Icons.article),
Positioned(
right: 0,
child: Container(
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(6),
),
constraints: const BoxConstraints(
minWidth: 12,
minHeight: 12,
),
child: const Text(
'1',
style: TextStyle(
color: Colors.white,
fontSize: 8,
),
textAlign: TextAlign.center,
),
),
),
],
),
const BottomNavigationBarItem(
icon: Icon(Icons.article),
label: 'Articles',
),
const BottomNavigationBarItem(
Expand All @@ -91,8 +94,12 @@ class MainLayoutState extends State<MainLayout> {
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.blueAccent,
unselectedItemColor: Colors.grey,
showUnselectedLabels: false,
backgroundColor: Colors.white,
onTap: _onItemTapped,
elevation: 10,
),
);
}
}
}
184 changes: 161 additions & 23 deletions lib/features/admin/presentation/screens/admin_dashboard.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,60 @@
import 'package:devotion/features/admin/presentation/admin_dashbaord_tile.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:file_picker/file_picker.dart';
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:devotion/core/constants/firebase_constants.dart';

class AdminDashboard extends StatelessWidget {
const AdminDashboard({Key? key}) : super(key: key);

Future<void> _uploadAudioFile() async {
final result = await FilePicker.platform.pickFiles(type: FileType.audio);
if (result != null) {
final file = File(result.files.single.path!);
final fileName = result.files.single.name;
final storageRef = FirebaseStorage.instance.ref().child("audio/$fileName");

try {
await storageRef.putFile(file);
final downloadUrl = await storageRef.getDownloadURL();
await FirebaseFirestore.instance
.collection(FirebaseConstants.sermonCollection)
.add({'title': fileName, 'url': downloadUrl, 'timestamp': FieldValue.serverTimestamp()});
debugPrint('Audio file uploaded successfully: $downloadUrl');
} catch (e) {
debugPrint('Error uploading audio: $e');
}
}
}

Future<void> _uploadBookFile() async {
final result = await FilePicker.platform.pickFiles(type: FileType.custom, allowedExtensions: ['pdf']);
if (result != null) {
final file = File(result.files.single.path!);
final fileName = result.files.single.name;
final storageRef = FirebaseStorage.instance.ref().child("books/$fileName");

try {
await storageRef.putFile(file);
final downloadUrl = await storageRef.getDownloadURL();
await FirebaseFirestore.instance
.collection(FirebaseConstants.testimonyCollection)
.add({'title': fileName, 'url': downloadUrl, 'timestamp': FieldValue.serverTimestamp()});
debugPrint('Book file uploaded successfully: $downloadUrl');
} catch (e) {
debugPrint('Error uploading book: $e');
}
}
}

void _navigateToWriteArticle(BuildContext context) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const WriteArticleScreen()),
);
}

@override
Widget build(BuildContext context) {
return Scaffold(
Expand All @@ -15,7 +64,7 @@ class AdminDashboard extends StatelessWidget {
IconButton(
icon: const Icon(Icons.logout),
onPressed: () {
Navigator.pushNamedAndRemoveUntil(context, '/login', (route) => false);
Navigator.pushNamedAndRemoveUntil(context, '/homeScreen', (route) => false);
},
tooltip: 'Logout',
),
Expand All @@ -42,29 +91,23 @@ class AdminDashboard extends StatelessWidget {
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: [
DashboardTile(
title: 'Upload Article',
iconPath: 'assets/icons/article.png',
route: '/uploadArticle',
isPending: false,
),
DashboardTile(
_buildDashboardTile(
context,
title: 'Upload Audio',
iconPath: 'assets/icons/audio.png',
route: '/uploadAudio',
isPending: true,
icon: Icons.audiotrack,
onTap: _uploadAudioFile,
),
DashboardTile(
_buildDashboardTile(
context,
title: 'Upload Book',
iconPath: 'assets/icons/book.png',
route: '/uploadBook',
isPending: false,
icon: Icons.book,
onTap: _uploadBookFile,
),
DashboardTile(
title: 'Answer Questions',
iconPath: 'assets/icons/questions.png',
route: '/answerQuestions',
isPending: true,
_buildDashboardTile(
context,
title: 'Write Article',
icon: Icons.article,
onTap: () => _navigateToWriteArticle(context),
),
],
),
Expand All @@ -74,4 +117,99 @@ class AdminDashboard extends StatelessWidget {
),
);
}

Widget _buildDashboardTile(BuildContext context, {
required String title,
required IconData icon,
required VoidCallback onTap,
}) {
return GestureDetector(
onTap: onTap,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 40, color: Colors.blueAccent),
const SizedBox(height: 10),
Text(
title,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
],
),
),
),
);
}
}

class WriteArticleScreen extends StatefulWidget {
const WriteArticleScreen({Key? key}) : super(key: key);

@override
State<WriteArticleScreen> createState() => _WriteArticleScreenState();
}

class _WriteArticleScreenState extends State<WriteArticleScreen> {
final _titleController = TextEditingController();
final _contentController = TextEditingController();

Future<void> _submitArticle() async {
final title = _titleController.text.trim();
final content = _contentController.text.trim();

if (title.isNotEmpty && content.isNotEmpty) {
try {
await FirebaseFirestore.instance.collection(FirebaseConstants.articleCollection).add({
'title': title,
'content': content,
'timestamp': FieldValue.serverTimestamp(),
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Article submitted successfully!')),
);
_titleController.clear();
_contentController.clear();
} catch (e) {
debugPrint('Error submitting article: $e');
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please fill in both fields.')),
);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Write Article')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _titleController,
decoration: const InputDecoration(labelText: 'Article Title'),
),
const SizedBox(height: 10),
TextField(
controller: _contentController,
decoration: const InputDecoration(labelText: 'Article Content'),
maxLines: 5,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _submitArticle,
child: const Text('Submit Article'),
),
],
),
),
);
}
}
Loading

0 comments on commit eb333c5

Please sign in to comment.