Browse Source

Merge pull request #742 from nextcloud/refactor/types

Refactor/types
pull/743/head
Nikolas Rimikis 1 year ago committed by GitHub
parent
commit
abbb3d764a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      packages/app/integration_test/screenshot_test.dart
  2. 2
      packages/app/lib/main.dart
  3. 2
      packages/dynamite/dynamite/lib/src/builder/client.dart
  4. 5
      packages/neon/neon/lib/blocs.dart
  5. 2
      packages/neon/neon/lib/neon.dart
  6. 14
      packages/neon/neon/lib/src/app.dart
  7. 6
      packages/neon/neon/lib/src/bloc/bloc.dart
  8. 3
      packages/neon/neon/lib/src/blocs/accounts.dart
  9. 16
      packages/neon/neon/lib/src/blocs/apps.dart
  10. 8
      packages/neon/neon/lib/src/blocs/capabilities.dart
  11. 10
      packages/neon/neon/lib/src/blocs/first_launch.dart
  12. 6
      packages/neon/neon/lib/src/blocs/login_check_account.dart
  13. 6
      packages/neon/neon/lib/src/blocs/login_check_server_status.dart
  14. 10
      packages/neon/neon/lib/src/blocs/login_flow.dart
  15. 10
      packages/neon/neon/lib/src/blocs/next_push.dart
  16. 14
      packages/neon/neon/lib/src/blocs/push_notifications.dart
  17. 6
      packages/neon/neon/lib/src/blocs/timer.dart
  18. 10
      packages/neon/neon/lib/src/blocs/unified_search.dart
  19. 8
      packages/neon/neon/lib/src/blocs/user_details.dart
  20. 10
      packages/neon/neon/lib/src/blocs/user_statuses.dart
  21. 2
      packages/neon/neon/lib/src/models/app_implementation.dart
  22. 2
      packages/neon/neon/lib/src/pages/account_settings.dart
  23. 8
      packages/neon/neon/lib/src/pages/home.dart
  24. 2
      packages/neon/neon/lib/src/pages/login.dart
  25. 2
      packages/neon/neon/lib/src/pages/login_check_account.dart
  26. 2
      packages/neon/neon/lib/src/pages/login_check_server_status.dart
  27. 2
      packages/neon/neon/lib/src/pages/login_flow.dart
  28. 2
      packages/neon/neon/lib/src/pages/login_qrcode.dart
  29. 2
      packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart
  30. 6
      packages/neon/neon/lib/src/pages/route_not_found.dart
  31. 3
      packages/neon/neon/lib/src/pages/settings.dart
  32. 4
      packages/neon/neon/lib/src/platform/platform.dart
  33. 2
      packages/neon/neon/lib/src/router.dart
  34. 4
      packages/neon/neon/lib/src/settings/models/options_collection.dart
  35. 18
      packages/neon/neon/lib/src/settings/models/storage.dart
  36. 2
      packages/neon/neon/lib/src/settings/utils/settings_export_helper.dart
  37. 2
      packages/neon/neon/lib/src/settings/widgets/account_settings_tile.dart
  38. 2
      packages/neon/neon/lib/src/settings/widgets/custom_settings_tile.dart
  39. 2
      packages/neon/neon/lib/src/settings/widgets/settings_tile.dart
  40. 3
      packages/neon/neon/lib/src/utils/account_options.dart
  41. 9
      packages/neon/neon/lib/src/utils/global_options.dart
  42. 2
      packages/neon/neon/lib/src/utils/global_popups.dart
  43. 2
      packages/neon/neon/lib/src/utils/push_utils.dart
  44. 39
      packages/neon/neon/lib/src/utils/request_manager.dart
  45. 6
      packages/neon/neon/lib/src/utils/stream_listenable.dart
  46. 1
      packages/neon/neon/lib/src/utils/user_agent.dart
  47. 2
      packages/neon/neon/lib/src/widgets/account_tile.dart
  48. 4
      packages/neon/neon/lib/src/widgets/app_bar.dart
  49. 42
      packages/neon/neon/lib/src/widgets/cached_image.dart
  50. 2
      packages/neon/neon/lib/src/widgets/exception.dart
  51. 2
      packages/neon/neon/lib/src/widgets/list_view.dart
  52. 4
      packages/neon/neon/test/option_test.dart
  53. 4
      packages/neon/neon/test/options_collection_test.dart
  54. 2
      packages/neon/neon/test/settings_export_test.dart
  55. 6
      packages/neon/neon_files/lib/blocs/browser.dart
  56. 8
      packages/neon/neon_files/lib/blocs/files.dart
  57. 4
      packages/neon/neon_files/lib/dialogs/choose_create.dart
  58. 2
      packages/neon/neon_files/lib/neon_files.dart
  59. 2
      packages/neon/neon_files/lib/options.dart
  60. 4
      packages/neon/neon_files/lib/utils/task.dart
  61. 13
      packages/neon/neon_files/lib/widgets/file_preview.dart
  62. 8
      packages/neon/neon_news/lib/blocs/article.dart
  63. 8
      packages/neon/neon_news/lib/blocs/articles.dart
  64. 8
      packages/neon/neon_news/lib/blocs/news.dart
  65. 3
      packages/neon/neon_news/lib/neon_news.dart
  66. 2
      packages/neon/neon_news/lib/pages/article.dart
  67. 2
      packages/neon/neon_news/lib/widgets/folder_select.dart
  68. 6
      packages/neon/neon_notes/lib/blocs/note.dart
  69. 8
      packages/neon/neon_notes/lib/blocs/notes.dart
  70. 2
      packages/neon/neon_notes/lib/neon_notes.dart
  71. 2
      packages/neon/neon_notes/lib/widgets/category_select.dart
  72. 2
      packages/neon/neon_notifications/lib/blocs/notifications.dart
  73. 2
      packages/neon/neon_notifications/lib/neon_notifications.dart
  74. 1
      packages/neon/neon_notifications/lib/pages/main.dart
  75. 1
      packages/neon_lints/lib/src/base.yaml
  76. 1
      packages/neon_lints/lint_maker.yaml
  77. 22
      packages/nextcloud/lib/src/api/news.openapi.dart
  78. 2
      packages/nextcloud/lib/src/webdav/client.dart
  79. 2
      packages/nextcloud/test/helper.dart
  80. 2
      packages/nextcloud/test/notifications_test.dart
  81. 4
      packages/nextcloud/test/settings_test.dart
  82. 2
      packages/sort_box/lib/sort_box.dart

10
packages/app/integration_test/screenshot_test.dart

