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.
405 lines
12 KiB
405 lines
12 KiB
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; |
|
|
|
// Create controllers for IP Address and Port |
|
TextEditingController ipAddressController = TextEditingController(); |
|
TextEditingController portController = TextEditingController(); |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
final bool isSmallScreen = MediaQuery.of(context).size.width < 600; |
|
AuthProvider authProvider = Provider.of<AuthProvider>(context); |
|
UserModel user = authProvider.user; |
|
|
|
// Function to show the SettingsModal |
|
void _showSettingsModal(BuildContext context) { |
|
showDialog( |
|
context: context, |
|
builder: (BuildContext context) { |
|
return SettingsModal(); |
|
}, |
|
); |
|
} |
|
|
|
return Scaffold( |
|
body: Center( |
|
child: isSmallScreen |
|
? SingleChildScrollView( |
|
reverse: true, |
|
scrollDirection: Axis.vertical, // Tambahkan ini |
|
child: Column( |
|
mainAxisSize: MainAxisSize.min, |
|
children: const [ |
|
_Logo(), |
|
_FormContent(), |
|
], |
|
), |
|
) |
|
: Container( |
|
padding: const EdgeInsets.all(30.0), |
|
constraints: const BoxConstraints(maxWidth: 800), |
|
child: Row( |
|
children: [ |
|
Expanded(child: _Logo()), |
|
Expanded( |
|
child: Center(child: _FormContent()), |
|
), |
|
], |
|
), |
|
), |
|
), |
|
bottomNavigationBar: BottomAppBar( |
|
color: Colors.grey[50], |
|
elevation: 0, |
|
child: Row( |
|
mainAxisAlignment: MainAxisAlignment.center, |
|
children: [ |
|
TextButton( |
|
onPressed: () { |
|
_showSettingsModal(context); // Show the modal |
|
}, |
|
child: Text('Settings'), |
|
), |
|
], |
|
), |
|
), |
|
); |
|
} |
|
} |
|
|
|
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: [ |
|
Container( |
|
margin: EdgeInsets.only(top: 30), |
|
child: Image.asset( |
|
'assets/img/logo_siopas.png', |
|
height: isSmallScreen ? 135 : 200, |
|
), |
|
), |
|
Padding( |
|
padding: const EdgeInsets.all(16.0), |
|
child: Text( |
|
"Welcome To Siopas!", |
|
textAlign: TextAlign.center, |
|
style: TextStyle( |
|
fontSize: isSmallScreen ? 18 : 22, |
|
fontWeight: semiBold, |
|
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: ''); |
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); |
|
|
|
bool isLoading = false; |
|
|
|
bool _isPasswordVisible = 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 |
|
// Role ID Operator |
|
// final String roleId = 'A5C7B207-1A1C-43B8-89BF-222222222222'; |
|
|
|
print('token dapat login: ${user.token}'); |
|
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: Row( |
|
mainAxisAlignment: MainAxisAlignment.center, |
|
children: [ |
|
Icon( |
|
Icons.warning, |
|
color: Colors.white, |
|
), |
|
SizedBox(width: 8), // Jarak antara ikon dan teks |
|
Text( |
|
'Gagal Login, Email dan Password anda salah', |
|
textAlign: TextAlign.center, |
|
), |
|
], |
|
), |
|
), |
|
); |
|
Future.delayed(Duration(seconds: 3), () { |
|
ScaffoldMessenger.of(context).hideCurrentSnackBar(); |
|
}); |
|
} |
|
|
|
setState(() { |
|
isLoading = false; |
|
}); |
|
} |
|
|
|
return Container( |
|
constraints: const BoxConstraints(maxWidth: 300), |
|
child: Form( |
|
key: _formKey, |
|
child: Column( |
|
mainAxisSize: MainAxisSize.min, |
|
mainAxisAlignment: MainAxisAlignment.center, |
|
children: [ |
|
TextFormField( |
|
validator: (value) { |
|
// add email validation |
|
if (value == null || value.isEmpty) { |
|
return 'Silakan masukkan email anda'; |
|
} |
|
|
|
bool emailValid = RegExp( |
|
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") |
|
.hasMatch(value); |
|
if (!emailValid) { |
|
return 'Tolong masukkan email yang benar'; |
|
} |
|
|
|
return null; |
|
}, |
|
controller: emailController, |
|
decoration: const InputDecoration( |
|
labelText: 'Email', |
|
hintText: 'Masukkan email Anda', |
|
prefixIcon: Icon(Icons.email_outlined), |
|
border: OutlineInputBorder(), |
|
), |
|
), |
|
_gap(), |
|
TextFormField( |
|
validator: (value) { |
|
if (value == null || value.isEmpty) { |
|
return 'Silakan masukkan password anda'; |
|
} |
|
|
|
if (value.length < 6) { |
|
return 'Kata sandi minimal harus 6 karakter'; |
|
} |
|
return null; |
|
}, |
|
obscureText: !_isPasswordVisible, |
|
controller: passwordController, |
|
decoration: InputDecoration( |
|
labelText: 'Password', |
|
hintText: 'Masukkan kata sandi Anda', |
|
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(), |
|
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 (_formKey.currentState!.validate()) { |
|
if (emailController.text.isEmpty || |
|
passwordController.text.isEmpty) { |
|
ScaffoldMessenger.of(context).showSnackBar( |
|
SnackBar( |
|
backgroundColor: alertColor, |
|
content: Row( |
|
children: [ |
|
Icon( |
|
Icons.warning, |
|
color: Colors.white, |
|
), |
|
SizedBox(width: 8), // Jarak antara ikon dan teks |
|
Text( |
|
'Email dan Password tidak boleh kosong', |
|
textAlign: TextAlign.center, |
|
), |
|
], |
|
), |
|
), |
|
); |
|
|
|
Future.delayed(Duration(seconds: 2), () { |
|
ScaffoldMessenger.of(context).hideCurrentSnackBar(); |
|
}); |
|
} else { |
|
handleSignIn(); |
|
} |
|
} |
|
}, |
|
), |
|
), |
|
], |
|
), |
|
), |
|
); |
|
} |
|
|
|
Widget _gap() => const SizedBox(height: 16); |
|
} |
|
|
|
class SettingsModal extends StatefulWidget { |
|
const SettingsModal({Key? key}) : super(key: key); |
|
|
|
@override |
|
State<SettingsModal> createState() => _SettingsModalState(); |
|
} |
|
|
|
class _SettingsModalState extends State<SettingsModal> { |
|
TextEditingController ipAddressController = TextEditingController(); |
|
TextEditingController portController = TextEditingController(); |
|
|
|
@override |
|
void initState() { |
|
super.initState(); |
|
// Load saved IP Address and Port when the modal is initialized |
|
loadSettings(); |
|
} |
|
|
|
void loadSettings() async { |
|
SharedPreferences prefs = await SharedPreferences.getInstance(); |
|
String ipAddress = prefs.getString('ipAddress') ?? ''; |
|
String port = prefs.getString('port') ?? ''; |
|
|
|
setState(() { |
|
ipAddressController.text = ipAddress; |
|
portController.text = port; |
|
}); |
|
} |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
return AlertDialog( |
|
title: Row( |
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
children: [ |
|
Text('Settings'), |
|
GestureDetector( |
|
onTap: () { |
|
Navigator.of(context).pop(); // Close the modal |
|
}, |
|
child: Icon(Icons.close), |
|
), |
|
], |
|
), |
|
content: Column( |
|
mainAxisSize: MainAxisSize.min, |
|
children: [ |
|
TextFormField( |
|
controller: ipAddressController, |
|
keyboardType: TextInputType.number, // Set numeric keyboard |
|
decoration: InputDecoration(labelText: 'IP Address'), |
|
), |
|
SizedBox(height: 16), |
|
TextFormField( |
|
controller: portController, |
|
keyboardType: TextInputType.number, // Set numeric keyboard |
|
decoration: InputDecoration(labelText: 'Port'), |
|
), |
|
], |
|
), |
|
actions: [ |
|
ElevatedButton( |
|
onPressed: () { |
|
// Save IP Address and Port to SharedPreferences |
|
saveSettings(ipAddressController.text, portController.text); |
|
Navigator.of(context).pop(); // Close the modal |
|
}, |
|
child: Text('Save'), |
|
), |
|
], |
|
); |
|
} |
|
|
|
void saveSettings(String ipAddress, String port) async { |
|
SharedPreferences prefs = await SharedPreferences.getInstance(); |
|
prefs.setString('ipAddress', ipAddress); |
|
prefs.setString('port', port); |
|
|
|
// Print the saved data |
|
print('IP Address saved: $ipAddress'); |
|
print('Port saved: $port'); |
|
} |
|
|
|
// Function to clear the IP Address and Port in SharedPreferences |
|
void clearSettings() async { |
|
SharedPreferences prefs = await SharedPreferences.getInstance(); |
|
prefs.remove('ipAddress'); |
|
prefs.remove('port'); |
|
print('IP Address and Port cleared'); |
|
} |
|
}
|
|
|