[mobile] Switch to feature flag plugin

This commit is contained in:
Neeraj Gupta 2024-04-23 11:54:24 +05:30
parent 74cdfdcb9e
commit 83075ea367
20 changed files with 101 additions and 70 deletions

View file

@ -10,19 +10,19 @@ PODS:
- Flutter
- file_saver (0.0.1):
- Flutter
- Firebase/CoreOnly (10.22.0):
- FirebaseCore (= 10.22.0)
- Firebase/Messaging (10.22.0):
- Firebase/CoreOnly (10.24.0):
- FirebaseCore (= 10.24.0)
- Firebase/Messaging (10.24.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 10.22.0)
- firebase_core (2.29.0):
- Firebase/CoreOnly (= 10.22.0)
- FirebaseMessaging (~> 10.24.0)
- firebase_core (2.30.0):
- Firebase/CoreOnly (= 10.24.0)
- Flutter
- firebase_messaging (14.7.19):
- Firebase/Messaging (= 10.22.0)
- firebase_messaging (14.8.1):
- Firebase/Messaging (= 10.24.0)
- firebase_core
- Flutter
- FirebaseCore (10.22.0):
- FirebaseCore (10.24.0):
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.12)
- GoogleUtilities/Logger (~> 7.12)
@ -33,7 +33,7 @@ PODS:
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- PromisesObjC (~> 2.1)
- FirebaseMessaging (10.22.0):
- FirebaseMessaging (10.24.0):
- FirebaseCore (~> 10.0)
- FirebaseInstallations (~> 10.0)
- GoogleDataTransport (~> 9.3)
@ -175,7 +175,7 @@ PODS:
- SDWebImage (5.19.1):
- SDWebImage/Core (= 5.19.1)
- SDWebImage/Core (5.19.1)
- SDWebImageWebPCoder (0.14.5):
- SDWebImageWebPCoder (0.14.6):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
- Sentry/HybridSDK (8.21.0):
@ -193,14 +193,14 @@ PODS:
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
- sqlite3 (3.45.1):
- sqlite3/common (= 3.45.1)
- sqlite3/common (3.45.1)
- sqlite3/fts5 (3.45.1):
- "sqlite3 (3.45.3+1)":
- "sqlite3/common (= 3.45.3+1)"
- "sqlite3/common (3.45.3+1)"
- "sqlite3/fts5 (3.45.3+1)":
- sqlite3/common
- sqlite3/perf-threadsafe (3.45.1):
- "sqlite3/perf-threadsafe (3.45.3+1)":
- sqlite3/common
- sqlite3/rtree (3.45.1):
- "sqlite3/rtree (3.45.3+1)":
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- Flutter
@ -404,13 +404,13 @@ SPEC CHECKSUMS:
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
Firebase: 797fd7297b7e1be954432743a0b3f90038e45a71
firebase_core: aaadbddb3cb2ee3792b9804f9dbb63e5f6f7b55c
firebase_messaging: e65050bf9b187511d80ea3a4de7cf5573d2c7543
FirebaseCore: 0326ec9b05fbed8f8716cddbf0e36894a13837f7
Firebase: 91fefd38712feb9186ea8996af6cbdef41473442
firebase_core: 66b99b4fb4e5d7cc4e88d4c195fe986681f3466a
firebase_messaging: 0eb0425d28b4f4af147cdd4adcaf7c0100df28ed
FirebaseCore: 11dc8a16dfb7c5e3c3f45ba0e191a33ac4f50894
FirebaseCoreInternal: bcb5acffd4ea05e12a783ecf835f2210ce3dc6af
FirebaseInstallations: 8f581fca6478a50705d2bd2abd66d306e0f5736e
FirebaseMessaging: 9f71037fd9db3376a4caa54e5a3949d1027b4b6e
FirebaseMessaging: 4d52717dd820707cc4eadec5eb981b4832ec8d5d
fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b
@ -452,14 +452,14 @@ SPEC CHECKSUMS:
receive_sharing_intent: 6837b01768e567fe8562182397bf43d63d8c6437
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb
SDWebImageWebPCoder: c94f09adbca681822edad9e532ac752db713eabf
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Sentry: ebc12276bd17613a114ab359074096b6b3725203
sentry_flutter: 88ebea3f595b0bc16acc5bedacafe6d60c12dcd5
SentryPrivate: d651efb234cf385ec9a1cdd3eff94b5e78a0e0fe
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
sqlite3: 73b7fc691fdc43277614250e04d183740cb15078
sqlite3: 02d1f07eaaa01f80a1c16b4b31dfcbb3345ee01a
sqlite3_flutter_libs: af0e8fe9bce48abddd1ffdbbf839db0302d72d80
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a

