Saba-dart/lib/screens/splash_screen.dart
2026-04-13 23:41:27 +03:30

439 lines
15 KiB
Dart

import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
import 'home_screen.dart';
import '../utils/secure_messaging_service.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with TickerProviderStateMixin {
static const _platform =
MethodChannel('com.example.saba_secure_sms/sms_role');
String _statusText = "در حال بررسی مجوزها...";
String? _startupError;
late AnimationController _animationController;
late AnimationController _loaderController;
late Animation<double> _scaleAnimation;
late Animation<double> _fadeAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
);
_scaleAnimation = Tween<double>(begin: 0.6, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.elasticOut),
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _animationController,
curve: const Interval(0.0, 0.5, curve: Curves.easeIn)),
);
_loaderController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1800),
)..repeat();
_animationController.forward();
_checkPermissions();
}
@override
void dispose() {
_animationController.dispose();
_loaderController.dispose();
super.dispose();
}
Future<void> _checkPermissions() async {
// کمی تاخیر برای اینکه انیمیشن دیده شود
await Future.delayed(const Duration(seconds: 2));
// ... rest of permission logic remains the same ...
Map<Permission, PermissionStatus> statuses = await [
Permission.sms,
Permission.phone,
Permission.contacts,
Permission.notification,
].request();
if (statuses[Permission.sms]!.isGranted &&
statuses[Permission.phone]!.isGranted &&
statuses[Permission.contacts]!.isGranted) {
await _checkAndRequestDefaultSms();
if (mounted) {
setState(() {
_statusText = "آماده‌سازی امن صبا...";
_startupError = null;
});
}
await _initializeSecureLayer();
} else {
if (mounted) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: const Text("مجوزهای مورد نیاز"),
content: const Text(
"صبا برای پیام‌رسانی امن به دسترسی پیامک و مخاطبین نیاز دارد."),
actions: [
TextButton(
onPressed: () => openAppSettings(),
child: const Text("تنظیمات"),
),
TextButton(
onPressed: () {
Navigator.pop(context);
_checkPermissions();
},
child: const Text("تلاش مجدد"),
),
],
),
);
}
}
}
Future<void> _initializeSecureLayer() async {
try {
await SecureMessagingService.instance.init();
// تاخیر کوتاه برای نمایش حالت 'آماده'
await Future.delayed(const Duration(milliseconds: 800));
_goToHome();
} catch (e) {
if (!mounted) return;
setState(() {
_startupError = e.toString();
_statusText = "خطا در راه‌اندازی لایه امنیتی";
});
}
}
Future<void> _checkAndRequestDefaultSms() async {
try {
final bool isDefault = await _platform.invokeMethod('isDefaultSmsApp');
if (!isDefault) {
await _platform.invokeMethod('requestDefaultSmsApp');
await Future.delayed(const Duration(seconds: 1));
}
} catch (_) {}
}
void _goToHome() {
if (mounted) {
Navigator.pushReplacement(
context,
PageRouteBuilder(
transitionDuration: const Duration(milliseconds: 800),
pageBuilder: (context, animation, secondaryAnimation) =>
const HomeScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(opacity: animation, child: child);
},
),
);
}
}
Widget _buildSecurityLoader() {
return AnimatedBuilder(
animation: _loaderController,
builder: (context, child) {
final t = _loaderController.value;
final scanProgress = Curves.easeInOut.transform(t);
final pulses = [
(t + 0.08) % 1.0,
(t + 0.58) % 1.0,
];
return SizedBox(
width: 180,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 120,
height: 120,
child: Stack(
alignment: Alignment.center,
children: [
for (final pulse in pulses)
Transform.scale(
scale: 0.78 + (pulse * 0.72),
child: Opacity(
opacity: (1 - pulse) * 0.22,
child: Container(
width: 88,
height: 88,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 1.2,
),
),
),
),
),
Container(
width: 92,
height: 92,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(28),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withValues(alpha: 0.18),
Colors.white.withValues(alpha: 0.06),
],
),
border: Border.all(
color: Colors.white.withValues(alpha: 0.22),
width: 1,
),
boxShadow: [
BoxShadow(
color:
const Color(0xFF8EC5FF).withValues(alpha: 0.18),
blurRadius: 20,
spreadRadius: 1,
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(28),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
top: 10 + (scanProgress * 50),
child: Container(
width: 78,
height: 18,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(18),
gradient: LinearGradient(
colors: [
Colors.transparent,
Colors.white.withValues(alpha: 0.0),
const Color(0xFF7FD8FF)
.withValues(alpha: 0.34),
Colors.white.withValues(alpha: 0.0),
Colors.transparent,
],
),
),
),
),
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withValues(alpha: 0.1),
),
),
const Icon(
Icons.verified_user_rounded,
color: Colors.white,
size: 34,
),
],
),
),
),
Positioned(
bottom: 2,
child: Row(
children: List.generate(4, (index) {
final wave = 0.5 +
0.5 *
math.sin(
((t + (index * 0.16)) * 2 * math.pi),
);
final height = 10 + (wave * 18);
return Container(
width: 9,
height: height,
margin: const EdgeInsets.symmetric(horizontal: 3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.white,
Color(0xFF7FD8FF),
],
),
),
);
}),
),
),
],
),
),
const SizedBox(height: 16),
Container(
width: 150,
height: 8,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(99),
color: Colors.white.withValues(alpha: 0.12),
),
child: Stack(
children: [
AnimatedAlign(
duration: const Duration(milliseconds: 120),
alignment: Alignment(-1 + (scanProgress * 2), 0),
child: Container(
width: 52,
height: 8,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(99),
gradient: const LinearGradient(
colors: [
Color(0xFF7FD8FF),
Color(0xFFFFFFFF),
],
),
),
),
),
],
),
),
],
),
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Theme.of(context).primaryColor, const Color(0xFF1A237E)],
),
),
child: Stack(
children: [
// Background subtle patterns could go here
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Opacity(
opacity: _fadeAnimation.value,
child: Transform.scale(
scale: _scaleAnimation.value,
child: Hero(
tag: 'app_logo',
child: SizedBox(
width: 200,
height: 200,
child: Image.asset('صبا بالا.png'),
),
),
),
);
},
),
const SizedBox(height: 40),
const Text(
"صبا",
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.white,
letterSpacing: 1.2,
),
),
const Text(
"پیام‌رسان امن و پیشرفته",
style: TextStyle(
fontSize: 16,
color: Colors.white70,
fontWeight: FontWeight.w300,
),
),
const SizedBox(height: 60),
if (_startupError == null) _buildSecurityLoader(),
if (_startupError != null)
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.blue.shade900,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
),
onPressed: () {
setState(() {
_startupError = null;
_statusText = "در حال اتصال...";
});
_checkPermissions();
},
child: const Text("تلاش مجدد"),
),
const SizedBox(height: 20),
Text(
_statusText,
style: const TextStyle(color: Colors.white60, fontSize: 13),
),
],
),
),
const Positioned(
bottom: 40,
left: 0,
right: 0,
child: Center(
child: Text(
"SABA SECURE MESSENGER",
style: TextStyle(
color: Colors.white24,
fontSize: 12,
letterSpacing: 2,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
);
}
}