import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:image_picker/image_picker.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:onsolgo/core/constants.dart'; import 'package:onsolgo/core/share_helper.dart'; import 'package:onsolgo/widgets/comments_sheet.dart'; class SocialFeed extends StatelessWidget { const SocialFeed({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar(title: const Text("MANAA SOCIAL", style: TextStyle(letterSpacing: 2, fontWeight: FontWeight.bold)), centerTitle: true), body: StreamBuilder( stream: FirebaseFirestore.instance.collection('social_posts').orderBy('timestamp', descending: true).snapshots(), builder: (context, snapshot) { if (!snapshot.hasData) return const Center(child: CircularProgressIndicator(color: kOnsolGold)); return ListView.builder( itemCount: snapshot.data!.docs.length, itemBuilder: (context, index) => _SocialPostCard(post: snapshot.data!.docs[index]), ); }, ), floatingActionButton: FloatingActionButton( backgroundColor: kOnsolGold, child: const Icon(Icons.add_a_photo, color: Colors.black), onPressed: () => showModalBottomSheet(context: context, isScrollControlled: true, backgroundColor: Colors.grey[900], builder: (c) => const _CreatePostSheet()), ), ); } } class _SocialPostCard extends StatefulWidget { final QueryDocumentSnapshot post; const _SocialPostCard({required this.post}); @override State<_SocialPostCard> createState() => _SocialPostCardState(); } class _SocialPostCardState extends State<_SocialPostCard> { final GlobalKey _postKey = GlobalKey(); Future _confirmDeletePost() async { final ok = await showDialog( context: context, builder: (c) => AlertDialog( backgroundColor: Colors.grey[900], title: const Text('Delete post?', style: TextStyle(color: Colors.white)), content: const Text('This cannot be undone.', style: TextStyle(color: Colors.white70)), actions: [ TextButton(onPressed: () => Navigator.pop(c, false), child: const Text('Cancel')), TextButton(onPressed: () => Navigator.pop(c, true), child: const Text('Delete', style: TextStyle(color: Colors.redAccent))), ], ), ); if (ok != true || !mounted) return; try { await widget.post.reference.delete(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Post removed'))); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Could not delete: $e'))); } } } Future _toggleLike() async { final uid = FirebaseAuth.instance.currentUser?.uid; if (uid == null) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Sign in to like posts'))); return; } final ref = widget.post.reference; try { await FirebaseFirestore.instance.runTransaction((txn) async { final snap = await txn.get(ref); final data = snap.data() as Map?; final liked = List.from((data?['likedBy'] as List?)?.map((e) => e.toString()) ?? []); final set = liked.toSet(); if (set.contains(uid)) { set.remove(uid); } else { set.add(uid); } final next = set.toList(); txn.update(ref, {'likedBy': next, 'likes': next.length}); }); } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Like failed: $e'))); } } } @override Widget build(BuildContext context) { final post = widget.post; final d = post.data() as Map; final bool isVer = (d['isVerified'] ?? false) || (d['authorRank'] == "VERIFIED ManaA ARTIST"); final uid = FirebaseAuth.instance.currentUser?.uid ?? ''; final likedBy = List.from((d['likedBy'] as List?)?.map((e) => e.toString()) ?? []); final liked = uid.isNotEmpty && likedBy.contains(uid); final likeCount = likedBy.length; final authorId = (d['authorId'] as String?) ?? ''; Widget card({required bool canDelete}) { return RepaintBoundary( key: _postKey, child: Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration(color: Colors.grey[900], borderRadius: BorderRadius.circular(15)), child: Column(children: [ StreamBuilder( stream: FirebaseFirestore.instance.collection('users').doc(d['authorId']).snapshots(), builder: (context, userSnap) { String? livePfp; if (userSnap.hasData && userSnap.data!.exists) { var uD = userSnap.data!.data() as Map; livePfp = uD.containsKey('pfpUrl') ? uD['pfpUrl'] : null; } return ListTile( leading: CircleAvatar( backgroundColor: Colors.black, backgroundImage: livePfp != null ? NetworkImage(livePfp) : null, child: livePfp == null ? const Icon(Icons.person, color: Colors.white24) : null), title: Row(children: [ Text(d['authorName'] ?? 'Citizen', style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white)), verifiedBadge(isVer, size: 18), ]), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (canDelete) IconButton( tooltip: 'Delete post', icon: const Icon(Icons.delete_outline, size: 20, color: Colors.redAccent), onPressed: _confirmDeletePost, ), IconButton( icon: const Icon(Icons.share_outlined, size: 18, color: Colors.grey), onPressed: () { final raw = (d['content'] as String?)?.trim() ?? ''; final caption = raw.isNotEmpty ? raw : 'Transmission from ${d['authorName'] ?? 'ONSOL-GO'}'; OnsolShare.share( _postKey, caption, link: kOnsolSharePostUrl(post.id), ); }, ), ], ), ); }), if (d['imageUrl'] != null) CachedNetworkImage(imageUrl: d['imageUrl'], width: double.infinity, fit: BoxFit.cover), if (d['content'] != "") Padding(padding: const EdgeInsets.all(16), child: Text(d['content'] ?? '')), Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 12), child: Row( children: [ IconButton( icon: Icon(liked ? Icons.favorite : Icons.favorite_border, color: liked ? Colors.redAccent : Colors.white70, size: 22), onPressed: _toggleLike, tooltip: 'Like', ), Text('$likeCount', style: const TextStyle(color: Colors.white70, fontWeight: FontWeight.w600)), const SizedBox(width: 8), IconButton( icon: const Icon(Icons.chat_bubble_outline, color: Colors.white70, size: 22), onPressed: () => CommentsSheet.show(context, parent: post.reference, title: 'Comments'), tooltip: 'Comments', ), const Text('Comment', style: TextStyle(color: Colors.white54, fontSize: 13)), ], ), ), ]), ), ); } if (uid.isEmpty) { return card(canDelete: false); } return StreamBuilder( stream: FirebaseFirestore.instance.collection('users').doc(uid).snapshots(), builder: (context, meSnap) { String? role; if (meSnap.hasData && meSnap.data!.exists) { role = (meSnap.data!.data() as Map?)?['role'] as String?; } final canDelete = uid == authorId || role == 'admin'; return card(canDelete: canDelete); }, ); } } class _CreatePostSheet extends StatefulWidget { const _CreatePostSheet(); @override State<_CreatePostSheet> createState() => _CreatePostSheetState(); } class _CreatePostSheetState extends State<_CreatePostSheet> { final _textC = TextEditingController(); Uint8List? _webImage; bool _posting = false; Future _pick() async { final picked = await ImagePicker().pickImage(source: ImageSource.gallery, imageQuality: 60); if (picked != null) { final bytes = await picked.readAsBytes(); setState(() => _webImage = bytes); } } @override Widget build(BuildContext context) { return SafeArea(child: Padding(padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom + 20, left: 20, right: 20, top: 20), child: Column(mainAxisSize: MainAxisSize.min, children: [ const Text("NEW ANNOUNCEMENT", style: TextStyle(fontWeight: FontWeight.bold, color: kOnsolGold)), if (_webImage != null) Image.memory(_webImage!, height: 100), TextField(controller: _textC, maxLines: 3, style: const TextStyle(color: Colors.white), decoration: const InputDecoration(hintText: "Speak to the Order...")), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton(onPressed: _pick, icon: const Icon(Icons.image, color: Colors.amber)), _posting ? const CircularProgressIndicator() : ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: kOnsolGold, foregroundColor: Colors.black), onPressed: () async { final messenger = ScaffoldMessenger.of(context); setState(() => _posting = true); try { final u = FirebaseAuth.instance.currentUser; final uSnap = await FirebaseFirestore.instance.collection('users').doc(u?.uid).get(); final raw = uSnap.data(); if (u == null || !uSnap.exists || raw == null) { messenger.showSnackBar( const SnackBar(content: Text('Profile not found. Try signing in again.')), ); return; } final uMap = Map.from(raw as Map); String? url; if (_webImage != null) { final ref = FirebaseStorage.instance.ref().child('social').child('${DateTime.now().millisecondsSinceEpoch}.jpg'); await ref.putData(_webImage!, SettableMetadata(contentType: 'image/jpeg')); url = await ref.getDownloadURL(); } await FirebaseFirestore.instance.collection('social_posts').add({ 'authorId': u.uid, 'authorName': uMap['username'], 'authorPfp': uMap['pfpUrl'], 'authorRank': getRankName(safeInt(uMap['rankLevel'])), 'isVerified': safeInt(uMap['rankLevel']) == 5 || (uMap['isVerified'] ?? false), 'content': _textC.text, 'imageUrl': url, 'likes': 0, 'likedBy': [], 'timestamp': FieldValue.serverTimestamp(), }); if (context.mounted) Navigator.pop(context); } catch (e) { messenger.showSnackBar(SnackBar(content: Text('Post failed: $e'))); } finally { if (mounted) setState(() => _posting = false); } }, child: const Text("POST")), ]), ]))); } }