/* * Copyright (c) 2024-2026 Fabian Freund. * * This file is part of WebLibre * (see https://weblibre.eu). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:weblibre/features/settings/presentation/widgets/settings_detail.dart'; import 'package:weblibre/features/user/data/models/engine_settings.dart'; import 'package:weblibre/features/user/domain/repositories/engine_settings.dart'; import 'package:weblibre/utils/exit_app.dart'; import 'package:weblibre/utils/form_validators.dart'; const _defaultServerUrl = 'https://services.addons.mozilla.org'; class AddonCollectionScreen extends HookConsumerWidget { const AddonCollectionScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final formKey = useMemoized(() => GlobalKey()); final addonCollectionSetting = ref.watch( engineSettingsWithDefaultsProvider.select( (value) => value.addonCollection, ), ); final serverURLController = useTextEditingController( text: addonCollectionSetting?.serverURL ?? _defaultServerUrl, keys: [addonCollectionSetting], ); final collectionUserController = useTextEditingController( text: addonCollectionSetting?.collectionUser, keys: [addonCollectionSetting], ); final collectionNameController = useTextEditingController( text: addonCollectionSetting?.collectionName, keys: [addonCollectionSetting], ); return SettingsCustomScrollScaffold( title: 'Custom Extension Collection', actions: [ if (addonCollectionSetting != null) IconButton( onPressed: () async { await ref .read(engineSettingsRepositoryProvider.notifier) .updateSettings( (currentSettings) => currentSettings.copyWith.addonCollection(null), ); await exitApp(ref.container); }, icon: const Icon(Icons.delete), ), ], slivers: [ SliverPadding( padding: const EdgeInsets.fromLTRB(16, 24, 16, 20), sliver: SliverToBoxAdapter( child: Form( key: formKey, child: SettingsSectionList( sections: [ SettingsSectionDefinition( title: 'Collection Source', entries: [ SettingsEntryDefinition( title: 'Collection configuration', subtitle: 'Mozilla server, collection owner, and collection name', keywords: const ['addons', 'collection'], child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ TextFormField( controller: serverURLController, decoration: const InputDecoration( label: Text('Server URL'), hintText: _defaultServerUrl, floatingLabelBehavior: FloatingLabelBehavior.always, ), keyboardType: TextInputType.url, validator: (value) { return validateUrl( value, onlyHttpProtocol: true, eagerParsing: false, ); }, ), const SizedBox(height: 8), TextFormField( controller: collectionUserController, decoration: const InputDecoration( label: Text('Collection User'), floatingLabelBehavior: FloatingLabelBehavior.always, ), validator: validateRequired, ), const SizedBox(height: 8), TextFormField( controller: collectionNameController, decoration: const InputDecoration( label: Text('Collection Name'), floatingLabelBehavior: FloatingLabelBehavior.always, ), validator: validateRequired, ), ], ), ), ), ], ), SettingsSectionDefinition( title: 'Actions', entries: [ SettingsEntryDefinition( title: 'Save & Restart Browser', subtitle: 'Apply the custom collection and restart the browser', keywords: const ['restart'], child: Padding( padding: const EdgeInsets.all(16.0), child: SizedBox( width: double.infinity, child: FilledButton( onPressed: () async { if (formKey.currentState?.validate() == true) { await ref .read( engineSettingsRepositoryProvider .notifier, ) .updateSettings( (currentSettings) => currentSettings .copyWith .addonCollection( AddonCollection( serverURL: serverURLController.text, collectionUser: collectionUserController .text, collectionName: collectionNameController .text, ), ), ); await exitApp(ref.container); } }, child: const Text('Save & Restart Browser'), ), ), ), ), ], ), ], query: '', ), ), ), ), ], ); } }