@ -14,7 +14,7 @@ import 'package:neon/settings.dart';
import 'package:neon_files/widgets/actions.dart'; import 'package:neon_files/widgets/actions.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
Future runTestApp( Future<void> runTestApp(
final WidgetTester tester, final WidgetTester tester,
final IntegrationTestWidgetsFlutterBinding binding, { final IntegrationTestWidgetsFlutterBinding binding, {
final Account? account, final Account? account,
@ -30,18 +30,18 @@ Future runTestApp(
await tester.pumpAndSettle(); await tester.pumpAndSettle();
} }
Future openDrawer(final WidgetTester tester) async { Future<void> openDrawer(final WidgetTester tester) async {
await tester.tap(find.byTooltip('Open navigation menu')); await tester.tap(find.byTooltip('Open navigation menu'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
} }
Future switchPage(final WidgetTester tester, final String name) async { Future<void> switchPage(final WidgetTester tester, final String name) async {
await openDrawer(tester); await openDrawer(tester);
await tester.tap(find.text(name).last); await tester.tap(find.text(name).last);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
} }
Future prepareScreenshot(final WidgetTester tester, final IntegrationTestWidgetsFlutterBinding binding) async { Future<void> prepareScreenshot(final WidgetTester tester, final IntegrationTestWidgetsFlutterBinding binding) async {
await binding.convertFlutterSurfaceToImage(); await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
} }
@ -63,7 +63,7 @@ Future<Account> getAccount(final String username) async {
); );
} }
Future main() async { Future<void> main() async {
// The screenshots are pretty annoying on Android. See https://github.com/flutter/flutter/issues/92381 // The screenshots are pretty annoying on Android. See https://github.com/flutter/flutter/issues/92381
assert(Platform.isAndroid, 'Screenshots need to be taken on Android'); assert(Platform.isAndroid, 'Screenshots need to be taken on Android');

2
packages/app/lib/main.dart

@ -2,7 +2,7 @@ import 'package:app/apps.dart';
import 'package:app/branding.dart'; import 'package:app/branding.dart';
import 'package:neon/neon.dart'; import 'package:neon/neon.dart';
Future main() async { Future<void> main() async {
await runNeon( await runNeon(
appImplementations: appImplementations, appImplementations: appImplementations,
theme: neonTheme, theme: neonTheme,

2
packages/dynamite/dynamite/lib/src/builder/client.dart

@ -604,7 +604,7 @@ final _response = await ${isRootClient ? 'this' : '_rootClient'}.doRequest(
b.returns = refer('Future<$dataType>'); b.returns = refer('Future<$dataType>');
code.write('return $dataValue;'); code.write('return $dataValue;');
} else { } else {
b.returns = refer('Future'); b.returns = refer('Future<void>');
code.write('return;'); code.write('return;');
} }

5
packages/neon/neon/lib/blocs.dart

@ -1,5 +1,6 @@
export 'package:neon/src/bloc/bloc.dart'; export 'package:neon/src/bloc/bloc.dart';
export 'package:neon/src/bloc/result.dart'; export 'package:neon/src/bloc/result.dart';
export 'package:neon/src/bloc/result_builder.dart'; export 'package:neon/src/bloc/result_builder.dart';
export 'package:neon/src/blocs/accounts.dart'; // TODO: Remove access to the AccountsBloc. Apps should not need to access this // TODO: Remove access to the AccountsBloc. Apps should not need to access this
export 'package:neon/src/blocs/timer.dart'; export 'package:neon/src/blocs/accounts.dart' show AccountsBloc;
export 'package:neon/src/blocs/timer.dart' hide TimerBlocEvents, TimerBlocStates;

2
packages/neon/neon/lib/neon.dart

@ -18,7 +18,7 @@ import 'package:neon/src/utils/user_agent.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
Future runNeon({ Future<void> runNeon({
required final Iterable<AppImplementation> appImplementations, required final Iterable<AppImplementation> appImplementations,
required final NeonTheme theme, required final NeonTheme theme,
@visibleForTesting final WidgetsBinding? bindingOverride, @visibleForTesting final WidgetsBinding? bindingOverride,

14
packages/neon/neon/lib/src/app.dart

@ -5,6 +5,7 @@ import 'dart:io';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/bloc/result_builder.dart';
import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/accounts.dart';
@ -27,6 +28,7 @@ import 'package:quick_actions/quick_actions.dart';
import 'package:tray_manager/tray_manager.dart' as tray; import 'package:tray_manager/tray_manager.dart' as tray;
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
@internal
class NeonApp extends StatefulWidget { class NeonApp extends StatefulWidget {
const NeonApp({ const NeonApp({
required this.neonTheme, required this.neonTheme,
@ -196,7 +198,7 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
} }
@override @override
Future onWindowClose() async { Future<void> onWindowClose() async {
if (_globalOptions.startupMinimizeInsteadOfExit.value) { if (_globalOptions.startupMinimizeInsteadOfExit.value) {
await _saveAndMinimizeWindow(); await _saveAndMinimizeWindow();
} else { } else {
@ -205,11 +207,11 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
} }
@override @override
Future onWindowMinimize() async { Future<void> onWindowMinimize() async {
await _saveAndMinimizeWindow(); await _saveAndMinimizeWindow();
} }
Future _handleShortcut(final String shortcutType) async { Future<void> _handleShortcut(final String shortcutType) async {
if (shortcutType == 'show_hide') { if (shortcutType == 'show_hide') {
if (NeonPlatform.instance.canUseWindowManager) { if (NeonPlatform.instance.canUseWindowManager) {
if (await windowManager.isVisible()) { if (await windowManager.isVisible()) {
@ -231,13 +233,13 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
} }
} }
Future _openAppFromExternal(final Account account, final String id) async { Future<void> _openAppFromExternal(final Account account, final String id) async {
await _accountsBloc.getAppsBlocFor(account).setActiveApp(id); await _accountsBloc.getAppsBlocFor(account).setActiveApp(id);
_navigatorKey.currentState!.popUntil((final route) => route.settings.name == 'home'); _navigatorKey.currentState!.popUntil((final route) => route.settings.name == 'home');
await _showAndRestoreWindow(); await _showAndRestoreWindow();
} }
Future _saveAndMinimizeWindow() async { Future<void> _saveAndMinimizeWindow() async {
_lastBounds = await windowManager.getBounds(); _lastBounds = await windowManager.getBounds();
if (_globalOptions.systemTrayEnabled.value && _globalOptions.systemTrayHideToTrayWhenMinimized.value) { if (_globalOptions.systemTrayEnabled.value && _globalOptions.systemTrayHideToTrayWhenMinimized.value) {
await windowManager.hide(); await windowManager.hide();
@ -246,7 +248,7 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
} }
} }
Future _showAndRestoreWindow() async { Future<void> _showAndRestoreWindow() async {
if (!NeonPlatform.instance.canUseWindowManager) { if (!NeonPlatform.instance.canUseWindowManager) {
return; return;
} }

6
packages/neon/neon/lib/src/bloc/bloc.dart

@ -17,7 +17,7 @@ abstract class InteractiveBloc extends Bloc {
final _errorsStreamController = StreamController<Object>(); final _errorsStreamController = StreamController<Object>();
late Stream<Object> errors = _errorsStreamController.stream.asBroadcastStream(); late Stream<Object> errors = _errorsStreamController.stream.asBroadcastStream();
Future refresh(); Future<void> refresh();
void addError(final Object error) { void addError(final Object error) {
_errorsStreamController.add(error); _errorsStreamController.add(error);
@ -25,9 +25,9 @@ abstract class InteractiveBloc extends Bloc {
// ignore: avoid_void_async // ignore: avoid_void_async
void wrapAction( void wrapAction(
final Future Function() call, { final AsyncCallback call, {
final bool disableTimeout = false, final bool disableTimeout = false,
final Future Function()? refresh, final AsyncCallback? refresh,
}) async { }) async {
try { try {
if (disableTimeout) { if (disableTimeout) {

3
packages/neon/neon/lib/src/blocs/accounts.dart

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/blocs/apps.dart'; import 'package:neon/src/blocs/apps.dart';
import 'package:neon/src/blocs/capabilities.dart'; import 'package:neon/src/blocs/capabilities.dart';
@ -17,6 +18,7 @@ import 'package:rxdart/rxdart.dart';
const _keyAccounts = 'accounts'; const _keyAccounts = 'accounts';
@internal
abstract interface class AccountsBlocEvents { abstract interface class AccountsBlocEvents {
/// Logs in the given [account]. /// Logs in the given [account].
/// ///
@ -40,6 +42,7 @@ abstract interface class AccountsBlocEvents {
void setActiveAccount(final Account account); void setActiveAccount(final Account account);
} }
@internal
abstract interface class AccountsBlocStates { abstract interface class AccountsBlocStates {
/// All registered accounts. /// All registered accounts.
/// ///

16
packages/neon/neon/lib/src/blocs/apps.dart

@ -16,7 +16,8 @@ import 'package:nextcloud/nextcloud.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
abstract class AppsBlocEvents { @internal
abstract interface class AppsBlocEvents {
/// Sets the active app using the [appID]. /// Sets the active app using the [appID].
/// ///
/// If the app is already the active app nothing will happen. /// If the app is already the active app nothing will happen.
@ -24,7 +25,8 @@ abstract class AppsBlocEvents {
void setActiveApp(final String appID, {final bool skipAlreadySet = false}); void setActiveApp(final String appID, {final bool skipAlreadySet = false});
} }
abstract class AppsBlocStates { @internal
abstract interface class AppsBlocStates {
BehaviorSubject<Result<List<CoreNavigationEntry>>> get apps; BehaviorSubject<Result<List<CoreNavigationEntry>>> get apps;
BehaviorSubject<Result<Iterable<AppImplementation>>> get appImplementations; BehaviorSubject<Result<Iterable<AppImplementation>>> get appImplementations;
@ -33,7 +35,7 @@ abstract class AppsBlocStates {
BehaviorSubject<AppImplementation> get activeApp; BehaviorSubject<AppImplementation> get activeApp;
BehaviorSubject get openNotifications; BehaviorSubject<void> get openNotifications;
BehaviorSubject<Iterable<(String, Object?)>?> get appVersions; BehaviorSubject<Iterable<(String, Object?)>?> get appVersions;
} }
@ -182,13 +184,13 @@ class AppsBloc extends InteractiveBloc implements AppsBlocEvents, AppsBlocStates
BehaviorSubject<Result<NotificationsAppInterface?>>(); BehaviorSubject<Result<NotificationsAppInterface?>>();
@override @override
BehaviorSubject openNotifications = BehaviorSubject(); BehaviorSubject<void> openNotifications = BehaviorSubject();
@override @override
BehaviorSubject<List<(String, Object?)>?> appVersions = BehaviorSubject(); BehaviorSubject<List<(String, Object?)>?> appVersions = BehaviorSubject();
@override @override
Future refresh() async { Future<void> refresh() async {
await RequestManager.instance await RequestManager.instance
.wrapNextcloud<List<CoreNavigationEntry>, CoreNavigationGetAppsNavigationResponseApplicationJson>( .wrapNextcloud<List<CoreNavigationEntry>, CoreNavigationGetAppsNavigationResponseApplicationJson>(
_account.id, _account.id,
@ -200,7 +202,7 @@ class AppsBloc extends InteractiveBloc implements AppsBlocEvents, AppsBlocStates
} }
@override @override
Future setActiveApp(final String appID, {final bool skipAlreadySet = false}) async { Future<void> setActiveApp(final String appID, {final bool skipAlreadySet = false}) async {
if (appID == AppIDs.notifications) { if (appID == AppIDs.notifications) {
openNotifications.add(null); openNotifications.add(null);
return; return;
@ -220,6 +222,6 @@ class AppsBloc extends InteractiveBloc implements AppsBlocEvents, AppsBlocStates
T getAppBloc<T extends Bloc>(final AppImplementation<T, dynamic> appImplementation) => T getAppBloc<T extends Bloc>(final AppImplementation<T, dynamic> appImplementation) =>
appImplementation.getBloc(_account); appImplementation.getBloc(_account);
List<Provider> get appBlocProviders => List<Provider<Bloc>> get appBlocProviders =>
_allAppImplementations.map((final appImplementation) => appImplementation.blocProvider).toList(); _allAppImplementations.map((final appImplementation) => appImplementation.blocProvider).toList();
} }

8
packages/neon/neon/lib/src/blocs/capabilities.dart

@ -8,9 +8,11 @@ import 'package:neon/src/utils/request_manager.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
abstract class CapabilitiesBlocEvents {} @internal
abstract interface class CapabilitiesBlocEvents {}
abstract class CapabilitiesBlocStates { @internal
abstract interface class CapabilitiesBlocStates {
BehaviorSubject<Result<CoreOcsGetCapabilitiesResponseApplicationJson_Ocs_Data>> get capabilities; BehaviorSubject<Result<CoreOcsGetCapabilitiesResponseApplicationJson_Ocs_Data>> get capabilities;
} }
@ -35,7 +37,7 @@ class CapabilitiesBloc extends InteractiveBloc implements CapabilitiesBlocEvents
BehaviorSubject<Result<CoreOcsGetCapabilitiesResponseApplicationJson_Ocs_Data>>(); BehaviorSubject<Result<CoreOcsGetCapabilitiesResponseApplicationJson_Ocs_Data>>();
@override @override
Future refresh() async { Future<void> refresh() async {
await RequestManager.instance.wrapNextcloud<CoreOcsGetCapabilitiesResponseApplicationJson_Ocs_Data, await RequestManager.instance.wrapNextcloud<CoreOcsGetCapabilitiesResponseApplicationJson_Ocs_Data,
CoreOcsGetCapabilitiesResponseApplicationJson>( CoreOcsGetCapabilitiesResponseApplicationJson>(
_account.id, _account.id,

10
packages/neon/neon/lib/src/blocs/first_launch.dart

@ -5,10 +5,12 @@ import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/settings/models/storage.dart'; import 'package:neon/src/settings/models/storage.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
abstract class FirstLaunchBlocEvents {} @internal
abstract interface class FirstLaunchBlocEvents {}
abstract class FirstLaunchBlocStates { @internal
BehaviorSubject get onFirstLaunch; abstract interface class FirstLaunchBlocStates {
BehaviorSubject<void> get onFirstLaunch;
} }
@immutable @immutable
@ -31,5 +33,5 @@ class FirstLaunchBloc extends Bloc implements FirstLaunchBlocEvents, FirstLaunch
} }
@override @override
final BehaviorSubject onFirstLaunch = BehaviorSubject(); final BehaviorSubject<void> onFirstLaunch = BehaviorSubject();
} }

6
packages/neon/neon/lib/src/blocs/login_check_account.dart

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/bloc/result.dart'; import 'package:neon/src/bloc/result.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
@ -8,13 +9,16 @@ import 'package:neon/src/utils/user_agent.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
@internal
abstract interface class LoginCheckAccountBlocEvents {} abstract interface class LoginCheckAccountBlocEvents {}
@internal
abstract interface class LoginCheckAccountBlocStates { abstract interface class LoginCheckAccountBlocStates {
/// Contains the account for the user /// Contains the account for the user
BehaviorSubject<Result<Account>> get state; BehaviorSubject<Result<Account>> get state;
} }
@internal
class LoginCheckAccountBloc extends InteractiveBloc class LoginCheckAccountBloc extends InteractiveBloc
implements LoginCheckAccountBlocEvents, LoginCheckAccountBlocStates { implements LoginCheckAccountBlocEvents, LoginCheckAccountBlocStates {
LoginCheckAccountBloc( LoginCheckAccountBloc(
@ -40,7 +44,7 @@ class LoginCheckAccountBloc extends InteractiveBloc
BehaviorSubject<Result<Account>> state = BehaviorSubject(); BehaviorSubject<Result<Account>> state = BehaviorSubject();
@override @override
Future refresh() async { Future<void> refresh() async {
state.add(Result.loading()); state.add(Result.loading());
try { try {

6
packages/neon/neon/lib/src/blocs/login_check_server_status.dart

@ -1,19 +1,23 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/bloc/result.dart'; import 'package:neon/src/bloc/result.dart';
import 'package:neon/src/utils/user_agent.dart'; import 'package:neon/src/utils/user_agent.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
@internal
abstract interface class LoginCheckServerStatusBlocEvents {} abstract interface class LoginCheckServerStatusBlocEvents {}
@internal
abstract interface class LoginCheckServerStatusBlocStates { abstract interface class LoginCheckServerStatusBlocStates {
/// Contains the current server connection state /// Contains the current server connection state
BehaviorSubject<Result<CoreStatus>> get state; BehaviorSubject<Result<CoreStatus>> get state;
} }
@internal
class LoginCheckServerStatusBloc extends InteractiveBloc class LoginCheckServerStatusBloc extends InteractiveBloc
implements LoginCheckServerStatusBlocEvents, LoginCheckServerStatusBlocStates { implements LoginCheckServerStatusBlocEvents, LoginCheckServerStatusBlocStates {
LoginCheckServerStatusBloc(this.serverURL) { LoginCheckServerStatusBloc(this.serverURL) {
@ -33,7 +37,7 @@ class LoginCheckServerStatusBloc extends InteractiveBloc
BehaviorSubject<Result<CoreStatus>> state = BehaviorSubject(); BehaviorSubject<Result<CoreStatus>> state = BehaviorSubject();
@override @override
Future refresh() async { Future<void> refresh() async {
state.add(Result.loading()); state.add(Result.loading());
try { try {

10
packages/neon/neon/lib/src/blocs/login_flow.dart

@ -1,20 +1,24 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/bloc/result.dart'; import 'package:neon/src/bloc/result.dart';
import 'package:neon/src/utils/user_agent.dart'; import 'package:neon/src/utils/user_agent.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
abstract class LoginFlowBlocEvents {} @internal
abstract interface class LoginFlowBlocEvents {}
abstract class LoginFlowBlocStates { @internal
abstract interface class LoginFlowBlocStates {
BehaviorSubject<Result<CoreLoginFlowV2>> get init; BehaviorSubject<Result<CoreLoginFlowV2>> get init;
Stream<CoreLoginFlowV2Credentials> get result; Stream<CoreLoginFlowV2Credentials> get result;
} }
@internal
class LoginFlowBloc extends InteractiveBloc implements LoginFlowBlocEvents, LoginFlowBlocStates { class LoginFlowBloc extends InteractiveBloc implements LoginFlowBlocEvents, LoginFlowBlocStates {
LoginFlowBloc(this.serverURL) { LoginFlowBloc(this.serverURL) {
unawaited(refresh()); unawaited(refresh());
@ -45,7 +49,7 @@ class LoginFlowBloc extends InteractiveBloc implements LoginFlowBlocEvents, Logi
late Stream<CoreLoginFlowV2Credentials> result = _resultController.stream.asBroadcastStream(); late Stream<CoreLoginFlowV2Credentials> result = _resultController.stream.asBroadcastStream();
@override @override
Future refresh() async { Future<void> refresh() async {
try { try {
init.add(Result.loading()); init.add(Result.loading());

10
packages/neon/neon/lib/src/blocs/next_push.dart

@ -8,10 +8,12 @@ import 'package:neon/src/models/account.dart';
import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/global_options.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
abstract class NextPushBlocEvents {} @internal
abstract interface class NextPushBlocEvents {}
abstract class NextPushBlocStates { @internal
BehaviorSubject get onNextPushSupported; abstract interface class NextPushBlocStates {
BehaviorSubject<void> get onNextPushSupported;
} }
@internal @internal
@ -78,5 +80,5 @@ class NextPushBloc extends Bloc implements NextPushBlocEvents, NextPushBlocState
} }
@override @override
BehaviorSubject onNextPushSupported = BehaviorSubject(); BehaviorSubject<void> onNextPushSupported = BehaviorSubject();
} }

14
packages/neon/neon/lib/src/blocs/push_notifications.dart

@ -14,9 +14,11 @@ import 'package:neon/src/utils/push_utils.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:unifiedpush/unifiedpush.dart'; import 'package:unifiedpush/unifiedpush.dart';
abstract class PushNotificationsBlocEvents {} @internal
abstract interface class PushNotificationsBlocEvents {}
abstract class PushNotificationsBlocStates { @internal
abstract interface class PushNotificationsBlocStates {
Stream<PushNotification> get notifications; Stream<PushNotification> get notifications;
} }
@ -40,7 +42,7 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents,
final GlobalOptions _globalOptions; final GlobalOptions _globalOptions;
final _notificationsController = StreamController<PushNotification>(); final _notificationsController = StreamController<PushNotification>();
StreamSubscription? _accountsListener; StreamSubscription<List<Account>>? _accountsListener;
@override @override
void dispose() { void dispose() {
@ -66,7 +68,7 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents,
} }
} }
Future _setupUnifiedPush() async { Future<void> _setupUnifiedPush() async {
// We just use a single RSA keypair for all accounts // We just use a single RSA keypair for all accounts
final keypair = await PushUtils.loadRSAKeypair(); final keypair = await PushUtils.loadRSAKeypair();
@ -118,7 +120,7 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents,
} }
} }
Future _unregisterUnifiedPushInstances(final List<Account> accounts) async { Future<void> _unregisterUnifiedPushInstances(final List<Account> accounts) async {
for (final account in accounts) { for (final account in accounts) {
try { try {
await account.client.notifications.push.removeDevice(); await account.client.notifications.push.removeDevice();
@ -130,7 +132,7 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents,
} }
} }
Future _registerUnifiedPushInstances(final List<Account> accounts) async { Future<void> _registerUnifiedPushInstances(final List<Account> accounts) async {
// Notifications will only work on accounts with app password // Notifications will only work on accounts with app password
for (final account in accounts.where((final a) => a.password != null)) { for (final account in accounts.where((final a) => a.password != null)) {
await UnifiedPush.registerApp(account.id); await UnifiedPush.registerApp(account.id);

6
packages/neon/neon/lib/src/blocs/timer.dart

@ -4,7 +4,8 @@ import 'dart:ui';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
abstract class TimerBlocEvents { @internal
abstract interface class TimerBlocEvents {
/// Register a [callback] that will be called periodically. /// Register a [callback] that will be called periodically.
/// The time between the executions is defined by the [duration]. /// The time between the executions is defined by the [duration].
NeonTimer registerTimer(final Duration duration, final VoidCallback callback); NeonTimer registerTimer(final Duration duration, final VoidCallback callback);
@ -14,7 +15,8 @@ abstract class TimerBlocEvents {
void unregisterTimer(final NeonTimer timer); void unregisterTimer(final NeonTimer timer);
} }
abstract class TimerBlocStates {} @internal
abstract interface class TimerBlocStates {}
/// Execute callbacks at defined periodic intervals. /// Execute callbacks at defined periodic intervals.
/// Components can register their callbacks and everything with the same periodicity will be executed at the same time. /// Components can register their callbacks and everything with the same periodicity will be executed at the same time.

10
packages/neon/neon/lib/src/blocs/unified_search.dart

@ -10,6 +10,7 @@ import 'package:neon/src/blocs/apps.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
@internal
abstract interface class UnifiedSearchBlocEvents { abstract interface class UnifiedSearchBlocEvents {
void search(final String term); void search(final String term);
@ -18,6 +19,7 @@ abstract interface class UnifiedSearchBlocEvents {
void disable(); void disable();
} }
@internal
abstract interface class UnifiedSearchBlocStates { abstract interface class UnifiedSearchBlocStates {
BehaviorSubject<bool> get enabled; BehaviorSubject<bool> get enabled;
@ -56,12 +58,12 @@ class UnifiedSearchBloc extends InteractiveBloc implements UnifiedSearchBlocEven
} }
@override @override
Future refresh() async { Future<void> refresh() async {
await _search(); await _search();
} }
@override @override
Future search(final String term) async { Future<void> search(final String term) async {
_term = term.trim(); _term = term.trim();
await _search(); await _search();
} }
@ -78,7 +80,7 @@ class UnifiedSearchBloc extends InteractiveBloc implements UnifiedSearchBlocEven
_term = ''; _term = '';
} }
Future _search() async { Future<void> _search() async {
if (_term.isEmpty) { if (_term.isEmpty) {
results.add(Result.success(null)); results.add(Result.success(null));
return; return;
@ -108,7 +110,7 @@ class UnifiedSearchBloc extends InteractiveBloc implements UnifiedSearchBlocEven
} }
} }
Future _searchProvider(final CoreUnifiedSearchProvider provider) async { Future<void> _searchProvider(final CoreUnifiedSearchProvider provider) async {
_updateResults(provider, Result.loading()); _updateResults(provider, Result.loading());
try { try {
final response = await _account.client.core.unifiedSearch.search( final response = await _account.client.core.unifiedSearch.search(

8
packages/neon/neon/lib/src/blocs/user_details.dart

@ -8,9 +8,11 @@ import 'package:neon/src/utils/request_manager.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
abstract class UserDetailsBlocEvents {} @internal
abstract interface class UserDetailsBlocEvents {}
abstract class UserDetailsBlocStates { @internal
abstract interface class UserDetailsBlocStates {
BehaviorSubject<Result<ProvisioningApiUserDetails>> get userDetails; BehaviorSubject<Result<ProvisioningApiUserDetails>> get userDetails;
} }
@ -35,7 +37,7 @@ class UserDetailsBloc extends InteractiveBloc implements UserDetailsBlocEvents,
BehaviorSubject<Result<ProvisioningApiUserDetails>>(); BehaviorSubject<Result<ProvisioningApiUserDetails>>();
@override @override
Future refresh() async { Future<void> refresh() async {
await RequestManager.instance await RequestManager.instance
.wrapNextcloud<ProvisioningApiUserDetails, ProvisioningApiUsersGetCurrentUserResponseApplicationJson>( .wrapNextcloud<ProvisioningApiUserDetails, ProvisioningApiUsersGetCurrentUserResponseApplicationJson>(
_account.id, _account.id,

10
packages/neon/neon/lib/src/blocs/user_statuses.dart

@ -11,11 +11,13 @@ import 'package:nextcloud/nextcloud.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
abstract class UserStatusesBlocEvents { @internal
abstract interface class UserStatusesBlocEvents {
void load(final String username, {final bool force = false}); void load(final String username, {final bool force = false});
} }
abstract class UserStatusesBlocStates { @internal
abstract interface class UserStatusesBlocStates {
BehaviorSubject<Map<String, Result<UserStatusPublicInterface?>>> get statuses; BehaviorSubject<Map<String, Result<UserStatusPublicInterface?>>> get statuses;
} }
@ -43,14 +45,14 @@ class UserStatusesBloc extends InteractiveBloc implements UserStatusesBlocEvents
BehaviorSubject<Map<String, Result<UserStatusPublicInterface?>>>(); BehaviorSubject<Map<String, Result<UserStatusPublicInterface?>>>();
@override @override
Future refresh() async { Future<void> refresh() async {
for (final username in _statuses.keys) { for (final username in _statuses.keys) {
await load(username, force: true); await load(username, force: true);
} }
} }
@override @override
Future load(final String username, {final bool force = false}) async { Future<void> load(final String username, {final bool force = false}) async {
if (!force && _statuses.containsKey(username)) { if (!force && _statuses.containsKey(username)) {
return; return;
} }

2
packages/neon/neon/lib/src/models/app_implementation.dart

@ -18,7 +18,7 @@ abstract class AppImplementation<T extends Bloc, R extends NextcloudAppOptions>
AppImplementation(); AppImplementation();
String get id; String get id;
LocalizationsDelegate get localizationsDelegate; LocalizationsDelegate<Object> get localizationsDelegate;
List<Locale> get supportedLocales; List<Locale> get supportedLocales;
String nameFromLocalization(final AppLocalizations localizations) => localizations.appImplementationName(id); String nameFromLocalization(final AppLocalizations localizations) => localizations.appImplementationName(id);

2
packages/neon/neon/lib/src/pages/account_settings.dart

@ -1,6 +1,7 @@
import 'package:filesize/filesize.dart'; import 'package:filesize/filesize.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/bloc/result_builder.dart';
import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/accounts.dart';
@ -16,6 +17,7 @@ import 'package:neon/src/widgets/exception.dart';
import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
@internal
class AccountSettingsPage extends StatelessWidget { class AccountSettingsPage extends StatelessWidget {
const AccountSettingsPage({ const AccountSettingsPage({
required this.bloc, required this.bloc,

8
packages/neon/neon/lib/src/pages/home.dart

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/bloc/result_builder.dart';
import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/accounts.dart';
@ -16,6 +17,7 @@ import 'package:neon/src/widgets/exception.dart';
import 'package:neon/src/widgets/unified_search_results.dart'; import 'package:neon/src/widgets/unified_search_results.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@internal
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
const HomePage({ const HomePage({
super.key, super.key,
@ -32,7 +34,7 @@ class _HomePageState extends State<HomePage> {
late GlobalOptions _globalOptions; late GlobalOptions _globalOptions;
late AccountsBloc _accountsBloc; late AccountsBloc _accountsBloc;
late AppsBloc _appsBloc; late AppsBloc _appsBloc;
late StreamSubscription _versionCheckSubscription; late StreamSubscription<List<(String, Object?)>?> _versionCheckSubscription;
@override @override
void initState() { void initState() {
@ -76,7 +78,7 @@ class _HomePageState extends State<HomePage> {
super.dispose(); super.dispose();
} }
Future _checkMaintenanceMode() async { Future<void> _checkMaintenanceMode() async {
try { try {
final status = await _account.client.core.getStatus(); final status = await _account.client.core.getStatus();
if (status.maintenance && mounted) { if (status.maintenance && mounted) {
@ -93,7 +95,7 @@ class _HomePageState extends State<HomePage> {
} }
} }
Future _showProblem(final String title) async { Future<void> _showProblem(final String title) async {
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
await showDialog( await showDialog(

2
packages/neon/neon/lib/src/pages/login.dart

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/platform/platform.dart'; import 'package:neon/src/platform/platform.dart';
import 'package:neon/src/router.dart'; import 'package:neon/src/router.dart';
@ -7,6 +8,7 @@ import 'package:neon/src/theme/dialog.dart';
import 'package:neon/src/utils/validators.dart'; import 'package:neon/src/utils/validators.dart';
import 'package:neon/src/widgets/nextcloud_logo.dart'; import 'package:neon/src/widgets/nextcloud_logo.dart';
@internal
class LoginPage extends StatefulWidget { class LoginPage extends StatefulWidget {
const LoginPage({ const LoginPage({
super.key, super.key,

2
packages/neon/neon/lib/src/pages/login_check_account.dart

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/bloc/result.dart'; import 'package:neon/src/bloc/result.dart';
import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/bloc/result_builder.dart';
@ -14,6 +15,7 @@ import 'package:neon/src/widgets/exception.dart';
import 'package:neon/src/widgets/validation_tile.dart'; import 'package:neon/src/widgets/validation_tile.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@internal
class LoginCheckAccountPage extends StatefulWidget { class LoginCheckAccountPage extends StatefulWidget {
const LoginCheckAccountPage({ const LoginCheckAccountPage({
required this.serverURL, required this.serverURL,

2
packages/neon/neon/lib/src/pages/login_check_server_status.dart

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/bloc/result.dart'; import 'package:neon/src/bloc/result.dart';
import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/bloc/result_builder.dart';
@ -9,6 +10,7 @@ import 'package:neon/src/widgets/exception.dart';
import 'package:neon/src/widgets/validation_tile.dart'; import 'package:neon/src/widgets/validation_tile.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
@internal
class LoginCheckServerStatusPage extends StatefulWidget { class LoginCheckServerStatusPage extends StatefulWidget {
const LoginCheckServerStatusPage({ const LoginCheckServerStatusPage({
required this.serverURL, required this.serverURL,

2
packages/neon/neon/lib/src/pages/login_flow.dart

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/bloc/result_builder.dart';
import 'package:neon/src/blocs/login_flow.dart'; import 'package:neon/src/blocs/login_flow.dart';
@ -7,6 +8,7 @@ import 'package:neon/src/widgets/exception.dart';
import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
@internal
class LoginFlowPage extends StatefulWidget { class LoginFlowPage extends StatefulWidget {
const LoginFlowPage({ const LoginFlowPage({
required this.serverURL, required this.serverURL,

2
packages/neon/neon/lib/src/pages/login_qrcode.dart

@ -1,10 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:flutter_zxing/flutter_zxing.dart';
import 'package:meta/meta.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
import 'package:neon/src/router.dart'; import 'package:neon/src/router.dart';
import 'package:neon/src/utils/exceptions.dart'; import 'package:neon/src/utils/exceptions.dart';
import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/exception.dart';
@internal
class LoginQrcodePage extends StatefulWidget { class LoginQrcodePage extends StatefulWidget {
const LoginQrcodePage({ const LoginQrcodePage({
super.key, super.key,

2
packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/models/app_implementation.dart';
import 'package:neon/src/settings/models/select_option.dart'; import 'package:neon/src/settings/models/select_option.dart';
@ -11,6 +12,7 @@ import 'package:neon/src/settings/widgets/settings_list.dart';
import 'package:neon/src/theme/dialog.dart'; import 'package:neon/src/theme/dialog.dart';
import 'package:neon/src/utils/confirmation_dialog.dart'; import 'package:neon/src/utils/confirmation_dialog.dart';
@internal
class NextcloudAppSettingsPage extends StatelessWidget { class NextcloudAppSettingsPage extends StatelessWidget {
const NextcloudAppSettingsPage({ const NextcloudAppSettingsPage({
required this.appImplementation, required this.appImplementation,

6
packages/neon/neon/lib/src/pages/route_not_found.dart

@ -1,12 +1,14 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:neon/blocs.dart'; import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/blocs/accounts.dart';
import 'package:neon/src/router.dart'; import 'package:neon/src/router.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@internal
class RouteNotFoundPage extends StatefulWidget { class RouteNotFoundPage extends StatefulWidget {
const RouteNotFoundPage({ const RouteNotFoundPage({
required this.uri, required this.uri,
@ -27,7 +29,7 @@ class _RouteNotFoundPageState extends State<RouteNotFoundPage> {
unawaited(_checkLaunchable()); unawaited(_checkLaunchable());
} }
Future _checkLaunchable() async { Future<void> _checkLaunchable() async {
final accountsBloc = Provider.of<AccountsBloc>(context, listen: false); final accountsBloc = Provider.of<AccountsBloc>(context, listen: false);
if (!accountsBloc.hasAccounts) { if (!accountsBloc.hasAccounts) {
return; return;

3
packages/neon/neon/lib/src/pages/settings.dart

@ -1,6 +1,7 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/accounts.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
@ -26,6 +27,7 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
@internal
enum SettingsCategories { enum SettingsCategories {
apps, apps,
theme, theme,
@ -37,6 +39,7 @@ enum SettingsCategories {
other, other,
} }
@internal
class SettingsPage extends StatefulWidget { class SettingsPage extends StatefulWidget {
const SettingsPage({ const SettingsPage({
this.initialCategory, this.initialCategory,

4
packages/neon/neon/lib/src/platform/platform.dart

@ -16,7 +16,7 @@ abstract interface class NeonPlatform {
/// Infers and configures the platform automatically. /// Infers and configures the platform automatically.
/// ///
/// Required to be called before accessing [NeonPlatform.instance]. /// Required to be called before accessing [NeonPlatform.instance].
static Future setup() async { static Future<void> setup() async {
if (Platform.isAndroid) { if (Platform.isAndroid) {
_platform = const AndroidNeonPlatform(); _platform = const AndroidNeonPlatform();
} else if (Platform.isLinux) { } else if (Platform.isLinux) {
@ -55,5 +55,5 @@ abstract interface class NeonPlatform {
FutureOr<String> get userAccessibleAppDataPath; FutureOr<String> get userAccessibleAppDataPath;
FutureOr init(); FutureOr<void> init();
} }

2
packages/neon/neon/lib/src/router.dart

@ -62,7 +62,7 @@ class AppRouter extends GoRouter {
routes: $appRoutes, routes: $appRoutes,
); );
static Page _buildErrorPage(final BuildContext context, final GoRouterState state) => MaterialPage( static Page<void> _buildErrorPage(final BuildContext context, final GoRouterState state) => MaterialPage(
child: RouteNotFoundPage( child: RouteNotFoundPage(
uri: state.uri, uri: state.uri,
), ),

4
packages/neon/neon/lib/src/settings/models/options_collection.dart

@ -14,7 +14,7 @@ abstract class OptionsCollection implements Exportable {
/// Collection of options. /// Collection of options.
@protected @protected
Iterable<Option> get options; Iterable<Option<dynamic>> get options;
/// Resets all [options]. /// Resets all [options].
/// ///
@ -61,5 +61,5 @@ abstract class NextcloudAppOptions extends OptionsCollection {
late final Iterable<OptionsCategory> categories; late final Iterable<OptionsCategory> categories;
@override @override
late final Iterable<Option> options; late final Iterable<Option<dynamic>> options;
} }

18
packages/neon/neon/lib/src/settings/models/storage.dart

@ -6,12 +6,12 @@ import 'package:shared_preferences/shared_preferences.dart';
abstract interface class SettingsStorage { abstract interface class SettingsStorage {
String? getString(final String key); String? getString(final String key);
Future setString(final String key, final String value); Future<bool> setString(final String key, final String value);
bool? getBool(final String key); bool? getBool(final String key);
// ignore: avoid_positional_boolean_parameters // ignore: avoid_positional_boolean_parameters
Future setBool(final String key, final bool value); Future<bool> setBool(final String key, final bool value);
Future<bool> remove(final String key); Future<bool> remove(final String key);
} }
@ -53,7 +53,7 @@ final class NeonStorage {
/// Sets up the [SharedPreferences] instance. /// Sets up the [SharedPreferences] instance.
/// ///
/// Required to be called before accessing [database]. /// Required to be called before accessing [database].
static Future init() async { static Future<void> init() async {
if (_sharedPreferences != null) { if (_sharedPreferences != null) {
return; return;
} }
@ -86,16 +86,16 @@ final class SingleValueStorage {
String? getString() => NeonStorage.database.getString(key.value); String? getString() => NeonStorage.database.getString(key.value);
Future setString(final String value) => NeonStorage.database.setString(key.value, value); Future<bool> setString(final String value) => NeonStorage.database.setString(key.value, value);
bool? getBool() => NeonStorage.database.getBool(key.value); bool? getBool() => NeonStorage.database.getBool(key.value);
// ignore: avoid_positional_boolean_parameters // ignore: avoid_positional_boolean_parameters
Future setBool(final bool value) => NeonStorage.database.setBool(key.value, value); Future<bool> setBool(final bool value) => NeonStorage.database.setBool(key.value, value);
List<String>? getStringList() => NeonStorage.database.getStringList(key.value); List<String>? getStringList() => NeonStorage.database.getStringList(key.value);
Future setStringList(final List<String> value) => NeonStorage.database.setStringList(key.value, value); Future<bool> setStringList(final List<String> value) => NeonStorage.database.setStringList(key.value, value);
} }
@immutable @immutable
@ -130,16 +130,16 @@ final class AppStorage implements SettingsStorage {
String? getString(final String key) => NeonStorage.database.getString(formatKey(key)); String? getString(final String key) => NeonStorage.database.getString(formatKey(key));
@override @override
Future setString(final String key, final String value) => NeonStorage.database.setString(formatKey(key), value); Future<bool> setString(final String key, final String value) => NeonStorage.database.setString(formatKey(key), value);
@override @override
bool? getBool(final String key) => NeonStorage.database.getBool(formatKey(key)); bool? getBool(final String key) => NeonStorage.database.getBool(formatKey(key));
@override @override
Future setBool(final String key, final bool value) => NeonStorage.database.setBool(formatKey(key), value); Future<bool> setBool(final String key, final bool value) => NeonStorage.database.setBool(formatKey(key), value);
List<String>? getStringList(final String key) => NeonStorage.database.getStringList(formatKey(key)); List<String>? getStringList(final String key) => NeonStorage.database.getStringList(formatKey(key));
Future setStringList(final String key, final List<String> value) => Future<bool> setStringList(final String key, final List<String> value) =>
NeonStorage.database.setStringList(formatKey(key), value); NeonStorage.database.setStringList(formatKey(key), value);
} }

2
packages/neon/neon/lib/src/settings/utils/settings_export_helper.dart

@ -74,6 +74,7 @@ class SettingsExportHelper {
} }
/// Helper class to export [AppImplementation]s implementing the [Exportable] interface. /// Helper class to export [AppImplementation]s implementing the [Exportable] interface.
@internal
@immutable @immutable
class AppImplementationsExporter implements Exportable { class AppImplementationsExporter implements Exportable {
const AppImplementationsExporter(this.appImplementations); const AppImplementationsExporter(this.appImplementations);
@ -109,6 +110,7 @@ class AppImplementationsExporter implements Exportable {
} }
/// Helper class to export [Account]s implementing the [Exportable] interface. /// Helper class to export [Account]s implementing the [Exportable] interface.
@internal
@immutable @immutable
class AccountsBlocExporter implements Exportable { class AccountsBlocExporter implements Exportable {
const AccountsBlocExporter(this.accountsBloc); const AccountsBlocExporter(this.accountsBloc);

2
packages/neon/neon/lib/src/settings/widgets/account_settings_tile.dart

@ -17,7 +17,7 @@ class AccountSettingsTile extends SettingsTile {
final Account account; final Account account;
final Color? color; final Color? color;
final Widget? trailing; final Widget? trailing;
final VoidCallback? onTap; final GestureTapCallback? onTap;
@override @override
Widget build(final BuildContext context) => NeonAccountTile( Widget build(final BuildContext context) => NeonAccountTile(

2
packages/neon/neon/lib/src/settings/widgets/custom_settings_tile.dart

@ -17,7 +17,7 @@ class CustomSettingsTile extends SettingsTile {
final Widget? subtitle; final Widget? subtitle;
final Widget? leading; final Widget? leading;
final Widget? trailing; final Widget? trailing;
final Function()? onTap; final GestureTapCallback? onTap;
@override @override
Widget build(final BuildContext context) => ListTile( Widget build(final BuildContext context) => ListTile(

2
packages/neon/neon/lib/src/settings/widgets/settings_tile.dart

@ -10,7 +10,7 @@ abstract class SettingsTile extends StatelessWidget {
} }
@internal @internal
abstract class InputSettingsTile<T extends Option> extends SettingsTile { abstract class InputSettingsTile<T extends Option<dynamic>> extends SettingsTile {
const InputSettingsTile({ const InputSettingsTile({
required this.option, required this.option,
super.key, super.key,

3
packages/neon/neon/lib/src/utils/account_options.dart

@ -30,7 +30,7 @@ class AccountSpecificOptions extends OptionsCollection {
final AppsBloc _appsBloc; final AppsBloc _appsBloc;
@override @override
late final List<Option> options = [ late final List<Option<dynamic>> options = [
initialApp, initialApp,
]; ];
@ -43,6 +43,7 @@ class AccountSpecificOptions extends OptionsCollection {
); );
} }
@internal
enum AccountOptionKeys implements Storable { enum AccountOptionKeys implements Storable {
initialApp._('initial-app'); initialApp._('initial-app');

9
packages/neon/neon/lib/src/utils/global_options.dart

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
import 'package:neon/src/models/label_builder.dart';
import 'package:neon/src/settings/models/option.dart'; import 'package:neon/src/settings/models/option.dart';
import 'package:neon/src/settings/models/options_collection.dart'; import 'package:neon/src/settings/models/options_collection.dart';
import 'package:neon/src/settings/models/select_option.dart'; import 'package:neon/src/settings/models/select_option.dart';
@ -51,7 +52,7 @@ class GlobalOptions extends OptionsCollection {
final PackageInfo _packageInfo; final PackageInfo _packageInfo;
late final _distributorsMap = <String, String Function(BuildContext)>{ late final _distributorsMap = <String, LabelBuilder>{
_packageInfo.packageName: (final context) => _packageInfo.packageName: (final context) =>
AppLocalizations.of(context).globalOptionsPushNotificationsDistributorFirebaseEmbedded, AppLocalizations.of(context).globalOptionsPushNotificationsDistributorFirebaseEmbedded,
'com.github.gotify.up': (final context) => 'com.github.gotify.up': (final context) =>
@ -68,7 +69,7 @@ class GlobalOptions extends OptionsCollection {
}; };
@override @override
late final List<Option> options = [ late final List<Option<dynamic>> options = [
themeMode, themeMode,
themeOLEDAsDark, themeOLEDAsDark,
themeKeepOriginalAccentColor, themeKeepOriginalAccentColor,
@ -101,7 +102,7 @@ class GlobalOptions extends OptionsCollection {
} }
} }
Future updateDistributors(final List<String> distributors) async { Future<void> updateDistributors(final List<String> distributors) async {
pushNotificationsDistributor.values = { pushNotificationsDistributor.values = {
for (final distributor in distributors) ...{ for (final distributor in distributors) ...{
distributor: _distributorsMap[distributor] ?? (final _) => distributor, distributor: _distributorsMap[distributor] ?? (final _) => distributor,
@ -220,6 +221,7 @@ class GlobalOptions extends OptionsCollection {
); );
} }
@internal
enum GlobalOptionKeys implements Storable { enum GlobalOptionKeys implements Storable {
themeMode._('theme-mode'), themeMode._('theme-mode'),
themeOledAsDark._('theme-oled-as-dark'), themeOledAsDark._('theme-oled-as-dark'),
@ -240,6 +242,7 @@ enum GlobalOptionKeys implements Storable {
final String value; final String value;
} }
@internal
enum NavigationMode { enum NavigationMode {
drawer, drawer,
drawerAlwaysVisible, drawerAlwaysVisible,

2
packages/neon/neon/lib/src/utils/global_popups.dart

@ -26,7 +26,7 @@ class GlobalPopups {
bool _registered = false; bool _registered = false;
late BuildContext _context; late BuildContext _context;
final _subscriptions = <StreamSubscription>[]; final _subscriptions = <StreamSubscription<dynamic>>[];
void dispose() { void dispose() {
for (final subscription in _subscriptions) { for (final subscription in _subscriptions) {

2
packages/neon/neon/lib/src/utils/push_utils.dart

@ -58,7 +58,7 @@ class PushUtils {
return localNotificationsPlugin; return localNotificationsPlugin;
} }
static Future onMessage(final Uint8List messages, final String instance) async { static Future<void> onMessage(final Uint8List messages, final String instance) async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
final localNotificationsPlugin = await initLocalNotifications( final localNotificationsPlugin = await initLocalNotifications(

39
packages/neon/neon/lib/src/utils/request_manager.dart

@ -10,6 +10,11 @@ import 'package:rxdart/rxdart.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
import 'package:xml/xml.dart' as xml; import 'package:xml/xml.dart' as xml;
typedef UnwrapCallback<T, R> = T Function(R);
typedef SerializeCallback<T> = String Function(T);
typedef DeserializeCallback<T> = T Function(String);
typedef NextcloudApiCallback<T> = Future<T> Function();
class RequestManager { class RequestManager {
RequestManager(); RequestManager();
@ -22,19 +27,19 @@ class RequestManager {
// ignore: prefer_constructors_over_static_methods // ignore: prefer_constructors_over_static_methods
static RequestManager get instance => _requestManager ??= RequestManager(); static RequestManager get instance => _requestManager ??= RequestManager();
Future initCache() async { Future<void> initCache() async {
_cache = Cache(); _cache = Cache();
await _cache!.init(); await _cache!.init();
} }
Cache? _cache; Cache? _cache;
Future wrapNextcloud<T, R>( Future<void> wrapNextcloud<T, R>(
final String clientID, final String clientID,
final String k, final String k,
final BehaviorSubject<Result<T>> subject, final BehaviorSubject<Result<T>> subject,
final Future<R> Function() call, final NextcloudApiCallback<R> call,
final T Function(R) unwrap, { final UnwrapCallback<T, R> unwrap, {
final bool disableTimeout = false, final bool disableTimeout = false,
final bool emitEmptyCache = false, final bool emitEmptyCache = false,
}) async => }) async =>
@ -51,12 +56,12 @@ class RequestManager {
0, 0,
); );
Future wrapWebDav<T>( Future<void> wrapWebDav<T>(
final String clientID, final String clientID,
final String k, final String k,
final BehaviorSubject<Result<T>> subject, final BehaviorSubject<Result<T>> subject,
final Future<WebDavMultistatus> Function() call, final NextcloudApiCallback<WebDavMultistatus> call,
final T Function(WebDavMultistatus) unwrap, { final UnwrapCallback<T, WebDavMultistatus> unwrap, {
final bool disableTimeout = false, final bool disableTimeout = false,
final bool emitEmptyCache = false, final bool emitEmptyCache = false,
}) async => }) async =>
@ -73,14 +78,14 @@ class RequestManager {
0, 0,
); );
Future _wrap<T, R>( Future<void> _wrap<T, R>(
final String clientID, final String clientID,
final String k, final String k,
final BehaviorSubject<Result<T>> subject, final BehaviorSubject<Result<T>> subject,
final Future<R> Function() call, final NextcloudApiCallback<R> call,
final T Function(R) unwrap, final UnwrapCallback<T, R> unwrap,
final String Function(R) serialize, final SerializeCallback<R> serialize,
final R Function(String) deserialize, final DeserializeCallback<R> deserialize,
final bool disableTimeout, final bool disableTimeout,
final bool emitEmptyCache, final bool emitEmptyCache,
final int retries, final int retries,
@ -150,8 +155,8 @@ class RequestManager {
Future<bool> _emitCached<T, R>( Future<bool> _emitCached<T, R>(
final String key, final String key,
final BehaviorSubject<Result<T>> subject, final BehaviorSubject<Result<T>> subject,
final T Function(R) unwrap, final UnwrapCallback<T, R> unwrap,
final R Function(String) deserialize, final DeserializeCallback<R> deserialize,
final bool emitEmptyCache, final bool emitEmptyCache,
final bool loading, final bool loading,
final Object? error, final Object? error,
@ -180,7 +185,7 @@ class RequestManager {
} }
Future<T> timeout<T>( Future<T> timeout<T>(
final Future<T> Function() call, final NextcloudApiCallback<T> call,
) => ) =>
call().timeout(const Duration(seconds: 30)); call().timeout(const Duration(seconds: 30));
} }
@ -189,7 +194,7 @@ class RequestManager {
class Cache { class Cache {
Database? _database; Database? _database;
Future init() async { Future<void> init() async {
if (_database != null) { if (_database != null) {
return; return;
} }
@ -210,7 +215,7 @@ class Cache {
Future<String?> get(final String key) async => Future<String?> get(final String key) async =>
(await _database!.rawQuery('SELECT value FROM cache WHERE key = ?', [key]))[0]['value'] as String?; (await _database!.rawQuery('SELECT value FROM cache WHERE key = ?', [key]))[0]['value'] as String?;
Future set(final String key, final String value) async => _database!.rawQuery( Future<void> set(final String key, final String value) async => _database!.rawQuery(
'INSERT INTO cache (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value', 'INSERT INTO cache (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value',
[key, value], [key, value],
); );

6
packages/neon/neon/lib/src/utils/stream_listenable.dart

@ -14,17 +14,17 @@ class StreamListenable extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
addSubscription(stream); _addSubscription(stream);
} }
/// Listenable for multiple Streams. /// Listenable for multiple Streams.
/// ///
/// Notifies it's listeners on every event emitted by any of the streams. /// Notifies it's listeners on every event emitted by any of the streams.
StreamListenable.multiListenable(final Iterable<Stream<dynamic>> streams) { StreamListenable.multiListenable(final Iterable<Stream<dynamic>> streams) {
streams.forEach(addSubscription); streams.forEach(_addSubscription);
} }
void addSubscription(final Stream<dynamic> stream) { void _addSubscription(final Stream<dynamic> stream) {
_subscriptions.add( _subscriptions.add(
stream.asBroadcastStream().listen((final _) { stream.asBroadcastStream().listen((final _) {
notifyListeners(); notifyListeners();

1
packages/neon/neon/lib/src/utils/user_agent.dart

@ -3,6 +3,7 @@ import 'package:package_info_plus/package_info_plus.dart';
late String? _userAgent; late String? _userAgent;
@internal
void buildUserAgent(final PackageInfo packageInfo) { void buildUserAgent(final PackageInfo packageInfo) {
var buildNumber = packageInfo.buildNumber; var buildNumber = packageInfo.buildNumber;
if (buildNumber.isEmpty) { if (buildNumber.isEmpty) {

2
packages/neon/neon/lib/src/widgets/account_tile.dart

@ -25,7 +25,7 @@ class NeonAccountTile extends StatelessWidget {
final Account account; final Account account;
final Color? color; final Color? color;
final Widget? trailing; final Widget? trailing;
final VoidCallback? onTap; final GestureTapCallback? onTap;
final Color? textColor; final Color? textColor;
final bool dense; final bool dense;
final bool showStatus; final bool showStatus;

4
packages/neon/neon/lib/src/widgets/app_bar.dart

@ -36,7 +36,7 @@ class _NeonAppBarState extends State<NeonAppBar> {
final _searchBarFocusNode = FocusNode(); final _searchBarFocusNode = FocusNode();
final _searchTermController = StreamController<String>(); final _searchTermController = StreamController<String>();
late final StreamSubscription _searchTermSubscription; late final StreamSubscription<String> _searchTermSubscription;
@override @override
void initState() { void initState() {
@ -181,7 +181,7 @@ class _NotificationIconButtonState extends State<NotificationIconButton> {
late AppsBloc _appsBloc; late AppsBloc _appsBloc;
late List<Account> _accounts; late List<Account> _accounts;
late Account _account; late Account _account;
late StreamSubscription notificationSubscription; late StreamSubscription<void> notificationSubscription;
@override @override
void initState() { void initState() {

42
packages/neon/neon/lib/src/widgets/cached_image.dart

@ -5,15 +5,20 @@ import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:neon/nextcloud.dart';
import 'package:neon/src/blocs/accounts.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/exception.dart';
import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart';
import 'package:provider/provider.dart';
typedef CacheReviver = FutureOr<Uint8List?> Function(CacheManager cacheManager); typedef CacheReviver = FutureOr<Uint8List?> Function(CacheManager cacheManager);
typedef ImageDownloader = FutureOr<Uint8List> Function(); typedef ImageDownloader = FutureOr<Uint8List> Function();
typedef CacheWriter = Future<void> Function(CacheManager cacheManager, Uint8List image); typedef CacheWriter = Future<void> Function(CacheManager cacheManager, Uint8List image);
typedef ErrorWidgetBuilder = Widget? Function(BuildContext, dynamic); typedef ErrorWidgetBuilder = Widget? Function(BuildContext, dynamic);
typedef ApiImageDownloader = FutureOr<Uint8List> Function(NextcloudClient client);
class NeonCachedImage extends StatefulWidget { class NeonCachedImage extends StatefulWidget {
const NeonCachedImage({ const NeonCachedImage({
required this.image, required this.image,
@ -186,3 +191,40 @@ class _NeonCachedImageState extends State<NeonCachedImage> {
iconSize: widget.size?.shortestSide, iconSize: widget.size?.shortestSide,
); );
} }
class NeonApiImage extends StatelessWidget {
const NeonApiImage({
required this.getImage,
required this.cacheKey,
this.reviver,
this.writeCache,
this.isSvgHint = false,
this.size,
this.fit,
this.svgColor,
this.iconColor,
this.errorBuilder,
super.key,
});
final ApiImageDownloader getImage;
final String cacheKey;
final CacheReviver? reviver;
final CacheWriter? writeCache;
final bool isSvgHint;
final Size? size;
final BoxFit? fit;
final Color? svgColor;
final Color? iconColor;
final ErrorWidgetBuilder? errorBuilder;
@override
Widget build(final BuildContext context) {
final account = Provider.of<AccountsBloc>(context, listen: false).activeAccount.value!;
return NeonCachedImage.custom(
getImage: () async => getImage(account.client),
cacheKey: '${account.id}-$cacheKey',
);
}
}

2
packages/neon/neon/lib/src/widgets/exception.dart

@ -22,7 +22,7 @@ class NeonException extends StatelessWidget {
}); });
final dynamic exception; final dynamic exception;
final Function() onRetry; final VoidCallback onRetry;
final bool onlyIcon; final bool onlyIcon;
final double? iconSize; final double? iconSize;
final Color? color; final Color? color;

2
packages/neon/neon/lib/src/widgets/list_view.dart

@ -19,7 +19,7 @@ class NeonListView<T> extends StatelessWidget {
final Iterable<T>? items; final Iterable<T>? items;
final bool isLoading; final bool isLoading;
final dynamic error; final dynamic error;
final Future Function() onRefresh; final RefreshCallback onRefresh;
final Widget Function(BuildContext, T data) builder; final Widget Function(BuildContext, T data) builder;
final String? scrollKey; final String? scrollKey;
final bool withFloatingActionButton; final bool withFloatingActionButton;

4
packages/neon/neon/test/option_test.dart

@ -45,7 +45,7 @@ void main() {
late SelectOption<SelectValues> option; late SelectOption<SelectValues> option;
setUp(() { setUp(() {
when(() => storage.setString(key.value, any())).thenAnswer((final _) async {}); when(() => storage.setString(key.value, any())).thenAnswer((final _) async => true);
when(() => storage.remove(key.value)).thenAnswer((final _) async => true); when(() => storage.remove(key.value)).thenAnswer((final _) async => true);
option = SelectOption<SelectValues>( option = SelectOption<SelectValues>(
@ -209,7 +209,7 @@ void main() {
late ToggleOption option; late ToggleOption option;
setUp(() { setUp(() {
when(() => storage.setBool(key.value, any())).thenAnswer((final _) async {}); when(() => storage.setBool(key.value, any())).thenAnswer((final _) async => true);
when(() => storage.remove(key.value)).thenAnswer((final _) async => true); when(() => storage.remove(key.value)).thenAnswer((final _) async => true);
option = ToggleOption( option = ToggleOption(

4
packages/neon/neon/test/options_collection_test.dart

@ -5,10 +5,10 @@ import 'package:neon/src/settings/models/storage.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
// ignore: missing_override_of_must_be_overridden // ignore: missing_override_of_must_be_overridden
class OptionMock extends Mock implements Option {} class OptionMock extends Mock implements Option<Object> {}
class Collection extends NextcloudAppOptions { class Collection extends NextcloudAppOptions {
Collection(final List<Option> options) : super(const AppStorage(StorageKeys.apps)) { Collection(final List<Option<Object>> options) : super(const AppStorage(StorageKeys.apps)) {
super.options = options; super.options = options;
} }
} }

2
packages/neon/neon/test/settings_export_test.dart

@ -4,7 +4,7 @@ import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
import 'package:neon/blocs.dart'; import 'package:neon/src/blocs/accounts.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/models/app_implementation.dart';
import 'package:neon/src/settings/models/exportable.dart'; import 'package:neon/src/settings/models/exportable.dart';

6
packages/neon/neon_files/lib/blocs/browser.dart

@ -1,12 +1,12 @@
part of '../neon_files.dart'; part of '../neon_files.dart';
abstract class FilesBrowserBlocEvents { abstract interface class FilesBrowserBlocEvents {
void setPath(final List<String> path); void setPath(final List<String> path);
void createFolder(final List<String> path); void createFolder(final List<String> path);
} }
abstract class FilesBrowserBlocStates { abstract interface class FilesBrowserBlocStates {
BehaviorSubject<Result<List<WebDavFile>>> get files; BehaviorSubject<Result<List<WebDavFile>>> get files;
BehaviorSubject<List<String>> get path; BehaviorSubject<List<String>> get path;
@ -37,7 +37,7 @@ class FilesBrowserBloc extends InteractiveBloc implements FilesBrowserBlocEvents
BehaviorSubject<List<String>> path = BehaviorSubject<List<String>>.seeded([]); BehaviorSubject<List<String>> path = BehaviorSubject<List<String>>.seeded([]);
@override @override
Future refresh() async { Future<void> refresh() async {
await RequestManager.instance.wrapWebDav<List<WebDavFile>>( await RequestManager.instance.wrapWebDav<List<WebDavFile>>(
account.id, account.id,
'files-${path.value.join('/')}', 'files-${path.value.join('/')}',

8
packages/neon/neon_files/lib/blocs/files.dart

@ -1,6 +1,6 @@
part of '../neon_files.dart'; part of '../neon_files.dart';
abstract class FilesBlocEvents { abstract interface class FilesBlocEvents {
void uploadFile(final List<String> path, final String localPath); void uploadFile(final List<String> path, final String localPath);
void syncFile(final List<String> path); void syncFile(final List<String> path);
@ -20,7 +20,7 @@ abstract class FilesBlocEvents {
void removeFavorite(final List<String> path); void removeFavorite(final List<String> path);
} }
abstract class FilesBlocStates { abstract interface class FilesBlocStates {
BehaviorSubject<List<FilesTask>> get tasks; BehaviorSubject<List<FilesTask>> get tasks;
} }
@ -103,7 +103,7 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
} }
@override @override
Future refresh() async { Future<void> refresh() async {
await browser.refresh(); await browser.refresh();
} }
@ -164,7 +164,7 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
); );
} }
Future _downloadFile( Future<void> _downloadFile(
final List<String> path, final List<String> path,
final File file, final File file,
) async { ) async {

4
packages/neon/neon_files/lib/dialogs/choose_create.dart

@ -15,7 +15,7 @@ class FilesChooseCreateDialog extends StatefulWidget {
} }
class _FilesChooseCreateDialogState extends State<FilesChooseCreateDialog> { class _FilesChooseCreateDialogState extends State<FilesChooseCreateDialog> {
Future uploadFromPick(final FileType type) async { Future<void> uploadFromPick(final FileType type) async {
final result = await FilePicker.platform.pickFiles( final result = await FilePicker.platform.pickFiles(
allowMultiple: true, allowMultiple: true,
type: type, type: type,
@ -27,7 +27,7 @@ class _FilesChooseCreateDialogState extends State<FilesChooseCreateDialog> {
} }
} }
Future upload(final File file) async { Future<void> upload(final File file) async {
final sizeWarning = widget.bloc.options.uploadSizeWarning.value; final sizeWarning = widget.bloc.options.uploadSizeWarning.value;
if (sizeWarning != null) { if (sizeWarning != null) {
final stat = file.statSync(); final stat = file.statSync();

2
packages/neon/neon_files/lib/neon_files.dart

@ -52,7 +52,7 @@ class FilesApp extends AppImplementation<FilesBloc, FilesAppSpecificOptions> {
final String id = AppIDs.files; final String id = AppIDs.files;
@override @override
final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate<AppLocalizations> localizationsDelegate = AppLocalizations.delegate;
@override @override
final List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;

2
packages/neon/neon_files/lib/options.dart

@ -86,7 +86,7 @@ class FilesAppSpecificOptions extends NextcloudAppOptions {
}, },
); );
late final _sizeWarningValues = <int?, String Function(BuildContext)>{ late final _sizeWarningValues = <int?, LabelBuilder>{
null: (final context) => AppLocalizations.of(context).optionsSizeWarningDisabled, null: (final context) => AppLocalizations.of(context).optionsSizeWarningDisabled,
for (final i in [ for (final i in [
1, 1,

4
packages/neon/neon_files/lib/utils/task.dart

@ -23,7 +23,7 @@ class FilesDownloadTask extends FilesTask {
required super.file, required super.file,
}); });
Future execute(final NextcloudClient client) async { Future<void> execute(final NextcloudClient client) async {
await client.webdav.getFile( await client.webdav.getFile(
Uri(pathSegments: path), Uri(pathSegments: path),
file, file,
@ -43,7 +43,7 @@ class FilesUploadTask extends FilesTask {
FileStat? _stat; FileStat? _stat;
FileStat get stat => _stat ??= file.statSync(); FileStat get stat => _stat ??= file.statSync();
Future execute(final NextcloudClient client) async { Future<void> execute(final NextcloudClient client) async {
await client.webdav.putFile( await client.webdav.putFile(
file, file,
stat, stat,

13
packages/neon/neon_files/lib/widgets/file_preview.dart

@ -41,9 +41,7 @@ class FilePreview extends StatelessWidget {
valueListenable: bloc.options.showPreviewsOption, valueListenable: bloc.options.showPreviewsOption,
builder: (final context, final showPreviews, final child) { builder: (final context, final showPreviews, final child) {
if (showPreviews && (details.hasPreview ?? false)) { if (showPreviews && (details.hasPreview ?? false)) {
final account = Provider.of<AccountsBloc>(context, listen: false).activeAccount.value!;
final preview = FilePreviewImage( final preview = FilePreviewImage(
account: account,
file: details, file: details,
size: size, size: size,
); );
@ -72,19 +70,17 @@ class FilePreview extends StatelessWidget {
} }
} }
class FilePreviewImage extends NeonCachedImage { class FilePreviewImage extends NeonApiImage {
factory FilePreviewImage({ factory FilePreviewImage({
required final Account account,
required final FileDetails file, required final FileDetails file,
required final Size size, required final Size size,
}) { }) {
final width = size.width.toInt(); final width = size.width.toInt();
final height = size.height.toInt(); final height = size.height.toInt();
final path = file.path.join('/'); final path = file.path.join('/');
final cacheKey = '${account.id}-preview-$path-$width-$height'; final cacheKey = 'preview-$path-$width-$height';
return FilePreviewImage._( return FilePreviewImage._(
account: account,
file: file, file: file,
size: size, size: size,
cacheKey: cacheKey, cacheKey: cacheKey,
@ -95,15 +91,14 @@ class FilePreviewImage extends NeonCachedImage {
} }
FilePreviewImage._({ FilePreviewImage._({
required final Account account,
required final FileDetails file, required final FileDetails file,
required Size super.size, required Size super.size,
required super.cacheKey, required super.cacheKey,
required final String path, required final String path,
required final int width, required final int width,
required final int height, required final int height,
}) : super.custom( }) : super(
getImage: () async => account.client.core.preview.getPreview( getImage: (final client) async => client.core.preview.getPreview(
file: path, file: path,
x: width, x: width,
y: height, y: height,

8
packages/neon/neon_news/lib/blocs/article.dart

@ -1,6 +1,6 @@
part of '../neon_news.dart'; part of '../neon_news.dart';
abstract class NewsArticleBlocEvents { abstract interface class NewsArticleBlocEvents {
void markArticleAsRead(); void markArticleAsRead();
void markArticleAsUnread(); void markArticleAsUnread();
@ -10,7 +10,7 @@ abstract class NewsArticleBlocEvents {
void unstarArticle(); void unstarArticle();
} }
abstract class NewsArticleBlocStates { abstract interface class NewsArticleBlocStates {
BehaviorSubject<bool> get unread; BehaviorSubject<bool> get unread;
BehaviorSubject<bool> get starred; BehaviorSubject<bool> get starred;
@ -44,7 +44,7 @@ class NewsArticleBloc extends InteractiveBloc implements NewsArticleBlocEvents,
BehaviorSubject<bool> unread = BehaviorSubject<bool>(); BehaviorSubject<bool> unread = BehaviorSubject<bool>();
@override @override
Future refresh() async {} Future<void> refresh() async {}
@override @override
void markArticleAsRead() { void markArticleAsRead() {
@ -78,7 +78,7 @@ class NewsArticleBloc extends InteractiveBloc implements NewsArticleBlocEvents,
}); });
} }
void _wrapArticleAction(final Future Function() call) => wrapAction( void _wrapArticleAction(final AsyncCallback call) => wrapAction(
call, call,
refresh: () async { refresh: () async {
await _newsArticlesBloc.refresh(); await _newsArticlesBloc.refresh();

8
packages/neon/neon_news/lib/blocs/articles.dart

@ -11,7 +11,7 @@ enum ListType {
folder, folder,
} }
abstract class NewsArticlesBlocEvents { abstract interface class NewsArticlesBlocEvents {
void setFilterType(final FilterType type); void setFilterType(final FilterType type);
void markArticleAsRead(final NewsArticle article); void markArticleAsRead(final NewsArticle article);
@ -23,7 +23,7 @@ abstract class NewsArticlesBlocEvents {
void unstarArticle(final NewsArticle article); void unstarArticle(final NewsArticle article);
} }
abstract class NewsArticlesBlocStates { abstract interface class NewsArticlesBlocStates {
BehaviorSubject<Result<List<NewsArticle>>> get articles; BehaviorSubject<Result<List<NewsArticle>>> get articles;
BehaviorSubject<FilterType> get filterType; BehaviorSubject<FilterType> get filterType;
@ -75,14 +75,14 @@ class NewsArticlesBloc extends InteractiveBloc implements NewsArticlesBlocEvents
BehaviorSubject<FilterType> filterType = BehaviorSubject<FilterType>(); BehaviorSubject<FilterType> filterType = BehaviorSubject<FilterType>();
@override @override
Future refresh() async { Future<void> refresh() async {
if (this is! NewsMainArticlesBloc) { if (this is! NewsMainArticlesBloc) {
await reload(); await reload();
} }
await _newsBloc.refresh(); await _newsBloc.refresh();
} }
Future reload() async { Future<void> reload() async {
// The API for pagination is pretty useless in this case sadly. So no pagination for us :( // The API for pagination is pretty useless in this case sadly. So no pagination for us :(
// https://github.com/nextcloud/news/blob/master/docs/api/api-v1-2.md#get-items // https://github.com/nextcloud/news/blob/master/docs/api/api-v1-2.md#get-items

8
packages/neon/neon_news/lib/blocs/news.dart

@ -1,6 +1,6 @@
part of '../neon_news.dart'; part of '../neon_news.dart';
abstract class NewsBlocEvents { abstract interface class NewsBlocEvents {
void addFeed(final String url, final int? folderId); void addFeed(final String url, final int? folderId);
void removeFeed(final int feedId); void removeFeed(final int feedId);
@ -20,7 +20,7 @@ abstract class NewsBlocEvents {
void markFolderAsRead(final int folderId); void markFolderAsRead(final int folderId);
} }
abstract class NewsBlocStates { abstract interface class NewsBlocStates {
BehaviorSubject<Result<List<NewsFolder>>> get folders; BehaviorSubject<Result<List<NewsFolder>>> get folders;
BehaviorSubject<Result<List<NewsFeed>>> get feeds; BehaviorSubject<Result<List<NewsFeed>>> get feeds;
@ -90,7 +90,7 @@ class NewsBloc extends InteractiveBloc implements NewsBlocEvents, NewsBlocStates
late BehaviorSubject<FilterType> filterType = mainArticlesBloc.filterType; late BehaviorSubject<FilterType> filterType = mainArticlesBloc.filterType;
@override @override
Future refresh() async { Future<void> refresh() async {
await Future.wait([ await Future.wait([
RequestManager.instance.wrapNextcloud<List<NewsFolder>, NewsListFolders>( RequestManager.instance.wrapNextcloud<List<NewsFolder>, NewsListFolders>(
account.id, account.id,
@ -187,7 +187,7 @@ class NewsBloc extends InteractiveBloc implements NewsBlocEvents, NewsBlocStates
} }
@override @override
Future reload() async { Future<void> reload() async {
await mainArticlesBloc.reload(); await mainArticlesBloc.reload();
} }
} }

3
packages/neon/neon_news/lib/neon_news.dart

@ -2,6 +2,7 @@ library neon_news;
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html/flutter_html.dart';
@ -59,7 +60,7 @@ class NewsApp extends AppImplementation<NewsBloc, NewsAppSpecificOptions> {
final String id = AppIDs.news; final String id = AppIDs.news;
@override @override
final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate<AppLocalizations> localizationsDelegate = AppLocalizations.delegate;
@override @override
final List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;

2
packages/neon/neon_news/lib/pages/article.dart

@ -63,7 +63,7 @@ class _NewsArticlePageState extends State<NewsArticlePage> {
super.dispose(); super.dispose();
} }
Future _startMarkAsReadTimer() async { Future<void> _startMarkAsReadTimer() async {
if (await widget.bloc.unread.first) { if (await widget.bloc.unread.first) {
if (widget.articlesBloc.options.articleDisableMarkAsReadTimeoutOption.value) { if (widget.articlesBloc.options.articleDisableMarkAsReadTimeoutOption.value) {
widget.bloc.markArticleAsRead(); widget.bloc.markArticleAsRead();

2
packages/neon/neon_news/lib/widgets/folder_select.dart

@ -9,7 +9,7 @@ class NewsFolderSelect extends StatelessWidget {
}); });
final List<NewsFolder> folders; final List<NewsFolder> folders;
final void Function(NewsFolder?) onChanged; final ValueChanged<NewsFolder?> onChanged;
final NewsFolder? value; final NewsFolder? value;
@override @override

6
packages/neon/neon_notes/lib/blocs/note.dart

@ -1,6 +1,6 @@
part of '../neon_notes.dart'; part of '../neon_notes.dart';
abstract class NotesNoteBlocEvents { abstract interface class NotesNoteBlocEvents {
void updateContent(final String content); void updateContent(final String content);
void updateTitle(final String title); void updateTitle(final String title);
@ -8,7 +8,7 @@ abstract class NotesNoteBlocEvents {
void updateCategory(final String category); void updateCategory(final String category);
} }
abstract class NotesNoteBlocStates { abstract interface class NotesNoteBlocStates {
BehaviorSubject<String> get category; BehaviorSubject<String> get category;
} }
@ -62,7 +62,7 @@ class NotesNoteBloc extends InteractiveBloc implements NotesNoteBlocEvents, Note
BehaviorSubject<String> category = BehaviorSubject<String>(); BehaviorSubject<String> category = BehaviorSubject<String>();
@override @override
Future refresh() async {} Future<void> refresh() async {}
@override @override
void updateCategory(final String category) { void updateCategory(final String category) {

8
packages/neon/neon_notes/lib/blocs/notes.dart

@ -1,6 +1,6 @@
part of '../neon_notes.dart'; part of '../neon_notes.dart';
abstract class NotesBlocEvents { abstract interface class NotesBlocEvents {
void createNote({ void createNote({
final String title = '', final String title = '',
final String category = '', final String category = '',
@ -18,7 +18,7 @@ abstract class NotesBlocEvents {
void deleteNote(final int id); void deleteNote(final int id);
} }
abstract class NotesBlocStates { abstract interface class NotesBlocStates {
BehaviorSubject<Result<List<NotesNote>>> get notes; BehaviorSubject<Result<List<NotesNote>>> get notes;
} }
@ -43,8 +43,8 @@ class NotesBloc extends InteractiveBloc implements NotesBlocEvents, NotesBlocSta
BehaviorSubject<Result<List<NotesNote>>> notes = BehaviorSubject<Result<List<NotesNote>>>(); BehaviorSubject<Result<List<NotesNote>>> notes = BehaviorSubject<Result<List<NotesNote>>>();
@override @override
Future refresh() async { Future<void> refresh() async {
await RequestManager.instance.wrapNextcloud<List<NotesNote>, BuiltList>( await RequestManager.instance.wrapNextcloud<List<NotesNote>, BuiltList<NotesNote>>(
account.id, account.id,
'notes-notes', 'notes-notes',
notes, notes,

2
packages/neon/neon_notes/lib/neon_notes.dart

@ -52,7 +52,7 @@ class NotesApp extends AppImplementation<NotesBloc, NotesAppSpecificOptions> {
final List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;
@override @override
final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate<AppLocalizations> localizationsDelegate = AppLocalizations.delegate;
@override @override
late final NotesAppSpecificOptions options = NotesAppSpecificOptions(storage); late final NotesAppSpecificOptions options = NotesAppSpecificOptions(storage);

2
packages/neon/neon_notes/lib/widgets/category_select.dart

@ -22,7 +22,7 @@ class NotesCategorySelect extends StatelessWidget {
final List<String> categories; final List<String> categories;
final String? initialValue; final String? initialValue;
final Function(String category) onChanged; final Function(String category) onChanged;
final Function() onSubmitted; final VoidCallback onSubmitted;
@override @override
Widget build(final BuildContext context) => Autocomplete<String>( Widget build(final BuildContext context) => Autocomplete<String>(

2
packages/neon/neon_notifications/lib/blocs/notifications.dart

@ -49,7 +49,7 @@ class NotificationsBloc extends InteractiveBloc
BehaviorSubject<int> unreadCounter = BehaviorSubject<int>(); BehaviorSubject<int> unreadCounter = BehaviorSubject<int>();
@override @override
Future refresh() async { Future<void> refresh() async {
await RequestManager.instance await RequestManager.instance
.wrapNextcloud<List<NotificationsNotification>, NotificationsEndpointListNotificationsResponseApplicationJson>( .wrapNextcloud<List<NotificationsNotification>, NotificationsEndpointListNotificationsResponseApplicationJson>(
_account.id, _account.id,

2
packages/neon/neon_notifications/lib/neon_notifications.dart

@ -29,7 +29,7 @@ class NotificationsApp extends AppImplementation<NotificationsBloc, Notification
final String id = AppIDs.notifications; final String id = AppIDs.notifications;
@override @override
final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate<AppLocalizations> localizationsDelegate = AppLocalizations.delegate;
@override @override
final List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;

1
packages/neon/neon_notifications/lib/pages/main.dart

@ -89,6 +89,7 @@ class _NotificationsMainPageState extends State<NotificationsMainPage> {
return; return;
} }
if (app != null) { if (app != null) {
// TODO: use go_router once implemented
final accountsBloc = Provider.of<AccountsBloc>(context, listen: false); final accountsBloc = Provider.of<AccountsBloc>(context, listen: false);
await accountsBloc.activeAppsBloc.setActiveApp(app.id); await accountsBloc.activeAppsBloc.setActiveApp(app.id);
} else { } else {

1
packages/neon_lints/lib/src/base.yaml

@ -1,6 +1,7 @@
analyzer: analyzer:
language: language:
strict-casts: true strict-casts: true
strict-raw-types: true
errors: errors:
flutter_style_todos: ignore flutter_style_todos: ignore
todo: ignore todo: ignore

1
packages/neon_lints/lint_maker.yaml

@ -19,6 +19,7 @@ dart:
analyzer: analyzer:
language: language:
strict-casts: true strict-casts: true
strict-raw-types: true
errors: errors:
flutter_style_todos: ignore flutter_style_todos: ignore
todo: ignore todo: ignore

22
packages/nextcloud/lib/src/api/news.openapi.dart

@ -154,7 +154,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future renameFolder({ Future<void> renameFolder({
required final int folderId, required final int folderId,
required final String name, required final String name,
}) async { }) async {
@ -183,7 +183,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future deleteFolder({required final int folderId}) async { Future<void> deleteFolder({required final int folderId}) async {
var path = '/index.php/apps/news/api/v1-3/folders/{folderId}'; var path = '/index.php/apps/news/api/v1-3/folders/{folderId}';
final queryParameters = <String, dynamic>{}; final queryParameters = <String, dynamic>{};
final headers = <String, String>{}; final headers = <String, String>{};
@ -208,7 +208,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future markFolderAsRead({ Future<void> markFolderAsRead({
required final int folderId, required final int folderId,
required final int newestItemId, required final int newestItemId,
}) async { }) async {
@ -298,7 +298,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future deleteFeed({required final int feedId}) async { Future<void> deleteFeed({required final int feedId}) async {
var path = '/index.php/apps/news/api/v1-3/feeds/{feedId}'; var path = '/index.php/apps/news/api/v1-3/feeds/{feedId}';
final queryParameters = <String, dynamic>{}; final queryParameters = <String, dynamic>{};
final headers = <String, String>{}; final headers = <String, String>{};
@ -323,7 +323,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future moveFeed({ Future<void> moveFeed({
required final int feedId, required final int feedId,
final int? folderId, final int? folderId,
}) async { }) async {
@ -354,7 +354,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future renameFeed({ Future<void> renameFeed({
required final int feedId, required final int feedId,
required final String feedTitle, required final String feedTitle,
}) async { }) async {
@ -383,7 +383,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future markFeedAsRead({ Future<void> markFeedAsRead({
required final int feedId, required final int feedId,
required final int newestItemId, required final int newestItemId,
}) async { }) async {
@ -504,7 +504,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future markArticleAsRead({required final int itemId}) async { Future<void> markArticleAsRead({required final int itemId}) async {
var path = '/index.php/apps/news/api/v1-3/items/{itemId}/read'; var path = '/index.php/apps/news/api/v1-3/items/{itemId}/read';
final queryParameters = <String, dynamic>{}; final queryParameters = <String, dynamic>{};
final headers = <String, String>{}; final headers = <String, String>{};
@ -529,7 +529,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future markArticleAsUnread({required final int itemId}) async { Future<void> markArticleAsUnread({required final int itemId}) async {
var path = '/index.php/apps/news/api/v1-3/items/{itemId}/unread'; var path = '/index.php/apps/news/api/v1-3/items/{itemId}/unread';
final queryParameters = <String, dynamic>{}; final queryParameters = <String, dynamic>{};
final headers = <String, String>{}; final headers = <String, String>{};
@ -554,7 +554,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future starArticle({required final int itemId}) async { Future<void> starArticle({required final int itemId}) async {
var path = '/index.php/apps/news/api/v1-3/items/{itemId}/star'; var path = '/index.php/apps/news/api/v1-3/items/{itemId}/star';
final queryParameters = <String, dynamic>{}; final queryParameters = <String, dynamic>{};
final headers = <String, String>{}; final headers = <String, String>{};
@ -579,7 +579,7 @@ class NewsClient extends DynamiteClient {
throw await NewsApiException.fromResponse(response); // coverage:ignore-line throw await NewsApiException.fromResponse(response); // coverage:ignore-line
} }
Future unstarArticle({required final int itemId}) async { Future<void> unstarArticle({required final int itemId}) async {
var path = '/index.php/apps/news/api/v1-3/items/{itemId}/unstar'; var path = '/index.php/apps/news/api/v1-3/items/{itemId}/unstar';
final queryParameters = <String, dynamic>{}; final queryParameters = <String, dynamic>{};
final headers = <String, String>{}; final headers = <String, String>{};

2
packages/nextcloud/lib/src/webdav/client.dart

@ -214,7 +214,7 @@ class WebDavClient {
); );
/// Gets the content of the file at [path]. /// Gets the content of the file at [path].
Future getFile( Future<void> getFile(
final Uri path, final Uri path,
final File file, { final File file, {
final Function(double progress)? onProgress, final Function(double progress)? onProgress,

2
packages/nextcloud/test/helper.dart

@ -20,7 +20,7 @@ class DockerContainer {
final int port; final int port;
Future runOccCommand(final List<String> args) async { Future<void> runOccCommand(final List<String> args) async {
final result = await runExecutableArguments( final result = await runExecutableArguments(
'docker', 'docker',
[ [

2
packages/nextcloud/test/notifications_test.dart

@ -21,7 +21,7 @@ void main() {
}); });
tearDown(() => container.destroy()); tearDown(() => container.destroy());
Future sendTestNotification() async { Future<void> sendTestNotification() async {
await client.notifications.api.generateNotification( await client.notifications.api.generateNotification(
userId: 'admin', userId: 'admin',
shortMessage: '123', shortMessage: '123',

4
packages/nextcloud/test/settings_test.dart

@ -4,11 +4,11 @@ import 'package:test/test.dart';
import 'helper.dart'; import 'helper.dart';
Future main() async { Future<void> main() async {
await run(await getDockerImage()); await run(await getDockerImage());
} }
Future run(final DockerImage image) async { Future<void> run(final DockerImage image) async {
group('settings', () { group('settings', () {
late DockerContainer container; late DockerContainer container;
late TestNextcloudClient client; late TestNextcloudClient client;

2
packages/sort_box/lib/sort_box.dart

@ -1,5 +1,5 @@
/// Signature of a function returning a [Comparable]. /// Signature of a function returning a [Comparable].
typedef ComparableGetter<T> = Comparable Function(T); typedef ComparableGetter<T> = Comparable<Object> Function(T);
/// Sorting Box to sort [List]s on multiple properties. /// Sorting Box to sort [List]s on multiple properties.
class SortBox<T extends Enum, R> { class SortBox<T extends Enum, R> {

Loading…
Cancel
Save