Merge branch 'main' into picker

This commit is contained in:
ashilkn 2023-02-03 15:40:37 +05:30
commit c2da85e7f0
31 changed files with 114 additions and 96 deletions

View file

@ -0,0 +1,29 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:photos/core/configuration.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart';
class EnteRequestInterceptor extends Interceptor {
final SharedPreferences _preferences;
final String enteEndpoint;
EnteRequestInterceptor(this._preferences, this.enteEndpoint);
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (kDebugMode) {
assert(
options.baseUrl == enteEndpoint,
"interceptor should only be used for API endpoint",
);
}
// ignore: prefer_const_constructors
options.headers.putIfAbsent("x-request-id", () => Uuid().v4().toString());
final String? tokenValue = _preferences.getString(Configuration.tokenKey);
if (tokenValue != null) {
options.headers.putIfAbsent("X-Auth-Token", () => tokenValue);
}
return super.onRequest(options, handler);
}
}

View file

@ -2,16 +2,14 @@ import 'dart:io';
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:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/network/ente_interceptor.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart';
int kConnectTimeout = 15000;
class Network {
class NetworkClient {
// apiEndpoint points to the Ente server's API endpoint
static const apiEndpoint = String.fromEnvironment(
"endpoint",
@ -46,37 +44,14 @@ class Network {
},
),
);
_enteDio.interceptors.add(EnteRequestInterceptor(preferences));
_enteDio.interceptors.add(EnteRequestInterceptor(preferences, apiEndpoint));
}
Network._privateConstructor();
NetworkClient._privateConstructor();
static Network instance = Network._privateConstructor();
static NetworkClient instance = NetworkClient._privateConstructor();
Dio getDio() => _dio;
Dio get enteDio => _enteDio;
}
class EnteRequestInterceptor extends Interceptor {
final SharedPreferences _preferences;
EnteRequestInterceptor(this._preferences);
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (kDebugMode) {
assert(
options.baseUrl == Network.apiEndpoint,
"interceptor should only be used for API endpoint",
);
}
// ignore: prefer_const_constructors
options.headers.putIfAbsent("x-request-id", () => Uuid().v4().toString());
final String? tokenValue = _preferences.getString(Configuration.tokenKey);
if (tokenValue != null) {
options.headers.putIfAbsent("X-Auth-Token", () => tokenValue);
}
return super.onRequest(options, handler);
}
}

View file

@ -12,7 +12,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/error-reporting/super_logging.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/upload_locks_db.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/services/app_lifecycle_service.dart';
@ -135,7 +135,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
}
CryptoUtil.init();
await NotificationService.instance.init();
await Network.instance.init();
await NetworkClient.instance.init();
await Configuration.instance.init();
await UserService.instance.init();
await UserRemoteFlagService.instance.init();

View file

