Merge branch 'master' into rewrite_device_sync

This commit is contained in:
Neeraj Gupta 2022-09-20 23:24:47 +05:30
commit 8734c94a4e
No known key found for this signature in database
GPG key ID: 3C5A1684DC1729E1
19 changed files with 642 additions and 302 deletions

View file

@ -1,13 +1,6 @@
PODS:
- background_fetch (1.1.0):
- Flutter
- better_player (0.0.1):
- Cache (~> 6.0.0)
- Flutter
- GCDWebServer
- HLSCachingReverseProxyServer
- PINCache
- Cache (6.0.0)
- connectivity (0.0.1):
- Flutter
- Reachability
@ -83,9 +76,6 @@ PODS:
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- GCDWebServer (3.5.4):
- GCDWebServer/Core (= 3.5.4)
- GCDWebServer/Core (3.5.4)
- GoogleDataTransport (9.1.4):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
@ -107,9 +97,6 @@ PODS:
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.7.0):
- GoogleUtilities/Logger
- HLSCachingReverseProxyServer (0.1.0):
- GCDWebServer (~> 3.5)
- PINCache (>= 3.0.1-beta.3)
- image_editor (0.0.1):
- Flutter
- in_app_purchase (0.0.1):
@ -137,8 +124,6 @@ PODS:
- nanopb/encode (= 2.30908.0)
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- open_file (0.0.1):
- Flutter
- open_mail_app (0.0.1):
- Flutter
- OrderedSet (5.0.0)
@ -146,19 +131,9 @@ PODS:
- Flutter
- path_provider_ios (0.0.1):
- Flutter
- "permission_handler (5.1.0+2)":
- Flutter
- photo_manager (2.0.0):
- Flutter
- FlutterMacOS
- PINCache (3.0.3):
- PINCache/Arc-exception-safe (= 3.0.3)
- PINCache/Core (= 3.0.3)
- PINCache/Arc-exception-safe (3.0.3):
- PINCache/Core
- PINCache/Core (3.0.3):
- PINOperation (~> 1.2.1)
- PINOperation (1.2.1)
- PromisesObjC (2.1.0)
- Reachability (3.2)
- receive_sharing_intent (0.0.1):
@ -169,8 +144,6 @@ PODS:
- SDWebImageWebPCoder (0.8.4):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.10)
- sensors (0.0.1):
- Flutter
- Sentry (7.11.0):
- Sentry/Core (= 7.11.0)
- Sentry/Core (7.11.0)
@ -178,8 +151,6 @@ PODS:
- Flutter
- FlutterMacOS
- Sentry (~> 7.11.0)
- share (0.0.1):
- Flutter
- share_plus (0.0.1):
- Flutter
- shared_preferences_ios (0.0.1):
@ -202,7 +173,6 @@ PODS:
DEPENDENCIES:
- background_fetch (from `.symlinks/plugins/background_fetch/ios`)
- better_player (from `.symlinks/plugins/better_player/ios`)
- connectivity (from `.symlinks/plugins/connectivity/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
@ -224,16 +194,12 @@ DEPENDENCIES:
- local_auth (from `.symlinks/plugins/local_auth/ios`)
- motionphoto (from `.symlinks/plugins/motionphoto/ios`)
- move_to_background (from `.symlinks/plugins/move_to_background/ios`)
- open_file (from `.symlinks/plugins/open_file/ios`)
- open_mail_app (from `.symlinks/plugins/open_mail_app/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- sensors (from `.symlinks/plugins/sensors/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- share (from `.symlinks/plugins/share/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
@ -245,23 +211,18 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- Cache
- Firebase
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseInstallations
- FirebaseMessaging
- FMDB
- GCDWebServer
- GoogleDataTransport
- GoogleUtilities
- HLSCachingReverseProxyServer
- libwebp
- Mantle
- nanopb
- OrderedSet
- PINCache
- PINOperation
- PromisesObjC
- Reachability
- SDWebImage
@ -272,8 +233,6 @@ SPEC REPOS:
EXTERNAL SOURCES:
background_fetch:
:path: ".symlinks/plugins/background_fetch/ios"
better_player:
:path: ".symlinks/plugins/better_player/ios"
connectivity:
:path: ".symlinks/plugins/connectivity/ios"
device_info:
@ -316,26 +275,18 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/motionphoto/ios"
move_to_background:
:path: ".symlinks/plugins/move_to_background/ios"
open_file:
:path: ".symlinks/plugins/open_file/ios"
open_mail_app:
:path: ".symlinks/plugins/open_mail_app/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_ios:
:path: ".symlinks/plugins/path_provider_ios/ios"
permission_handler:
:path: ".symlinks/plugins/permission_handler/ios"
photo_manager:
:path: ".symlinks/plugins/photo_manager/ios"
receive_sharing_intent:
:path: ".symlinks/plugins/receive_sharing_intent/ios"
sensors:
:path: ".symlinks/plugins/sensors/ios"
sentry_flutter:
:path: ".symlinks/plugins/sentry_flutter/ios"
share:
:path: ".symlinks/plugins/share/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_ios:
@ -355,8 +306,6 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
background_fetch: 3795af8a49054dc526477cc2f60d2ed41de60587
better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646
Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d
connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
@ -379,10 +328,8 @@ SPEC CHECKSUMS:
fluttercontactpicker: d582836dea6b5d489f3d259f35d7817ae82ee5e6
fluttertoast: 16fbe6039d06a763f3533670197d01fc73459037
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4
GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b
GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181
image_editor: c1d038630eedea60d2dee9c14f36aa66c7f9cfab
in_app_purchase: 3e2155afa9d03d4fa32d9e62d567885080ce97d6
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
@ -391,24 +338,18 @@ SPEC CHECKSUMS:
motionphoto: d4a432b8c8f22fb3ad966258597c0103c9c5ff16
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d
open_mail_app: 794172f6a22cd16319d3ddaf45e945b2f74952b0
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086
PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20
PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
receive_sharing_intent: c0d87310754e74c0f9542947e7cbdf3a0335a3b1
SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e
SDWebImageWebPCoder: f93010f3f6c031e2f8fb3081ca4ee6966c539815
sensors: 84eb7a30e47a649e4172b71d6e81be614c280336
Sentry: 0c5cd63d714187b4a39c331c1f0eb04ba7868341
sentry_flutter: efb3df2c203cd03aad255892a8d628a458656d14
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904

View file

@ -256,20 +256,15 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Cache/Cache.framework",
"${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
"${BUILT_PRODUCTS_DIR}/GCDWebServer/GCDWebServer.framework",
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
"${BUILT_PRODUCTS_DIR}/HLSCachingReverseProxyServer/HLSCachingReverseProxyServer.framework",
"${BUILT_PRODUCTS_DIR}/Mantle/Mantle.framework",
"${BUILT_PRODUCTS_DIR}/OrderedSet/OrderedSet.framework",
"${BUILT_PRODUCTS_DIR}/PINCache/PINCache.framework",
"${BUILT_PRODUCTS_DIR}/PINOperation/PINOperation.framework",
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
"${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
@ -277,7 +272,6 @@
"${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework",
"${BUILT_PRODUCTS_DIR}/Toast/Toast.framework",
"${BUILT_PRODUCTS_DIR}/background_fetch/background_fetch.framework",
"${BUILT_PRODUCTS_DIR}/better_player/better_player.framework",
"${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework",
"${BUILT_PRODUCTS_DIR}/device_info/device_info.framework",
"${BUILT_PRODUCTS_DIR}/fk_user_agent/fk_user_agent.framework",
@ -298,15 +292,12 @@
"${BUILT_PRODUCTS_DIR}/motionphoto/motionphoto.framework",
"${BUILT_PRODUCTS_DIR}/move_to_background/move_to_background.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
"${BUILT_PRODUCTS_DIR}/open_file/open_file.framework",
"${BUILT_PRODUCTS_DIR}/open_mail_app/open_mail_app.framework",
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
"${BUILT_PRODUCTS_DIR}/path_provider_ios/path_provider_ios.framework",
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
"${BUILT_PRODUCTS_DIR}/receive_sharing_intent/receive_sharing_intent.framework",
"${BUILT_PRODUCTS_DIR}/sensors/sensors.framework",
"${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework",
"${BUILT_PRODUCTS_DIR}/share/share.framework",
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
"${BUILT_PRODUCTS_DIR}/shared_preferences_ios/shared_preferences_ios.framework",
"${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
@ -318,20 +309,15 @@
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cache.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreDiagnostics.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GCDWebServer.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HLSCachingReverseProxyServer.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mantle.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OrderedSet.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PINCache.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PINOperation.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
@ -339,7 +325,6 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Toast.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/background_fetch.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/better_player.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fk_user_agent.framework",
@ -360,15 +345,12 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/motionphoto.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/move_to_background.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_file.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_mail_app.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/receive_sharing_intent.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sensors.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",

View file

@ -10,7 +10,6 @@ import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/network.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/l10n/l10n.dart';
import 'package:photos/services/app_lifecycle_service.dart';
@ -58,7 +57,6 @@ class _EnteAppState extends State<EnteApp> with WidgetsBindingObserver {
darkTheme: dartTheme,
home: EnteApp._homeWidget,
debugShowCheckedModeBanner: false,
navigatorKey: Network.instance.getAlice().getNavigatorKey(),
builder: EasyLoading.init(),
supportedLocales: L10n.all,
localizationsDelegates: const [
@ -77,7 +75,6 @@ class _EnteAppState extends State<EnteApp> with WidgetsBindingObserver {
darkTheme: darkThemeData,
home: EnteApp._homeWidget,
debugShowCheckedModeBanner: false,
navigatorKey: Network.instance.getAlice().getNavigatorKey(),
builder: EasyLoading.init(),
supportedLocales: L10n.all,
localizationsDelegates: const [

View file

@ -1,11 +1,8 @@
// @dart=2.9
import 'dart:io';
import 'package:alice/alice.dart';
import 'package:dio/dio.dart';
import 'package:fk_user_agent/fk_user_agent.dart';
import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:uuid/uuid.dart';
@ -13,10 +10,8 @@ int kConnectTimeout = 15000;
class Network {
Dio _dio;
Alice _alice;
Future<void> init() async {
_alice = Alice(darkTheme: true, showNotification: kDebugMode);
await FkUserAgent.init();
final packageInfo = await PackageInfo.fromPlatform();
_dio = Dio(
@ -30,7 +25,6 @@ class Network {
),
);
_dio.interceptors.add(RequestIdInterceptor());
_dio.interceptors.add(_alice.getDioInterceptor());
}
Network._privateConstructor();
@ -38,8 +32,6 @@ class Network {
static Network instance = Network._privateConstructor();
Dio getDio() => _dio;
Alice getAlice() => _alice;
}
class RequestIdInterceptor extends Interceptor {

View file

@ -363,6 +363,29 @@ extension CustomColorScheme on ColorScheme {
Color get searchResultsBackgroundColor => brightness == Brightness.light
? Colors.black.withOpacity(0.32)
: Colors.black.withOpacity(0.64);
Color get fillFaint => brightness == Brightness.light
? Colors.white.withOpacity(0.04)
: Colors.black.withOpacity(0.12);
Color get warning500 => const Color.fromRGBO(255, 101, 101, 1);
List<BoxShadow> get shadowMenu => brightness == Brightness.light
? [
BoxShadow(blurRadius: 6, color: Colors.white.withOpacity(0.16)),
BoxShadow(
blurRadius: 6,
color: Colors.white.withOpacity(0.12),
offset: const Offset(0, 3),
),
]
: [
BoxShadow(blurRadius: 6, color: Colors.black.withOpacity(0.50)),
BoxShadow(
blurRadius: 6,
color: Colors.black.withOpacity(0.25),
offset: const Offset(0, 3),
),
];
}
OutlinedButtonThemeData buildOutlinedButtonThemeData({

View file

@ -0,0 +1,5 @@
import 'package:photos/events/event.dart';
// NotificationEvent event is used to re-fresh the UI to show latest notification
// (if any)
class NotificationEvent extends Event {}

View file

@ -31,6 +31,7 @@ import 'package:photos/services/search_service.dart';
import 'package:photos/services/sync_service.dart';
import 'package:photos/services/trash_sync_service.dart';
import 'package:photos/services/update_service.dart';
import 'package:photos/services/user_remote_flag_service.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/tools/app_lock.dart';
import 'package:photos/ui/tools/lock_screen.dart';
@ -133,6 +134,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
await Network.instance.init();
await Configuration.instance.init();
await UserService.instance.init();
await UserRemoteFlagService.instance.init();
await UpdateService.instance.init();
await BillingService.instance.init();
await CollectionsService.instance.init();

View file

@ -292,6 +292,9 @@ class CollectionsService {
Uint8List _getDecryptedKey(Collection collection) {
final encryptedKey = Sodium.base642bin(collection.encryptedKey);
if (collection.owner.id == _config.getUserID()) {
if(_config.getKey() == null) {
throw Exception("key can not be null");
}
return CryptoUtil.decryptSync(
encryptedKey,
_config.getKey(),

View file

@ -0,0 +1,123 @@
import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/network.dart';
import 'package:photos/services/user_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
class UserRemoteFlagService {
final _dio = Network.instance.getDio();
final _logger = Logger((UserRemoteFlagService).toString());
final _config = Configuration.instance;
late SharedPreferences _prefs;
UserRemoteFlagService._privateConstructor();
static final UserRemoteFlagService instance =
UserRemoteFlagService._privateConstructor();
static const String recoveryVerificationFlag = "recoveryKeyVerified";
static const String needRecoveryKeyVerification =
"needRecoveryKeyVerification";
Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}
bool shouldShowRecoveryVerification() {
if (!_prefs.containsKey(needRecoveryKeyVerification)) {
// fetch the status from remote
unawaited(_refreshRecoveryVerificationFlag());
return false;
}
return _prefs.getBool(needRecoveryKeyVerification)!;
}
// markRecoveryVerificationAsDone is used to track if user has verified their
// recovery key in the past or not. This helps in avoid showing the same
// prompt to the user on re-install or signing into a different device
Future<void> markRecoveryVerificationAsDone() async {
await _updateKeyValue(recoveryVerificationFlag, true.toString());
await _prefs.setBool(needRecoveryKeyVerification, false);
}
Future<void> _refreshRecoveryVerificationFlag() async {
final remoteStatusValue =
await _getValue(recoveryVerificationFlag, "false");
if (remoteStatusValue.toLowerCase() == "true") {
await _prefs.setBool(needRecoveryKeyVerification, false);
} else {
// check the session creationTime. If any active session is older than
// 1 day, set the need to verification as true
final activeSessions = await UserService.instance.getActiveSessions();
final int microSecondsInADay = const Duration(days: 1).inMicroseconds;
final bool anyActiveSessionOlderThanADay =
activeSessions.sessions.firstWhere(
(e) =>
(e.creationTime + microSecondsInADay) <
DateTime.now().microsecondsSinceEpoch,
orElse: () => null,
) !=
null;
if (anyActiveSessionOlderThanADay) {
await _prefs.setBool(needRecoveryKeyVerification, true);
} else {
// continue defaulting to no verification prompt
_logger.finest('No active session older than 1 day');
}
}
}
Future<String> _getValue(String key, String? defaultValue) async {
try {
final Map<String, dynamic> queryParams = {"key": key};
if (defaultValue != null) {
queryParams["defaultValue"] = defaultValue;
}
final response = await _dio.get(
_config.getHttpEndpoint() + "/remote-store",
queryParameters: queryParams,
options: Options(
headers: {
"X-Auth-Token": _config.getToken(),
},
),
);
if (response.statusCode != HttpStatus.ok) {
throw Exception("Unexpected status code ${response.statusCode}");
}
return response.data["value"];
} catch (e) {
_logger.info("Error while fetching bool status for $key", e);
rethrow;
}
}
// _setBooleanFlag sets the corresponding flag on remote
// to mark recovery as completed
Future<void> _updateKeyValue(String key, String value) async {
try {
final response = await _dio.post(
_config.getHttpEndpoint() + "/remote-store/update",
data: {
"key": key,
"value": value,
},
options: Options(
headers: {
"X-Auth-Token": _config.getToken(),
},
),
);
if (response.statusCode != HttpStatus.ok) {
throw Exception("Unexpected state");
}
} catch (e) {
_logger.warning("Failed to set flag for $key", e);
rethrow;
}
}
}

View file

@ -56,135 +56,149 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
'recovery code should have $kMnemonicKeyWordCount words',
);
}
final double topPadding = widget.showAppBar
? 40
: widget.showProgressBar
? 32
: 120;
return Scaffold(
appBar: widget.showProgressBar
? AppBar(
elevation: 0,
title: Hero(
tag: "recovery_key",
child: StepProgressIndicator(
totalSteps: 4,
currentStep: 3,
selectedColor: Theme.of(context).colorScheme.greenAlternative,
roundedEdges: const Radius.circular(10),
unselectedColor:
Theme.of(context).colorScheme.stepProgressUnselectedColor,
),
),
)
: widget.showAppBar
? AppBar(
elevation: 0,
title: Text(widget.title ?? "Recovery key"),
)
: null,
body: Padding(
padding: EdgeInsets.fromLTRB(
20,
widget.showAppBar
? 40
: widget.showProgressBar
? 32
: 120,
20,
20,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
widget.showAppBar
? const SizedBox.shrink()
: Text(
widget.title ?? "Recovery key",
style: Theme.of(context).textTheme.headline4,
appBar: widget.showProgressBar
? AppBar(
elevation: 0,
title: Hero(
tag: "recovery_key",
child: StepProgressIndicator(
totalSteps: 4,
currentStep: 3,
selectedColor:
Theme.of(context).colorScheme.greenAlternative,
roundedEdges: const Radius.circular(10),
unselectedColor: Theme.of(context)
.colorScheme
.stepProgressUnselectedColor,
),
Padding(padding: EdgeInsets.all(widget.showAppBar ? 0 : 12)),
Text(
widget.text ??
"If you forget your password, the only way you can recover your data is with this key.",
style: Theme.of(context).textTheme.subtitle1,
),
const Padding(padding: EdgeInsets.only(top: 24)),
DottedBorder(
color: const Color.fromRGBO(17, 127, 56, 1),
//color of dotted/dash line
strokeWidth: 1,
//thickness of dash/dots
dashPattern: const [6, 6],
radius: const Radius.circular(8),
//dash patterns, 10 is dash width, 6 is space width
child: SizedBox(
//inner container
height: 120, //height of inner container
width:
double.infinity, //width to 100% match to parent container.
// ignore: prefer_const_literals_to_create_immutables
child: Column(
children: [
GestureDetector(
onTap: () async {
await Clipboard.setData(
ClipboardData(text: recoveryKey),
);
showToast(context, "Recovery key copied to clipboard");
setState(() {
_hasTriedToSave = true;
});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: const Color.fromRGBO(49, 155, 86, .2),
),
borderRadius: const BorderRadius.all(
Radius.circular(2),
),
color:
Theme.of(context).colorScheme.recoveryKeyBoxColor,
),
)
: widget.showAppBar
? AppBar(
elevation: 0,
title: Text(widget.title ?? "Recovery key"),
)
: null,
body: Padding(
padding: EdgeInsets.fromLTRB(20, topPadding, 20, 20),
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: constraints.maxWidth,
minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
widget.showAppBar
? const SizedBox.shrink()
: Text(
widget.title ?? "Recovery key",
style: Theme.of(context).textTheme.headline4,
),
Padding(
padding:
EdgeInsets.all(widget.showAppBar ? 0 : 12)),
Text(
widget.text ??
"If you forget your password, the only way you can recover your data is with this key.",
style: Theme.of(context).textTheme.subtitle1,
),
height: 120,
padding: const EdgeInsets.all(20),
width: double.infinity,
child: Text(
recoveryKey,
style: Theme.of(context).textTheme.bodyText1,
const Padding(padding: EdgeInsets.only(top: 24)),
DottedBorder(
color: const Color.fromRGBO(17, 127, 56, 1),
//color of dotted/dash line
strokeWidth: 1,
//thickness of dash/dots
dashPattern: const [6, 6],
radius: const Radius.circular(8),
//dash patterns, 10 is dash width, 6 is space width
child: SizedBox(
//inner container
// height: 120, //height of inner container
width: double
.infinity, //width to 100% match to parent container.
// ignore: prefer_const_literals_to_create_immutables
child: Column(
children: [
GestureDetector(
onTap: () async {
await Clipboard.setData(
ClipboardData(text: recoveryKey),
);
showToast(context,
"Recovery key copied to clipboard");
setState(() {
_hasTriedToSave = true;
});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: const Color.fromRGBO(
49, 155, 86, .2),
),
borderRadius: const BorderRadius.all(
Radius.circular(2),
),
color: Theme.of(context)
.colorScheme
.recoveryKeyBoxColor,
),
padding: const EdgeInsets.all(20),
width: double.infinity,
child: Text(
recoveryKey,
style:
Theme.of(context).textTheme.bodyText1,
),
),
),
],
),
),
),
),
),
],
SizedBox(
height: 80,
width: double.infinity,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
widget.subText ??
"We dont store this key, please save this in a safe place.",
style: Theme.of(context).textTheme.bodyText1,
),
),
),
Expanded(
child: Container(
alignment: Alignment.bottomCenter,
width: double.infinity,
padding: const EdgeInsets.fromLTRB(10, 10, 10, 42),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _saveOptions(context, recoveryKey),
),
),
)
],
), // columnEnds
),
),
),
),
SizedBox(
height: 80,
width: double.infinity,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
widget.subText ??
"We dont store this key, please save this in a safe place.",
style: Theme.of(context).textTheme.bodyText1,
),
),
),
Expanded(
child: Container(
alignment: Alignment.bottomCenter,
width: double.infinity,
padding: const EdgeInsets.fromLTRB(10, 10, 10, 24),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _saveOptions(context, recoveryKey),
),
),
)
],
),
),
);
);
},
),
));
}
List<Widget> _saveOptions(BuildContext context, String recoveryKey) {

View file

@ -0,0 +1,241 @@
import 'dart:ui';
import 'package:bip39/bip39.dart' as bip39;
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/events/notification_event.dart';
import 'package:photos/services/local_authentication_service.dart';
import 'package:photos/services/user_remote_flag_service.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/account/recovery_key_page.dart';
import 'package:photos/ui/common/dialogs.dart';
import 'package:photos/ui/common/gradient_button.dart';
import 'package:photos/utils/dialog_util.dart';
import 'package:photos/utils/navigation_util.dart';
class VerifyRecoveryPage extends StatefulWidget {
const VerifyRecoveryPage({Key? key}) : super(key: key);
@override
State<VerifyRecoveryPage> createState() => _VerifyRecoveryPageState();
}
class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
final _recoveryKey = TextEditingController();
final Logger _logger = Logger((_VerifyRecoveryPageState).toString());
void _verifyRecoveryKey() async {
final dialog = createProgressDialog(context, "Verifying recovery key...");
await dialog.show();
try {
final String inputKey = _recoveryKey.text.trim();
final String recoveryKey = Sodium.bin2hex(
await UserService.instance.getOrCreateRecoveryKey(context),
);
final String recoveryKeyWords = bip39.entropyToMnemonic(recoveryKey);
if (inputKey == recoveryKey || inputKey == recoveryKeyWords) {
try {
await UserRemoteFlagService.instance.markRecoveryVerificationAsDone();
} catch (e) {
await dialog.hide();
if (e is DioError && e.type == DioErrorType.other) {
await showErrorDialog(
context,
"No internet connection",
"Please check your internet connection and try again.",
);
} else {
await showGenericErrorDialog(context);
}
return;
}
Bus.instance.fire(NotificationEvent());
await dialog.hide();
// todo: change this as per figma once the component is ready
await showErrorDialog(
context,
"Recovery key verified",
"Great! Your recovery key is valid. Thank you for verifying.\n"
"\nPlease"
" remember to keep your recovery key safely backed up.",
);
Navigator.of(context).pop();
} else {
throw Exception("recovery key didn't match");
}
} catch (e, s) {
_logger.severe("failed to verify recovery key", e, s);
await dialog.hide();
const String errMessage =
"The recovery key you entered is not valid. Please make sure it "
"contains 24 words, and check the spelling of each.\n\nIf you "
"entered an older recovery code, make sure it is 64 characters long, and check each of them.";
final result = await showChoiceDialog(
context,
"Invalid key",
errMessage,
firstAction: "Try again",
secondAction: "View recovery key",
);
if (result == DialogUserChoice.secondChoice) {
await _onViewRecoveryKeyClick();
}
}
}
Future<void> _onViewRecoveryKeyClick() async {
final hasAuthenticated =
await LocalAuthenticationService.instance.requestLocalAuthentication(
context,
"Please authenticate to view your recovery key",
);
if (hasAuthenticated) {
String recoveryKey;
try {
recoveryKey = Sodium.bin2hex(
await UserService.instance.getOrCreateRecoveryKey(context),
);
routeToPage(
context,
RecoveryKeyPage(
recoveryKey,
"OK",
showAppBar: true,
onDone: () {
Navigator.of(context).pop();
},
),
);
} catch (e) {
showGenericErrorDialog(context);
return;
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
color: Theme.of(context).iconTheme.color,
onPressed: () {
Navigator.of(context).pop();
},
),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: constraints.maxWidth,
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
children: [
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: Text(
'Verify recovery key',
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.left,
),
),
const SizedBox(height: 12),
Text(
"If you forget your password, your recovery key is the "
"only way to recover your photos.\n\nPlease verify that "
"you have safely backed up your 24 word recovery key by re-entering it.",
style: Theme.of(context).textTheme.subtitle2,
),
const SizedBox(height: 12),
TextFormField(
decoration: InputDecoration(
filled: true,
hintText: "Enter your recovery key",
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(6),
),
),
style: const TextStyle(
fontSize: 14,
fontFeatures: [FontFeature.tabularFigures()],
),
controller: _recoveryKey,
autofocus: false,
autocorrect: false,
keyboardType: TextInputType.multiline,
minLines: 4,
maxLines: null,
onChanged: (_) {
setState(() {});
},
),
const SizedBox(height: 12),
Text(
"If you saved the recovery key from older app versions, you might have a 64 character recovery code instead of 24 words. You can enter that too.",
style: Theme.of(context).textTheme.caption,
),
const SizedBox(height: 8),
Expanded(
child: Container(
alignment: Alignment.bottomCenter,
width: double.infinity,
padding: const EdgeInsets.fromLTRB(0, 12, 0, 40),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
GradientButton(
onTap: _verifyRecoveryKey,
text: "Verify",
paddingValue: 6,
iconData: Icons.shield_outlined,
),
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
child: Hero(
tag: "recovery_key",
child: ElevatedButton(
style: Theme.of(context)
.colorScheme
.optionalActionButtonStyle,
onPressed: _onViewRecoveryKeyClick,
child: const Text(
"View recovery key",
// same for both themes
style: TextStyle(color: Colors.black),
),
),
),
),
],
),
),
),
const SizedBox(height: 20)
],
),
),
),
);
},
),
),
);
}
}