View file

@ -21,12 +21,12 @@ 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/l10n/l10n.dart";
import "package:photos/service_locator.dart";
import 'package:photos/services/app_lifecycle_service.dart';
import 'package:photos/services/billing_service.dart';
import 'package:photos/services/collections_service.dart';
import "package:photos/services/entity_service.dart";
import 'package:photos/services/favorites_service.dart';
import 'package:photos/services/feature_flag_service.dart';
import 'package:photos/services/home_widget_service.dart';
import 'package:photos/services/local_file_update_service.dart';
import 'package:photos/services/local_sync_service.dart';
@ -178,6 +178,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
_isProcessRunning = true;
_logger.info("Initializing... inBG =$isBackground via: $via");
final SharedPreferences preferences = await SharedPreferences.getInstance();
await _logFGHeartBeatInfo();
unawaited(_scheduleHeartBeat(preferences, isBackground));
AppLifecycleService.instance.init(preferences);
@ -191,6 +192,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
CryptoUtil.init();
await Configuration.instance.init();
await NetworkClient.instance.init();
ServiceLocator.instance.init(preferences, NetworkClient.instance.enteDio);
await UserService.instance.init();
await EntityService.instance.init();
LocationService.instance.init(preferences);
@ -224,7 +226,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
);
});
}
unawaited(FeatureFlagService.instance.init());
unawaited(SemanticSearchService.instance.init());
MachineLearningController.instance.init();
// Can not including existing tf/ml binaries as they are not being built

View file

