resolve conflicts and merge main
This commit is contained in:
commit
faede193b1
24 changed files with 513 additions and 101 deletions
9
lib/generated/intl/messages_en.dart
generated
9
lib/generated/intl/messages_en.dart
generated
|
@ -187,6 +187,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
static String m59(count) =>
|
||||
"${Intl.plural(count, zero: '', one: '1 day', other: '${count} days')}";
|
||||
|
||||
static String m64(endDate) => "Valid till ${endDate}";
|
||||
|
||||
static String m60(email) => "Verify ${email}";
|
||||
|
||||
static String m61(email) => "We have sent a mail to <green>${email}</green>";
|
||||
|
@ -218,6 +220,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"addLocation": MessageLookupByLibrary.simpleMessage("Add location"),
|
||||
"addLocationButton": MessageLookupByLibrary.simpleMessage("Add"),
|
||||
"addMore": MessageLookupByLibrary.simpleMessage("Add more"),
|
||||
"addOnPageSubtitle":
|
||||
MessageLookupByLibrary.simpleMessage("Details of add-ons"),
|
||||
"addOns": MessageLookupByLibrary.simpleMessage("Add-ons"),
|
||||
"addPhotos": MessageLookupByLibrary.simpleMessage("Add photos"),
|
||||
"addSelected": MessageLookupByLibrary.simpleMessage("Add selected"),
|
||||
"addToAlbum": MessageLookupByLibrary.simpleMessage("Add to album"),
|
||||
|
@ -696,8 +701,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Group nearby photos"),
|
||||
"hearUsExplanation": MessageLookupByLibrary.simpleMessage(
|
||||
"We don\'t track app installs. It\'d help if you told us where you found us!"),
|
||||
"hearUsHint": MessageLookupByLibrary.simpleMessage(
|
||||
"friend, reddit, ad, search, etc."),
|
||||
"hearUsWhereTitle": MessageLookupByLibrary.simpleMessage(
|
||||
"How did you hear about Ente? (optional)"),
|
||||
"hidden": MessageLookupByLibrary.simpleMessage("Hidden"),
|
||||
|
@ -1345,6 +1348,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"useSelectedPhoto":
|
||||
MessageLookupByLibrary.simpleMessage("Use selected photo"),
|
||||
"usedSpace": MessageLookupByLibrary.simpleMessage("Used space"),
|
||||
"validTill": m64,
|
||||
"verificationFailedPleaseTryAgain":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Verification failed, please try again"),
|
||||
|
@ -1362,6 +1366,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"videoSmallCase": MessageLookupByLibrary.simpleMessage("video"),
|
||||
"viewActiveSessions":
|
||||
MessageLookupByLibrary.simpleMessage("View active sessions"),
|
||||
"viewAddOnButton": MessageLookupByLibrary.simpleMessage("View add-ons"),
|
||||
"viewAll": MessageLookupByLibrary.simpleMessage("View all"),
|
||||
"viewAllExifData":
|
||||
MessageLookupByLibrary.simpleMessage("View all EXIF data"),
|
||||
|
|
12
lib/generated/intl/messages_it.dart
generated
12
lib/generated/intl/messages_it.dart
generated
|
@ -187,6 +187,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
static String m59(count) =>
|
||||
"${Intl.plural(count, zero: '', one: '1 giorno', other: '${count} giorni')}";
|
||||
|
||||
static String m64(endDate) => "Valido fino al ${endDate}";
|
||||
|
||||
static String m60(email) => "Verifica ${email}";
|
||||
|
||||
static String m61(email) =>
|
||||
|
@ -220,6 +222,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"addLocation": MessageLookupByLibrary.simpleMessage("Aggiungi luogo"),
|
||||
"addLocationButton": MessageLookupByLibrary.simpleMessage("Aggiungi"),
|
||||
"addMore": MessageLookupByLibrary.simpleMessage("Aggiungi altri"),
|
||||
"addOnPageSubtitle": MessageLookupByLibrary.simpleMessage(
|
||||
"Dettagli dei componenti aggiuntivi"),
|
||||
"addOns": MessageLookupByLibrary.simpleMessage("Componenti aggiuntivi"),
|
||||
"addPhotos": MessageLookupByLibrary.simpleMessage("Aggiungi foto"),
|
||||
"addSelected":
|
||||
MessageLookupByLibrary.simpleMessage("Aggiungi selezionate"),
|
||||
|
@ -712,6 +717,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Concedi il permesso"),
|
||||
"groupNearbyPhotos": MessageLookupByLibrary.simpleMessage(
|
||||
"Raggruppa foto nelle vicinanze"),
|
||||
"hearUsExplanation": MessageLookupByLibrary.simpleMessage(
|
||||
"Non teniamo traccia del numero di installazioni dell\'app. Sarebbe utile se ci dicesse dove ci ha trovato!"),
|
||||
"hearUsWhereTitle": MessageLookupByLibrary.simpleMessage(
|
||||
"Come hai sentito parlare di Ente? (opzionale)"),
|
||||
"hidden": MessageLookupByLibrary.simpleMessage("Nascosti"),
|
||||
"hide": MessageLookupByLibrary.simpleMessage("Nascondi"),
|
||||
"hiding": MessageLookupByLibrary.simpleMessage("Nascondendo..."),
|
||||
|
@ -1378,6 +1387,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"useSelectedPhoto":
|
||||
MessageLookupByLibrary.simpleMessage("Usa la foto selezionata"),
|
||||
"usedSpace": MessageLookupByLibrary.simpleMessage("Spazio utilizzato"),
|
||||
"validTill": m64,
|
||||
"verificationFailedPleaseTryAgain":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Verifica fallita, per favore prova di nuovo"),
|
||||
|
@ -1396,6 +1406,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"videoSmallCase": MessageLookupByLibrary.simpleMessage("video"),
|
||||
"viewActiveSessions":
|
||||
MessageLookupByLibrary.simpleMessage("Visualizza sessioni attive"),
|
||||
"viewAddOnButton": MessageLookupByLibrary.simpleMessage(
|
||||
"Visualizza componenti aggiuntivi"),
|
||||
"viewAll": MessageLookupByLibrary.simpleMessage("Visualizza tutte"),
|
||||
"viewAllExifData":
|
||||
MessageLookupByLibrary.simpleMessage("Mostra tutti i dati EXIF"),
|
||||
|
|
10
lib/generated/intl/messages_zh.dart
generated
10
lib/generated/intl/messages_zh.dart
generated
|
@ -170,6 +170,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
static String m59(count) =>
|
||||
"${Intl.plural(count, zero: '', one: '1天', other: '${count} 天')}";
|
||||
|
||||
static String m64(endDate) => "有效期至 ${endDate}";
|
||||
|
||||
static String m60(email) => "验证 ${email}";
|
||||
|
||||
static String m61(email) => "我们已经发送邮件到 <green>${email}</green>";
|
||||
|
@ -196,6 +198,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"addLocation": MessageLookupByLibrary.simpleMessage("添加地点"),
|
||||
"addLocationButton": MessageLookupByLibrary.simpleMessage("添加"),
|
||||
"addMore": MessageLookupByLibrary.simpleMessage("添加更多"),
|
||||
"addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("附加组件详情"),
|
||||
"addOns": MessageLookupByLibrary.simpleMessage("附加组件"),
|
||||
"addPhotos": MessageLookupByLibrary.simpleMessage("添加照片"),
|
||||
"addSelected": MessageLookupByLibrary.simpleMessage("添加所选项"),
|
||||
"addToAlbum": MessageLookupByLibrary.simpleMessage("添加到相册"),
|
||||
|
@ -582,6 +586,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("请在“设置”应用中将权限更改为允许访问所有所有照片"),
|
||||
"grantPermission": MessageLookupByLibrary.simpleMessage("授予权限"),
|
||||
"groupNearbyPhotos": MessageLookupByLibrary.simpleMessage("将附近的照片分组"),
|
||||
"hearUsExplanation": MessageLookupByLibrary.simpleMessage(
|
||||
"我们不跟踪应用程序安装情况。如果您告诉我们您是在哪里找到我们的,将会有所帮助!"),
|
||||
"hearUsWhereTitle":
|
||||
MessageLookupByLibrary.simpleMessage("您是如何知道Ente的? (可选的)"),
|
||||
"hidden": MessageLookupByLibrary.simpleMessage("已隐藏"),
|
||||
"hide": MessageLookupByLibrary.simpleMessage("隐藏"),
|
||||
"hiding": MessageLookupByLibrary.simpleMessage("正在隐藏..."),
|
||||
|
@ -1109,6 +1117,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"useRecoveryKey": MessageLookupByLibrary.simpleMessage("使用恢复密钥"),
|
||||
"useSelectedPhoto": MessageLookupByLibrary.simpleMessage("使用所选照片"),
|
||||
"usedSpace": MessageLookupByLibrary.simpleMessage("已用空间"),
|
||||
"validTill": m64,
|
||||
"verificationFailedPleaseTryAgain":
|
||||
MessageLookupByLibrary.simpleMessage("验证失败,请重试"),
|
||||
"verificationId": MessageLookupByLibrary.simpleMessage("验证 ID"),
|
||||
|
@ -1122,6 +1131,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("正在验证恢复密钥..."),
|
||||
"videoSmallCase": MessageLookupByLibrary.simpleMessage("视频"),
|
||||
"viewActiveSessions": MessageLookupByLibrary.simpleMessage("查看活动会话"),
|
||||
"viewAddOnButton": MessageLookupByLibrary.simpleMessage("查看附加组件"),
|
||||
"viewAll": MessageLookupByLibrary.simpleMessage("查看全部"),
|
||||
"viewAllExifData": MessageLookupByLibrary.simpleMessage("查看所有 EXIF 数据"),
|
||||
"viewLogs": MessageLookupByLibrary.simpleMessage("查看日志"),
|
||||
|
|
50
lib/generated/l10n.dart
generated
50
lib/generated/l10n.dart
generated
|
@ -3914,6 +3914,16 @@ class S {
|
|||
);
|
||||
}
|
||||
|
||||
/// `Valid till {endDate}`
|
||||
String validTill(Object endDate) {
|
||||
return Intl.message(
|
||||
'Valid till $endDate',
|
||||
name: 'validTill',
|
||||
desc: '',
|
||||
args: [endDate],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Free trial valid till {endDate}.\nYou can choose a paid plan afterwards.`
|
||||
String playStoreFreeTrialValidTill(Object endDate) {
|
||||
return Intl.message(
|
||||
|
@ -7835,16 +7845,6 @@ class S {
|
|||
);
|
||||
}
|
||||
|
||||
/// `friend, reddit, ad, search, etc.`
|
||||
String get hearUsHint {
|
||||
return Intl.message(
|
||||
'friend, reddit, ad, search, etc.',
|
||||
name: 'hearUsHint',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `We don't track app installs. It'd help if you told us where you found us!`
|
||||
String get hearUsExplanation {
|
||||
return Intl.message(
|
||||
|
@ -7854,6 +7854,36 @@ class S {
|
|||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `View add-ons`
|
||||
String get viewAddOnButton {
|
||||
return Intl.message(
|
||||
'View add-ons',
|
||||
name: 'viewAddOnButton',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Add-ons`
|
||||
String get addOns {
|
||||
return Intl.message(
|
||||
'Add-ons',
|
||||
name: 'addOns',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Details of add-ons`
|
||||
String get addOnPageSubtitle {
|
||||
return Intl.message(
|
||||
'Details of add-ons',
|
||||
name: 'addOnPageSubtitle',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
|
|
@ -557,6 +557,7 @@
|
|||
"faqs": "FAQs",
|
||||
"renewsOn": "Renews on {endDate}",
|
||||
"freeTrialValidTill": "Free trial valid till {endDate}",
|
||||
"validTill": "Valid till {endDate}",
|
||||
"playStoreFreeTrialValidTill": "Free trial valid till {endDate}.\nYou can choose a paid plan afterwards.",
|
||||
"subWillBeCancelledOn": "Your subscription will be cancelled on {endDate}",
|
||||
"subscription": "Subscription",
|
||||
|
@ -1116,5 +1117,8 @@
|
|||
"fileTypes": "File types",
|
||||
"deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.",
|
||||
"hearUsWhereTitle": "How did you hear about Ente? (optional)",
|
||||
"hearUsExplanation": "We don't track app installs. It'd help if you told us where you found us!"
|
||||
}
|
||||
"hearUsExplanation": "We don't track app installs. It'd help if you told us where you found us!",
|
||||
"viewAddOnButton": "View add-ons",
|
||||
"addOns": "Add-ons",
|
||||
"addOnPageSubtitle": "Details of add-ons"
|
||||
}
|
||||
|
|
|
@ -557,6 +557,7 @@
|
|||
"faqs": "FAQ",
|
||||
"renewsOn": "Si rinnova il {endDate}",
|
||||
"freeTrialValidTill": "La prova gratuita termina il {endDate}",
|
||||
"validTill": "Valido fino al {endDate}",
|
||||
"playStoreFreeTrialValidTill": "Prova gratuita valida fino al {endDate}.\nPuoi scegliere un piano a pagamento in seguito.",
|
||||
"subWillBeCancelledOn": "L'abbonamento verrà cancellato il {endDate}",
|
||||
"subscription": "Abbonamento",
|
||||
|
@ -1102,6 +1103,10 @@
|
|||
"crashReporting": "Segnalazione di crash",
|
||||
"addToHiddenAlbum": "Aggiungi ad album nascosto",
|
||||
"moveToHiddenAlbum": "Sposta in album nascosto",
|
||||
"fileTypes": "File types",
|
||||
"deleteConfirmDialogBody": "Questo account è collegato ad altre app di ente, se ne utilizzi.\\n\\nI tuoi dati caricati, su tutte le app di ente, saranno pianificati per la cancellazione e il tuo account verrà eliminato definitivamente."
|
||||
"deleteConfirmDialogBody": "Questo account è collegato ad altre app di ente, se ne utilizzi.\\n\\nI tuoi dati caricati, su tutte le app di ente, saranno pianificati per la cancellazione e il tuo account verrà eliminato definitivamente.",
|
||||
"hearUsWhereTitle": "Come hai sentito parlare di Ente? (opzionale)",
|
||||
"hearUsExplanation": "Non teniamo traccia del numero di installazioni dell'app. Sarebbe utile se ci dicesse dove ci ha trovato!",
|
||||
"viewAddOnButton": "Visualizza componenti aggiuntivi",
|
||||
"addOns": "Componenti aggiuntivi",
|
||||
"addOnPageSubtitle": "Dettagli dei componenti aggiuntivi"
|
||||
}
|
|
@ -557,6 +557,7 @@
|
|||
"faqs": "常见问题",
|
||||
"renewsOn": "在 {endDate} 前续费",
|
||||
"freeTrialValidTill": "免费试用有效期至 {endDate}",
|
||||
"validTill": "有效期至 {endDate}",
|
||||
"playStoreFreeTrialValidTill": "免费试用有效期至 {endDate}。\n之后您可以选择付费计划。",
|
||||
"subWillBeCancelledOn": "您的订阅将于 {endDate} 取消",
|
||||
"subscription": "订阅",
|
||||
|
@ -1102,6 +1103,10 @@
|
|||
"crashReporting": "崩溃报告",
|
||||
"addToHiddenAlbum": "添加到隐藏相册",
|
||||
"moveToHiddenAlbum": "移至隐藏相册",
|
||||
"fileTypes": "File types",
|
||||
"deleteConfirmDialogBody": "此账户已链接到其他 ente 旗下的应用程序(如果您使用任何 ente 旗下的应用程序)。\\n\\n您在所有 ente 旗下的应用程序中上传的数据将被安排删除,并且您的账户将被永久删除。"
|
||||
"deleteConfirmDialogBody": "此账户已链接到其他 ente 旗下的应用程序(如果您使用任何 ente 旗下的应用程序)。\\n\\n您在所有 ente 旗下的应用程序中上传的数据将被安排删除,并且您的账户将被永久删除。",
|
||||
"hearUsWhereTitle": "您是如何知道Ente的? (可选的)",
|
||||
"hearUsExplanation": "我们不跟踪应用程序安装情况。如果您告诉我们您是在哪里找到我们的,将会有所帮助!",
|
||||
"viewAddOnButton": "查看附加组件",
|
||||
"addOns": "附加组件",
|
||||
"addOnPageSubtitle": "附加组件详情"
|
||||
}
|
60
lib/models/api/storage_bonus/bonus.dart
Normal file
60
lib/models/api/storage_bonus/bonus.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
class Bonus {
|
||||
int storage;
|
||||
String type;
|
||||
int validTill;
|
||||
bool isRevoked;
|
||||
|
||||
Bonus(this.storage, this.type, this.validTill, this.isRevoked);
|
||||
|
||||
factory Bonus.fromJson(Map<String, dynamic> json) {
|
||||
return Bonus(
|
||||
json['storage'],
|
||||
json['type'],
|
||||
json['validTill'],
|
||||
json['isRevoked'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'storage': storage,
|
||||
'type': type,
|
||||
'validTill': validTill,
|
||||
'isRevoked': isRevoked,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class BonusData {
|
||||
static Set<String> signUpBonusTypes = {'SIGN_UP', 'REFERRAL'};
|
||||
final List<Bonus> storageBonuses;
|
||||
|
||||
BonusData(this.storageBonuses);
|
||||
|
||||
List<Bonus> getAddOnBonuses() {
|
||||
return storageBonuses
|
||||
.where((b) => !signUpBonusTypes.contains(b.type))
|
||||
.toList();
|
||||
}
|
||||
|
||||
int totalAddOnBonus() {
|
||||
return getAddOnBonuses().fold(0, (sum, bonus) => sum + bonus.storage);
|
||||
}
|
||||
|
||||
factory BonusData.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null || json['storageBonuses'] == null) {
|
||||
return BonusData([]);
|
||||
}
|
||||
return BonusData(
|
||||
(json['storageBonuses'] as List)
|
||||
.map((bonus) => Bonus.fromJson(bonus))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'storageBonuses': storageBonuses.map((bonus) => bonus.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
|
||||
class ReferralView {
|
||||
PlanInfo planInfo;
|
||||
String code;
|
||||
|
@ -86,34 +88,6 @@ class ReferralStat {
|
|||
}
|
||||
}
|
||||
|
||||
class Bonus {
|
||||
int storage;
|
||||
String type;
|
||||
int validTill;
|
||||
bool isRevoked;
|
||||
|
||||
Bonus(this.storage, this.type, this.validTill, this.isRevoked);
|
||||
|
||||
// fromJson
|
||||
factory Bonus.fromJson(Map<String, dynamic> json) {
|
||||
return Bonus(
|
||||
json['storage'],
|
||||
json['type'],
|
||||
json['validTill'],
|
||||
json['isRevoked'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'storage': storage,
|
||||
'type': type,
|
||||
'validTill': validTill,
|
||||
'isRevoked': isRevoked,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class BonusDetails {
|
||||
List<ReferralStat> referralStats;
|
||||
List<Bonus> bonuses;
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
import 'package:photos/models/file/file_type.dart';
|
||||
import 'package:photos/models/subscription.dart';
|
||||
|
||||
|
@ -14,6 +15,7 @@ class UserDetails {
|
|||
final Subscription subscription;
|
||||
final FamilyData? familyData;
|
||||
final ProfileData? profileData;
|
||||
final BonusData? bonusData;
|
||||
|
||||
const UserDetails(
|
||||
this.email,
|
||||
|
@ -24,6 +26,7 @@ class UserDetails {
|
|||
this.subscription,
|
||||
this.familyData,
|
||||
this.profileData,
|
||||
this.bonusData,
|
||||
);
|
||||
|
||||
bool isPartOfFamily() {
|
||||
|
@ -55,6 +58,12 @@ class UserDetails {
|
|||
storageBonus;
|
||||
}
|
||||
|
||||
// This is the total storage for which user has paid for.
|
||||
int getPlanPlusAddonStorage() {
|
||||
return (isPartOfFamily() ? familyData!.storage : subscription.storage) +
|
||||
bonusData!.totalAddOnBonus();
|
||||
}
|
||||
|
||||
factory UserDetails.fromMap(Map<String, dynamic> map) {
|
||||
return UserDetails(
|
||||
map['email'] as String,
|
||||
|
@ -65,6 +74,7 @@ class UserDetails {
|
|||
Subscription.fromMap(map['subscription']),
|
||||
FamilyData.fromMap(map['familyData']),
|
||||
ProfileData.fromJson(map['profileData']),
|
||||
BonusData.fromJson(map['bonusData']),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -78,6 +88,7 @@ class UserDetails {
|
|||
'subscription': subscription.toMap(),
|
||||
'familyData': familyData?.toMap(),
|
||||
'profileData': profileData?.toJson(),
|
||||
'bonusData': bonusData?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -123,6 +134,7 @@ class FamilyMember {
|
|||
factory FamilyMember.fromJson(String source) =>
|
||||
FamilyMember.fromMap(json.decode(source));
|
||||
}
|
||||
|
||||
class ProfileData {
|
||||
bool canDisableEmailMFA;
|
||||
bool isEmailMFAEnabled;
|
||||
|
@ -135,7 +147,6 @@ class ProfileData {
|
|||
this.isTwoFactorEnabled = false,
|
||||
});
|
||||
|
||||
|
||||
// Factory method to create ProfileData instance from JSON
|
||||
factory ProfileData.fromJson(Map<String, dynamic>? json) {
|
||||
return ProfileData(
|
||||
|
@ -153,6 +164,7 @@ class ProfileData {
|
|||
'isTwoFactorEnabled': isTwoFactorEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
String toJsonString() => json.encode(toJson());
|
||||
}
|
||||
|
||||
|
|
|
@ -679,33 +679,23 @@ class UserService {
|
|||
} on DioError catch (e, s) {
|
||||
await dialog.hide();
|
||||
if (e.response != null && e.response!.statusCode == 401) {
|
||||
final dialogChoice = await showChoiceDialog(
|
||||
await _showContactSupportDialog(
|
||||
context,
|
||||
title: S.of(context).incorrectPasswordTitle,
|
||||
body: S.of(context).pleaseTryAgain,
|
||||
firstButtonLabel: S.of(context).contactSupport,
|
||||
secondButtonLabel: S.of(context).ok,
|
||||
S.of(context).incorrectPasswordTitle,
|
||||
S.of(context).pleaseTryAgain,
|
||||
);
|
||||
if (dialogChoice!.action == ButtonAction.first) {
|
||||
await sendLogs(
|
||||
context,
|
||||
S.of(context).contactSupport,
|
||||
"support@ente.io",
|
||||
postShare: () {},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_logger.fine('failed to verify password', e, s);
|
||||
await showErrorDialog(
|
||||
_logger.severe('failed to verify password', e, s);
|
||||
await _showContactSupportDialog(
|
||||
context,
|
||||
S.of(context).oops,
|
||||
S.of(context).verificationFailedPleaseTryAgain,
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
_logger.fine('failed to verify password', e, s);
|
||||
_logger.severe('failed to verify password', e, s);
|
||||
await dialog.hide();
|
||||
await showErrorDialog(
|
||||
await _showContactSupportDialog(
|
||||
context,
|
||||
S.of(context).oops,
|
||||
S.of(context).verificationFailedPleaseTryAgain,
|
||||
|
@ -1174,4 +1164,26 @@ class UserService {
|
|||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showContactSupportDialog(
|
||||
BuildContext context,
|
||||
String title,
|
||||
String message,
|
||||
) async {
|
||||
final dialogChoice = await showChoiceDialog(
|
||||
context,
|
||||
title: title,
|
||||
body: message,
|
||||
firstButtonLabel: S.of(context).contactSupport,
|
||||
secondButtonLabel: S.of(context).ok,
|
||||
);
|
||||
if (dialogChoice!.action == ButtonAction.first) {
|
||||
await sendLogs(
|
||||
context,
|
||||
S.of(context).contactSupport,
|
||||
"support@ente.io",
|
||||
postShare: () {},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,12 +122,14 @@ class _StorageDetailsScreenState extends State<StorageDetailsScreen> {
|
|||
leftValue: convertBytesToAbsoluteGBs(
|
||||
min(
|
||||
widget.referralView.claimedStorage,
|
||||
widget.userDetails.getTotalStorage(),
|
||||
widget.userDetails
|
||||
.getPlanPlusAddonStorage(),
|
||||
),
|
||||
),
|
||||
leftUnitName: "GB",
|
||||
rightValue: convertBytesToAbsoluteGBs(
|
||||
widget.userDetails.getTotalStorage(),
|
||||
widget.userDetails
|
||||
.getPlanPlusAddonStorage(),
|
||||
),
|
||||
rightUnitName: "GB",
|
||||
),
|
||||
|
|
123
lib/ui/payment/add_on_page.dart
Normal file
123
lib/ui/payment/add_on_page.dart
Normal file
|
@ -0,0 +1,123 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:intl/intl.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import 'package:photos/ui/components/buttons/icon_button_widget.dart';
|
||||
import "package:photos/ui/components/title_bar_title_widget.dart";
|
||||
import "package:photos/ui/components/title_bar_widget.dart";
|
||||
import "package:photos/utils/data_util.dart";
|
||||
|
||||
class AddOnPage extends StatelessWidget {
|
||||
final BonusData bonusData;
|
||||
|
||||
const AddOnPage(this.bonusData, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: CustomScrollView(
|
||||
primary: false,
|
||||
slivers: <Widget>[
|
||||
TitleBarWidget(
|
||||
flexibleSpaceTitle: TitleBarTitleWidget(
|
||||
title: S.of(context).addOns,
|
||||
),
|
||||
flexibleSpaceCaption: S.of(context).addOnPageSubtitle,
|
||||
actionIcons: [
|
||||
IconButtonWidget(
|
||||
icon: Icons.close_outlined,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(delegateBuildContext, index) {
|
||||
Bonus bonus = bonusData.getAddOnBonuses()[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: AddOnViewSection(
|
||||
sectionName: bonus.type == 'ADD_ON_BF_2023'
|
||||
? "Black friday 2023"
|
||||
: bonus.type.replaceAll('_', ' '),
|
||||
bonus: bonus,
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: bonusData?.getAddOnBonuses().length ?? 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AddOnViewSection extends StatelessWidget {
|
||||
final String sectionName;
|
||||
final Bonus bonus;
|
||||
|
||||
const AddOnViewSection({
|
||||
super.key,
|
||||
required this.sectionName,
|
||||
required this.bonus,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
final textStyle = getEnteTextTheme(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
sectionName,
|
||||
style: textStyle.body.copyWith(
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
),
|
||||
if (bonus.validTill != 0)
|
||||
Text(
|
||||
S.of(context).validTill(
|
||||
DateFormat.yMMMd(
|
||||
Localizations.localeOf(context).languageCode,
|
||||
)
|
||||
.format(
|
||||
DateTime.fromMicrosecondsSinceEpoch(
|
||||
bonus.validTill,
|
||||
),
|
||||
)
|
||||
.toString(),
|
||||
),
|
||||
style: textStyle.body.copyWith(
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: convertBytesToReadableFormat(bonus.storage).toString(),
|
||||
style: textStyle.h3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ import 'package:photos/ui/payment/child_subscription_widget.dart';
|
|||
import 'package:photos/ui/payment/skip_subscription_widget.dart';
|
||||
import 'package:photos/ui/payment/subscription_common_widgets.dart';
|
||||
import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
||||
import "package:photos/ui/payment/view_add_on_widget.dart";
|
||||
import "package:photos/utils/data_util.dart";
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
@ -238,7 +240,12 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
|
|||
}
|
||||
|
||||
if (_hasActiveSubscription) {
|
||||
widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
|
||||
widgets.add(
|
||||
ValidityWidget(
|
||||
currentSubscription: _currentSubscription,
|
||||
bonusData: _userDetails.bonusData,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (_currentSubscription!.productID == freeProductID) {
|
||||
|
@ -290,7 +297,7 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
|
|||
if (!widget.isOnboarding) {
|
||||
widgets.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 80),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
|
||||
child: MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: _isFreePlanUser()
|
||||
|
@ -310,6 +317,8 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
|
|||
),
|
||||
),
|
||||
);
|
||||
widgets.add(ViewAddOnButton(_userDetails.bonusData));
|
||||
widgets.add(const SizedBox(height: 80));
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
|
@ -490,7 +499,16 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
|
|||
if (isActive) {
|
||||
return;
|
||||
}
|
||||
if (_userDetails.getFamilyOrPersonalUsage() > plan.storage) {
|
||||
final int addOnBonus =
|
||||
_userDetails.bonusData?.totalAddOnBonus() ?? 0;
|
||||
if (_userDetails.getFamilyOrPersonalUsage() >
|
||||
(plan.storage + addOnBonus)) {
|
||||
_logger.warning(
|
||||
" familyUsage ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage())}"
|
||||
" plan storage ${convertBytesToReadableFormat(plan.storage)} "
|
||||
"addOnBonus ${convertBytesToReadableFormat(addOnBonus)},"
|
||||
"overshooting by ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage() - (plan.storage + addOnBonus))}",
|
||||
);
|
||||
showErrorDialog(
|
||||
context,
|
||||
S.of(context).sorry,
|
||||
|
|
|
@ -25,6 +25,8 @@ import 'package:photos/ui/payment/payment_web_page.dart';
|
|||
import 'package:photos/ui/payment/skip_subscription_widget.dart';
|
||||
import 'package:photos/ui/payment/subscription_common_widgets.dart';
|
||||
import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
||||
import "package:photos/ui/payment/view_add_on_widget.dart";
|
||||
import "package:photos/utils/data_util.dart";
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:step_progress_indicator/step_progress_indicator.dart';
|
||||
|
@ -209,7 +211,10 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
widgets.add(_showSubscriptionToggle());
|
||||
|
||||
if (_hasActiveSubscription) {
|
||||
widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
|
||||
widgets.add(ValidityWidget(
|
||||
currentSubscription: _currentSubscription,
|
||||
bonusData: _userDetails.bonusData,
|
||||
));
|
||||
}
|
||||
|
||||
if (_currentSubscription!.productID == freeProductID) {
|
||||
|
@ -252,7 +257,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
if (!widget.isOnboarding) {
|
||||
widgets.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 80),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
|
||||
child: MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: S.of(context).manageFamily,
|
||||
|
@ -270,6 +275,8 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
),
|
||||
),
|
||||
);
|
||||
widgets.add(ViewAddOnButton(_userDetails.bonusData));
|
||||
widgets.add(const SizedBox(height: 80));
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
|
@ -446,7 +453,16 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (_userDetails.getFamilyOrPersonalUsage() > plan.storage) {
|
||||
final int addOnBonus =
|
||||
_userDetails.bonusData?.totalAddOnBonus() ?? 0;
|
||||
if (_userDetails.getFamilyOrPersonalUsage() >
|
||||
(plan.storage + addOnBonus)) {
|
||||
logger.warning(
|
||||
" familyUsage ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage())}"
|
||||
" plan storage ${convertBytesToReadableFormat(plan.storage)} "
|
||||
"addOnBonus ${convertBytesToReadableFormat(addOnBonus)},"
|
||||
"overshooting by ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage() - (plan.storage + addOnBonus))}",
|
||||
);
|
||||
showErrorDialog(
|
||||
context,
|
||||
S.of(context).sorry,
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import "package:intl/intl.dart";
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
import 'package:photos/models/subscription.dart';
|
||||
import "package:photos/services/update_service.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
|
@ -87,21 +88,27 @@ class _SubscriptionHeaderWidgetState extends State<SubscriptionHeaderWidget> {
|
|||
|
||||
class ValidityWidget extends StatelessWidget {
|
||||
final Subscription? currentSubscription;
|
||||
final BonusData? bonusData;
|
||||
|
||||
const ValidityWidget({Key? key, this.currentSubscription}) : super(key: key);
|
||||
const ValidityWidget({Key? key, this.currentSubscription, this.bonusData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (currentSubscription == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final bool isFreeTrialSub = currentSubscription!.productID == freeProductID;
|
||||
if (isFreeTrialSub && (bonusData?.getAddOnBonuses().isNotEmpty ?? false)) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final endDate =
|
||||
DateFormat.yMMMd(Localizations.localeOf(context).languageCode).format(
|
||||
DateTime.fromMicrosecondsSinceEpoch(currentSubscription!.expiryTime),
|
||||
);
|
||||
|
||||
var message = S.of(context).renewsOn(endDate);
|
||||
if (currentSubscription!.productID == freeProductID) {
|
||||
if (isFreeTrialSub) {
|
||||
message = UpdateService.instance.isPlayStoreFlavor()
|
||||
? S.of(context).playStoreFreeTrialValidTill(endDate)
|
||||
: S.of(context).freeTrialValidTill(endDate);
|
||||
|
|
41
lib/ui/payment/view_add_on_widget.dart
Normal file
41
lib/ui/payment/view_add_on_widget.dart
Normal file
|
@ -0,0 +1,41 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
import "package:photos/theme/colors.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/components/captioned_text_widget.dart";
|
||||
import "package:photos/ui/components/menu_item_widget/menu_item_widget.dart";
|
||||
import "package:photos/ui/payment/add_on_page.dart";
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
|
||||
class ViewAddOnButton extends StatelessWidget {
|
||||
final BonusData? bonusData;
|
||||
|
||||
const ViewAddOnButton(this.bonusData, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (bonusData?.getAddOnBonuses().isEmpty ?? true) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final EnteColorScheme colorScheme = getEnteColorScheme(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 4, 16, 0),
|
||||
child: MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: S.of(context).viewAddOnButton,
|
||||
),
|
||||
menuItemColor: colorScheme.fillFaint,
|
||||
trailingWidget: Icon(
|
||||
Icons.chevron_right_outlined,
|
||||
color: colorScheme.strokeBase,
|
||||
),
|
||||
singleBorderRadius: 4,
|
||||
alignCaptionedTextToLeft: true,
|
||||
onTap: () async {
|
||||
routeToPage(context, AddOnPage(bonusData!));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -8,7 +8,9 @@ import 'package:photos/services/deduplication_service.dart';
|
|||
import 'package:photos/services/sync_service.dart';
|
||||
import 'package:photos/services/update_service.dart';
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
import "package:photos/ui/components/buttons/button_widget.dart";
|
||||
import "package:photos/ui/components/captioned_text_widget.dart";
|
||||
import "package:photos/ui/components/dialog_widget.dart";
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart';
|
||||
import "package:photos/ui/components/models/button_type.dart";
|
||||
|
@ -16,9 +18,10 @@ import 'package:photos/ui/settings/backup/backup_folder_selection_page.dart';
|
|||
import 'package:photos/ui/settings/backup/backup_settings_screen.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/tools/deduplicate_page.dart';
|
||||
import 'package:photos/ui/tools/free_space_page.dart';
|
||||
import "package:photos/ui/tools/free_space_page.dart";
|
||||
import 'package:photos/utils/data_util.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import "package:photos/utils/local_settings.dart";
|
||||
import 'package:photos/utils/navigation_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
|
||||
|
@ -153,25 +156,55 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
|
|||
}
|
||||
|
||||
void _showSpaceFreedDialog(BackupStatus status) {
|
||||
showChoiceDialog(
|
||||
context,
|
||||
title: S.of(context).success,
|
||||
body: S.of(context).youHaveSuccessfullyFreedUp(formatBytes(status.size)),
|
||||
firstButtonLabel: S.of(context).rateUs,
|
||||
firstButtonOnTap: () async {
|
||||
UpdateService.instance.launchReviewUrl();
|
||||
},
|
||||
firstButtonType: ButtonType.primary,
|
||||
secondButtonLabel: S.of(context).ok,
|
||||
secondButtonOnTap: () async {
|
||||
if (Platform.isIOS) {
|
||||
showToast(
|
||||
context,
|
||||
S.of(context).remindToEmptyDeviceTrash,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
if (LocalSettings.instance.shouldPromptToRateUs()) {
|
||||
LocalSettings.instance.setRateUsShownCount(
|
||||
LocalSettings.instance.getRateUsShownCount() + 1,
|
||||
);
|
||||
showChoiceDialog(
|
||||
context,
|
||||
title: S.of(context).success,
|
||||
body:
|
||||
S.of(context).youHaveSuccessfullyFreedUp(formatBytes(status.size)),
|
||||
firstButtonLabel: S.of(context).rateUs,
|
||||
firstButtonOnTap: () async {
|
||||
UpdateService.instance.launchReviewUrl();
|
||||
},
|
||||
firstButtonType: ButtonType.primary,
|
||||
secondButtonLabel: S.of(context).ok,
|
||||
secondButtonOnTap: () async {
|
||||
if (Platform.isIOS) {
|
||||
showToast(
|
||||
context,
|
||||
S.of(context).remindToEmptyDeviceTrash,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
showDialogWidget(
|
||||
context: context,
|
||||
title: S.of(context).success,
|
||||
body:
|
||||
S.of(context).youHaveSuccessfullyFreedUp(formatBytes(status.size)),
|
||||
icon: Icons.download_done_rounded,
|
||||
isDismissible: true,
|
||||
buttons: [
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.neutral,
|
||||
labelText: S.of(context).ok,
|
||||
isInAlert: true,
|
||||
onTap: () async {
|
||||
if (Platform.isIOS) {
|
||||
showToast(
|
||||
context,
|
||||
S.of(context).remindToEmptyDeviceTrash,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _showDuplicateFilesDeletedDialog(DeduplicationResult result) {
|
||||
|
|
|
@ -164,7 +164,6 @@ class _DetailPageState extends State<DetailPage> {
|
|||
}
|
||||
|
||||
Widget _buildPageView(BuildContext context) {
|
||||
final bottomPadding = MediaQuery.of(context).padding.bottom;
|
||||
return PageView.builder(
|
||||
itemBuilder: (context, index) {
|
||||
final file = _files![index];
|
||||
|
|
|
@ -11,6 +11,7 @@ import "package:photos/models/file/extensions/file_props.dart";
|
|||
import 'package:photos/models/file/file.dart';
|
||||
import "package:photos/services/feature_flag_service.dart";
|
||||
import 'package:photos/services/files_service.dart';
|
||||
import "package:photos/ui/actions/file/file_actions.dart";
|
||||
import 'package:photos/ui/viewer/file/thumbnail_widget.dart';
|
||||
import 'package:photos/ui/viewer/file/video_controls.dart';
|
||||
import "package:photos/utils/dialog_util.dart";
|
||||
|
@ -184,7 +185,14 @@ class _VideoWidgetState extends State<VideoWidget> {
|
|||
final contentWithDetector = GestureDetector(
|
||||
child: content,
|
||||
onVerticalDragUpdate: (d) => {
|
||||
if (d.delta.dy > dragSensitivity) {Navigator.of(context).pop()},
|
||||
if (d.delta.dy > dragSensitivity)
|
||||
{
|
||||
Navigator.of(context).pop(),
|
||||
}
|
||||
else if (d.delta.dy < (dragSensitivity * -1))
|
||||
{
|
||||
showDetailsSheet(context, widget.file),
|
||||
},
|
||||
},
|
||||
);
|
||||
return VisibilityDetector(
|
||||
|
|
|
@ -12,6 +12,7 @@ import "package:photos/models/file/file.dart";
|
|||
import "package:photos/services/files_service.dart";
|
||||
import "package:photos/theme/colors.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/actions/file/file_actions.dart";
|
||||
import "package:photos/ui/viewer/file/thumbnail_widget.dart";
|
||||
import "package:photos/utils/dialog_util.dart";
|
||||
import "package:photos/utils/file_util.dart";
|
||||
|
@ -133,7 +134,14 @@ class _VideoWidgetNewState extends State<VideoWidgetNew>
|
|||
fullscreen: const MaterialVideoControlsThemeData(),
|
||||
child: GestureDetector(
|
||||
onVerticalDragUpdate: (d) => {
|
||||
if (d.delta.dy > dragSensitivity) {Navigator.of(context).pop()},
|
||||
if (d.delta.dy > dragSensitivity)
|
||||
{
|
||||
Navigator.of(context).pop(),
|
||||
}
|
||||
else if (d.delta.dy < (dragSensitivity * -1))
|
||||
{
|
||||
showDetailsSheet(context, widget.file),
|
||||
},
|
||||
},
|
||||
child: Center(
|
||||
child: controller != null
|
||||
|
|
|
@ -16,6 +16,7 @@ import "package:photos/models/file/extensions/file_props.dart";
|
|||
import 'package:photos/models/file/file.dart';
|
||||
import "package:photos/models/metadata/file_magic.dart";
|
||||
import "package:photos/services/file_magic_service.dart";
|
||||
import "package:photos/ui/actions/file/file_actions.dart";
|
||||
import 'package:photos/ui/common/loading_widget.dart';
|
||||
import 'package:photos/utils/file_util.dart';
|
||||
import 'package:photos/utils/image_util.dart';
|
||||
|
@ -111,8 +112,17 @@ class _ZoomableImageState extends State<ZoomableImage>
|
|||
final GestureDragUpdateCallback? verticalDragCallback = _isZooming
|
||||
? null
|
||||
: (d) => {
|
||||
if (!_isZooming && d.delta.dy > dragSensitivity)
|
||||
{Navigator.of(context).pop()},
|
||||
if (!_isZooming)
|
||||
{
|
||||
if (d.delta.dy > dragSensitivity)
|
||||
{
|
||||
{Navigator.of(context).pop()},
|
||||
}
|
||||
else if (d.delta.dy < (dragSensitivity * -1))
|
||||
{
|
||||
showDetailsSheet(context, widget.photo),
|
||||
},
|
||||
},
|
||||
};
|
||||
return GestureDetector(
|
||||
onVerticalDragUpdate: verticalDragCallback,
|
||||
|
|
|
@ -13,6 +13,8 @@ class LocalSettings {
|
|||
static final LocalSettings instance = LocalSettings._privateConstructor();
|
||||
static const kCollectionSortPref = "collection_sort_pref";
|
||||
static const kPhotoGridSize = "photo_grid_size";
|
||||
static const kRateUsShownCount = "rate_us_shown_count";
|
||||
static const kRateUsPromptThreshold = 2;
|
||||
|
||||
late SharedPreferences _prefs;
|
||||
|
||||
|
@ -39,4 +41,20 @@ class LocalSettings {
|
|||
Future<void> setPhotoGridSize(int value) async {
|
||||
await _prefs.setInt(kPhotoGridSize, value);
|
||||
}
|
||||
|
||||
int getRateUsShownCount() {
|
||||
if (_prefs.containsKey(kRateUsShownCount)) {
|
||||
return _prefs.getInt(kRateUsShownCount)!;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setRateUsShownCount(int value) async {
|
||||
await _prefs.setInt(kRateUsShownCount, value);
|
||||
}
|
||||
|
||||
bool shouldPromptToRateUs() {
|
||||
return getRateUsShownCount() < kRateUsPromptThreshold;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ description: ente photos application
|
|||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
|
||||
version: 0.7.105+505
|
||||
version: 0.7.108+508
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
@ -148,7 +148,7 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/ente-io/packages.git
|
||||
ref: android_video_roation_fix
|
||||
path: packages/video_player/video_player/p
|
||||
path: packages/video_player/video_player/
|
||||
video_thumbnail: ^0.5.3
|
||||
visibility_detector: ^0.3.3
|
||||
wakelock_plus: ^1.1.1
|
||||
|
|
Loading…
Reference in a new issue