@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/models/billing_plan.dart';
import 'package:photos/models/subscription.dart';
import 'package:photos/models/user_details.dart';
@ -32,7 +32,7 @@ class BillingService {
static final BillingService instance = BillingService._privateConstructor();
final _logger = Logger("BillingService");
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
bool _isOnSubscriptionPage = false;

View file

@ -12,7 +12,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/collections_db.dart';
import 'package:photos/db/device_files_db.dart';
import 'package:photos/db/files_db.dart';
@ -50,7 +50,7 @@ class CollectionsService {
late Configuration _config;
late SharedPreferences _prefs;
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
final _localPathToCollectionID = <String, int>{};
final _collectionIDToCollections = <int, Collection>{};
final _cachedKeys = <int, Uint8List>{};

View file

@ -1,13 +1,13 @@
import 'package:logging/logging.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/models/duplicate_files.dart';
import 'package:photos/models/file.dart';
class DeduplicationService {
final _logger = Logger("DeduplicationService");
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
DeduplicationService._privateConstructor();

View file

@ -5,7 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:shared_preferences/shared_preferences.dart';
class FeatureFlagService {
@ -69,7 +69,7 @@ class FeatureFlagService {
Future<void> fetchFeatureFlags() async {
try {
final response = await Network.instance
final response = await NetworkClient.instance
.getDio()
.get("https://static.ente.io/feature_flags.json");
final flagsResponse = FeatureFlags.fromMap(response.data);

View file

@ -7,7 +7,7 @@ import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/events/files_updated_event.dart';
import 'package:photos/events/force_reload_home_gallery_event.dart';
@ -26,7 +26,7 @@ class FileMagicService {
FileMagicService._privateConstructor() {
_filesDB = FilesDB.instance;
_enteDio = Network.instance.enteDio;
_enteDio = NetworkClient.instance.enteDio;
}
static final FileMagicService instance =

View file

@ -2,7 +2,7 @@ import 'package:dio/dio.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/extensions/list.dart';
import 'package:photos/models/file.dart';
@ -17,7 +17,7 @@ class FilesService {
late Configuration _config;
FilesService._privateConstructor() {
_enteDio = Network.instance.enteDio;
_enteDio = NetworkClient.instance.enteDio;
_logger = Logger("FilesService");
_filesDB = FilesDB.instance;
_config = Configuration.instance;

View file

@ -171,6 +171,10 @@ class LocalSyncService {
}
Future<bool> syncAll() async {
if (!Configuration.instance.isLoggedIn()) {
_logger.warning("syncCall called when user is not logged in");
return false;
}
final stopwatch = EnteWatch("localSyncAll")..start();
final localAssets = await getAllLocalAssets();

View file

@ -4,7 +4,7 @@ import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/events/signed_in_event.dart';
import 'package:photos/services/sync_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -74,7 +74,7 @@ class PushService {
String fcmToken,
String? apnsToken,
) async {
await Network.instance.enteDio.post(
await NetworkClient.instance.enteDio.post(
"/push/token",
data: {
"fcmToken": fcmToken,

View file

@ -1,6 +1,6 @@
import 'package:logging/logging.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/data/holidays.dart';
import 'package:photos/data/months.dart';
import 'package:photos/data/years.dart';
@ -21,7 +21,7 @@ import 'package:tuple/tuple.dart';
class SearchService {
Future<List<File>>? _cachedFilesFuture;
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
final _logger = Logger((SearchService).toString());
final _collectionService = CollectionsService.instance;
static const _maximumResultsLimit = 20;
@ -115,8 +115,8 @@ class SearchService {
break;
}
if (!c.collection.isHidden() && c.collection.type != CollectionType
.uncategorized &&
if (!c.collection.isHidden() &&
c.collection.type != CollectionType.uncategorized &&
c.collection.name!.toLowerCase().contains(
query.toLowerCase(),
)) {

View file

@ -9,7 +9,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/device_files_db.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/events/permission_granted_event.dart';
@ -28,7 +28,7 @@ class SyncService {
final _logger = Logger("SyncService");
final _localSyncService = LocalSyncService.instance;
final _remoteSyncService = RemoteSyncService.instance;
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
final _uploader = FileUploader.instance;
bool _syncStopRequested = false;
Completer<bool>? _existingSync;

View file

@ -4,7 +4,7 @@ import 'package:dio/dio.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/trash_db.dart';
import 'package:photos/events/collection_updated_event.dart';
import 'package:photos/events/force_reload_trash_page_event.dart';
@ -29,7 +29,7 @@ class TrashSyncService {
static final TrashSyncService instance =
TrashSyncService._privateConstructor();
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
void init(SharedPreferences preferences) {
_prefs = preferences;

View file

@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/services/notification_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tuple/tuple.dart';
@ -98,7 +98,7 @@ class UpdateService {
}
Future<LatestVersionInfo> _getLatestVersionInfo() async {
final response = await Network.instance
final response = await NetworkClient.instance
.getDio()
.get("https://ente.io/release-info/independent.json");
return LatestVersionInfo.fromMap(response.data["latestVersion"]);

View file

@ -4,13 +4,13 @@ import 'dart:io';
import 'package:collection/collection.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/events/notification_event.dart';
import 'package:photos/services/user_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
class UserRemoteFlagService {
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
final _logger = Logger((UserRemoteFlagService).toString());
late SharedPreferences _prefs;

View file

@ -9,7 +9,7 @@ import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/public_keys_db.dart';
import 'package:photos/events/two_factor_status_change_event.dart';
import 'package:photos/events/user_details_changed_event.dart';
@ -37,8 +37,8 @@ import 'package:shared_preferences/shared_preferences.dart';
class UserService {
static const keyHasEnabledTwoFactor = "has_enabled_two_factor";
static const keyUserDetails = "user_details";
final _dio = Network.instance.getDio();
final _enteDio = Network.instance.enteDio;
final _dio = NetworkClient.instance.getDio();
final _enteDio = NetworkClient.instance.enteDio;
final _logger = Logger((UserService).toString());
final _config = Configuration.instance;
late SharedPreferences _preferences;

View file

@ -127,17 +127,19 @@ class _SessionsPageState extends State<SessionsPage> {
}
Future<void> _fetchActiveSessions() async {
_sessions = await UserService.instance
.getActiveSessions()
.onError((error, stackTrace) {
showToast(context, "Failed to fetch active sessions");
throw error!;
_sessions = await UserService.instance.getActiveSessions().onError((e, s) {
_logger.severe("failed to fetch active sessions", e, s);
if (mounted) {
showToast(context, "Failed to fetch active sessions");
}
});
if (_sessions != null) {
_sessions!.sessions.sort((first, second) {
return second.lastUsedTime.compareTo(first.lastUsedTime);
});
setState(() {});
if (mounted) {
setState(() {});
}
}
}

View file

@ -16,13 +16,15 @@ extension CollectionFileActions on CollectionActions {
BuildContext bContext,
Collection collection,
SelectedFiles selectedFiles,
bool removingOthersFile,
) async {
final actionResult = await showActionSheet(
context: bContext,
buttons: [
ButtonWidget(
labelText: "Yes, remove",
buttonType: ButtonType.neutral,
labelText: "Remove",
buttonType:
removingOthersFile ? ButtonType.critical : ButtonType.neutral,
buttonSize: ButtonSize.large,
shouldStickToDarkTheme: true,
isInAlert: true,
@ -48,9 +50,11 @@ extension CollectionFileActions on CollectionActions {
isInAlert: true,
),
],
title: "Remove from album?",
body: "Selected items will be removed from this album. Items which are "
"only in this album will be moved to Uncategorized.",
title: removingOthersFile ? "Remove from album?" : null,
body: removingOthersFile
? "Some of the items you are removing were "
"added by other people, and you will lose access to them"
: "Selected items will be removed from this album",
actionSheetType: ActionSheetType.defaultActionSheet,
);
if (actionResult != null && actionResult == ButtonAction.error) {

View file

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:expansion_tile_card/expansion_tile_card.dart';
import 'package:flutter/material.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/ui/common/loading_widget.dart';
@ -14,7 +14,7 @@ class BillingQuestionsWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: Network.instance
future: NetworkClient.instance
.getDio()
.get("https://static.ente.io/faq.json")
.then((response) {

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:photos/core/configuration.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/services/update_service.dart';
import 'package:photos/theme/ente_theme.dart';
@ -183,7 +183,7 @@ class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
Future<void> _downloadApk() async {
try {
await Network.instance.getDio().download(
await NetworkClient.instance.getDio().download(
widget.versionInfo!.url,
_saveUrl,
onReceiveProgress: (count, _) {

View file

@ -26,10 +26,13 @@ class UserAvatarWidget extends StatelessWidget {
final displayChar = (user.name == null || user.name!.isEmpty)
? ((user.email.isEmpty) ? " " : user.email.substring(0, 1))
: user.name!.substring(0, 1);
final randomColor = colorScheme.avatarColors[
(user.id ?? 0).remainder(colorScheme.avatarColors.length)];
final Color decorationColor =
((user.id ?? -1) == currentUserID) ? Colors.black : randomColor;
Color decorationColor;
if (user.id == null || user.id! <= 0 || user.id == currentUserID) {
decorationColor = Colors.black;
} else {
decorationColor = colorScheme
.avatarColors[(user.id!).remainder(colorScheme.avatarColors.length)];
}
final avatarStyle = getAvatarStyle(context, type);
final double size = avatarStyle.item1;

View file

@ -316,10 +316,13 @@ class _FileSelectionActionWidgetState extends State<FileSelectionActionWidget> {
widget.selectedFiles
.unSelectAll(split.ownedByOtherUsers.toSet(), skipNotify: true);
}
final bool removingOthersFile =
isCollectionOwner && split.ownedByOtherUsers.isNotEmpty;
await collectionActions.showRemoveFromCollectionSheetV2(
context,
widget.collection!,
widget.selectedFiles,
removingOthersFile,
);
}

View file

@ -10,7 +10,6 @@ import 'package:photos/db/files_db.dart';
import 'package:photos/db/trash_db.dart';
import 'package:photos/events/files_updated_event.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/extensions/string_ext.dart';
import 'package:photos/models/collection.dart';
import 'package:photos/models/file.dart';
import 'package:photos/models/file_type.dart';
@ -128,11 +127,10 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
);
} else if (widget.file!.pubMagicMetadata!.uploaderName != null) {
contentChildren.add(
// Use uploadName hashCode as userID so that different uploader
// get avatar color
// Use -1 as userID for enforcing black avatar color
OwnerAvatarOverlayIcon(
User(
id: widget.file!.pubMagicMetadata!.uploaderName.sumAsciiValues,
id: -1,
email: '',
name: widget.file!.pubMagicMetadata!.uploaderName,
),

View file

@ -3,7 +3,7 @@ import 'dart:math';
import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/models/file.dart';
import 'package:photos/models/magic_metadata.dart';
@ -12,7 +12,7 @@ import 'package:photos/utils/file_download_util.dart';
class DiffFetcher {
final _logger = Logger("DiffFetcher");
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
Future<Diff> getEncryptedFilesDiff(int collectionID, int sinceTime) async {
_logger.info(

View file

@ -5,7 +5,7 @@ import 'package:dio/dio.dart';
import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/models/file.dart' as ente;
import 'package:photos/services/collections_service.dart';
import 'package:photos/utils/crypto_util.dart';
@ -22,7 +22,7 @@ Future<io.File?> downloadAndDecrypt(
".encrypted";
final encryptedFile = io.File(encryptedFilePath);
final startTime = DateTime.now().millisecondsSinceEpoch;
return Network.instance
return NetworkClient.instance
.getDio()
.download(
file.downloadUrl,

View file

@ -15,7 +15,7 @@ import 'package:path/path.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/db/upload_locks_db.dart';
import 'package:photos/events/files_updated_event.dart';
@ -44,8 +44,8 @@ class FileUploader {
static const kFileUploadTimeout = Duration(minutes: 50);
final _logger = Logger("FileUploader");
final _dio = Network.instance.getDio();
final _enteDio = Network.instance.enteDio;
final _dio = NetworkClient.instance.getDio();
final _enteDio = NetworkClient.instance.enteDio;
final LinkedHashMap _queue = LinkedHashMap<String, FileUploadItem>();
final _uploadLocks = UploadLocksDB.instance;
final kSafeBufferForLockExpiry = const Duration(days: 1).inMicroseconds;

View file

@ -11,7 +11,7 @@ import 'package:photos/core/cache/thumbnail_in_memory_cache.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/models/file.dart';
import 'package:photos/utils/crypto_util.dart';
import 'package:photos/utils/file_download_util.dart';
@ -129,7 +129,7 @@ Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
final file = item.file;
Uint8List encryptedThumbnail;
try {
encryptedThumbnail = (await Network.instance.getDio().get(
encryptedThumbnail = (await NetworkClient.instance.getDio().get(
file.thumbnailUrl,
options: Options(
headers: {"X-Auth-Token": Configuration.instance.getToken()},

View file

@ -3,7 +3,7 @@ import 'dart:math';
import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/network.dart';
import 'package:photos/core/network/network.dart';
import 'package:photos/models/magic_metadata.dart';
import 'package:photos/models/trash_file.dart';
import 'package:photos/utils/crypto_util.dart';
@ -11,7 +11,7 @@ import 'package:photos/utils/file_download_util.dart';
class TrashDiffFetcher {
final _logger = Logger("TrashDiffFetcher");
final _enteDio = Network.instance.enteDio;
final _enteDio = NetworkClient.instance.enteDio;
Future<Diff> getTrashFilesDiff(int sinceTime) async {
try {

View file

@ -12,7 +12,7 @@ description: ente photos application
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.7.19+419
version: 0.7.20+420
environment:
sdk: '>=2.17.0 <3.0.0'