You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
452 lines
14 KiB
452 lines
14 KiB
11 months ago
|
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/gps_samara.jpeg',
|
||
|
// height: 100, // Sesuaikan tinggi gambar sesuai kebutuhan
|
||
|
// ),
|
||
|
|
||
|
FlutterLogo(
|
||
|
size: 100,
|
||
|
),
|
||
|
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),
|
||
|
Padding(
|
||
|
padding: const EdgeInsets.all(16.0),
|
||
|
child: Text(
|
||
|
"Welcome to Flutter!",
|
||
|
textAlign: TextAlign.center,
|
||
|
style: isSmallScreen
|
||
|
? Theme.of(context).textTheme.headline5
|
||
|
: Theme.of(context)
|
||
|
.textTheme
|
||
|
.headline4
|
||
|
?.copyWith(color: Colors.black),
|
||
|
),
|
||
|
)
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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(
|
||
|
'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();
|
||
|
}
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Widget _gap() => const SizedBox(height: 16);
|
||
|
}
|