NullSafety: Apply dart migrate suggestions + compilation fixes

This commit is contained in:
Neeraj Gupta 2022-12-30 17:40:17 +05:30
parent 0e62793b7b
commit d6ad004354
No known key found for this signature in database
GPG key ID: 3C5A1684DC1729E1
89 changed files with 1232 additions and 1241 deletions

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io';
@ -23,7 +23,7 @@ class EnteApp extends StatefulWidget {
const EnteApp(
this.runBackgroundTask,
this.killBackgroundTask, {
Key key,
Key? key,
}) : super(key: key);
@override

View file

@ -614,7 +614,7 @@ class Configuration {
return _preferences.setBool(keyShouldHideFromRecents, value);
}
void setVolatilePassword(String volatilePassword) {
void setVolatilePassword(String? volatilePassword) {
_volatilePassword = volatilePassword;
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:io';
@ -230,7 +230,7 @@ Future<bool> _isRunningInForeground() async {
(currentTime - kFGTaskDeathTimeoutInMicroseconds);
}
Future<void> _killBGTask([String taskId]) async {
Future<void> _killBGTask([String? taskId]) async {
await UploadLocksDB.instance.releaseLocksAcquiredByOwnerBefore(
ProcessType.background.toString(),
DateTime.now().microsecondsSinceEpoch,
@ -281,7 +281,7 @@ Future<void> _logFGHeartBeatInfo() async {
_logger.info('isAlreaduunningFG: $isRunningInFG, last Beat: $lastRun');
}
void _scheduleSuicide(Duration duration, [String taskID]) {
void _scheduleSuicide(Duration duration, [String? taskID]) {
final taskIDVal = taskID ?? 'no taskID';
_logger.warning("Schedule seppuku taskID: $taskIDVal");
Future.delayed(duration, () {

View file

@ -16,9 +16,9 @@ class LocalAuthenticationService {
String infoMessage,
) async {
if (await _isLocalAuthSupportedOnDevice()) {
AppLock.of(context).setEnabled(false);
AppLock.of(context)!.setEnabled(false);
final result = await requestAuthentication(infoMessage);
AppLock.of(context).setEnabled(
AppLock.of(context)!.setEnabled(
Configuration.instance.shouldShowLockScreen(),
);
if (!result) {
@ -39,17 +39,17 @@ class LocalAuthenticationService {
String errorDialogTitle = "",
]) async {
if (await _isLocalAuthSupportedOnDevice()) {
AppLock.of(context).disable();
AppLock.of(context)!.disable();
final result = await requestAuthentication(
infoMessage,
);
if (result) {
AppLock.of(context).setEnabled(shouldEnableLockScreen);
AppLock.of(context)!.setEnabled(shouldEnableLockScreen);
await Configuration.instance
.setShouldShowLockScreen(shouldEnableLockScreen);
return true;
} else {
AppLock.of(context)
AppLock.of(context)!
.setEnabled(Configuration.instance.shouldShowLockScreen());
}
} else {

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:email_validator/email_validator.dart';
import 'package:flutter/gestures.dart';
@ -13,7 +13,7 @@ import 'package:photos/ui/common/web_page.dart';
import 'package:step_progress_indicator/step_progress_indicator.dart';
class EmailEntryPage extends StatefulWidget {
const EmailEntryPage({Key key}) : super(key: key);
const EmailEntryPage({Key? key}) : super(key: key);
@override
State<EmailEntryPage> createState() => _EmailEntryPageState();
@ -28,13 +28,13 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
final _passwordController2 = TextEditingController();
final Color _validFieldValueColor = const Color.fromRGBO(45, 194, 98, 0.2);
String _email;
String _password;
String? _email;
String? _password;
String _cnfPassword = '';
double _passwordStrength = 0.0;
bool _emailIsValid = false;
bool _hasAgreedToTOS = true;
bool _hasAgreedToE2E = false;
bool? _hasAgreedToTOS = true;
bool? _hasAgreedToE2E = false;
bool _password1Visible = false;
bool _password2Visible = false;
bool _passwordsMatch = false;
@ -65,7 +65,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Widget build(BuildContext context) {
final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
FloatingActionButtonLocation fabLocation() {
FloatingActionButtonLocation? fabLocation() {
if (isKeypadOpen) {
return null;
} else {
@ -104,9 +104,9 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
buttonText: 'Create account',
onPressedFunction: () {
_config.setVolatilePassword(_passwordController1.text);
UserService.instance.setEmail(_email);
UserService.instance.setEmail(_email!);
UserService.instance
.sendOtt(context, _email, isCreateAccountScreen: true);
.sendOtt(context, _email!, isCreateAccountScreen: true);
FocusScope.of(context).unfocus();
},
),
@ -162,7 +162,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
size: 20,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.focusedBorder!
.borderSide
.color,
)
@ -170,9 +170,9 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
),
onChanged: (value) {
_email = value.trim();
if (_emailIsValid != EmailValidator.validate(_email)) {
if (_emailIsValid != EmailValidator.validate(_email!)) {
setState(() {
_emailIsValid = EmailValidator.validate(_email);
_emailIsValid = EmailValidator.validate(_email!);
});
}
},
@ -220,7 +220,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Icons.check,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.focusedBorder!
.borderSide
.color,
)
@ -287,7 +287,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Icons.check,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.focusedBorder!
.borderSide
.color,
)
@ -352,7 +352,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
return GestureDetector(
onTap: () {
setState(() {
_hasAgreedToTOS = !_hasAgreedToTOS;
_hasAgreedToTOS = !_hasAgreedToTOS!;
});
},
behavior: HitTestBehavior.translucent,
@ -416,7 +416,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
],
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 12),
),
textAlign: TextAlign.left,
@ -431,7 +431,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
return GestureDetector(
onTap: () {
setState(() {
_hasAgreedToE2E = !_hasAgreedToE2E;
_hasAgreedToE2E = !_hasAgreedToE2E!;
});
},
behavior: HitTestBehavior.translucent,
@ -477,7 +477,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
],
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 12),
),
textAlign: TextAlign.left,
@ -491,8 +491,8 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
bool _isFormValid() {
return _emailIsValid &&
_passwordsMatch &&
_hasAgreedToTOS &&
_hasAgreedToE2E &&
_hasAgreedToTOS! &&
_hasAgreedToE2E! &&
_passwordIsValid;
}
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:email_validator/email_validator.dart';
import 'package:flutter/gestures.dart';
@ -9,7 +9,7 @@ import 'package:photos/ui/common/dynamic_fab.dart';
import 'package:photos/ui/common/web_page.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key key}) : super(key: key);
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
@ -18,8 +18,8 @@ class LoginPage extends StatefulWidget {
class _LoginPageState extends State<LoginPage> {
final _config = Configuration.instance;
bool _emailIsValid = false;
String _email;
Color _emailInputFieldColor;
String? _email;
Color? _emailInputFieldColor;
@override
void initState() {
@ -31,7 +31,7 @@ class _LoginPageState extends State<LoginPage> {
Widget build(BuildContext context) {
final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
FloatingActionButtonLocation fabLocation() {
FloatingActionButtonLocation? fabLocation() {
if (isKeypadOpen) {
return null;
} else {
@ -57,9 +57,9 @@ class _LoginPageState extends State<LoginPage> {
isFormValid: _emailIsValid,
buttonText: 'Log in',
onPressedFunction: () {
UserService.instance.setEmail(_email);
UserService.instance.setEmail(_email!);
UserService.instance
.sendOtt(context, _email, isCreateAccountScreen: false);
.sendOtt(context, _email!, isCreateAccountScreen: false);
FocusScope.of(context).unfocus();
},
),
@ -105,7 +105,7 @@ class _LoginPageState extends State<LoginPage> {
size: 20,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.focusedBorder!
.borderSide
.color,
)
@ -114,7 +114,7 @@ class _LoginPageState extends State<LoginPage> {
onChanged: (value) {
setState(() {
_email = value.trim();
_emailIsValid = EmailValidator.validate(_email);
_emailIsValid = EmailValidator.validate(_email!);
if (_emailIsValid) {
_emailInputFieldColor =
const Color.fromRGBO(45, 194, 98, 0.2);
@ -145,7 +145,7 @@ class _LoginPageState extends State<LoginPage> {
text: TextSpan(
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 12),
children: [
const TextSpan(

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
@ -15,7 +15,7 @@ class OTTVerificationPage extends StatefulWidget {
this.email, {
this.isChangeEmail = false,
this.isCreateAccountScreen = false,
Key key,
Key? key,
}) : super(key: key);
@override
@ -29,7 +29,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
Widget build(BuildContext context) {
final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
FloatingActionButtonLocation fabLocation() {
FloatingActionButtonLocation? fabLocation() {
if (isKeypadOpen) {
return null;
} else {
@ -114,7 +114,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
text: TextSpan(
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 14),
children: [
const TextSpan(text: "We've sent a mail to "),
@ -134,7 +134,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
'Please check your inbox (and spam) to complete verification',
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 14),
),
],
@ -187,7 +187,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
},
child: Text(
"Resend email",
style: Theme.of(context).textTheme.subtitle1.copyWith(
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -26,7 +26,7 @@ enum PasswordEntryMode {
class PasswordEntryPage extends StatefulWidget {
final PasswordEntryMode mode;
const PasswordEntryPage({this.mode = PasswordEntryMode.set, Key key})
const PasswordEntryPage({this.mode = PasswordEntryMode.set, Key? key})
: super(key: key);
@override
@ -41,7 +41,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
final _passwordController1 = TextEditingController(),
_passwordController2 = TextEditingController();
final Color _validFieldValueColor = const Color.fromRGBO(45, 194, 98, 0.2);
String _volatilePassword;
String? _volatilePassword;
String _passwordInInputBox = '';
String _passwordInInputConfirmationBox = '';
double _passwordStrength = 0.0;
@ -62,7 +62,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
if (_volatilePassword != null) {
Future.delayed(
Duration.zero,
() => _showRecoveryCodeDialog(_volatilePassword),
() => _showRecoveryCodeDialog(_volatilePassword!),
);
}
_password1FocusNode.addListener(() {
@ -81,7 +81,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
Widget build(BuildContext context) {
final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
FloatingActionButtonLocation fabLocation() {
FloatingActionButtonLocation? fabLocation() {
if (isKeypadOpen) {
return null;
} else {
@ -167,7 +167,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
textAlign: TextAlign.start,
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 14),
),
),
@ -178,7 +178,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
text: TextSpan(
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 14),
children: [
const TextSpan(
@ -187,7 +187,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
),
TextSpan(
text: "we cannot decrypt your data",
style: Theme.of(context).textTheme.subtitle1.copyWith(
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
@ -245,7 +245,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
Icons.check,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.focusedBorder!
.borderSide
.color,
)
@ -307,7 +307,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
Icons.check,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.focusedBorder!
.borderSide
.color,
)
@ -364,7 +364,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
child: RichText(
text: TextSpan(
text: "How it works",
style: Theme.of(context).textTheme.subtitle1.copyWith(
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -17,7 +17,7 @@ import 'package:photos/utils/dialog_util.dart';
import 'package:photos/utils/email_util.dart';
class PasswordReentryPage extends StatefulWidget {
const PasswordReentryPage({Key key}) : super(key: key);
const PasswordReentryPage({Key? key}) : super(key: key);
@override
State<PasswordReentryPage> createState() => _PasswordReentryPageState();
@ -27,7 +27,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
final _logger = Logger((_PasswordReentryPageState).toString());
final _passwordController = TextEditingController();
final FocusNode _passwordFocusNode = FocusNode();
String email;
String? email;
bool _passwordInFocus = false;
bool _passwordVisible = false;
@ -46,7 +46,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
Widget build(BuildContext context) {
final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
FloatingActionButtonLocation fabLocation() {
FloatingActionButtonLocation? fabLocation() {
if (isKeypadOpen) {
return null;
} else {
@ -78,7 +78,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
try {
await Configuration.instance.decryptAndSaveSecrets(
_passwordController.text,
Configuration.instance.getKeyAttributes(),
Configuration.instance.getKeyAttributes()!,
);
} on KeyDerivationError catch (e, s) {
_logger.severe("Password verification failed", e, s);
@ -245,7 +245,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
child: Text(
"Forgot password",
style:
Theme.of(context).textTheme.subtitle1.copyWith(
Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
@ -267,7 +267,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
child: Text(
"Change email",
style:
Theme.of(context).textTheme.subtitle1.copyWith(
Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io' as io;
@ -15,20 +15,20 @@ import 'package:share_plus/share_plus.dart';
import 'package:step_progress_indicator/step_progress_indicator.dart';
class RecoveryKeyPage extends StatefulWidget {
final bool showAppBar;
final bool? showAppBar;
final String recoveryKey;
final String doneText;
final Function() onDone;
final bool isDismissible;
final String title;
final String text;
final String subText;
final Function()? onDone;
final bool? isDismissible;
final String? title;
final String? text;
final String? subText;
final bool showProgressBar;
const RecoveryKeyPage(
this.recoveryKey,
this.doneText, {
Key key,
Key? key,
this.showAppBar,
this.onDone,
this.isDismissible,
@ -56,7 +56,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
'recovery code should have $mnemonicKeyWordCount words',
);
}
final double topPadding = widget.showAppBar
final double topPadding = widget.showAppBar!
? 40
: widget.showProgressBar
? 32
@ -79,7 +79,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
),
),
)
: widget.showAppBar
: widget.showAppBar!
? AppBar(
elevation: 0,
title: Text(widget.title ?? "Recovery key"),
@ -100,14 +100,14 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.showAppBar
widget.showAppBar!
? const SizedBox.shrink()
: Text(
widget.title ?? "Recovery key",
style: Theme.of(context).textTheme.headline4,
),
Padding(
padding: EdgeInsets.all(widget.showAppBar ? 0 : 12),
padding: EdgeInsets.all(widget.showAppBar! ? 0 : 12),
),
Text(
widget.text ??
@ -263,6 +263,6 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
if (_recoveryKeyFile.existsSync()) {
await _recoveryKeyFile.delete();
}
widget.onDone();
widget.onDone!();
}
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:ui';
@ -10,7 +10,7 @@ import 'package:photos/utils/dialog_util.dart';
import 'package:photos/utils/toast_util.dart';
class RecoveryPage extends StatefulWidget {
const RecoveryPage({Key key}) : super(key: key);
const RecoveryPage({Key? key}) : super(key: key);
@override
State<RecoveryPage> createState() => _RecoveryPageState();
@ -22,7 +22,7 @@ class _RecoveryPageState extends State<RecoveryPage> {
@override
Widget build(BuildContext context) {
final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
FloatingActionButtonLocation fabLocation() {
FloatingActionButtonLocation? fabLocation() {
if (isKeypadOpen) {
return null;
} else {
@ -140,7 +140,7 @@ class _RecoveryPageState extends State<RecoveryPage> {
child: Text(
"No recovery key?",
style:
Theme.of(context).textTheme.subtitle1.copyWith(
Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:io';
import 'dart:ui';
@ -24,9 +22,9 @@ class BackupFolderSelectionPage extends StatefulWidget {
final String buttonText;
const BackupFolderSelectionPage({
@required this.buttonText,
required this.buttonText,
this.isOnboarding = false,
Key key,
Key? key,
}) : super(key: key);
@override
@ -38,8 +36,8 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
final Logger _logger = Logger((_BackupFolderSelectionPageState).toString());
final Set<String> _allDevicePathIDs = <String>{};
final Set<String> _selectedDevicePathIDs = <String>{};
List<DeviceCollection> _deviceCollections;
Map<String, int> _pathIDToItemCount;
List<DeviceCollection>? _deviceCollections;
Map<String, int>? _pathIDToItemCount;
@override
void initState() {
@ -50,10 +48,10 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
await FilesDB.instance.getDevicePathIDToImportedFileCount();
setState(() {
_deviceCollections = files;
_deviceCollections.sort((first, second) {
_deviceCollections!.sort((first, second) {
return first.name.toLowerCase().compareTo(second.name.toLowerCase());
});
for (final file in _deviceCollections) {
for (final file in _deviceCollections!) {
_allDevicePathIDs.add(file.id);
if (file.shouldBackup) {
_selectedDevicePathIDs.add(file.id);
@ -103,7 +101,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
padding: const EdgeInsets.only(left: 24, right: 48),
child: Text(
"Selected folders will be encrypted and backed up",
style: Theme.of(context).textTheme.caption.copyWith(height: 1.3),
style: Theme.of(context).textTheme.caption!.copyWith(height: 1.3),
),
),
const Padding(
@ -139,7 +137,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
} else {
_selectedDevicePathIDs.addAll(_allDevicePathIDs);
}
_deviceCollections.sort((first, second) {
_deviceCollections!.sort((first, second) {
return first.name
.toLowerCase()
.compareTo(second.name.toLowerCase());
@ -191,7 +189,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
},
child: Text(
"Skip",
style: Theme.of(context).textTheme.caption.copyWith(
style: Theme.of(context).textTheme.caption!.copyWith(
decoration: TextDecoration.underline,
),
),
@ -247,11 +245,11 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
padding: const EdgeInsets.only(right: 4),
child: ImplicitlyAnimatedReorderableList<DeviceCollection>(
controller: scrollController,
items: _deviceCollections,
items: _deviceCollections!,
areItemsTheSame: (oldItem, newItem) => oldItem.id == newItem.id,
onReorderFinished: (item, from, to, newItems) {
setState(() {
_deviceCollections
_deviceCollections!
..clear()
..addAll(newItems);
});
@ -261,7 +259,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
key: ValueKey(file),
builder: (context, dragAnimation, inDrag) {
final t = dragAnimation.value;
final elevation = lerpDouble(0, 8, t);
final elevation = lerpDouble(0, 8, t)!;
final themeColor = Theme.of(context).colorScheme.onSurface;
final color =
Color.lerp(themeColor, themeColor.withOpacity(0.8), t);
@ -288,7 +286,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
Widget _getFileItem(DeviceCollection deviceCollection) {
final isSelected = _selectedDevicePathIDs.contains(deviceCollection.id);
final importedCount = _pathIDToItemCount != null
? _pathIDToItemCount[deviceCollection.id] ?? 0
? _pathIDToItemCount![deviceCollection.id] ?? 0
: -1;
return Padding(
padding: const EdgeInsets.only(bottom: 1, right: 1),
@ -326,7 +324,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
activeColor: Colors.white,
value: isSelected,
onChanged: (value) {
if (value) {
if (value!) {
_selectedDevicePathIDs.add(deviceCollection.id);
} else {
_selectedDevicePathIDs.remove(deviceCollection.id);
@ -375,7 +373,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
),
],
),
_getThumbnail(deviceCollection.thumbnail, isSelected),
_getThumbnail(deviceCollection.thumbnail!, isSelected),
],
),
onTap: () {
@ -393,7 +391,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
}
void _sortFiles() {
_deviceCollections.sort((first, second) {
_deviceCollections!.sort((first, second) {
if (_selectedDevicePathIDs.contains(first.id) &&
_selectedDevicePathIDs.contains(second.id)) {
return first.name.toLowerCase().compareTo(second.name.toLowerCase());

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -17,7 +17,7 @@ import 'package:photos/ui/viewer/gallery/empty_state.dart';
class DeviceFoldersGridViewWidget extends StatefulWidget {
const DeviceFoldersGridViewWidget({
Key key,
Key? key,
}) : super(key: key);
@override
@ -27,8 +27,8 @@ class DeviceFoldersGridViewWidget extends StatefulWidget {
class _DeviceFoldersGridViewWidgetState
extends State<DeviceFoldersGridViewWidget> {
StreamSubscription<BackupFoldersUpdatedEvent> _backupFoldersUpdatedEvent;
StreamSubscription<LocalPhotosUpdatedEvent> _localFilesSubscription;
StreamSubscription<BackupFoldersUpdatedEvent>? _backupFoldersUpdatedEvent;
StreamSubscription<LocalPhotosUpdatedEvent>? _localFilesSubscription;
String _loadReason = "init";
@override
@ -65,7 +65,7 @@ class _DeviceFoldersGridViewWidgetState
.getDeviceCollections(includeCoverThumbnail: true),
builder: (context, snapshot) {
if (snapshot.hasData) {
return snapshot.data.isEmpty
return snapshot.data!.isEmpty
? Padding(
padding: const EdgeInsets.all(22),
child: (isMigrationDone
@ -81,10 +81,10 @@ class _DeviceFoldersGridViewWidgetState
physics: const ScrollPhysics(),
// to disable GridView's scrolling
itemBuilder: (context, index) {
final deviceCollection = snapshot.data[index];
final deviceCollection = snapshot.data![index];
return DeviceFolderIcon(deviceCollection);
},
itemCount: snapshot.data.length,
itemCount: snapshot.data!.length,
);
} else if (snapshot.hasError) {
logger.severe("failed to load device gallery", snapshot.error);

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/services/local_authentication_service.dart';
@ -10,7 +10,7 @@ class HiddenCollectionsButtonWidget extends StatelessWidget {
const HiddenCollectionsButtonWidget(
this.textStyle, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -24,7 +24,7 @@ class HiddenCollectionsButtonWidget extends StatelessWidget {
padding: const EdgeInsets.all(0),
side: BorderSide(
width: 0.5,
color: Theme.of(context).iconTheme.color.withOpacity(0.24),
color: Theme.of(context).iconTheme.color!.withOpacity(0.24),
),
),
child: SizedBox(

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:math';
@ -17,11 +17,11 @@ class RemoteCollectionsGridViewWidget extends StatelessWidget {
static const fixedGapBetweenAlbum = 8.0;
static const minGapForHorizontalPadding = 8.0;
final List<CollectionWithThumbnail> collections;
final List<CollectionWithThumbnail>? collections;
const RemoteCollectionsGridViewWidget(
this.collections, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -46,13 +46,13 @@ class RemoteCollectionsGridViewWidget extends StatelessWidget {
physics: const ScrollPhysics(),
// to disable GridView's scrolling
itemBuilder: (context, index) {
if (index < collections.length) {
return CollectionItem(collections[index], sideOfThumbnail);
if (index < collections!.length) {
return CollectionItem(collections![index], sideOfThumbnail);
} else {
return const CreateNewAlbumWidget();
}
},
itemCount: collections.length + 1,
itemCount: collections!.length + 1,
// To include the + button
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: albumsCountInOneRow,

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -26,7 +26,7 @@ import 'package:photos/ui/viewer/gallery/empty_state.dart';
import 'package:photos/utils/local_settings.dart';
class CollectionsGalleryWidget extends StatefulWidget {
const CollectionsGalleryWidget({Key key}) : super(key: key);
const CollectionsGalleryWidget({Key? key}) : super(key: key);
@override
State<CollectionsGalleryWidget> createState() =>
@ -36,10 +36,10 @@ class CollectionsGalleryWidget extends StatefulWidget {
class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
with AutomaticKeepAliveClientMixin {
final _logger = Logger((_CollectionsGalleryWidgetState).toString());
StreamSubscription<LocalPhotosUpdatedEvent> _localFilesSubscription;
StreamSubscription<CollectionUpdatedEvent> _collectionUpdatesSubscription;
StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
AlbumSortKey sortKey;
late StreamSubscription<LocalPhotosUpdatedEvent> _localFilesSubscription;
late StreamSubscription<CollectionUpdatedEvent> _collectionUpdatesSubscription;
late StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
AlbumSortKey? sortKey;
String _loadReason = "init";
@override
@ -98,8 +98,8 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
(first, second) {
if (sortKey == AlbumSortKey.albumName) {
return compareAsciiLowerCaseNatural(
first.collection.name,
second.collection.name,
first.collection.name!,
second.collection.name!,
);
} else if (sortKey == AlbumSortKey.newestPhoto) {
return (second.thumbnail?.creationTime ?? -1 * intMaxValue)
@ -121,13 +121,13 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
}
Widget _getCollectionsGalleryWidget(
List<CollectionWithThumbnail> collections,
List<CollectionWithThumbnail>? collections,
) {
final TextStyle trashAndHiddenTextStyle = Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(
color: Theme.of(context).textTheme.subtitle1.color.withOpacity(0.5),
color: Theme.of(context).textTheme.subtitle1!.color!.withOpacity(0.5),
);
return SingleChildScrollView(
@ -190,9 +190,9 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
}
return Text(
text,
style: Theme.of(context).textTheme.subtitle1.copyWith(
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
color: Theme.of(context).iconTheme.color.withOpacity(0.7),
color: Theme.of(context).iconTheme.color!.withOpacity(0.7),
),
);
}
@ -228,7 +228,7 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
),
onSelected: (int index) async {
sortKey = AlbumSortKey.values[index];
await LocalSettings.instance.setAlbumSortKey(sortKey);
await LocalSettings.instance.setAlbumSortKey(sortKey!);
setState(() {});
},
itemBuilder: (context) {

View file

@ -1,11 +1,11 @@
// @dart=2.9
import 'package:flutter/material.dart';
class DividerWithPadding extends StatelessWidget {
final double left, top, right, bottom, thinckness;
const DividerWithPadding({
Key key,
Key? key,
this.left = 0,
this.top = 0,
this.right = 0,

View file

@ -1,11 +1,11 @@
// @dart=2.9
import 'package:flutter/material.dart';
class BottomShadowWidget extends StatelessWidget {
final double offsetDy;
final Color shadowColor;
const BottomShadowWidget({this.offsetDy = 28, this.shadowColor, Key key})
final Color? shadowColor;
const BottomShadowWidget({this.offsetDy = 28, this.shadowColor, Key? key})
: super(key: key);
@override

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
@ -11,14 +11,14 @@ enum ActionType {
}
// if dialog is dismissed by tapping outside, this will return null
Future<DialogUserChoice> showChoiceDialog<T>(
Future<DialogUserChoice?> showChoiceDialog<T>(
BuildContext context,
String title,
String content, {
String firstAction = 'Ok',
Color firstActionColor,
Color? firstActionColor,
String secondAction = 'Cancel',
Color secondActionColor,
Color? secondActionColor,
ActionType actionType = ActionType.confirm,
}) {
final AlertDialog alert = AlertDialog(

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:math' as math;
@ -6,13 +6,13 @@ import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
class DynamicFAB extends StatelessWidget {
final bool isKeypadOpen;
final bool isFormValid;
final String buttonText;
final Function onPressedFunction;
final bool? isKeypadOpen;
final bool? isFormValid;
final String? buttonText;
final Function? onPressedFunction;
const DynamicFAB({
Key key,
Key? key,
this.isKeypadOpen,
this.buttonText,
this.isFormValid,
@ -21,7 +21,7 @@ class DynamicFAB extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (isKeypadOpen) {
if (isKeypadOpen!) {
return Container(
decoration: BoxDecoration(
boxShadow: [
@ -43,13 +43,13 @@ class DynamicFAB extends StatelessWidget {
Theme.of(context).colorScheme.dynamicFABBackgroundColor,
foregroundColor:
Theme.of(context).colorScheme.dynamicFABTextColor,
onPressed: isFormValid
? onPressedFunction
onPressed: isFormValid!
? onPressedFunction as void Function()?
: () {
FocusScope.of(context).unfocus();
},
child: Transform.rotate(
angle: isFormValid ? 0 : math.pi / 2,
angle: isFormValid! ? 0 : math.pi / 2,
child: const Icon(
Icons.chevron_right,
size: 36,
@ -65,8 +65,8 @@ class DynamicFAB extends StatelessWidget {
height: 56,
padding: const EdgeInsets.symmetric(horizontal: 20),
child: OutlinedButton(
onPressed: isFormValid ? onPressedFunction : null,
child: Text(buttonText),
onPressed: isFormValid! ? onPressedFunction as void Function()? : null,
child: Text(buttonText!),
),
);
}
@ -75,17 +75,17 @@ class DynamicFAB extends StatelessWidget {
class NoScalingAnimation extends FloatingActionButtonAnimator {
@override
Offset getOffset({Offset begin, Offset end, double progress}) {
Offset getOffset({Offset? begin, required Offset end, double? progress}) {
return end;
}
@override
Animation<double> getRotationAnimation({Animation<double> parent}) {
Animation<double> getRotationAnimation({required Animation<double> parent}) {
return Tween<double>(begin: 1.0, end: 1.0).animate(parent);
}
@override
Animation<double> getScaleAnimation({Animation<double> parent}) {
Animation<double> getScaleAnimation({required Animation<double> parent}) {
return Tween<double>(begin: 1.0, end: 1.0).animate(parent);
}
}

View file

@ -1,23 +1,23 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/theme/ente_theme.dart';
class GradientButton extends StatelessWidget {
final List<Color> linearGradientColors;
final Function onTap;
final Function? onTap;
// text is ignored if child is specified
final String text;
// nullable
final IconData iconData;
final IconData? iconData;
// padding between the text and icon
final double paddingValue;
const GradientButton({
Key key,
Key? key,
this.linearGradientColors = const [
Color(0xFF2CD267),
Color(0xFF1DB954),
@ -65,7 +65,7 @@ class GradientButton extends StatelessWidget {
);
}
return InkWell(
onTap: onTap,
onTap: onTap as void Function()?,
child: Container(
height: 56,
decoration: BoxDecoration(

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
@ -6,14 +6,14 @@ import 'package:photos/ente_theme_data.dart';
class LinearProgressDialog extends StatefulWidget {
final String message;
const LinearProgressDialog(this.message, {Key key}) : super(key: key);
const LinearProgressDialog(this.message, {Key? key}) : super(key: key);
@override
LinearProgressDialogState createState() => LinearProgressDialogState();
}
class LinearProgressDialogState extends State<LinearProgressDialog> {
double _progress;
double? _progress;
@override
void initState() {

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'package:flutter/material.dart';
enum ProgressDialogType { normal, download }
@ -7,7 +5,7 @@ enum ProgressDialogType { normal, download }
String _dialogMessage = "Loading...";
double _progress = 0.0, _maxProgress = 100.0;
Widget _customBody;
Widget? _customBody;
TextAlign _textAlign = TextAlign.left;
Alignment _progressWidgetAlignment = Alignment.centerLeft;
@ -15,10 +13,10 @@ Alignment _progressWidgetAlignment = Alignment.centerLeft;
TextDirection _direction = TextDirection.ltr;
bool _isShowing = false;
BuildContext _context, _dismissingContext;
ProgressDialogType _progressDialogType;
BuildContext? _context, _dismissingContext;
ProgressDialogType? _progressDialogType;
bool _barrierDismissible = true, _showLogs = false;
Color _barrierColor;
Color? _barrierColor;
TextStyle _progressTextStyle = const TextStyle(
color: Colors.black,
@ -42,16 +40,16 @@ Widget _progressWidget = Image.asset(
);
class ProgressDialog {
_Body _dialog;
_Body? _dialog;
ProgressDialog(
BuildContext context, {
ProgressDialogType type,
bool isDismissible,
bool showLogs,
TextDirection textDirection,
Widget customBody,
Color barrierColor,
ProgressDialogType? type,
bool? isDismissible,
bool? showLogs,
TextDirection? textDirection,
Widget? customBody,
Color? barrierColor,
}) {
_context = context;
_progressDialogType = type ?? ProgressDialogType.normal;
@ -63,20 +61,20 @@ class ProgressDialog {
}
void style({
Widget child,
double progress,
double maxProgress,
String message,
Widget progressWidget,
Color backgroundColor,
TextStyle progressTextStyle,
TextStyle messageTextStyle,
double elevation,
TextAlign textAlign,
double borderRadius,
Curve insetAnimCurve,
EdgeInsets padding,
Alignment progressWidgetAlignment,
Widget? child,
double? progress,
double? maxProgress,
String? message,
Widget? progressWidget,
Color? backgroundColor,
TextStyle? progressTextStyle,
TextStyle? messageTextStyle,
double? elevation,
TextAlign? textAlign,
double? borderRadius,
Curve? insetAnimCurve,
EdgeInsets? padding,
Alignment? progressWidgetAlignment,
}) {
if (_isShowing) return;
if (_progressDialogType == ProgressDialogType.download) {
@ -100,12 +98,12 @@ class ProgressDialog {
}
void update({
double progress,
double maxProgress,
String message,
Widget progressWidget,
TextStyle progressTextStyle,
TextStyle messageTextStyle,
double? progress,
double? maxProgress,
String? message,
Widget? progressWidget,
TextStyle? progressTextStyle,
TextStyle? messageTextStyle,
}) {
if (_progressDialogType == ProgressDialogType.download) {
_progress = progress ?? _progress;
@ -117,7 +115,7 @@ class ProgressDialog {
_messageStyle = messageTextStyle ?? _messageStyle;
_progressTextStyle = progressTextStyle ?? _progressTextStyle;
if (_isShowing) _dialog.update();
if (_isShowing) _dialog!.update();
}
bool isShowing() {
@ -128,7 +126,9 @@ class ProgressDialog {
try {
if (_isShowing) {
_isShowing = false;
Navigator.of(_dismissingContext).pop();
if (_dismissingContext != null) {
Navigator.of(_dismissingContext!).pop();
}
if (_showLogs) debugPrint('ProgressDialog dismissed');
return Future.value(true);
} else {
@ -147,7 +147,7 @@ class ProgressDialog {
if (!_isShowing) {
_dialog = _Body();
showDialog<dynamic>(
context: _context,
context: _context!,
barrierDismissible: _barrierDismissible,
barrierColor: _barrierColor,
builder: (BuildContext context) {

View file

@ -1,14 +1,14 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/utils/dialog_util.dart';
class RenameDialog extends StatefulWidget {
final String name;
final String? name;
final String type;
final int maxLength;
const RenameDialog(this.name, this.type, {Key key, this.maxLength = 100})
const RenameDialog(this.name, this.type, {Key? key, this.maxLength = 100})
: super(key: key);
@override
@ -16,7 +16,7 @@ class RenameDialog extends StatefulWidget {
}
class _RenameDialogState extends State<RenameDialog> {
String _newName;
String? _newName;
@override
void initState() {
@ -74,7 +74,7 @@ class _RenameDialogState extends State<RenameDialog> {
),
),
onPressed: () {
if (_newName.trim().isEmpty) {
if (_newName!.trim().isEmpty) {
showErrorDialog(
context,
"Empty name",
@ -82,7 +82,7 @@ class _RenameDialogState extends State<RenameDialog> {
);
return;
}
if (_newName.trim().length > widget.maxLength) {
if (_newName!.trim().length > widget.maxLength) {
showErrorDialog(
context,
"Name too large",
@ -90,7 +90,7 @@ class _RenameDialogState extends State<RenameDialog> {
);
return;
}
Navigator.of(context).pop(_newName.trim());
Navigator.of(context).pop(_newName!.trim());
},
),
],

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
@ -8,7 +8,7 @@ class WebPage extends StatefulWidget {
final String title;
final String url;
const WebPage(this.title, this.url, {Key key}) : super(key: key);
const WebPage(this.title, this.url, {Key? key}) : super(key: key);
@override
State<WebPage> createState() => _WebPageState();

View file

@ -103,12 +103,12 @@ class BottomActionBarWidget extends StatelessWidget {
}
List<Widget> _iconButtons(BuildContext context) {
final iconButtonsWithExpansionIcon = <Widget?>[
final iconButtonsWithExpansionIcon = <Widget>[
...?iconButtons,
ExpansionIconWidget(expandableController: _expandableController)
];
iconButtonsWithExpansionIcon.removeWhere((element) => element == null);
return iconButtonsWithExpansionIcon as List<Widget>;
return iconButtonsWithExpansionIcon;
}
ExpandableThemeData _getExpandableTheme() {

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
@ -46,14 +44,14 @@ String _actionName(CollectionActionType type, bool plural) {
}
class CreateCollectionPage extends StatefulWidget {
final SelectedFiles selectedFiles;
final List<SharedMediaFile> sharedFiles;
final SelectedFiles? selectedFiles;
final List<SharedMediaFile>? sharedFiles;
final CollectionActionType actionType;
const CreateCollectionPage(
this.selectedFiles,
this.sharedFiles, {
Key key,
Key? key,
this.actionType = CollectionActionType.addFiles,
}) : super(key: key);
@ -63,13 +61,13 @@ class CreateCollectionPage extends StatefulWidget {
class _CreateCollectionPageState extends State<CreateCollectionPage> {
final _logger = Logger((_CreateCollectionPageState).toString());
String _albumName;
late String _albumName;
@override
Widget build(BuildContext context) {
final filesCount = widget.sharedFiles != null
? widget.sharedFiles.length
: widget.selectedFiles.files.length;
? widget.sharedFiles!.length
: widget.selectedFiles!.files.length;
return Scaffold(
appBar: AppBar(
title: Text(_actionName(widget.actionType, filesCount > 1)),
@ -134,9 +132,9 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
} else if (snapshot.hasData) {
return ListView.builder(
itemBuilder: (context, index) {
return _buildCollectionItem(snapshot.data[index]);
return _buildCollectionItem(snapshot.data![index]);
},
itemCount: snapshot.data.length,
itemCount: snapshot.data!.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
);
@ -171,7 +169,7 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
const Padding(padding: EdgeInsets.all(8)),
Expanded(
child: Text(
item.collection.name,
item.collection.name!,
style: const TextStyle(
fontSize: 16,
),
@ -184,8 +182,8 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
showShortToast(
context,
widget.actionType == CollectionActionType.addFiles
? "Added successfully to " + item.collection.name
: "Moved successfully to " + item.collection.name,
? "Added successfully to " + item.collection.name!
: "Moved successfully to " + item.collection.name!,
);
_navigateToCollection(item.collection);
}
@ -305,11 +303,11 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
await dialog.show();
try {
final int fromCollectionID =
widget.selectedFiles.files.first?.collectionID;
widget.selectedFiles!.files.first.collectionID!;
await CollectionsService.instance.move(
toCollectionID,
fromCollectionID,
widget.selectedFiles.files?.toList(),
widget.selectedFiles!.files?.toList() ?? <File>[],
);
await dialog.hide();
RemoteSyncService.instance.sync(silently: true);
@ -318,7 +316,7 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
return true;
} on AssertionError catch (e) {
await dialog.hide();
showErrorDialog(context, "Oops", e.message);
showErrorDialog(context, "Oops", e.message as String?);
return false;
} catch (e, s) {
_logger.severe("Could not move to album", e, s);
@ -332,15 +330,15 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
final dialog = createProgressDialog(context, "Restoring files...");
await dialog.show();
try {
await CollectionsService.instance
.restore(toCollectionID, widget.selectedFiles.files?.toList());
await CollectionsService.instance.restore(
toCollectionID, widget.selectedFiles!.files?.toList() ?? <File>[]);
RemoteSyncService.instance.sync(silently: true);
widget.selectedFiles?.clearAll();
await dialog.hide();
return true;
} on AssertionError catch (e) {
await dialog.hide();
showErrorDialog(context, "Oops", e.message);
showErrorDialog(context, "Oops", e.message as String?);
return false;
} catch (e, s) {
_logger.severe("Could not move to album", e, s);
@ -359,13 +357,18 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
if (widget.sharedFiles != null) {
filesPendingUpload.addAll(
await convertIncomingSharedMediaToFile(
widget.sharedFiles,
widget.sharedFiles!,
collectionID,
),
);
} else {
for (final file in widget.selectedFiles.files) {
final currentFile = await FilesDB.instance.getFile(file.generatedID);
for (final file in widget.selectedFiles!.files) {
final File? currentFile =
await (FilesDB.instance.getFile(file.generatedID!));
if (currentFile == null) {
_logger.severe("Failed to find fileBy genID");
continue;
}
if (currentFile.uploadedFileID == null) {
currentFile.collectionID = collectionID;
filesPendingUpload.add(currentFile);
@ -396,8 +399,8 @@ class _CreateCollectionPageState extends State<CreateCollectionPage> {
return false;
}
Future<Collection> _createAlbum(String albumName) async {
Collection collection;
Future<Collection?> _createAlbum(String albumName) async {
Collection? collection;
final dialog = createProgressDialog(context, "Creating album...");
await dialog.show();
try {

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
@ -49,10 +49,10 @@ class ExtentsPageView extends StatefulWidget {
/// child that could possibly be displayed in the page view, instead of just
/// those children that are actually visible.
ExtentsPageView({
Key key,
Key? key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController controller,
PageController? controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@ -81,15 +81,15 @@ class ExtentsPageView extends StatefulWidget {
/// you are planning to change child order at a later time, consider using
/// [PageView] or [PageView.custom].
ExtentsPageView.builder({
Key key,
Key? key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController controller,
PageController? controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
required IndexedWidgetBuilder itemBuilder,
int? itemCount,
this.dragStartBehavior = DragStartBehavior.start,
this.openDrawer,
}) : controller = controller ?? _defaultPageController,
@ -99,16 +99,16 @@ class ExtentsPageView extends StatefulWidget {
super(key: key);
ExtentsPageView.extents({
Key key,
Key? key,
this.extents = 1,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController controller,
PageController? controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
required IndexedWidgetBuilder itemBuilder,
int? itemCount,
this.dragStartBehavior = DragStartBehavior.start,
this.openDrawer,
}) : controller = controller ?? _defaultPageController,
@ -201,14 +201,14 @@ class ExtentsPageView extends StatefulWidget {
/// ```
/// {@end-tool}
ExtentsPageView.custom({
Key key,
Key? key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController controller,
PageController? controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@required this.childrenDelegate,
required this.childrenDelegate,
this.dragStartBehavior = DragStartBehavior.start,
this.openDrawer,
}) : assert(childrenDelegate != null),
@ -257,13 +257,13 @@ class ExtentsPageView extends StatefulWidget {
/// [PageScrollPhysics] prior to being used.
///
/// Defaults to matching platform conventions.
final ScrollPhysics physics;
final ScrollPhysics? physics;
/// Set to false to disable page snapping, useful for custom scroll behavior.
final bool pageSnapping;
/// Called whenever the page in the center of the viewport changes.
final ValueChanged<int> onPageChanged;
final ValueChanged<int>? onPageChanged;
/// A delegate that provides the children for the [PageView].
///
@ -276,7 +276,7 @@ class ExtentsPageView extends StatefulWidget {
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
final Function openDrawer; //nullable
final Function? openDrawer; //nullable
@override
State<ExtentsPageView> createState() => _PageViewState();
@ -292,7 +292,7 @@ class _PageViewState extends State<ExtentsPageView> {
widget.openDrawer != null
? widget.controller.addListener(() {
if (widget.controller.offset < -45) {
widget.openDrawer();
widget.openDrawer!();
}
})
: null;
@ -304,7 +304,7 @@ class _PageViewState extends State<ExtentsPageView> {
super.dispose();
}
AxisDirection _getDirection(BuildContext context) {
AxisDirection? _getDirection(BuildContext context) {
switch (widget.scrollDirection) {
case Axis.horizontal:
assert(debugCheckHasDirectionality(context));
@ -322,8 +322,8 @@ class _PageViewState extends State<ExtentsPageView> {
@override
Widget build(BuildContext context) {
final AxisDirection axisDirection = _getDirection(context);
final ScrollPhysics physics = widget.pageSnapping
final AxisDirection axisDirection = _getDirection(context)!;
final ScrollPhysics? physics = widget.pageSnapping
? _kPagePhysics.applyTo(widget.physics)
: widget.physics;
@ -332,11 +332,11 @@ class _PageViewState extends State<ExtentsPageView> {
if (notification.depth == 0 &&
widget.onPageChanged != null &&
notification is ScrollUpdateNotification) {
final PageMetrics metrics = notification.metrics;
final int currentPage = metrics.page.round();
final PageMetrics metrics = notification.metrics as PageMetrics;
final int currentPage = metrics.page!.round();
if (currentPage != _lastReportedPage) {
_lastReportedPage = currentPage;
widget.onPageChanged(currentPage);
widget.onPageChanged!(currentPage);
}
}
return false;

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/errors.dart';
@ -7,9 +7,9 @@ import 'package:photos/ui/payment/subscription.dart';
import 'package:photos/utils/email_util.dart';
class HeaderErrorWidget extends StatelessWidget {
final Error _error;
final Error? _error;
const HeaderErrorWidget({Key key, @required Error error})
const HeaderErrorWidget({Key? key, required Error? error})
: _error = error,
super(key: key);
@ -123,7 +123,7 @@ class HeaderErrorWidget extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(50, 16, 50, 16),
side: BorderSide(
width: 2,
color: Colors.orange[600],
color: Colors.orange[600]!,
),
),
child: Text(

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
@ -16,12 +16,12 @@ import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
class HomeGalleryWidget extends StatelessWidget {
final Widget header;
final Widget footer;
final SelectedFiles selectedFiles;
final Widget? header;
final Widget? footer;
final SelectedFiles? selectedFiles;
const HomeGalleryWidget({
Key key,
Key? key,
this.header,
this.footer,
this.selectedFiles,
@ -42,7 +42,7 @@ class HomeGalleryWidget extends StatelessWidget {
result = await FilesDB.instance.getAllLocalAndUploadedFiles(
creationStartTime,
creationEndTime,
ownerID,
ownerID!,
limit: limit,
asc: asc,
ignoredCollectionIDs: collectionsToHide,
@ -51,7 +51,7 @@ class HomeGalleryWidget extends StatelessWidget {
result = await FilesDB.instance.getAllPendingOrUploadedFiles(
creationStartTime,
creationEndTime,
ownerID,
ownerID!,
limit: limit,
asc: asc,
ignoredCollectionIDs: collectionsToHide,
@ -88,7 +88,7 @@ class HomeGalleryWidget extends StatelessWidget {
return Stack(
children: [
gallery,
FileSelectionOverlayBar(GalleryType.homepage, selectedFiles)
FileSelectionOverlayBar(GalleryType.homepage, selectedFiles!)
],
);
// return gallery;

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io';
@ -17,7 +17,7 @@ import 'package:photos/ui/common/gradient_button.dart';
import 'package:photos/ui/payment/subscription.dart';
class LandingPageWidget extends StatefulWidget {
const LandingPageWidget({Key key}) : super(key: key);
const LandingPageWidget({Key? key}) : super(key: key);
@override
State<LandingPageWidget> createState() => _LandingPageWidgetState();
@ -240,7 +240,7 @@ class FeatureItemWidget extends StatelessWidget {
this.featureTitleFirstLine,
this.featureTitleSecondLine,
this.subText, {
Key key,
Key? key,
}) : super(key: key);
@override

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
@ -14,20 +14,20 @@ import 'package:photos/utils/share_util.dart';
import 'package:step_progress_indicator/step_progress_indicator.dart';
class MemoriesWidget extends StatelessWidget {
const MemoriesWidget({Key key}) : super(key: key);
const MemoriesWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return FutureBuilder<List<Memory>>(
future: MemoriesService.instance.getMemories(),
builder: (context, snapshot) {
if (snapshot.hasError || !snapshot.hasData || snapshot.data.isEmpty) {
if (snapshot.hasError || !snapshot.hasData || snapshot.data!.isEmpty) {
return const SizedBox.shrink();
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildMemories(snapshot.data),
_buildMemories(snapshot.data!),
const Divider(),
],
);
@ -69,17 +69,17 @@ class MemoriesWidget extends StatelessWidget {
bool _areMemoriesFromSameYear(Memory first, Memory second) {
final firstDate =
DateTime.fromMicrosecondsSinceEpoch(first.file.creationTime);
DateTime.fromMicrosecondsSinceEpoch(first.file.creationTime!);
final secondDate =
DateTime.fromMicrosecondsSinceEpoch(second.file.creationTime);
DateTime.fromMicrosecondsSinceEpoch(second.file.creationTime!);
return firstDate.year == secondDate.year;
}
}
class MemoryWidget extends StatefulWidget {
const MemoryWidget({
Key key,
@required this.memories,
Key? key,
required this.memories,
}) : super(key: key);
final List<Memory> memories;
@ -119,7 +119,7 @@ class _MemoryWidgetState extends State<MemoryWidget> {
title,
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontSize: 12),
textAlign: TextAlign.center,
),
@ -186,7 +186,7 @@ class _MemoryWidgetState extends State<MemoryWidget> {
String _getTitle(Memory memory) {
final present = DateTime.now();
final then = DateTime.fromMicrosecondsSinceEpoch(memory.file.creationTime);
final then = DateTime.fromMicrosecondsSinceEpoch(memory.file.creationTime!);
final diffInYears = present.year - then.year;
if (diffInYears == 1) {
return "1 year ago";
@ -201,7 +201,7 @@ class FullScreenMemory extends StatefulWidget {
final List<Memory> memories;
final int index;
const FullScreenMemory(this.title, this.memories, this.index, {Key key})
const FullScreenMemory(this.title, this.memories, this.index, {Key? key})
: super(key: key);
@override
@ -215,7 +215,7 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
// when the top step indicator isn't visible.
bool _showCounter = false;
bool _showStepIndicator = true;
PageController _pageController;
PageController? _pageController;
bool _shouldDisableScroll = false;
final GlobalKey shareButtonKey = GlobalKey();
@ -273,9 +273,9 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
),
Text(
getFormattedDate(
DateTime.fromMicrosecondsSinceEpoch(file.creationTime),
DateTime.fromMicrosecondsSinceEpoch(file.creationTime!),
),
style: Theme.of(context).textTheme.subtitle1.copyWith(
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
color: Colors.white,
), //same for both themes
@ -328,7 +328,7 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
'${_index + 1}/${widget.memories.length}',
style: Theme.of(context)
.textTheme
.bodyText1
.bodyText1!
.copyWith(color: Colors.white.withOpacity(0.4)),
)
: AnimatedOpacity(
@ -338,7 +338,7 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
widget.title,
style: Theme.of(context)
.textTheme
.headline4
.headline4!
.copyWith(color: Colors.white),
),
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -19,18 +19,18 @@ import 'package:photos/utils/navigation_util.dart';
const double kContainerHeight = 36;
class StatusBarWidget extends StatefulWidget {
const StatusBarWidget({Key key}) : super(key: key);
const StatusBarWidget({Key? key}) : super(key: key);
@override
State<StatusBarWidget> createState() => _StatusBarWidgetState();
}
class _StatusBarWidgetState extends State<StatusBarWidget> {
StreamSubscription<SyncStatusUpdate> _subscription;
StreamSubscription<NotificationEvent> _notificationSubscription;
late StreamSubscription<SyncStatusUpdate> _subscription;
late StreamSubscription<NotificationEvent> _notificationSubscription;
bool _showStatus = false;
bool _showErrorBanner = false;
Error _syncError;
Error? _syncError;
@override
void initState() {
@ -118,7 +118,7 @@ class _StatusBarWidgetState extends State<StatusBarWidget> {
}
class SyncStatusWidget extends StatefulWidget {
const SyncStatusWidget({Key key}) : super(key: key);
const SyncStatusWidget({Key? key}) : super(key: key);
@override
State<SyncStatusWidget> createState() => _SyncStatusWidgetState();
@ -127,8 +127,8 @@ class SyncStatusWidget extends StatefulWidget {
class _SyncStatusWidgetState extends State<SyncStatusWidget> {
static const Duration kSleepDuration = Duration(milliseconds: 3000);
SyncStatusUpdate _event;
StreamSubscription<SyncStatusUpdate> _subscription;
SyncStatusUpdate? _event;
late StreamSubscription<SyncStatusUpdate> _subscription;
@override
void initState() {
@ -150,17 +150,17 @@ class _SyncStatusWidgetState extends State<SyncStatusWidget> {
@override
Widget build(BuildContext context) {
final bool isNotOutdatedEvent = _event != null &&
(_event.status == SyncStatus.completedBackup ||
_event.status == SyncStatus.completedFirstGalleryImport) &&
(DateTime.now().microsecondsSinceEpoch - _event.timestamp >
(_event!.status == SyncStatus.completedBackup ||
_event!.status == SyncStatus.completedFirstGalleryImport) &&
(DateTime.now().microsecondsSinceEpoch - _event!.timestamp >
kSleepDuration.inMicroseconds);
if (_event == null ||
isNotOutdatedEvent ||
//sync error cases are handled in StatusBarWidget
_event.status == SyncStatus.error) {
_event!.status == SyncStatus.error) {
return const SizedBox.shrink();
}
if (_event.status == SyncStatus.completedBackup) {
if (_event!.status == SyncStatus.completedBackup) {
return const SyncStatusCompletedWidget();
}
return RefreshIndicatorWidget(_event);
@ -173,9 +173,9 @@ class RefreshIndicatorWidget extends StatelessWidget {
valueColor: AlwaysStoppedAnimation<Color>(Color.fromRGBO(45, 194, 98, 1.0)),
);
final SyncStatusUpdate event;
final SyncStatusUpdate? event;
const RefreshIndicatorWidget(this.event, {Key key}) : super(key: key);
const RefreshIndicatorWidget(this.event, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -211,30 +211,30 @@ class RefreshIndicatorWidget extends StatelessWidget {
}
String _getRefreshingText() {
if (event.status == SyncStatus.startedFirstGalleryImport ||
event.status == SyncStatus.completedFirstGalleryImport) {
if (event!.status == SyncStatus.startedFirstGalleryImport ||
event!.status == SyncStatus.completedFirstGalleryImport) {
return "Loading gallery...";
}
if (event.status == SyncStatus.applyingRemoteDiff) {
if (event!.status == SyncStatus.applyingRemoteDiff) {
return "Syncing...";
}
if (event.status == SyncStatus.preparingForUpload) {
if (event!.status == SyncStatus.preparingForUpload) {
return "Encrypting backup...";
}
if (event.status == SyncStatus.inProgress) {
return event.completed.toString() +
if (event!.status == SyncStatus.inProgress) {
return event!.completed.toString() +
"/" +
event.total.toString() +
event!.total.toString() +
" memories preserved";
}
if (event.status == SyncStatus.paused) {
return event.reason;
if (event!.status == SyncStatus.paused) {
return event!.reason;
}
if (event.status == SyncStatus.error) {
return event.reason ?? "Upload failed";
if (event!.status == SyncStatus.error) {
return event!.reason ?? "Upload failed";
}
if (event.status == SyncStatus.completedBackup) {
if (event.wasStopped) {
if (event!.status == SyncStatus.completedBackup) {
if (event!.wasStopped) {
return "Sync stopped";
}
}
@ -243,7 +243,7 @@ class RefreshIndicatorWidget extends StatelessWidget {
}
class BrandingWidget extends StatelessWidget {
const BrandingWidget({Key key}) : super(key: key);
const BrandingWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -271,7 +271,7 @@ class BrandingWidget extends StatelessWidget {
}
class SyncStatusCompletedWidget extends StatelessWidget {
const SyncStatusCompletedWidget({Key key}) : super(key: key);
const SyncStatusCompletedWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:io';
@ -51,7 +51,7 @@ import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:uni_links/uni_links.dart';
class HomeWidget extends StatefulWidget {
const HomeWidget({Key key}) : super(key: key);
const HomeWidget({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _HomeWidgetState();
@ -74,17 +74,17 @@ class _HomeWidgetState extends State<HomeWidget> {
// for receiving media files
// ignore: unused_field
StreamSubscription _intentDataStreamSubscription;
List<SharedMediaFile> _sharedFiles;
StreamSubscription? _intentDataStreamSubscription;
List<SharedMediaFile>? _sharedFiles;
StreamSubscription<TabChangedEvent> _tabChangedEventSubscription;
StreamSubscription<SubscriptionPurchasedEvent> _subscriptionPurchaseEvent;
StreamSubscription<TriggerLogoutEvent> _triggerLogoutEvent;
StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
StreamSubscription<PermissionGrantedEvent> _permissionGrantedEvent;
StreamSubscription<SyncStatusUpdate> _firstImportEvent;
StreamSubscription<BackupFoldersUpdatedEvent> _backupFoldersUpdatedEvent;
StreamSubscription<AccountConfiguredEvent> _accountConfiguredEvent;
late StreamSubscription<TabChangedEvent> _tabChangedEventSubscription;
late StreamSubscription<SubscriptionPurchasedEvent> _subscriptionPurchaseEvent;
late StreamSubscription<TriggerLogoutEvent> _triggerLogoutEvent;
late StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
late StreamSubscription<PermissionGrantedEvent> _permissionGrantedEvent;
late StreamSubscription<SyncStatusUpdate> _firstImportEvent;
late StreamSubscription<BackupFoldersUpdatedEvent> _backupFoldersUpdatedEvent;
late StreamSubscription<AccountConfiguredEvent> _accountConfiguredEvent;
@override
void initState() {
@ -323,7 +323,7 @@ class _HomeWidgetState extends State<HomeWidget> {
if (UserRemoteFlagService.instance.showPasswordReminder()) {
return const PasswordReminder();
}
if (_sharedFiles != null && _sharedFiles.isNotEmpty) {
if (_sharedFiles != null && _sharedFiles!.isNotEmpty) {
ReceiveSharingIntent.reset();
return CreateCollectionPage(null, _sharedFiles);
}
@ -392,7 +392,7 @@ class _HomeWidgetState extends State<HomeWidget> {
Future<bool> _initDeepLinks() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
final String initialLink = await getInitialLink();
final String? initialLink = await getInitialLink();
// Parse the link and warn the user, if it is not correct,
// but keep in mind it could be `null`.
if (initialLink != null) {
@ -410,8 +410,8 @@ class _HomeWidgetState extends State<HomeWidget> {
// Attach a listener to the stream
linkStream.listen(
(String link) {
_logger.info("Link received: " + link);
(String? link) {
_logger.info("Link received: " + link!);
_getCredentials(context, link);
},
onError: (err) {
@ -421,11 +421,11 @@ class _HomeWidgetState extends State<HomeWidget> {
return false;
}
void _getCredentials(BuildContext context, String link) {
void _getCredentials(BuildContext context, String? link) {
if (Configuration.instance.hasConfiguredAccount()) {
return;
}
final ott = Uri.parse(link).queryParameters["ott"];
final ott = Uri.parse(link!).queryParameters["ott"]!;
UserService.instance.verifyEmail(context, ott);
}

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:async';
import 'package:flutter/foundation.dart';
@ -12,18 +10,18 @@ class DraggableScrollbar extends StatefulWidget {
final Color backgroundColor;
final Color drawColor;
final double heightScrollThumb;
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry? padding;
final int totalCount;
final int initialScrollIndex;
final double bottomSafeArea;
final int currentFirstIndex;
final ValueChanged<double> onChange;
final ValueChanged<double>? onChange;
final String Function(int) labelTextBuilder;
final bool isEnabled;
const DraggableScrollbar({
Key key,
@required this.child,
Key? key,
required this.child,
this.backgroundColor = Colors.white,
this.drawColor = Colors.grey,
this.heightScrollThumb = 80.0,
@ -32,7 +30,7 @@ class DraggableScrollbar extends StatefulWidget {
this.totalCount = 1,
this.initialScrollIndex = 0,
this.currentFirstIndex = 0,
@required this.labelTextBuilder,
required this.labelTextBuilder,
this.onChange,
this.isEnabled = true,
}) : super(key: key);
@ -47,18 +45,18 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
static const labelAnimationDuration = Duration(milliseconds: 1000);
double thumbOffset = 0.0;
bool isDragging = false;
int currentFirstIndex;
late int currentFirstIndex;
double get thumbMin => 0.0;
double get thumbMax =>
context.size.height - widget.heightScrollThumb - widget.bottomSafeArea;
context.size!.height - widget.heightScrollThumb - widget.bottomSafeArea;
AnimationController _thumbAnimationController;
Animation<double> _thumbAnimation;
AnimationController _labelAnimationController;
Animation<double> _labelAnimation;
Timer _fadeoutTimer;
late AnimationController _thumbAnimationController;
Animation<double>? _thumbAnimation;
late AnimationController _labelAnimationController;
Animation<double>? _labelAnimation;
Timer? _fadeoutTimer;
@override
void initState() {
@ -66,7 +64,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
currentFirstIndex = widget.currentFirstIndex;
if (widget.initialScrollIndex > 0 && widget.totalCount > 1) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(
() => thumbOffset = (widget.initialScrollIndex / widget.totalCount) *
(thumbMax - thumbMin),
@ -130,7 +128,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
}
Widget buildThumb() => Padding(
padding: widget.padding,
padding: widget.padding!,
child: Container(
alignment: Alignment.topRight,
margin: EdgeInsets.only(top: thumbOffset),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:math' show max;
@ -17,7 +17,7 @@ typedef HugeListViewErrorBuilder = Widget Function(
class HugeListView<T> extends StatefulWidget {
/// A [ScrollablePositionedList] controller for jumping or scrolling to an item.
final ItemScrollController controller;
final ItemScrollController? controller;
/// Index of an item to initially align within the viewport.
final int startIndex;
@ -46,29 +46,29 @@ class HugeListView<T> extends StatefulWidget {
final HugeListViewItemBuilder<T> itemBuilder;
/// Called to build a progress widget while the whole list is initialized.
final WidgetBuilder waitBuilder;
final WidgetBuilder? waitBuilder;
/// Called to build a widget when the list is empty.
final WidgetBuilder emptyResultBuilder;
final WidgetBuilder? emptyResultBuilder;
/// Called to build a widget when there is an error.
final HugeListViewErrorBuilder errorBuilder;
final HugeListViewErrorBuilder? errorBuilder;
/// Event to call with the index of the topmost visible item in the viewport while scrolling.
/// Can be used to display the current letter of an alphabetically sorted list, for instance.
final ValueChanged<int> firstShown;
final ValueChanged<int>? firstShown;
final bool isDraggableScrollbarEnabled;
final EdgeInsetsGeometry thumbPadding;
final EdgeInsetsGeometry? thumbPadding;
const HugeListView({
Key key,
Key? key,
this.controller,
@required this.startIndex,
@required this.totalCount,
@required this.labelTextBuilder,
@required this.itemBuilder,
required this.startIndex,
required this.totalCount,
required this.labelTextBuilder,
required this.itemBuilder,
this.waitBuilder,
this.emptyResultBuilder,
this.errorBuilder,
@ -121,13 +121,13 @@ class HugeListViewState<T> extends State<HugeListView<T>> {
@override
Widget build(BuildContext context) {
if (error != null && widget.errorBuilder != null) {
return widget.errorBuilder(context, error);
return widget.errorBuilder!(context, error);
}
if (widget.totalCount == -1 && widget.waitBuilder != null) {
return widget.waitBuilder(context);
return widget.waitBuilder!(context);
}
if (widget.totalCount == 0 && widget.emptyResultBuilder != null) {
return widget.emptyResultBuilder(context);
return widget.emptyResultBuilder!(context);
}
return LayoutBuilder(

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:math';
@ -25,16 +25,16 @@ import 'package:photos/utils/navigation_util.dart';
import 'package:visibility_detector/visibility_detector.dart';
class LazyLoadingGallery extends StatefulWidget {
final List<File> files;
final List<File?> files;
final int index;
final Stream<FilesUpdatedEvent> reloadEvent;
final Stream<FilesUpdatedEvent>? reloadEvent;
final Set<EventType> removalEventTypes;
final GalleryLoader asyncLoader;
final SelectedFiles selectedFiles;
final SelectedFiles? selectedFiles;
final String tag;
final String logTag;
final String? logTag;
final Stream<int> currentIndexStream;
final int photoGirdSize;
final int? photoGirdSize;
LazyLoadingGallery(
this.files,
@ -47,7 +47,7 @@ class LazyLoadingGallery extends StatefulWidget {
this.currentIndexStream, {
this.logTag = "",
this.photoGirdSize = photoGridSizeDefault,
Key key,
Key? key,
}) : super(key: key ?? UniqueKey());
@override
@ -58,12 +58,12 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
static const kRecycleLimit = 400;
static const kNumberOfDaysToRenderBeforeAndAfter = 8;
Logger _logger;
late Logger _logger;
List<File> _files;
StreamSubscription<FilesUpdatedEvent> _reloadEventSubscription;
StreamSubscription<int> _currentIndexSubscription;
bool _shouldRender;
List<File?>? _files;
late StreamSubscription<FilesUpdatedEvent> _reloadEventSubscription;
late StreamSubscription<int> _currentIndexSubscription;
bool? _shouldRender;
final ValueNotifier<bool> _toggleSelectAllFromDay = ValueNotifier(false);
final ValueNotifier<bool> _showSelectAllButton = ValueNotifier(false);
final ValueNotifier<bool> _areAllFromDaySelected = ValueNotifier(false);
@ -71,7 +71,7 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
@override
void initState() {
//this is for removing the 'select all from day' icon on unselecting all files with 'cancel'
widget.selectedFiles.addListener(_selectedFilesListener);
widget.selectedFiles!.addListener(_selectedFilesListener);
super.initState();
_init();
}
@ -80,7 +80,7 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
_logger = Logger("LazyLoading_${widget.logTag}");
_shouldRender = true;
_files = widget.files;
_reloadEventSubscription = widget.reloadEvent.listen((e) => _onReload(e));
_reloadEventSubscription = widget.reloadEvent!.listen((e) => _onReload(e));
_currentIndexSubscription =
widget.currentIndexStream.listen((currentIndex) {
@ -96,9 +96,9 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
Future _onReload(FilesUpdatedEvent event) async {
final galleryDate =
DateTime.fromMicrosecondsSinceEpoch(_files[0].creationTime);
DateTime.fromMicrosecondsSinceEpoch(_files![0]!.creationTime!);
final filesUpdatedThisDay = event.updatedFiles.where((file) {
final fileDate = DateTime.fromMicrosecondsSinceEpoch(file.creationTime);
final fileDate = DateTime.fromMicrosecondsSinceEpoch(file.creationTime!);
return fileDate.year == galleryDate.year &&
fileDate.month == galleryDate.month &&
fileDate.day == galleryDate.day;
@ -125,8 +125,8 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
}
} else if (widget.removalEventTypes.contains(event.type)) {
// Files were removed
final generatedFileIDs = <int>{};
final uploadedFileIds = <int>{};
final generatedFileIDs = <int?>{};
final uploadedFileIds = <int?>{};
for (final file in filesUpdatedThisDay) {
if (file.generatedID != null) {
generatedFileIDs.add(file.generatedID);
@ -134,16 +134,16 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
uploadedFileIds.add(file.uploadedFileID);
}
}
final List<File> files = [];
files.addAll(_files);
final List<File?> files = [];
files.addAll(_files!);
files.removeWhere(
(file) =>
generatedFileIDs.contains(file.generatedID) ||
generatedFileIDs.contains(file!.generatedID) ||
uploadedFileIds.contains(file.uploadedFileID),
);
if (kDebugMode) {
_logger.finest(
"removed ${_files.length - files.length} due to ${event.reason}",
"removed ${_files!.length - files.length} due to ${event.reason}",
);
}
if (mounted) {
@ -163,7 +163,7 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
void dispose() {
_reloadEventSubscription.cancel();
_currentIndexSubscription.cancel();
widget.selectedFiles.removeListener(_selectedFilesListener);
widget.selectedFiles!.removeListener(_selectedFilesListener);
_toggleSelectAllFromDay.dispose();
_showSelectAllButton.dispose();
_areAllFromDaySelected.dispose();
@ -181,7 +181,7 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
@override
Widget build(BuildContext context) {
if (_files.isEmpty) {
if (_files!.isEmpty) {
return const SizedBox.shrink();
}
return Column(
@ -191,12 +191,12 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
children: [
getDayWidget(
context,
_files[0].creationTime,
widget.photoGirdSize,
_files![0]!.creationTime!,
widget.photoGirdSize!,
),
ValueListenableBuilder(
valueListenable: _showSelectAllButton,
builder: (context, value, _) {
builder: (context, dynamic value, _) {
return !value
? const SizedBox.shrink()
: GestureDetector(
@ -206,7 +206,7 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
height: 44,
child: ValueListenableBuilder(
valueListenable: _areAllFromDaySelected,
builder: (context, value, _) {
builder: (context, dynamic value, _) {
return value
? const Icon(
Icons.check_circle,
@ -232,11 +232,11 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
)
],
),
_shouldRender
_shouldRender!
? _getGallery()
: PlaceHolderWidget(
_files.length,
widget.photoGirdSize,
_files!.length,
widget.photoGirdSize!,
),
],
);
@ -244,21 +244,21 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
Widget _getGallery() {
final List<Widget> childGalleries = [];
final subGalleryItemLimit = widget.photoGirdSize < photoGridSizeDefault
final subGalleryItemLimit = widget.photoGirdSize! < photoGridSizeDefault
? subGalleryLimitMin
: subGalleryLimitDefault;
for (int index = 0; index < _files.length; index += subGalleryItemLimit) {
for (int index = 0; index < _files!.length; index += subGalleryItemLimit) {
childGalleries.add(
LazyLoadingGridView(
widget.tag,
_files.sublist(
_files!.sublist(
index,
min(index + subGalleryItemLimit, _files.length),
min(index + subGalleryItemLimit, _files!.length),
),
widget.asyncLoader,
widget.selectedFiles,
index == 0,
_files.length > kRecycleLimit,
_files!.length > kRecycleLimit,
_toggleSelectAllFromDay,
_areAllFromDaySelected,
widget.photoGirdSize,
@ -272,7 +272,7 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
}
void _selectedFilesListener() {
if (widget.selectedFiles.files.isEmpty) {
if (widget.selectedFiles!.files.isEmpty) {
_showSelectAllButton.value = false;
} else {
_showSelectAllButton.value = true;
@ -282,14 +282,14 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
class LazyLoadingGridView extends StatefulWidget {
final String tag;
final List<File> filesInDay;
final List<File?> filesInDay;
final GalleryLoader asyncLoader;
final SelectedFiles selectedFiles;
final SelectedFiles? selectedFiles;
final bool shouldRender;
final bool shouldRecycle;
final ValueNotifier toggleSelectAllFromDay;
final ValueNotifier areAllFilesSelected;
final int photoGridSize;
final int? photoGridSize;
LazyLoadingGridView(
this.tag,
@ -301,7 +301,7 @@ class LazyLoadingGridView extends StatefulWidget {
this.toggleSelectAllFromDay,
this.areAllFilesSelected,
this.photoGridSize, {
Key key,
Key? key,
}) : super(key: key ?? UniqueKey());
@override
@ -309,15 +309,15 @@ class LazyLoadingGridView extends StatefulWidget {
}
class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
bool _shouldRender;
int _currentUserID;
StreamSubscription<ClearSelectionsEvent> _clearSelectionsEvent;
bool? _shouldRender;
int? _currentUserID;
late StreamSubscription<ClearSelectionsEvent> _clearSelectionsEvent;
@override
void initState() {
_shouldRender = widget.shouldRender;
_currentUserID = Configuration.instance.getUserID();
widget.selectedFiles.addListener(_selectedFilesListener);
widget.selectedFiles!.addListener(_selectedFilesListener);
_clearSelectionsEvent =
Bus.instance.on<ClearSelectionsEvent>().listen((event) {
if (mounted) {
@ -330,7 +330,7 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
@override
void dispose() {
widget.selectedFiles.removeListener(_selectedFilesListener);
widget.selectedFiles!.removeListener(_selectedFilesListener);
_clearSelectionsEvent.cancel();
widget.toggleSelectAllFromDay
.removeListener(_toggleSelectAllFromDayListener);
@ -365,25 +365,25 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
});
}
},
child: _shouldRender
child: _shouldRender!
? _getGridView()
: PlaceHolderWidget(widget.filesInDay.length, widget.photoGridSize),
: PlaceHolderWidget(widget.filesInDay.length, widget.photoGridSize!),
);
}
Widget _getNonRecyclableView() {
if (!_shouldRender) {
if (!_shouldRender!) {
return VisibilityDetector(
key: UniqueKey(),
onVisibilityChanged: (visibility) {
if (mounted && visibility.visibleFraction > 0 && !_shouldRender) {
if (mounted && visibility.visibleFraction > 0 && !_shouldRender!) {
setState(() {
_shouldRender = true;
});
}
},
child:
PlaceHolderWidget(widget.filesInDay.length, widget.photoGridSize),
PlaceHolderWidget(widget.filesInDay.length, widget.photoGridSize!),
);
} else {
return _getGridView();
@ -396,34 +396,34 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
physics: const NeverScrollableScrollPhysics(),
// to disable GridView's scrolling
itemBuilder: (context, index) {
return _buildFile(context, widget.filesInDay[index]);
return _buildFile(context, widget.filesInDay[index]!);
},
itemCount: widget.filesInDay.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 2,
mainAxisSpacing: 2,
crossAxisCount: widget.photoGridSize,
crossAxisCount: widget.photoGridSize!,
),
padding: const EdgeInsets.all(0),
);
}
Widget _buildFile(BuildContext context, File file) {
final isFileSelected = widget.selectedFiles.isFileSelected(file);
final isFileSelected = widget.selectedFiles!.isFileSelected(file);
Color selectionColor = Colors.white;
if (isFileSelected &&
file.isUploaded &&
(file.ownerID != _currentUserID ||
file.pubMagicMetadata.uploaderName != null)) {
file.pubMagicMetadata!.uploaderName != null)) {
final avatarColors = getEnteColorScheme(context).avatarColors;
final int randomID = file.ownerID != _currentUserID
? file.ownerID
: file.pubMagicMetadata.uploaderName.sumAsciiValues;
? file.ownerID!
: file.pubMagicMetadata!.uploaderName.sumAsciiValues;
selectionColor = avatarColors[(randomID).remainder(avatarColors.length)];
}
return GestureDetector(
onTap: () {
if (widget.selectedFiles.files.isNotEmpty) {
if (widget.selectedFiles!.files.isNotEmpty) {
_selectFile(file);
} else {
_routeToDetailPage(file, context);
@ -452,7 +452,7 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
serverLoadDeferDuration: thumbnailServerLoadDeferDuration,
shouldShowLivePhotoOverlay: true,
key: Key(widget.tag + file.tag),
thumbnailSize: widget.photoGridSize < photoGridSizeDefault
thumbnailSize: widget.photoGridSize! < photoGridSizeDefault
? thumbnailLargeSize
: thumbnailSmallSize,
shouldShowOwnerAvatar: !isFileSelected,
@ -478,7 +478,7 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
}
void _selectFile(File file) {
widget.selectedFiles.toggleSelection(file);
widget.selectedFiles!.toggleSelection(file);
}
void _routeToDetailPage(File file, BuildContext context) {
@ -494,14 +494,14 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
}
void _selectedFilesListener() {
if (widget.selectedFiles.files.containsAll(widget.filesInDay.toSet())) {
if (widget.selectedFiles!.files.containsAll(widget.filesInDay.toSet())) {
widget.areAllFilesSelected.value = true;
} else {
widget.areAllFilesSelected.value = false;
}
bool shouldRefresh = false;
for (final file in widget.filesInDay) {
if (widget.selectedFiles.isPartOfLastSelected(file)) {
if (widget.selectedFiles!.isPartOfLastSelected(file!)) {
shouldRefresh = true;
}
}
@ -511,12 +511,12 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
}
void _toggleSelectAllFromDayListener() {
if (widget.selectedFiles.files.containsAll(widget.filesInDay.toSet())) {
if (widget.selectedFiles!.files.containsAll(widget.filesInDay.toSet())) {
setState(() {
widget.selectedFiles.unSelectAll(widget.filesInDay.toSet());
widget.selectedFiles!.unSelectAll(widget.filesInDay.toSet() as Set<File>);
});
} else {
widget.selectedFiles.selectAll(widget.filesInDay.toSet());
widget.selectedFiles!.selectAll(widget.filesInDay.toSet() as Set<File>);
}
}
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
@ -7,8 +7,8 @@ class ScrollBarThumb extends StatelessWidget {
final Color drawColor;
final double height;
final String title;
final Animation labelAnimation;
final Animation thumbAnimation;
final Animation? labelAnimation;
final Animation? thumbAnimation;
final Function(DragStartDetails details) onDragStart;
final Function(DragUpdateDetails details) onDragUpdate;
final Function(DragEndDetails details) onDragEnd;
@ -23,7 +23,7 @@ class ScrollBarThumb extends StatelessWidget {
this.onDragStart,
this.onDragUpdate,
this.onDragEnd, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -33,7 +33,7 @@ class ScrollBarThumb extends StatelessWidget {
children: [
IgnorePointer(
child: FadeTransition(
opacity: labelAnimation,
opacity: labelAnimation as Animation<double>,
child: Container(
padding: const EdgeInsets.fromLTRB(20, 12, 20, 12),
decoration: BoxDecoration(
@ -60,7 +60,7 @@ class ScrollBarThumb extends StatelessWidget {
onVerticalDragUpdate: onDragUpdate,
onVerticalDragEnd: onDragEnd,
child: SlideFadeTransition(
animation: thumbAnimation,
animation: thumbAnimation as Animation<double>?,
child: CustomPaint(
foregroundPainter: _ArrowCustomPainter(drawColor),
child: Material(
@ -131,27 +131,27 @@ class _ArrowCustomPainter extends CustomPainter {
}
class SlideFadeTransition extends StatelessWidget {
final Animation<double> animation;
final Animation<double>? animation;
final Widget child;
const SlideFadeTransition({
Key key,
@required this.animation,
@required this.child,
Key? key,
required this.animation,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) => animation.value == 0.0 ? Container() : child,
animation: animation!,
builder: (context, child) => animation!.value == 0.0 ? Container() : child!,
child: SlideTransition(
position: Tween(
begin: const Offset(0.3, 0.0),
end: const Offset(0.0, 0.0),
).animate(animation),
).animate(animation!),
child: FadeTransition(
opacity: animation,
opacity: animation!,
child: child,
),
),

View file

@ -1,11 +1,11 @@
// @dart=2.9
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class LifecycleEventHandler extends WidgetsBindingObserver {
final AsyncCallback resumeCallBack;
final AsyncCallback suspendingCallBack;
final AsyncCallback? resumeCallBack;
final AsyncCallback? suspendingCallBack;
LifecycleEventHandler({
this.resumeCallBack,
@ -17,14 +17,14 @@ class LifecycleEventHandler extends WidgetsBindingObserver {
switch (state) {
case AppLifecycleState.resumed:
if (resumeCallBack != null) {
await resumeCallBack();
await resumeCallBack!();
}
break;
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
if (suspendingCallBack != null) {
await suspendingCallBack();
await suspendingCallBack!();
}
break;
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:io';
@ -15,15 +15,15 @@ import 'package:photos/ui/common/bottom_shadow.dart';
import 'package:photos/utils/navigation_util.dart';
class LoadingPhotosWidget extends StatefulWidget {
const LoadingPhotosWidget({Key key}) : super(key: key);
const LoadingPhotosWidget({Key? key}) : super(key: key);
@override
State<LoadingPhotosWidget> createState() => _LoadingPhotosWidgetState();
}
class _LoadingPhotosWidgetState extends State<LoadingPhotosWidget> {
StreamSubscription<SyncStatusUpdate> _firstImportEvent;
StreamSubscription<LocalImportProgressEvent> _imprortProgressEvent;
late StreamSubscription<SyncStatusUpdate> _firstImportEvent;
late StreamSubscription<LocalImportProgressEvent> _imprortProgressEvent;
int _currentPage = 0;
String _loadingMessage = "Loading your photos...";
final PageController _pageController = PageController(
@ -145,7 +145,7 @@ class _LoadingPhotosWidgetState extends State<LoadingPhotosWidget> {
children: [
Text(
"Did you know?",
style: Theme.of(context).textTheme.headline6.copyWith(
style: Theme.of(context).textTheme.headline6!.copyWith(
color: Theme.of(context).colorScheme.greenText,
),
),
@ -192,7 +192,7 @@ class _LoadingPhotosWidgetState extends State<LoadingPhotosWidget> {
textAlign: TextAlign.start,
style: Theme.of(context)
.textTheme
.headline5
.headline5!
.copyWith(color: Theme.of(context).colorScheme.defaultTextColor),
);
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
library google_nav_bar;
@ -7,7 +7,7 @@ import 'package:flutter/services.dart';
class GNav extends StatefulWidget {
const GNav({
Key key,
Key? key,
this.tabs,
this.selectedIndex = 0,
this.onTabChange,
@ -34,29 +34,29 @@ class GNav extends StatefulWidget {
this.mainAxisAlignment = MainAxisAlignment.spaceBetween,
}) : super(key: key);
final List<GButton> tabs;
final List<GButton>? tabs;
final int selectedIndex;
final Function onTabChange;
final double gap;
final double tabBorderRadius;
final double iconSize;
final Color activeColor;
final Color backgroundColor;
final Color tabBackgroundColor;
final Color color;
final Color rippleColor;
final Color hoverColor;
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry tabMargin;
final TextStyle textStyle;
final Duration duration;
final Curve curve;
final bool debug;
final bool haptic;
final Border tabBorder;
final Border tabActiveBorder;
final List<BoxShadow> tabShadow;
final Gradient tabBackgroundGradient;
final Function? onTabChange;
final double? gap;
final double? tabBorderRadius;
final double? iconSize;
final Color? activeColor;
final Color? backgroundColor;
final Color? tabBackgroundColor;
final Color? color;
final Color? rippleColor;
final Color? hoverColor;
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry? tabMargin;
final TextStyle? textStyle;
final Duration? duration;
final Curve? curve;
final bool? debug;
final bool? haptic;
final Border? tabBorder;
final Border? tabActiveBorder;
final List<BoxShadow>? tabShadow;
final Gradient? tabBackgroundGradient;
final MainAxisAlignment mainAxisAlignment;
@override
@ -64,7 +64,7 @@ class GNav extends StatefulWidget {
}
class _GNavState extends State<GNav> {
int selectedIndex;
int? selectedIndex;
bool clickable = true;
@override
@ -83,20 +83,20 @@ class _GNavState extends State<GNav> {
color: widget.backgroundColor ?? Colors.transparent,
child: Row(
mainAxisAlignment: widget.mainAxisAlignment,
children: widget.tabs
children: widget.tabs!
.map(
(t) => GButton(
key: t.key,
border: t.border ?? widget.tabBorder,
activeBorder: t.activeBorder ?? widget.tabActiveBorder,
borderRadius: t.borderRadius ?? widget.tabBorderRadius != null
borderRadius: t.borderRadius as bool? ?? widget.tabBorderRadius != null
? BorderRadius.all(
Radius.circular(widget.tabBorderRadius),
Radius.circular(widget.tabBorderRadius!),
)
: const BorderRadius.all(Radius.circular(100.0)),
debug: widget.debug ?? false,
margin: t.margin ?? widget.tabMargin,
active: selectedIndex == widget.tabs.indexOf(t),
active: selectedIndex == widget.tabs!.indexOf(t),
gap: t.gap ?? widget.gap,
iconActiveColor: t.iconActiveColor ?? widget.activeColor,
iconColor: t.iconColor ?? widget.color,
@ -118,7 +118,7 @@ class _GNavState extends State<GNav> {
Colors.transparent,
duration: widget.duration ?? const Duration(milliseconds: 500),
onPressed: () {
widget.onTabChange(widget.tabs.indexOf(t));
widget.onTabChange!(widget.tabs!.indexOf(t));
},
),
)
@ -129,35 +129,35 @@ class _GNavState extends State<GNav> {
}
class GButton extends StatefulWidget {
final bool active;
final bool debug;
final bool haptic;
final double gap;
final Color iconColor;
final Color rippleColor;
final Color hoverColor;
final Color iconActiveColor;
final Color textColor;
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry margin;
final TextStyle textStyle;
final double iconSize;
final Function onPressed;
final bool? active;
final bool? debug;
final bool? haptic;
final double? gap;
final Color? iconColor;
final Color? rippleColor;
final Color? hoverColor;
final Color? iconActiveColor;
final Color? textColor;
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry? margin;
final TextStyle? textStyle;
final double? iconSize;
final Function? onPressed;
final String text;
final IconData icon;
final Color backgroundColor;
final Duration duration;
final Curve curve;
final Gradient backgroundGradient;
final Widget leading;
final BorderRadius borderRadius;
final Border border;
final Border activeBorder;
final List<BoxShadow> shadow;
final String semanticLabel;
final IconData? icon;
final Color? backgroundColor;
final Duration? duration;
final Curve? curve;
final Gradient? backgroundGradient;
final Widget? leading;
final BorderRadius? borderRadius;
final Border? border;
final Border? activeBorder;
final List<BoxShadow>? shadow;
final String? semanticLabel;
const GButton({
Key key,
Key? key,
this.active,
this.haptic,
this.backgroundColor,
@ -205,8 +205,8 @@ class _GButtonState extends State<GButton> {
iconSize: widget.iconSize,
active: widget.active,
onPressed: () {
if (widget.haptic) HapticFeedback.selectionClick();
widget.onPressed();
if (widget.haptic!) HapticFeedback.selectionClick();
widget.onPressed!();
},
padding: widget.padding,
margin: widget.margin,
@ -227,7 +227,7 @@ class _GButtonState extends State<GButton> {
class Button extends StatefulWidget {
const Button({
Key key,
Key? key,
this.icon,
this.iconSize,
this.leading,
@ -252,38 +252,38 @@ class Button extends StatefulWidget {
this.shadow,
}) : super(key: key);
final IconData icon;
final double iconSize;
final Text text;
final Widget leading;
final Color iconActiveColor;
final Color iconColor;
final Color color;
final Color rippleColor;
final Color hoverColor;
final double gap;
final bool active;
final bool debug;
final VoidCallback onPressed;
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry margin;
final Duration duration;
final Curve curve;
final Gradient gradient;
final BorderRadius borderRadius;
final Border border;
final Border activeBorder;
final List<BoxShadow> shadow;
final IconData? icon;
final double? iconSize;
final Text? text;
final Widget? leading;
final Color? iconActiveColor;
final Color? iconColor;
final Color? color;
final Color? rippleColor;
final Color? hoverColor;
final double? gap;
final bool? active;
final bool? debug;
final VoidCallback? onPressed;
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry? margin;
final Duration? duration;
final Curve? curve;
final Gradient? gradient;
final BorderRadius? borderRadius;
final Border? border;
final Border? activeBorder;
final List<BoxShadow>? shadow;
@override
State<Button> createState() => _ButtonState();
}
class _ButtonState extends State<Button> with TickerProviderStateMixin {
bool _expanded;
bool? _expanded;
AnimationController expandController;
Animation<double> animation;
late AnimationController expandController;
Animation<double>? animation;
@override
void initState() {
@ -302,8 +302,8 @@ class _ButtonState extends State<Button> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
_expanded = !widget.active;
if (_expanded) {
_expanded = !widget.active!;
if (_expanded!) {
expandController.reverse();
} else {
expandController.forward();
@ -312,7 +312,7 @@ class _ButtonState extends State<Button> with TickerProviderStateMixin {
final Widget icon = widget.leading ??
Icon(
widget.icon,
color: _expanded ? widget.iconColor : widget.iconActiveColor,
color: _expanded! ? widget.iconColor : widget.iconActiveColor,
size: widget.iconSize,
);
@ -323,23 +323,23 @@ class _ButtonState extends State<Button> with TickerProviderStateMixin {
splashColor: widget.rippleColor,
borderRadius: BorderRadius.circular(100),
onTap: () {
widget.onPressed();
widget.onPressed!();
},
child: Container(
padding: widget.margin,
child: AnimatedContainer(
curve: Curves.easeOut,
padding: widget.padding,
duration: widget.duration,
duration: widget.duration!,
decoration: BoxDecoration(
boxShadow: widget.shadow,
border: widget.active
border: widget.active!
? (widget.activeBorder ?? widget.border)
: widget.border,
gradient: widget.gradient,
color: _expanded
? widget.color.withOpacity(0)
: widget.debug
color: _expanded!
? widget.color!.withOpacity(0)
: widget.debug!
? Colors.red
: widget.gradient != null
? Colors.white

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:convert';
import 'package:expansion_tile_card/expansion_tile_card.dart';
@ -10,7 +8,7 @@ import 'package:photos/ui/common/loading_widget.dart';
class BillingQuestionsWidget extends StatelessWidget {
const BillingQuestionsWidget({
Key key,
Key? key,
}) : super(key: key);
@override
@ -64,11 +62,11 @@ class BillingQuestionsWidget extends StatelessWidget {
class FaqWidget extends StatelessWidget {
const FaqWidget({
Key key,
@required this.faq,
Key? key,
required this.faq,
}) : super(key: key);
final FaqItem faq;
final FaqItem? faq;
@override
Widget build(BuildContext context) {
@ -76,7 +74,7 @@ class FaqWidget extends StatelessWidget {
padding: const EdgeInsets.all(2),
child: ExpansionTileCard(
elevation: 0,
title: Text(faq.q),
title: Text(faq!.q!),
expandedTextColor: Theme.of(context).colorScheme.greenAlternative,
baseColor: Theme.of(context).cardColor,
children: [
@ -87,7 +85,7 @@ class FaqWidget extends StatelessWidget {
bottom: 12,
),
child: Text(
faq.a,
faq!.a!,
style: const TextStyle(
height: 1.5,
),
@ -100,16 +98,16 @@ class FaqWidget extends StatelessWidget {
}
class FaqItem {
final String q;
final String a;
final String? q;
final String? a;
FaqItem({
this.q,
this.a,
});
FaqItem copyWith({
String q,
String a,
String? q,
String? a,
}) {
return FaqItem(
q: q ?? this.q,
@ -125,11 +123,9 @@ class FaqItem {
}
factory FaqItem.fromMap(Map<String, dynamic> map) {
if (map == null) return null;
return FaqItem(
q: map['q'],
a: map['a'],
q: map['q'] ?? 'q',
a: map['a'] ?? 'a',
);
}

View file

@ -1,7 +1,6 @@
// @dart=2.9
import 'dart:io';
import 'package:collection/collection.dart' show IterableNullableExtension;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
@ -15,10 +14,10 @@ import 'package:photos/ui/common/progress_dialog.dart';
import 'package:photos/utils/dialog_util.dart';
class PaymentWebPage extends StatefulWidget {
final String planId;
final String actionType;
final String? planId;
final String? actionType;
const PaymentWebPage({Key key, this.planId, this.actionType})
const PaymentWebPage({Key? key, this.planId, this.actionType})
: super(key: key);
@override
@ -30,10 +29,10 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
final UserService userService = UserService.instance;
final BillingService billingService = BillingService.instance;
final String basePaymentUrl = kWebPaymentBaseEndpoint;
ProgressDialog _dialog;
InAppWebViewController webView;
late ProgressDialog _dialog;
InAppWebViewController? webView;
double progress = 0;
Uri initPaymentUrl;
Uri? initPaymentUrl;
@override
void initState() {
@ -54,7 +53,7 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
return const EnteLoadingWidget();
}
return WillPopScope(
onWillPop: () async => _buildPageExitWidget(context),
onWillPop: (() async => _buildPageExitWidget(context)),
child: Scaffold(
appBar: AppBar(
title: const Text('Subscription'),
@ -83,7 +82,7 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
_logger.info("Loading url $loadingUri");
// handle the payment response
if (_isPaymentActionComplete(loadingUri)) {
await _handlePaymentResponse(loadingUri);
await _handlePaymentResponse(loadingUri!);
return NavigationActionPolicy.CANCEL;
}
return NavigationActionPolicy.ALLOW;
@ -113,7 +112,7 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
},
),
),
].where((Object o) => o != null).toList(),
].whereNotNull().toList(),
),
),
);
@ -125,7 +124,7 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
super.dispose();
}
Uri _getPaymentUrl(String paymentToken) {
Uri _getPaymentUrl(String? paymentToken) {
final queryParameters = {
'productID': widget.planId,
'paymentToken': paymentToken,
@ -134,15 +133,15 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
};
final tryParse = Uri.tryParse(kWebPaymentBaseEndpoint);
if (kDebugMode && kWebPaymentBaseEndpoint.startsWith("http://")) {
return Uri.http(tryParse.authority, tryParse.path, queryParameters);
return Uri.http(tryParse!.authority, tryParse.path, queryParameters);
} else {
return Uri.https(tryParse.authority, tryParse.path, queryParameters);
return Uri.https(tryParse!.authority, tryParse.path, queryParameters);
}
}
// show dialog to handle accidental back press.
Future<bool> _buildPageExitWidget(BuildContext context) {
return showDialog(
Future<bool> _buildPageExitWidget(BuildContext context) async {
final result = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Are you sure you want to exit?'),
@ -168,9 +167,13 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
],
),
);
if (result != null) {
return result;
}
return false;
}
bool _isPaymentActionComplete(Uri loadingUri) {
bool _isPaymentActionComplete(Uri? loadingUri) {
return loadingUri.toString().startsWith(kWebPaymentRedirectUrl);
}
@ -240,13 +243,13 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
}
// warn the user to wait for sometime before trying another payment
Future<dynamic> _showExitPageDialog({String title, String content}) {
Future<dynamic> _showExitPageDialog({String? title, String? content}) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text(title),
content: Text(content),
title: Text(title!),
content: Text(content!),
actions: <Widget>[
TextButton(
child: Text(

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -30,7 +30,7 @@ class StripeSubscriptionPage extends StatefulWidget {
const StripeSubscriptionPage({
this.isOnboarding = false,
Key key,
Key? key,
}) : super(key: key);
@override
@ -40,13 +40,13 @@ class StripeSubscriptionPage extends StatefulWidget {
class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
final _billingService = BillingService.instance;
final _userService = UserService.instance;
Subscription _currentSubscription;
ProgressDialog _dialog;
UserDetails _userDetails;
Subscription? _currentSubscription;
late ProgressDialog _dialog;
late UserDetails _userDetails;
// indicates if user's subscription plan is still active
bool _hasActiveSubscription;
FreePlan _freePlan;
late bool _hasActiveSubscription;
late FreePlan _freePlan;
List<BillingPlan> _plans = [];
bool _hasLoadedData = false;
bool _isLoading = false;
@ -64,9 +64,9 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
.then((userDetails) async {
_userDetails = userDetails;
_currentSubscription = userDetails.subscription;
_showYearlyPlan = _currentSubscription.isYearlyPlan();
_hasActiveSubscription = _currentSubscription.isValid();
_isStripeSubscriber = _currentSubscription.paymentProvider == stripe;
_showYearlyPlan = _currentSubscription!.isYearlyPlan();
_hasActiveSubscription = _currentSubscription!.isValid();
_isStripeSubscriber = _currentSubscription!.paymentProvider == stripe;
return _filterStripeForUI().then((value) {
_hasLoadedData = true;
setState(() {});
@ -101,8 +101,8 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
// verify user has subscribed before redirecting to main page
if (widget.isOnboarding &&
_currentSubscription != null &&
_currentSubscription.isValid() &&
_currentSubscription.productID != freeProductID) {
_currentSubscription!.isValid() &&
_currentSubscription!.productID != freeProductID) {
Navigator.of(context).popUntil((route) => route.isFirst);
}
}
@ -203,7 +203,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
}
if (_currentSubscription.productID == freeProductID) {
if (_currentSubscription!.productID == freeProductID) {
if (widget.isOnboarding) {
widgets.add(SkipSubscriptionWidget(freePlan: _freePlan));
}
@ -215,22 +215,22 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
widgets.add(_stripeRenewOrCancelButton());
}
if (_currentSubscription.productID != freeProductID) {
if (_currentSubscription!.productID != freeProductID) {
widgets.addAll([
Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () async {
final String paymentProvider =
_currentSubscription.paymentProvider;
switch (_currentSubscription.paymentProvider) {
_currentSubscription!.paymentProvider;
switch (_currentSubscription!.paymentProvider) {
case stripe:
await _launchStripePortal();
break;
case playStore:
launchUrlString(
"https://play.google.com/store/account/subscriptions?sku=" +
_currentSubscription.productID +
_currentSubscription!.productID +
"&package=io.ente.photos",
);
break;
@ -288,7 +288,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
RichText(
text: TextSpan(
text: "Manage family",
style: Theme.of(context).textTheme.bodyMedium.copyWith(
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
decoration: TextDecoration.underline,
),
),
@ -330,7 +330,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
Widget _stripeRenewOrCancelButton() {
final bool isRenewCancelled =
_currentSubscription.attributes?.isCancelled ?? false;
_currentSubscription!.attributes?.isCancelled ?? false;
final String title =
isRenewCancelled ? "Renew subscription" : "Cancel subscription";
return TextButton(
@ -397,7 +397,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
continue;
}
final isActive =
_hasActiveSubscription && _currentSubscription.productID == productID;
_hasActiveSubscription && _currentSubscription!.productID == productID;
if (isActive) {
foundActivePlan = true;
}
@ -412,12 +412,12 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
// payment providers
if (!_isStripeSubscriber &&
_hasActiveSubscription &&
_currentSubscription.productID != freeProductID) {
_currentSubscription!.productID != freeProductID) {
showErrorDialog(
context,
"Sorry",
"Please cancel your existing subscription from "
"${_currentSubscription.paymentProvider} first",
"${_currentSubscription!.paymentProvider} first",
);
return;
}
@ -515,13 +515,13 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
void _addCurrentPlanWidget(List<Widget> planWidgets) {
// don't add current plan if it's monthly plan but UI is showing yearly plans
// and vice versa.
if (_showYearlyPlan != _currentSubscription.isYearlyPlan() &&
_currentSubscription.productID != freeProductID) {
if (_showYearlyPlan != _currentSubscription!.isYearlyPlan() &&
_currentSubscription!.productID != freeProductID) {
return;
}
int activePlanIndex = 0;
for (; activePlanIndex < _plans.length; activePlanIndex++) {
if (_plans[activePlanIndex].storage > _currentSubscription.storage) {
if (_plans[activePlanIndex].storage > _currentSubscription!.storage) {
break;
}
}
@ -531,9 +531,9 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
child: InkWell(
onTap: () {},
child: SubscriptionPlanWidget(
storage: _currentSubscription.storage,
price: _currentSubscription.price,
period: _currentSubscription.period,
storage: _currentSubscription!.storage,
price: _currentSubscription!.price,
period: _currentSubscription!.period,
isActive: true,
),
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
@ -8,11 +8,11 @@ import 'package:photos/utils/data_util.dart';
import 'package:photos/utils/date_time_util.dart';
class SubscriptionHeaderWidget extends StatefulWidget {
final bool isOnboarding;
final int currentUsage;
final bool? isOnboarding;
final int? currentUsage;
const SubscriptionHeaderWidget({
Key key,
Key? key,
this.isOnboarding,
this.currentUsage,
}) : super(key: key);
@ -26,7 +26,7 @@ class SubscriptionHeaderWidget extends StatefulWidget {
class _SubscriptionHeaderWidgetState extends State<SubscriptionHeaderWidget> {
@override
Widget build(BuildContext context) {
if (widget.isOnboarding) {
if (widget.isOnboarding!) {
return Padding(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 24),
child: Column(
@ -64,10 +64,10 @@ class _SubscriptionHeaderWidgetState extends State<SubscriptionHeaderWidget> {
style: Theme.of(context).textTheme.subtitle1,
),
TextSpan(
text: formatBytes(widget.currentUsage),
text: formatBytes(widget.currentUsage!),
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontWeight: FontWeight.bold),
)
],
@ -80,9 +80,9 @@ class _SubscriptionHeaderWidgetState extends State<SubscriptionHeaderWidget> {
}
class ValidityWidget extends StatelessWidget {
final Subscription currentSubscription;
final Subscription? currentSubscription;
const ValidityWidget({Key key, this.currentSubscription}) : super(key: key);
const ValidityWidget({Key? key, this.currentSubscription}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -90,12 +90,12 @@ class ValidityWidget extends StatelessWidget {
return const SizedBox.shrink();
}
final endDate = getDateAndMonthAndYear(
DateTime.fromMicrosecondsSinceEpoch(currentSubscription.expiryTime),
DateTime.fromMicrosecondsSinceEpoch(currentSubscription!.expiryTime),
);
var message = "Renews on $endDate";
if (currentSubscription.productID == freeProductID) {
if (currentSubscription!.productID == freeProductID) {
message = "Free trial valid till $endDate";
} else if (currentSubscription.attributes?.isCancelled ?? false) {
} else if (currentSubscription!.attributes?.isCancelled ?? false) {
message = "Your subscription will be cancelled on $endDate";
}
return Padding(
@ -109,7 +109,7 @@ class ValidityWidget extends StatelessWidget {
}
class SubFaqWidget extends StatelessWidget {
const SubFaqWidget({Key key}) : super(key: key);
const SubFaqWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -132,7 +132,7 @@ class SubFaqWidget extends StatelessWidget {
child: RichText(
text: TextSpan(
text: "Questions?",
style: Theme.of(context).textTheme.bodyMedium.copyWith(
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
decoration: TextDecoration.underline,
),
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:io';
@ -29,7 +29,7 @@ class SubscriptionPage extends StatefulWidget {
const SubscriptionPage({
this.isOnboarding = false,
Key key,
Key? key,
}) : super(key: key);
@override
@ -40,16 +40,16 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
final _logger = Logger("SubscriptionPage");
final _billingService = BillingService.instance;
final _userService = UserService.instance;
Subscription _currentSubscription;
StreamSubscription _purchaseUpdateSubscription;
ProgressDialog _dialog;
UserDetails _userDetails;
bool _hasActiveSubscription;
FreePlan _freePlan;
List<BillingPlan> _plans;
Subscription? _currentSubscription;
late StreamSubscription _purchaseUpdateSubscription;
late ProgressDialog _dialog;
late UserDetails _userDetails;
late bool _hasActiveSubscription;
late FreePlan _freePlan;
late List<BillingPlan> _plans;
bool _hasLoadedData = false;
bool _isLoading = false;
bool _isActiveStripeSubscriber;
late bool _isActiveStripeSubscriber;
@override
void initState() {
@ -76,9 +76,9 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
String text = "Thank you for subscribing!";
if (!widget.isOnboarding) {
final isUpgrade = _hasActiveSubscription &&
newSubscription.storage > _currentSubscription.storage;
newSubscription.storage > _currentSubscription!.storage;
final isDowngrade = _hasActiveSubscription &&
newSubscription.storage < _currentSubscription.storage;
newSubscription.storage < _currentSubscription!.storage;
if (isUpgrade) {
text = "Your plan was successfully upgraded";
} else if (isDowngrade) {
@ -87,7 +87,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
}
showShortToast(context, text);
_currentSubscription = newSubscription;
_hasActiveSubscription = _currentSubscription.isValid();
_hasActiveSubscription = _currentSubscription!.isValid();
setState(() {});
await _dialog.hide();
Bus.instance.fire(SubscriptionPurchasedEvent());
@ -155,11 +155,11 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
_userService.getUserDetailsV2(memoryCount: false).then((userDetails) async {
_userDetails = userDetails;
_currentSubscription = userDetails.subscription;
_hasActiveSubscription = _currentSubscription.isValid();
_hasActiveSubscription = _currentSubscription!.isValid();
final billingPlans = await _billingService.getBillingPlans();
_isActiveStripeSubscriber =
_currentSubscription.paymentProvider == stripe &&
_currentSubscription.isValid();
_currentSubscription!.paymentProvider == stripe &&
_currentSubscription!.isValid();
_plans = billingPlans.plans.where((plan) {
final productID = _isActiveStripeSubscriber
? plan.stripeID
@ -210,7 +210,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
}
if (_currentSubscription.productID == freeProductID) {
if (_currentSubscription!.productID == freeProductID) {
if (widget.isOnboarding) {
widgets.add(SkipSubscriptionWidget(freePlan: _freePlan));
}
@ -218,20 +218,20 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
}
if (_hasActiveSubscription &&
_currentSubscription.productID != freeProductID) {
_currentSubscription!.productID != freeProductID) {
widgets.addAll([
Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
final String paymentProvider =
_currentSubscription.paymentProvider;
_currentSubscription!.paymentProvider;
if (paymentProvider == appStore && !Platform.isAndroid) {
launchUrlString("https://apps.apple.com/account/billing");
} else if (paymentProvider == playStore && Platform.isAndroid) {
launchUrlString(
"https://play.google.com/store/account/subscriptions?sku=" +
_currentSubscription.productID +
_currentSubscription!.productID +
"&package=io.ente.photos",
);
} else if (paymentProvider == stripe) {
@ -294,7 +294,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
RichText(
text: TextSpan(
text: "Manage family",
style: Theme.of(context).textTheme.bodyMedium.copyWith(
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
decoration: TextDecoration.underline,
),
),
@ -324,7 +324,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
continue;
}
final isActive =
_hasActiveSubscription && _currentSubscription.productID == productID;
_hasActiveSubscription && _currentSubscription!.productID == productID;
if (isActive) {
foundActivePlan = true;
}
@ -362,7 +362,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
bool foundActivePlan = false;
final List<Widget> planWidgets = [];
if (_hasActiveSubscription &&
_currentSubscription.productID == freeProductID) {
_currentSubscription!.productID == freeProductID) {
foundActivePlan = true;
planWidgets.add(
SubscriptionPlanWidget(
@ -376,7 +376,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
for (final plan in _plans) {
final productID = Platform.isAndroid ? plan.androidID : plan.iosID;
final isActive =
_hasActiveSubscription && _currentSubscription.productID == productID;
_hasActiveSubscription && _currentSubscription!.productID == productID;
if (isActive) {
foundActivePlan = true;
}
@ -408,8 +408,8 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
}
final isCrossGradingOnAndroid = Platform.isAndroid &&
_hasActiveSubscription &&
_currentSubscription.productID != freeProductID &&
_currentSubscription.productID != plan.androidID;
_currentSubscription!.productID != freeProductID &&
_currentSubscription!.productID != plan.androidID;
if (isCrossGradingOnAndroid) {
await _dialog.hide();
showErrorDialog(
@ -445,7 +445,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
void _addCurrentPlanWidget(List<Widget> planWidgets) {
int activePlanIndex = 0;
for (; activePlanIndex < _plans.length; activePlanIndex++) {
if (_plans[activePlanIndex].storage > _currentSubscription.storage) {
if (_plans[activePlanIndex].storage > _currentSubscription!.storage) {
break;
}
}
@ -455,9 +455,9 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
child: InkWell(
onTap: () {},
child: SubscriptionPlanWidget(
storage: _currentSubscription.storage,
price: _currentSubscription.price,
period: _currentSubscription.period,
storage: _currentSubscription!.storage,
price: _currentSubscription!.price,
period: _currentSubscription!.period,
isActive: true,
),
),

View file

@ -1,14 +1,14 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/utils/data_util.dart';
class SubscriptionPlanWidget extends StatelessWidget {
const SubscriptionPlanWidget({
Key key,
@required this.storage,
@required this.price,
@required this.period,
Key? key,
required this.storage,
required this.price,
required this.period,
this.isActive = false,
}) : super(key: key);
@ -57,12 +57,12 @@ class SubscriptionPlanWidget extends StatelessWidget {
convertBytesToReadableFormat(storage),
style: Theme.of(context)
.textTheme
.headline6
.headline6!
.copyWith(color: textColor),
),
Text(
_displayPrice(),
style: Theme.of(context).textTheme.headline6.copyWith(
style: Theme.of(context).textTheme.headline6!.copyWith(
color: textColor,
fontWeight: FontWeight.normal,
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
@ -11,9 +11,9 @@ import 'package:photos/theme/ente_theme.dart';
import 'package:url_launcher/url_launcher_string.dart';
class AppUpdateDialog extends StatefulWidget {
final LatestVersionInfo latestVersionInfo;
final LatestVersionInfo? latestVersionInfo;
const AppUpdateDialog(this.latestVersionInfo, {Key key}) : super(key: key);
const AppUpdateDialog(this.latestVersionInfo, {Key? key}) : super(key: key);
@override
State<AppUpdateDialog> createState() => _AppUpdateDialogState();
@ -25,7 +25,7 @@ class _AppUpdateDialogState extends State<AppUpdateDialog> {
final List<Widget> changelog = [];
final enteTextTheme = getEnteTextTheme(context);
final enteColor = getEnteColorScheme(context);
for (final log in widget.latestVersionInfo.changelog) {
for (final log in widget.latestVersionInfo!.changelog) {
changelog.add(
Padding(
padding: const EdgeInsets.fromLTRB(0, 4, 0, 4),
@ -68,7 +68,7 @@ class _AppUpdateDialogState extends State<AppUpdateDialog> {
width: double.infinity,
height: 56,
child: OutlinedButton(
style: Theme.of(context).outlinedButtonTheme.style.copyWith(
style: Theme.of(context).outlinedButtonTheme.style!.copyWith(
textStyle: MaterialStateProperty.resolveWith<TextStyle>(
(Set<MaterialState> states) {
return enteTextTheme.bodyBold;
@ -97,11 +97,11 @@ class _AppUpdateDialogState extends State<AppUpdateDialog> {
"Install manually",
style: Theme.of(context)
.textTheme
.caption
.caption!
.copyWith(decoration: TextDecoration.underline),
),
onTap: () => launchUrlString(
widget.latestVersionInfo.url,
widget.latestVersionInfo!.url,
mode: LaunchMode.externalApplication,
),
),
@ -109,7 +109,7 @@ class _AppUpdateDialogState extends State<AppUpdateDialog> {
],
);
final shouldForceUpdate =
UpdateService.instance.shouldForceUpdate(widget.latestVersionInfo);
UpdateService.instance.shouldForceUpdate(widget.latestVersionInfo!);
return WillPopScope(
onWillPop: () async => !shouldForceUpdate,
child: AlertDialog(
@ -139,24 +139,24 @@ class _AppUpdateDialogState extends State<AppUpdateDialog> {
}
class ApkDownloaderDialog extends StatefulWidget {
final LatestVersionInfo versionInfo;
final LatestVersionInfo? versionInfo;
const ApkDownloaderDialog(this.versionInfo, {Key key}) : super(key: key);
const ApkDownloaderDialog(this.versionInfo, {Key? key}) : super(key: key);
@override
State<ApkDownloaderDialog> createState() => _ApkDownloaderDialogState();
}
class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
String _saveUrl;
double _downloadProgress;
String? _saveUrl;
double? _downloadProgress;
@override
void initState() {
super.initState();
_saveUrl = Configuration.instance.getTempDirectory() +
"ente-" +
widget.versionInfo.name +
widget.versionInfo!.name +
".apk";
_downloadApk();
}
@ -186,11 +186,11 @@ class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
Future<void> _downloadApk() async {
try {
await Network.instance.getDio().download(
widget.versionInfo.url,
widget.versionInfo!.url,
_saveUrl,
onReceiveProgress: (count, _) {
setState(() {
_downloadProgress = count / widget.versionInfo.size;
_downloadProgress = count / widget.versionInfo!.size;
});
},
);

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io';
@ -26,7 +26,7 @@ import 'package:photos/utils/toast_util.dart';
import 'package:url_launcher/url_launcher_string.dart';
class BackupSectionWidget extends StatefulWidget {
const BackupSectionWidget({Key key}) : super(key: key);
const BackupSectionWidget({Key? key}) : super(key: key);
@override
BackupSectionWidgetState createState() => BackupSectionWidgetState();
@ -108,7 +108,7 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
"You've no files on this device that can be deleted",
);
} else {
final bool result =
final bool? result =
await routeToPage(context, FreeSpacePage(status));
if (result == true) {
_showSpaceFreedDialog(status);
@ -145,7 +145,7 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
"You've no duplicate files that can be cleared",
);
} else {
final DeduplicationResult result =
final DeduplicationResult? result =
await routeToPage(context, DeduplicatePage(duplicates));
if (result != null) {
_showDuplicateFilesDeletedDialog(result);

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:flutter/material.dart';
@ -11,14 +11,14 @@ import 'package:photos/ui/components/menu_item_widget.dart';
import 'package:photos/ui/settings/common_settings.dart';
class ThemeSwitchWidget extends StatefulWidget {
const ThemeSwitchWidget({Key key}) : super(key: key);
const ThemeSwitchWidget({Key? key}) : super(key: key);
@override
State<ThemeSwitchWidget> createState() => _ThemeSwitchWidgetState();
}
class _ThemeSwitchWidgetState extends State<ThemeSwitchWidget> {
AdaptiveThemeMode currentThemeMode;
AdaptiveThemeMode? currentThemeMode;
@override
void initState() {
@ -67,7 +67,7 @@ class _ThemeSwitchWidgetState extends State<ThemeSwitchWidget> {
Widget _menuItem(BuildContext context, AdaptiveThemeMode themeMode) {
return MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: toBeginningOfSentenceCase(themeMode.name),
title: toBeginningOfSentenceCase(themeMode.name)!,
textStyle: Theme.of(context).colorScheme.enteTheme.textTheme.body,
),
pressedColor: getEnteColorScheme(context).fillFaint,

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io';
@ -23,8 +23,8 @@ import 'package:photos/ui/settings/support_section_widget.dart';
import 'package:photos/ui/settings/theme_switch_widget.dart';
class SettingsPage extends StatelessWidget {
final ValueNotifier<String> emailNotifier;
const SettingsPage({Key key, @required this.emailNotifier}) : super(key: key);
final ValueNotifier<String?> emailNotifier;
const SettingsPage({Key? key, required this.emailNotifier}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -51,9 +51,9 @@ class SettingsPage extends StatelessWidget {
child: AnimatedBuilder(
// [AnimatedBuilder] accepts any [Listenable] subtype.
animation: emailNotifier,
builder: (BuildContext context, Widget child) {
builder: (BuildContext context, Widget? child) {
return Text(
emailNotifier.value,
emailNotifier.value!,
style: enteTextTheme.body.copyWith(
color: colorScheme.textMuted,
overflow: TextOverflow.ellipsis,

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:math';
@ -28,7 +28,7 @@ import 'package:photos/utils/share_util.dart';
import 'package:photos/utils/toast_util.dart';
class SharedCollectionGallery extends StatefulWidget {
const SharedCollectionGallery({Key key}) : super(key: key);
const SharedCollectionGallery({Key? key}) : super(key: key);
@override
State<SharedCollectionGallery> createState() =>
@ -38,9 +38,9 @@ class SharedCollectionGallery extends StatefulWidget {
class _SharedCollectionGalleryState extends State<SharedCollectionGallery>
with AutomaticKeepAliveClientMixin {
final Logger _logger = Logger("SharedCollectionGallery");
StreamSubscription<LocalPhotosUpdatedEvent> _localFilesSubscription;
StreamSubscription<CollectionUpdatedEvent> _collectionUpdatesSubscription;
StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
late StreamSubscription<LocalPhotosUpdatedEvent> _localFilesSubscription;
late StreamSubscription<CollectionUpdatedEvent> _collectionUpdatesSubscription;
late StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
@override
void initState() {
@ -71,10 +71,10 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery>
final List<CollectionWithThumbnail> incoming = [];
for (final file in files) {
final c =
CollectionsService.instance.getCollectionByID(file.collectionID);
if (c.owner.id == Configuration.instance.getUserID()) {
if (c.sharees.isNotEmpty ||
c.publicURLs.isNotEmpty ||
CollectionsService.instance.getCollectionByID(file.collectionID!)!;
if (c.owner!.id == Configuration.instance.getUserID()) {
if (c.sharees!.isNotEmpty ||
c.publicURLs!.isNotEmpty ||
c.isSharedFilesCollection()) {
outgoing.add(
CollectionWithThumbnail(
@ -112,7 +112,7 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery>
}),
builder: (context, snapshot) {
if (snapshot.hasData) {
return _getSharedCollectionsGallery(snapshot.data);
return _getSharedCollectionsGallery(snapshot.data!);
} else if (snapshot.hasError) {
_logger.shout(snapshot.error);
return Center(child: Text(snapshot.error.toString()));
@ -264,20 +264,20 @@ class OutgoingCollectionItem extends StatelessWidget {
const OutgoingCollectionItem(
this.c, {
Key key,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final sharees = <String>[];
for (int index = 0; index < c.collection.sharees.length; index++) {
final sharee = c.collection.sharees[index];
final sharees = <String?>[];
for (int index = 0; index < c.collection.sharees!.length; index++) {
final sharee = c.collection.sharees![index]!;
final name =
(sharee.name?.isNotEmpty ?? false) ? sharee.name : sharee.email;
if (index < 2) {
sharees.add(name);
} else {
final remaining = c.collection.sharees.length - index;
final remaining = c.collection.sharees!.length - index;
if (remaining == 1) {
// If it's the last sharee
sharees.add(name);
@ -304,10 +304,10 @@ class OutgoingCollectionItem extends StatelessWidget {
height: 60,
width: 60,
child: Hero(
tag: "outgoing_collection" + c.thumbnail.tag,
tag: "outgoing_collection" + c.thumbnail!.tag,
child: ThumbnailWidget(
c.thumbnail,
key: Key("outgoing_collection" + c.thumbnail.tag),
key: Key("outgoing_collection" + c.thumbnail!.tag),
),
),
),
@ -320,15 +320,15 @@ class OutgoingCollectionItem extends StatelessWidget {
Row(
children: [
Text(
c.collection.name,
c.collection.name!,
style: const TextStyle(
fontSize: 16,
),
),
const Padding(padding: EdgeInsets.all(2)),
c.collection.publicURLs.isEmpty
c.collection.publicURLs!.isEmpty
? Container()
: (c.collection.publicURLs.first.isExpired
: (c.collection.publicURLs!.first!.isExpired
? const Icon(
Icons.link,
color: warning500,
@ -373,7 +373,7 @@ class IncomingCollectionItem extends StatelessWidget {
const IncomingCollectionItem(
this.c, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -381,7 +381,7 @@ class IncomingCollectionItem extends StatelessWidget {
const double horizontalPaddingOfGridRow = 16;
const double crossAxisSpacingOfGrid = 9;
final TextStyle albumTitleTextStyle =
Theme.of(context).textTheme.subtitle1.copyWith(fontSize: 14);
Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 14);
final Size size = MediaQuery.of(context).size;
final int albumsCountInOneRow = max(size.width ~/ 220.0, 2);
final double totalWhiteSpaceOfRow = (horizontalPaddingOfGridRow * 2) +
@ -400,10 +400,10 @@ class IncomingCollectionItem extends StatelessWidget {
child: Stack(
children: [
Hero(
tag: "shared_collection" + c.thumbnail.tag,
tag: "shared_collection" + c.thumbnail!.tag,
child: ThumbnailWidget(
c.thumbnail,
key: Key("shared_collection" + c.thumbnail.tag),
key: Key("shared_collection" + c.thumbnail!.tag),
),
),
Align(
@ -411,7 +411,7 @@ class IncomingCollectionItem extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(right: 8.0, bottom: 8.0),
child: UserAvatarWidget(
c.collection.owner,
c.collection.owner!,
thumbnailView: true,
),
),
@ -426,7 +426,7 @@ class IncomingCollectionItem extends StatelessWidget {
Container(
constraints: BoxConstraints(maxWidth: sideOfThumbnail - 40),
child: Text(
c.collection.name,
c.collection.name!,
style: albumTitleTextStyle,
overflow: TextOverflow.ellipsis,
),
@ -434,11 +434,11 @@ class IncomingCollectionItem extends StatelessWidget {
FutureBuilder<int>(
future: FilesDB.instance.collectionFileCount(c.collection.id),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data > 0) {
if (snapshot.hasData && snapshot.data! > 0) {
return RichText(
text: TextSpan(
style: albumTitleTextStyle.copyWith(
color: albumTitleTextStyle.color.withOpacity(0.5),
color: albumTitleTextStyle.color!.withOpacity(0.5),
),
children: [
const TextSpan(text: " \u2022 "),

View file

@ -1,6 +1,5 @@
// @dart=2.9
import 'dart:convert';
import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:flutter/cupertino.dart';
@ -25,9 +24,9 @@ import 'package:photos/utils/toast_util.dart';
import 'package:tuple/tuple.dart';
class ManageSharedLinkWidget extends StatefulWidget {
final Collection collection;
final Collection? collection;
const ManageSharedLinkWidget({Key key, this.collection}) : super(key: key);
const ManageSharedLinkWidget({Key? key, this.collection}) : super(key: key);
@override
State<ManageSharedLinkWidget> createState() => _ManageSharedLinkWidgetState();
@ -46,7 +45,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
const Tuple3(6, "Custom", -1),
];
Tuple3<int, String, int> _selectedExpiry;
late Tuple3<int, String, int> _selectedExpiry;
int _selectedDeviceLimitIndex = 0;
final CollectionActions sharingActions =
CollectionActions(CollectionsService.instance);
@ -60,7 +59,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
@override
Widget build(BuildContext context) {
final enteColorScheme = getEnteColorScheme(context);
final PublicURL url = widget.collection?.publicURLs?.firstOrNull;
final PublicURL url = widget.collection!.publicURLs!.firstOrNull!;
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
@ -85,7 +84,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
menuItemColor: getEnteColorScheme(context).fillFaint,
pressedColor: getEnteColorScheme(context).fillFaint,
trailingWidget: Switch.adaptive(
value: widget.collection.publicURLs?.firstOrNull
value: widget.collection!.publicURLs?.firstOrNull
?.enableCollect ??
false,
onChanged: (value) async {
@ -131,7 +130,8 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: "Device limit",
subTitle: widget.collection.publicURLs.first.deviceLimit
subTitle: widget
.collection!.publicURLs!.first!.deviceLimit
.toString(),
),
trailingIcon: Icons.chevron_right,
@ -156,7 +156,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
menuItemColor: getEnteColorScheme(context).fillFaint,
pressedColor: getEnteColorScheme(context).fillFaint,
trailingWidget: Switch.adaptive(
value: widget.collection.publicURLs?.firstOrNull
value: widget.collection!.publicURLs?.firstOrNull
?.enableDownload ??
true,
onChanged: (value) async {
@ -205,7 +205,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
menuItemColor: getEnteColorScheme(context).fillFaint,
pressedColor: getEnteColorScheme(context).fillFaint,
trailingWidget: Switch.adaptive(
value: widget.collection.publicURLs?.firstOrNull
value: widget.collection!.publicURLs?.firstOrNull
?.passwordEnabled ??
false,
onChanged: (enablePassword) async {
@ -246,7 +246,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
onTap: () async {
final bool result = await sharingActions.publicLinkToggle(
context,
widget.collection,
widget.collection!,
false,
);
if (result && mounted) {
@ -369,7 +369,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
}
// _showDateTimePicker return null if user doesn't select date-time
Future<int> _showDateTimePicker() async {
Future<int?> _showDateTimePicker() async {
final dateResult = await DatePicker.showDatePicker(
context,
minTime: DateTime.now(),
@ -396,7 +396,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
final TextEditingController _textFieldController = TextEditingController();
Future<String> _displayLinkPasswordInput(BuildContext context) async {
Future<String?> _displayLinkPasswordInput(BuildContext context) async {
_textFieldController.clear();
return showDialog<String>(
context: context,
@ -469,7 +469,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
final int opsLimit = Sodium.cryptoPwhashOpslimitInteractive;
final kekSalt = CryptoUtil.getSaltToDeriveKey();
final result = await CryptoUtil.deriveKey(
utf8.encode(pass),
utf8.encode(pass) as Uint8List,
kekSalt,
memLimit,
opsLimit,
@ -489,7 +489,8 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
final dialog = createProgressDialog(context, "Please wait...");
await dialog.show();
try {
await CollectionsService.instance.updateShareUrl(widget.collection, prop);
await CollectionsService.instance
.updateShareUrl(widget.collection!, prop);
await dialog.hide();
showShortToast(context, "Album updated");
} catch (e) {
@ -500,7 +501,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
Text _getLinkExpiryTimeWidget() {
final int validTill =
widget.collection.publicURLs?.firstOrNull?.validTill ?? 0;
widget.collection!.publicURLs?.firstOrNull?.validTill ?? 0;
if (validTill == 0) {
return const Text(
'Never',
@ -568,7 +569,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
onPressed: () async {
await _updateUrlSettings(context, {
'deviceLimit': int.tryParse(
options[_selectedDeviceLimitIndex].data,
options[_selectedDeviceLimitIndex].data!,
),
});
setState(() {});

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -27,24 +27,24 @@ import 'package:flutter/material.dart';
// ignore_for_file: unnecessary_this, library_private_types_in_public_api
class AppLock extends StatefulWidget {
final Widget Function(Object) builder;
final Widget Function(Object?) builder;
final Widget lockScreen;
final bool enabled;
final Duration backgroundLockLatency;
final ThemeData darkTheme;
final ThemeData lightTheme;
final ThemeData? darkTheme;
final ThemeData? lightTheme;
const AppLock({
Key key,
@required this.builder,
@required this.lockScreen,
Key? key,
required this.builder,
required this.lockScreen,
this.enabled = true,
this.backgroundLockLatency = const Duration(seconds: 0),
this.darkTheme,
this.lightTheme,
}) : super(key: key);
static _AppLockState of(BuildContext context) =>
static _AppLockState? of(BuildContext context) =>
context.findAncestorStateOfType<_AppLockState>();
@override
@ -54,11 +54,11 @@ class AppLock extends StatefulWidget {
class _AppLockState extends State<AppLock> with WidgetsBindingObserver {
static final GlobalKey<NavigatorState> _navigatorKey = GlobalKey();
bool _didUnlockForAppLaunch;
bool _isLocked;
bool _enabled;
late bool _didUnlockForAppLaunch;
late bool _isLocked;
late bool _enabled;
Timer _backgroundLockLatencyTimer;
Timer? _backgroundLockLatencyTimer;
@override
void initState() {
@ -139,7 +139,7 @@ class _AppLockState extends State<AppLock> with WidgetsBindingObserver {
/// when built. Use this when you want to inject objects created from the
/// [lockScreen] in to the rest of your app so you can better guarantee that some
/// objects, services or databases are already instantiated before using them.
void didUnlock([Object args]) {
void didUnlock([Object? args]) {
if (this._didUnlockForAppLaunch) {
this._didUnlockOnAppPaused();
} else {
@ -178,17 +178,17 @@ class _AppLockState extends State<AppLock> with WidgetsBindingObserver {
/// Manually show the [lockScreen].
Future<void> showLockScreen() {
this._isLocked = true;
return _navigatorKey.currentState.pushNamed('/lock-screen');
return _navigatorKey.currentState!.pushNamed('/lock-screen');
}
void _didUnlockOnAppLaunch(Object args) {
void _didUnlockOnAppLaunch(Object? args) {
this._didUnlockForAppLaunch = true;
_navigatorKey.currentState
_navigatorKey.currentState!
.pushReplacementNamed('/unlocked', arguments: args);
}
void _didUnlockOnAppPaused() {
this._isLocked = false;
_navigatorKey.currentState.pop();
_navigatorKey.currentState!.pop();
}
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io';
import 'dart:ui';
@ -8,14 +8,14 @@ import 'package:photos/ui/common/loading_widget.dart';
class LogFileViewer extends StatefulWidget {
final File file;
const LogFileViewer(this.file, {Key key}) : super(key: key);
const LogFileViewer(this.file, {Key? key}) : super(key: key);
@override
State<LogFileViewer> createState() => _LogFileViewerState();
}
class _LogFileViewerState extends State<LogFileViewer> {
String _logs;
String? _logs;
@override
void initState() {
widget.file.readAsString().then((logs) {
@ -45,7 +45,7 @@ class _LogFileViewerState extends State<LogFileViewer> {
padding: const EdgeInsets.only(left: 12, top: 8, right: 12),
child: SingleChildScrollView(
child: Text(
_logs,
_logs!,
style: const TextStyle(
fontFeatures: [
FontFeature.tabularFigures(),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -21,7 +21,7 @@ import 'package:photos/utils/toast_util.dart';
class DeduplicatePage extends StatefulWidget {
final List<DuplicateFiles> duplicates;
const DeduplicatePage(this.duplicates, {Key key}) : super(key: key);
const DeduplicatePage(this.duplicates, {Key? key}) : super(key: key);
@override
State<DeduplicatePage> createState() => _DeduplicatePageState();
@ -47,9 +47,9 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
);
final Set<File> _selectedFiles = <File>{};
final Map<int, int> _fileSizeMap = {};
List<DuplicateFiles> _duplicates;
bool _shouldClubByCaptureTime = true;
final Map<int?, int> _fileSizeMap = {};
late List<DuplicateFiles> _duplicates;
bool? _shouldClubByCaptureTime = true;
SortKey sortKey = SortKey.size;
@ -91,7 +91,7 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
Radius.circular(8),
),
),
onSelected: (value) {
onSelected: (dynamic value) {
setState(() {
_selectedFiles.clear();
});
@ -114,7 +114,7 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
"Deselect all",
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(fontWeight: FontWeight.w600),
),
),
@ -138,7 +138,7 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
} else if (sortKey == SortKey.count) {
return second.files.length - first.files.length;
} else {
return second.files.first.creationTime - first.files.first.creationTime;
return second.files.first.creationTime! - first.files.first.creationTime!;
}
});
}
@ -197,7 +197,7 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
children: [
Text(
"Following files were clubbed based on their sizes" +
((_shouldClubByCaptureTime ? " and capture times." : ".")),
(_shouldClubByCaptureTime! ? " and capture times." : "."),
style: Theme.of(context).textTheme.subtitle2,
),
const Padding(
@ -234,7 +234,7 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
}
void _resetEntriesAndSelection() {
if (_shouldClubByCaptureTime) {
if (_shouldClubByCaptureTime!) {
_duplicates =
DeduplicationService.instance.clubDuplicatesByTime(_duplicates);
} else {
@ -259,9 +259,9 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
}
return Text(
text,
style: Theme.of(context).textTheme.subtitle1.copyWith(
style: Theme.of(context).textTheme.subtitle1!.copyWith(
fontSize: 14,
color: Theme.of(context).iconTheme.color.withOpacity(0.7),
color: Theme.of(context).iconTheme.color!.withOpacity(0.7),
),
);
}
@ -320,7 +320,7 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
}
int size = 0;
for (final file in _selectedFiles) {
size += _fileSizeMap[file.uploadedFileID];
size += _fileSizeMap[file.uploadedFileID]!;
}
return SizedBox(
width: double.infinity,
@ -471,9 +471,9 @@ class _DeduplicatePageState extends State<DeduplicatePage> {
padding: const EdgeInsets.only(right: 2),
child: Text(
CollectionsService.instance
.getCollectionByID(file.collectionID)
.name,
style: Theme.of(context).textTheme.caption.copyWith(fontSize: 12),
.getCollectionByID(file.collectionID!)!
.name!,
style: Theme.of(context).textTheme.caption!.copyWith(fontSize: 12),
overflow: TextOverflow.ellipsis,
),
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:math';
@ -7,14 +7,14 @@ import 'package:image_editor/image_editor.dart';
class FilteredImage extends StatelessWidget {
const FilteredImage({
@required this.child,
required this.child,
this.brightness,
this.saturation,
this.hue,
Key key,
Key? key,
}) : super(key: key);
final double brightness, saturation, hue;
final double? brightness, saturation, hue;
final Widget child;
@override

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
@ -38,7 +36,7 @@ class ImageEditorPage extends StatefulWidget {
this.imageProvider,
this.originalFile,
this.detailPageConfig, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -57,8 +55,8 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
final GlobalKey<ExtendedImageEditorState> editorKey =
GlobalKey<ExtendedImageEditorState>();
double _brightness = kBrightnessDefault;
double _saturation = kSaturationDefault;
double? _brightness = kBrightnessDefault;
double? _saturation = kSaturationDefault;
bool _hasEdited = false;
@override
@ -81,7 +79,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
IconButton(
padding: const EdgeInsets.only(right: 16, left: 16),
onPressed: () {
editorKey.currentState.reset();
editorKey.currentState!.reset();
setState(() {
_brightness = kBrightnessDefault;
_saturation = kSaturationDefault;
@ -163,7 +161,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
}
Widget _buildFlipButton() {
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2;
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2!;
return GestureDetector(
behavior: HitTestBehavior.translucent,
@ -178,7 +176,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
padding: const EdgeInsets.only(bottom: 2),
child: Icon(
Icons.flip,
color: Theme.of(context).iconTheme.color.withOpacity(0.8),
color: Theme.of(context).iconTheme.color!.withOpacity(0.8),
size: 20,
),
),
@ -186,7 +184,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
Text(
"Flip",
style: subtitle2.copyWith(
color: subtitle2.color.withOpacity(0.8),
color: subtitle2.color!.withOpacity(0.8),
),
textAlign: TextAlign.center,
),
@ -197,7 +195,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
}
Widget _buildRotateLeftButton() {
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2;
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2!;
return GestureDetector(
behavior: HitTestBehavior.translucent,
@ -210,13 +208,13 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
children: [
Icon(
Icons.rotate_left,
color: Theme.of(context).iconTheme.color.withOpacity(0.8),
color: Theme.of(context).iconTheme.color!.withOpacity(0.8),
),
const Padding(padding: EdgeInsets.all(2)),
Text(
"Rotate left",
style: subtitle2.copyWith(
color: subtitle2.color.withOpacity(0.8),
color: subtitle2.color!.withOpacity(0.8),
),
textAlign: TextAlign.center,
),
@ -227,7 +225,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
}
Widget _buildRotateRightButton() {
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2;
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2!;
return GestureDetector(
behavior: HitTestBehavior.translucent,
@ -240,13 +238,13 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
children: [
Icon(
Icons.rotate_right,
color: Theme.of(context).iconTheme.color.withOpacity(0.8),
color: Theme.of(context).iconTheme.color!.withOpacity(0.8),
),
const Padding(padding: EdgeInsets.all(2)),
Text(
"Rotate right",
style: subtitle2.copyWith(
color: subtitle2.color.withOpacity(0.8),
color: subtitle2.color!.withOpacity(0.8),
),
textAlign: TextAlign.center,
),
@ -257,7 +255,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
}
Widget _buildSaveButton() {
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2;
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2!;
return GestureDetector(
behavior: HitTestBehavior.translucent,
@ -270,13 +268,13 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
children: [
Icon(
Icons.save_alt_outlined,
color: Theme.of(context).iconTheme.color.withOpacity(0.8),
color: Theme.of(context).iconTheme.color!.withOpacity(0.8),
),
const Padding(padding: EdgeInsets.all(2)),
Text(
"Save copy",
style: subtitle2.copyWith(
color: subtitle2.color.withOpacity(0.8),
color: subtitle2.color!.withOpacity(0.8),
),
textAlign: TextAlign.center,
),
@ -289,15 +287,15 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
Future<void> _saveEdits() async {
final dialog = createProgressDialog(context, "Saving...");
await dialog.show();
final ExtendedImageEditorState state = editorKey.currentState;
final ExtendedImageEditorState? state = editorKey.currentState;
if (state == null) {
return;
}
final Rect rect = state.getCropRect();
final Rect? rect = state.getCropRect();
if (rect == null) {
return;
}
final EditActionDetails action = state.editAction;
final EditActionDetails action = state.editAction!;
final double radian = action.rotateAngle;
final bool flipHorizontal = action.flipY;
@ -320,13 +318,13 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
option.addOption(RotateOption(radian.toInt()));
}
option.addOption(ColorOption.saturation(_saturation));
option.addOption(ColorOption.brightness(_brightness));
option.addOption(ColorOption.saturation(_saturation!));
option.addOption(ColorOption.brightness(_brightness!));
option.outputFormat = const OutputFormat.png(88);
final DateTime start = DateTime.now();
final Uint8List result = await ImageEditor.editImage(
final Uint8List? result = await ImageEditor.editImage(
image: img,
imageEditorOption: option,
);
@ -341,16 +339,14 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
}
try {
final fileName =
path.basenameWithoutExtension(widget.originalFile.title) +
path.basenameWithoutExtension(widget.originalFile.title!) +
"_edited_" +
DateTime.now().microsecondsSinceEpoch.toString() +
path.extension(widget.originalFile.title);
final newAsset = await PhotoManager.editor.saveImage(
result,
title: fileName,
);
final newFile =
await ente.File.fromAsset(widget.originalFile.deviceFolder, newAsset);
path.extension(widget.originalFile.title!);
final AssetEntity? newAsset =
await (PhotoManager.editor.saveImage(result, title: fileName));
final newFile = await ente.File.fromAsset(
widget.originalFile.deviceFolder!, newAsset!);
newFile.creationTime = widget.originalFile.creationTime;
newFile.collectionID = widget.originalFile.collectionID;
newFile.location = widget.originalFile.location;
@ -369,9 +365,9 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
_logger.info("Original file " + widget.originalFile.toString());
_logger.info("Saved edits to file " + newFile.toString());
final existingFiles = widget.detailPageConfig.files;
final files = (await widget.detailPageConfig.asyncLoader(
existingFiles[existingFiles.length - 1].creationTime,
existingFiles[0].creationTime,
final files = (await widget.detailPageConfig.asyncLoader!(
existingFiles[existingFiles.length - 1].creationTime!,
existingFiles[0].creationTime!,
))
.files;
// the index could be -1 if the files fetched doesn't contain the newly
@ -406,7 +402,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
}
Widget _buildSat() {
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2;
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2!;
return Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
@ -417,7 +413,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
child: Text(
"Color",
style: subtitle2.copyWith(
color: subtitle2.color.withOpacity(0.8),
color: subtitle2.color!.withOpacity(0.8),
),
),
),
@ -452,7 +448,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
}
Widget _buildBrightness() {
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2;
final TextStyle subtitle2 = Theme.of(context).textTheme.subtitle2!;
return Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
@ -463,7 +459,7 @@ class _ImageEditorPageState extends State<ImageEditorPage> {
child: Text(
"Light",
style: subtitle2.copyWith(
color: subtitle2.color.withOpacity(0.8),
color: subtitle2.color!.withOpacity(0.8),
),
),
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
@ -14,7 +14,7 @@ class FreeSpacePage extends StatefulWidget {
const FreeSpacePage(
this.status, {
Key key,
Key? key,
this.clearSpaceForFolder = false,
}) : super(key: key);

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
@ -7,7 +7,7 @@ import 'package:photos/ui/tools/app_lock.dart';
import 'package:photos/utils/auth_util.dart';
class LockScreen extends StatefulWidget {
const LockScreen({Key key}) : super(key: key);
const LockScreen({Key? key}) : super(key: key);
@override
State<LockScreen> createState() => _LockScreenState();
@ -100,7 +100,7 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
);
_isShowingLockScreen = false;
if (result) {
AppLock.of(context).didUnlock();
AppLock.of(context)!.didUnlock();
} else {
_logger.info("Dismissed");
if (!_hasPlacedAppInBackground) {

View file

@ -1,17 +1,18 @@
// @dart=2.9
import 'package:flutter/material.dart';
class CustomAppBar extends PreferredSize {
@override
final Widget child;
@override
final Size preferredSize;
final double height;
const CustomAppBar(this.child, {Key key, this.height = kToolbarHeight})
: super(key: key);
@override
Size get preferredSize => Size.fromHeight(height);
const CustomAppBar(
this.child,
this.preferredSize, {
Key? key,
this.height = kToolbarHeight,
}) : super(key: key, child: child, preferredSize: preferredSize);
@override
Widget build(BuildContext context) {

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -24,7 +22,7 @@ enum DetailPageMode {
class DetailPageConfiguration {
final List<File> files;
final GalleryLoader asyncLoader;
final GalleryLoader? asyncLoader;
final int selectedIndex;
final String tagPrefix;
final DetailPageMode mode;
@ -38,10 +36,10 @@ class DetailPageConfiguration {
});
DetailPageConfiguration copyWith({
List<File> files,
GalleryLoader asyncLoader,
int selectedIndex,
String tagPrefix,
List<File>? files,
GalleryLoader? asyncLoader,
int? selectedIndex,
String? tagPrefix,
}) {
return DetailPageConfiguration(
files ?? this.files,
@ -65,15 +63,15 @@ class _DetailPageState extends State<DetailPage> {
static const kLoadLimit = 100;
final _logger = Logger("DetailPageState");
bool _shouldDisableScroll = false;
List<File> _files;
PageController _pageController;
List<File>? _files;
PageController? _pageController;
int _selectedIndex = 0;
bool _hasPageChanged = false;
bool _hasLoadedTillStart = false;
bool _hasLoadedTillEnd = false;
bool _shouldHideAppBar = false;
GlobalKey<FadingAppBarState> _appBarKey;
GlobalKey<FadingBottomBarState> _bottomBarKey;
GlobalKey<FadingAppBarState>? _appBarKey;
GlobalKey<FadingBottomBarState>? _bottomBarKey;
@override
void initState() {
@ -98,18 +96,18 @@ class _DetailPageState extends State<DetailPage> {
Widget build(BuildContext context) {
_logger.info(
"Opening " +
_files[_selectedIndex].toString() +
_files![_selectedIndex].toString() +
". " +
(_selectedIndex + 1).toString() +
" / " +
_files.length.toString() +
_files!.length.toString() +
" files .",
);
_appBarKey = GlobalKey<FadingAppBarState>();
_bottomBarKey = GlobalKey<FadingBottomBarState>();
return Scaffold(
appBar: FadingAppBar(
_files[_selectedIndex],
_files![_selectedIndex],
_onFileRemoved,
Configuration.instance.getUserID(),
100,
@ -122,7 +120,7 @@ class _DetailPageState extends State<DetailPage> {
children: [
_buildPageView(),
FadingBottomBar(
_files[_selectedIndex],
_files![_selectedIndex],
_onEditFileRequested,
widget.config.mode == DetailPageMode.minimalistic,
key: _bottomBarKey,
@ -140,7 +138,7 @@ class _DetailPageState extends State<DetailPage> {
_pageController = PageController(initialPage: _selectedIndex);
return PageView.builder(
itemBuilder: (context, index) {
final file = _files[index];
final file = _files![index];
final Widget content = FileWidget(
file,
autoPlay: !_hasPageChanged,
@ -181,17 +179,17 @@ class _DetailPageState extends State<DetailPage> {
? const NeverScrollableScrollPhysics()
: const PageScrollPhysics(),
controller: _pageController,
itemCount: _files.length,
itemCount: _files!.length,
);
}
void _toggleFullScreen() {
if (_shouldHideAppBar) {
_appBarKey.currentState.hide();
_bottomBarKey.currentState.hide();
_appBarKey!.currentState!.hide();
_bottomBarKey!.currentState!.hide();
} else {
_appBarKey.currentState.show();
_bottomBarKey.currentState.show();
_appBarKey!.currentState!.show();
_bottomBarKey!.currentState!.show();
}
Future.delayed(Duration.zero, () {
SystemChrome.setEnabledSystemUIMode(
@ -207,8 +205,8 @@ class _DetailPageState extends State<DetailPage> {
return;
}
if (_selectedIndex == 0 && !_hasLoadedTillStart) {
final result = await widget.config.asyncLoader(
_files[_selectedIndex].creationTime + 1,
final result = await widget.config.asyncLoader!(
_files![_selectedIndex].creationTime! + 1,
DateTime.now().microsecondsSinceEpoch,
limit: kLoadLimit,
asc: true,
@ -221,38 +219,38 @@ class _DetailPageState extends State<DetailPage> {
_hasLoadedTillStart = true;
}
final length = files.length;
files.addAll(_files);
files.addAll(_files!);
_files = files;
_pageController.jumpToPage(length);
_pageController!.jumpToPage(length);
_selectedIndex = length;
});
}
if (_selectedIndex == _files.length - 1 && !_hasLoadedTillEnd) {
final result = await widget.config.asyncLoader(
if (_selectedIndex == _files!.length - 1 && !_hasLoadedTillEnd) {
final result = await widget.config.asyncLoader!(
galleryLoadStartTime,
_files[_selectedIndex].creationTime - 1,
_files![_selectedIndex].creationTime! - 1,
limit: kLoadLimit,
);
setState(() {
if (!result.hasMore) {
_hasLoadedTillEnd = true;
}
_files.addAll(result.files);
_files!.addAll(result.files);
});
}
}
void _preloadFiles(int index) {
if (index > 0) {
preloadFile(_files[index - 1]);
preloadFile(_files![index - 1]);
}
if (index < _files.length - 1) {
preloadFile(_files[index + 1]);
if (index < _files!.length - 1) {
preloadFile(_files![index + 1]);
}
}
Future<void> _onFileRemoved(File file) async {
final totalFiles = _files.length;
final totalFiles = _files!.length;
if (totalFiles == 1) {
// Deleted the only file
Navigator.of(context).pop(); // Close pageview
@ -260,21 +258,21 @@ class _DetailPageState extends State<DetailPage> {
}
if (_selectedIndex == totalFiles - 1) {
// Deleted the last file
await _pageController.previousPage(
await _pageController!.previousPage(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
);
setState(() {
_files.remove(file);
_files!.remove(file);
});
} else {
await _pageController.nextPage(
await _pageController!.nextPage(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
);
setState(() {
_selectedIndex--;
_files.remove(file);
_files!.remove(file);
});
}
}
@ -297,7 +295,7 @@ class _DetailPageState extends State<DetailPage> {
final dialog = createProgressDialog(context, "Please wait...");
await dialog.show();
final imageProvider =
ExtendedFileImageProvider(await getFile(file), cacheRawData: true);
ExtendedFileImageProvider((await getFile(file))!, cacheRawData: true);
await precacheImage(imageProvider, context);
await dialog.hide();
replacePage(

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:photos/ui/common/loading_widget.dart';
@ -7,16 +5,16 @@ import 'package:photos/ui/viewer/file/file_info_collection_widget.dart';
class DeviceFoldersListOfFileWidget extends StatelessWidget {
final Future<Set<String>> allDeviceFoldersOfFile;
const DeviceFoldersListOfFileWidget(this.allDeviceFoldersOfFile, {Key key})
const DeviceFoldersListOfFileWidget(this.allDeviceFoldersOfFile, {Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
return FutureBuilder(
return FutureBuilder<Set<String>>(
future: allDeviceFoldersOfFile,
builder: (context, snapshot) {
if (snapshot.hasData) {
final List<String> deviceFolders = snapshot.data.toList();
final List<String> deviceFolders = snapshot.data!.toList();
return ListView.builder(
itemCount: deviceFolders.length,
scrollDirection: Axis.horizontal,

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:ui';
@ -9,7 +9,7 @@ import 'package:photos/utils/exif_util.dart';
class ExifInfoDialog extends StatefulWidget {
final File file;
const ExifInfoDialog(this.file, {Key key}) : super(key: key);
const ExifInfoDialog(this.file, {Key? key}) : super(key: key);
@override
State<ExifInfoDialog> createState() => _ExifInfoDialogState();
@ -21,7 +21,7 @@ class _ExifInfoDialogState extends State<ExifInfoDialog> {
final scrollController = ScrollController();
return AlertDialog(
title: Text(
widget.file.title,
widget.file.title!,
style: Theme.of(context).textTheme.headline5,
),
content: Scrollbar(

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:io';
import 'dart:io' as io;
@ -37,7 +35,7 @@ class FadingAppBar extends StatefulWidget implements PreferredSizeWidget {
final Function(File) onFileRemoved;
final double height;
final bool shouldShowActions;
final int userID;
final int? userID;
const FadingAppBar(
this.file,
@ -45,7 +43,7 @@ class FadingAppBar extends StatefulWidget implements PreferredSizeWidget {
this.userID,
this.height,
this.shouldShowActions, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -84,7 +82,7 @@ class FadingAppBarState extends State<FadingAppBar> {
),
),
),
height: Platform.isAndroid ? 80 : 96,
Size.fromHeight(Platform.isAndroid ? 80 : 96),
);
}
@ -114,7 +112,7 @@ class FadingAppBarState extends State<FadingAppBar> {
bool isFileHidden = false;
if (isOwnedByUser && isFileUploaded) {
isFileHidden = CollectionsService.instance
.getCollectionByID(widget.file.collectionID)
.getCollectionByID(widget.file.collectionID!)
?.isHidden() ??
false;
}
@ -231,7 +229,7 @@ class FadingAppBarState extends State<FadingAppBar> {
}
return items;
},
onSelected: (value) {
onSelected: (dynamic value) {
if (value == 1) {
_download(widget.file);
} else if (value == 2) {
@ -285,7 +283,7 @@ class FadingAppBarState extends State<FadingAppBar> {
}
Widget _getFavoriteButton() {
return FutureBuilder(
return FutureBuilder<bool>(
future: FavoritesService.instance.isFavorite(widget.file),
builder: (context, snapshot) {
if (snapshot.hasData) {
@ -297,7 +295,7 @@ class FadingAppBarState extends State<FadingAppBar> {
);
}
Widget _getLikeButton(File file, bool isLiked) {
Widget _getLikeButton(File file, bool? isLiked) {
return LikeButton(
isLiked: isLiked,
onTap: (oldValue) async {
@ -305,7 +303,7 @@ class FadingAppBarState extends State<FadingAppBar> {
bool hasError = false;
if (isLiked) {
final shouldBlockUser = file.uploadedFileID == null;
ProgressDialog dialog;
late ProgressDialog dialog;
if (shouldBlockUser) {
dialog = createProgressDialog(context, "Adding to favorites...");
await dialog.show();
@ -417,27 +415,27 @@ class FadingAppBarState extends State<FadingAppBar> {
final FileType type = file.fileType;
final bool downloadLivePhotoOnDroid =
type == FileType.livePhoto && Platform.isAndroid;
AssetEntity savedAsset;
final io.File fileToSave = await getFile(file);
AssetEntity? savedAsset;
final io.File? fileToSave = await getFile(file);
if (type == FileType.image) {
savedAsset = await PhotoManager.editor
.saveImageWithPath(fileToSave.path, title: file.title);
.saveImageWithPath(fileToSave!.path, title: file.title!);
} else if (type == FileType.video) {
savedAsset =
await PhotoManager.editor.saveVideo(fileToSave, title: file.title);
savedAsset = await PhotoManager.editor
.saveVideo(fileToSave!, title: file.title!);
} else if (type == FileType.livePhoto) {
final io.File liveVideoFile =
final io.File? liveVideoFile =
await getFileFromServer(file, liveVideo: true);
if (liveVideoFile == null) {
throw AssertionError("Live video can not be null");
}
if (downloadLivePhotoOnDroid) {
await _saveLivePhotoOnDroid(fileToSave, liveVideoFile, file);
await _saveLivePhotoOnDroid(fileToSave!, liveVideoFile, file);
} else {
savedAsset = await PhotoManager.editor.darwin.saveLivePhoto(
imageFile: fileToSave,
imageFile: fileToSave!,
videoFile: liveVideoFile,
title: file.title,
title: file.title!,
);
}
}
@ -479,8 +477,11 @@ class FadingAppBarState extends State<FadingAppBar> {
File enteFile,
) async {
debugPrint("Downloading LivePhoto on Droid");
AssetEntity savedAsset = await PhotoManager.editor
.saveImageWithPath(image.path, title: enteFile.title);
AssetEntity? savedAsset = await (PhotoManager.editor
.saveImageWithPath(image.path, title: enteFile.title!));
if (savedAsset == null) {
throw Exception("Failed to save image of live photo");
}
IgnoredFile ignoreVideoFile = IgnoredFile(
savedAsset.id,
savedAsset.title ?? '',
@ -488,12 +489,16 @@ class FadingAppBarState extends State<FadingAppBar> {
"remoteDownload",
);
await IgnoredFilesService.instance.cacheAndInsert([ignoreVideoFile]);
final videoTitle = file_path.basenameWithoutExtension(enteFile.title) +
final videoTitle = file_path.basenameWithoutExtension(enteFile.title!) +
file_path.extension(video.path);
savedAsset = (await PhotoManager.editor.saveVideo(
savedAsset = (await (PhotoManager.editor.saveVideo(
video,
title: videoTitle,
));
)));
if (savedAsset == null) {
throw Exception("Failed to save video of live photo");
}
ignoreVideoFile = IgnoredFile(
savedAsset.id,
savedAsset.title ?? videoTitle,
@ -507,7 +512,10 @@ class FadingAppBarState extends State<FadingAppBar> {
final dialog = createProgressDialog(context, "Please wait...");
await dialog.show();
try {
final io.File fileToSave = await getFile(file);
final io.File? fileToSave = await (getFile(file));
if (fileToSave == null) {
throw Exception("Fail to get file for setAs operation");
}
final m = MediaExtension();
final bool result = await m.setAs("file://${fileToSave.path}", "image/*");
if (result == false) {

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io';
@ -30,7 +30,7 @@ class FadingBottomBar extends StatefulWidget {
this.file,
this.onEditRequested,
this.showOnlyInfoButton, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -96,7 +96,7 @@ class FadingBottomBarState extends State<FadingBottomBar> {
bool isFileHidden = false;
if (isUploadedByUser) {
isFileHidden = CollectionsService.instance
.getCollectionByID(widget.file.collectionID)
.getCollectionByID(widget.file.collectionID!)
?.isHidden() ??
false;
}
@ -203,7 +203,7 @@ class FadingBottomBarState extends State<FadingBottomBar> {
12,
),
child: Text(
widget.file.caption,
widget.file.caption!,
overflow: TextOverflow.ellipsis,
maxLines: 4,
style: getEnteTextTheme(context)
@ -269,7 +269,7 @@ class FadingBottomBarState extends State<FadingBottomBar> {
),
onPressed: () async {
final trashedFile = <TrashFile>[];
trashedFile.add(widget.file);
trashedFile.add(widget.file as TrashFile);
if (await deleteFromTrash(context, trashedFile) == true) {
Navigator.pop(context);
}

View file

@ -1,18 +1,18 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
class FileInfoCollectionWidget extends StatelessWidget {
final String name;
final Function onTap;
const FileInfoCollectionWidget({this.name, this.onTap, Key key})
final String? name;
final Function? onTap;
const FileInfoCollectionWidget({this.name, this.onTap, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
onTap: onTap as void Function()?,
child: Container(
margin: const EdgeInsets.only(
top: 10,
@ -32,7 +32,7 @@ class FileInfoCollectionWidget extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(
name,
name!,
style: Theme.of(context).textTheme.subtitle2,
overflow: TextOverflow.ellipsis,
),

View file

@ -1,11 +1,10 @@
// @dart=2.9
import 'dart:ui';
import "package:exif/exif.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:photo_manager/photo_manager.dart';
import "package:photos/core/configuration.dart";
import 'package:photos/db/files_db.dart';
import "package:photos/ente_theme_data.dart";
@ -30,7 +29,7 @@ class FileInfoWidget extends StatefulWidget {
const FileInfoWidget(
this.file, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -38,7 +37,7 @@ class FileInfoWidget extends StatefulWidget {
}
class _FileInfoWidgetState extends State<FileInfoWidget> {
Map<String, IfdTag> _exif;
Map<String, IfdTag>? _exif;
final Map<String, dynamic> _exifData = {
"focalLength": null,
"fNumber": null,
@ -50,7 +49,7 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
};
bool _isImage = false;
int _currentUserID;
int? _currentUserID;
@override
void initState() {
@ -76,22 +75,21 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
final fileIsBackedup = file.uploadedFileID == null ? false : true;
final bool isFileOwner =
file.ownerID == null || file.ownerID == _currentUserID;
Future<Set<int>> allCollectionIDsOfFile;
Future<Set<String>>
allDeviceFoldersOfFile; //Typing this as Future<Set<T>> as it would be easier to implement showing multiple device folders for a file in the future
late Future<Set<int>> allCollectionIDsOfFile;
; //Typing this as Future<Set<T>> as it would be easier to implement showing multiple device folders for a file in the future
Future<Set<String>> allDeviceFoldersOfFile =
Future.sync(() => {file.deviceFolder ?? ''});
if (fileIsBackedup) {
allCollectionIDsOfFile = FilesDB.instance.getAllCollectionIDsOfFile(
file.uploadedFileID,
file.uploadedFileID!,
);
} else {
allDeviceFoldersOfFile = Future.sync(() => {file.deviceFolder});
}
final dateTime = DateTime.fromMicrosecondsSinceEpoch(file.creationTime);
final dateTime = DateTime.fromMicrosecondsSinceEpoch(file.creationTime!);
final dateTimeForUpdationTime =
DateTime.fromMicrosecondsSinceEpoch(file.updationTime);
DateTime.fromMicrosecondsSinceEpoch(file.updationTime!);
if (_isImage && _exif != null) {
_generateExifForDetails(_exif);
_generateExifForDetails(_exif!);
}
final bool showExifListTile = _exifData["focalLength"] != null ||
_exifData["fNumber"] != null ||
@ -100,7 +98,7 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
_exifData["ISO"] != null;
final bool showDimension =
_exifData["resolution"] != null && _exifData["megaPixels"] != null;
final listTiles = <Widget>[
final listTiles = <Widget?>[
!widget.file.isUploaded ||
(!isFileOwner && (widget.file.caption?.isEmpty ?? true))
? const SizedBox.shrink()
@ -108,7 +106,7 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
padding: const EdgeInsets.only(top: 8, bottom: 4),
child: isFileOwner
? FileCaptionWidget(file: widget.file)
: FileCaptionReadyOnly(caption: widget.file.caption),
: FileCaptionReadyOnly(caption: widget.file.caption!),
),
ListTile(
horizontalTitleGap: 2,
@ -118,12 +116,12 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
),
title: Text(
getFullDate(
DateTime.fromMicrosecondsSinceEpoch(file.creationTime),
DateTime.fromMicrosecondsSinceEpoch(file.creationTime!),
),
),
subtitle: Text(
getTimeIn12hrFormat(dateTime) + " " + dateTime.timeZoneName,
style: Theme.of(context).textTheme.bodyText2.copyWith(
style: Theme.of(context).textTheme.bodyText2!.copyWith(
color: Theme.of(context)
.colorScheme
.defaultTextColor
@ -232,7 +230,7 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
title: fileIsBackedup
? CollectionsListOfFileWidget(
allCollectionIDsOfFile,
_currentUserID,
_currentUserID!,
)
: DeviceFoldersListOfFileWidget(allDeviceFoldersOfFile),
),
@ -246,14 +244,14 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
),
title: Text(
getFullDate(
DateTime.fromMicrosecondsSinceEpoch(file.updationTime),
DateTime.fromMicrosecondsSinceEpoch(file.updationTime!),
),
),
subtitle: Text(
getTimeIn12hrFormat(dateTimeForUpdationTime) +
" " +
dateTimeForUpdationTime.timeZoneName,
style: Theme.of(context).textTheme.bodyText2.copyWith(
style: Theme.of(context).textTheme.bodyText2!.copyWith(
color: Theme.of(context)
.colorScheme
.defaultTextColor
@ -320,14 +318,14 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
if (file.uploadedFileID == null) {
return const SizedBox.shrink();
}
String addedBy;
String? addedBy;
if (file.ownerID == _currentUserID) {
if (file.pubMagicMetadata.uploaderName != null) {
addedBy = file.pubMagicMetadata.uploaderName;
if (file.pubMagicMetadata!.uploaderName != null) {
addedBy = file.pubMagicMetadata!.uploaderName;
}
} else {
final fileOwner = CollectionsService.instance
.getFileOwner(file.ownerID, file.collectionID);
.getFileOwner(file.ownerID!, file.collectionID);
if (fileOwner != null) {
addedBy = fileOwner.email;
}
@ -349,15 +347,15 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
_generateExifForDetails(Map<String, IfdTag> exif) {
if (exif["EXIF FocalLength"] != null) {
_exifData["focalLength"] =
(exif["EXIF FocalLength"].values.toList()[0] as Ratio).numerator /
(exif["EXIF FocalLength"].values.toList()[0] as Ratio)
(exif["EXIF FocalLength"]!.values.toList()[0] as Ratio).numerator /
(exif["EXIF FocalLength"]!.values.toList()[0] as Ratio)
.denominator;
}
if (exif["EXIF FNumber"] != null) {
_exifData["fNumber"] =
(exif["EXIF FNumber"].values.toList()[0] as Ratio).numerator /
(exif["EXIF FNumber"].values.toList()[0] as Ratio).denominator;
(exif["EXIF FNumber"]!.values.toList()[0] as Ratio).numerator /
(exif["EXIF FNumber"]!.values.toList()[0] as Ratio).denominator;
}
final imageWidth = exif["EXIF ExifImageWidth"] ?? exif["Image ImageWidth"];
final imageLength = exif["EXIF ExifImageLength"] ??
@ -390,14 +388,14 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
if (widget.file.fileSize != null) {
fileSizeFuture = Future.value(widget.file.fileSize);
} else {
fileSizeFuture = getFile(widget.file).then((f) => f.length());
fileSizeFuture = getFile(widget.file).then((f) => f!.length());
}
return FutureBuilder(
return FutureBuilder<int>(
future: fileSizeFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
(snapshot.data / (1024 * 1024)).toStringAsFixed(2) + " MB",
(snapshot.data! / (1024 * 1024)).toStringAsFixed(2) + " MB",
);
} else {
return Center(
@ -416,15 +414,15 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
Widget _getVideoDuration() {
if (widget.file.duration != 0) {
return Text(
secondsToHHMMSS(widget.file.duration),
secondsToHHMMSS(widget.file.duration!),
);
}
return FutureBuilder(
return FutureBuilder<AssetEntity?>(
future: widget.file.getAsset,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
snapshot.data.videoDuration.toString().split(".")[0],
snapshot.data!.videoDuration.toString().split(".")[0],
);
} else {
return Center(
@ -445,7 +443,7 @@ class _FileInfoWidgetState extends State<FileInfoWidget> {
context,
minTime: DateTime(1800, 1, 1),
maxTime: DateTime.now(),
currentTime: DateTime.fromMicrosecondsSinceEpoch(file.creationTime),
currentTime: DateTime.fromMicrosecondsSinceEpoch(file.creationTime!),
locale: LocaleType.en,
theme: Theme.of(context).colorScheme.dateTimePickertheme,
);

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
@ -10,11 +10,11 @@ import 'package:photos/ui/viewer/file/zoomable_live_image.dart';
class FileWidget extends StatelessWidget {
final File file;
final String tagPrefix;
final Function(bool) shouldDisableScroll;
final Function(bool) playbackCallback;
final BoxDecoration backgroundDecoration;
final bool autoPlay;
final String? tagPrefix;
final Function(bool)? shouldDisableScroll;
final Function(bool)? playbackCallback;
final BoxDecoration? backgroundDecoration;
final bool? autoPlay;
const FileWidget(
this.file, {
@ -23,7 +23,7 @@ class FileWidget extends StatelessWidget {
this.playbackCallback,
this.tagPrefix,
this.backgroundDecoration,
Key key,
Key? key,
}) : super(key: key);
@override

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:exif/exif.dart';
import 'package:flutter/material.dart';
@ -15,8 +15,8 @@ enum Status {
class RawExifListTileWidget extends StatelessWidget {
final File file;
final Map<String, IfdTag> exif;
const RawExifListTileWidget(this.exif, this.file, {Key key})
final Map<String, IfdTag>? exif;
const RawExifListTileWidget(this.exif, this.file, {Key? key})
: super(key: key);
@override
@ -24,7 +24,7 @@ class RawExifListTileWidget extends StatelessWidget {
Status exifStatus = Status.loading;
if (exif == null) {
exifStatus = Status.loading;
} else if (exif.isNotEmpty) {
} else if (exif!.isNotEmpty) {
exifStatus = Status.exifIsAvailable;
} else {
exifStatus = Status.noExif;
@ -58,7 +58,7 @@ class RawExifListTileWidget extends StatelessWidget {
: exifStatus == Status.exifIsAvailable
? "View all EXIF data"
: "No EXIF data",
style: Theme.of(context).textTheme.bodyText2.copyWith(
style: Theme.of(context).textTheme.bodyText2!.copyWith(
color: Theme.of(context)
.colorScheme
.defaultTextColor

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/cache/thumbnail_cache.dart';
@ -23,20 +21,20 @@ import 'package:photos/utils/file_util.dart';
import 'package:photos/utils/thumbnail_util.dart';
class ThumbnailWidget extends StatefulWidget {
final File file;
final File? file;
final BoxFit fit;
final bool shouldShowSyncStatus;
final bool shouldShowArchiveStatus;
final bool showFavForAlbumOnly;
final bool shouldShowLivePhotoOverlay;
final Duration diskLoadDeferDuration;
final Duration serverLoadDeferDuration;
final Duration? diskLoadDeferDuration;
final Duration? serverLoadDeferDuration;
final int thumbnailSize;
final bool shouldShowOwnerAvatar;
ThumbnailWidget(
this.file, {
Key key,
Key? key,
this.fit = BoxFit.cover,
this.shouldShowSyncStatus = true,
this.shouldShowLivePhotoOverlay = false,
@ -46,7 +44,7 @@ class ThumbnailWidget extends StatefulWidget {
this.diskLoadDeferDuration,
this.serverLoadDeferDuration,
this.thumbnailSize = thumbnailSmallSize,
}) : super(key: key ?? Key(file.tag));
}) : super(key: key ?? Key(file!.tag));
@override
State<ThumbnailWidget> createState() => _ThumbnailWidgetState();
@ -59,7 +57,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
bool _errorLoadingLocalThumbnail = false;
bool _isLoadingRemoteThumbnail = false;
bool _errorLoadingRemoteThumbnail = false;
ImageProvider _imageProvider;
ImageProvider? _imageProvider;
@override
void initState() {
@ -71,8 +69,8 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
super.dispose();
Future.delayed(const Duration(milliseconds: 10), () {
// Cancel request only if the widget has been unmounted
if (!mounted && widget.file.isRemoteFile && !_hasLoadedThumbnail) {
removePendingGetThumbnailRequestIfAny(widget.file);
if (!mounted && widget.file!.isRemoteFile && !_hasLoadedThumbnail) {
removePendingGetThumbnailRequestIfAny(widget.file!);
}
});
}
@ -80,62 +78,62 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
@override
void didUpdateWidget(ThumbnailWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.file.generatedID != oldWidget.file.generatedID) {
if (widget.file!.generatedID != oldWidget.file!.generatedID) {
_reset();
}
}
@override
Widget build(BuildContext context) {
if (widget.file.isRemoteFile) {
if (widget.file!.isRemoteFile) {
_loadNetworkImage();
} else {
_loadLocalImage(context);
}
Widget image;
Widget? image;
if (_imageProvider != null) {
image = Image(
image: _imageProvider,
image: _imageProvider!,
fit: widget.fit,
);
}
// todo: [2ndJuly22] pref-review if the content Widget which depends on
// thumbnail fetch logic should be part of separate stateFull widget.
// If yes, parent thumbnail widget can be stateless
Widget content;
Widget? content;
if (image != null) {
final List<Widget> contentChildren = [image];
if (FavoritesService.instance.isFavoriteCache(
widget.file,
widget.file!,
checkOnlyAlbum: widget.showFavForAlbumOnly,
)) {
contentChildren.add(const FavoriteOverlayIcon());
}
if (widget.file.fileType == FileType.video) {
if (widget.file!.fileType == FileType.video) {
contentChildren.add(const VideoOverlayIcon());
} else if (widget.file.fileType == FileType.livePhoto &&
} else if (widget.file!.fileType == FileType.livePhoto &&
widget.shouldShowLivePhotoOverlay) {
contentChildren.add(const LivePhotoOverlayIcon());
}
if (widget.shouldShowOwnerAvatar) {
final owner = CollectionsService.instance
.getFileOwner(widget.file.ownerID, widget.file.collectionID);
if (widget.file.ownerID != null &&
widget.file.ownerID != Configuration.instance.getUserID()) {
if (widget.file!.ownerID != null &&
widget.file!.ownerID != Configuration.instance.getUserID()) {
final owner = CollectionsService.instance
.getFileOwner(widget.file!.ownerID!, widget.file!.collectionID);
// hide this icon if the current thumbnail is being showed as album
// cover
contentChildren.add(
OwnerAvatarOverlayIcon(owner),
);
} else if (widget.file.pubMagicMetadata.uploaderName != null) {
} else if (widget.file!.pubMagicMetadata!.uploaderName != null) {
contentChildren.add(
// Use uploadName hashCode as userID so that different uploader
// get avatar color
OwnerAvatarOverlayIcon(
User(
id: widget.file.pubMagicMetadata.uploaderName.sumAsciiValues,
email: owner.email,
name: widget.file.pubMagicMetadata.uploaderName,
id: widget.file!.pubMagicMetadata!.uploaderName.sumAsciiValues,
email: '',
name: widget.file!.pubMagicMetadata!.uploaderName,
),
),
);
@ -156,11 +154,11 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
child: content,
)
];
if (widget.shouldShowSyncStatus && widget.file.uploadedFileID == null) {
if (widget.shouldShowSyncStatus && widget.file!.uploadedFileID == null) {
viewChildren.add(const UnSyncedIcon());
}
if (widget.file is TrashFile) {
viewChildren.add(TrashedFileOverlayText(widget.file));
viewChildren.add(TrashedFileOverlayText(widget.file as TrashFile));
}
// todo: Move this icon overlay to the collection widget.
if (widget.shouldShowArchiveStatus) {
@ -179,13 +177,13 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
!_isLoadingLocalThumbnail) {
_isLoadingLocalThumbnail = true;
final cachedSmallThumbnail =
ThumbnailLruCache.get(widget.file, thumbnailSmallSize);
ThumbnailLruCache.get(widget.file!, thumbnailSmallSize);
if (cachedSmallThumbnail != null) {
_imageProvider = Image.memory(cachedSmallThumbnail).image;
_hasLoadedThumbnail = true;
} else {
if (widget.diskLoadDeferDuration != null) {
Future.delayed(widget.diskLoadDeferDuration, () {
Future.delayed(widget.diskLoadDeferDuration!, () {
if (mounted) {
_getThumbnailFromDisk();
}
@ -199,23 +197,23 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
Future _getThumbnailFromDisk() async {
getThumbnailFromLocal(
widget.file,
widget.file!,
size: widget.thumbnailSize,
).then((thumbData) async {
if (thumbData == null) {
if (widget.file.uploadedFileID != null) {
_logger.fine("Removing localID reference for " + widget.file.tag);
widget.file.localID = null;
if (widget.file!.uploadedFileID != null) {
_logger.fine("Removing localID reference for " + widget.file!.tag);
widget.file!.localID = null;
if (widget.file is TrashFile) {
TrashDB.instance.update(widget.file);
TrashDB.instance.update(widget.file as TrashFile);
} else {
FilesDB.instance.update(widget.file);
FilesDB.instance.update(widget.file!);
}
_loadNetworkImage();
} else {
if (await doesLocalFileExist(widget.file) == false) {
_logger.info("Deleting file " + widget.file.tag);
FilesDB.instance.deleteLocalFile(widget.file);
if (await doesLocalFileExist(widget.file!) == false) {
_logger.info("Deleting file " + widget.file!.tag);
FilesDB.instance.deleteLocalFile(widget.file!);
Bus.instance.fire(
LocalPhotosUpdatedEvent(
[widget.file],
@ -232,7 +230,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
final imageProvider = Image.memory(thumbData).image;
_cacheAndRender(imageProvider);
}
ThumbnailLruCache.put(widget.file, thumbData, thumbnailSmallSize);
ThumbnailLruCache.put(widget.file!, thumbData, thumbnailSmallSize);
}).catchError((e) {
_logger.warning("Could not load image: ", e);
_errorLoadingLocalThumbnail = true;
@ -244,14 +242,14 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
!_errorLoadingRemoteThumbnail &&
!_isLoadingRemoteThumbnail) {
_isLoadingRemoteThumbnail = true;
final cachedThumbnail = ThumbnailLruCache.get(widget.file);
final cachedThumbnail = ThumbnailLruCache.get(widget.file!);
if (cachedThumbnail != null) {
_imageProvider = Image.memory(cachedThumbnail).image;
_hasLoadedThumbnail = true;
return;
}
if (widget.serverLoadDeferDuration != null) {
Future.delayed(widget.serverLoadDeferDuration, () {
Future.delayed(widget.serverLoadDeferDuration!, () {
if (mounted) {
_getThumbnailFromServer();
}
@ -264,7 +262,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
void _getThumbnailFromServer() async {
try {
final thumbnail = await getThumbnailFromServer(widget.file);
final thumbnail = await getThumbnailFromServer(widget.file!);
if (mounted) {
final imageProvider = Image.memory(thumbnail).image;
_cacheAndRender(imageProvider);

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -10,7 +10,7 @@ import 'package:photos/utils/date_time_util.dart';
import 'package:video_player/video_player.dart';
class VideoControls extends StatefulWidget {
const VideoControls({Key key}) : super(key: key);
const VideoControls({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
@ -19,27 +19,27 @@ class VideoControls extends StatefulWidget {
}
class _VideoControlsState extends State<VideoControls> {
VideoPlayerValue _latestValue;
VideoPlayerValue? _latestValue;
bool _hideStuff = true;
Timer _hideTimer;
Timer _initTimer;
Timer _showAfterExpandCollapseTimer;
Timer? _hideTimer;
Timer? _initTimer;
Timer? _showAfterExpandCollapseTimer;
bool _dragging = false;
bool _displayTapped = false;
final barHeight = 120.0;
final marginSize = 5.0;
VideoPlayerController controller;
ChewieController chewieController;
late VideoPlayerController controller;
ChewieController? chewieController;
@override
Widget build(BuildContext context) {
if (_latestValue.hasError) {
return chewieController.errorBuilder != null
? chewieController.errorBuilder(
if (_latestValue!.hasError) {
return chewieController!.errorBuilder != null
? chewieController!.errorBuilder!(
context,
chewieController.videoPlayerController.value.errorDescription,
chewieController!.videoPlayerController.value.errorDescription!,
)
: Center(
child: Icon(
@ -63,9 +63,9 @@ class _VideoControlsState extends State<VideoControls> {
Column(
children: [
_latestValue != null &&
!_latestValue.isPlaying &&
_latestValue.duration == null ||
_latestValue.isBuffering
!_latestValue!.isPlaying &&
_latestValue!.duration == null ||
_latestValue!.isBuffering
? const Center(
child: CircularProgressIndicator(),
)
@ -100,7 +100,7 @@ class _VideoControlsState extends State<VideoControls> {
void didChangeDependencies() {
final oldController = chewieController;
chewieController = ChewieController.of(context);
controller = chewieController.videoPlayerController;
controller = chewieController!.videoPlayerController;
if (oldController != chewieController) {
_dispose();
@ -113,7 +113,7 @@ class _VideoControlsState extends State<VideoControls> {
Widget _buildBottomBar(
BuildContext context,
) {
final iconColor = Theme.of(context).textTheme.button.color;
final iconColor = Theme.of(context).textTheme.button!.color;
return Container(
padding: const EdgeInsets.only(bottom: 60),
@ -126,7 +126,7 @@ class _VideoControlsState extends State<VideoControls> {
child: Row(
children: <Widget>[
_buildCurrentPosition(iconColor),
chewieController.isLive ? const SizedBox() : _buildProgressBar(),
chewieController!.isLive ? const SizedBox() : _buildProgressBar(),
_buildTotalDuration(iconColor),
],
),
@ -167,7 +167,7 @@ class _VideoControlsState extends State<VideoControls> {
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Icon(
_latestValue.isPlaying ? Icons.pause : Icons.play_arrow,
_latestValue!.isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white, // same for both themes
size: 64.0,
),
@ -180,9 +180,9 @@ class _VideoControlsState extends State<VideoControls> {
);
}
Widget _buildCurrentPosition(Color iconColor) {
final position = _latestValue != null && _latestValue.position != null
? _latestValue.position
Widget _buildCurrentPosition(Color? iconColor) {
final position = _latestValue != null && _latestValue!.position != null
? _latestValue!.position
: Duration.zero;
return Container(
@ -197,9 +197,9 @@ class _VideoControlsState extends State<VideoControls> {
);
}
Widget _buildTotalDuration(Color iconColor) {
final duration = _latestValue != null && _latestValue.duration != null
? _latestValue.duration
Widget _buildTotalDuration(Color? iconColor) {
final duration = _latestValue != null && _latestValue!.duration != null
? _latestValue!.duration
: Duration.zero;
return Padding(
@ -230,11 +230,11 @@ class _VideoControlsState extends State<VideoControls> {
_updateState();
if ((controller.value != null && controller.value.isPlaying) ||
chewieController.autoPlay) {
chewieController!.autoPlay) {
_startHideTimer();
}
if (chewieController.showControlsOnInitialize) {
if (chewieController!.showControlsOnInitialize) {
_initTimer = Timer(const Duration(milliseconds: 200), () {
setState(() {
_hideStuff = false;
@ -244,7 +244,7 @@ class _VideoControlsState extends State<VideoControls> {
}
void _playPause() {
final bool isFinished = _latestValue.position >= _latestValue.duration;
final bool isFinished = _latestValue!.position >= _latestValue!.duration;
setState(() {
if (controller.value.isPlaying) {
@ -302,7 +302,7 @@ class _VideoControlsState extends State<VideoControls> {
_startHideTimer();
},
colors: chewieController.materialProgressColors ??
colors: chewieController!.materialProgressColors ??
ChewieProgressColors(
playedColor: Theme.of(context).colorScheme.greenAlternative,
handleColor: Colors.white,

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:async';
import 'dart:io' as io;
@ -21,16 +19,16 @@ import 'package:wakelock/wakelock.dart';
class VideoWidget extends StatefulWidget {
final File file;
final bool autoPlay;
final String tagPrefix;
final Function(bool) playbackCallback;
final bool? autoPlay;
final String? tagPrefix;
final Function(bool)? playbackCallback;
const VideoWidget(
this.file, {
this.autoPlay = false,
this.tagPrefix,
this.playbackCallback,
Key key,
Key? key,
}) : super(key: key);
@override
@ -39,10 +37,10 @@ class VideoWidget extends StatefulWidget {
class _VideoWidgetState extends State<VideoWidget> {
final _logger = Logger("VideoWidget");
VideoPlayerController _videoPlayerController;
ChewieController _chewieController;
double _progress;
bool _isPlaying;
VideoPlayerController? _videoPlayerController;
ChewieController? _chewieController;
double? _progress;
bool _isPlaying = false;
bool _wakeLockEnabledHere = false;
@override
@ -78,7 +76,7 @@ class _VideoWidgetState extends State<VideoWidget> {
if (widget.file.fileSize == null &&
widget.file.ownerID == Configuration.instance.getUserID()) {
FilesService.instance
.getFileSize(widget.file.uploadedFileID)
.getFileSize(widget.file.uploadedFileID!)
.then((value) {
widget.file.fileSize = value;
if (mounted) {
@ -111,10 +109,10 @@ class _VideoWidgetState extends State<VideoWidget> {
@override
void dispose() {
if (_videoPlayerController != null) {
_videoPlayerController.dispose();
_videoPlayerController!.dispose();
}
if (_chewieController != null) {
_chewieController.dispose();
_chewieController!.dispose();
}
if (_wakeLockEnabledHere) {
unawaited(
@ -126,12 +124,13 @@ class _VideoWidgetState extends State<VideoWidget> {
super.dispose();
}
VideoPlayerController _setVideoPlayerController({String url, io.File file}) {
VideoPlayerController _setVideoPlayerController(
{String? url, io.File? file}) {
VideoPlayerController videoPlayerController;
if (url != null) {
videoPlayerController = VideoPlayerController.network(url);
} else {
videoPlayerController = VideoPlayerController.file(file);
videoPlayerController = VideoPlayerController.file(file!);
}
return _videoPlayerController = videoPlayerController
..initialize().whenComplete(() {
@ -144,7 +143,7 @@ class _VideoWidgetState extends State<VideoWidget> {
@override
Widget build(BuildContext context) {
final content = _videoPlayerController != null &&
_videoPlayerController.value.isInitialized
_videoPlayerController!.value.isInitialized
? _getVideoPlayer()
: _getLoadingWidget();
final contentWithDetector = GestureDetector(
@ -158,12 +157,12 @@ class _VideoWidgetState extends State<VideoWidget> {
onVisibilityChanged: (info) {
if (info.visibleFraction < 1) {
if (mounted && _chewieController != null) {
_chewieController.pause();
_chewieController!.pause();
}
}
},
child: Hero(
tag: widget.tagPrefix + widget.file.tag,
tag: widget.tagPrefix! + widget.file.tag,
child: contentWithDetector,
),
);
@ -225,19 +224,19 @@ class _VideoWidgetState extends State<VideoWidget> {
}
Widget _getVideoPlayer() {
_videoPlayerController.addListener(() {
if (_isPlaying != _videoPlayerController.value.isPlaying) {
_isPlaying = _videoPlayerController.value.isPlaying;
_videoPlayerController!.addListener(() {
if (_isPlaying != _videoPlayerController!.value.isPlaying) {
_isPlaying = _videoPlayerController!.value.isPlaying;
if (widget.playbackCallback != null) {
widget.playbackCallback(_isPlaying);
widget.playbackCallback!(_isPlaying);
}
unawaited(_keepScreenAliveOnPlaying(_isPlaying));
unawaited(_keepScreenAliveOnPlaying(_isPlaying!));
}
});
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
aspectRatio: _videoPlayerController.value.aspectRatio,
autoPlay: widget.autoPlay,
videoPlayerController: _videoPlayerController!,
aspectRatio: _videoPlayerController!.value.aspectRatio,
autoPlay: widget.autoPlay!,
autoInitialize: true,
looping: true,
allowMuting: true,
@ -246,7 +245,7 @@ class _VideoWidgetState extends State<VideoWidget> {
);
return Container(
color: Colors.black,
child: Chewie(controller: _chewieController),
child: Chewie(controller: _chewieController!),
);
}
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io';
@ -18,16 +18,16 @@ import 'package:photos/utils/file_util.dart';
import 'package:photos/utils/thumbnail_util.dart';
class ZoomableImage extends StatefulWidget {
final File photo;
final Function(bool) shouldDisableScroll;
final String tagPrefix;
final Decoration backgroundDecoration;
final File? photo;
final Function(bool)? shouldDisableScroll;
final String? tagPrefix;
final Decoration? backgroundDecoration;
const ZoomableImage(
this.photo, {
Key key,
Key? key,
this.shouldDisableScroll,
@required this.tagPrefix,
required this.tagPrefix,
this.backgroundDecoration,
}) : super(key: key);
@ -38,14 +38,14 @@ class ZoomableImage extends StatefulWidget {
class _ZoomableImageState extends State<ZoomableImage>
with SingleTickerProviderStateMixin {
final Logger _logger = Logger("ZoomableImage");
File _photo;
ImageProvider _imageProvider;
File? _photo;
ImageProvider? _imageProvider;
bool _loadedSmallThumbnail = false;
bool _loadingLargeThumbnail = false;
bool _loadedLargeThumbnail = false;
bool _loadingFinalImage = false;
bool _loadedFinalImage = false;
ValueChanged<PhotoViewScaleState> _scaleStateChangedCallback;
ValueChanged<PhotoViewScaleState>? _scaleStateChangedCallback;
bool _isZooming = false;
@override
@ -54,7 +54,7 @@ class _ZoomableImageState extends State<ZoomableImage>
debugPrint('initState for ${_photo.toString()}');
_scaleStateChangedCallback = (value) {
if (widget.shouldDisableScroll != null) {
widget.shouldDisableScroll(value != PhotoViewScaleState.initial);
widget.shouldDisableScroll!(value != PhotoViewScaleState.initial);
}
_isZooming = value != PhotoViewScaleState.initial;
debugPrint("isZooming = $_isZooming, currentState $value");
@ -65,7 +65,7 @@ class _ZoomableImageState extends State<ZoomableImage>
@override
Widget build(BuildContext context) {
if (_photo.isRemoteFile) {
if (_photo!.isRemoteFile) {
_loadNetworkImage();
} else {
_loadLocalImage(context);
@ -81,16 +81,16 @@ class _ZoomableImageState extends State<ZoomableImage>
minScale: PhotoViewComputedScale.contained,
gaplessPlayback: true,
heroAttributes: PhotoViewHeroAttributes(
tag: widget.tagPrefix + _photo.tag,
tag: widget.tagPrefix! + _photo!.tag,
),
backgroundDecoration: widget.backgroundDecoration,
backgroundDecoration: widget.backgroundDecoration as BoxDecoration?,
),
);
} else {
content = const EnteLoadingWidget();
}
final GestureDragUpdateCallback verticalDragCallback = _isZooming
final GestureDragUpdateCallback? verticalDragCallback = _isZooming
? null
: (d) => {
if (!_isZooming && d.delta.dy > dragSensitivity)
@ -104,12 +104,12 @@ class _ZoomableImageState extends State<ZoomableImage>
void _loadNetworkImage() {
if (!_loadedSmallThumbnail && !_loadedFinalImage) {
final cachedThumbnail = ThumbnailLruCache.get(_photo);
final cachedThumbnail = ThumbnailLruCache.get(_photo!);
if (cachedThumbnail != null) {
_imageProvider = Image.memory(cachedThumbnail).image;
_loadedSmallThumbnail = true;
} else {
getThumbnailFromServer(_photo).then((file) {
getThumbnailFromServer(_photo!).then((file) {
final imageProvider = Image.memory(file).image;
if (mounted) {
precacheImage(imageProvider, context).then((value) {
@ -128,10 +128,10 @@ class _ZoomableImageState extends State<ZoomableImage>
}
}
if (!_loadedFinalImage) {
getFileFromServer(_photo).then((file) {
getFileFromServer(_photo!).then((file) {
_onFinalImageLoaded(
Image.file(
file,
file!,
gaplessPlayback: true,
).image,
);
@ -143,7 +143,7 @@ class _ZoomableImageState extends State<ZoomableImage>
if (!_loadedSmallThumbnail &&
!_loadedLargeThumbnail &&
!_loadedFinalImage) {
final cachedThumbnail = ThumbnailLruCache.get(_photo, thumbnailSmallSize);
final cachedThumbnail = ThumbnailLruCache.get(_photo!, thumbnailSmallSize);
if (cachedThumbnail != null) {
_imageProvider = Image.memory(cachedThumbnail).image;
_loadedSmallThumbnail = true;
@ -154,7 +154,7 @@ class _ZoomableImageState extends State<ZoomableImage>
!_loadedLargeThumbnail &&
!_loadedFinalImage) {
_loadingLargeThumbnail = true;
getThumbnailFromLocal(_photo, size: thumbnailLargeSize, quality: 100)
getThumbnailFromLocal(_photo!, size: thumbnailLargeSize, quality: 100)
.then((cachedThumbnail) {
if (cachedThumbnail != null) {
_onLargeThumbnailLoaded(Image.memory(cachedThumbnail).image, context);
@ -165,7 +165,7 @@ class _ZoomableImageState extends State<ZoomableImage>
if (!_loadingFinalImage && !_loadedFinalImage) {
_loadingFinalImage = true;
getFile(
_photo,
_photo!,
isOrigin: Platform.isIOS &&
_isGIF(), // since on iOS GIFs playback only when origin-files are loaded
).then((file) {
@ -173,12 +173,12 @@ class _ZoomableImageState extends State<ZoomableImage>
_onFinalImageLoaded(Image.file(file).image);
} else {
_logger.info("File was deleted " + _photo.toString());
if (_photo.uploadedFileID != null) {
_photo.localID = null;
FilesDB.instance.update(_photo);
if (_photo!.uploadedFileID != null) {
_photo!.localID = null;
FilesDB.instance.update(_photo!);
_loadNetworkImage();
} else {
FilesDB.instance.deleteLocalFile(_photo);
FilesDB.instance.deleteLocalFile(_photo!);
Bus.instance.fire(
LocalPhotosUpdatedEvent(
[_photo],
@ -221,5 +221,5 @@ class _ZoomableImageState extends State<ZoomableImage>
}
}
bool _isGIF() => _photo.displayName.toLowerCase().endsWith(".gif");
bool _isGIF() => _photo!.displayName.toLowerCase().endsWith(".gif");
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:io' as io;
@ -15,15 +15,15 @@ import 'package:video_player/video_player.dart';
class ZoomableLiveImage extends StatefulWidget {
final File file;
final Function(bool) shouldDisableScroll;
final String tagPrefix;
final Decoration backgroundDecoration;
final Function(bool)? shouldDisableScroll;
final String? tagPrefix;
final Decoration? backgroundDecoration;
const ZoomableLiveImage(
this.file, {
Key key,
Key? key,
this.shouldDisableScroll,
@required this.tagPrefix,
required this.tagPrefix,
this.backgroundDecoration,
}) : super(key: key);
@ -34,12 +34,12 @@ class ZoomableLiveImage extends StatefulWidget {
class _ZoomableLiveImageState extends State<ZoomableLiveImage>
with SingleTickerProviderStateMixin {
final Logger _logger = Logger("ZoomableLiveImage");
File _file;
File? _file;
bool _showVideo = false;
bool _isLoadingVideoPlayer = false;
VideoPlayerController _videoPlayerController;
ChewieController _chewieController;
VideoPlayerController? _videoPlayerController;
ChewieController? _chewieController;
@override
void initState() {
@ -51,7 +51,7 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
void _onLongPressEvent(bool isPressed) {
if (_videoPlayerController != null && isPressed == false) {
// stop playing video
_videoPlayerController.pause();
_videoPlayerController!.pause();
}
if (mounted) {
setState(() {
@ -88,20 +88,20 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
@override
void dispose() {
if (_videoPlayerController != null) {
_videoPlayerController.pause();
_videoPlayerController.dispose();
_videoPlayerController!.pause();
_videoPlayerController!.dispose();
}
if (_chewieController != null) {
_chewieController.dispose();
_chewieController!.dispose();
}
super.dispose();
}
Widget _getVideoPlayer() {
_videoPlayerController.seekTo(Duration.zero);
_videoPlayerController!.seekTo(Duration.zero);
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
aspectRatio: _videoPlayerController.value.aspectRatio,
videoPlayerController: _videoPlayerController!,
aspectRatio: _videoPlayerController!.value.aspectRatio,
autoPlay: true,
autoInitialize: true,
looping: true,
@ -110,7 +110,7 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
);
return Container(
color: Colors.black,
child: Chewie(controller: _chewieController), // same for both theme
child: Chewie(controller: _chewieController!), // same for both theme
);
}
@ -120,14 +120,14 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
return;
}
_isLoadingVideoPlayer = true;
if (_file.isRemoteFile && !(await isFileCached(_file, liveVideo: true))) {
if (_file!.isRemoteFile && !(await isFileCached(_file!, liveVideo: true))) {
showShortToast(context, "Downloading...");
}
var videoFile = await getFile(widget.file, liveVideo: true)
io.File? videoFile = await getFile(widget.file, liveVideo: true)
.timeout(const Duration(seconds: 15))
.onError((e, s) {
_logger.info("getFile failed ${_file.tag}", e);
.onError((dynamic e, s) {
_logger.info("getFile failed ${_file!.tag}", e);
return null;
});
@ -135,11 +135,11 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
// getFile with liveVideo as true can fail for file with localID when
// the live photo was downloaded from remote.
if ((videoFile == null || !videoFile.existsSync()) &&
_file.uploadedFileID != null) {
_file!.uploadedFileID != null) {
videoFile = await getFileFromServer(widget.file, liveVideo: true)
.timeout(const Duration(seconds: 15))
.onError((e, s) {
_logger.info("getRemoteFile failed ${_file.tag}", e);
.onError((dynamic e, s) {
_logger.info("getRemoteFile failed ${_file!.tag}", e);
return null;
});
}
@ -152,7 +152,7 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
_isLoadingVideoPlayer = false;
}
VideoPlayerController _setVideoPlayerController({io.File file}) {
VideoPlayerController _setVideoPlayerController({required io.File file}) {
final videoPlayerController = VideoPlayerController.file(file);
return _videoPlayerController = videoPlayerController
..initialize().whenComplete(() {

View file

@ -1,5 +1,6 @@
// @dart=2.9
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
@ -23,7 +24,7 @@ class ArchivePage extends StatelessWidget {
this.tagPrefix = "archived_page",
this.appBarType = GalleryType.archive,
this.overlayType = GalleryType.archive,
Key key,
Key? key,
}) : super(key: key);
@override
@ -35,7 +36,7 @@ class ArchivePage extends StatelessWidget {
return FilesDB.instance.getAllPendingOrUploadedFiles(
creationStartTime,
creationEndTime,
Configuration.instance.getUserID(),
Configuration.instance.getUserID()!,
visibility: visibilityArchive,
limit: limit,
asc: asc,
@ -44,9 +45,8 @@ class ArchivePage extends StatelessWidget {
},
reloadEvent: Bus.instance.on<FilesUpdatedEvent>().where(
(event) =>
event.updatedFiles.firstWhere(
event.updatedFiles.firstWhereOrNull(
(element) => element.uploadedFileID != null,
orElse: () => null,
) !=
null,
),
@ -54,9 +54,8 @@ class ArchivePage extends StatelessWidget {
forceReloadEvents: [
Bus.instance.on<FilesUpdatedEvent>().where(
(event) =>
event.updatedFiles.firstWhere(
event.updatedFiles.firstWhereOrNull(
(element) => element.uploadedFileID != null,
orElse: () => null,
) !=
null,
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
@ -26,7 +26,7 @@ class CollectionPage extends StatefulWidget {
this.tagPrefix = "collection",
this.appBarType = GalleryType.ownedCollection,
this.hasVerifiedLock = false,
Key key,
Key? key,
}) : super(key: key);
@override

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
@ -20,7 +20,7 @@ class DeviceFolderPage extends StatelessWidget {
final DeviceCollection deviceCollection;
final _selectedFiles = SelectedFiles();
DeviceFolderPage(this.deviceCollection, {Key key}) : super(key: key);
DeviceFolderPage(this.deviceCollection, {Key? key}) : super(key: key);
@override
Widget build(Object context) {
@ -74,7 +74,7 @@ class DeviceFolderPage extends StatelessWidget {
class BackupConfigurationHeaderWidget extends StatefulWidget {
final DeviceCollection deviceCollection;
const BackupConfigurationHeaderWidget(this.deviceCollection, {Key key})
const BackupConfigurationHeaderWidget(this.deviceCollection, {Key? key})
: super(key: key);
@override
@ -84,7 +84,7 @@ class BackupConfigurationHeaderWidget extends StatefulWidget {
class _BackupConfigurationHeaderWidgetState
extends State<BackupConfigurationHeaderWidget> {
bool _isBackedUp;
late bool _isBackedUp;
@override
void initState() {

View file

@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:async';
import 'package:flutter/foundation.dart';
@ -25,28 +23,28 @@ import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
typedef GalleryLoader = Future<FileLoadResult> Function(
int creationStartTime,
int creationEndTime, {
int limit,
bool asc,
int? limit,
bool? asc,
});
class Gallery extends StatefulWidget {
final GalleryLoader asyncLoader;
final List<File> initialFiles;
final Stream<FilesUpdatedEvent> reloadEvent;
final List<Stream<Event>> forceReloadEvents;
final List<File?>? initialFiles;
final Stream<FilesUpdatedEvent>? reloadEvent;
final List<Stream<Event>>? forceReloadEvents;
final Set<EventType> removalEventTypes;
final SelectedFiles selectedFiles;
final SelectedFiles? selectedFiles;
final String tagPrefix;
final Widget header;
final Widget footer;
final Widget? header;
final Widget? footer;
final Widget emptyState;
final String albumName;
final String? albumName;
final double scrollBottomSafeArea;
const Gallery({
@required this.asyncLoader,
@required this.selectedFiles,
@required this.tagPrefix,
required this.asyncLoader,
required this.selectedFiles,
required this.tagPrefix,
this.initialFiles,
this.reloadEvent,
this.forceReloadEvents,
@ -56,7 +54,7 @@ class Gallery extends StatefulWidget {
this.emptyState = const EmptyState(),
this.scrollBottomSafeArea = 120.0,
this.albumName = '',
Key key,
Key? key,
}) : super(key: key);
@override
@ -70,25 +68,25 @@ class _GalleryState extends State<Gallery> {
final _hugeListViewKey = GlobalKey<HugeListViewState>();
Logger _logger;
List<List<File>> _collatedFiles = [];
late Logger _logger;
List<List<File?>> _collatedFiles = [];
bool _hasLoadedFiles = false;
ItemScrollController _itemScroller;
StreamSubscription<FilesUpdatedEvent> _reloadEventSubscription;
StreamSubscription<TabDoubleTapEvent> _tabDoubleTapEvent;
ItemScrollController? _itemScroller;
StreamSubscription<FilesUpdatedEvent>? _reloadEventSubscription;
StreamSubscription<TabDoubleTapEvent>? _tabDoubleTapEvent;
final _forceReloadEventSubscriptions = <StreamSubscription<Event>>[];
String _logTag;
int _photoGridSize;
String? _logTag;
int? _photoGridSize;
@override
void initState() {
_logTag =
"Gallery_${widget.tagPrefix}${kDebugMode ? "_" + widget.albumName : ""}";
_logger = Logger(_logTag);
"Gallery_${widget.tagPrefix}${kDebugMode ? "_" + widget.albumName! : ""}";
_logger = Logger(_logTag!);
_logger.finest("init Gallery");
_itemScroller = ItemScrollController();
if (widget.reloadEvent != null) {
_reloadEventSubscription = widget.reloadEvent.listen((event) async {
_reloadEventSubscription = widget.reloadEvent!.listen((event) async {
// In soft refresh, setState is called for entire gallery only when
// number of child change
_logger.finest("Soft refresh all files on ${event.reason} ");
@ -106,14 +104,14 @@ class _GalleryState extends State<Gallery> {
// todo: Assign ID to Gallery and fire generic event with ID &
// target index/date
if (mounted && event.selectedIndex == 0) {
_itemScroller.scrollTo(
_itemScroller!.scrollTo(
index: 0,
duration: const Duration(milliseconds: 150),
);
}
});
if (widget.forceReloadEvents != null) {
for (final event in widget.forceReloadEvents) {
for (final event in widget.forceReloadEvents!) {
_forceReloadEventSubscriptions.add(
event.listen((event) async {
_logger.finest("Force refresh all files on ${event.reason}");
@ -124,7 +122,7 @@ class _GalleryState extends State<Gallery> {
}
}
if (widget.initialFiles != null) {
_onFilesLoaded(widget.initialFiles);
_onFilesLoaded(widget.initialFiles!);
}
_loadFiles(limit: kInitialLoadLimit).then((result) async {
_setFilesAndReload(result.files);
@ -143,7 +141,7 @@ class _GalleryState extends State<Gallery> {
}
}
Future<FileLoadResult> _loadFiles({int limit}) async {
Future<FileLoadResult> _loadFiles({int? limit}) async {
_logger.info("Loading ${limit ?? "all"} files");
try {
final startTime = DateTime.now().microsecondsSinceEpoch;
@ -169,7 +167,7 @@ class _GalleryState extends State<Gallery> {
}
// Collates files and returns `true` if it resulted in a gallery reload
bool _onFilesLoaded(List<File> files) {
bool _onFilesLoaded(List<File?> files) {
final updatedCollatedFiles = _collateFiles(files);
if (_collatedFiles.length != updatedCollatedFiles.length ||
_collatedFiles.isEmpty) {
@ -219,7 +217,7 @@ class _GalleryState extends State<Gallery> {
emptyResultBuilder: (_) {
final List<Widget> children = [];
if (widget.header != null) {
children.add(widget.header);
children.add(widget.header!);
}
children.add(
Expanded(
@ -227,7 +225,7 @@ class _GalleryState extends State<Gallery> {
),
);
if (widget.footer != null) {
children.add(widget.footer);
children.add(widget.footer!);
}
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -252,17 +250,17 @@ class _GalleryState extends State<Gallery> {
photoGirdSize: _photoGridSize,
);
if (widget.header != null && index == 0) {
gallery = Column(children: [widget.header, gallery]);
gallery = Column(children: [widget.header!, gallery]);
}
if (widget.footer != null && index == _collatedFiles.length - 1) {
gallery = Column(children: [gallery, widget.footer]);
gallery = Column(children: [gallery, widget.footer!]);
}
return gallery;
},
labelTextBuilder: (int index) {
return getMonthAndYear(
DateTime.fromMicrosecondsSinceEpoch(
_collatedFiles[index][0].creationTime,
_collatedFiles[index][0]!.creationTime!,
),
);
},
@ -280,16 +278,16 @@ class _GalleryState extends State<Gallery> {
);
}
List<List<File>> _collateFiles(List<File> files) {
final List<File> dailyFiles = [];
final List<List<File>> collatedFiles = [];
List<List<File?>> _collateFiles(List<File?> files) {
final List<File?> dailyFiles = [];
final List<List<File?>> collatedFiles = [];
for (int index = 0; index < files.length; index++) {
if (index > 0 &&
!areFromSameDay(
files[index - 1].creationTime,
files[index].creationTime,
files[index - 1]!.creationTime!,
files[index]!.creationTime!,
)) {
final List<File> collatedDailyFiles = [];
final List<File?> collatedDailyFiles = [];
collatedDailyFiles.addAll(dailyFiles);
collatedFiles.add(collatedDailyFiles);
dailyFiles.clear();
@ -300,7 +298,7 @@ class _GalleryState extends State<Gallery> {
collatedFiles.add(dailyFiles);
}
collatedFiles
.sort((a, b) => b[0].creationTime.compareTo(a[0].creationTime));
.sort((a, b) => b[0]!.creationTime!.compareTo(a[0]!.creationTime!));
return collatedFiles;
}
}

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:io';
@ -35,16 +35,16 @@ import 'package:url_launcher/url_launcher_string.dart';
class GalleryAppBarWidget extends StatefulWidget {
final GalleryType type;
final String title;
final String? title;
final SelectedFiles selectedFiles;
final DeviceCollection deviceCollection;
final Collection collection;
final DeviceCollection? deviceCollection;
final Collection? collection;
const GalleryAppBarWidget(
this.type,
this.title,
this.selectedFiles, {
Key key,
Key? key,
this.deviceCollection,
this.collection,
}) : super(key: key);
@ -55,9 +55,9 @@ class GalleryAppBarWidget extends StatefulWidget {
class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
final _logger = Logger("GalleryAppBar");
StreamSubscription _userAuthEventSubscription;
Function() _selectedFilesListener;
String _appBarTitle;
late StreamSubscription _userAuthEventSubscription;
late Function() _selectedFilesListener;
String? _appBarTitle;
final GlobalKey shareButtonKey = GlobalKey();
@override
@ -95,10 +95,10 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
? const SizedBox.shrink()
: TextButton(
child: Text(
_appBarTitle,
_appBarTitle!,
style: Theme.of(context)
.textTheme
.headline5
.headline5!
.copyWith(fontSize: 16),
),
onPressed: () => _renameAlbum(context),
@ -119,14 +119,14 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
barrierColor: Colors.black.withOpacity(0.85),
);
// indicates user cancelled the rename request
if (result == null || result.trim() == _appBarTitle.trim()) {
if (result == null || result.trim() == _appBarTitle!.trim()) {
return;
}
final dialog = createProgressDialog(context, "Changing name...");
await dialog.show();
try {
await CollectionsService.instance.rename(widget.collection, result);
await CollectionsService.instance.rename(widget.collection!, result);
await dialog.hide();
if (mounted) {
_appBarTitle = result;
@ -139,7 +139,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
}
Future<dynamic> _leaveAlbum(BuildContext context) async {
final DialogUserChoice result = await showChoiceDialog(
final DialogUserChoice? result = await showChoiceDialog(
context,
"Leave shared album?",
"You will leave the album, and it will stop being visible to you.",
@ -154,7 +154,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
final dialog = createProgressDialog(context, "Leaving album...");
await dialog.show();
try {
await CollectionsService.instance.leaveAlbum(widget.collection);
await CollectionsService.instance.leaveAlbum(widget.collection!);
await dialog.hide();
if (mounted) {
Navigator.of(context).pop();
@ -175,7 +175,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
BackupStatus status;
try {
status = await SyncService.instance
.getBackupStatus(pathID: widget.deviceCollection.id);
.getBackupStatus(pathID: widget.deviceCollection!.id);
} catch (e) {
await dialog.hide();
showGenericErrorDialog(context: context);
@ -190,7 +190,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
"You've no files in this album that can be deleted",
);
} else {
final bool result = await routeToPage(
final bool? result = await routeToPage(
context,
FreeSpacePage(status, clearSpaceForFolder: true),
);
@ -254,7 +254,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
}
final List<PopupMenuItem> items = [];
if (widget.type == GalleryType.ownedCollection) {
if (widget.collection.type != CollectionType.favorites) {
if (widget.collection!.type != CollectionType.favorites) {
items.add(
PopupMenuItem(
value: 1,
@ -270,10 +270,10 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
),
);
}
final bool isArchived = widget.collection.isArchived();
final bool isArchived = widget.collection!.isArchived();
// Do not show archive option for favorite collection. If collection is
// already archived, allow user to unarchive that collection.
if (isArchived || widget.collection.type != CollectionType.favorites) {
if (isArchived || widget.collection!.type != CollectionType.favorites) {
items.add(
PopupMenuItem(
value: 2,
@ -289,7 +289,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
),
);
}
if (widget.collection.type != CollectionType.favorites) {
if (widget.collection!.type != CollectionType.favorites) {
items.add(
PopupMenuItem(
value: 3,
@ -345,14 +345,14 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
itemBuilder: (context) {
return items;
},
onSelected: (value) async {
onSelected: (dynamic value) async {
if (value == 1) {
await _renameAlbum(context);
} else if (value == 2) {
await changeCollectionVisibility(
context,
widget.collection,
widget.collection.isArchived()
widget.collection!,
widget.collection!.isArchived()
? visibilityVisible
: visibilityArchive,
);
@ -378,7 +378,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
await CollectionsService.instance.getCollectionsWithThumbnails();
final bool isEmptyCollection = collectionWithThumbnail
.firstWhereOrNull(
(element) => element.collection.id == widget.collection.id,
(element) => element.collection.id == widget.collection!.id,
)
?.thumbnail ==
null;
@ -403,7 +403,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
await dialog.show();
try {
await CollectionsService.instance
.trashCollection(widget.collection, isEmptyCollection);
.trashCollection(widget.collection!, isEmptyCollection);
showShortToast(context, "Successfully deleted album");
await dialog.hide();
Navigator.of(context).pop();
@ -424,7 +424,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
"Cannot share empty collection of typex ${widget.type}",
);
}
if (Configuration.instance.getUserID() == widget.collection.owner.id) {
if (Configuration.instance.getUserID() == widget.collection!.owner!.id) {
unawaited(
routeToPage(
context,

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
import 'dart:io';
@ -28,15 +28,15 @@ import 'package:photos/utils/toast_util.dart';
class GalleryOverlayWidget extends StatefulWidget {
final GalleryType type;
final SelectedFiles selectedFiles;
final String path;
final Collection collection;
final String? path;
final Collection? collection;
const GalleryOverlayWidget(
this.type,
this.selectedFiles, {
this.path,
this.collection,
Key key,
Key? key,
}) : super(key: key);
@override
@ -44,8 +44,8 @@ class GalleryOverlayWidget extends StatefulWidget {
}
class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
StreamSubscription _userAuthEventSubscription;
Function() _selectedFilesListener;
late StreamSubscription _userAuthEventSubscription;
late Function() _selectedFilesListener;
final GlobalKey shareButtonKey = GlobalKey();
@override
@ -100,15 +100,15 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
class OverlayWidget extends StatefulWidget {
final GalleryType type;
final SelectedFiles selectedFiles;
final String path;
final Collection collection;
final String? path;
final Collection? collection;
const OverlayWidget(
this.type,
this.selectedFiles, {
this.path,
this.collection,
Key key,
Key? key,
}) : super(key: key);
@override
@ -117,8 +117,8 @@ class OverlayWidget extends StatefulWidget {
class _OverlayWidgetState extends State<OverlayWidget> {
final _logger = Logger("GalleryOverlay");
StreamSubscription _userAuthEventSubscription;
Function() _selectedFilesListener;
late StreamSubscription _userAuthEventSubscription;
late Function() _selectedFilesListener;
final GlobalKey shareButtonKey = GlobalKey();
@override
@ -172,7 +172,7 @@ class _OverlayWidgetState extends State<OverlayWidget> {
' selected',
style: Theme.of(context)
.textTheme
.subtitle2
.subtitle2!
.copyWith(
fontWeight: FontWeight.w600,
color:
@ -210,7 +210,7 @@ class _OverlayWidgetState extends State<OverlayWidget> {
child: Center(
child: Text(
'Cancel',
style: Theme.of(context).textTheme.subtitle2.copyWith(
style: Theme.of(context).textTheme.subtitle2!.copyWith(
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.iconColor,
),
@ -307,7 +307,7 @@ class _OverlayWidgetState extends State<OverlayWidget> {
}
if (Configuration.instance.hasConfiguredAccount() &&
widget.type == GalleryType.ownedCollection &&
widget.collection.type != CollectionType.favorites) {
widget.collection!.type != CollectionType.favorites) {
actions.add(
Tooltip(
message: "Move",
@ -357,7 +357,7 @@ class _OverlayWidgetState extends State<OverlayWidget> {
),
);
} else if (widget.type == GalleryType.ownedCollection) {
if (widget.collection.type == CollectionType.folder) {
if (widget.collection!.type == CollectionType.folder) {
actions.add(
Tooltip(
message: "Delete",
@ -645,7 +645,7 @@ class _OverlayWidgetState extends State<OverlayWidget> {
" file" +
(count == 1 ? "" : "s") +
" from " +
widget.collection.name +
widget.collection!.name! +
"?",
),
actions: <Widget>[
@ -657,7 +657,7 @@ class _OverlayWidgetState extends State<OverlayWidget> {
await dialog.show();
try {
await CollectionsService.instance.removeFromCollection(
widget.collection.id,
widget.collection!.id,
widget.selectedFiles.files.toList(),
);
await dialog.hide();

View file

@ -1,5 +1,6 @@
// @dart=2.9
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
@ -23,7 +24,7 @@ class HiddenPage extends StatelessWidget {
this.tagPrefix = "hidden_page",
this.appBarType = GalleryType.hidden,
this.overlayType = GalleryType.hidden,
Key key,
Key? key,
}) : super(key: key);
@override
@ -34,16 +35,15 @@ class HiddenPage extends StatelessWidget {
CollectionsService.instance.getHiddenCollections().toList(),
creationStartTime,
creationEndTime,
Configuration.instance.getUserID(),
Configuration.instance.getUserID()!,
limit: limit,
asc: asc,
);
},
reloadEvent: Bus.instance.on<FilesUpdatedEvent>().where(
(event) =>
event.updatedFiles.firstWhere(
event.updatedFiles.firstWhereOrNull(
(element) => element.uploadedFileID != null,
orElse: () => null,
) !=
null,
),
@ -55,9 +55,8 @@ class HiddenPage extends StatelessWidget {
forceReloadEvents: [
Bus.instance.on<FilesUpdatedEvent>().where(
(event) =>
event.updatedFiles.firstWhere(
event.updatedFiles.firstWhereOrNull(
(element) => element.uploadedFileID != null,
orElse: () => null,
) !=
null,
),

View file

@ -1,7 +1,8 @@
// @dart=2.9
import 'dart:ui';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/trash_db.dart';
@ -24,7 +25,7 @@ class TrashPage extends StatefulWidget {
this.tagPrefix = "trash_page",
this.appBarType = GalleryType.trash,
this.overlayType = GalleryType.trash,
Key key,
Key? key,
}) : super(key: key);
@override
@ -32,7 +33,7 @@ class TrashPage extends StatefulWidget {
}
class _TrashPageState extends State<TrashPage> {
Function() _selectedFilesListener;
late Function() _selectedFilesListener;
@override
void initState() {
_selectedFilesListener = () {
@ -63,9 +64,8 @@ class _TrashPageState extends State<TrashPage> {
},
reloadEvent: Bus.instance.on<FilesUpdatedEvent>().where(
(event) =>
event.updatedFiles.firstWhere(
event.updatedFiles.firstWhereOrNull(
(element) => element.uploadedFileID != null,
orElse: () => null,
) !=
null,
),
@ -124,12 +124,12 @@ class _TrashPageState extends State<TrashPage> {
return FutureBuilder<int>(
future: TrashDB.instance.count(),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data > 0) {
if (snapshot.hasData && snapshot.data! > 0) {
return Padding(
padding: const EdgeInsets.all(16),
child: Text(
'Items show the number the days remaining before permanent deletion',
style: Theme.of(context).textTheme.caption.copyWith(fontSize: 16),
style: Theme.of(context).textTheme.caption!.copyWith(fontSize: 16),
),
);
} else {
@ -141,7 +141,7 @@ class _TrashPageState extends State<TrashPage> {
}
class BottomButtonsWidget extends StatelessWidget {
const BottomButtonsWidget({Key key}) : super(key: key);
const BottomButtonsWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -167,7 +167,7 @@ class BottomButtonsWidget extends StatelessWidget {
),
child: Text(
'Delete All',
style: Theme.of(context).textTheme.subtitle2.copyWith(
style: Theme.of(context).textTheme.subtitle2!.copyWith(
color: const Color.fromRGBO(255, 101, 101, 1),
),
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
@ -11,7 +11,7 @@ import 'package:photos/utils/navigation_util.dart';
class FileSearchResultWidget extends StatelessWidget {
final FileSearchResult matchedFile;
const FileSearchResultWidget(this.matchedFile, {Key key}) : super(key: key);
const FileSearchResultWidget(this.matchedFile, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -44,7 +44,7 @@ class FileSearchResultWidget extends StatelessWidget {
SizedBox(
width: 220,
child: Text(
matchedFile.file.title,
matchedFile.file.title!,
style: const TextStyle(fontSize: 18),
overflow: TextOverflow.ellipsis,
),

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
@ -22,7 +22,7 @@ class SearchResultPage extends StatelessWidget {
SearchResultPage(
this.searchResult, {
Key key,
Key? key,
}) : super(key: key);
@override
@ -33,8 +33,8 @@ class SearchResultPage extends StatelessWidget {
final result = files
.where(
(file) =>
file.creationTime >= creationStartTime &&
file.creationTime <= creationEndTime,
file.creationTime! >= creationStartTime &&
file.creationTime! <= creationEndTime,
)
.toList();
return Future.value(

View file

@ -1,11 +1,11 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
class SearchSuffixIcon extends StatefulWidget {
final bool shouldShowSpinner;
const SearchSuffixIcon(this.shouldShowSpinner, {Key key}) : super(key: key);
const SearchSuffixIcon(this.shouldShowSpinner, {Key? key}) : super(key: key);
@override
State<SearchSuffixIcon> createState() => _SearchSuffixIconState();

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
@ -18,7 +18,7 @@ class SearchSuggestionsWidget extends StatelessWidget {
const SearchSuggestionsWidget(
this.results, {
Key key,
Key? key,
}) : super(key: key);
@override

View file

@ -1,4 +1,4 @@
// @dart=2.9
import 'dart:async';
@ -17,7 +17,7 @@ import 'package:photos/utils/debouncer.dart';
import 'package:photos/utils/navigation_util.dart';
class SearchIconWidget extends StatefulWidget {
const SearchIconWidget({Key key}) : super(key: key);
const SearchIconWidget({Key? key}) : super(key: key);
@override
State<SearchIconWidget> createState() => _SearchIconWidgetState();
@ -50,7 +50,7 @@ class _SearchIconWidgetState extends State<SearchIconWidget> {
}
class SearchWidget extends StatefulWidget {
const SearchWidget({Key key}) : super(key: key);
const SearchWidget({Key? key}) : super(key: key);
@override
State<SearchWidget> createState() => _SearchWidgetState();
@ -129,7 +129,7 @@ class _SearchWidgetState extends State<SearchWidget> {
builder: (
BuildContext context,
bool isDebouncing,
Widget child,
Widget? child,
) {
return SearchSuffixIcon(
isDebouncing,

View file

@ -62,7 +62,7 @@ Future<void> sendLogs(
showDialog(
context: context,
builder: (BuildContext context) {
return LogFileViewer(SuperLogging.logFile);
return LogFileViewer(SuperLogging.logFile!);
},
barrierColor: Colors.black87,
barrierDismissible: false,