Merge remote-tracking branch 'origin/main' into mobile-preview-video
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: Report a bug
|
||||
description: Let us know if something's not working the way you expected.
|
||||
labels: ["triage"]
|
||||
labels: []
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
2
.github/workflows/auth-internal-release.yml
vendored
@ -4,7 +4,7 @@ on:
|
||||
workflow_dispatch: # Allow manually running the action
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
FLUTTER_VERSION: "3.27.2"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
2
.github/workflows/auth-lint.yml
vendored
@ -8,7 +8,7 @@ on:
|
||||
- ".github/workflows/auth-lint.yml"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
FLUTTER_VERSION: "3.27.2"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
2
.github/workflows/auth-release.yml
vendored
@ -29,7 +29,7 @@ on:
|
||||
- "auth-v*"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
FLUTTER_VERSION: "3.27.2"
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
|
@ -4,7 +4,7 @@ on:
|
||||
workflow_dispatch: # Allow manually running the action
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
FLUTTER_VERSION: "3.27.2"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
2
.github/workflows/mobile-lint.yml
vendored
@ -9,7 +9,7 @@ on:
|
||||
|
||||
env:
|
||||
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
FLUTTER_VERSION: "3.27.2"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
2
.github/workflows/mobile-release.yml
vendored
@ -9,7 +9,7 @@ on:
|
||||
- "photos-v*"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
FLUTTER_VERSION: "3.27.2"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -46,6 +46,7 @@
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data android:name="flutterEmbedding" android:value="2"/>
|
||||
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
|
||||
|
||||
<meta-data android:name="io.sentry.dsn"
|
||||
android:value="https://ed4ddd6309b847ba8849935e26e9b648@sentry.ente.io/9"/>
|
||||
|
BIN
auth/assets/2.0x/calender_banner_dark.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
auth/assets/2.0x/calender_banner_light.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
auth/assets/2.0x/discount.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
auth/assets/2.0x/ente_5gb.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
auth/assets/2.0x/rate_us.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
auth/assets/2.0x/star_us.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
auth/assets/3.0x/calender_banner_dark.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
auth/assets/3.0x/calender_banner_light.png
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
auth/assets/3.0x/discount.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
auth/assets/3.0x/ente_5gb.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
auth/assets/3.0x/rate_us.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
auth/assets/3.0x/star_us.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
auth/assets/calender_banner_dark.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
auth/assets/calender_banner_light.png
Normal file
After Width: | Height: | Size: 18 KiB |
@ -257,6 +257,9 @@
|
||||
"Crypto com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "CSAM"
|
||||
},
|
||||
{
|
||||
"title": "CSFloat"
|
||||
},
|
||||
@ -342,8 +345,7 @@
|
||||
"title": "Estateguru"
|
||||
},
|
||||
{
|
||||
"title": "Fastmail",
|
||||
"hex": "0067B9"
|
||||
"title": "Fastmail"
|
||||
},
|
||||
{
|
||||
"title": "Fidelity",
|
||||
@ -834,6 +836,9 @@
|
||||
"Registro.br"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "reMarkable"
|
||||
},
|
||||
{
|
||||
"title": "Restorecord"
|
||||
},
|
||||
|
4
auth/assets/custom-icons/icons/csam.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
||||
<circle cx="512" cy="512" r="512" fill="#9a2857"/>
|
||||
<path d="M727 278.6q-99 37.09-197.74 74.76a27.83 27.83 0 0 1-20.85.41q-102.54-36.2-205.09-72.35c-4.45-1.57-9-2.82-14.22-4.56v469.89c3.42-1.16 5.67-1.83 7.84-2.7 69-28.07 138.13-55.9 206.95-84.41a34.06 34.06 0 0 1 29.52.36c66.62 29.54 133.53 58.41 201.5 88V276c-3.35 1.09-5.67 1.74-7.91 2.6Zm-208 339-.57-225.6c18.21-6.66 36.44-13.21 54.6-20 42.69-15.8 85.34-31.83 129.09-48.23v373.44C640.57 671 579.79 644.3 519 617.63Zm162.1-107a14 14 0 0 1-12.86 13.31 14.34 14.34 0 0 1-13.66-12.66c-.32-5.93 6.92-13.46 13-13.53a14.58 14.58 0 0 1 13.51 12.88Z" fill="#fff"/>
|
||||
</svg>
|
After Width: | Height: | Size: 683 B |
3
auth/assets/custom-icons/icons/remarkable.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 960">
|
||||
<path fill="#000000" d="M494.86,409.59l-37.52-83.51h-35.35v1.44c2.89,2.52,4.69,9.56,4.69,17.31v80.63c0,12.8-1.62,19.12-4.33,21.83v1.44h20.56s0-1.44,0-1.44c-2.71-2.71-5.41-7.22-5.41-21.83v-80.99s46.18,104.26,46.18,104.26h5.23l46.19-104.61v84.05c0,10.1-1.62,16.42-4.33,19.12v1.44h34.81s0-1.44,0-1.44c-2.71-2.71-4.33-9.01-4.33-19.12v-83.34c0-7.76,1.81-14.79,4.69-17.31v-1.44h-34.09l-36.98,83.51h0ZM378.21,373.87v-20.2h-.73l-31.03,11.19v1.27c3.79,3.25,6.49,10.28,6.49,20.92v41.12c0,10.1-1.62,16.42-4.33,19.12v1.44h35.71s0-1.44,0-1.44c-3.06-2.35-6.14-6.68-6.14-19.12v-47.98c3.79-3.6,9.56-5.6,16.96-5.6,6.14,0,11.9,1.08,16.23,3.25h1.44s0-22.54,0-22.54c-1.62-.36-3.97-.54-6.49-.54-12.44,0-22.37,8.66-28.14,19.12h.01Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 784 B |
BIN
auth/assets/discount.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
auth/assets/ente_5gb.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
auth/assets/rate_us.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
auth/assets/star_us.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
@ -1 +1 @@
|
||||
Subproject commit 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||
Subproject commit 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3
|
@ -82,8 +82,6 @@ PODS:
|
||||
- qr_code_scanner (0.2.0):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- scan (0.0.1):
|
||||
- Flutter
|
||||
- SDWebImage (5.20.0):
|
||||
- SDWebImage/Core (= 5.20.0)
|
||||
- SDWebImage/Core (5.20.0)
|
||||
@ -146,7 +144,6 @@ DEPENDENCIES:
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- privacy_screen (from `.symlinks/plugins/privacy_screen/ios`)
|
||||
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
|
||||
- scan (from `.symlinks/plugins/scan/ios`)
|
||||
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
@ -208,8 +205,6 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/privacy_screen/ios"
|
||||
qr_code_scanner:
|
||||
:path: ".symlinks/plugins/qr_code_scanner/ios"
|
||||
scan:
|
||||
:path: ".symlinks/plugins/scan/ios"
|
||||
sentry_flutter:
|
||||
:path: ".symlinks/plugins/sentry_flutter/ios"
|
||||
share_plus:
|
||||
@ -250,7 +245,6 @@ SPEC CHECKSUMS:
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
|
||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||
scan: aea35bb4aa59ccc8839c576a18cd57c7d492cc86
|
||||
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
|
||||
Sentry: f8374b5415bc38dfb5645941b3ae31230fbeae57
|
||||
sentry_flutter: 0eb93e5279eb41e2392212afe1ccd2fecb4f8cbe
|
||||
|
@ -63,6 +63,8 @@
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>FlutterDeepLinkingEnabled</key>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
|
@ -88,6 +88,8 @@
|
||||
"useRecoveryKey": "Utilizza un codice di recupero",
|
||||
"incorrectPasswordTitle": "Password sbagliata",
|
||||
"welcomeBack": "Bentornato!",
|
||||
"emailAlreadyRegistered": "Email già registrata.",
|
||||
"emailNotRegistered": "Email non registrata.",
|
||||
"madeWithLoveAtPrefix": "realizzato con ❤️ a ",
|
||||
"supportDevs": "Iscriviti a <bold-green>ente</bold-green> per supportare questo progetto.",
|
||||
"supportDiscount": "Utilizzare il codice coupon \"AUTH\" per ottenere il 10% di sconto al primo anno",
|
||||
|
@ -88,6 +88,8 @@
|
||||
"useRecoveryKey": "Herstelsleutel gebruiken",
|
||||
"incorrectPasswordTitle": "Onjuist wachtwoord",
|
||||
"welcomeBack": "Welkom terug!",
|
||||
"emailAlreadyRegistered": "E-mail is al geregistreerd.",
|
||||
"emailNotRegistered": "E-mail niet geregistreerd.",
|
||||
"madeWithLoveAtPrefix": "met ❤️ gemaakt door",
|
||||
"supportDevs": "Abonneer u op <bold-green>ente</bold-green> om ons te steunen",
|
||||
"supportDiscount": "Gebruik couponcode \"AUTH\" om het eerste jaar 10% korting te krijgen",
|
||||
|
@ -88,6 +88,8 @@
|
||||
"useRecoveryKey": "Använd återställningsnyckel",
|
||||
"incorrectPasswordTitle": "Felaktigt lösenord",
|
||||
"welcomeBack": "Välkommen tillbaka!",
|
||||
"emailAlreadyRegistered": "E-postadress redan registrerad.",
|
||||
"emailNotRegistered": "E-postadress ej registrerad.",
|
||||
"madeWithLoveAtPrefix": "gjord med ❤️ av ",
|
||||
"supportDevs": "Prenumerera på <bold-green>ente</bold-green> för att stödja oss",
|
||||
"supportDiscount": "Använd kupongkoden \"AUTH\" för att få 10% rabatt första året",
|
||||
@ -321,7 +323,11 @@
|
||||
"terminate": "Avsluta",
|
||||
"thisDevice": "Den här enheten",
|
||||
"thisEmailIsAlreadyInUse": "Denna e-postadress används redan",
|
||||
"verificationFailedPleaseTryAgain": "Verifiering misslyckades, vänligen försök igen",
|
||||
"yourVerificationCodeHasExpired": "Din verifieringskod har upphört att gälla",
|
||||
"incorrectCode": "Felaktig kod",
|
||||
"sorryTheCodeYouveEnteredIsIncorrect": "Tyvärr, den kod som du har angett är felaktig",
|
||||
"authenticationFailedPleaseTryAgain": "Autentisering misslyckades, vänligen försök igen",
|
||||
"authenticationSuccessful": "Autentisering lyckades!",
|
||||
"twofactorAuthenticationSuccessfullyReset": "Tvåfaktorsautentisering återställd",
|
||||
"incorrectRecoveryKey": "Felaktig återställningsnyckel",
|
||||
|
@ -104,7 +104,12 @@ Future<void> _runInForeground() async {
|
||||
final savedThemeMode = _themeMode(await AdaptiveTheme.getThemeMode());
|
||||
return await _runWithLogs(() async {
|
||||
_logger.info("Starting app in foreground");
|
||||
await _init(false, via: 'mainMethod');
|
||||
try {
|
||||
await _init(false, via: 'mainMethod');
|
||||
} catch (e, s) {
|
||||
_logger.severe("Failed to init", e, s);
|
||||
rethrow;
|
||||
}
|
||||
final Locale? locale = await getLocale(noFallback: true);
|
||||
unawaited(UpdateService.instance.showUpdateNotification());
|
||||
runApp(
|
||||
@ -156,7 +161,7 @@ void _registerWindowsProtocol() {
|
||||
|
||||
Future<void> _init(bool bool, {String? via}) async {
|
||||
_registerWindowsProtocol();
|
||||
await initCryptoUtil();
|
||||
await CryptoUtil.init();
|
||||
|
||||
await PreferenceService.instance.init();
|
||||
await CodeStore.instance.init();
|
||||
|
@ -7,7 +7,5 @@ String twoFactorTypeToString(TwoFactorType type) {
|
||||
return "totp";
|
||||
case TwoFactorType.passkey:
|
||||
return "passkey";
|
||||
default:
|
||||
return type.name;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class WindowListenerService {
|
||||
static const double minWindowHeight = 600.0;
|
||||
static const double minWindowHeight = 320.0;
|
||||
static const double minWindowWidth = 800.0;
|
||||
static const double maxWindowHeight = 8192.0;
|
||||
static const double maxWindowWidth = 8192.0;
|
||||
@ -25,21 +26,16 @@ class WindowListenerService {
|
||||
_preferences.getDouble('windowWidth') ?? minWindowWidth;
|
||||
final double windowHeight =
|
||||
_preferences.getDouble('windowHeight') ?? minWindowHeight;
|
||||
return Size(
|
||||
windowWidth.clamp(minWindowWidth, maxWindowWidth),
|
||||
windowHeight.clamp(minWindowHeight, maxWindowHeight),
|
||||
);
|
||||
final w = windowWidth.clamp(200.0, maxWindowWidth);
|
||||
final h = windowHeight.clamp(400.0, maxWindowHeight);
|
||||
return Size(w, h);
|
||||
}
|
||||
|
||||
Future<void> onWindowResize() async {
|
||||
final width = (await windowManager.getSize()).width;
|
||||
final height = (await windowManager.getSize()).height;
|
||||
// Save the window size to shared preferences
|
||||
await _preferences.setDouble(
|
||||
'windowWidth',
|
||||
(await windowManager.getSize()).width,
|
||||
);
|
||||
await _preferences.setDouble(
|
||||
'windowHeight',
|
||||
(await windowManager.getSize()).height,
|
||||
);
|
||||
await _preferences.setDouble('windowWidth', width);
|
||||
await _preferences.setDouble('windowHeight', height);
|
||||
}
|
||||
}
|
||||
|
@ -64,22 +64,6 @@ class CodeStore {
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> updateCodeIndex(Code code) async {
|
||||
final key = code.generatedID!;
|
||||
|
||||
_cacheCodes.remove(key);
|
||||
int deletedIndex = code.display.position;
|
||||
|
||||
_cacheCodes.forEach((key, c) async {
|
||||
if (c.display.position > deletedIndex) {
|
||||
Code updatedCode = c.copyWith(
|
||||
display: c.display.copyWith(position: c.display.position - 1),
|
||||
);
|
||||
await addCode(updatedCode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<List<Code>> getAllCodes({
|
||||
AccountMode? accountMode,
|
||||
bool sortCodes = true,
|
||||
@ -179,7 +163,6 @@ class CodeStore {
|
||||
Future<void> removeCode(Code code, {AccountMode? accountMode}) async {
|
||||
final mode = accountMode ?? _authenticatorService.getAccountMode();
|
||||
await _authenticatorService.deleteEntry(code.generatedID!, mode);
|
||||
await updateCodeIndex(code);
|
||||
Bus.instance.fire(CodesUpdatedEvent());
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ignorePin = widget.sortKey == null || widget.sortKey == CodeSortKey.manual;
|
||||
ignorePin = widget.sortKey != null && widget.sortKey == CodeSortKey.manual;
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
if (isMaskingEnabled != PreferenceService.instance.shouldHideCodes()) {
|
||||
isMaskingEnabled = PreferenceService.instance.shouldHideCodes();
|
||||
@ -645,7 +645,12 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
firstButtonLabel: l10n.delete,
|
||||
isCritical: true,
|
||||
firstButtonOnTap: () async {
|
||||
await CodeStore.instance.removeCode(widget.code);
|
||||
try {
|
||||
await CodeStore.instance.removeCode(widget.code);
|
||||
} catch (e,s) {
|
||||
logger.severe('Failed to delete code',e,s);
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
178
auth/lib/ui/components/banner_widget.dart
Normal file
@ -0,0 +1,178 @@
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:styled_text/tags/styled_text_tag.dart';
|
||||
import 'package:styled_text/widgets/styled_text.dart';
|
||||
|
||||
enum BannerType {
|
||||
rateUs,
|
||||
starUs,
|
||||
freeStorage,
|
||||
discount,
|
||||
}
|
||||
|
||||
class BannerWidget extends StatelessWidget {
|
||||
final String text;
|
||||
final String? subText;
|
||||
final BannerType type;
|
||||
final TextStyle? mainTextStyle;
|
||||
|
||||
const BannerWidget({
|
||||
super.key,
|
||||
required this.text,
|
||||
required this.type,
|
||||
this.subText,
|
||||
this.mainTextStyle,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isLightMode =
|
||||
MediaQuery.of(context).platformBrightness == Brightness.light;
|
||||
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
Color dashColor;
|
||||
List<BoxShadow>? boxShadow;
|
||||
String imagePath;
|
||||
|
||||
switch (type) {
|
||||
case BannerType.rateUs:
|
||||
imagePath = "assets/rate_us.png";
|
||||
dashColor = const Color.fromRGBO(255, 191, 12, 1);
|
||||
boxShadow = [
|
||||
BoxShadow(
|
||||
color: const Color(0xFFFDB816).withOpacity(0.1),
|
||||
blurRadius: 50,
|
||||
spreadRadius: 80,
|
||||
),
|
||||
BoxShadow(
|
||||
color: const Color(0xFFFDB816).withOpacity(0.2),
|
||||
blurRadius: 25,
|
||||
),
|
||||
];
|
||||
break;
|
||||
case BannerType.starUs:
|
||||
imagePath = "assets/star_us.png";
|
||||
dashColor = const Color.fromRGBO(233, 233, 233, 1);
|
||||
boxShadow = [
|
||||
BoxShadow(
|
||||
color: const Color.fromRGBO(78, 78, 78, 1).withOpacity(0.2),
|
||||
blurRadius: 50,
|
||||
spreadRadius: 100,
|
||||
),
|
||||
BoxShadow(
|
||||
color: const Color.fromRGBO(23, 22, 22, 0.30).withOpacity(0.1),
|
||||
blurRadius: 25,
|
||||
),
|
||||
];
|
||||
|
||||
case BannerType.freeStorage:
|
||||
imagePath = "assets/ente_5gb.png";
|
||||
dashColor = const Color.fromRGBO(29, 185, 84, 1);
|
||||
boxShadow = [
|
||||
BoxShadow(
|
||||
color: const Color.fromRGBO(38, 203, 95, 1).withOpacity(0.08),
|
||||
blurRadius: 50,
|
||||
spreadRadius: 100,
|
||||
),
|
||||
BoxShadow(
|
||||
color: const Color.fromRGBO(0, 0, 0, 0.50).withOpacity(0.08),
|
||||
blurRadius: 25,
|
||||
),
|
||||
];
|
||||
case BannerType.discount:
|
||||
dashColor = const Color.fromRGBO(29, 185, 84, 1);
|
||||
imagePath = "assets/discount.png";
|
||||
boxShadow = [
|
||||
BoxShadow(
|
||||
color: const Color.fromRGBO(38, 203, 95, 1).withOpacity(0.08),
|
||||
blurRadius: 50,
|
||||
spreadRadius: 100,
|
||||
),
|
||||
BoxShadow(
|
||||
color: const Color.fromRGBO(0, 0, 0, 0.50).withOpacity(0.08),
|
||||
blurRadius: 25,
|
||||
),
|
||||
];
|
||||
}
|
||||
return ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
||||
child: DottedBorder(
|
||||
borderType: BorderType.RRect,
|
||||
radius: const Radius.circular(50),
|
||||
dashPattern: const <double>[3, 3],
|
||||
color: dashColor,
|
||||
child: Stack(
|
||||
children: [
|
||||
if (BannerType.starUs == type)
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
||||
child: isLightMode
|
||||
? Image.asset("assets/calender_banner_light.png")
|
||||
: Image.asset("assets/calender_banner_dark.png"),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
if (!isLightMode)
|
||||
Container(
|
||||
height: 80,
|
||||
width: 80,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: boxShadow,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
width: 60,
|
||||
child: Image.asset(imagePath),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
StyledText(
|
||||
text: text,
|
||||
style: getEnteTextTheme(context).large,
|
||||
textAlign: TextAlign.left,
|
||||
tags: {
|
||||
'bold-green': StyledTextTag(
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: colorScheme.primaryGreen,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
subText ?? "",
|
||||
textAlign: TextAlign.left,
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -210,7 +210,7 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
Future<void> _onTap() async {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {return;}
|
||||
_debouncer.run(
|
||||
() => Future(
|
||||
() {
|
||||
@ -247,7 +247,7 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
void _onTapDown(details) {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {return;}
|
||||
setState(() {
|
||||
if (widget.pressedColor == null) {
|
||||
hasPassedGestureCallbacks()
|
||||
@ -265,7 +265,7 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
void _onTapUp(details) {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {return;}
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
() => setState(() {
|
||||
@ -276,7 +276,7 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
void _onCancel() {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {return;}
|
||||
setState(() {
|
||||
menuItemColor = widget.menuItemColor;
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/services/auth_feature_flag.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/ui/settings/data/import_page.dart';
|
||||
import 'package:ente_auth/utils/navigation_util.dart';
|
||||
@ -10,13 +9,11 @@ import 'package:logging/logging.dart';
|
||||
class HomeEmptyStateWidget extends StatelessWidget {
|
||||
final VoidCallback? onScanTap;
|
||||
final VoidCallback? onManuallySetupTap;
|
||||
final VoidCallback? onImportFromGallery;
|
||||
|
||||
const HomeEmptyStateWidget({
|
||||
super.key,
|
||||
required this.onScanTap,
|
||||
required this.onManuallySetupTap,
|
||||
this.onImportFromGallery,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -62,23 +59,6 @@ class HomeEmptyStateWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
if (PlatformUtil.isMobile() &&
|
||||
FeatureFlagService.instance
|
||||
.isInternalUserOrDebugBuild())
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onImportFromGallery,
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
),
|
||||
child: const Text(
|
||||
"Import from gallery",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
|
@ -14,7 +14,6 @@ import 'package:ente_auth/models/code.dart';
|
||||
import 'package:ente_auth/onboarding/model/tag_enums.dart';
|
||||
import 'package:ente_auth/onboarding/view/common/tag_chip.dart';
|
||||
import 'package:ente_auth/onboarding/view/setup_enter_secret_key_page.dart';
|
||||
import 'package:ente_auth/services/auth_feature_flag.dart';
|
||||
import 'package:ente_auth/services/preference_service.dart';
|
||||
import 'package:ente_auth/services/user_service.dart';
|
||||
import 'package:ente_auth/store/code_display_store.dart';
|
||||
@ -40,7 +39,6 @@ import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/lock_screen_settings.dart';
|
||||
import 'package:ente_auth/utils/platform_util.dart';
|
||||
import 'package:ente_auth/utils/totp_util.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@ -48,7 +46,6 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:move_to_background/move_to_background.dart';
|
||||
import 'package:scan/scan.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
@ -93,8 +90,8 @@ class _HomePageState extends State<HomePage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_textController.addListener(_applyFilteringAndRefresh);
|
||||
_codeSortKey = PreferenceService.instance.codeSortKey();
|
||||
_textController.addListener(_applyFilteringAndRefresh);
|
||||
_loadCodes();
|
||||
_streamSubscription = Bus.instance.on<CodesUpdatedEvent>().listen((event) {
|
||||
_loadCodes();
|
||||
@ -274,7 +271,6 @@ class _HomePageState extends State<HomePage> {
|
||||
);
|
||||
break;
|
||||
case CodeSortKey.manual:
|
||||
default:
|
||||
codes.sort((a, b) => a.display.position.compareTo(b.display.position));
|
||||
break;
|
||||
}
|
||||
@ -483,7 +479,6 @@ class _HomePageState extends State<HomePage> {
|
||||
return HomeEmptyStateWidget(
|
||||
onScanTap: _redirectToScannerPage,
|
||||
onManuallySetupTap: _redirectToManualEntryPage,
|
||||
onImportFromGallery: _importFromGallery,
|
||||
);
|
||||
} else {
|
||||
final anyCodeHasError =
|
||||
@ -585,7 +580,7 @@ class _HomePageState extends State<HomePage> {
|
||||
|
||||
return ClipRect(
|
||||
child: CodeWidget(
|
||||
key: ValueKey('${code.hashCode}_$newIndex'),
|
||||
key: ValueKey('${code.hashCode}_${newIndex}_$_codeSortKey'),
|
||||
code,
|
||||
isCompactMode: isCompactMode,
|
||||
sortKey: _codeSortKey,
|
||||
@ -621,6 +616,7 @@ class _HomePageState extends State<HomePage> {
|
||||
key: ValueKey('${codeState.hashCode}_$index'),
|
||||
codeState,
|
||||
isCompactMode: isCompactMode,
|
||||
sortKey: _codeSortKey,
|
||||
);
|
||||
}),
|
||||
itemCount: _filteredCodes.length,
|
||||
@ -671,16 +667,24 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int lastScanTime = DateTime.now().millisecondsSinceEpoch - 1000;
|
||||
void _handleDeeplink(BuildContext context, String? link) {
|
||||
if (!Configuration.instance.hasConfiguredAccount() || link == null) {
|
||||
bool isAccountConfigured = Configuration.instance.hasConfiguredAccount();
|
||||
bool isOfflineModeEnabled = Configuration.instance.hasOptedForOfflineMode() &&
|
||||
Configuration.instance.getOfflineSecretKey() != null;
|
||||
if (!(isAccountConfigured || isOfflineModeEnabled) || link == null) {
|
||||
return;
|
||||
}
|
||||
if (DateTime.now().millisecondsSinceEpoch - lastScanTime < 1000) {
|
||||
_logger.info("Ignoring potential event for same deeplink");
|
||||
return;
|
||||
}
|
||||
lastScanTime = DateTime.now().millisecondsSinceEpoch;
|
||||
if (mounted && link.toLowerCase().startsWith("otpauth://")) {
|
||||
try {
|
||||
final newCode = Code.fromOTPAuthUrl(link);
|
||||
getNextTotp(newCode);
|
||||
CodeStore.instance.addCode(newCode);
|
||||
CodeStore.instance.addCode(newCode, shouldSync: false);
|
||||
_focusNewCode(newCode);
|
||||
} catch (e, s) {
|
||||
showGenericErrorDialog(
|
||||
@ -699,29 +703,6 @@ class _HomePageState extends State<HomePage> {
|
||||
_applyFilteringAndRefresh();
|
||||
}
|
||||
|
||||
Future<void> _importFromGallery() async {
|
||||
try {
|
||||
final FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.image,
|
||||
allowMultiple: false,
|
||||
);
|
||||
if (result != null) {
|
||||
final path = result.files.single.path!;
|
||||
String? res = await Scan.parse(path);
|
||||
final Code? code = res != null ? Code.fromOTPAuthUrl(res) : null;
|
||||
if (code != null) {
|
||||
await CodeStore.instance.addCode(code);
|
||||
if ((_allCodes?.where((e) => !e.hasError).length ?? 0) > 2) {
|
||||
_focusNewCode(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e, s) {
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
_logger.severe("Error while importing from gallery", e, s);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _getFab() {
|
||||
if (PlatformUtil.isDesktop()) {
|
||||
return FloatingActionButton(
|
||||
@ -752,15 +733,6 @@ class _HomePageState extends State<HomePage> {
|
||||
labelWidget: SpeedDialLabelWidget(context.l10n.scanAQrCode),
|
||||
onTap: _redirectToScannerPage,
|
||||
),
|
||||
if (PlatformUtil.isMobile() &&
|
||||
FeatureFlagService.instance.isInternalUserOrDebugBuild())
|
||||
SpeedDialChild(
|
||||
child: const Icon(Icons.image),
|
||||
foregroundColor: Theme.of(context).colorScheme.fabForegroundColor,
|
||||
backgroundColor: Theme.of(context).colorScheme.fabBackgroundColor,
|
||||
labelWidget: const SpeedDialLabelWidget("Import from gallery"),
|
||||
onTap: _importFromGallery,
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: const Icon(Icons.keyboard),
|
||||
foregroundColor: Theme.of(context).colorScheme.fabForegroundColor,
|
||||
|
@ -90,7 +90,6 @@ class LockScreenSettings {
|
||||
: await PrivacyScreen.instance.enable(
|
||||
iosOptions: const PrivacyIosOptions(
|
||||
enablePrivacy: true,
|
||||
privacyImageName: 'LaunchImage',
|
||||
),
|
||||
androidOptions: const PrivacyAndroidOptions(
|
||||
enableSecure: true,
|
||||
|
@ -27,6 +27,8 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- rive_common (0.0.1):
|
||||
- FlutterMacOS
|
||||
- screen_retriever (0.0.1):
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (8.36.0)
|
||||
@ -82,6 +84,7 @@ DEPENDENCIES:
|
||||
- local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`)
|
||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- rive_common (from `Flutter/ephemeral/.symlinks/plugins/rive_common/macos`)
|
||||
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
|
||||
- sentry_flutter (from `Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos`)
|
||||
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
|
||||
@ -124,6 +127,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
|
||||
path_provider_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||
rive_common:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/rive_common/macos
|
||||
screen_retriever:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
|
||||
sentry_flutter:
|
||||
@ -159,6 +164,7 @@ SPEC CHECKSUMS:
|
||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
rive_common: 9580b9f1f08a8c85006083078e80479edf3db26a
|
||||
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
|
||||
Sentry: f8374b5415bc38dfb5645941b3ae31230fbeae57
|
||||
sentry_flutter: 0eb93e5279eb41e2392212afe1ccd2fecb4f8cbe
|
||||
|
@ -5,15 +5,15 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "72.0.0"
|
||||
version: "76.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
version: "0.3.3"
|
||||
adaptive_theme:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -26,10 +26,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.7.0"
|
||||
version: "6.11.0"
|
||||
ansicolor:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -250,10 +250,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
version: "1.19.0"
|
||||
confetti:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -387,7 +387,7 @@ packages:
|
||||
description:
|
||||
path: "."
|
||||
ref: HEAD
|
||||
resolved-ref: e2e66ffd03f23bef5e0bb138b5f01b32d8e9b7bb
|
||||
resolved-ref: f91e1545f8263df127762240c4da54a0c42835b2
|
||||
url: "https://github.com/ente-io/ente_crypto_dart.git"
|
||||
source: git
|
||||
version: "1.0.0"
|
||||
@ -434,11 +434,12 @@ packages:
|
||||
figma_squircle:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: figma_squircle
|
||||
sha256: "790b91a9505e90d246f6efe2fa065ff7fffe658c7b44fe9b5b20c7b0ad3818c0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.3"
|
||||
path: "."
|
||||
ref: HEAD
|
||||
resolved-ref: "5f1ad5aaccdf31fc398fc141979ea845a0f45383"
|
||||
url: "https://github.com/Ax0elz/figma_squircle.git"
|
||||
source: git
|
||||
version: "0.5.5"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -913,18 +914,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.5"
|
||||
version: "10.0.7"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.8"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -993,10 +994,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
version: "0.1.3-main.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1301,14 +1302,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
scan:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: scan
|
||||
sha256: b343ec36f863a88d41eb4c174b810c055c6bd1f1822b2188ab31aab684fb7cdb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
screen_retriever:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1433,7 +1426,7 @@ packages:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
version: "0.0.0"
|
||||
sodium:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1527,10 +1520,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
version: "1.12.0"
|
||||
steam_totp:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1567,10 +1560,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
styled_text:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1599,10 +1592,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
version: "0.7.3"
|
||||
timezone:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1767,10 +1760,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
version: "14.3.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 4.2.8+428
|
||||
version: 4.3.1+431
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@ -32,7 +32,9 @@ dependencies:
|
||||
expandable: ^5.0.1
|
||||
expansion_tile_card: ^3.0.0
|
||||
ffi: ^2.1.0
|
||||
figma_squircle: ^0.5.3
|
||||
figma_squircle:
|
||||
git:
|
||||
url: https://github.com/Ax0elz/figma_squircle.git
|
||||
file_picker: ^8.1.7
|
||||
# https://github.com/incrediblezayed/file_saver/issues/86
|
||||
file_saver: ^0.2.11
|
||||
@ -82,8 +84,7 @@ dependencies:
|
||||
privacy_screen: ^0.0.6
|
||||
protobuf: ^3.0.0
|
||||
qr_code_scanner: ^1.0.1
|
||||
qr_flutter: ^4.1.0
|
||||
scan: ^1.6.0
|
||||
qr_flutter: ^4.1.0
|
||||
sentry: ^8.7.0
|
||||
sentry_flutter: ^8.7.0
|
||||
share_plus: ^10.0.2
|
||||
|
@ -65,7 +65,7 @@ type AlbumFileEntry struct {
|
||||
func SortAlbumFileEntry(entries []*AlbumFileEntry) {
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
if entries[i].IsDeleted != entries[j].IsDeleted {
|
||||
return !entries[i].IsDeleted && entries[j].IsDeleted
|
||||
return entries[i].IsDeleted && !entries[j].IsDeleted
|
||||
}
|
||||
return entries[i].AlbumID < entries[j].AlbumID
|
||||
})
|
||||
|
3
desktop/.gitignore
vendored
@ -20,3 +20,6 @@ out
|
||||
|
||||
# electron-builder
|
||||
dist/
|
||||
|
||||
# We download it on demand, if needed for the particular OS/arch.
|
||||
build/magick*
|
||||
|
@ -32,13 +32,14 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
<branding>
|
||||
<color type="primary" scheme_preference="light">#1db954</color>
|
||||
<color type="primary" scheme_preference="dark">#1db954</color>
|
||||
</branding>
|
||||
|
||||
<releases>
|
||||
<release version="1.7.8" date="2025-01-13">
|
||||
<description>
|
||||
<ul>
|
||||
<li>Parse description from image metadata.</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url type="details">https://github.com/ente-io/photos-desktop/releases/tag/v1.7.8</url>
|
||||
</release>
|
||||
</releases>
|
||||
</component>
|
||||
|
@ -103,7 +103,7 @@ Some extra ones specific to the code here are:
|
||||
|
||||
### Format conversion
|
||||
|
||||
The main tool we use is for arbitrary conversions is ffmpeg. To bundle a
|
||||
For video conversions and metadata extraction, we use ffmpeg. To bundle a
|
||||
(platform specific) static binary of ffmpeg with our app, we use
|
||||
[ffmpeg-static](https://github.com/eugeneware/ffmpeg-static).
|
||||
|
||||
@ -111,10 +111,12 @@ The main tool we use is for arbitrary conversions is ffmpeg. To bundle a
|
||||
> ffmpeg binary and using the wasm one (that our renderer process already has).
|
||||
> Which is why we bundle it to speed up operations on the desktop app.
|
||||
|
||||
In addition, we also bundle a static Linux binary of imagemagick in our extra
|
||||
resources (`build`) folder. This is used for thumbnail generation on Linux.
|
||||
On Linux and Windows, we use ImageMagick for thumbnail generation and JPEG
|
||||
conversion of unpreviewable images. A static OS/architecture specific binary of
|
||||
this is bundled in our extra resources (`build`) folder by `scripts/magick.sh`
|
||||
and/or `scripts/beforeBuild.js`. See "[Note: ImageMagick]" for more details.
|
||||
|
||||
On macOS, we use the `sips` CLI tool for conversion, but that is already
|
||||
On macOS, we use the `sips` CLI tool for these tasks, but that is already
|
||||
available on the host machine, and is not bundled with our app.
|
||||
|
||||
### ML
|
||||
|
@ -6,6 +6,7 @@ files:
|
||||
extraFiles:
|
||||
- from: build
|
||||
to: resources
|
||||
beforeBuild: scripts/beforeBuild.js
|
||||
protocols:
|
||||
- name: Ente
|
||||
schemes: ["ente"]
|
||||
@ -33,3 +34,4 @@ mac:
|
||||
arch: [universal]
|
||||
category: public.app-category.photography
|
||||
hardenedRuntime: true
|
||||
mergeASARs: false
|
||||
|
@ -19,7 +19,7 @@ export default ts.config(
|
||||
{
|
||||
// The list of (minimatch) globs to ignore. This needs to be the only
|
||||
// key in this configuration object.
|
||||
ignores: ["eslint.config.mjs", "app/", "out/", "dist/"],
|
||||
ignores: ["eslint.config.mjs", "scripts/*.js", "app/", "out/", "dist/"],
|
||||
},
|
||||
{
|
||||
// Rule customizations.
|
||||
|
@ -8,17 +8,18 @@
|
||||
"main": "app/main.js",
|
||||
"scripts": {
|
||||
"build": "yarn build-renderer && yarn build-main",
|
||||
"build-main": "tsc && electron-builder",
|
||||
"build-main:quick": "tsc && electron-builder --dir --config.compression=store --config.mac.identity=null",
|
||||
"build-renderer": "cross-env-shell _ENTE_IS_DESKTOP=1 \"cd ../web && yarn install && yarn build:photos && cd ../desktop && shx rm -f out && shx ln -sf ../web/apps/photos/out out\"",
|
||||
"build:ci": "yarn build-renderer && tsc",
|
||||
"build:quick": "yarn build-renderer && yarn build-main:quick",
|
||||
"build-main": "tsc && electron-builder",
|
||||
"build-main:quick": "tsc && electron-builder --dir --config.compression=store --config.mac.identity=null",
|
||||
"build-renderer": "cross-env-shell _ENTE_IS_DESKTOP=1 \"cd ../web && yarn install && yarn build:photos && cd ../desktop && shx rm -rf out && shx cp -r ../web/apps/photos/out out\"",
|
||||
"dev": "concurrently --kill-others --success first --names 'main,rndr' \"yarn dev-main\" \"yarn dev-renderer\"",
|
||||
"dev-main": "tsc && electron .",
|
||||
"dev-renderer": "cross-env-shell _ENTE_IS_DESKTOP=1 \"cd ../web && yarn install && yarn workspace photos next dev -p 3008\"",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"lint": "yarn prettier --check --log-level warn . && yarn eslint && yarn tsc",
|
||||
"lint-fix": "yarn prettier --write --log-level warn . && yarn eslint && yarn tsc"
|
||||
"lint-fix": "yarn prettier --write --log-level warn . && yarn eslint && yarn tsc",
|
||||
"prepare": "node scripts/magick.js"
|
||||
},
|
||||
"resolutions": {
|
||||
"jackspeak": "2.1.1"
|
||||
@ -32,7 +33,7 @@
|
||||
"compare-versions": "^6.1.1",
|
||||
"electron-log": "^5.2.4",
|
||||
"electron-store": "^8.2.0",
|
||||
"electron-updater": "^6.3.9",
|
||||
"electron-updater": "^6.4.0-alpha.3",
|
||||
"ffmpeg-static": "^5.2.0",
|
||||
"lru-cache": "^11.0.2",
|
||||
"next-electron-server": "^1.0.0",
|
||||
@ -40,23 +41,23 @@
|
||||
"onnxruntime-node": "^1.20.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.17.0",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/auto-launch": "^5.0.5",
|
||||
"@types/eslint__js": "^8.42.3",
|
||||
"@types/ffmpeg-static": "^3.0.3",
|
||||
"ajv": "^8.17.1",
|
||||
"concurrently": "^9.1.1",
|
||||
"concurrently": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "^33.2.1",
|
||||
"electron-builder": "^25.1.8",
|
||||
"electron": "^34.0.0",
|
||||
"electron-builder": "^26.0.0-alpha.10",
|
||||
"eslint": "^9",
|
||||
"prettier": "3.4.2",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"prettier-plugin-packagejson": "^2.5.6",
|
||||
"prettier-plugin-packagejson": "^2.5.8",
|
||||
"shx": "^0.3.4",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.18.2"
|
||||
"typescript-eslint": "^8.21.0"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"productName": "ente"
|
||||
|
64
desktop/scripts/beforeBuild.js
Executable file
@ -0,0 +1,64 @@
|
||||
const fsp = require("fs/promises");
|
||||
|
||||
/**
|
||||
* This hook is invoked during the initial build (e.g. when triggered by "yarn
|
||||
* build"), and importantly, on each rebuild for a different architecture during
|
||||
* the build. We use it to ensure that the magick binary is for the current
|
||||
* architecture being built. See "[Note: ImageMagick]" for more details.
|
||||
*
|
||||
* The documentation for this hook is at:
|
||||
* https://www.electron.build/app-builder-lib.interface.configuration#beforebuild
|
||||
*
|
||||
* > The function to be run before dependencies are installed or rebuilt.
|
||||
*
|
||||
* Here is an example of the context that it gets
|
||||
* https://www.electron.build/app-builder-lib.interface.beforebuildcontext
|
||||
*
|
||||
* appDir: '/path/to/ente/desktop',
|
||||
* platform: Platform {
|
||||
* name: 'mac',
|
||||
* buildConfigurationKey: 'mac',
|
||||
* nodeName: 'darwin'
|
||||
* },
|
||||
* arch: 'arm64'
|
||||
*
|
||||
* Note that we must not return falsey from this function, because
|
||||
* > Resolving to false will skip dependencies install or rebuild.
|
||||
*/
|
||||
module.exports = async (context) => {
|
||||
const { appDir, platform, arch } = context;
|
||||
|
||||
// The arch used by Electron Builder is not the same as the arch used by
|
||||
// Node's process, but for the two cases that we care about, "x64" and
|
||||
// "arm64", both of them use the string constant and thus can be compared.
|
||||
//
|
||||
// https://github.com/electron-userland/electron-builder/blob/master/packages/builder-util/src/arch.ts#L9
|
||||
// https://nodejs.org/api/process.html#processarch
|
||||
if (arch == process.arch) {
|
||||
// `magick.js` would've already downloaded the file, nothing to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
const download = async (downloadName, outputName) => {
|
||||
const out = `${appDir}/build/${outputName}`;
|
||||
console.log(`Downloading ${downloadName}`);
|
||||
const downloadPath = `https://github.com/ente-io/ImageMagick/releases/download/2025-01-21/${downloadName}`;
|
||||
return fetch(downloadPath)
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => fsp.writeFile(out, blob.stream()))
|
||||
.then(() => fsp.chmod(out, "744"));
|
||||
};
|
||||
|
||||
switch (`${platform.nodeName}-${arch}`) {
|
||||
case "linux-x64":
|
||||
await download("magick-x86_64", "magick");
|
||||
case "linux-arm64":
|
||||
await download("magick-aarch64", "magick");
|
||||
case "win32-x64":
|
||||
await download("magick-x64.exe", "magick.exe");
|
||||
case "linux-arm64":
|
||||
await download("magick-arm64.exe", "magick.exe");
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
78
desktop/scripts/magick.js
Executable file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* [Note: ImageMagick]
|
||||
*
|
||||
* We need static builds for Linux and Windows for both x64 and ARM. For this,
|
||||
* we need a custom workflow because (as of writing):
|
||||
*
|
||||
* 1. Upstream doesn't publish ARM64 binaries for Linux
|
||||
*
|
||||
* 2. The Windows portable releases are not part of the artifacts attached to
|
||||
* the upstream GitHub release.
|
||||
*
|
||||
* Our custom workflow is an adaption of the upstream release.yml - its goal is
|
||||
* to have 4 standalone binaries - Linux x64, Linux ARM, Win x64, Win ARM -
|
||||
* attached to a GitHub release from which we can pull them when building the
|
||||
* desktop app.
|
||||
*
|
||||
* This is our custom workflow, which runs on a fork of upstream:
|
||||
* https://github.com/ente-io/ImageMagick/commit/df895cce13d6a3f874a716c05ff2babeb33351b9
|
||||
* (For reference, we also include a copy of it in this repo - `magick.yml`).
|
||||
*
|
||||
* The binaries it creates are available at
|
||||
* https://github.com/ente-io/ImageMagick/releases/tag/2025-01-21.
|
||||
*
|
||||
* To integrate this ImageMagick binary, we need to modify two places:
|
||||
*
|
||||
* 1. This script, `magick.js`, runs during "yarn install" (it is set as the
|
||||
* "prepare" step in our `package.json`). It downloads the relevant binary
|
||||
* for the current OS/arch combination and places it in the `build` folder,
|
||||
* allowing it to be used during development.
|
||||
*
|
||||
* 2. The sibling script, `beforeBuild.js`, runs during "yarn build" (it is set
|
||||
* as the beforeBuild script in `electrons-builder.yml`). It downloads the
|
||||
* relevant binary for the OS/arch combination being built.
|
||||
*
|
||||
* Note that `magick.js` would've already run once `beforeBuild.js` is run, but
|
||||
* on our CI we prepare builds for multiple architectures in one go, so we need
|
||||
* to unconditonally replace the binary with the relevant one for the current
|
||||
* architecture being built (which might be different from the one we're running
|
||||
* on). `beforeBuild.js` runs for each architecture being built.
|
||||
*
|
||||
* On macOS, we don't need ImageMagick since there we use the native `sips`.
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const fsp = require("fs/promises");
|
||||
|
||||
const main = () => {
|
||||
switch (`${process.platform}-${process.arch}`) {
|
||||
case "linux-x64":
|
||||
return downloadIfNeeded("magick-x86_64", "magick");
|
||||
case "linux-arm64":
|
||||
return downloadIfNeeded("magick-aarch64", "magick");
|
||||
case "win32-x64":
|
||||
return downloadIfNeeded("magick-x64.exe", "magick.exe");
|
||||
case "linux-arm64":
|
||||
return downloadIfNeeded("magick-arm64.exe", "magick.exe");
|
||||
}
|
||||
};
|
||||
|
||||
const downloadIfNeeded = (downloadName, outputName) => {
|
||||
const out = `build/${outputName}`;
|
||||
|
||||
try {
|
||||
// Making the file executable is the last step, so if the file exists at
|
||||
// this path and is executable, we assume it is the correct one.
|
||||
fs.accessSync(out, fs.constants.X_OK);
|
||||
return;
|
||||
} catch {}
|
||||
|
||||
console.log(`Downloading ${downloadName}`);
|
||||
const downloadPath = `https://github.com/ente-io/ImageMagick/releases/download/2025-01-21/${downloadName}`;
|
||||
return fetch(downloadPath)
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => fsp.writeFile(out, blob.stream()))
|
||||
.then(() => fsp.chmod(out, "744"));
|
||||
};
|
||||
|
||||
main();
|
127
desktop/scripts/magick.yml
Normal file
@ -0,0 +1,127 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push: # Push a tag to build and create a draft release
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
name: binaries-for-ente
|
||||
jobs:
|
||||
create_magick_binary:
|
||||
name: Create magick binary (Linux)
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
||||
compiler: [gcc]
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: aarch64
|
||||
- compiler: gcc
|
||||
cxx_compiler: g++
|
||||
packages: gcc g++
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt update -y
|
||||
sudo apt install -y autoconf curl fuse git kmod libbz2-dev libdjvulibre-dev libfontconfig-dev libfreetype6-dev libfribidi-dev libharfbuzz-dev liblcms-dev libopenexr-dev libopenjp2-7-dev libturbojpeg0-dev liblqr-dev libraqm-dev libtiff-dev libwebp-dev libx11-dev libxml2-dev liblzma-dev make software-properties-common wget ${{ matrix.packages }}
|
||||
sudo add-apt-repository ppa:git-core/ppa -y
|
||||
sudo apt install -y git
|
||||
sudo add-apt-repository ppa:strukturag/libheif -y
|
||||
sudo add-apt-repository ppa:strukturag/libde265 -y
|
||||
sudo apt install libheif-dev -y
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Avoid fatal: detected dubious ownership in repository at '/__w/ImageMagick/ImageMagick'
|
||||
# Possible workaround: https://github.com/actions/runner/issues/2033#issuecomment-1598547465
|
||||
- name: Flag current workspace as safe for git
|
||||
run: git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: Download AppImage
|
||||
run: |
|
||||
set -e
|
||||
sudo apt install -y file
|
||||
mkdir -p out/app-image
|
||||
cd out/app-image
|
||||
wget -c https://github.com/$(wget -q https://github.com/probonopd/go-appimage/releases/expanded_assets/continuous -O - | grep "appimagetool-.*-${{ matrix.arch }}.AppImage" | head -n 1 | cut -d '"' -f 2)
|
||||
chmod +x appimagetool-*.AppImage
|
||||
|
||||
- name: Build ImageMagick
|
||||
env:
|
||||
CFLAGS:
|
||||
-Wno-deprecated-declarations -Wdeclaration-after-statement
|
||||
-Wno-error=unused-variable
|
||||
CC: ${{ matrix.compiler }}
|
||||
CXX: ${{ matrix.cxx_compiler }}
|
||||
run: |
|
||||
set -e
|
||||
./configure --with-quantum-depth=16 --without-magick-plus-plus --without-perl --without-x --disable-docs --prefix=/usr
|
||||
make
|
||||
make install DESTDIR=$(readlink -f out/appdir)
|
||||
|
||||
- name: Create ImageMagick AppImage
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p out/appdir/usr/share/applications/
|
||||
cp app-image/imagemagick.desktop out/appdir/usr/share/applications/
|
||||
mkdir -p out/appdir/usr/share/icons/hicolor/256x256/apps/
|
||||
cp app-image/icon.png out/appdir/usr/share/icons/hicolor/256x256/apps/imagemagick.png
|
||||
unset QTDIR
|
||||
unset QT_PLUGIN_PATH
|
||||
unset LD_LIBRARY_PATH
|
||||
export VERSION=7
|
||||
cd out
|
||||
./app-image/appimagetool-*.AppImage --appimage-extract-and-run -s deploy appdir/usr/share/applications/*.desktop
|
||||
chmod +x appdir/usr/lib/ld-linux-aarch64.so.1 || true
|
||||
./app-image/appimagetool-*.AppImage --appimage-extract-and-run appdir
|
||||
mkdir artifacts
|
||||
cp ImageMagick*.AppImage artifacts/magick-${{ matrix.arch }}
|
||||
|
||||
- name: Upload ImageMagick AppImage
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: magick-${{ matrix.arch }}
|
||||
path: out/artifacts
|
||||
|
||||
- name: Create a draft GitHub release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "out/artifacts/*"
|
||||
draft: true
|
||||
allowUpdates: true
|
||||
updateOnlyUnreleased: true
|
||||
|
||||
download_and_keep_windows_binaries:
|
||||
name: Download magick binary (Windows)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Download
|
||||
run: |
|
||||
mkdir -p out/artifacts
|
||||
curl -LO https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-43-portable-Q16-x64.zip
|
||||
unzip ImageMagick-7.1.1-43-portable-Q16-x64.zip
|
||||
cp ImageMagick-7.1.1-43-portable-Q16-x64/magick.exe out/artifacts/magick-x64.exe
|
||||
curl -LO https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-43-portable-Q16-arm64.zip
|
||||
unzip ImageMagick-7.1.1-43-portable-Q16-arm64.zip
|
||||
cp ImageMagick-7.1.1-43-portable-Q16-arm64/magick.exe out/artifacts/magick-arm64.exe
|
||||
|
||||
- name: Upload ImageMagick exes
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: magick-${{ matrix.arch }}
|
||||
path: out/artifacts
|
||||
|
||||
- name: Create a draft GitHub release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "out/artifacts/*"
|
||||
draft: true
|
||||
allowUpdates: true
|
||||
updateOnlyUnreleased: true
|
2
desktop/scripts/vips/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
1.heic
|
||||
1.jpeg
|
18
desktop/scripts/vips/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
# https://github.com/libvips/libvips/blob/master/.github/workflows/ci.yml
|
||||
RUN apt-get update -y && apt-get install -y \
|
||||
meson pkg-config \
|
||||
libarchive-dev libcfitsio-dev libcgif-dev \
|
||||
libexif-dev libexpat1-dev libffi-dev \
|
||||
libfftw3-dev libheif-dev libheif-plugin-aomenc \
|
||||
libheif-plugin-x265 libhwy-dev libimagequant-dev \
|
||||
libjpeg-dev libjxl-dev liblcms2-dev \
|
||||
libmatio-dev libnifti-dev libopenexr-dev \
|
||||
libopenjp2-7-dev libopenslide-dev libpango1.0-dev \
|
||||
libpng-dev libpoppler-glib-dev librsvg2-dev \
|
||||
libtiff5-dev libwebp-dev
|
||||
|
||||
RUN apt-get install -y git && git clone --depth 1 https://github.com/libvips/libvips
|
||||
|
||||
WORKDIR /libvips
|
74
desktop/scripts/vips/Dockerfile.staticx
Normal file
@ -0,0 +1,74 @@
|
||||
FROM debian:bullseye
|
||||
|
||||
# Don't care about layer size.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
gcc-10 \
|
||||
make \
|
||||
pkg-config
|
||||
|
||||
# Don't care about layer size.
|
||||
RUN apt-get install -y --no-install-recommends \
|
||||
python3-minimal \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
patchelf
|
||||
|
||||
RUN python3 -m pip \
|
||||
--disable-pip-version-check \
|
||||
--no-cache-dir \
|
||||
install \
|
||||
'staticx==0.12.0'
|
||||
|
||||
# Don't care about layer caching, because I'm only using docker for building.
|
||||
RUN apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
g++ \
|
||||
g++-10 \
|
||||
libglib2.0-dev \
|
||||
libexpat1-dev \
|
||||
libjpeg-dev \
|
||||
libpng-dev \
|
||||
libimagequant-dev \
|
||||
libexif-dev \
|
||||
liborc-0.4-dev \
|
||||
&& rm -rf /var/lib/apt/lists
|
||||
|
||||
# TODO: Vendored source to remove test/ and doc/ with patches to remove test/ from configure.
|
||||
# This would also remove the need to install ca-certificates + curl.
|
||||
|
||||
# TODO: libspng build with meson, miniz to replace libpng-dev.
|
||||
# https://github.com/randy408/libspng/blob/master/docs/build.md#meson
|
||||
# Then, publish the final image somewhere.
|
||||
|
||||
WORKDIR /build
|
||||
RUN curl -sL https://github.com/libvips/libvips/releases/download/v8.10.1/vips-8.10.1.tar.gz | \
|
||||
tar -xz -f- --strip-components=1
|
||||
|
||||
# XXX: -static doesn't work here. I'm using staticx to make the final vips binary static.
|
||||
# Could also try clang.
|
||||
# TODO: webp support
|
||||
RUN CFLAGS="-O2 -flto -pipe" CXXFLAGS="-O2 -flto -pipe" \
|
||||
./configure \
|
||||
--disable-deprecated \
|
||||
--disable-shared \
|
||||
--disable-static \
|
||||
--disable-dependency-tracking \
|
||||
--disable-gtk-doc
|
||||
|
||||
# This is the fastest easiest way I found to compile the
|
||||
# CLI as fast as possible. You can probably get more optimal,
|
||||
# but it'd be a lot harder wrestling autotools.
|
||||
RUN cd libvips \
|
||||
&& make -j"$(nproc)"
|
||||
|
||||
RUN cd tools \
|
||||
&& make -j"$(nproc)" vips
|
||||
|
||||
RUN cd tools \
|
||||
&& staticx vips /bin/vips \
|
||||
&& strip -s /bin/vips
|
||||
|
||||
ENTRYPOINT ["/bin/vips"]
|
||||
CMD ["--help"]
|
38
desktop/scripts/vips/Dockerfile.vips-mini
Normal file
@ -0,0 +1,38 @@
|
||||
FROM --platform=linux/arm64/v8 alpine:3.18
|
||||
|
||||
ARG VIPS_VERSION=8.14.5
|
||||
ARG ALPINE_VERSION=3.18
|
||||
|
||||
# Environment variables
|
||||
ENV VIPS_HOME=/usr/local/vips-${VIPS_VERSION}
|
||||
ENV VIPS_BLOCK_UNTRUSTED=true \
|
||||
LD_LIBRARY_PATH=$VIPS_HOME/lib \
|
||||
PKG_CONFIG_PATH=$VIPS_HOME/lib/pkgconfig \
|
||||
PATH=$PATH:$VIPS_HOME/bin \
|
||||
WORKDIR=/usr/local/src
|
||||
|
||||
WORKDIR $WORKDIR
|
||||
|
||||
RUN apk add xz \
|
||||
&& wget https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.xz \
|
||||
&& tar -xf vips-${VIPS_VERSION}.tar.xz \
|
||||
&& cd vips-${VIPS_VERSION} \
|
||||
&& apk add \
|
||||
meson \
|
||||
build-base \
|
||||
vips-dev \
|
||||
fftw-dev \
|
||||
glib-dev \
|
||||
expat-dev expat \
|
||||
libjpeg-turbo-dev \
|
||||
libheif-dev \
|
||||
libspng-dev \
|
||||
curl
|
||||
|
||||
RUN APK add curl-dev
|
||||
RUN meson configure -Dintrospection=false -Dmodules=disabled -Dexamples=false -Dheif=disabled -Djpeg=disabled -Dopenjpeg=disabled -Ddeprecated=false -Dcplusplus=false --default-library=static --prefer-static --buildtype release
|
||||
|
||||
# RUN meson setup build-dir -Dintrospection=false -Dmodules=disabled -Dexamples=false --prefer-static --buildtype release \
|
||||
# && cd build-dir \
|
||||
# && meson compile \
|
||||
# && meson install
|
6
desktop/scripts/vips/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
Experimenting with libvips.
|
||||
|
||||
```sh
|
||||
docker build -t vips-test .
|
||||
docker run -it --rm -v $(pwd):/w vips-test vips copy /w/1.heic /w/1.jpeg
|
||||
```
|
@ -2,7 +2,7 @@
|
||||
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { CustomErrorMessage, type ZipItem } from "../../types/ipc";
|
||||
import { type ZipItem } from "../../types/ipc";
|
||||
import { execAsync, isDev } from "../utils/electron";
|
||||
import {
|
||||
deleteTempFileIgnoringErrors,
|
||||
@ -44,25 +44,29 @@ const convertToJPEGCommand = (
|
||||
];
|
||||
|
||||
case "linux":
|
||||
// The bundled binary is an ELF x86-64 executable.
|
||||
if (process.arch != "x64")
|
||||
throw new Error(CustomErrorMessage.NotAvailable);
|
||||
case "win32":
|
||||
return [
|
||||
imageMagickPath(),
|
||||
"convert",
|
||||
inputFilePath,
|
||||
"-quality",
|
||||
"100%",
|
||||
outputFilePath,
|
||||
];
|
||||
|
||||
default: // "win32"
|
||||
throw new Error(CustomErrorMessage.NotAvailable);
|
||||
default:
|
||||
throw new Error("Not available on the current OS/arch");
|
||||
}
|
||||
};
|
||||
|
||||
/** Path to the Linux image-magick executable bundled with our app */
|
||||
/**
|
||||
* Path to the magick executable bundled with our app on Linux and Windows.
|
||||
*/
|
||||
const imageMagickPath = () =>
|
||||
path.join(isDev ? "build" : process.resourcesPath, "image-magick");
|
||||
path.join(
|
||||
isDev ? "build" : process.resourcesPath,
|
||||
process.platform == "win32" ? "magick.exe" : "magick",
|
||||
);
|
||||
|
||||
export const generateImageThumbnail = async (
|
||||
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
|
||||
@ -133,14 +137,13 @@ const generateImageThumbnailCommand = (
|
||||
];
|
||||
|
||||
case "linux":
|
||||
// The bundled binary is an ELF x86-64 executable.
|
||||
if (process.arch != "x64")
|
||||
throw new Error(CustomErrorMessage.NotAvailable);
|
||||
case "win32":
|
||||
return [
|
||||
imageMagickPath(),
|
||||
"convert",
|
||||
inputFilePath,
|
||||
"-define",
|
||||
`jpeg:size=${2 * maxDimension}x${2 * maxDimension}`,
|
||||
inputFilePath,
|
||||
"-auto-orient",
|
||||
"-thumbnail",
|
||||
`${maxDimension}x${maxDimension}`,
|
||||
@ -151,7 +154,7 @@ const generateImageThumbnailCommand = (
|
||||
outputFilePath,
|
||||
];
|
||||
|
||||
default: // "win32"
|
||||
throw new Error(CustomErrorMessage.NotAvailable);
|
||||
default:
|
||||
throw new Error("Not available on the current OS/arch");
|
||||
}
|
||||
};
|
||||
|
@ -56,6 +56,8 @@ export const execAsync = async (command: string | string[]) => {
|
||||
const startTime = Date.now();
|
||||
const result = await execAsync_(escapedCommand);
|
||||
log.debug(() => `${escapedCommand} (${Date.now() - startTime} ms)`);
|
||||
// TODO(MR): Temp for debugging in nightlies; Remove before release.
|
||||
log.info(`${escapedCommand} (${Date.now() - startTime} ms)`);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
@ -32,13 +32,3 @@ export interface PendingUploads {
|
||||
filePaths: string[];
|
||||
zipItems: ZipItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* See: [Note: Custom errors across Electron/Renderer boundary]
|
||||
*
|
||||
* Note: this is not a type, and cannot be used in preload.js; it is only meant
|
||||
* for use in the main process code.
|
||||
*/
|
||||
export const CustomErrorMessage = {
|
||||
NotAvailable: "This feature in not available on the current OS/arch",
|
||||
};
|
||||
|
@ -25,6 +25,15 @@
|
||||
ajv "^6.12.0"
|
||||
ajv-keywords "^3.4.1"
|
||||
|
||||
"@electron/asar@3.2.18":
|
||||
version "3.2.18"
|
||||
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.18.tgz#fa607f829209bab8b9e0ce6658d3fe81b2cba517"
|
||||
integrity sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==
|
||||
dependencies:
|
||||
commander "^5.0.0"
|
||||
glob "^7.1.6"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
"@electron/asar@^3.2.7":
|
||||
version "3.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.10.tgz#615cf346b734b23cafa4e0603551010bd0e50aa8"
|
||||
@ -34,6 +43,15 @@
|
||||
glob "^7.1.6"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
"@electron/fuses@^1.8.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@electron/fuses/-/fuses-1.8.0.tgz#ad34d3cc4703b1258b83f6989917052cfc1490a0"
|
||||
integrity sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==
|
||||
dependencies:
|
||||
chalk "^4.1.1"
|
||||
fs-extra "^9.0.1"
|
||||
minimist "^1.2.5"
|
||||
|
||||
"@electron/get@^2.0.0":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@electron/get/-/get-2.0.3.tgz#fba552683d387aebd9f3fcadbcafc8e12ee4f960"
|
||||
@ -49,6 +67,21 @@
|
||||
optionalDependencies:
|
||||
global-agent "^3.0.0"
|
||||
|
||||
"@electron/node-gyp@https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2":
|
||||
version "10.2.0-electron.1"
|
||||
resolved "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2"
|
||||
dependencies:
|
||||
env-paths "^2.2.0"
|
||||
exponential-backoff "^3.1.1"
|
||||
glob "^8.1.0"
|
||||
graceful-fs "^4.2.6"
|
||||
make-fetch-happen "^10.2.1"
|
||||
nopt "^6.0.0"
|
||||
proc-log "^2.0.1"
|
||||
semver "^7.3.5"
|
||||
tar "^6.2.1"
|
||||
which "^2.0.2"
|
||||
|
||||
"@electron/notarize@2.5.0":
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@electron/notarize/-/notarize-2.5.0.tgz#d4d25356adfa29df4a76bd64a8bd347237cd251e"
|
||||
@ -70,11 +103,12 @@
|
||||
minimist "^1.2.6"
|
||||
plist "^3.0.5"
|
||||
|
||||
"@electron/rebuild@3.6.1":
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-3.6.1.tgz#59e8e36c3f6e6b94a699425dfb61f0394c3dd4df"
|
||||
integrity sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==
|
||||
"@electron/rebuild@3.7.0":
|
||||
version "3.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-3.7.0.tgz#82e20c467ddedbb295d7f641592c52e68c141e9f"
|
||||
integrity sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==
|
||||
dependencies:
|
||||
"@electron/node-gyp" "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2"
|
||||
"@malept/cross-spawn-promise" "^2.0.0"
|
||||
chalk "^4.0.0"
|
||||
debug "^4.1.1"
|
||||
@ -83,7 +117,6 @@
|
||||
got "^11.7.0"
|
||||
node-abi "^3.45.0"
|
||||
node-api-version "^0.2.0"
|
||||
node-gyp "^9.0.0"
|
||||
ora "^5.1.0"
|
||||
read-binary-file-arch "^1.0.6"
|
||||
semver "^7.3.5"
|
||||
@ -144,10 +177,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.9.1.tgz#4a97e85e982099d6c7ee8410aacb55adaa576f06"
|
||||
integrity sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==
|
||||
|
||||
"@eslint/js@^9.17.0":
|
||||
version "9.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.17.0.tgz#1523e586791f80376a6f8398a3964455ecc651ec"
|
||||
integrity sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==
|
||||
"@eslint/js@^9.18.0":
|
||||
version "9.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.18.0.tgz#3356f85d18ed3627ab107790b53caf7e1e3d1e84"
|
||||
integrity sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==
|
||||
|
||||
"@eslint/object-schema@^2.1.4":
|
||||
version "2.1.4"
|
||||
@ -384,85 +417,85 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz#c78e363ab5fe3b21dd1c90d8be9581534417f78e"
|
||||
integrity sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==
|
||||
"@typescript-eslint/eslint-plugin@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.21.0.tgz#395014a75112ecdb81142b866ab6bb62e3be0f2a"
|
||||
integrity sha512-eTH+UOR4I7WbdQnG4Z48ebIA6Bgi7WO8HvFEneeYBxG8qCOYgTOFPSg6ek9ITIDvGjDQzWHcoWHCDO2biByNzA==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.18.2"
|
||||
"@typescript-eslint/type-utils" "8.18.2"
|
||||
"@typescript-eslint/utils" "8.18.2"
|
||||
"@typescript-eslint/visitor-keys" "8.18.2"
|
||||
"@typescript-eslint/scope-manager" "8.21.0"
|
||||
"@typescript-eslint/type-utils" "8.21.0"
|
||||
"@typescript-eslint/utils" "8.21.0"
|
||||
"@typescript-eslint/visitor-keys" "8.21.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.3.1"
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
ts-api-utils "^2.0.0"
|
||||
|
||||
"@typescript-eslint/parser@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.18.2.tgz#0379a2e881d51d8fcf7ebdfa0dd18eee79182ce2"
|
||||
integrity sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==
|
||||
"@typescript-eslint/parser@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.21.0.tgz#312c638aaba4f640d45bfde7c6795a9d75deb088"
|
||||
integrity sha512-Wy+/sdEH9kI3w9civgACwabHbKl+qIOu0uFZ9IMKzX3Jpv9og0ZBJrZExGrPpFAY7rWsXuxs5e7CPPP17A4eYA==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.18.2"
|
||||
"@typescript-eslint/types" "8.18.2"
|
||||
"@typescript-eslint/typescript-estree" "8.18.2"
|
||||
"@typescript-eslint/visitor-keys" "8.18.2"
|
||||
"@typescript-eslint/scope-manager" "8.21.0"
|
||||
"@typescript-eslint/types" "8.21.0"
|
||||
"@typescript-eslint/typescript-estree" "8.21.0"
|
||||
"@typescript-eslint/visitor-keys" "8.21.0"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.18.2.tgz#d193c200d61eb0ddec5987c8e48c9d4e1c0510bd"
|
||||
integrity sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==
|
||||
"@typescript-eslint/scope-manager@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.21.0.tgz#d08d94e2a34b4ccdcc975543c25bb62917437500"
|
||||
integrity sha512-G3IBKz0/0IPfdeGRMbp+4rbjfSSdnGkXsM/pFZA8zM9t9klXDnB/YnKOBQ0GoPmoROa4bCq2NeHgJa5ydsQ4mA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.18.2"
|
||||
"@typescript-eslint/visitor-keys" "8.18.2"
|
||||
"@typescript-eslint/types" "8.21.0"
|
||||
"@typescript-eslint/visitor-keys" "8.21.0"
|
||||
|
||||
"@typescript-eslint/type-utils@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.18.2.tgz#5ad07e09002eee237591881df674c1c0c91ca52f"
|
||||
integrity sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==
|
||||
"@typescript-eslint/type-utils@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.21.0.tgz#2e69d1a93cdbedc73fe694cd6ae4dfedd00430a0"
|
||||
integrity sha512-95OsL6J2BtzoBxHicoXHxgk3z+9P3BEcQTpBKriqiYzLKnM2DeSqs+sndMKdamU8FosiadQFT3D+BSL9EKnAJQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "8.18.2"
|
||||
"@typescript-eslint/utils" "8.18.2"
|
||||
"@typescript-eslint/typescript-estree" "8.21.0"
|
||||
"@typescript-eslint/utils" "8.21.0"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^1.3.0"
|
||||
ts-api-utils "^2.0.0"
|
||||
|
||||
"@typescript-eslint/types@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.18.2.tgz#5ebad5b384c8aa1c0f86cee1c61bcdbe7511f547"
|
||||
integrity sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==
|
||||
"@typescript-eslint/types@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.21.0.tgz#58f30aec8db8212fd886835dc5969cdf47cb29f5"
|
||||
integrity sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.2.tgz#fffb85527f8304e29bfbbdc712f4515da9f8b47c"
|
||||
integrity sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==
|
||||
"@typescript-eslint/typescript-estree@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.21.0.tgz#5ce71acdbed3b97b959f6168afba5a03c88f69a9"
|
||||
integrity sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.18.2"
|
||||
"@typescript-eslint/visitor-keys" "8.18.2"
|
||||
"@typescript-eslint/types" "8.21.0"
|
||||
"@typescript-eslint/visitor-keys" "8.21.0"
|
||||
debug "^4.3.4"
|
||||
fast-glob "^3.3.2"
|
||||
is-glob "^4.0.3"
|
||||
minimatch "^9.0.4"
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
ts-api-utils "^2.0.0"
|
||||
|
||||
"@typescript-eslint/utils@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.18.2.tgz#a2635f71904a84f9e47fe1b6f65a6d944ff1adf9"
|
||||
integrity sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==
|
||||
"@typescript-eslint/utils@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.21.0.tgz#bc4874fbc30feb3298b926e3b03d94570b3999c5"
|
||||
integrity sha512-xcXBfcq0Kaxgj7dwejMbFyq7IOHgpNMtVuDveK7w3ZGwG9owKzhALVwKpTF2yrZmEwl9SWdetf3fxNzJQaVuxw==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@typescript-eslint/scope-manager" "8.18.2"
|
||||
"@typescript-eslint/types" "8.18.2"
|
||||
"@typescript-eslint/typescript-estree" "8.18.2"
|
||||
"@typescript-eslint/scope-manager" "8.21.0"
|
||||
"@typescript-eslint/types" "8.21.0"
|
||||
"@typescript-eslint/typescript-estree" "8.21.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.18.2":
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.2.tgz#b3e434b701f086b10a7c82416ebc56899d27ef2f"
|
||||
integrity sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==
|
||||
"@typescript-eslint/visitor-keys@8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.21.0.tgz#a89744c4cdc83b5c761eb5878befe6c33d1481b2"
|
||||
integrity sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.18.2"
|
||||
"@typescript-eslint/types" "8.21.0"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
|
||||
"@xmldom/xmldom@^0.8.8":
|
||||
@ -571,35 +604,36 @@ anymatch@~3.1.2:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
app-builder-bin@5.0.0-alpha.10:
|
||||
version "5.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz#cf12e593b6b847fb9d04027fa755c6c6610d778b"
|
||||
integrity sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==
|
||||
app-builder-bin@5.0.0-alpha.12:
|
||||
version "5.0.0-alpha.12"
|
||||
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz#2daf82f8badc698e0adcc95ba36af4ff0650dc80"
|
||||
integrity sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==
|
||||
|
||||
app-builder-lib@25.1.8:
|
||||
version "25.1.8"
|
||||
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-25.1.8.tgz#ae376039c5f269c7d562af494a087e5bc6310f1b"
|
||||
integrity sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==
|
||||
app-builder-lib@26.0.0-alpha.10:
|
||||
version "26.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-26.0.0-alpha.10.tgz#3eb3f64ffa5e995595ad61497c5e7a0c2d64b817"
|
||||
integrity sha512-9K3MulGK7j+En4KjH3aq7AzDqe8nn35x7O9l5kwl16nWFdBthcdy1IKsx9CgjMSF+eTNctOZlXwnYiPiGzY+GQ==
|
||||
dependencies:
|
||||
"@develar/schema-utils" "~2.6.5"
|
||||
"@electron/asar" "3.2.18"
|
||||
"@electron/fuses" "^1.8.0"
|
||||
"@electron/notarize" "2.5.0"
|
||||
"@electron/osx-sign" "1.3.1"
|
||||
"@electron/rebuild" "3.6.1"
|
||||
"@electron/rebuild" "3.7.0"
|
||||
"@electron/universal" "2.0.1"
|
||||
"@malept/flatpak-bundler" "^0.4.0"
|
||||
"@types/fs-extra" "9.0.13"
|
||||
async-exit-hook "^2.0.1"
|
||||
bluebird-lst "^1.0.9"
|
||||
builder-util "25.1.7"
|
||||
builder-util-runtime "9.2.10"
|
||||
builder-util "26.0.0-alpha.10"
|
||||
builder-util-runtime "9.3.0-alpha.0"
|
||||
chromium-pickle-js "^0.2.0"
|
||||
config-file-ts "0.2.8-rc1"
|
||||
debug "^4.3.4"
|
||||
dotenv "^16.4.5"
|
||||
dotenv-expand "^11.0.6"
|
||||
ejs "^3.1.8"
|
||||
electron-publish "25.1.7"
|
||||
form-data "^4.0.0"
|
||||
electron-publish "26.0.0-alpha.10"
|
||||
fs-extra "^10.1.0"
|
||||
hosted-git-info "^4.1.0"
|
||||
is-ci "^3.0.0"
|
||||
@ -609,7 +643,6 @@ app-builder-lib@25.1.8:
|
||||
lazy-val "^1.0.5"
|
||||
minimatch "^10.0.0"
|
||||
resedit "^1.7.0"
|
||||
sanitize-filename "^1.6.3"
|
||||
semver "^7.3.8"
|
||||
tar "^6.1.12"
|
||||
temp-file "^3.4.0"
|
||||
@ -619,19 +652,6 @@ applescript@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/applescript/-/applescript-1.0.0.tgz#bb87af568cad034a4e48c4bdaf6067a3a2701317"
|
||||
integrity sha512-yvtNHdWvtbYEiIazXAdp/NY+BBb65/DAseqlNiJQjOx9DynuzOYDbVLBJvuc0ve0VL9x6B3OHF6eH52y9hCBtQ==
|
||||
|
||||
"aproba@^1.0.3 || ^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
|
||||
integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
|
||||
|
||||
are-we-there-yet@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd"
|
||||
integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==
|
||||
dependencies:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
@ -764,32 +784,33 @@ buffer@^5.1.0, buffer@^5.5.0:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
builder-util-runtime@9.2.10:
|
||||
version "9.2.10"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz#a0f7d9e214158402e78b74a745c8d9f870c604bc"
|
||||
integrity sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==
|
||||
builder-util-runtime@9.3.0-alpha.0:
|
||||
version "9.3.0-alpha.0"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.0-alpha.0.tgz#c4639ae24a74d2e0f4eb324100af3040300bae62"
|
||||
integrity sha512-EriE6Uf15niqdkyjBOS09OrXlhEV0HKhnATlI9n63vCoisnvvRTQNgoR2MV9vnBmNGhavBPZXPWPItv4QMDVfw==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
sax "^1.2.4"
|
||||
|
||||
builder-util@25.1.7:
|
||||
version "25.1.7"
|
||||
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-25.1.7.tgz#a07b404f0cb1a635aa165902be65297d58932ff8"
|
||||
integrity sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==
|
||||
builder-util@26.0.0-alpha.10:
|
||||
version "26.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-26.0.0-alpha.10.tgz#f445a530c28da6e3650b93e92263c06c6f89a2cc"
|
||||
integrity sha512-RMVOAgdd+tzwpyF5C8gx9KjzwdUvkUEubpsHTvb2JwlQnBcyBc6hyVCU2gt2MivQCLbjCOEgsUX1/zHrWDqGfg==
|
||||
dependencies:
|
||||
"7zip-bin" "~5.2.0"
|
||||
"@types/debug" "^4.1.6"
|
||||
app-builder-bin "5.0.0-alpha.10"
|
||||
app-builder-bin "5.0.0-alpha.12"
|
||||
bluebird-lst "^1.0.9"
|
||||
builder-util-runtime "9.2.10"
|
||||
builder-util-runtime "9.3.0-alpha.0"
|
||||
chalk "^4.1.2"
|
||||
cross-spawn "^7.0.3"
|
||||
cross-spawn "^7.0.6"
|
||||
debug "^4.3.4"
|
||||
fs-extra "^10.1.0"
|
||||
http-proxy-agent "^7.0.0"
|
||||
https-proxy-agent "^7.0.0"
|
||||
is-ci "^3.0.0"
|
||||
js-yaml "^4.1.0"
|
||||
sanitize-filename "^1.6.3"
|
||||
source-map-support "^0.5.19"
|
||||
stat-mode "^1.0.0"
|
||||
temp-file "^3.4.0"
|
||||
@ -846,7 +867,7 @@ caseless@^0.12.0:
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
|
||||
|
||||
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2:
|
||||
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
@ -952,11 +973,6 @@ color-name@~1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-support@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
|
||||
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
@ -999,10 +1015,10 @@ concat-stream@^2.0.0:
|
||||
readable-stream "^3.0.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concurrently@^9.1.1:
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.1.1.tgz#609dde2ce12f4f12d6a5ea6eace4c38bb7ab2ead"
|
||||
integrity sha512-6VX8lrBIycgZKTwBsWS+bLrmkGRkDmvtGsYylRN9b93CygN6CbK46HmnQ3rdSOR8HRjdahDrxb5MqD9cEFOg5Q==
|
||||
concurrently@^9.1.2:
|
||||
version "9.1.2"
|
||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.1.2.tgz#22d9109296961eaee773e12bfb1ce9a66bc9836c"
|
||||
integrity sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==
|
||||
dependencies:
|
||||
chalk "^4.1.2"
|
||||
lodash "^4.17.21"
|
||||
@ -1036,11 +1052,6 @@ config-file-ts@0.2.8-rc1:
|
||||
glob "^10.3.12"
|
||||
typescript "^5.4.3"
|
||||
|
||||
console-control-strings@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||
integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
|
||||
|
||||
core-util-is@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
@ -1060,7 +1071,7 @@ cross-env@^7.0.3:
|
||||
dependencies:
|
||||
cross-spawn "^7.0.1"
|
||||
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
@ -1069,6 +1080,15 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
cross-spawn@^7.0.6:
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
debounce-fn@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-4.0.0.tgz#ed76d206d8a50e60de0dd66d494d82835ffe61c7"
|
||||
@ -1130,11 +1150,6 @@ delayed-stream@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
delegates@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
|
||||
|
||||
detect-indent@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-7.0.1.tgz#cbb060a12842b9c4d333f1cac4aa4da1bb66bc25"
|
||||
@ -1163,14 +1178,14 @@ dir-compare@^4.2.0:
|
||||
minimatch "^3.0.5"
|
||||
p-limit "^3.1.0 "
|
||||
|
||||
dmg-builder@25.1.8:
|
||||
version "25.1.8"
|
||||
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-25.1.8.tgz#41f3b725edd896156e891016a44129e1bd580430"
|
||||
integrity sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==
|
||||
dmg-builder@26.0.0-alpha.10:
|
||||
version "26.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-26.0.0-alpha.10.tgz#d4d908922005a0c852d0919a7dd0b8f77d3c4bd0"
|
||||
integrity sha512-RWzCNLLu4dGIvBf8kBzjF/zI5aMOSA149S1V2NgAA4La8f8ghdJAm/DI5crSb2zDijFLyTNmUGTtvU6eHgiZyQ==
|
||||
dependencies:
|
||||
app-builder-lib "25.1.8"
|
||||
builder-util "25.1.7"
|
||||
builder-util-runtime "9.2.10"
|
||||
app-builder-lib "26.0.0-alpha.10"
|
||||
builder-util "26.0.0-alpha.10"
|
||||
builder-util-runtime "9.3.0-alpha.0"
|
||||
fs-extra "^10.1.0"
|
||||
iconv-lite "^0.6.2"
|
||||
js-yaml "^4.1.0"
|
||||
@ -1217,16 +1232,16 @@ ejs@^3.1.8:
|
||||
dependencies:
|
||||
jake "^10.8.5"
|
||||
|
||||
electron-builder@^25.1.8:
|
||||
version "25.1.8"
|
||||
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-25.1.8.tgz#b0e310f1600787610bb84c3f39bc7aadb2548486"
|
||||
integrity sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==
|
||||
electron-builder@^26.0.0-alpha.10:
|
||||
version "26.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.0.0-alpha.10.tgz#6f629f5f1f3340286af71cabd12d94edc53f15ea"
|
||||
integrity sha512-QTitqOlP5aZ/8zhnxqjRb6BxSR7Kvwv07PoBGeIXADwSPHQhKhZ+S+GRFzUSYQrMTTJLGzUHbnAes6fZ3uThEA==
|
||||
dependencies:
|
||||
app-builder-lib "25.1.8"
|
||||
builder-util "25.1.7"
|
||||
builder-util-runtime "9.2.10"
|
||||
app-builder-lib "26.0.0-alpha.10"
|
||||
builder-util "26.0.0-alpha.10"
|
||||
builder-util-runtime "9.3.0-alpha.0"
|
||||
chalk "^4.1.2"
|
||||
dmg-builder "25.1.8"
|
||||
dmg-builder "26.0.0-alpha.10"
|
||||
fs-extra "^10.1.0"
|
||||
is-ci "^3.0.0"
|
||||
lazy-val "^1.0.5"
|
||||
@ -1238,15 +1253,16 @@ electron-log@^5.2.4:
|
||||
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-5.2.4.tgz#6b488d9db80aa3c6f3dc39bcd635fc9d1f79c8af"
|
||||
integrity sha512-iX12WXc5XAaKeHg2QpiFjVwL+S1NVHPFd3V5RXtCmKhpAzXsVQnR3UEc0LovM6p6NkUQxDWnkdkaam9FNUVmCA==
|
||||
|
||||
electron-publish@25.1.7:
|
||||
version "25.1.7"
|
||||
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-25.1.7.tgz#14e50c2a3fafdc1c454eadbbc47ead89a48bb554"
|
||||
integrity sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==
|
||||
electron-publish@26.0.0-alpha.10:
|
||||
version "26.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-26.0.0-alpha.10.tgz#16ac95acca2d796ca00c7a90ca27ebf31855f284"
|
||||
integrity sha512-yUkCJD7MLN57d6PJ8PMcBCR35xytA+jHyrOiS/H0hlmTOWq1sXN+tIBylX4h0dD/C6mn75/y5eE156Pe2nccPw==
|
||||
dependencies:
|
||||
"@types/fs-extra" "^9.0.11"
|
||||
builder-util "25.1.7"
|
||||
builder-util-runtime "9.2.10"
|
||||
builder-util "26.0.0-alpha.10"
|
||||
builder-util-runtime "9.3.0-alpha.0"
|
||||
chalk "^4.1.2"
|
||||
form-data "^4.0.0"
|
||||
fs-extra "^10.1.0"
|
||||
lazy-val "^1.0.5"
|
||||
mime "^2.5.2"
|
||||
@ -1259,12 +1275,12 @@ electron-store@^8.2.0:
|
||||
conf "^10.2.0"
|
||||
type-fest "^2.17.0"
|
||||
|
||||
electron-updater@^6.3.9:
|
||||
version "6.3.9"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.3.9.tgz#e1e7f155624c58e6f3760f376c3a584028165ec4"
|
||||
integrity sha512-2PJNONi+iBidkoC5D1nzT9XqsE8Q1X28Fn6xRQhO3YX8qRRyJ3mkV4F1aQsuRnYPqq6Hw+E51y27W75WgDoofw==
|
||||
electron-updater@^6.4.0-alpha.3:
|
||||
version "6.4.0-alpha.3"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.4.0-alpha.3.tgz#4c33647c79f7ea1bcd184aac8a0b15d5a2b37cf1"
|
||||
integrity sha512-pqbEqfKVly49UO3QhnRnzghK75BW6v6ZrpW/2vs+ZVVxHmrdwEl1bTjJFQl1LSIBABpBEwT5W9uwf3cKfrD+Bg==
|
||||
dependencies:
|
||||
builder-util-runtime "9.2.10"
|
||||
builder-util-runtime "9.3.0-alpha.0"
|
||||
fs-extra "^10.1.0"
|
||||
js-yaml "^4.1.0"
|
||||
lazy-val "^1.0.5"
|
||||
@ -1273,10 +1289,10 @@ electron-updater@^6.3.9:
|
||||
semver "^7.6.3"
|
||||
tiny-typed-emitter "^2.1.0"
|
||||
|
||||
electron@^33.2.1:
|
||||
version "33.2.1"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-33.2.1.tgz#d0d7bba7a7abf4f14881d0a6e03c498b301a2d5f"
|
||||
integrity sha512-SG/nmSsK9Qg1p6wAW+ZfqU+AV8cmXMTIklUL18NnOKfZLlum4ZsDoVdmmmlL39ZmeCaq27dr7CgslRPahfoVJg==
|
||||
electron@^34.0.0:
|
||||
version "34.0.0"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-34.0.0.tgz#30ccedbc02d2f036868b8278960fd0e438ec0e52"
|
||||
integrity sha512-fpaPb0lifoUJ6UJa4Lk8/0B2Ku/xDZWdc1Gkj67jbygTCrvSon0qquju6Ltx1Kz23GRqqlIHXiy9EvrjpY7/Wg==
|
||||
dependencies:
|
||||
"@electron/get" "^2.0.0"
|
||||
"@types/node" "^20.9.0"
|
||||
@ -1640,20 +1656,6 @@ function-bind@^1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
gauge@^4.0.3:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce"
|
||||
integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==
|
||||
dependencies:
|
||||
aproba "^1.0.3 || ^2.0.0"
|
||||
color-support "^1.1.3"
|
||||
console-control-strings "^1.1.0"
|
||||
has-unicode "^2.0.1"
|
||||
signal-exit "^3.0.7"
|
||||
string-width "^4.2.3"
|
||||
strip-ansi "^6.0.1"
|
||||
wide-align "^1.1.5"
|
||||
|
||||
get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
@ -1713,7 +1715,7 @@ glob@^10.3.12, glob@^10.3.7:
|
||||
package-json-from-dist "^1.0.0"
|
||||
path-scurry "^1.11.1"
|
||||
|
||||
glob@^7.0.0, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
|
||||
glob@^7.0.0, glob@^7.1.3, glob@^7.1.6:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
@ -1725,7 +1727,7 @@ glob@^7.0.0, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^8.0.1:
|
||||
glob@^8.0.1, glob@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
|
||||
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
|
||||
@ -1817,11 +1819,6 @@ has-symbols@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
||||
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
||||
|
||||
has-unicode@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
|
||||
|
||||
hasown@^2.0.0, hasown@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||
@ -2230,7 +2227,7 @@ lru-cache@^7.7.1:
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
|
||||
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
|
||||
|
||||
make-fetch-happen@^10.0.3:
|
||||
make-fetch-happen@^10.2.1:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164"
|
||||
integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==
|
||||
@ -2337,7 +2334,7 @@ minimatch@^9.0.3, minimatch@^9.0.4:
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist@^1.2.3, minimist@^1.2.6:
|
||||
minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||
@ -2475,23 +2472,6 @@ node-api-version@^0.2.0:
|
||||
dependencies:
|
||||
semver "^7.3.5"
|
||||
|
||||
node-gyp@^9.0.0:
|
||||
version "9.4.1"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.4.1.tgz#8a1023e0d6766ecb52764cc3a734b36ff275e185"
|
||||
integrity sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==
|
||||
dependencies:
|
||||
env-paths "^2.2.0"
|
||||
exponential-backoff "^3.1.1"
|
||||
glob "^7.1.4"
|
||||
graceful-fs "^4.2.6"
|
||||
make-fetch-happen "^10.0.3"
|
||||
nopt "^6.0.0"
|
||||
npmlog "^6.0.0"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.2"
|
||||
which "^2.0.2"
|
||||
|
||||
node-stream-zip@^1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.15.0.tgz#158adb88ed8004c6c49a396b50a6a5de3bca33ea"
|
||||
@ -2514,16 +2494,6 @@ normalize-url@^6.0.1:
|
||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
|
||||
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
|
||||
|
||||
npmlog@^6.0.0:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830"
|
||||
integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==
|
||||
dependencies:
|
||||
are-we-there-yet "^3.0.0"
|
||||
console-control-strings "^1.1.0"
|
||||
gauge "^4.0.3"
|
||||
set-blocking "^2.0.0"
|
||||
|
||||
object-keys@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
|
||||
@ -2724,12 +2694,12 @@ prettier-plugin-organize-imports@^4.1.0:
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz#f3d3764046a8e7ba6491431158b9be6ffd83b90f"
|
||||
integrity sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==
|
||||
|
||||
prettier-plugin-packagejson@^2.5.6:
|
||||
version "2.5.6"
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.6.tgz#cd3cca60e1aa87ee3ce3b4032c1c999798d9f714"
|
||||
integrity sha512-TY7KiLtyt6Tlf53BEbXUWkN0+TRdHKgIMmtXtDCyHH6yWnZ50Lwq6Vb6lyjapZrhDTXooC4EtlY5iLe1sCgi5w==
|
||||
prettier-plugin-packagejson@^2.5.8:
|
||||
version "2.5.8"
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.8.tgz#1b307fce044d0230ea8f3210f8a731c5cc1b288d"
|
||||
integrity sha512-BaGOF63I0IJZoudxpuQe17naV93BRtK8b3byWktkJReKEMX9CC4qdGUzThPDVO/AUhPzlqDiAXbp18U6X8wLKA==
|
||||
dependencies:
|
||||
sort-package-json "2.12.0"
|
||||
sort-package-json "2.14.0"
|
||||
synckit "0.9.2"
|
||||
|
||||
prettier@3.4.2:
|
||||
@ -2737,6 +2707,11 @@ prettier@3.4.2:
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
|
||||
integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==
|
||||
|
||||
proc-log@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685"
|
||||
integrity sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==
|
||||
|
||||
progress@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||
@ -2785,7 +2760,7 @@ read-binary-file-arch@^1.0.6:
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
|
||||
readable-stream@^3.0.2, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
readable-stream@^3.0.2, readable-stream@^3.4.0:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
|
||||
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
|
||||
@ -2953,11 +2928,6 @@ serialize-error@^7.0.1:
|
||||
dependencies:
|
||||
type-fest "^0.13.1"
|
||||
|
||||
set-blocking@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||
@ -2992,7 +2962,7 @@ shx@^0.3.4:
|
||||
minimist "^1.2.3"
|
||||
shelljs "^0.8.5"
|
||||
|
||||
signal-exit@^3.0.2, signal-exit@^3.0.7:
|
||||
signal-exit@^3.0.2:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||
@ -3045,10 +3015,10 @@ sort-object-keys@^1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
|
||||
integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
|
||||
|
||||
sort-package-json@2.12.0:
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.12.0.tgz#4196a1ba82ba63c4a512add1d00ab39026bf8ab7"
|
||||
integrity sha512-/HrPQAeeLaa+vbAH/znjuhwUluuiM/zL5XX9kop8UpDgjtyWKt43hGDk2vd/TBdDpzIyzIHVUgmYofzYrAQjew==
|
||||
sort-package-json@2.14.0:
|
||||
version "2.14.0"
|
||||
resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.14.0.tgz#ba0c7420dc6edea4b0eb7e9f502fda63f57586d8"
|
||||
integrity sha512-xBRdmMjFB/KW3l51mP31dhlaiFmqkHLfWTfZAno8prb/wbDxwBPWFpxB16GZbiPbYr3wL41H8Kx22QIDWRe8WQ==
|
||||
dependencies:
|
||||
detect-indent "^7.0.1"
|
||||
detect-newline "^4.0.0"
|
||||
@ -3089,7 +3059,7 @@ stat-mode@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-1.0.0.tgz#68b55cb61ea639ff57136f36b216a291800d1465"
|
||||
integrity sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@ -3151,7 +3121,7 @@ synckit@0.9.2:
|
||||
"@pkgr/core" "^0.1.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.1.2:
|
||||
tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.2.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a"
|
||||
integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
|
||||
@ -3232,10 +3202,10 @@ truncate-utf8-bytes@^1.0.0:
|
||||
dependencies:
|
||||
utf8-byte-length "^1.0.1"
|
||||
|
||||
ts-api-utils@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
|
||||
integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
|
||||
ts-api-utils@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.0.tgz#b9d7d5f7ec9f736f4d0f09758b8607979044a900"
|
||||
integrity sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==
|
||||
|
||||
tslib@^2.1.0, tslib@^2.6.2:
|
||||
version "2.7.0"
|
||||
@ -3264,14 +3234,14 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
||||
|
||||
typescript-eslint@^8.18.2:
|
||||
version "8.18.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.18.2.tgz#71334dcf843adc3fbb771dce5ade7876aa0d62b7"
|
||||
integrity sha512-KuXezG6jHkvC3MvizeXgupZzaG5wjhU3yE8E7e6viOvAvD9xAWYp8/vy0WULTGe9DYDWcQu7aW03YIV3mSitrQ==
|
||||
typescript-eslint@^8.21.0:
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.21.0.tgz#78bdb83a6d771f0312b128297d84a3111885fd08"
|
||||
integrity sha512-txEKYY4XMKwPXxNkN8+AxAdX6iIJAPiJbHE/FpQccs/sxw8Lf26kqwC3cn0xkHlW8kEbLhkhCsjWuMveaY9Rxw==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "8.18.2"
|
||||
"@typescript-eslint/parser" "8.18.2"
|
||||
"@typescript-eslint/utils" "8.18.2"
|
||||
"@typescript-eslint/eslint-plugin" "8.21.0"
|
||||
"@typescript-eslint/parser" "8.21.0"
|
||||
"@typescript-eslint/utils" "8.21.0"
|
||||
|
||||
typescript@^5.4.3:
|
||||
version "5.5.4"
|
||||
@ -3357,13 +3327,6 @@ which@^2.0.1, which@^2.0.2:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
|
||||
integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2 || 3 || 4"
|
||||
|
||||
winreg@1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
|
||||
|
@ -8,6 +8,13 @@ export default defineConfig({
|
||||
head: [["link", { rel: "icon", type: "image/png", href: "/favicon.png" }]],
|
||||
cleanUrls: true,
|
||||
ignoreDeadLinks: "localhostLinks",
|
||||
vite: {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ['client-museum-s3.png'] // Added to handle static asset import
|
||||
}
|
||||
}
|
||||
},
|
||||
themeConfig: {
|
||||
// We use the default theme (with some CSS color overrides). This
|
||||
// themeConfig block can be used to further customize the default theme.
|
||||
|
@ -247,15 +247,6 @@ export const sidebar = [
|
||||
text: "Hosting the web app",
|
||||
link: "/self-hosting/guides/web-app",
|
||||
},
|
||||
{
|
||||
text: "Administering your server",
|
||||
link: "/self-hosting/guides/admin",
|
||||
},
|
||||
|
||||
{
|
||||
text: "Mobile build",
|
||||
link: "/self-hosting/guides/mobile-build",
|
||||
},
|
||||
{
|
||||
text: "Configuring S3",
|
||||
link: "/self-hosting/guides/configuring-s3",
|
||||
@ -276,6 +267,15 @@ export const sidebar = [
|
||||
text: "Configure CLI for Self Hosted Instance",
|
||||
link: "/self-hosting/guides/selfhost-cli",
|
||||
},
|
||||
{
|
||||
text: "Administering your server",
|
||||
link: "/self-hosting/guides/admin",
|
||||
},
|
||||
|
||||
{
|
||||
text: "Mobile build",
|
||||
link: "/self-hosting/guides/mobile-build",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -38,3 +38,11 @@ that the original is not modified. For more details, see the
|
||||
A two way sync is not currently supported. Attempting to export data to the same
|
||||
folder that is also being watched by the Ente app will result in undefined
|
||||
behaviour (e.g. duplicate files, export stalling etc).
|
||||
|
||||
## Why is my export size larger than my backed-up size in Ente?
|
||||
|
||||
One possible reason could be that you have files that are in multiple different
|
||||
albums. Whenever a file is backed-up to Ente in multiple albums it will still
|
||||
count only once towards the total storage in Ente. However, during export that
|
||||
file will be downloaded multiple times to the different folders corresponding to
|
||||
said albums, causing the total export size to be larger.
|
||||
|
BIN
docs/docs/public/client-museum-s3.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
@ -5,7 +5,9 @@ description:
|
||||
from outside localhost
|
||||
---
|
||||
|
||||
# Configuring S3
|
||||
# Components of the Architecture
|
||||
|
||||

|
||||
|
||||
There are three components involved in uploading:
|
||||
|
||||
@ -24,6 +26,8 @@ interaction goes something like this:
|
||||
The upshot of this is that _both_ the client and museum should be able to reach
|
||||
your S3 bucket.
|
||||
|
||||
## Configuring S3
|
||||
|
||||
The URL for the S3 bucket is configured in
|
||||
[scripts/compose/credentials.yaml](https://github.com/ente-io/ente/blob/main/server/scripts/compose/credentials.yaml#L10).
|
||||
You can edit this file directly when testing, though it is just simpler and more
|
||||
@ -32,61 +36,64 @@ and put your custom configuration there (in your case, you can put an entire
|
||||
`s3` config object in your `museum.yaml`).
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> For more details about these configuration objects, see the documentation for
|
||||
> the `s3` object in
|
||||
> [configurations/local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml).
|
||||
|
||||
By default, you only need to configure the endpoint for the first bucket.
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> If you're wondering why there are 3 buckets - that's because our production
|
||||
> instance uses these to perform replication.
|
||||
>
|
||||
> However, in a self hosted setup replication is off by default (you can turn it
|
||||
> on if you want). When replication is turned off, only the first bucket (it
|
||||
> must be named `b2-eu-cen`) is used, and you can ignore the other two. Use the
|
||||
> `hot_bucket` option if you'd like to set one of the other predefined buckets
|
||||
> as the "first" bucket.
|
||||
|
||||
The `endpoint` for the first bucket in the starter `credentials.yaml` is
|
||||
`localhost:3200`. The way this works then is that both museum (`2`) and minio
|
||||
(`3`) are running within the same Docker compose cluster, so are able to reach
|
||||
each other. If at this point we were to run the web app (`1`) on localhost (say
|
||||
using `yarn dev:photos`), it would also run on localhost and thus would be able
|
||||
to reach `3`.
|
||||
|
||||
If you were to try and connect from a mobile app, this would not work since
|
||||
`localhost:3200` would not resolve on your mobile. So you'll need to modify this
|
||||
endpoint to a value, say `yourserverip:3200`, so that the mobile app can also
|
||||
reach it.
|
||||
The docker compose file is shipped with MinIO as the Self Hosted S3 Compatible Storage.
|
||||
By default, MinIO server is served on `localhost:3200` and the MinIO UI on
|
||||
`localhost:3201`.
|
||||
For example, in a localhost network situation, the way this
|
||||
connection works is, Museum (`1`) and MinIO (`2`) run on the same docker network and
|
||||
the web app (`3`) which will also be hosted on the localhost. This enables all the
|
||||
three components of the setup being able to communicate with each other seamlessly.
|
||||
|
||||
The same principle applies if you're deploying to your custom domain.
|
||||
|
||||
## Replication
|
||||
|
||||
If you're wondering why there are 3 buckets on MinIO UI - that's because our
|
||||
production instance uses these to perform [replication](https://ente.io/reliability/).
|
||||
|
||||
In a self hosted Ente Instance replication is turned off by default.
|
||||
When replication is turned off, only the first bucket (`b2-eu-cen`) is used,
|
||||
and you can ignore the other two. Use the `s3.hot_storage.primary` option
|
||||
if you'd like to set one of the other predefined buckets as the primary bucket.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> As of now, Replication works only if all the 3 storage type
|
||||
> needs are fulfilled (1 Hot, 1 Cold and 1 Glacier Storage).
|
||||
>
|
||||
> [Reference](https://github.com/ente-io/ente/discussions/3167#discussioncomment-10585970)
|
||||
|
||||
## SSL Configuration
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> If you need to configure SSL, for example if you're running over the internet,
|
||||
> you'll need to turn off `s3.are_local_buckets` (which disables SSL in the
|
||||
> default starter compose template).
|
||||
>
|
||||
> Disabling `s3.are_local_buckets` also switches to the subdomain style URLs for
|
||||
> the buckets. However, not all S3 providers support these, in particular, minio
|
||||
> does not work with these in default configuration. So in such cases you'll
|
||||
> also need to then enable `s3.use_path_style_urls`.
|
||||
|
||||
To summarize:
|
||||
Disabling `s3.are_local_buckets` also switches to the subdomain style URLs for
|
||||
the buckets. However, not all S3 providers support these, in particular, minio
|
||||
does not work with these in default configuration. So in such cases you'll
|
||||
also need to then enable `s3.use_path_style_urls`.
|
||||
|
||||
## Summary
|
||||
|
||||
Set the S3 bucket `endpoint` in `credentials.yaml` to a `yourserverip:3200` or
|
||||
some such IP/hostname that accessible from both where you are running the Ente
|
||||
clients (e.g. the mobile app) and also from within the Docker compose cluster.
|
||||
|
||||
### Example
|
||||
#### Example
|
||||
|
||||
An example `museum.yaml` when you're trying to connect to museum running on your
|
||||
computer from your phone on the same WiFi network:
|
||||
|
||||
```
|
||||
```yaml
|
||||
s3:
|
||||
are_local_buckets: true
|
||||
b2-eu-cen:
|
||||
@ -97,6 +104,20 @@ s3:
|
||||
bucket: b2-eu-cen
|
||||
```
|
||||
|
||||
## FAE (Frequently Answered Errors)
|
||||
|
||||
Here are some Frequently Answered Errors from the Community Chat with the reasoning
|
||||
for a particular error and its potential fix.
|
||||
|
||||
In most situations, the problem turns out to be some minute mistakes or misconfigurations
|
||||
on the users end and that turns out to be the bottleneck of the whole problem.
|
||||
Please make sure to `reverse_proxy` Museum to a domain as well as check your S3
|
||||
Credentials and whole config for any minor mis-configurations.
|
||||
|
||||
It is also suggested that the user setups Bucket CORS on MinIO or any external
|
||||
S3 Bucket they are connecting to. To setup Bucket CORS, help yourself by upload
|
||||
[this](https://help.ente.io/self-hosting/guides/external-s3#_5-fix-potential-cors-issue-with-your-bucket).
|
||||
|
||||
### 403 Forbidden
|
||||
|
||||
If museum (`2`) is able to make a network connection to your S3 bucket (`3`) but
|
||||
@ -108,11 +129,24 @@ corresponding object exists in the S3 bucket.
|
||||
To fix these, you should ensure the following:
|
||||
|
||||
1. The bucket CORS rules do not allow museum to access these objects.
|
||||
|
||||
> For uploading files from the browser, you will need to currently set
|
||||
> allowedOrigins to "\*", and allow the "X-Auth-Token", "X-Client-Package"
|
||||
> headers configuration too.
|
||||
> [Here is an example of a working configuration](https://github.com/ente-io/ente/discussions/1764#discussioncomment-9478204).
|
||||
- For uploading files from the browser, you will need to currently set
|
||||
allowedOrigins to "\*", and allow the "X-Auth-Token", "X-Client-Package"
|
||||
headers configuration too.
|
||||
[Here is an example of a working configuration](https://github.com/ente-io/ente/discussions/1764#discussioncomment-9478204).
|
||||
|
||||
2. The credentials are not being picked up (you might be setting the correct
|
||||
creds, but not in the place where museum picks them from).
|
||||
|
||||
### Mismatch in File Size
|
||||
|
||||
The "Mismatch in File Size" error mostly occurs in a situation where the client (`1`)
|
||||
is re-uploading a file which is already in the bucket with a different File Size. The
|
||||
reason for re-upload could be anything including Network issue, sudden killing of app
|
||||
before the upload is complete and etc.
|
||||
|
||||
This is also one of Museums (`2`) Validation Checks for the size of file being
|
||||
re-uploaded from the client to the size of the file which is already
|
||||
uploaded to the S3 Bucket.
|
||||
|
||||
In most case, it is very unlikely that this error could be a cause of some mistake in
|
||||
the configuration or Browser/Bucket CORS.
|
||||
|
@ -10,6 +10,12 @@ description:
|
||||
The getting started instructions mention using `yarn dev` (which is an alias of
|
||||
`yarn dev:photos`) to serve your web app.
|
||||
|
||||
>[!IMPORTANT]
|
||||
> Please note that Ente's Web App supports the Yarn version 1.22.xx or 1.22.22 specifically.
|
||||
> Make sure to install the right version or modify your yarn installation to meet the requirements.
|
||||
> The user might end up into unknown version and dependency related errors if yarn
|
||||
> is on different version.
|
||||
|
||||
```sh
|
||||
cd ente/web
|
||||
git submodule update --init --recursive
|
||||
@ -45,8 +51,8 @@ COPY apps/ .
|
||||
RUN corepack enable
|
||||
|
||||
# Endpoint for Ente Server
|
||||
NEXT_PUBLIC_ENTE_ENDPOINT=https://your-ente-endpoint.com
|
||||
NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=https://your-albums-endpoint.com
|
||||
ENV NEXT_PUBLIC_ENTE_ENDPOINT=https://your-ente-endpoint.com
|
||||
ENV NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=https://your-albums-endpoint.com
|
||||
|
||||
RUN yarn cache clean
|
||||
RUN yarn install --network-timeout 1000000000
|
||||
@ -157,8 +163,8 @@ npm install pm2@latest
|
||||
Copy the below contents to a file called `ecosystem.config.js` inside the
|
||||
`ente/web` directory.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
```js
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: "photos",
|
||||
@ -174,7 +180,8 @@ Copy the below contents to a file called `ecosystem.config.js` inside the
|
||||
env: {
|
||||
NODE_ENV: "development",
|
||||
PORT: "3001"
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "auth",
|
||||
script: "yarn workspace auth next dev",
|
||||
|
@ -24,12 +24,10 @@
|
||||
.link-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 16px; /* Add padding for better appearance */
|
||||
text-decoration: none; /* Remove underline */
|
||||
color: inherit; /* Inherit color from parent */
|
||||
font-weight: bold; /* Make the text bold */
|
||||
font-size: 40px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.duckie-container {
|
||||
@ -62,7 +60,7 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
marign: 20px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.horizontal-group {
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Link } from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
@ -233,7 +232,6 @@ const App: React.FC = () => {
|
||||
) => {
|
||||
setTabValue(newValue);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const searchParam = new URLSearchParams(window.location.search);
|
||||
const userToken = searchParam.get("token");
|
||||
@ -241,23 +239,9 @@ const App: React.FC = () => {
|
||||
if (userToken) {
|
||||
setLocalToken(userToken);
|
||||
setToken(userToken);
|
||||
|
||||
const editToken = document.getElementById(":r1:");
|
||||
if (editToken instanceof HTMLInputElement) {
|
||||
editToken.readOnly = true;
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const updateToken = () => {
|
||||
const editToken = document.getElementById(":r1:");
|
||||
if (editToken instanceof HTMLInputElement) {
|
||||
editToken.readOnly = false;
|
||||
// Change focus to token field
|
||||
editToken.focus();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div>
|
||||
@ -272,30 +256,6 @@ const App: React.FC = () => {
|
||||
staff.ente.io
|
||||
</a>
|
||||
<div className="text-fields">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
label="Token"
|
||||
value={localToken}
|
||||
onChange={(e) => {
|
||||
setLocalToken(e.target.value);
|
||||
setToken(e.target.value);
|
||||
}}
|
||||
size="medium"
|
||||
className="text-field-token"
|
||||
style={{ maxWidth: "parent" }}
|
||||
/>
|
||||
<Link
|
||||
style={{ textAlign: "left" }}
|
||||
onClick={updateToken}
|
||||
>
|
||||
Update Token?
|
||||
</Link>
|
||||
</div>
|
||||
<TextField
|
||||
label="Email"
|
||||
value={localEmail}
|
||||
|
@ -46,7 +46,7 @@ You can alternatively install the build from PlayStore or F-Droid.
|
||||
|
||||
## 🧑💻 Building from source
|
||||
|
||||
1. [Install Flutter v3.24.3](https://flutter.dev/docs/get-started/install).
|
||||
1. [Install Flutter v3.27.2](https://flutter.dev/docs/get-started/install).
|
||||
|
||||
2. Pull in all submodules with `git submodule update --init --recursive`
|
||||
|
||||
|
@ -61,6 +61,7 @@ analyzer:
|
||||
unnecessary_const: error
|
||||
cancel_subscriptions: error
|
||||
unrelated_type_equality_checks: error
|
||||
unnecessary_cast: info
|
||||
|
||||
|
||||
unawaited_futures: warning # convert to warning after fixing existing issues
|
||||
|
@ -89,6 +89,7 @@
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data android:name="flutterEmbedding" android:value="2" />
|
||||
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
|
||||
<meta-data android:name="asset_statements"
|
||||
android:resource="@string/asset_statements" />
|
||||
<meta-data android:name="io.sentry.dsn"
|
||||
|
36
mobile/fastlane/metadata/android/ro/full_description.txt
Normal file
@ -0,0 +1,36 @@
|
||||
ente este o aplicație simplă pentru a face copii de rezervă și a partaja fotografiile și videoclipurile.
|
||||
|
||||
Dacă ați căutat o alternativă la Google Photos care să respecte confidențialitatea, ați ajuns la locul potrivit. Cu ente, acestea sunt stocate criptat integral (e2ee). Asta înseamnă că numai dvs. le puteți vedea.
|
||||
|
||||
Avem aplicații open-source pentru Android, iOS, web și desktop, iar fotografiile dvs. se vor sincroniza perfect între toate acestea într-o manieră criptată integral (e2ee).
|
||||
|
||||
De asemenea, ente simplifică partajarea albumelor dvs. cu cei dragi, chiar dacă aceștia nu folosesc ente. Puteți partaja linkuri vizibile public, unde aceștia pot vizualiza albumul dvs. și pot colabora prin adăugarea de fotografii la acesta, chiar și fără un cont sau o aplicație.
|
||||
|
||||
Datele dvs. criptate sunt copiate în 3 locații diferite, inclusiv într-un adăpost antiatomic din Paris. Luăm posteritatea în serios și vă asigurăm că amintirile dvs. vor ajunge la următoarea generație.
|
||||
|
||||
Suntem aici pentru a crea cea mai sigură aplicație de fotografii, veniți alături de noi!
|
||||
|
||||
CARACTERISTICI
|
||||
- Copii de rezervă în calitate originală, deoarece fiecare pixel contează
|
||||
- Planuri de familie, astfel încât să puteți distribui spațiul cu familia dvs.
|
||||
- Albume colaborative, astfel încât să puteți pune în comun fotografii după o excursie
|
||||
- Dosare distribuite, în cazul în care doriți ca partenerul dvs. să se bucure și de fotografiile dvs.
|
||||
- Linkuri pentru albume care pot fi protejate cu o parolă
|
||||
- Abilitatea de a elibera spațiu, prin eliminarea fișierelor care au fost salvate în siguranță
|
||||
- Asistență umană, pentru că meritați
|
||||
- Descrieri, astfel încât să vă puteți subtitra amintirile și să le găsiți cu ușurință
|
||||
- Editor de imagini, pentru a adăuga ultimele retușuri
|
||||
- Evidențiați, ascundeți și retrăiți-vă amintirile, căci sunt prețioase
|
||||
- Import cu o singură apăsare din Google, Apple, hard disk și multe altele
|
||||
- Temă întunecată, deoarece fotografiile dvs. arată bine și cu ea
|
||||
- 2FA, 3FA, autentificare biometrică
|
||||
- și MULTE altele!
|
||||
|
||||
PERMISIUNI
|
||||
ente solicită anumite permisiuni pentru a servi scopului unui furnizor de stocare a fotografiilor, care poate fi revizuit aici: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
|
||||
|
||||
PREȚURI
|
||||
Nu oferim planuri gratuite pentru totdeauna, deoarece este important pentru noi să rămânem sustenabili și să trecem testul timpului. În schimb, oferim planuri accesibile pe care le puteți distribui liber familiei dvs. Puteți afla mai multe la ente.io.
|
||||
|
||||
ASISTENȚĂ
|
||||
Suntem mândri să oferim asistență umană. Dacă sunteți clientul nostru plătit, vă puteți adresa la team@ente.io și așteptați un răspuns din partea echipei noastre în termen de 24 de ore.
|
@ -0,0 +1 @@
|
||||
ente este o aplicație de stocare foto criptată integral
|
1
mobile/fastlane/metadata/android/ro/title.txt
Normal file
@ -0,0 +1 @@
|
||||
ente - stocare foto criptată
|
33
mobile/fastlane/metadata/ios/ro/description.txt
Normal file
@ -0,0 +1,33 @@
|
||||
Ente este o aplicație simplă pentru a face automat copii de rezervă și a vă organiza fotografiile și videoclipurile.
|
||||
|
||||
Dacă erați în căutarea unei alternative care să respecte confidențialitatea pentru a vă păstra amintirile, ați ajuns la locul potrivit. Cu Ente, acestea sunt stocate criptate integral (e2ee). Asta înseamnă că numai dvs. le puteți vedea.
|
||||
|
||||
Avem aplicații pentru toate platformele, iar fotografiile dvs. se vor sincroniza perfect între toate dispozitivele dvs. într-un mod criptat integral (e2ee).
|
||||
|
||||
De asemenea, Ente simplifică distribuirea albumelor dvs. cu cei dragi. Puteți fie să le distribuiți direct altor utilizatori Ente, criptate integral, fie cu linkuri care pot fi vizualizate public.
|
||||
|
||||
Datele dvs. criptate sunt stocate în mai multe locații, inclusiv într-un adăpost antiatomic din Paris. Luăm posteritatea în serios și vă asigurăm că amintirile dvs. vor ajunge la următoarea generație.
|
||||
|
||||
Suntem aici pentru a crea cea mai sigură aplicație de fotografii, veniți alături de noi!
|
||||
|
||||
CARACTERISTICI
|
||||
- Copii de rezervă în calitate originală, deoarece fiecare pixel contează
|
||||
- Planuri de familie, astfel încât să puteți distribui spațiul cu familia dvs.
|
||||
- Dosare distribuite, în cazul în care doriți ca partenerul dvs. să se bucure și de fotografiile dvs.
|
||||
- Linkuri pentru albume, care pot fi protejate cu o parolă și setate să expire
|
||||
- Abilitatea de a elibera spațiu, prin eliminarea fișierelor care au fost salvate în siguranță
|
||||
- Editor de imagini, pentru a adăuga ultimele retușuri
|
||||
- Evidențiați, ascundeți și retrăiți-vă amintirile, căci sunt prețioase
|
||||
- Import cu un singur clic de la toți furnizorii majori de stocare
|
||||
- Temă întunecată, deoarece fotografiile dvs. arată bine și cu ea
|
||||
- 2FA, 3FA, autentificare biometrică
|
||||
- și MULTE altele!
|
||||
|
||||
PREȚURI
|
||||
Nu oferim planuri gratuite pentru totdeauna, deoarece este important pentru noi să rămânem sustenabili și să trecem testul timpului. În schimb, oferim planuri accesibile pe care le puteți distribui liber familiei dvs. Puteți afla mai multe la ente.io.
|
||||
|
||||
ASISTENȚĂ
|
||||
Suntem mândri să oferim asistență umană. Dacă sunteți clientul nostru plătit, vă puteți adresa la team@ente.io și așteptați un răspuns din partea echipei noastre în termen de 24 de ore.
|
||||
|
||||
TERMENI
|
||||
https://ente.io/terms
|
1
mobile/fastlane/metadata/ios/ro/keywords.txt
Normal file
@ -0,0 +1 @@
|
||||
fotografii,fotografie,familie,intimitate,cloud,backup,video,foto,criptare,stocare,album,alternative
|
1
mobile/fastlane/metadata/ios/ro/name.txt
Normal file
@ -0,0 +1 @@
|
||||
Ente Foto
|
1
mobile/fastlane/metadata/ios/ro/subtitle.txt
Normal file
@ -0,0 +1 @@
|
||||
Stocare foto criptată
|
@ -16,7 +16,7 @@
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
DA6BE5E826B3BC8600656280 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
|
||||
DA6BE5E826B3BC8600656280 /* (null) in Resources */ = {isa = PBXBuildFile; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@ -230,7 +230,7 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
DA6BE5E826B3BC8600656280 /* BuildFile in Resources */,
|
||||
DA6BE5E826B3BC8600656280 /* (null) in Resources */,
|
||||
277218A0270F596900FFE3CC /* GoogleService-Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -608,6 +608,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
APP_DISPLAY_NAME = "Ente Profile";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
@ -770,6 +771,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
APP_DISPLAY_NAME = "Ente Debug";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
@ -794,7 +796,7 @@
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 0.0.11;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.debug;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -809,6 +811,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
APP_DISPLAY_NAME = "Ente Photos";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
|
@ -15,7 +15,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Ente Photos</string>
|
||||
<string>$(APP_DISPLAY_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
@ -24,6 +24,8 @@
|
||||
<string>????</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>12.1</string>
|
||||
<key>FlutterDeepLinkingEnabled</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>googlegmail</string>
|
||||
|
@ -1,4 +1,3 @@
|
||||
import "dart:io";
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:logging/logging.dart";
|
||||
@ -98,15 +97,4 @@ extension ClipDB on MLDataDB {
|
||||
embedding.version,
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> _clearDeprecatedStores(Directory dir) async {
|
||||
final deprecatedObjectBox = Directory(dir.path + "/object-box-store");
|
||||
if (await deprecatedObjectBox.exists()) {
|
||||
await deprecatedObjectBox.delete(recursive: true);
|
||||
}
|
||||
final deprecatedIsar = File(dir.path + "/default.isar");
|
||||
if (await deprecatedIsar.exists()) {
|
||||
await deprecatedIsar.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
"@@locale ": "en",
|
||||
"enterYourEmailAddress": "Voer uw e-mailadres in",
|
||||
"accountWelcomeBack": "Welkom terug!",
|
||||
"emailAlreadyRegistered": "E-mail is al geregistreerd.",
|
||||
"emailNotRegistered": "E-mail niet geregistreerd.",
|
||||
"email": "E-mail",
|
||||
"cancel": "Annuleer",
|
||||
"verify": "Verifiëren",
|
||||
@ -185,6 +187,8 @@
|
||||
},
|
||||
"allowAddPhotosDescription": "Sta toe dat mensen met de link ook foto's kunnen toevoegen aan het gedeelde album.",
|
||||
"passwordLock": "Wachtwoord slot",
|
||||
"canNotOpenTitle": "Kan dit album niet openen",
|
||||
"canNotOpenBody": "Sorry, dit album kan niet worden geopend in de app.",
|
||||
"disableDownloadWarningTitle": "Let op",
|
||||
"disableDownloadWarningBody": "Kijkers kunnen nog steeds screenshots maken of een kopie van je foto's opslaan met behulp van externe tools",
|
||||
"allowDownloads": "Downloads toestaan",
|
||||
@ -1378,6 +1382,7 @@
|
||||
"extraPhotosFound": "Extra foto's gevonden",
|
||||
"configuration": "Configuratie",
|
||||
"localIndexing": "Lokaal indexeren",
|
||||
"processed": "Verwerkt",
|
||||
"resetPerson": "Verwijderen",
|
||||
"areYouSureYouWantToResetThisPerson": "Weet u zeker dat u deze persoon wilt resetten?",
|
||||
"allPersonGroupingWillReset": "Alle groepen voor deze persoon worden gereset, en je verliest alle suggesties die voor deze persoon zijn gedaan",
|
||||
@ -1578,5 +1583,11 @@
|
||||
},
|
||||
"legacyInvite": "{email} heeft je uitgenodigd om een vertrouwd contact te zijn",
|
||||
"authToManageLegacy": "Verifieer om je vertrouwde contacten te beheren",
|
||||
"useDifferentPlayerInfo": "Problemen met het afspelen van deze video? Hier ingedrukt houden om een andere speler te proberen."
|
||||
"useDifferentPlayerInfo": "Problemen met het afspelen van deze video? Hier ingedrukt houden om een andere speler te proberen.",
|
||||
"hideSharedItemsFromHomeGallery": "Verberg gedeelde bestanden uit de galerij",
|
||||
"gallery": "Galerij",
|
||||
"joinAlbum": "Deelnemen aan album",
|
||||
"joinAlbumSubtext": "om je foto's te bekijken en toe te voegen",
|
||||
"joinAlbumSubtextViewer": "om dit aan gedeelde albums toe te voegen",
|
||||
"join": "Deelnemen"
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
"@@locale ": "en",
|
||||
"enterYourEmailAddress": "Introduceți adresa de e-mail",
|
||||
"accountWelcomeBack": "Bine ați revenit!",
|
||||
"emailAlreadyRegistered": "E-mail deja înregistrat.",
|
||||
"emailNotRegistered": "E-mailul nu este înregistrat.",
|
||||
"email": "E-mail",
|
||||
"cancel": "Anulare",
|
||||
"verify": "Verificare",
|
||||
@ -185,6 +187,8 @@
|
||||
},
|
||||
"allowAddPhotosDescription": "Permiteți persoanelor care au linkul să adauge și fotografii la albumul distribuit.",
|
||||
"passwordLock": "Blocare cu parolă",
|
||||
"canNotOpenTitle": "Nu se poate deschide acest album",
|
||||
"canNotOpenBody": "Ne pare rău, acest album nu poate fi deschis în aplicație.",
|
||||
"disableDownloadWarningTitle": "Rețineți",
|
||||
"disableDownloadWarningBody": "Observatorii pot să facă capturi de ecran sau să salveze o copie a fotografiilor dvs. folosind instrumente externe",
|
||||
"allowDownloads": "Permiteți descărcările",
|
||||
@ -351,6 +355,7 @@
|
||||
"failedToLoadAlbums": "Încărcarea albumelor nu a reușit",
|
||||
"hidden": "Ascunse",
|
||||
"authToViewYourHiddenFiles": "Vă rugăm să vă autentificați pentru a vedea fișierele ascunse",
|
||||
"authToViewTrashedFiles": "Vă rugăm să vă autentificați pentru a vedea fișierele din coșul de gunoi",
|
||||
"trash": "Coș de gunoi",
|
||||
"uncategorized": "Necategorisite",
|
||||
"videoSmallCase": "videoclip",
|
||||
@ -412,6 +417,7 @@
|
||||
"description": "The text to display in the advanced settings section"
|
||||
},
|
||||
"photoGridSize": "Dimensiunea grilei foto",
|
||||
"manageDeviceStorage": "Gestionați memoria cache a dispozitivului",
|
||||
"manageDeviceStorageDesc": "Revizuiți și ștergeți spațiul din memoria cache locală.",
|
||||
"machineLearning": "Învățare automată",
|
||||
"mlConsent": "Activați învățarea automată",
|
||||
@ -688,6 +694,8 @@
|
||||
"noPhotosAreBeingBackedUpRightNow": "Nicio fotografie nu este salvată în acest moment",
|
||||
"preserveMore": "Păstrați mai multe",
|
||||
"grantFullAccessPrompt": "Vă rugăm să permiteți accesul la toate fotografiile în aplicația Setări",
|
||||
"allowPermTitle": "Permiteți accesul la fotografii",
|
||||
"allowPermBody": "Vă rugăm să permiteți accesul la fotografiile dvs. din Setări, astfel încât Ente să vă poată afișa și salva biblioteca.",
|
||||
"openSettings": "Deschideți Setări",
|
||||
"selectMorePhotos": "Selectați mai multe fotografii",
|
||||
"existingUser": "Utilizator existent",
|
||||
@ -1090,6 +1098,83 @@
|
||||
"description": "Label of confirm button to add a new custom radius to the radius selector of a location tag"
|
||||
},
|
||||
"setRadius": "Setare rază",
|
||||
"familyPlanPortalTitle": "Familie",
|
||||
"familyPlanOverview": "Adăugați 5 membri ai familiei la planul dvs. existent fără a plăti suplimentar.\n\nFiecare membru primește propriul spațiu privat și nu poate vedea fișierele celuilalt decât dacă acestea sunt partajate.\n\nPlanurile de familie sunt disponibile pentru clienții care au un abonament Ente plătit.\n\nAbonați-vă acum pentru a începe!",
|
||||
"androidBiometricHint": "Verificați-vă identitatea",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Neidentificat. Încercați din nou.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "Succes",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "Anulare",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "Autentificare necesară",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricRequiredTitle": "Biometrice necesare",
|
||||
"@androidBiometricRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsRequiredTitle": "Sunt necesare acreditările dispozitivului",
|
||||
"@androidDeviceCredentialsRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsSetupDescription": "Sunt necesare acreditările dispozitivului",
|
||||
"@androidDeviceCredentialsSetupDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"goToSettings": "Mergeți la setări",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
},
|
||||
"androidGoToSettingsDescription": "Autentificarea biometrică nu este configurată pe dispozitivul dvs. Mergeți la „Setări > Securitate” pentru a adăuga autentificarea biometrică.",
|
||||
"@androidGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"iOSLockOut": "Autentificarea biometrică este dezactivată. Vă rugăm să blocați și să deblocați ecranul pentru a o activa.",
|
||||
"@iOSLockOut": {
|
||||
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSGoToSettingsDescription": "Autentificarea biometrică nu este configurată pe dispozitivul dvs. Vă rugăm să activați Touch ID sau Face ID pe telefonul dvs.",
|
||||
"@iOSGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSOkButton": "OK",
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"openstreetmapContributors": "Contribuitori OpenStreetMap",
|
||||
"hostedAtOsmFrance": "Găzduit la OSM Franţa",
|
||||
"map": "Hartă",
|
||||
"@map": {
|
||||
"description": "Label for the map view"
|
||||
},
|
||||
"maps": "Hărţi",
|
||||
"enableMaps": "Activare hărți",
|
||||
"enableMapsDesc": "Se va afișa fotografiile dvs. pe o hartă a lumii.\n\nAceastă hartă este găzduită de Open Street Map, iar locațiile exacte ale fotografiilor dvs. nu sunt niciodată partajate.\n\nPuteți dezactiva această funcție oricând din Setări.",
|
||||
"quickLinks": "Link-uri rapide",
|
||||
"selectItemsToAdd": "Selectați elementele de adăugat",
|
||||
"addSelected": "Adăugați selectate",
|
||||
"addFromDevice": "Adăugați de pe dispozitiv",
|
||||
"addPhotos": "Adăugați fotografii",
|
||||
"noPhotosFoundHere": "Nu s-au găsit fotografii aici",
|
||||
"zoomOutToSeePhotos": "Micșorați pentru a vedea fotografiile",
|
||||
"noImagesWithLocation": "Nicio imagine cu locație",
|
||||
"unpinAlbum": "Anulați fixarea albumului",
|
||||
"pinAlbum": "Fixați albumul",
|
||||
"create": "Creare",
|
||||
"viewAll": "Vizualizați tot",
|
||||
"nothingSharedWithYouYet": "Nimic distribuit cu dvs. încă",
|
||||
"noAlbumsSharedByYouYet": "Niciun album nu a fost distribuit de dvs. încă",
|
||||
"sharedWithYou": "Distribuite cu dvs.",
|
||||
"sharedByYou": "Distribuite de dvs.",
|
||||
"inviteYourFriendsToEnte": "Invitați-vă prietenii la Ente",
|
||||
@ -1152,6 +1237,21 @@
|
||||
"changeLocationOfSelectedItems": "Schimbați locația articolelor selectate?",
|
||||
"editsToLocationWillOnlyBeSeenWithinEnte": "Editările locației vor fi vizibile doar pe Ente",
|
||||
"cleanUncategorized": "Curățare Necategorisite",
|
||||
"cleanUncategorizedDescription": "Eliminați toate fișierele din „Fără categorie” care sunt prezente în alte albume",
|
||||
"waitingForVerification": "Se așteaptă verificarea...",
|
||||
"passkey": "Cheie de acces",
|
||||
"passkeyAuthTitle": "Verificare cheie de acces",
|
||||
"loginWithTOTP": "Autentificare cu parolă unică (TOTP)",
|
||||
"passKeyPendingVerification": "Verificarea este încă în așteptare",
|
||||
"loginSessionExpired": "Sesiune expirată",
|
||||
"loginSessionExpiredDetails": "Sesiunea a expirat. Vă rugăm să vă autentificați din nou.",
|
||||
"verifyPasskey": "Verificați cheia de acces",
|
||||
"playOnTv": "Redare album pe TV",
|
||||
"pair": "Asociere",
|
||||
"deviceNotFound": "Dispozitivul nu a fost găsit",
|
||||
"castInstruction": "Accesați cast.ente.io de pe dispozitivul pe care doriți să îl asociați.\n\nIntroduceți codul de mai jos pentru a reda albumul pe TV.",
|
||||
"deviceCodeHint": "Introduceți codul",
|
||||
"joinDiscord": "Alăturați-vă pe Discord",
|
||||
"locations": "Locații",
|
||||
"addAName": "Adăugați un nume",
|
||||
"findThemQuickly": "Găsiți rapid",
|
||||
@ -1225,5 +1325,269 @@
|
||||
"panorama": "Panoramă",
|
||||
"reenterPassword": "Reintroduceți parola",
|
||||
"reenterPin": "Reintroduceți codul PIN",
|
||||
"deviceLock": "Blocare dispozitiv"
|
||||
"deviceLock": "Blocare dispozitiv",
|
||||
"pinLock": "Blocare PIN",
|
||||
"next": "Înainte",
|
||||
"setNewPassword": "Setați parola noua",
|
||||
"enterPin": "Introduceţi codul PIN",
|
||||
"setNewPin": "Setați un cod nou PIN",
|
||||
"appLock": "Blocare aplicație",
|
||||
"noSystemLockFound": "Nu s-a găsit nicio blocare de sistem",
|
||||
"tapToUnlock": "Atingeți pentru a debloca",
|
||||
"tooManyIncorrectAttempts": "Prea multe încercări incorecte",
|
||||
"videoInfo": "Informaţii video",
|
||||
"autoLock": "Blocare automată",
|
||||
"immediately": "Imediat",
|
||||
"autoLockFeatureDescription": "Timpul după care aplicația se blochează după ce a fost pusă în fundal",
|
||||
"hideContent": "Ascundeți conținutul",
|
||||
"hideContentDescriptionAndroid": "Ascunde conținutul aplicației în comutatorul de aplicații și dezactivează capturile de ecran",
|
||||
"hideContentDescriptionIos": "Ascunde conținutul aplicației în comutatorul de aplicații",
|
||||
"passwordStrengthInfo": "Puterea parolei este calculată luând în considerare lungimea parolei, caracterele utilizate și dacă parola apare sau nu în top 10.000 cele mai utilizate parole",
|
||||
"noQuickLinksSelected": "Nu au fost găsite linkuri rapide",
|
||||
"pleaseSelectQuickLinksToRemove": "Vă rugăm să selectați linkurile rapide de eliminat",
|
||||
"removePublicLinks": "Eliminați linkurile publice",
|
||||
"thisWillRemovePublicLinksOfAllSelectedQuickLinks": "Se vor elimina linkurile publice ale linkurilor rapide selectate.",
|
||||
"guestView": "Mod oaspete",
|
||||
"guestViewEnablePreSteps": "Pentru a activa modul oaspete, vă rugăm să configurați codul de acces al dispozitivului sau blocarea ecranului în setările sistemului.",
|
||||
"nameTheAlbum": "Denumiți albumul",
|
||||
"collectPhotosDescription": "Creați un link unde prietenii dvs. pot încărca fotografii la calitatea originală.",
|
||||
"collect": "Colectare",
|
||||
"appLockDescriptions": "Alegeți între ecranul de blocare implicit al dispozitivului dvs. și un ecran de blocare personalizat cu PIN sau parolă.",
|
||||
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pentru a activa blocarea aplicației, vă rugăm să configurați codul de acces al dispozitivului sau blocarea ecranului în setările sistemului.",
|
||||
"authToViewPasskey": "Vă rugăm să vă autentificați pentru a vizualiza cheia de acces",
|
||||
"loopVideoOn": "Repetare video activată",
|
||||
"loopVideoOff": "Repetare video dezactivată",
|
||||
"localSyncErrorMessage": "Se pare că ceva nu a mers bine, deoarece sincronizarea fotografiilor locale durează mai mult decât ne așteptam. Vă rugăm să contactați echipa noastră de asistență",
|
||||
"showPerson": "Afișare persoană",
|
||||
"sort": "Sortare",
|
||||
"mostRecent": "Cele mai recente",
|
||||
"mostRelevant": "Cele mai relevante",
|
||||
"loadingYourPhotos": "Se încarcă fotografiile dvs...",
|
||||
"processingImport": "Se procesează {folderName}...",
|
||||
"personName": "Numele persoanei",
|
||||
"addNewPerson": "Adăugare persoană nouă",
|
||||
"addNameOrMerge": "Adăugare nume sau îmbinare",
|
||||
"mergeWithExisting": "Îmbinare cu unul existent",
|
||||
"newPerson": "Persoană nouă",
|
||||
"addName": "Adăugare nume",
|
||||
"add": "Adăugare",
|
||||
"extraPhotosFoundFor": "S-au găsit fotografii extra pentru {text}",
|
||||
"@extraPhotosFoundFor": {
|
||||
"placeholders": {
|
||||
"text": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extraPhotosFound": "S-au găsit fotografii extra",
|
||||
"configuration": "Configurare",
|
||||
"localIndexing": "Indexare locală",
|
||||
"processed": "Procesate",
|
||||
"resetPerson": "Eliminare",
|
||||
"areYouSureYouWantToResetThisPerson": "Sunteți sigur că doriți să resetaţi această persoană?",
|
||||
"allPersonGroupingWillReset": "Toate grupările pentru această persoană vor fi resetate și veți pierde toate sugestiile făcute pentru această persoană",
|
||||
"yesResetPerson": "Da, resetează persoana",
|
||||
"onlyThem": "Numai el/ea",
|
||||
"checkingModels": "Se verifică modelele...",
|
||||
"enableMachineLearningBanner": "Activați învățarea automată pentru a folosi căutarea magică și recunoașterea facială",
|
||||
"searchDiscoverEmptySection": "Imaginile vor fi afișate aici odată ce procesarea și sincronizarea este completă",
|
||||
"searchPersonsEmptySection": "Persoanele vor fi afișate aici odată ce procesarea și sincronizarea este completă",
|
||||
"viewersSuccessfullyAdded": "{count, plural, one {} few {S-au adăugat {count} observatori}=0 {S-au adăugat 0 observatori} =1 {S-a adăugat 1 observator} other {S-au adăugat {count} de observatori}}",
|
||||
"@viewersSuccessfullyAdded": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int",
|
||||
"example": "2"
|
||||
}
|
||||
},
|
||||
"description": "Number of viewers that were successfully added to an album."
|
||||
},
|
||||
"collaboratorsSuccessfullyAdded": "{count, plural, one {} few {S-au adăugat {count} colaboratori}=0 {S-au adăugat 0 colaboratori} =1 {S-a adăugat 1 colaborator} other {S-au adăugat {count} de colaboratori}}",
|
||||
"@collaboratorsSuccessfullyAdded": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int",
|
||||
"example": "2"
|
||||
}
|
||||
},
|
||||
"description": "Number of collaborators that were successfully added to an album."
|
||||
},
|
||||
"accountIsAlreadyConfigured": "Contul este deja configurat.",
|
||||
"sessionIdMismatch": "Nepotrivire ID sesiune",
|
||||
"@sessionIdMismatch": {
|
||||
"description": "In passkey page, deeplink is ignored because of session ID mismatch."
|
||||
},
|
||||
"failedToFetchActiveSessions": "Nu s-a reușit preluarea sesiunilor active",
|
||||
"@failedToFetchActiveSessions": {
|
||||
"description": "In session page, warn user (in toast) that active sessions could not be fetched."
|
||||
},
|
||||
"failedToRefreshStripeSubscription": "Nu s-a reușit reîmprospătarea abonamentului",
|
||||
"failedToPlayVideo": "Eroare la redarea videoclipului",
|
||||
"uploadIsIgnoredDueToIgnorereason": "Încărcare ignorată din motivul {ignoreReason}",
|
||||
"@uploadIsIgnoredDueToIgnorereason": {
|
||||
"placeholders": {
|
||||
"ignoreReason": {
|
||||
"type": "String",
|
||||
"example": "no network"
|
||||
}
|
||||
}
|
||||
},
|
||||
"typeOfGallerGallerytypeIsNotSupportedForRename": "Tipul de galerie {galleryType} nu este acceptat pentru redenumire",
|
||||
"@typeOfGallerGallerytypeIsNotSupportedForRename": {
|
||||
"placeholders": {
|
||||
"galleryType": {
|
||||
"type": "String",
|
||||
"example": "no network"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tapToUploadIsIgnoredDue": "Atingeți pentru a încărca, încărcarea este ignorată în prezent datorită {ignoreReason}",
|
||||
"@tapToUploadIsIgnoredDue": {
|
||||
"description": "Shown in upload icon widet, inside a tooltip.",
|
||||
"placeholders": {
|
||||
"ignoreReason": {
|
||||
"type": "String",
|
||||
"example": "no network"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tapToUpload": "Atingeți pentru a încărca",
|
||||
"@tapToUpload": {
|
||||
"description": "Shown in upload icon widet, inside a tooltip."
|
||||
},
|
||||
"info": "Informații",
|
||||
"addFiles": "Adăugați fișiere",
|
||||
"castAlbum": "Difuzați albumul",
|
||||
"imageNotAnalyzed": "Imaginea nu a fost analizată",
|
||||
"noFacesFound": "Nu au fost găsite fețe",
|
||||
"fileNotUploadedYet": "Fișierul nu a fost încărcat încă",
|
||||
"noSuggestionsForPerson": "Nicio sugestie pentru {personName}",
|
||||
"@noSuggestionsForPerson": {
|
||||
"placeholders": {
|
||||
"personName": {
|
||||
"type": "String",
|
||||
"example": "Alice"
|
||||
}
|
||||
}
|
||||
},
|
||||
"month": "lună",
|
||||
"yearShort": "an",
|
||||
"@yearShort": {
|
||||
"description": "Appears in pricing page (/yr)"
|
||||
},
|
||||
"currentlyRunning": "rulează în prezent",
|
||||
"ignored": "ignorat",
|
||||
"photosCount": "{count, plural, one {} few {{count} fotografii}=0 {0 fotografii} =1 {1 fotografie} other {{count} de fotografii}}",
|
||||
"@photosCount": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int",
|
||||
"example": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"file": "Fișier",
|
||||
"searchSectionsLengthMismatch": "Lungimea secțiunilor nu se potrivesc: {snapshotLength} != {searchLength}",
|
||||
"@searchSectionsLengthMismatch": {
|
||||
"description": "Appears in search tab page",
|
||||
"placeholders": {
|
||||
"snapshotLength": {
|
||||
"type": "int",
|
||||
"example": "1"
|
||||
},
|
||||
"searchLength": {
|
||||
"type": "int",
|
||||
"example": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"selectMailApp": "Selectați aplicația de e-mail",
|
||||
"selectAllShort": "Toate",
|
||||
"@selectAllShort": {
|
||||
"description": "Text that appears in bottom right when you start to select multiple photos. When clicked, it selects all photos."
|
||||
},
|
||||
"changeLogMagicSearchImprovementTitle": "Îmbunătățire a căutării magice",
|
||||
"changeLogMagicSearchImprovementContent": "Am îmbunătățit căutarea magică pentru a deveni mult mai rapidă, astfel încât să nu trebuiască să așteptați pentru a găsi ceea ce căutați.",
|
||||
"changeLogBackupStatusTitle": "Starea copiei de rezervă",
|
||||
"changeLogBackupStatusContent": "Am adăugat un jurnal al tuturor fișierelor care au fost încărcate pe Ente, inclusiv eșecurile și coada de așteptare.",
|
||||
"changeLogDiscoverTitle": "Descoperire",
|
||||
"changeLogDiscoverContent": "Căutați fotografii ale cărților de identitate, notițe sau chiar meme-uri? Mergeți la fila de căutare și dați o privire la Descoperire. Bazat pe căutarea noastră semantică, este un loc în care puteți găsi fotografii care ar putea fi importante pentru dvs.\\n\\nEste disponibilă numai dacă ați activat învățarea automată.",
|
||||
"selectCoverPhoto": "Selectați fotografia de copertă",
|
||||
"newLocation": "Locație nouă",
|
||||
"faceNotClusteredYet": "Fața nu este încă grupată, vă rugăm să reveniți mai târziu",
|
||||
"theLinkYouAreTryingToAccessHasExpired": "Linkul pe care încercați să îl accesați a expirat.",
|
||||
"openFile": "Deschidere fișier",
|
||||
"backupFile": "Salvare fișier",
|
||||
"openAlbumInBrowser": "Deschideți albumul în browser",
|
||||
"openAlbumInBrowserTitle": "Vă rugăm să utilizați aplicația web pentru a adăuga fotografii la acest album",
|
||||
"allow": "Permiteți",
|
||||
"allowAppToOpenSharedAlbumLinks": "Permiteți aplicației să deschidă link-uri de album partajate",
|
||||
"seePublicAlbumLinksInApp": "Vedeți linkurile albumelor publice în aplicație",
|
||||
"emergencyContacts": "Contacte de urgență",
|
||||
"acceptTrustInvite": "Acceptați invitația",
|
||||
"declineTrustInvite": "Refuzați invitația",
|
||||
"removeYourselfAsTrustedContact": "Eliminați-vă ca persoană de contact de încredere",
|
||||
"legacy": "Moștenire",
|
||||
"legacyPageDesc": "Moștenirea permite contactelor de încredere să vă acceseze contul în absența dvs.",
|
||||
"legacyPageDesc2": "Persoanele de contact de încredere pot iniția recuperarea contului și, dacă nu este blocată în termen de 30 de zile, vă pot reseta parola și accesa contul.",
|
||||
"legacyAccounts": "Conturi de moștenire",
|
||||
"trustedContacts": "Contacte de încredere",
|
||||
"addTrustedContact": "Adăugare contact de încredere",
|
||||
"removeInvite": "Eliminare invitație",
|
||||
"recoveryWarning": "Un contact de încredere încearcă să vă acceseze contul",
|
||||
"rejectRecovery": "Respingeți recuperarea",
|
||||
"recoveryInitiated": "Recuperare inițiată",
|
||||
"recoveryInitiatedDesc": "Puteți accesa contul după {days} zile. O notificare va fi trimisă la {email}.",
|
||||
"@recoveryInitiatedDesc": {
|
||||
"placeholders": {
|
||||
"days": {
|
||||
"type": "int",
|
||||
"example": "30"
|
||||
},
|
||||
"email": {
|
||||
"type": "String",
|
||||
"example": "me@example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"cancelAccountRecovery": "Anulare recuperare",
|
||||
"recoveryAccount": "Recuperare cont",
|
||||
"cancelAccountRecoveryBody": "Sunteți sigur că doriți să anulați recuperarea?",
|
||||
"startAccountRecoveryTitle": "Începeți recuperarea",
|
||||
"whyAddTrustContact": "Contactul de încredere vă poate ajuta la recuperarea datelor.",
|
||||
"recoveryReady": "Acum puteți recupera contul {email} setând o nouă parolă.",
|
||||
"@recoveryReady": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String",
|
||||
"example": "me@example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"recoveryWarningBody": "{email} încearcă să vă recupereze contul.",
|
||||
"trustedInviteBody": "Ați fost învitat să fiți un contact de moștenire de către {email}.",
|
||||
"warning": "Atenție",
|
||||
"proceed": "Continuați",
|
||||
"confirmAddingTrustedContact": "Sunteți pe cale să adăugați {email} ca persoană de contact de încredere. Acesta va putea să vă recupereze contul dacă lipsiți timp de {numOfDays} de zile.",
|
||||
"@confirmAddingTrustedContact": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String",
|
||||
"example": "me@example.com"
|
||||
},
|
||||
"numOfDays": {
|
||||
"type": "int",
|
||||
"example": "30"
|
||||
}
|
||||
}
|
||||
},
|
||||
"legacyInvite": "{email} v-a invitat să fiți un contact de încredere",
|
||||
"authToManageLegacy": "Vă rugăm să vă autentificați pentru a gestiona contactele de încredere",
|
||||
"useDifferentPlayerInfo": "Aveți probleme cu redarea acestui videoclip? Apăsați lung aici pentru a încerca un alt player.",
|
||||
"hideSharedItemsFromHomeGallery": "Ascundeți elementele distribuite din galeria principală",
|
||||
"gallery": "Galerie",
|
||||
"joinAlbum": "Alăturați-vă albumului",
|
||||
"joinAlbumSubtext": "pentru a vedea și a adăuga fotografii",
|
||||
"joinAlbumSubtextViewer": "pentru a adăuga la albumele distribuite",
|
||||
"join": "Alăturare"
|
||||
}
|
@ -7,7 +7,5 @@ String twoFactorTypeToString(TwoFactorType type) {
|
||||
return "totp";
|
||||
case TwoFactorType.passkey:
|
||||
return "passkey";
|
||||
default:
|
||||
return type.name;
|
||||
}
|
||||
}
|
||||
|
@ -93,8 +93,6 @@ enum SideDataType {
|
||||
switch (this) {
|
||||
case SideDataType.displayMatrix:
|
||||
return 'Display Matrix';
|
||||
default:
|
||||
assert(false, 'Unknown side data type: $this');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,10 @@
|
||||
|
||||
import "dart:developer";
|
||||
|
||||
import "package:collection/collection.dart";
|
||||
import "package:intl/intl.dart";
|
||||
import "package:photos/models/ffmpeg/channel_layouts.dart";
|
||||
import "package:photos/models/ffmpeg/codecs.dart";
|
||||
import "package:photos/models/ffmpeg/ffprobe_keys.dart";
|
||||
import "package:photos/models/ffmpeg/language.dart";
|
||||
import "package:photos/models/ffmpeg/mp4.dart";
|
||||
import "package:photos/models/location/location.dart";
|
||||
|
||||
@ -344,12 +342,6 @@ class FFProbeProps {
|
||||
return value;
|
||||
}
|
||||
|
||||
static String _formatLanguage(String value) {
|
||||
final language = Language.living639_2
|
||||
.firstWhereOrNull((language) => language.iso639_2 == value);
|
||||
return language?.native ?? value;
|
||||
}
|
||||
|
||||
static final _durationHmsmPattern = RegExp(r'(\d+):(\d+):(\d+)(.\d+)');
|
||||
static final _durationSmPattern = RegExp(r'(\d+)(.\d+)');
|
||||
static final _locationPattern = RegExp(r'([+-][.0-9]+)');
|
||||
|
@ -267,7 +267,9 @@ Map<LocationTag, int> _getLocationTagsToOccurenceForIsolate(
|
||||
for (EnteFile file in files) {
|
||||
if (file.uploadedFileID == null ||
|
||||
file.uploadedFileID == -1 ||
|
||||
!file.hasLocation) continue;
|
||||
!file.hasLocation) {
|
||||
continue;
|
||||
}
|
||||
for (LocalEntity<LocationTag> locationTagEntity in locationTagEntities) {
|
||||
final locationTag = locationTagEntity.item;
|
||||
final fileCoordinates = file.location!;
|
||||
|
@ -3,7 +3,6 @@ import "dart:developer";
|
||||
import "dart:typed_data" show Uint8List;
|
||||
|
||||
import "package:computer/computer.dart";
|
||||
import "package:flutter/foundation.dart" show kDebugMode;
|
||||
import "package:logging/logging.dart";
|
||||
import "package:ml_linalg/dtype.dart";
|
||||
import "package:ml_linalg/vector.dart";
|
||||
@ -400,7 +399,8 @@ ClusteringResult runLinearClustering(Map args) {
|
||||
} else {
|
||||
thresholdValue = distanceThreshold;
|
||||
}
|
||||
final bool faceHasBeenRejectedBefore = sortedFaceInfos[i].rejectedClusterIds != null;
|
||||
final bool faceHasBeenRejectedBefore =
|
||||
sortedFaceInfos[i].rejectedClusterIds != null;
|
||||
if (i % 250 == 0) {
|
||||
_logger.info("Processed ${offset != null ? i + offset : i} faces");
|
||||
}
|
||||
@ -416,8 +416,8 @@ ClusteringResult runLinearClustering(Map args) {
|
||||
if (faceHasBeenRejectedBefore &&
|
||||
sortedFaceInfos[j].clusterId != null &&
|
||||
sortedFaceInfos[i].rejectedClusterIds!.contains(
|
||||
sortedFaceInfos[j].clusterId!,
|
||||
)) {
|
||||
sortedFaceInfos[j].clusterId!,
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
closestDistance = distance;
|
||||
@ -736,62 +736,3 @@ Map<String, (Uint8List, int)> _updateClusterSummaries({
|
||||
|
||||
return newClusterSummaries;
|
||||
}
|
||||
|
||||
void _analyzeClusterResults(List<FaceInfo> sortedFaceInfos) {
|
||||
if (!kDebugMode) return;
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
final Map<String, String> faceIdToCluster = {};
|
||||
for (final faceInfo in sortedFaceInfos) {
|
||||
faceIdToCluster[faceInfo.faceID] = faceInfo.clusterId!;
|
||||
}
|
||||
|
||||
// Find faceIDs that are part of a cluster which is larger than 5 and are new faceIDs
|
||||
final Map<String, int> clusterIdToSize = {};
|
||||
faceIdToCluster.forEach((key, value) {
|
||||
if (clusterIdToSize.containsKey(value)) {
|
||||
clusterIdToSize[value] = clusterIdToSize[value]! + 1;
|
||||
} else {
|
||||
clusterIdToSize[value] = 1;
|
||||
}
|
||||
});
|
||||
|
||||
// print top 10 cluster ids and their sizes based on the internal cluster id
|
||||
final clusterIds = faceIdToCluster.values.toSet();
|
||||
final clusterSizes = clusterIds.map((clusterId) {
|
||||
return faceIdToCluster.values.where((id) => id == clusterId).length;
|
||||
}).toList();
|
||||
clusterSizes.sort();
|
||||
// find clusters whose size is greater than 1
|
||||
int oneClusterCount = 0;
|
||||
int moreThan5Count = 0;
|
||||
int moreThan10Count = 0;
|
||||
int moreThan20Count = 0;
|
||||
int moreThan50Count = 0;
|
||||
int moreThan100Count = 0;
|
||||
|
||||
for (int i = 0; i < clusterSizes.length; i++) {
|
||||
if (clusterSizes[i] > 100) {
|
||||
moreThan100Count++;
|
||||
} else if (clusterSizes[i] > 50) {
|
||||
moreThan50Count++;
|
||||
} else if (clusterSizes[i] > 20) {
|
||||
moreThan20Count++;
|
||||
} else if (clusterSizes[i] > 10) {
|
||||
moreThan10Count++;
|
||||
} else if (clusterSizes[i] > 5) {
|
||||
moreThan5Count++;
|
||||
} else if (clusterSizes[i] == 1) {
|
||||
oneClusterCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// print the metrics
|
||||
log(
|
||||
"[ClusterIsolate] Total clusters ${clusterIds.length}: \n oneClusterCount $oneClusterCount \n moreThan5Count $moreThan5Count \n moreThan10Count $moreThan10Count \n moreThan20Count $moreThan20Count \n moreThan50Count $moreThan50Count \n moreThan100Count $moreThan100Count",
|
||||
);
|
||||
stopwatch.stop();
|
||||
log(
|
||||
"[ClusterIsolate] Clustering additional analysis took ${stopwatch.elapsedMilliseconds} ms",
|
||||
);
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ extension FaceDirectionExtension on FaceDirection {
|
||||
return 'Right';
|
||||
case FaceDirection.straight:
|
||||
return 'Straight';
|
||||
default:
|
||||
throw Exception('Unknown FaceDirection');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ import "package:photos/core/event_bus.dart";
|
||||
import "package:photos/events/machine_learning_control_event.dart";
|
||||
|
||||
class MachineLearningController {
|
||||
MachineLearningController._privateConstructor();
|
||||
|
||||
final _logger = Logger("MachineLearningController");
|
||||
|
||||
static const kMaximumTemperature = 42; // 42 degree celsius
|
||||
|
@ -58,7 +58,9 @@ class MLService {
|
||||
Future<void> init() async {
|
||||
if (_isInitialized) return;
|
||||
if (!userRemoteFlagService
|
||||
.getCachedBoolValue(UserRemoteFlagService.mlEnabled)) return;
|
||||
.getCachedBoolValue(UserRemoteFlagService.mlEnabled)) {
|
||||
return;
|
||||
}
|
||||
_logger.info("init called");
|
||||
|
||||
// Check if the device has enough RAM to run local indexing
|
||||
@ -72,7 +74,9 @@ class MLService {
|
||||
// Listen on MachineLearningController
|
||||
Bus.instance.on<MachineLearningControlEvent>().listen((event) {
|
||||
if (!userRemoteFlagService
|
||||
.getCachedBoolValue(UserRemoteFlagService.mlEnabled)) return;
|
||||
.getCachedBoolValue(UserRemoteFlagService.mlEnabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_mlControllerStatus = event.shouldRun;
|
||||
if (_mlControllerStatus) {
|
||||
|
@ -213,7 +213,9 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
Future<void> _onTap() async {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {
|
||||
return;
|
||||
}
|
||||
_debouncer.run(
|
||||
() => Future(
|
||||
() {
|
||||
@ -250,7 +252,9 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
void _onTapDown(details) {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
if (widget.pressedColor == null) {
|
||||
hasPassedGestureCallbacks()
|
||||
@ -270,7 +274,9 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
void _onTapUp(details) {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {
|
||||
return;
|
||||
}
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
() => setState(() {
|
||||
@ -281,7 +287,9 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
|
||||
void _onCancel() {
|
||||
if (executionStateNotifier.value == ExecutionState.inProgress ||
|
||||
executionStateNotifier.value == ExecutionState.successful) return;
|
||||
executionStateNotifier.value == ExecutionState.successful) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
menuItemColor = widget.menuItemColor;
|
||||
});
|
||||
|