feat: main loading page while Flutter JS loads

This commit is contained in:
sBubshait 2025-08-03 10:54:36 +03:00
parent d6a0e78031
commit 121395481e
2 changed files with 219 additions and 165 deletions

View File

@ -459,195 +459,196 @@ class _SignInPageState extends State<SignInPage> {
], ],
), ),
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
SizedBox(height: 20), SizedBox(height: 20),
// Logo // Logo
Center( Center(
child: Text(
'وصال',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.w200,
fontFamily: 'Blaka',
color: Color(0xFF6A4C93),
),
),
),
SizedBox(height: 40),
// Welcome text
Text(
'Welcome Back!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
SizedBox(height: 8),
Text(
'Sign in to socialize with your colleagues\nand transform your social life!',
style: TextStyle(
fontSize: 16,
color: Colors.grey[600],
),
textAlign: TextAlign.center,
),
SizedBox(height: 40),
// Email field
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email_outlined),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Color(0xFF6A4C93),
),
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
if (!value.contains('@')) {
return 'Please enter a valid email';
}
return null;
},
),
SizedBox(height: 20),
// Password field
TextFormField(
controller: _passwordController,
obscureText: !_isPasswordVisible,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_isPasswordVisible
? Icons.visibility_off
: Icons.visibility,
),
onPressed: () {
setState(() {
_isPasswordVisible = !_isPasswordVisible;
});
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Color(0xFF6A4C93),
),
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your password';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
return null;
},
),
SizedBox(height: 12),
// Forgot password
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: _showHelpBottomSheet,
child: Text( child: Text(
'Forgot Password?', 'وصال',
style: TextStyle( style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.w200,
fontFamily: 'Blaka',
color: Color(0xFF6A4C93), color: Color(0xFF6A4C93),
fontWeight: FontWeight.w600,
), ),
), ),
), ),
),
SizedBox(height: 30), SizedBox(height: 40),
// Sign in button // Welcome text
Container( Text(
height: 56, 'Welcome Back!',
child: ElevatedButton( style: TextStyle(
onPressed: _isLoading ? null : _handleSignIn, fontSize: 24,
style: ElevatedButton.styleFrom( fontWeight: FontWeight.bold,
backgroundColor: Color(0xFF6A4C93), color: Colors.black87,
foregroundColor: Colors.white, ),
shape: RoundedRectangleBorder( textAlign: TextAlign.center,
),
SizedBox(height: 8),
Text(
'Sign in to socialize with your colleagues\nand transform your social life!',
style: TextStyle(
fontSize: 16,
color: Colors.grey[600],
),
textAlign: TextAlign.center,
),
SizedBox(height: 40),
// Email field
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email_outlined),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
elevation: 2, focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Color(0xFF6A4C93),
),
),
), ),
child: _isLoading validator: (value) {
? CircularProgressIndicator( if (value == null || value.isEmpty) {
valueColor: AlwaysStoppedAnimation<Color>( return 'Please enter your email';
Colors.white, }
), if (!value.contains('@')) {
) return 'Please enter a valid email';
: Text( }
'Sign In', return null;
style: TextStyle( },
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
), ),
),
SizedBox(height: 20), SizedBox(height: 20),
// Contact link for new accounts // Password field
Row( TextFormField(
mainAxisAlignment: MainAxisAlignment.center, controller: _passwordController,
children: [ obscureText: !_isPasswordVisible,
Text( decoration: InputDecoration(
"Don't have an account? ", labelText: 'Password',
style: TextStyle(color: Colors.grey[600]), prefixIcon: Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_isPasswordVisible
? Icons.visibility_off
: Icons.visibility,
),
onPressed: () {
setState(() {
_isPasswordVisible = !_isPasswordVisible;
});
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Color(0xFF6A4C93),
),
),
), ),
GestureDetector( validator: (value) {
onTap: _showHelpBottomSheet, if (value == null || value.isEmpty) {
return 'Please enter your password';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
return null;
},
),
SizedBox(height: 12),
// Forgot password
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: _showHelpBottomSheet,
child: Text( child: Text(
'Contact Support', 'Forgot Password?',
style: TextStyle( style: TextStyle(
color: Color(0xFF6A4C93), color: Color(0xFF6A4C93),
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
), ),
], ),
),
SizedBox(height: 40), SizedBox(height: 30),
],
), // Sign in button
Container(
height: 56,
child: ElevatedButton(
onPressed: _isLoading ? null : _handleSignIn,
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF6A4C93),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 2,
),
child: _isLoading
? CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(
Colors.white,
),
)
: Text(
'Sign In',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
),
SizedBox(height: 20),
// Contact link for new accounts
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have an account? ",
style: TextStyle(color: Colors.grey[600]),
),
GestureDetector(
onTap: _showHelpBottomSheet,
child: Text(
'Contact Support',
style: TextStyle(
color: Color(0xFF6A4C93),
fontWeight: FontWeight.w600,
),
),
),
],
),
SizedBox(height: 40),
],
),
), ),
), ),
), ),

View File

@ -45,13 +45,66 @@
position: fixed; position: fixed;
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0;
padding: 0;
}
/* Loading screen styles */
#loading {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(180deg, #32B0A5 0%, #4600B9 50%);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
/* Loading spinner */
.spinner {
width: 80px;
height: 80px;
border: 6px solid rgba(255, 255, 255, 0.3);
border-top: 6px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Hide loading screen when Flutter loads */
.flutter-loaded #loading {
display: none;
} }
</style> </style>
</head> </head>
<body> <body>
<!-- Loading screen -->
<div id="loading">
<div class="spinner"></div>
</div>
<script src="flutter_bootstrap.js" async></script> <script src="flutter_bootstrap.js" async></script>
<!-- Hide loading screen when Flutter loads -->
<script>
window.addEventListener('flutter-first-frame', function () {
document.body.classList.add('flutter-loaded');
});
// Fallback: hide after 10 seconds if Flutter doesn't load
setTimeout(function() {
document.body.classList.add('flutter-loaded');
}, 10000);
</script>
<!-- Firebase Messaging Service Worker --> <!-- Firebase Messaging Service Worker -->
<script> <script>
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {