social-buddy-mobile-app/lib/features/connect/screens/social_connect_details_screen.dart

333 lines
11 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../core/constants/colors.dart';
import '../services/social_auth_service.dart';
import 'channels_screen.dart';
import '../../posts/screens/posts_screen.dart';
import '../../automation/screens/automation_screen.dart';
class SocialMediaConnectScreen extends StatefulWidget {
final bool isTab;
const SocialMediaConnectScreen({super.key, this.isTab = true});
@override
State<SocialMediaConnectScreen> createState() => _SocialMediaConnectScreenState();
}
class _SocialMediaConnectScreenState extends State<SocialMediaConnectScreen> with WidgetsBindingObserver {
final SocialAuthService _socialAuthService = SocialAuthService();
String _status = "checking"; // checking, not_connected, finalizing, connected, error
String? _error;
bool _isLoading = false;
@override
void initState() {
super.initState();
WidgetsFlutterBinding.ensureInitialized();
WidgetsBinding.instance.addObserver(this);
_validateSessionAndInit();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_checkStatus();
}
}
Future<void> _validateSessionAndInit() async {
final prefs = await SharedPreferences.getInstance();
final userJson = prefs.getString('user_details');
if (userJson != null) {
final user = jsonDecode(userJson);
final role = user['role'];
// customer → pricing check required
if (role == 'customer') {
final session = prefs.getString('payment_session');
if (session == null) {
// If in a real app, navigate to Pricing
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Subscription required to access this feature.")),
);
// For now, we continue to check status but could redirect
}
}
}
_checkStatus();
}
Future<void> _checkStatus() async {
if (!mounted) return;
setState(() {
_status = "checking";
_error = null;
});
try {
final status = await _socialAuthService.getStatus();
if (status['connected'] == true) {
setState(() => _status = "connected");
} else {
setState(() => _status = "not_connected");
}
} catch (e) {
if (mounted) {
setState(() {
_status = "error";
_error = e.toString().replaceAll("Exception: ", "");
});
}
}
}
Future<void> _handleDisconnect() async {
setState(() => _isLoading = true);
try {
final success = await _socialAuthService.disconnect();
if (success) {
setState(() => _status = "not_connected");
} else {
setState(() {
_status = "error";
_error = "Failed to remove Facebook account";
});
}
} catch (e) {
setState(() {
_status = "error";
_error = "Error during disconnection";
});
} finally {
setState(() => _isLoading = false);
}
}
Future<void> _handleConnect() async {
const url = 'https://api.socialbuddy.co/api/social/auth/login';
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
} else {
setState(() {
_status = "error";
_error = "Could not launch connection page";
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.darkBg,
appBar: widget.isTab ? null : AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context),
),
),
body: Stack(
children: [
// Background Bubbles (Replicating React bubbles)
Positioned(bottom: -20, left: 20, child: _renderBubble(70, Colors.pink.withOpacity(0.3))),
Positioned(bottom: -30, left: 100, child: _renderBubble(90, Colors.blue.withOpacity(0.3))),
Positioned(bottom: -15, right: 100, child: _renderBubble(60, Colors.green.withOpacity(0.3))),
Positioned(bottom: -40, right: 30, child: _renderBubble(85, Colors.purple.withOpacity(0.3))),
Center(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 24),
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 50),
decoration: BoxDecoration(
color: const Color(0xFF242424),
borderRadius: BorderRadius.circular(30),
border: Border.all(color: Colors.white.withOpacity(0.15)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.4),
blurRadius: 32,
offset: const Offset(0, 10),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ShaderMask(
shaderCallback: (bounds) => const LinearGradient(
colors: [Color(0xFF0073C6), Color(0xFFE44DB3), Color(0xFF5BBE5B)],
).createShader(bounds),
child: Text(
"Social Buddy",
style: GoogleFonts.nunito(
fontSize: 38,
fontWeight: FontWeight.w900,
color: Colors.white,
letterSpacing: 1.1,
),
),
),
const SizedBox(height: 16),
Text(
"Connect & manage your social accounts securely.",
textAlign: TextAlign.center,
style: GoogleFonts.nunito(
fontSize: 17,
color: Colors.white.withOpacity(0.9),
height: 1.4,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 32),
// Status
if (_status == "checking")
const Text("Checking connection...", style: TextStyle(color: Colors.grey, fontSize: 16))
else if (_status == "finalizing")
const Text("Finalizing connection...", style: TextStyle(color: Colors.white, fontSize: 16))
else if (_status == "connected")
const Text(
"✔ Facebook connected!",
style: TextStyle(color: Color(0xFF00AB55), fontWeight: FontWeight.bold, fontSize: 16),
)
else if (_status == "not_connected")
const Text(
"No Facebook account connected.",
style: TextStyle(color: Color(0xFFD4791E), fontWeight: FontWeight.w600, fontSize: 16),
)
else if (_status == "error")
Text(
"$_error",
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.redAccent, fontSize: 15),
),
const SizedBox(height: 40),
// Connect Button
if (_status == "not_connected")
_buildGradientButton(
text: "Connect with Facebook",
onPressed: _isLoading ? null : _handleConnect,
colors: [const Color(0xFF2563EB), const Color(0xFFD946EF)],
),
// Disconnect Button
if (_status == "connected")
_buildFullWidthButton(
text: "Disconnect Facebook",
onPressed: _isLoading ? null : _handleDisconnect,
color: const Color(0xFFE11D48),
),
if (_status == "connected") ...[
const SizedBox(height: 20),
Text(
"You can re-connect anytime.",
style: GoogleFonts.nunito(
color: Colors.white.withOpacity(0.5),
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
],
),
),
),
],
),
);
}
Widget _renderBubble(double size, Color color) {
return Container(
width: size,
height: size,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
boxShadow: [BoxShadow(color: color.withOpacity(0.2), blurRadius: 20)],
),
);
}
Widget _buildGradientButton({required String text, required VoidCallback? onPressed, required List<Color> colors}) {
return SizedBox(
width: double.infinity,
height: 56,
child: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(colors: colors),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: colors.first.withOpacity(0.3),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
padding: const EdgeInsets.symmetric(horizontal: 24),
),
onPressed: onPressed,
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
text,
style: GoogleFonts.nunito(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white),
),
),
),
),
);
}
Widget _buildFullWidthButton({required String text, required VoidCallback? onPressed, required Color color}) {
return SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: color,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 24),
shadowColor: Colors.transparent,
).copyWith(
overlayColor: MaterialStateProperty.all(Colors.white.withOpacity(0.1)),
),
onPressed: onPressed,
child: _isLoading
? const SizedBox(height: 24, width: 24, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2))
: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
text,
style: GoogleFonts.nunito(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white),
),
),
),
);
}
}