mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
243 lines
8.2 KiB
Dart
243 lines
8.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:chopper/chopper.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
|
import 'package:fladder/models/account_model.dart';
|
|
import 'package:fladder/models/credentials_model.dart';
|
|
import 'package:fladder/models/login_screen_model.dart';
|
|
import 'package:fladder/providers/api_provider.dart';
|
|
import 'package:fladder/providers/dashboard_provider.dart';
|
|
import 'package:fladder/providers/favourites_provider.dart';
|
|
import 'package:fladder/providers/image_provider.dart';
|
|
import 'package:fladder/providers/library_screen_provider.dart';
|
|
import 'package:fladder/providers/service_provider.dart';
|
|
import 'package:fladder/providers/shared_provider.dart';
|
|
import 'package:fladder/providers/user_provider.dart';
|
|
import 'package:fladder/providers/views_provider.dart';
|
|
import 'package:fladder/screens/login/lock_screen.dart';
|
|
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
|
import 'package:fladder/util/fladder_config.dart';
|
|
import 'package:fladder/util/localization_helper.dart';
|
|
import 'package:fladder/util/string_extensions.dart';
|
|
|
|
final authProvider = StateNotifierProvider<AuthNotifier, LoginScreenModel>((ref) {
|
|
return AuthNotifier(ref);
|
|
});
|
|
|
|
class AuthNotifier extends StateNotifier<LoginScreenModel> {
|
|
AuthNotifier(this.ref) : super(LoginScreenModel());
|
|
|
|
final Ref ref;
|
|
|
|
late final JellyService api = ref.read(jellyApiProvider);
|
|
|
|
BuildContext? context;
|
|
|
|
Future<void> initModel(BuildContext newContext) async {
|
|
context ??= newContext;
|
|
ref.read(userProvider.notifier).clear();
|
|
final currentAccounts = ref.read(authProvider.notifier).getSavedAccounts();
|
|
ref.read(lockScreenActiveProvider.notifier).update((state) => true);
|
|
if (FladderConfig.baseUrl != null) {
|
|
final url = FladderConfig.baseUrl;
|
|
state = state.copyWith(
|
|
hasBaseUrl: true,
|
|
);
|
|
if (url != null) {
|
|
await setServer(url);
|
|
}
|
|
}
|
|
state = state.copyWith(
|
|
accounts: currentAccounts,
|
|
screen: currentAccounts.isEmpty ? LoginScreenType.login : LoginScreenType.users,
|
|
);
|
|
}
|
|
|
|
Future<void> _fetchServerInfo(String url) async {
|
|
try {
|
|
final newCredentials = CredentialsModel.createNewCredentials().copyWith(server: url.rtrim('/'));
|
|
final newLoginModel = ServerLoginModel(tempCredentials: newCredentials);
|
|
state = state.copyWith(
|
|
serverLoginModel: newLoginModel,
|
|
loading: true,
|
|
);
|
|
final publicUsers = (await getPublicUsers())?.body ?? [];
|
|
final quickConnectStatus = (await api.quickConnectEnabled()).body ?? false;
|
|
final branding = await api.getBranding();
|
|
final serverResponse = await api.systemInfoPublicGet();
|
|
state = state.copyWith(
|
|
screen: quickConnectStatus ? LoginScreenType.code : LoginScreenType.login,
|
|
serverLoginModel: newLoginModel.copyWith(
|
|
tempCredentials: newCredentials.copyWith(
|
|
serverName: serverResponse.body?.serverName,
|
|
serverId: serverResponse.body?.id,
|
|
),
|
|
accounts: publicUsers,
|
|
hasQuickConnect: quickConnectStatus,
|
|
serverMessage: branding.body?.loginDisclaimer,
|
|
),
|
|
loading: false,
|
|
);
|
|
} catch (e) {
|
|
state = state.copyWith(
|
|
errorMessage: context?.localized.invalidUrl,
|
|
loading: false,
|
|
);
|
|
if (context != null) {
|
|
fladderSnackbar(context!, title: context!.localized.unableToConnectHost);
|
|
}
|
|
}
|
|
}
|
|
|
|
String? _parseUrl(String url) {
|
|
if (url.isEmpty) {
|
|
return null;
|
|
}
|
|
if (!Uri.parse(url).isAbsolute) {
|
|
return context?.localized.invalidUrl;
|
|
}
|
|
|
|
if (!url.startsWith('https://') && !url.startsWith('http://')) {
|
|
return context?.localized.invalidUrlDesc;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Future<Response<List<AccountModel>>?> getPublicUsers() async {
|
|
try {
|
|
state = state.copyWith(loading: true);
|
|
final credentials = state.serverLoginModel?.tempCredentials;
|
|
if (credentials == null) return null;
|
|
var response = await api.usersPublicGet(credentials);
|
|
if (response.isSuccessful && response.body != null) {
|
|
var models = response.body ?? [];
|
|
return response.copyWith(body: models.toList());
|
|
}
|
|
state = state.copyWith(
|
|
serverLoginModel: state.serverLoginModel?.copyWith(
|
|
accounts: response.body ?? [],
|
|
),
|
|
);
|
|
return response.copyWith(body: []);
|
|
} catch (e) {
|
|
return null;
|
|
} finally {
|
|
state = state.copyWith(loading: false);
|
|
}
|
|
}
|
|
|
|
Future<Response<AccountModel>?> authenticateUsingSecret(String secret) async {
|
|
clearAllProviders();
|
|
var response = await api.quickConnectAuthenticate(secret);
|
|
return _createAccountModel(response);
|
|
}
|
|
|
|
Future<Response<AccountModel>?> authenticateByName(String userName, String password) async {
|
|
clearAllProviders();
|
|
var response = await api.usersAuthenticateByNamePost(userName: userName, password: password);
|
|
return _createAccountModel(response);
|
|
}
|
|
|
|
Future<Response<AccountModel>?> _createAccountModel(Response<AuthenticationResult> response) async {
|
|
CredentialsModel? credentials = state.serverLoginModel?.tempCredentials;
|
|
if (credentials == null) return null;
|
|
if (response.isSuccessful && (response.body?.accessToken?.isNotEmpty ?? false)) {
|
|
var serverResponse = await api.systemInfoPublicGet();
|
|
credentials = credentials.copyWith(
|
|
token: response.body?.accessToken ?? "",
|
|
serverId: response.body?.serverId,
|
|
serverName: serverResponse.body?.serverName ?? "",
|
|
);
|
|
var imageUrl = ref.read(imageUtilityProvider).getUserImageUrl(response.body?.user?.id ?? "");
|
|
AccountModel newUser = AccountModel(
|
|
name: response.body?.user?.name ?? "",
|
|
id: response.body?.user?.id ?? "",
|
|
avatar: imageUrl,
|
|
credentials: credentials,
|
|
lastUsed: DateTime.now(),
|
|
);
|
|
ref.read(sharedUtilityProvider).addAccount(newUser);
|
|
ref.read(userProvider.notifier).userState = newUser;
|
|
final currentAccounts = ref.read(authProvider.notifier).getSavedAccounts();
|
|
|
|
state = state.copyWith(
|
|
serverLoginModel: null,
|
|
accounts: currentAccounts,
|
|
);
|
|
|
|
return Response(response.base, newUser);
|
|
}
|
|
return Response(response.base, null);
|
|
}
|
|
|
|
Future<Response?> logOutUser() async {
|
|
final currentUser = ref.read(userProvider);
|
|
state = state.copyWith(serverLoginModel: null);
|
|
await ref.read(sharedUtilityProvider).removeAccount(currentUser);
|
|
clearAllProviders();
|
|
return null;
|
|
}
|
|
|
|
Future<void> switchUser() async {
|
|
clearAllProviders();
|
|
}
|
|
|
|
void clearAllProviders() {
|
|
ref.read(dashboardProvider.notifier).clear();
|
|
ref.read(viewsProvider.notifier).clear();
|
|
ref.read(favouritesProvider.notifier).clear();
|
|
ref.read(userProvider.notifier).clear();
|
|
ref.read(libraryScreenProvider.notifier).clear();
|
|
}
|
|
|
|
Future<void> setServer(String server) async {
|
|
final url = (state.hasBaseUrl ? FladderConfig.baseUrl : server);
|
|
if (url == null || server.isEmpty) return;
|
|
final isUrlValid = _parseUrl(url);
|
|
state = state.copyWith(
|
|
errorMessage: isUrlValid,
|
|
serverLoginModel: null,
|
|
);
|
|
if (isUrlValid == null) {
|
|
await _fetchServerInfo(url);
|
|
}
|
|
}
|
|
|
|
List<AccountModel> getSavedAccounts() {
|
|
state = state.copyWith(accounts: ref.read(sharedUtilityProvider).getAccounts());
|
|
return state.accounts;
|
|
}
|
|
|
|
void reOrderUsers(int oldIndex, int newIndex) {
|
|
final accounts = state.accounts;
|
|
final original = accounts.elementAt(oldIndex);
|
|
accounts.removeAt(oldIndex);
|
|
accounts.insert(newIndex, original);
|
|
ref.read(sharedUtilityProvider).saveAccounts(accounts);
|
|
}
|
|
|
|
void addNewUser() {
|
|
state = state.copyWith(
|
|
screen: LoginScreenType.login,
|
|
);
|
|
}
|
|
|
|
void goUserSelect() {
|
|
state = state.copyWith(
|
|
serverLoginModel: state.hasBaseUrl ? state.serverLoginModel : null,
|
|
screen: LoginScreenType.users,
|
|
);
|
|
}
|
|
|
|
void tryParseUrl(String server) {
|
|
if (server.isNotEmpty && state.errorMessage != null) {
|
|
final url = server;
|
|
final isUrlValid = _parseUrl(url);
|
|
state = state.copyWith(
|
|
errorMessage: isUrlValid,
|
|
);
|
|
}
|
|
}
|
|
}
|