View file

@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
class NotificationWarningWidget extends StatelessWidget {
final IconData warningIcon;
final IconData actionIcon;
final String text;
final GestureTapCallback onTap;
const NotificationWarningWidget({
Key? key,
required this.warningIcon,
required this.actionIcon,
required this.text,
required this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(8),
),
boxShadow: Theme.of(context).colorScheme.shadowMenu,
color: Theme.of(context).colorScheme.warning500,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: Row(
children: [
Icon(
warningIcon,
size: 36,
color: Colors.white,
),
const SizedBox(width: 10),
Flexible(
child: Text(
text,
style: const TextStyle(height: 1.4, color: Colors.white),
textAlign: TextAlign.left,
),
),
const SizedBox(width: 10),
ClipOval(
child: Material(
color: Theme.of(context).colorScheme.fillFaint,
child: InkWell(
splashColor: Colors.red, // Splash color
onTap: onTap,
child: SizedBox(
width: 40,
height: 40,
child: Icon(
actionIcon,
color: Colors.white,
),
),
),
),
),
],
),
),
),
),
),
);
}
}

View file

@ -2,7 +2,7 @@
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:open_file/open_file.dart';
// import 'package:open_file/open_file.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/network.dart';
import 'package:photos/ente_theme_data.dart';
@ -152,7 +152,7 @@ class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
},
);
Navigator.of(context, rootNavigator: true).pop('dialog');
OpenFile.open(_saveUrl);
// OpenFile.open(_saveUrl);
} catch (e) {
Logger("ApkDownloader").severe(e);
final AlertDialog alert = AlertDialog(

View file

@ -2,7 +2,6 @@
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/utils/dialog_util.dart';
class AppVersionWidget extends StatefulWidget {
@ -38,7 +37,6 @@ class _AppVersionWidgetState extends State<AppVersionWidget> {
const Duration(milliseconds: kDummyDelayDurationInMilliseconds),
);
await dialog.hide();
Network.instance.getAlice().showInspector();
}
} else {
_consecutiveTaps = 1;

View file

@ -4,7 +4,6 @@ import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/network.dart';
import 'package:photos/services/ignored_files_service.dart';
import 'package:photos/services/local_sync_service.dart';
import 'package:photos/services/sync_service.dart';
@ -38,16 +37,6 @@ class DebugSectionWidget extends StatelessWidget {
icon: Icons.navigate_next,
),
),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () async {
Network.instance.getAlice().showInspector();
},
child: const SettingsTextItem(
text: "Network requests",
icon: Icons.navigate_next,
),
),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () async {

View file

@ -5,10 +5,15 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/events/notification_event.dart';
import 'package:photos/events/sync_status_update_event.dart';
import 'package:photos/services/sync_service.dart';
import 'package:photos/services/user_remote_flag_service.dart';
import 'package:photos/ui/account/verify_recovery_page.dart';
import 'package:photos/ui/components/notification_warning_widget.dart';
import 'package:photos/ui/header_error_widget.dart';
import 'package:photos/ui/viewer/search/search_widget.dart';
import 'package:photos/utils/navigation_util.dart';
const double kContainerHeight = 36;
@ -21,6 +26,7 @@ class StatusBarWidget extends StatefulWidget {
class _StatusBarWidgetState extends State<StatusBarWidget> {
StreamSubscription<SyncStatusUpdate> _subscription;
StreamSubscription<NotificationEvent> _notificationSubscription;
bool _showStatus = false;
bool _showErrorBanner = false;
@ -51,12 +57,19 @@ class _StatusBarWidgetState extends State<StatusBarWidget> {
});
}
});
_notificationSubscription =
Bus.instance.on<NotificationEvent>().listen((event) {
if (mounted) {
setState(() {});
}
});
super.initState();
}
@override
void dispose() {
_subscription.cancel();
_notificationSubscription.cancel();
super.dispose();
}
@ -96,6 +109,20 @@ class _StatusBarWidgetState extends State<StatusBarWidget> {
duration: const Duration(milliseconds: 1000),
child: const Divider(),
),
UserRemoteFlagService.instance.shouldShowRecoveryVerification()
? NotificationWarningWidget(
warningIcon: Icons.gpp_maybe,
actionIcon: Icons.arrow_forward,
text: "Please ensure that you have your 24 word recovery key",
onTap: () async => {
await routeToPage(
context,
const VerifyRecoveryPage(),
forceCustomPageRoute: true,
)
},
)
: const SizedBox.shrink()
],
);
}

