Setup common accounts package
This commit is contained in:
committed by
AmanRajSinghMourya
parent
0b766415a4
commit
d227a2bf20
@@ -1,74 +1 @@
|
||||
# For more linters, we can check https://dart-lang.github.io/linter/lints/index.html
|
||||
# or https://pub.dev/packages/lint (Effective dart)
|
||||
# use "flutter analyze ." or "dart analyze ." for running lint checks
|
||||
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
linter:
|
||||
rules:
|
||||
# Ref https://github.com/flutter/packages/blob/master/packages/flutter_lints/lib/flutter.yaml
|
||||
# Ref https://dart-lang.github.io/linter/lints/
|
||||
- avoid_print
|
||||
- avoid_unnecessary_containers
|
||||
- avoid_web_libraries_in_flutter
|
||||
- no_logic_in_create_state
|
||||
- prefer_const_constructors
|
||||
- prefer_const_constructors_in_immutables
|
||||
- prefer_const_declarations
|
||||
- prefer_const_literals_to_create_immutables
|
||||
- prefer_final_locals
|
||||
- require_trailing_commas
|
||||
- sized_box_for_whitespace
|
||||
- use_full_hex_values_for_flutter_colors
|
||||
- use_key_in_widget_constructors
|
||||
- cancel_subscriptions
|
||||
|
||||
|
||||
- avoid_empty_else
|
||||
- exhaustive_cases
|
||||
|
||||
# just style suggestions
|
||||
- sort_pub_dependencies
|
||||
- use_rethrow_when_possible
|
||||
- prefer_double_quotes
|
||||
- directives_ordering
|
||||
- always_use_package_imports
|
||||
- sort_child_properties_last
|
||||
- unawaited_futures
|
||||
|
||||
analyzer:
|
||||
errors:
|
||||
avoid_empty_else: error
|
||||
exhaustive_cases: error
|
||||
curly_braces_in_flow_control_structures: error
|
||||
directives_ordering: error
|
||||
require_trailing_commas: error
|
||||
always_use_package_imports: warning
|
||||
prefer_final_fields: error
|
||||
unused_import: error
|
||||
camel_case_types: error
|
||||
prefer_is_empty: warning
|
||||
use_rethrow_when_possible: info
|
||||
unused_field: warning
|
||||
use_key_in_widget_constructors: warning
|
||||
sort_child_properties_last: warning
|
||||
sort_pub_dependencies: warning
|
||||
library_private_types_in_public_api: warning
|
||||
constant_identifier_names: ignore
|
||||
prefer_const_constructors: warning
|
||||
prefer_const_declarations: warning
|
||||
prefer_const_constructors_in_immutables: warning
|
||||
prefer_final_locals: warning
|
||||
unnecessary_const: error
|
||||
cancel_subscriptions: error
|
||||
unrelated_type_equality_checks: error
|
||||
unnecessary_cast: info
|
||||
|
||||
|
||||
unawaited_futures: warning # convert to warning after fixing existing issues
|
||||
invalid_dependency: info
|
||||
use_build_context_synchronously: ignore # experimental lint, requires many changes
|
||||
prefer_interpolation_to_compose_strings: ignore # later too many warnings
|
||||
prefer_double_quotes: ignore # too many warnings
|
||||
avoid_renaming_method_parameters: ignore # incorrect warnings for `equals` overrides
|
||||
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
@@ -1,32 +1,3 @@
|
||||
export 'models/bonus.dart';
|
||||
export 'models/delete_account.dart';
|
||||
export 'models/sessions.dart';
|
||||
export 'models/set_keys_request.dart';
|
||||
export 'models/set_recovery_key_request.dart';
|
||||
export 'models/srp.dart';
|
||||
export 'models/subscription.dart';
|
||||
export 'models/two_factor.dart';
|
||||
export 'models/user_details.dart';
|
||||
|
||||
export 'pages/change_email_dialog.dart';
|
||||
export 'pages/delete_account_page.dart';
|
||||
export 'pages/email_entry_page.dart';
|
||||
export 'pages/login_page.dart';
|
||||
export 'pages/login_pwd_verification_page.dart';
|
||||
export 'pages/ott_verification_page.dart';
|
||||
export 'pages/passkey_page.dart';
|
||||
export 'pages/password_entry_page.dart';
|
||||
export 'pages/password_reentry_page.dart';
|
||||
export 'pages/recovery_key_page.dart';
|
||||
export 'pages/recovery_page.dart';
|
||||
export 'pages/request_pwd_verification_page.dart';
|
||||
export 'pages/sessions_page.dart';
|
||||
export 'pages/two_factor_authentication_page.dart';
|
||||
export 'pages/two_factor_recovery_page.dart';
|
||||
|
||||
export 'services/passkey_service.dart';
|
||||
export 'services/user_service.dart';
|
||||
|
||||
/// A Flutter package containing account-related functionality for Ente apps
|
||||
library ente_accounts;
|
||||
|
||||
|
||||
@@ -1,256 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:ente_accounts/models/bonus.dart';
|
||||
import 'package:ente_accounts/models/subscription.dart';
|
||||
|
||||
class UserDetails {
|
||||
final String email;
|
||||
final int usage;
|
||||
final int fileCount;
|
||||
final int storageBonus;
|
||||
final int sharedCollectionsCount;
|
||||
final Subscription subscription;
|
||||
final FamilyData? familyData;
|
||||
final ProfileData? profileData;
|
||||
final BonusData? bonusData;
|
||||
|
||||
const UserDetails(
|
||||
this.email,
|
||||
this.usage,
|
||||
this.fileCount,
|
||||
this.storageBonus,
|
||||
this.sharedCollectionsCount,
|
||||
this.subscription,
|
||||
this.familyData,
|
||||
this.profileData,
|
||||
this.bonusData,
|
||||
);
|
||||
|
||||
bool isPartOfFamily() {
|
||||
return familyData?.members?.isNotEmpty ?? false;
|
||||
}
|
||||
|
||||
bool hasPaidAddon() {
|
||||
return bonusData?.getAddOnBonuses().isNotEmpty ?? false;
|
||||
}
|
||||
|
||||
bool isFamilyAdmin() {
|
||||
assert(isPartOfFamily(), "verify user is part of family before calling");
|
||||
final FamilyMember currentUserMember = familyData!.members!
|
||||
.firstWhere((element) => element.email.trim() == email.trim());
|
||||
return currentUserMember.isAdmin;
|
||||
}
|
||||
|
||||
// getFamilyOrPersonalUsage will return total usage for family if user
|
||||
// belong to family group. Otherwise, it will return storage consumed by
|
||||
// current user
|
||||
int getFamilyOrPersonalUsage() {
|
||||
return isPartOfFamily() ? familyData!.getTotalUsage() : usage;
|
||||
}
|
||||
|
||||
int getFreeStorage() {
|
||||
final int? memberLimit = familyMemberStorageLimit();
|
||||
if (memberLimit != null) {
|
||||
return max(memberLimit - usage, 0);
|
||||
}
|
||||
return max(getTotalStorage() - getFamilyOrPersonalUsage(), 0);
|
||||
}
|
||||
|
||||
// getTotalStorage will return total storage available including the
|
||||
// storage bonus
|
||||
int getTotalStorage() {
|
||||
return (isPartOfFamily() ? familyData!.storage : subscription.storage) +
|
||||
storageBonus;
|
||||
}
|
||||
|
||||
// return the member storage limit if user is part of family and the admin
|
||||
// has set the storage limit for the user.
|
||||
int? familyMemberStorageLimit() {
|
||||
if (isPartOfFamily()) {
|
||||
try {
|
||||
final FamilyMember currentUserMember = familyData!.members!
|
||||
.firstWhere((element) => element.email.trim() == email.trim());
|
||||
return currentUserMember.storageLimit;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 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,
|
||||
map['usage'] as int,
|
||||
(map['fileCount'] ?? 0) as int,
|
||||
(map['storageBonus'] ?? 0) as int,
|
||||
(map['sharedCollectionsCount'] ?? 0) as int,
|
||||
Subscription.fromMap(map['subscription']),
|
||||
FamilyData.fromMap(map['familyData']),
|
||||
ProfileData.fromJson(map['profileData']),
|
||||
BonusData.fromJson(map['bonusData']),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'email': email,
|
||||
'usage': usage,
|
||||
'fileCount': fileCount,
|
||||
'storageBonus': storageBonus,
|
||||
'sharedCollectionsCount': sharedCollectionsCount,
|
||||
'subscription': subscription.toMap(),
|
||||
'familyData': familyData?.toMap(),
|
||||
'profileData': profileData?.toJson(),
|
||||
'bonusData': bonusData?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory UserDetails.fromJson(String source) =>
|
||||
UserDetails.fromMap(json.decode(source));
|
||||
}
|
||||
|
||||
class FamilyMember {
|
||||
final String email;
|
||||
final int usage;
|
||||
final String id;
|
||||
final bool isAdmin;
|
||||
final int? storageLimit;
|
||||
|
||||
FamilyMember(
|
||||
this.email,
|
||||
this.usage,
|
||||
this.id,
|
||||
this.isAdmin,
|
||||
this.storageLimit,
|
||||
);
|
||||
|
||||
factory FamilyMember.fromMap(Map<String, dynamic> map) {
|
||||
return FamilyMember(
|
||||
(map['email'] ?? '') as String,
|
||||
map['usage'] as int,
|
||||
map['id'] as String,
|
||||
map['isAdmin'] as bool,
|
||||
map['storageLimit'] as int?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'email': email,
|
||||
'usage': usage,
|
||||
'id': id,
|
||||
'isAdmin': isAdmin,
|
||||
'storageLimit': storageLimit,
|
||||
};
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory FamilyMember.fromJson(String source) =>
|
||||
FamilyMember.fromMap(json.decode(source));
|
||||
}
|
||||
|
||||
class ProfileData {
|
||||
bool canDisableEmailMFA;
|
||||
bool isEmailMFAEnabled;
|
||||
bool isTwoFactorEnabled;
|
||||
|
||||
// Constructor with default values
|
||||
ProfileData({
|
||||
this.canDisableEmailMFA = false,
|
||||
this.isEmailMFAEnabled = false,
|
||||
this.isTwoFactorEnabled = false,
|
||||
});
|
||||
|
||||
// Factory method to create ProfileData instance from JSON
|
||||
factory ProfileData.fromJson(Map<String, dynamic>? json) {
|
||||
return ProfileData(
|
||||
canDisableEmailMFA: json?['canDisableEmailMFA'] ?? false,
|
||||
isEmailMFAEnabled: json?['isEmailMFAEnabled'] ?? false,
|
||||
isTwoFactorEnabled: json?['isTwoFactorEnabled'] ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
// Method to convert ProfileData instance to JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'canDisableEmailMFA': canDisableEmailMFA,
|
||||
'isEmailMFAEnabled': isEmailMFAEnabled,
|
||||
'isTwoFactorEnabled': isTwoFactorEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
String toJsonString() => json.encode(toJson());
|
||||
}
|
||||
|
||||
class FamilyData {
|
||||
final List<FamilyMember>? members;
|
||||
|
||||
// Storage available based on the family plan
|
||||
final int storage;
|
||||
final int expiryTime;
|
||||
|
||||
FamilyData(
|
||||
this.members,
|
||||
this.storage,
|
||||
this.expiryTime,
|
||||
);
|
||||
|
||||
int getTotalUsage() {
|
||||
return members!
|
||||
.map((e) => e.usage)
|
||||
.toList()
|
||||
.fold(0, (sum, usage) => sum + usage);
|
||||
}
|
||||
|
||||
FamilyMember? getMemberByID(String id) {
|
||||
try {
|
||||
return members!.firstWhere((element) => element.id == id);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static fromMap(Map<String, dynamic>? map) {
|
||||
if (map == null) return null;
|
||||
assert(map['members'] != null && map['members'].length >= 0);
|
||||
final members = List<FamilyMember>.from(
|
||||
map['members'].map((x) => FamilyMember.fromMap(x)),
|
||||
);
|
||||
return FamilyData(
|
||||
members,
|
||||
map['storage'] as int,
|
||||
map['expiryTime'] as int,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'members': members?.map((x) => x.toMap()).toList(),
|
||||
'storage': storage,
|
||||
'expiryTime': expiryTime,
|
||||
};
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory FamilyData.fromJson(String source) =>
|
||||
FamilyData.fromMap(json.decode(source));
|
||||
}
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'bonus.dart';
|
||||
import 'subscription.dart';
|
||||
|
||||
|
||||
@@ -1,85 +1,3 @@
|
||||
import 'package:ente_accounts/ente_accounts.dart';
|
||||
import 'package:ente_strings/ente_strings.dart';
|
||||
import 'package:ente_ui/utils/dialog_util.dart';
|
||||
import 'package:ente_utils/email_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ChangeEmailDialog extends StatefulWidget {
|
||||
const ChangeEmailDialog({super.key});
|
||||
|
||||
@override
|
||||
State<ChangeEmailDialog> createState() => _ChangeEmailDialogState();
|
||||
}
|
||||
|
||||
class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
|
||||
String _email = "";
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(context.strings.enterNewEmailHint),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: context.strings.email,
|
||||
hintStyle: const TextStyle(
|
||||
color: Colors.white30,
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(12),
|
||||
),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_email = value;
|
||||
});
|
||||
},
|
||||
autocorrect: false,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
initialValue: _email,
|
||||
autofocus: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
context.strings.cancel,
|
||||
style: const TextStyle(
|
||||
color: Colors.redAccent,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
context.strings.verify,
|
||||
style: const TextStyle(
|
||||
color: Colors.purple,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
if (!isValidEmail(_email)) {
|
||||
showErrorDialog(
|
||||
context,
|
||||
context.strings.invalidEmailTitle,
|
||||
context.strings.invalidEmailMessage,
|
||||
);
|
||||
return;
|
||||
}
|
||||
UserService.instance.sendOtt(context, _email, isChangeEmail: true);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
import 'package:ente_accounts/ente_accounts.dart';
|
||||
import 'package:ente_ui/utils/dialog_util.dart';
|
||||
import 'package:ente_utils/email_util.dart';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,65 +2,6 @@ name: ente_accounts
|
||||
description: A Flutter package containing account-related models, pages, and services for Ente apps
|
||||
version: 1.0.0
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
app_links: ^6.3.3
|
||||
bip39: ^1.0.6
|
||||
collection: ^1.18.0
|
||||
dio: ^5.4.0
|
||||
dotted_border: ^3.1.0
|
||||
email_validator: ^3.0.0
|
||||
ente_base:
|
||||
path: ../base
|
||||
ente_configuration:
|
||||
path: ../configuration
|
||||
ente_crypto_dart:
|
||||
git:
|
||||
url: https://github.com/ente-io/ente_crypto_dart.git
|
||||
ente_events:
|
||||
path: ../events
|
||||
ente_lock_screen:
|
||||
path: ../lock_screen
|
||||
ente_network:
|
||||
path: ../network
|
||||
ente_strings:
|
||||
path: ../strings
|
||||
ente_ui:
|
||||
path: ../ui
|
||||
ente_utils:
|
||||
path: ../utils
|
||||
file_saver: ^0.3.0
|
||||
flutter:
|
||||
sdk: flutter
|
||||
logging: ^1.2.0
|
||||
password_strength: ^0.2.0
|
||||
pinput: ^5.0.1
|
||||
pointycastle: ^3.7.3
|
||||
share_plus: ^11.0.0
|
||||
shared_preferences: ^2.2.2
|
||||
step_progress_indicator: ^1.0.2
|
||||
styled_text: ^8.1.0
|
||||
url_launcher: ^6.3.1
|
||||
url_launcher_ios: ^6.3.1
|
||||
uuid: ^4.2.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^5.0.0
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
flutter:
|
||||
|
||||
# This package is not meant to be published
|
||||
publish_to: none
|
||||
|
||||
name: ente_accounts
|
||||
description: A Flutter package containing account-related models, pages, and services for Ente apps
|
||||
version: 1.0.0
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
Reference in New Issue
Block a user