forked from ReiMerc/skantravels
Implement login and save token
This commit is contained in:
parent
c9769fcada
commit
debbddd05b
@ -1,4 +1,6 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
android:label="mobile"
|
||||
android:name="${applicationName}"
|
||||
|
53
Mobile/lib/api.dart
Normal file
53
Mobile/lib/api.dart
Normal file
@ -0,0 +1,53 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
|
||||
enum ApiService {
|
||||
auth,
|
||||
app,
|
||||
}
|
||||
|
||||
Future<String?> request(BuildContext context, ApiService service, String method, String path, Object? body) async {
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
|
||||
final host = switch (service) {
|
||||
ApiService.auth => const String.fromEnvironment('AUTH_SERVICE_HOST'),
|
||||
ApiService.app => const String.fromEnvironment('APP_SERVICE_HOST'),
|
||||
};
|
||||
|
||||
final http.Response response;
|
||||
|
||||
try {
|
||||
if (method == 'GET') {
|
||||
response = await http.get(Uri.parse(host + path));
|
||||
} else {
|
||||
final function = switch (method) {
|
||||
'POST' => http.post,
|
||||
'PUT' => http.put,
|
||||
'DELETE' => http.delete,
|
||||
_ => throw const FormatException('Invalid method'),
|
||||
};
|
||||
|
||||
response = await function(
|
||||
Uri.parse(host + path),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: body != null ? jsonEncode(body) : null,
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
messenger.showSnackBar(const SnackBar(content: Text('Unable to connect to server')));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||
try {
|
||||
final json = jsonDecode(response.body);
|
||||
messenger.showSnackBar(SnackBar(content: Text(json['message'])));
|
||||
} catch (_) {
|
||||
messenger.showSnackBar(SnackBar(content: Text('Something went wrong (HTTP ${response.statusCode})')));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.body;
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'register.dart';
|
||||
import 'api.dart' as api;
|
||||
|
||||
class LoginPage extends StatefulWidget {
|
||||
const LoginPage({super.key, required this.title});
|
||||
@ -11,6 +15,26 @@ class LoginPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _LoginPageState extends State<LoginPage> {
|
||||
final emailInput = TextEditingController();
|
||||
final passwordInput = TextEditingController();
|
||||
|
||||
Future<void> _login() async {
|
||||
final token = await api.request(context, api.ApiService.auth, 'POST', '/api/Users/login', {
|
||||
'email': emailInput.text,
|
||||
'password': passwordInput.text,
|
||||
});
|
||||
|
||||
if (token == null) return;
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString('token', token);
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Successfully logged in')));
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -25,16 +49,16 @@ class _LoginPageState extends State<LoginPage> {
|
||||
children: [
|
||||
const SizedBox(height: 80),
|
||||
const Text('Email'),
|
||||
const TextField(),
|
||||
TextField(controller: emailInput),
|
||||
const SizedBox(height: 30),
|
||||
const Text('Password'),
|
||||
const TextField(obscureText: true, enableSuggestions: false, autocorrect: false),
|
||||
TextField(controller: passwordInput, obscureText: true, enableSuggestions: false, autocorrect: false),
|
||||
const SizedBox(height: 30),
|
||||
ElevatedButton(child: const Text('Log ind'), onPressed: () => Navigator.pop(context)),
|
||||
ElevatedButton(onPressed: _login, child: const Text('Log ind')),
|
||||
const SizedBox(height: 10),
|
||||
TextButton(
|
||||
child: const Text('Registrer konto'),
|
||||
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => const RegisterPage(title: 'Registrer'))),
|
||||
onPressed: () => Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => const RegisterPage(title: 'Registrer'))),
|
||||
)
|
||||
]
|
||||
)
|
||||
@ -42,4 +66,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
emailInput.dispose();
|
||||
passwordInput.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
const SizedBox(height: 10),
|
||||
TextButton(
|
||||
child: const Text('Log ind'),
|
||||
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => const LoginPage(title: 'Log ind')))
|
||||
onPressed: () => Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => const LoginPage(title: 'Log ind')))
|
||||
),
|
||||
]
|
||||
)
|
||||
|
@ -5,6 +5,8 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
}
|
||||
|
@ -8,5 +8,7 @@
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -4,5 +4,7 @@
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -65,6 +65,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -91,6 +107,11 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -211,6 +232,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.5"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
polylabel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -227,6 +288,62 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: a7e8467e9181cef109f601e3f65765685786c1a738a83d7fbbde377589c0d974
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -328,6 +445,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
sdks:
|
||||
dart: ">=3.3.4 <4.0.0"
|
||||
flutter: ">=3.18.0-18.0.pre.54"
|
||||
dart: ">=3.4.0 <4.0.0"
|
||||
flutter: ">=3.22.0"
|
||||
|
@ -37,6 +37,7 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.6
|
||||
shared_preferences: ^2.3.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user