diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml
index afd97abab..3732de0ff 100644
--- a/.github/workflows/crowdin.yml
+++ b/.github/workflows/crowdin.yml
@@ -6,6 +6,8 @@ on:
paths:
- 'lib/l10n/intl_en.arb'
branches: [ main ]
+ schedule:
+ - cron: '0 */12 * * *' # Every 12 hours - https://crontab.guru/#0_*/12_*_*_*
jobs:
synchronize-with-crowdin:
diff --git a/.gitignore b/.gitignore
index 2ff5fe7c7..465f249bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@
#Visual Studio Code related
.vscode/launch.json
+.vscode/settings.json
# Flutter/Dart/Pub related
**/doc/api/
@@ -28,7 +29,6 @@
.pub/
/build/
-lib/generated/*
# Web related
lib/generated_plugin_registrant.dart
diff --git a/README.md b/README.md
index 571d732c7..ebcd1164a 100644
--- a/README.md
+++ b/README.md
@@ -66,8 +66,9 @@ You can alternatively install the build from PlayStore or F-Droid.
3. Pull in all submodules with `git submodule update --init --recursive`
4. Enable repo git hooks `git config core.hooksPath hooks`
5. Setup TensorFlowLite by executing `setup.sh`
-6. For Android, [setup your keystore](https://docs.flutter.dev/deployment/android#create-an-upload-keystore) and run `flutter build apk --release --flavor independent`
-7. For iOS, run `flutter build ios`
+6. If using Visual Studio Code, add the [Flutter Intl](https://marketplace.visualstudio.com/items?itemName=localizely.flutter-intl) extension
+7. For Android, [setup your keystore](https://docs.flutter.dev/deployment/android#create-an-upload-keystore) and run `flutter build apk --release --flavor independent`
+8. For iOS, run `flutter build ios`
## 🙋 Help
diff --git a/lib/app.dart b/lib/app.dart
index 7d8409770..feba2c151 100644
--- a/lib/app.dart
+++ b/lib/app.dart
@@ -21,29 +21,44 @@ class EnteApp extends StatefulWidget {
final Future Function(String) runBackgroundTask;
final Future Function(String) killBackgroundTask;
final AdaptiveThemeMode? savedThemeMode;
+ final Locale locale;
const EnteApp(
this.runBackgroundTask,
this.killBackgroundTask,
+ this.locale,
this.savedThemeMode, {
Key? key,
}) : super(key: key);
+ static void setLocale(BuildContext context, Locale newLocale) {
+ final state = context.findAncestorStateOfType<_EnteAppState>()!;
+ state.setLocale(newLocale);
+ }
+
@override
State createState() => _EnteAppState();
}
class _EnteAppState extends State with WidgetsBindingObserver {
final _logger = Logger("EnteAppState");
+ late Locale locale;
@override
void initState() {
_logger.info('init App');
super.initState();
+ locale = widget.locale;
setupIntentAction();
WidgetsBinding.instance.addObserver(this);
}
+ setLocale(Locale newLocale) {
+ setState(() {
+ locale = newLocale;
+ });
+ }
+
void setupIntentAction() async {
final mediaExtentionAction = Platform.isAndroid
? await initIntentAction()
@@ -72,6 +87,7 @@ class _EnteAppState extends State with WidgetsBindingObserver {
: const HomeWidget(),
debugShowCheckedModeBanner: false,
builder: EasyLoading.init(),
+ locale: locale,
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [
@@ -89,6 +105,7 @@ class _EnteAppState extends State with WidgetsBindingObserver {
home: const HomeWidget(),
debugShowCheckedModeBanner: false,
builder: EasyLoading.init(),
+ locale: locale,
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [
diff --git a/lib/core/constants.dart b/lib/core/constants.dart
index 236419b4d..63f62ed39 100644
--- a/lib/core/constants.dart
+++ b/lib/core/constants.dart
@@ -57,3 +57,11 @@ const double restrictedMaxWidth = 430;
const double mobileSmallThreshold = 336;
const publicLinkDeviceLimits = [50, 25, 10, 5, 2, 1];
+
+const kilometersPerDegree = 111.16;
+
+const radiusValues = [2, 10, 20, 40, 80, 200, 400, 1200];
+
+const defaultRadiusValueIndex = 4;
+
+const galleryGridSpacing = 2.0;
diff --git a/lib/db/entities_db.dart b/lib/db/entities_db.dart
new file mode 100644
index 000000000..b8b48fbe4
--- /dev/null
+++ b/lib/db/entities_db.dart
@@ -0,0 +1,65 @@
+import 'package:flutter/foundation.dart';
+import 'package:photos/db/files_db.dart';
+import "package:photos/models/api/entity/type.dart";
+import "package:photos/models/local_entity_data.dart";
+import 'package:sqflite/sqlite_api.dart';
+
+extension EntitiesDB on FilesDB {
+ Future upsertEntities(
+ List data, {
+ ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm.replace,
+ }) async {
+ debugPrint("Inserting missing PathIDToLocalIDMapping");
+ final db = await database;
+ var batch = db.batch();
+ int batchCounter = 0;
+ for (LocalEntityData e in data) {
+ if (batchCounter == 400) {
+ await batch.commit(noResult: true);
+ batch = db.batch();
+ batchCounter = 0;
+ }
+ batch.insert(
+ "entities",
+ e.toJson(),
+ conflictAlgorithm: conflictAlgorithm,
+ );
+ batchCounter++;
+ }
+ await batch.commit(noResult: true);
+ }
+
+ Future deleteEntities(
+ List ids,
+ ) async {
+ final db = await database;
+ var batch = db.batch();
+ int batchCounter = 0;
+ for (String id in ids) {
+ if (batchCounter == 400) {
+ await batch.commit(noResult: true);
+ batch = db.batch();
+ batchCounter = 0;
+ }
+ batch.delete(
+ "entities",
+ where: "id = ?",
+ whereArgs: [id],
+ );
+ batchCounter++;
+ }
+ await batch.commit(noResult: true);
+ }
+
+ Future> getEntities(EntityType type) async {
+ final db = await database;
+ final List