diff --git a/app/analysis_options.yaml b/app/analysis_options.yaml index f9b30346..41026582 100644 --- a/app/analysis_options.yaml +++ b/app/analysis_options.yaml @@ -1 +1,8 @@ include: package:flutter_lints/flutter.yaml + +linter: + rules: + depend_on_referenced_packages: false + prefer_interpolation_to_compose_strings: false + no_leading_underscores_for_local_identifiers: false + use_build_context_synchronously: false diff --git a/app/lib/api/api.dart b/app/lib/api/api.dart index ca5bb83c..a644b527 100644 --- a/app/lib/api/api.dart +++ b/app/lib/api/api.dart @@ -31,10 +31,10 @@ class Response { class Api { Api(this._account); - _Files files() => _Files(this); - _Ocs ocs() => _Ocs(this); - _Systemtags systemtags() => _Systemtags(this); - _SystemtagsRelations systemtagsRelations() => _SystemtagsRelations(this); + ApiFiles files() => ApiFiles(this); + ApiOcs ocs() => ApiOcs(this); + ApiSystemtags systemtags() => ApiSystemtags(this); + ApiSystemtagsRelations systemtagsRelations() => ApiSystemtagsRelations(this); static String getAuthorizationHeaderValue(Account account) { final auth = @@ -108,8 +108,8 @@ class Api { bool _isHttpStatusGood(int status) => status ~/ 100 == 2; -class _Files { - _Files(this._api); +class ApiFiles { + ApiFiles(this._api); final Api _api; @@ -447,26 +447,26 @@ class _Files { static final _log = Logger("api.api._Files"); } -class _Ocs { - _Ocs(this._api); +class ApiOcs { + ApiOcs(this._api); - _OcsDav dav() => _OcsDav(this); - _OcsFacerecognition facerecognition() => _OcsFacerecognition(this); - _OcsFilesSharing filesSharing() => _OcsFilesSharing(this); + ApiOcsDav dav() => ApiOcsDav(this); + ApiOcsFacerecognition facerecognition() => ApiOcsFacerecognition(this); + ApiOcsFilesSharing filesSharing() => ApiOcsFilesSharing(this); final Api _api; } -class _OcsDav { - _OcsDav(this._ocs); +class ApiOcsDav { + ApiOcsDav(this._ocs); - _OcsDavDirect direct() => _OcsDavDirect(this); + ApiOcsDavDirect direct() => ApiOcsDavDirect(this); - final _Ocs _ocs; + final ApiOcs _ocs; } -class _OcsDavDirect { - _OcsDavDirect(this._dav); +class ApiOcsDavDirect { + ApiOcsDavDirect(this._dav); Future post({ required int fileId, @@ -490,23 +490,23 @@ class _OcsDavDirect { } } - final _OcsDav _dav; + final ApiOcsDav _dav; static final _log = Logger("api.api._OcsDavDirect"); } -class _OcsFacerecognition { - _OcsFacerecognition(this._ocs); +class ApiOcsFacerecognition { + ApiOcsFacerecognition(this._ocs); - _OcsFacerecognitionPersons persons() => _OcsFacerecognitionPersons(this); - _OcsFacerecognitionPerson person(String name) => - _OcsFacerecognitionPerson(this, name); + ApiOcsFacerecognitionPersons persons() => ApiOcsFacerecognitionPersons(this); + ApiOcsFacerecognitionPerson person(String name) => + ApiOcsFacerecognitionPerson(this, name); - final _Ocs _ocs; + final ApiOcs _ocs; } -class _OcsFacerecognitionPersons { - _OcsFacerecognitionPersons(this._facerecognition); +class ApiOcsFacerecognitionPersons { + ApiOcsFacerecognitionPersons(this._facerecognition); Future get() async { try { @@ -526,23 +526,23 @@ class _OcsFacerecognitionPersons { } } - final _OcsFacerecognition _facerecognition; + final ApiOcsFacerecognition _facerecognition; static final _log = Logger("api.api._OcsFacerecognitionPersons"); } -class _OcsFacerecognitionPerson { - _OcsFacerecognitionPerson(this._facerecognition, this._name); +class ApiOcsFacerecognitionPerson { + ApiOcsFacerecognitionPerson(this._facerecognition, this._name); - _OcsFacerecognitionPersonFaces faces() => - _OcsFacerecognitionPersonFaces(this); + ApiOcsFacerecognitionPersonFaces faces() => + ApiOcsFacerecognitionPersonFaces(this); - final _OcsFacerecognition _facerecognition; + final ApiOcsFacerecognition _facerecognition; final String _name; } -class _OcsFacerecognitionPersonFaces { - _OcsFacerecognitionPersonFaces(this._person); +class ApiOcsFacerecognitionPersonFaces { + ApiOcsFacerecognitionPersonFaces(this._person); Future get() async { try { @@ -562,24 +562,24 @@ class _OcsFacerecognitionPersonFaces { } } - final _OcsFacerecognitionPerson _person; + final ApiOcsFacerecognitionPerson _person; static final _log = Logger("api.api._OcsFacerecognitionPersonFaces"); } -class _OcsFilesSharing { - _OcsFilesSharing(this._ocs); +class ApiOcsFilesSharing { + ApiOcsFilesSharing(this._ocs); - _OcsFilesSharingShares shares() => _OcsFilesSharingShares(this); - _OcsFilesSharingShare share(String shareId) => - _OcsFilesSharingShare(this, shareId); - _OcsFilesSharingSharees sharees() => _OcsFilesSharingSharees(this); + ApiOcsFilesSharingShares shares() => ApiOcsFilesSharingShares(this); + ApiOcsFilesSharingShare share(String shareId) => + ApiOcsFilesSharingShare(this, shareId); + ApiOcsFilesSharingSharees sharees() => ApiOcsFilesSharingSharees(this); - final _Ocs _ocs; + final ApiOcs _ocs; } -class _OcsFilesSharingShares { - _OcsFilesSharingShares(this._filesSharing); +class ApiOcsFilesSharingShares { + ApiOcsFilesSharingShares(this._filesSharing); /// Get Shares from a specific file or folder /// @@ -652,19 +652,19 @@ class _OcsFilesSharingShares { } } - final _OcsFilesSharing _filesSharing; + final ApiOcsFilesSharing _filesSharing; static final _log = Logger("api.api._OcsFilesSharingShares"); } -class _OcsFilesSharingShare { - _OcsFilesSharingShare(this._filesSharing, this._shareId); +class ApiOcsFilesSharingShare { + ApiOcsFilesSharingShare(this._filesSharing, this._shareId); /// Remove the given share /// /// See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#delete-share /// * The type of share ID is listed as int in the document, however, the - /// share ID returned in [_OcsFilesSharingShares.get] is actually a string. To + /// share ID returned in [ApiOcsFilesSharingShares.get] is actually a string. To /// keep it consistent, we'll use string instead Future delete() async { try { @@ -681,14 +681,14 @@ class _OcsFilesSharingShare { } } - final _OcsFilesSharing _filesSharing; + final ApiOcsFilesSharing _filesSharing; final String _shareId; static final _log = Logger("api.api._OcsFilesSharingShare"); } -class _OcsFilesSharingSharees { - _OcsFilesSharingSharees(this._filesSharing); +class ApiOcsFilesSharingSharees { + ApiOcsFilesSharingSharees(this._filesSharing); /// Get all sharees matching a search term /// @@ -720,13 +720,13 @@ class _OcsFilesSharingSharees { } } - final _OcsFilesSharing _filesSharing; + final ApiOcsFilesSharing _filesSharing; static final _log = Logger("api.api._OcsFilesSharingSharees"); } -class _Systemtags { - const _Systemtags(this.api); +class ApiSystemtags { + const ApiSystemtags(this.api); Future propfind({ id, @@ -791,17 +791,17 @@ class _Systemtags { static final _log = Logger("api.api._Systemtags"); } -class _SystemtagsRelations { - const _SystemtagsRelations(this.api); +class ApiSystemtagsRelations { + const ApiSystemtagsRelations(this.api); - _SystemtagsRelationsFiles files(int fileId) => - _SystemtagsRelationsFiles(this, fileId); + ApiSystemtagsRelationsFiles files(int fileId) => + ApiSystemtagsRelationsFiles(this, fileId); final Api api; } -class _SystemtagsRelationsFiles { - const _SystemtagsRelationsFiles(this.systemtagsRelations, this.fileId); +class ApiSystemtagsRelationsFiles { + const ApiSystemtagsRelationsFiles(this.systemtagsRelations, this.fileId); /// List systemtags associated with a file /// @@ -864,7 +864,7 @@ class _SystemtagsRelationsFiles { } } - final _SystemtagsRelations systemtagsRelations; + final ApiSystemtagsRelations systemtagsRelations; final int fileId; static final _log = Logger("api.api._SystemtagsRelationsFiles"); diff --git a/app/lib/event/native_event.dart b/app/lib/event/native_event.dart index 1fcaa54f..f8bca097 100644 --- a/app/lib/event/native_event.dart +++ b/app/lib/event/native_event.dart @@ -25,7 +25,7 @@ class NativeEventListener { _subscription = null; } - static late final _mappedStream = + static final _mappedStream = NativeEvent.stream.whereType().map((ev) { switch (ev.event) { case FileExifUpdatedEvent._id: diff --git a/app/lib/mobile/android/download.dart b/app/lib/mobile/android/download.dart index 086376be..e3bac793 100644 --- a/app/lib/mobile/android/download.dart +++ b/app/lib/mobile/android/download.dart @@ -12,7 +12,7 @@ class DownloadEvent { static const _downloadCancelChannel = EventChannel( "com.nkming.nc_photos/download_event/action_download_cancel"); - static late final _cancelStream = _downloadCancelChannel + static final _cancelStream = _downloadCancelChannel .receiveBroadcastStream() .map((data) => DownloadCancelEvent( data["notificationId"], diff --git a/app/lib/service.dart b/app/lib/service.dart index de454242..038ed9fb 100644 --- a/app/lib/service.dart +++ b/app/lib/service.dart @@ -210,7 +210,7 @@ class _L10n { } } - static late final _inst = _L10n._(); + static final _inst = _L10n._(); late AppLocalizations _l10n; static final _log = Logger("service._L10n"); diff --git a/app/lib/web/google_gps_map.dart b/app/lib/web/google_gps_map.dart index 5248dc6e..5507ed1a 100644 --- a/app/lib/web/google_gps_map.dart +++ b/app/lib/web/google_gps_map.dart @@ -1,9 +1,9 @@ // ignore: avoid_web_libraries_in_flutter import 'dart:html'; -import 'package:/nc_photos/mobile/ui_hack.dart' if (dart.library.html) 'dart:ui' - as ui; import 'package:flutter/widgets.dart'; +import 'package:nc_photos/mobile/ui_hack.dart' if (dart.library.html) 'dart:ui' + as ui; import 'package:tuple/tuple.dart'; class GoogleGpsMap extends StatefulWidget { diff --git a/app/lib/widget/album_browser_mixin.dart b/app/lib/widget/album_browser_mixin.dart index 865c0c43..ff5e1340 100644 --- a/app/lib/widget/album_browser_mixin.dart +++ b/app/lib/widget/album_browser_mixin.dart @@ -231,11 +231,11 @@ mixin AlbumBrowserMixin )(); } catch (e, stackTrace) { _log.shout( - "[_onAddToCollectionPressed] Failed while ImportPendingSharedAlbum: ${logFilename(album.albumFile?.path)}", + "[_onAddToCollectionPressed] Failed while _onAddToCollectionPressed: ${logFilename(album.albumFile?.path)}", e, stackTrace); } - if (newAlbum != null) { + if (newAlbum != null && mounted) { album_browser_util.pushReplacement(context, account, newAlbum!); } } diff --git a/app/lib/widget/album_importer.dart b/app/lib/widget/album_importer.dart index 1c537548..6bea7450 100644 --- a/app/lib/widget/album_importer.dart +++ b/app/lib/widget/album_importer.dart @@ -178,7 +178,7 @@ class _AlbumImporterState extends State { icon: AnimatedSwitcher( duration: k.animationDurationShort, transitionBuilder: (child, animation) => - ScaleTransition(child: child, scale: animation), + ScaleTransition(scale: animation, child: child), child: Icon( isPicked ? Icons.check_box : Icons.check_box_outline_blank, key: ValueKey(isPicked), @@ -218,7 +218,9 @@ class _AlbumImporterState extends State { // make sure we dismiss the dialog in any cases Navigator.of(context).pop(); } - Navigator.of(context).pop(); + if (mounted) { + Navigator.of(context).pop(); + } } Future _createAllAlbums(BuildContext context) async { diff --git a/app/lib/widget/dir_picker.dart b/app/lib/widget/dir_picker.dart index ad6bc295..74d9b683 100644 --- a/app/lib/widget/dir_picker.dart +++ b/app/lib/widget/dir_picker.dart @@ -95,11 +95,11 @@ class DirPickerState extends State { duration: k.animationDurationNormal, // see AnimatedSwitcher.defaultLayoutBuilder layoutBuilder: (currentChild, previousChildren) => Stack( + alignment: Alignment.topLeft, children: [ ...previousChildren, if (currentChild != null) currentChild, ], - alignment: Alignment.topLeft, ), // needed to prevent background color overflowing the parent bound, see: // https://github.com/flutter/flutter/issues/86584 @@ -171,7 +171,7 @@ class DirPickerState extends State { icon: AnimatedSwitcher( duration: k.animationDurationShort, transitionBuilder: (child, animation) => - ScaleTransition(child: child, scale: animation), + ScaleTransition(scale: animation, child: child), child: Icon( iconData, key: ValueKey(pickState), diff --git a/app/lib/widget/draggable.dart b/app/lib/widget/draggable.dart index 8621eb9f..5a9b29a7 100644 --- a/app/lib/widget/draggable.dart +++ b/app/lib/widget/draggable.dart @@ -57,11 +57,11 @@ class Draggable extends StatelessWidget { ), ), ), - child: child, childWhenDragging: Opacity( opacity: .25, child: child, ), + child: child, ), ), if (onDropBefore != null || onDropAfter != null) diff --git a/app/lib/widget/draggable_item_list_mixin.dart b/app/lib/widget/draggable_item_list_mixin.dart index 7e314504..21c909b2 100644 --- a/app/lib/widget/draggable_item_list_mixin.dart +++ b/app/lib/widget/draggable_item_list_mixin.dart @@ -44,13 +44,13 @@ mixin DraggableItemListMixin on State { final item = _items[index]; return my.Draggable( data: item, - child: item.buildWidget(context), feedback: item.buildDragFeedbackWidget(context), onDropBefore: item.onDropBefore, onDropAfter: item.onDropAfter, onDragStarted: item.onDragStarted, onDragEndedAny: item.onDragEndedAny, feedbackSize: Size(_maxCrossAxisExtent * .65, _maxCrossAxisExtent * .65), + child: item.buildWidget(context), ); } diff --git a/app/lib/widget/photo_date_time_edit_dialog.dart b/app/lib/widget/photo_date_time_edit_dialog.dart index 62c1dc57..a1e89c13 100644 --- a/app/lib/widget/photo_date_time_edit_dialog.dart +++ b/app/lib/widget/photo_date_time_edit_dialog.dart @@ -33,6 +33,7 @@ class _PhotoDateTimeEditDialogState extends State { Row( children: [ Flexible( + flex: 1, child: TextFormField( decoration: InputDecoration( hintText: L10n.global().dateYearInputHint, @@ -51,10 +52,10 @@ class _PhotoDateTimeEditDialogState extends State { }, initialValue: "${widget.initialDateTime.year}", ), - flex: 1, ), const SizedBox(width: 4), Flexible( + flex: 1, child: TextFormField( decoration: InputDecoration( hintText: L10n.global().dateMonthInputHint, @@ -72,10 +73,10 @@ class _PhotoDateTimeEditDialogState extends State { initialValue: widget.initialDateTime.month.toString().padLeft(2, "0"), ), - flex: 1, ), const SizedBox(width: 4), Flexible( + flex: 1, child: TextFormField( decoration: InputDecoration( hintText: L10n.global().dateDayInputHint, @@ -93,7 +94,6 @@ class _PhotoDateTimeEditDialogState extends State { initialValue: widget.initialDateTime.day.toString().padLeft(2, "0"), ), - flex: 1, ), ], ), @@ -105,6 +105,7 @@ class _PhotoDateTimeEditDialogState extends State { Row( children: [ Flexible( + flex: 1, child: TextFormField( decoration: InputDecoration( hintText: L10n.global().timeHourInputHint, @@ -122,10 +123,10 @@ class _PhotoDateTimeEditDialogState extends State { initialValue: widget.initialDateTime.hour.toString().padLeft(2, "0"), ), - flex: 1, ), const SizedBox(width: 4), Flexible( + flex: 1, child: TextFormField( decoration: InputDecoration( hintText: L10n.global().timeMinuteInputHint, @@ -144,12 +145,11 @@ class _PhotoDateTimeEditDialogState extends State { .toString() .padLeft(2, "0"), ), - flex: 1, ), const SizedBox(width: 4), const Flexible( - child: SizedBox(), flex: 1, + child: SizedBox(), ), ], ), diff --git a/app/lib/widget/settings.dart b/app/lib/widget/settings.dart index 0e359e21..c62abc67 100644 --- a/app/lib/widget/settings.dart +++ b/app/lib/widget/settings.dart @@ -1504,6 +1504,6 @@ enum _Experiment { sharedAlbum, } -late final _enabledExperiments = [ +final _enabledExperiments = [ _Experiment.sharedAlbum, ]; diff --git a/app/lib/widget/share_album_dialog.dart b/app/lib/widget/share_album_dialog.dart index 19b2a8ab..5b7b6e40 100644 --- a/app/lib/widget/share_album_dialog.dart +++ b/app/lib/widget/share_album_dialog.dart @@ -100,6 +100,7 @@ class _ShareAlbumDialogState extends State { ); } return SimpleDialogOption( + onPressed: isProcessing ? () {} : () => _onShareItemPressed(share), child: ListTile( title: Text(share.displayName), subtitle: Text(share.shareWith.toString()), @@ -108,7 +109,6 @@ class _ShareAlbumDialogState extends State { child: trailing, ), ), - onPressed: isProcessing ? () {} : () => _onShareItemPressed(share), ); } diff --git a/app/lib/widget/shared_file_viewer.dart b/app/lib/widget/shared_file_viewer.dart index 6584a62f..9a79dd17 100644 --- a/app/lib/widget/shared_file_viewer.dart +++ b/app/lib/widget/shared_file_viewer.dart @@ -226,7 +226,9 @@ class _SharedFileViewerState extends State { } } } finally { - Navigator.of(context).pop(); + if (mounted) { + Navigator.of(context).pop(); + } } } else { setState(() { diff --git a/app/lib/widget/slideshow_dialog.dart b/app/lib/widget/slideshow_dialog.dart index a933df14..5ceef56b 100644 --- a/app/lib/widget/slideshow_dialog.dart +++ b/app/lib/widget/slideshow_dialog.dart @@ -73,6 +73,7 @@ class _SlideshowDialogState extends State { Row( children: [ Flexible( + flex: 1, child: TextFormField( decoration: InputDecoration( hintText: L10n.global().timeMinuteInputHint, @@ -98,12 +99,12 @@ class _SlideshowDialogState extends State { initialValue: widget.duration.inMinutes.toString().padLeft(2, "0"), ), - flex: 1, ), const SizedBox(width: 4), const Text(":"), const SizedBox(width: 4), Flexible( + flex: 1, child: TextFormField( decoration: InputDecoration( hintText: L10n.global().timeSecondInputHint, @@ -130,7 +131,6 @@ class _SlideshowDialogState extends State { .toString() .padLeft(2, "0"), ), - flex: 1, ), ], ), diff --git a/app/lib/widget/trashbin_viewer.dart b/app/lib/widget/trashbin_viewer.dart index 2fd409d5..f68e4d13 100644 --- a/app/lib/widget/trashbin_viewer.dart +++ b/app/lib/widget/trashbin_viewer.dart @@ -172,7 +172,9 @@ class _TrashbinViewerState extends State { content: Text(L10n.global().restoreSuccessNotification), duration: k.snackBarDurationNormal, )); - Navigator.of(context).pop(); + if (mounted) { + Navigator.of(context).pop(); + } } catch (e, stacktrace) { _log.shout("Failed while restore trashbin: ${logFilename(file.path)}", e, stacktrace); @@ -314,7 +316,7 @@ class _TrashbinViewerState extends State { shouldCleanupAlbum: false, isRemoveOpened: true, ); - if (count > 0) { + if (count > 0 && mounted) { Navigator.of(context).pop(); } } diff --git a/app/lib/widget/viewer.dart b/app/lib/widget/viewer.dart index b043b4b9..7997e67c 100644 --- a/app/lib/widget/viewer.dart +++ b/app/lib/widget/viewer.dart @@ -599,7 +599,7 @@ class _ViewerState extends State isRemoveOpened: true, isMoveToTrash: true, ); - if (count > 0) { + if (count > 0 && mounted) { Navigator.of(context).pop(); } } diff --git a/app/pubspec.lock b/app/pubspec.lock index d63c13e2..f3809f4f 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -398,7 +398,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_localizations: dependency: "direct main" description: flutter @@ -571,7 +571,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" lists: dependency: transitive description: @@ -839,12 +839,12 @@ packages: source: hosted version: "2.1.0" quiver: - dependency: transitive + dependency: "direct main" description: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "3.0.1+1" + version: "3.1.0" rxdart: dependency: transitive description: @@ -1152,12 +1152,12 @@ packages: source: hosted version: "3.0.1" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.5" + version: "3.0.6" vector_math: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index b05c840b..f77fcd41 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -84,6 +84,7 @@ dependencies: page_view_indicators: ^2.0.0 path: ^1.8.0 path_provider: ^2.0.6 + quiver: ^3.1.0 screen_brightness: ^0.1.1 shared_preferences: ^2.0.8 # android/ios only @@ -91,6 +92,7 @@ dependencies: synchronized: ^3.0.0 tuple: ^2.0.0 url_launcher: ^6.0.3 + uuid: ^3.0.6 video_player: git: url: https://gitlab.com/nc-photos/flutter-plugins @@ -104,7 +106,7 @@ dependencies: dev_dependencies: test: any bloc_test: any - flutter_lints: ^1.0.4 + flutter_lints: ^2.0.1 # flutter_test: # sdk: flutter # integration_test: