|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
|
|
|
|
import 'package:siopas/theme.dart';
|
|
|
|
|
|
|
|
import '../models/user_model.dart';
|
|
|
|
import '../providers/auth_provider.dart';
|
|
|
|
import '../widget/loading_button.dart';
|
|
|
|
|
|
|
|
class SignInPage extends StatefulWidget {
|
|
|
|
@override
|
|
|
|
State<SignInPage> createState() => _SignInPageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _SignInPageState extends State<SignInPage> {
|
|
|
|
TextEditingController emailController = TextEditingController(text: '');
|
|
|
|
TextEditingController passwordController = TextEditingController(text: '');
|
|
|
|
bool isLoading = false;
|
|
|
|
bool _isPasswordVisible = false;
|
|
|
|
bool _rememberMe = false;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
final bool isSmallScreen = MediaQuery.of(context).size.width < 600;
|
|
|
|
|
|
|
|
AuthProvider authProvider = Provider.of<AuthProvider>(context);
|
|
|
|
UserModel user = authProvider.user;
|
|
|
|
|
|
|
|
handleSignIn() async {
|
|
|
|
// setState(() {
|
|
|
|
// isLoading = true;
|
|
|
|
// });
|
|
|
|
|
|
|
|
if (await authProvider.login(
|
|
|
|
email: emailController.text,
|
|
|
|
password: passwordController.text,
|
|
|
|
)) {
|
|
|
|
UserModel user = authProvider.user;
|
|
|
|
// Simpan token pengguna ke SharedPreferences
|
|
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
|
|
prefs.setString('token', user.token!); // Pastikan user.token tidak null
|
|
|
|
// print('token dapat login: ${user.token}');
|
|
|
|
|
|
|
|
// Periksa apakah pengguna memiliki roles
|
|
|
|
if (user.role_id == "1") {
|
|
|
|
print('Berhasil login HALAMAN ADMIN');
|
|
|
|
Navigator.pushNamed(context, '/home');
|
|
|
|
} else if (user.role_id == "2") {
|
|
|
|
print('Berhasil login HALAMAN USER');
|
|
|
|
Navigator.pushNamed(context, '/home');
|
|
|
|
} else {
|
|
|
|
print('Tidak ada informasi peran (roles) yang tersedia');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
backgroundColor: alertColor,
|
|
|
|
content: Text(
|
|
|
|
'Gagal Login',
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// setState(() {
|
|
|
|
// isLoading = false;
|
|
|
|
// });
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget header() {
|
|
|
|
return Container(
|
|
|
|
margin: EdgeInsets.only(top: 30),
|
|
|
|
child: Column(
|
|
|
|
children: [
|
|
|
|
Image.asset(
|
|
|
|
'assets/logo_login.png',
|
|
|
|
height: 100, // Sesuaikan tinggi gambar sesuai kebutuhan
|
|
|
|
),
|
|
|
|
SizedBox(height: 10),
|
|
|
|
Text(
|
|
|
|
'Login',
|
|
|
|
style: TextStyle(
|
|
|
|
fontSize: 24,
|
|
|
|
fontWeight: semiBold,
|
|
|
|
color: primaryTextColor,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(height: 2),
|
|
|
|
Text(
|
|
|
|
'Sign In to Continue',
|
|
|
|
style: TextStyle(
|
|
|
|
fontSize: 14,
|
|
|
|
fontWeight: regular,
|
|
|
|
color: Colors.black,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget emailInput() {
|
|
|
|
return Container(
|
|
|
|
margin: EdgeInsets.only(top: 20),
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
TextFormField(
|
|
|
|
validator: (value) {
|
|
|
|
// add email validation
|
|
|
|
if (value == null || value.isEmpty) {
|
|
|
|
return 'Please enter some text';
|
|
|
|
}
|
|
|
|
|
|
|
|
bool emailValid = RegExp(
|
|
|
|
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
|
|
|
|
.hasMatch(value);
|
|
|
|
if (!emailValid) {
|
|
|
|
return 'Please enter a valid email';
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
controller: emailController,
|
|
|
|
decoration: const InputDecoration(
|
|
|
|
labelText: 'Email',
|
|
|
|
hintText: 'Enter your email',
|
|
|
|
prefixIcon: Icon(Icons.email_outlined),
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget passwordInput() {
|
|
|
|
return Container(
|
|
|
|
margin: EdgeInsets.only(top: 20),
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
TextFormField(
|
|
|
|
validator: (value) {
|
|
|
|
if (value == null || value.isEmpty) {
|
|
|
|
return 'Please enter some text';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value.length < 6) {
|
|
|
|
return 'Password must be at least 6 characters';
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
obscureText: !_isPasswordVisible,
|
|
|
|
controller: passwordController,
|
|
|
|
decoration: InputDecoration(
|
|
|
|
labelText: 'Password',
|
|
|
|
hintText: 'Enter your password',
|
|
|
|
prefixIcon: const Icon(Icons.lock_outline_rounded),
|
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
suffixIcon: IconButton(
|
|
|
|
icon: Icon(_isPasswordVisible
|
|
|
|
? Icons.visibility_off
|
|
|
|
: Icons.visibility),
|
|
|
|
onPressed: () {
|
|
|
|
setState(() {
|
|
|
|
_isPasswordVisible = !_isPasswordVisible;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget signInButton() {
|
|
|
|
return Container(
|
|
|
|
height: 50,
|
|
|
|
width: double.infinity,
|
|
|
|
margin: EdgeInsets.only(top: 30),
|
|
|
|
child: SizedBox(
|
|
|
|
width: double.infinity,
|
|
|
|
child: ElevatedButton(
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
shape: RoundedRectangleBorder(
|
|
|
|
borderRadius: BorderRadius.circular(4)),
|
|
|
|
),
|
|
|
|
child: const Padding(
|
|
|
|
padding: EdgeInsets.all(10.0),
|
|
|
|
child: Text(
|
|
|
|
'Sign in',
|
|
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
onPressed: () {
|
|
|
|
if (emailController.text.isEmpty ||
|
|
|
|
passwordController.text.isEmpty) {
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
backgroundColor: alertColor,
|
|
|
|
content: Text(
|
|
|
|
'Email dan Password tidak boleh kosong',
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
handleSignIn();
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Scaffold(
|
|
|
|
body: Center(
|
|
|
|
child: isSmallScreen
|
|
|
|
? Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: const [
|
|
|
|
_Logo(),
|
|
|
|
_FormContent(),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
: Container(
|
|
|
|
padding: const EdgeInsets.all(30.0),
|
|
|
|
constraints: const BoxConstraints(maxWidth: 800),
|
|
|
|
child: Row(
|
|
|
|
children: const [
|
|
|
|
Expanded(child: _Logo()),
|
|
|
|
Expanded(
|
|
|
|
child: Center(child: _FormContent()),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class _Logo extends StatelessWidget {
|
|
|
|
const _Logo({Key? key}) : super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
final bool isSmallScreen = MediaQuery.of(context).size.width < 600;
|
|
|
|
|
|
|
|
return Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
// FlutterLogo(size: isSmallScreen ? 100 : 200),
|
|
|
|
Container(
|
|
|
|
margin: EdgeInsets.only(top: 30),
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
borderRadius:
|
|
|
|
BorderRadius.circular(10), // Mengatur sudut menjadi bulat
|
|
|
|
border: Border.all(
|
|
|
|
color: Colors.black, // Warna garis tepi
|
|
|
|
width: 2, // Lebar garis tepi
|
|
|
|
),
|
|
|
|
boxShadow: [
|
|
|
|
BoxShadow(
|
|
|
|
color: Colors.grey.withOpacity(0.5),
|
|
|
|
spreadRadius: 2,
|
|
|
|
blurRadius: 7,
|
|
|
|
offset: Offset(0, 3), // changes position of shadow
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
child: Image.asset(
|
|
|
|
'assets/logo_login.png',
|
|
|
|
height: isSmallScreen ? 100 : 200,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.all(16.0),
|
|
|
|
child: Text(
|
|
|
|
"Welcome To Siopas!",
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
style: isSmallScreen
|
|
|
|
? Theme.of(context).textTheme.headline5
|
|
|
|
: Theme.of(context)
|
|
|
|
.textTheme
|
|
|
|
.headline4
|
|
|
|
?.copyWith(color: Colors.black),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(height: 2),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class _FormContent extends StatefulWidget {
|
|
|
|
const _FormContent({Key? key}) : super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<_FormContent> createState() => __FormContentState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class __FormContentState extends State<_FormContent> {
|
|
|
|
TextEditingController emailController = TextEditingController(text: '');
|
|
|
|
TextEditingController passwordController = TextEditingController(text: '');
|
|
|
|
bool isLoading = false;
|
|
|
|
|
|
|
|
bool _isPasswordVisible = false;
|
|
|
|
bool _rememberMe = false;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
AuthProvider authProvider = Provider.of<AuthProvider>(context);
|
|
|
|
UserModel user = authProvider.user;
|
|
|
|
|
|
|
|
handleSignIn() async {
|
|
|
|
setState(() {
|
|
|
|
isLoading = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (await authProvider.login(
|
|
|
|
email: emailController.text,
|
|
|
|
password: passwordController.text,
|
|
|
|
)) {
|
|
|
|
UserModel user = authProvider.user;
|
|
|
|
// Simpan token pengguna ke SharedPreferences
|
|
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
|
|
prefs.setString('token', user.token!); // Pastikan user.token tidak null
|
|
|
|
print('token dapat login: ${user.token}');
|
|
|
|
|
|
|
|
// Periksa apakah pengguna memiliki roles
|
|
|
|
if (user.role_id == 1) {
|
|
|
|
print('Berhasil login HALAMAN ADMIN');
|
|
|
|
Navigator.pushNamed(context, '/home');
|
|
|
|
} else if (user.role_id == 2) {
|
|
|
|
print('Berhasil login HALAMAN USER');
|
|
|
|
Navigator.pushNamed(context, '/home');
|
|
|
|
} else {
|
|
|
|
print('Tidak ada informasi peran (roles) yang tersedia');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
backgroundColor: alertColor,
|
|
|
|
content: Text(
|
|
|
|
'Gagal Login',
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
isLoading = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return Container(
|
|
|
|
constraints: const BoxConstraints(maxWidth: 300),
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
TextFormField(
|
|
|
|
validator: (value) {
|
|
|
|
// add email validation
|
|
|
|
if (value == null || value.isEmpty) {
|
|
|
|
return 'Please enter some text';
|
|
|
|
}
|
|
|
|
|
|
|
|
bool emailValid = RegExp(
|
|
|
|
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
|
|
|
|
.hasMatch(value);
|
|
|
|
if (!emailValid) {
|
|
|
|
return 'Please enter a valid email';
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
controller: emailController,
|
|
|
|
decoration: const InputDecoration(
|
|
|
|
labelText: 'Email',
|
|
|
|
hintText: 'Enter your email',
|
|
|
|
prefixIcon: Icon(Icons.email_outlined),
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
_gap(),
|
|
|
|
TextFormField(
|
|
|
|
validator: (value) {
|
|
|
|
if (value == null || value.isEmpty) {
|
|
|
|
return 'Please enter some text';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value.length < 6) {
|
|
|
|
return 'Password must be at least 6 characters';
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
obscureText: !_isPasswordVisible,
|
|
|
|
controller: passwordController,
|
|
|
|
decoration: InputDecoration(
|
|
|
|
labelText: 'Password',
|
|
|
|
hintText: 'Enter your password',
|
|
|
|
prefixIcon: const Icon(Icons.lock_outline_rounded),
|
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
suffixIcon: IconButton(
|
|
|
|
icon: Icon(_isPasswordVisible
|
|
|
|
? Icons.visibility_off
|
|
|
|
: Icons.visibility),
|
|
|
|
onPressed: () {
|
|
|
|
setState(() {
|
|
|
|
_isPasswordVisible = !_isPasswordVisible;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
// _gap(),
|
|
|
|
// CheckboxListTile(
|
|
|
|
// value: _rememberMe,
|
|
|
|
// onChanged: (value) {
|
|
|
|
// if (value == null) return;
|
|
|
|
// setState(() {
|
|
|
|
// _rememberMe = value;
|
|
|
|
// });
|
|
|
|
// },
|
|
|
|
// title: const Text('Remember me'),
|
|
|
|
// controlAffinity: ListTileControlAffinity.leading,
|
|
|
|
// dense: true,
|
|
|
|
// contentPadding: const EdgeInsets.all(0),
|
|
|
|
// ),
|
|
|
|
_gap(),
|
|
|
|
SizedBox(
|
|
|
|
width: double.infinity,
|
|
|
|
child: ElevatedButton(
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
shape: RoundedRectangleBorder(
|
|
|
|
borderRadius: BorderRadius.circular(4)),
|
|
|
|
),
|
|
|
|
child: const Padding(
|
|
|
|
padding: EdgeInsets.all(10.0),
|
|
|
|
child: Text(
|
|
|
|
'Login',
|
|
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
onPressed: () {
|
|
|
|
if (emailController.text.isEmpty ||
|
|
|
|
passwordController.text.isEmpty) {
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
backgroundColor: alertColor,
|
|
|
|
content: Text(
|
|
|
|
'Email dan Password tidak boleh kosong',
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
handleSignIn();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _gap() => const SizedBox(height: 16);
|
|
|
|
}
|