Implement token-based login method and update localization for token prompts

This commit is contained in:
RaffaelW 2026-01-28 23:15:20 +01:00
parent 8f18e328e0
commit 2aa745cf69
3 changed files with 188 additions and 69 deletions

View file

@ -1,13 +1,14 @@
import "package:flutter/material.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:inventree/app_colors.dart";
import "package:inventree/user_profile.dart";
import "package:inventree/l10.dart";
import "package:inventree/api.dart";
import "package:inventree/app_colors.dart";
import "package:inventree/l10.dart";
import "package:inventree/user_profile.dart";
import "package:inventree/widget/dialogs.dart";
import "package:inventree/widget/progress.dart";
enum LoginMethod { credentials, token }
class InvenTreeLoginWidget extends StatefulWidget {
const InvenTreeLoginWidget(this.profile) : super();
@ -22,9 +23,12 @@ class _InvenTreeLoginState extends State<InvenTreeLoginWidget> {
String username = "";
String password = "";
String token = "";
bool _obscured = true;
LoginMethod _method = LoginMethod.credentials;
String error = "";
// Attempt login
@ -44,12 +48,19 @@ class _InvenTreeLoginState extends State<InvenTreeLoginWidget> {
showLoadingOverlay();
// Attempt login
final response = await InvenTreeAPI().fetchToken(
widget.profile,
username,
password,
);
final APIResponse response;
if (_method == LoginMethod.credentials) {
// Attempt login
response = await InvenTreeAPI().fetchToken(
widget.profile,
username,
password,
);
} else {
// Check token validity
response = await InvenTreeAPI().checkToken(widget.profile, token);
}
hideLoadingOverlay();
@ -123,55 +134,116 @@ class _InvenTreeLoginState extends State<InvenTreeLoginWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...before,
TextFormField(
decoration: InputDecoration(
labelText: L10().username,
labelStyle: TextStyle(fontWeight: FontWeight.bold),
hintText: L10().enterUsername,
),
initialValue: "",
keyboardType: TextInputType.text,
onSaved: (value) {
username = value?.trim() ?? "";
},
validator: (value) {
if (value == null || value.trim().isEmpty) {
return L10().usernameEmpty;
}
return null;
},
),
TextFormField(
decoration: InputDecoration(
labelText: L10().password,
labelStyle: TextStyle(fontWeight: FontWeight.bold),
hintText: L10().enterPassword,
suffixIcon: IconButton(
icon: _obscured
? Icon(TablerIcons.eye)
: Icon(TablerIcons.eye_off),
onPressed: () {
setState(() {
_obscured = !_obscured;
});
},
// Dropdown to select login method
Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: DropdownButtonFormField<LoginMethod>(
value: _method,
decoration: InputDecoration(
labelText: L10().loginMethod,
labelStyle: TextStyle(fontWeight: FontWeight.bold),
),
items: [
DropdownMenuItem(
child: Text(L10().usernameAndPassword),
value: LoginMethod.credentials,
),
DropdownMenuItem(
child: Text(L10().token),
value: LoginMethod.token,
),
],
onChanged: (val) {
setState(() {
_method = val ?? LoginMethod.credentials;
});
},
),
initialValue: "",
keyboardType: TextInputType.visiblePassword,
obscureText: _obscured,
onSaved: (value) {
password = value?.trim() ?? "";
},
validator: (value) {
if (value == null || value.trim().isEmpty) {
return L10().passwordEmpty;
}
return null;
},
),
// Show fields depending on selected login method
if (_method == LoginMethod.credentials) ...[
TextFormField(
decoration: InputDecoration(
labelText: L10().username,
labelStyle: TextStyle(fontWeight: FontWeight.bold),
hintText: L10().enterUsername,
),
initialValue: "",
keyboardType: TextInputType.text,
onSaved: (value) {
username = value?.trim() ?? "";
},
validator: (value) {
if (value == null || value.trim().isEmpty) {
return L10().usernameEmpty;
}
return null;
},
),
TextFormField(
decoration: InputDecoration(
labelText: L10().password,
labelStyle: TextStyle(fontWeight: FontWeight.bold),
hintText: L10().enterPassword,
suffixIcon: IconButton(
icon: _obscured
? Icon(TablerIcons.eye)
: Icon(TablerIcons.eye_off),
onPressed: () {
setState(() {
_obscured = !_obscured;
});
},
),
),
initialValue: "",
keyboardType: TextInputType.visiblePassword,
obscureText: _obscured,
onSaved: (value) {
password = value?.trim() ?? "";
},
validator: (value) {
if (value == null || value.trim().isEmpty) {
return L10().passwordEmpty;
}
return null;
},
),
] else ...[
TextFormField(
decoration: InputDecoration(
labelText: L10().token,
labelStyle: TextStyle(fontWeight: FontWeight.bold),
hintText: L10().enterToken,
suffixIcon: IconButton(
icon: _obscured
? Icon(TablerIcons.eye)
: Icon(TablerIcons.eye_off),
onPressed: () {
setState(() {
_obscured = !_obscured;
});
},
),
),
initialValue: "",
keyboardType: TextInputType.visiblePassword,
obscureText: _obscured,
onSaved: (value) {
token = value?.trim() ?? "";
},
validator: (value) {
if (value == null || value.trim().isEmpty) {
return L10().tokenEmpty;
}
return null;
},
),
],
...after,
],
),