@ -9,7 +9,7 @@ import 'package:photos/core/constants.dart';
import 'package:photos/models/file/file_type.dart';
import 'package:photos/models/location/location.dart';
import "package:photos/models/metadata/file_magic.dart";
import 'package:photos/services/feature_flag_service.dart';
import "package:photos/service_locator.dart";
import 'package:photos/utils/date_time_util.dart';
import 'package:photos/utils/exif_util.dart';
import 'package:photos/utils/file_uploader_util.dart';
@ -244,8 +244,7 @@ class EnteFile {
String get downloadUrl {
final endpoint = Configuration.instance.getHttpEndpoint();
if (endpoint != kDefaultProductionEndpoint ||
FeatureFlagService.instance.disableCFWorker()) {
if (endpoint != kDefaultProductionEndpoint || flagService.disableCFWorker) {
return endpoint + "/files/download/" + uploadedFileID.toString();
} else {
return "https://files.ente.io/?fileID=" + uploadedFileID.toString();
@ -258,8 +257,7 @@ class EnteFile {
String get thumbnailUrl {
final endpoint = Configuration.instance.getHttpEndpoint();
if (endpoint != kDefaultProductionEndpoint ||
FeatureFlagService.instance.disableCFWorker()) {
if (endpoint != kDefaultProductionEndpoint || flagService.disableCFWorker) {
return endpoint + "/files/preview/" + uploadedFileID.toString();
} else {
return "https://thumbnails.ente.io/?fileID=" + uploadedFileID.toString();

View file

@ -0,0 +1,28 @@
import "package:dio/dio.dart";
import "package:ente_feature_flag/ente_feature_flag.dart";
import "package:shared_preferences/shared_preferences.dart";
class ServiceLocator {
late final SharedPreferences prefs;
late final Dio enteDio;
// instance
ServiceLocator._privateConstructor();
static final ServiceLocator instance = ServiceLocator._privateConstructor();
init(SharedPreferences prefs, Dio enteDio) {
this.prefs = prefs;
this.enteDio = enteDio;
}
}
FlagService? _flagService;
FlagService get flagService {
_flagService ??= FlagService(
ServiceLocator.instance.prefs,
ServiceLocator.instance.enteDio,
);
return _flagService!;
}

View file

@ -30,9 +30,9 @@ import 'package:photos/models/collection/collection_items.dart';
import 'package:photos/models/file/file.dart';
import "package:photos/models/files_split.dart";
import "package:photos/models/metadata/collection_magic.dart";
import "package:photos/service_locator.dart";
import 'package:photos/services/app_lifecycle_service.dart';
import "package:photos/services/favorites_service.dart";
import "package:photos/services/feature_flag_service.dart";
import 'package:photos/services/file_magic_service.dart';
import 'package:photos/services/local_sync_service.dart';
import 'package:photos/services/remote_sync_service.dart';
@ -1162,7 +1162,7 @@ class CollectionsService {
await _addToCollection(dstCollectionID, splitResult.ownedByCurrentUser);
}
if (splitResult.ownedByOtherUsers.isNotEmpty) {
if (!FeatureFlagService.instance.isInternalUserOrDebugBuild()) {
if (!flagService.internalUser) {
throw ArgumentError('Cannot add files owned by other users');
}
late final List<EnteFile> filesToCopy;

View file

@ -23,9 +23,9 @@ import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart';
import 'package:photos/models/file/file_type.dart';
import 'package:photos/models/upload_strategy.dart';
import "package:photos/service_locator.dart";
import 'package:photos/services/app_lifecycle_service.dart';
import 'package:photos/services/collections_service.dart';
import "package:photos/services/feature_flag_service.dart";
import 'package:photos/services/ignored_files_service.dart';
import 'package:photos/services/local_file_update_service.dart';
import "package:photos/services/notification_service.dart";
@ -185,7 +185,7 @@ class RemoteSyncService {
rethrow;
} else {
_logger.severe("Error executing remote sync ", e, s);
if (FeatureFlagService.instance.isInternalUserOrDebugBuild()) {
if (flagService.internalUser) {
rethrow;
}
}

View file

@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/services/feature_flag_service.dart';
import "package:photos/service_locator.dart";
import 'package:photos/services/update_service.dart';
import "package:photos/ui/payment/store_subscription_page.dart";
import 'package:photos/ui/payment/stripe_subscription_page.dart';
@ -9,8 +9,7 @@ StatefulWidget getSubscriptionPage({bool isOnBoarding = false}) {
if (UpdateService.instance.isIndependentFlavor()) {
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
}
if (FeatureFlagService.instance.enableStripe() &&
_isUserCreatedPostStripeSupport()) {
if (flagService.enableStripe && _isUserCreatedPostStripeSupport()) {
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
} else {
return StoreSubscriptionPage(isOnboarding: isOnBoarding);

View file

@ -5,7 +5,7 @@ import "package:intl/intl.dart";
import "package:photos/core/event_bus.dart";
import 'package:photos/events/embedding_updated_event.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/services/feature_flag_service.dart";
import "package:photos/service_locator.dart";
import 'package:photos/services/machine_learning/semantic_search/frameworks/ml_framework.dart';
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
import "package:photos/theme/ente_theme.dart";
@ -151,7 +151,7 @@ class _MachineLearningSettingsPageState
const SizedBox(
height: 12,
),
FeatureFlagService.instance.isInternalUserOrDebugBuild()
flagService.internalUser
? MenuItemWidget(
leadingIcon: Icons.delete_sweep_outlined,
captionedTextWidget: CaptionedTextWidget(

View file

@ -10,7 +10,7 @@ import 'package:photos/events/two_factor_status_change_event.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/l10n/l10n.dart";
import "package:photos/models/user_details.dart";
import "package:photos/services/feature_flag_service.dart";
import 'package:photos/service_locator.dart';
import 'package:photos/services/local_authentication_service.dart';
import "package:photos/services/passkey_service.dart";
import 'package:photos/services/user_service.dart';
@ -70,8 +70,7 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
final Completer completer = Completer();
final List<Widget> children = [];
if (_config.hasConfiguredAccount()) {
final bool isInternalUser =
FeatureFlagService.instance.isInternalUserOrDebugBuild();
final bool isInternalUser = flagService.internalUser;
children.addAll(
[
sectionOptionSpacing,

View file

@ -7,7 +7,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/opened_settings_event.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/feature_flag_service.dart';
import "package:photos/service_locator.dart";
import "package:photos/services/storage_bonus_service.dart";
import 'package:photos/theme/colors.dart';
import 'package:photos/theme/ente_theme.dart';
@ -140,8 +140,7 @@ class SettingsPage extends StatelessWidget {
const AboutSectionWidget(),
]);
if (hasLoggedIn &&
FeatureFlagService.instance.isInternalUserOrDebugBuild()) {
if (hasLoggedIn && flagService.internalUser) {
contents.addAll([sectionSpacing, const DebugSectionWidget()]);
}
contents.add(const AppVersionWidget());

View file

@ -7,7 +7,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:photos/core/cache/video_cache_manager.dart';
import 'package:photos/core/configuration.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/services/feature_flag_service.dart';
import "package:photos/service_locator.dart";
import 'package:photos/theme/ente_theme.dart';
import 'package:photos/ui/components/buttons/icon_button_widget.dart';
import 'package:photos/ui/components/captioned_text_widget.dart';
@ -34,7 +34,7 @@ class _AppStorageViewerState extends State<AppStorageViewer> {
@override
void initState() {
internalUser = FeatureFlagService.instance.isInternalUserOrDebugBuild();
internalUser = flagService.internalUser;
addPath();
super.initState();
}

View file

@ -14,8 +14,8 @@ import 'package:photos/models/files_split.dart';
import 'package:photos/models/gallery_type.dart';
import "package:photos/models/metadata/common_keys.dart";
import 'package:photos/models/selected_files.dart';
import "package:photos/service_locator.dart";
import 'package:photos/services/collections_service.dart';
import "package:photos/services/feature_flag_service.dart";
import 'package:photos/services/hidden_service.dart';
import "package:photos/theme/colors.dart";
import "package:photos/theme/ente_theme.dart";
@ -98,7 +98,7 @@ class _FileSelectionActionsWidgetState
@override
Widget build(BuildContext context) {
_isInternalUser = FeatureFlagService.instance.isInternalUserOrDebugBuild();
_isInternalUser = flagService.internalUser;
final ownedFilesCount = split.ownedByCurrentUser.length;
final ownedAndPendingUploadFilesCount =
ownedFilesCount + split.pendingUploads.length;

View file

@ -18,8 +18,8 @@ import 'package:photos/models/file/trash_file.dart';
import 'package:photos/models/ignored_file.dart';
import "package:photos/models/metadata/common_keys.dart";
import 'package:photos/models/selected_files.dart';
import "package:photos/service_locator.dart";
import 'package:photos/services/collections_service.dart';
import "package:photos/services/feature_flag_service.dart";
import 'package:photos/services/hidden_service.dart';
import 'package:photos/services/ignored_files_service.dart';
import 'package:photos/services/local_sync_service.dart';
@ -141,8 +141,7 @@ class FileAppBarState extends State<FileAppBar> {
);
}
// only show fav option for files owned by the user
if ((isOwnedByUser ||
FeatureFlagService.instance.isInternalUserOrDebugBuild()) &&
if ((isOwnedByUser || flagService.internalUser) &&
!isFileHidden &&
isFileUploaded) {
_actions.add(

View file

@ -9,7 +9,7 @@ import 'package:photos/core/constants.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart';
import "package:photos/services/feature_flag_service.dart";
import "package:photos/service_locator.dart";
import 'package:photos/services/files_service.dart';
import "package:photos/ui/actions/file/file_actions.dart";
import 'package:photos/ui/viewer/file/thumbnail_widget.dart';
@ -161,8 +161,7 @@ class _VideoWidgetState extends State<VideoWidget> {
}
}).onError(
(error, stackTrace) {
if (mounted &&
FeatureFlagService.instance.isInternalUserOrDebugBuild()) {
if (mounted && flagService.internalUser) {
if (error is Exception) {
showErrorDialogForException(
context: context,

View file

@ -19,8 +19,8 @@ import 'package:photos/models/device_collection.dart';
import 'package:photos/models/gallery_type.dart';
import "package:photos/models/metadata/common_keys.dart";
import 'package:photos/models/selected_files.dart';
import 'package:photos/service_locator.dart';
import 'package:photos/services/collections_service.dart';
import "package:photos/services/feature_flag_service.dart";
import 'package:photos/services/sync_service.dart';
import 'package:photos/services/update_service.dart';
import 'package:photos/ui/actions/collection/collection_sharing_actions.dart';
@ -96,7 +96,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
_selectedFilesListener = () {
setState(() {});
};
isInternalUser = FeatureFlagService.instance.isInternalUserOrDebugBuild();
isInternalUser = flagService.internalUser;
collectionActions = CollectionActions(CollectionsService.instance);
widget.selectedFiles.addListener(_selectedFilesListener);
_userAuthEventSubscription =

View file

@ -5,7 +5,7 @@ import "package:flutter/services.dart";
import "package:photos/generated/l10n.dart";
import 'package:photos/models/button_result.dart';
import 'package:photos/models/typedefs.dart';
import "package:photos/services/feature_flag_service.dart";
import "package:photos/service_locator.dart";
import 'package:photos/theme/colors.dart';
import 'package:photos/ui/common/loading_widget.dart';
import 'package:photos/ui/common/progress_dialog.dart';
@ -91,8 +91,7 @@ String parseErrorForUI(
}
}
// return generic error if the user is not internal and the error is not in debug mode
if (!(FeatureFlagService.instance.isInternalUserOrDebugBuild() &&
kDebugMode)) {
if (!(flagService.internalUser && kDebugMode)) {
return genericError;
}
String errorInfo = "";

View file

@ -6,7 +6,7 @@ import "package:dio/dio.dart";
import "package:logging/logging.dart";
import "package:photos/core/constants.dart";
import "package:photos/core/network/network.dart";
import "package:photos/services/feature_flag_service.dart";
import "package:photos/service_locator.dart";
import "package:photos/utils/xml_parser_util.dart";
final _enteDio = NetworkClient.instance.enteDio;
@ -58,7 +58,7 @@ Future<int> calculatePartCount(int fileSize) async {
Future<MultipartUploadURLs> getMultipartUploadURLs(int count) async {
try {
assert(
FeatureFlagService.instance.isInternalUserOrDebugBuild(),
flagService.internalUser,
"Multipart upload should not be enabled for external users.",
);
final response = await _enteDio.get(

View file

@ -46,7 +46,7 @@ class FlagService {
if (kDebugMode) {
debugPrint("Fetching feature flags");
}
final response = await _enteDio.get("/remote-store/feature_flags");
final response = await _enteDio.get("/remote-store/feature-flags");
final remoteFlags = RemoteFlags.fromMap(response.data);
await _prefs.setString("remote_flags", remoteFlags.toJson());
_flags = remoteFlags;

View file

@ -434,6 +434,13 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.17"
ente_feature_flag:
dependency: "direct main"
description:
path: "plugins/ente_feature_flag"
relative: true
source: path
version: "0.0.1"
equatable:
dependency: "direct main"
description:
@ -551,10 +558,10 @@ packages:
dependency: "direct main"
description:
name: firebase_core
sha256: a864d1b6afd25497a3b57b016886d1763df52baaa69758a46723164de8d187fe
sha256: "6b1152a5af3b1cfe7e45309e96fc1aa14873f410f7aadb3878aa7812acfa7531"
url: "https://pub.dev"
source: hosted
version: "2.29.0"
version: "2.30.0"
firebase_core_platform_interface:
dependency: transitive
description:
@ -575,10 +582,10 @@ packages:
dependency: "direct main"
description:
name: firebase_messaging
sha256: e41586e0fd04fe9a40424f8b0053d0832e6d04f49e020cdaf9919209a28497e9
sha256: "87e3eda0ecdfeadb5fd1cf0dc5153aea5307a0cfca751c4b1ac97bfdd805660e"
url: "https://pub.dev"
source: hosted
version: "14.7.19"
version: "14.8.1"
firebase_messaging_platform_interface:
dependency: transitive
description:

View file

@ -47,6 +47,8 @@ dependencies:
dotted_border: ^2.1.0
dropdown_button2: ^2.0.0
email_validator: ^2.0.1
ente_feature_flag:
path: plugins/ente_feature_flag
equatable: ^2.0.5
event_bus: ^2.0.0
exif: ^3.0.0
@ -59,8 +61,8 @@ dependencies:
file_saver:
# Use forked version till this PR is merged: https://github.com/incrediblezayed/file_saver/pull/87
git: https://github.com/jesims/file_saver.git
firebase_core: ^2.13.1
firebase_messaging: ^14.6.2
firebase_core: ^2.30.0
firebase_messaging: ^14.8.0
fk_user_agent: ^2.0.1
flutter:
sdk: flutter