View file

@ -204,6 +204,7 @@ class CryptoUtil {
Uint8List key,
Uint8List nonce,
) {
assert(key != null, "key can not be null");
final args = <String, dynamic>{};
args["cipher"] = cipher;
args["nonce"] = nonce;

View file

@ -8,15 +8,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
alice:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: "42c97aebbea93d1944a199b453b41bbed1f3013a"
url: "https://github.com/jhomlala/alice.git"
source: git
version: "0.2.5"
animate_do:
dependency: "direct main"
description:
@ -52,13 +43,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
better_player:
dependency: transitive
description:
name: better_player
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.81"
bip39:
dependency: "direct main"
description:
@ -115,13 +99,6 @@ packages:
relative: true
source: path
version: "1.2.2"
chopper:
dependency: transitive
description:
name: chopper
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.5"
clock:
dependency: transitive
description:
@ -562,13 +539,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_widget_from_html_core:
dependency: transitive
description:
name: flutter_widget_from_html_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+3"
flutter_windowmanager:
dependency: "direct main"
description:
@ -590,13 +560,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.9"
fwfh_text_style:
dependency: transitive
description:
name: fwfh_text_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.3+2"
google_nav_bar:
dependency: "direct main"
description:
@ -795,13 +758,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
open_file:
dependency: "direct main"
description:
name: open_file
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
open_mail_app:
dependency: "direct main"
description:
@ -942,20 +898,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.1"
permission_handler:
dependency: transitive
description:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "8.3.0"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.7.0"
petitparser:
dependency: transitive
description:
@ -1047,13 +989,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.3"
sensors:
dependency: transitive
description:
name: sensors
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
sentry:
dependency: "direct main"
description:
@ -1068,13 +1003,6 @@ packages:
relative: true
source: path
version: "6.5.1"
share:
dependency: transitive
description:
name: share
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
share_plus:
dependency: "direct main"
description:

View file

@ -11,15 +11,13 @@ description: ente photos application
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.6.31+361
version: 0.6.32+362
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
adaptive_theme: ^3.1.0
alice:
git: "https://github.com/jhomlala/alice.git"
animate_do: ^2.0.0
archive: ^3.1.2
background_fetch: ^1.0.1
@ -82,7 +80,7 @@ dependencies:
git: "https://github.com/ente-io/motionphoto.git"
move_to_background: ^1.0.2
open_file: ^3.2.1
# open_file: ^3.2.1
open_mail_app: ^0.4.5
package_info_plus: ^1.0.1
page_transition: ^2.0.2