TF-3985 Navigate Paywall url when click Increase your space button
This commit is contained in:
@@ -32,6 +32,7 @@ extension SessionExtensions on Session {
|
|||||||
tmailContactCapabilityIdentifier: AutocompleteCapability.deserialize,
|
tmailContactCapabilityIdentifier: AutocompleteCapability.deserialize,
|
||||||
linagoraDownloadAllCapability: DownloadAllCapability.deserialize,
|
linagoraDownloadAllCapability: DownloadAllCapability.deserialize,
|
||||||
capabilityServerSettings: SettingsCapability.deserialize,
|
capabilityServerSettings: SettingsCapability.deserialize,
|
||||||
|
linagoraSaaSCapability: SaaSAccountCapability.deserialize,
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ class MailboxView extends BaseMailboxView {
|
|||||||
end: isDesktop ? 0 : 24,
|
end: isDesktop ? 0 : 24,
|
||||||
),
|
),
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
onTapAction: () {},
|
onTapAction: () => controller
|
||||||
|
.mailboxDashBoardController
|
||||||
|
.navigateToPaywall(context),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import 'package:core/utils/app_logger.dart';
|
|||||||
import 'package:tmail_ui_user/features/login/data/extensions/service_path_extension.dart';
|
import 'package:tmail_ui_user/features/login/data/extensions/service_path_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/login/data/network/endpoint.dart';
|
import 'package:tmail_ui_user/features/login/data/network/endpoint.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/linagora_ecosystem_exceptions.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/linagora_ecosystem_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/linagora_ecosystem/api_url_linagora_ecosystem.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/linagora_ecosystem/linagora_ecosystem.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/linagora_ecosystem/linagora_ecosystem.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/linagora_ecosystem/linagora_ecosystem_identifier.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
|
||||||
class LinagoraEcosystemApi {
|
class LinagoraEcosystemApi {
|
||||||
final DioClient _dioClient;
|
final DioClient _dioClient;
|
||||||
@@ -26,4 +29,33 @@ class LinagoraEcosystemApi {
|
|||||||
throw NotFoundLinagoraEcosystem();
|
throw NotFoundLinagoraEcosystem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<PaywallUrlPattern> getPaywallUrl(String baseUrl) async {
|
||||||
|
final result = await _dioClient.get(
|
||||||
|
Endpoint.linagoraEcosystem.usingBaseUrl(baseUrl).generateEndpointPath(),
|
||||||
|
);
|
||||||
|
log('LinagoraEcosystemApi::getPaywallUrl: $result');
|
||||||
|
|
||||||
|
LinagoraEcosystem? linagoraEcosystem;
|
||||||
|
|
||||||
|
if (result is Map<String, dynamic>) {
|
||||||
|
linagoraEcosystem = LinagoraEcosystem.deserialize(result);
|
||||||
|
} else if (result is String) {
|
||||||
|
linagoraEcosystem = LinagoraEcosystem.deserialize(jsonDecode(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linagoraEcosystem == null) {
|
||||||
|
throw NotFoundLinagoraEcosystem();
|
||||||
|
} else {
|
||||||
|
final paywallProperty =
|
||||||
|
linagoraEcosystem.properties?[LinagoraEcosystemIdentifier.paywallURL] as ApiUrlLinagoraEcosystem?;
|
||||||
|
log('LinagoraEcosystemApi::getPaywallUrl: paywallProperty = $paywallProperty');
|
||||||
|
|
||||||
|
if (paywallProperty == null) {
|
||||||
|
throw NotFoundPaywallUrl();
|
||||||
|
} else {
|
||||||
|
return PaywallUrlPattern(paywallProperty.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
|
|
||||||
class NotFoundLinagoraEcosystem implements Exception {}
|
class NotFoundLinagoraEcosystem implements Exception {}
|
||||||
|
|
||||||
|
class NotFoundPaywallUrl implements Exception {}
|
||||||
+1
@@ -27,6 +27,7 @@ class LinagoraEcosystemConverter {
|
|||||||
LinagoraEcosystemIdentifier.twakeSync: AppLinagoraEcosystem.deserialize,
|
LinagoraEcosystemIdentifier.twakeSync: AppLinagoraEcosystem.deserialize,
|
||||||
LinagoraEcosystemIdentifier.linShare: AppLinagoraEcosystem.deserialize,
|
LinagoraEcosystemIdentifier.linShare: AppLinagoraEcosystem.deserialize,
|
||||||
LinagoraEcosystemIdentifier.mobileApps: MobileAppsLinagoraEcosystemConverter.deserialize,
|
LinagoraEcosystemIdentifier.mobileApps: MobileAppsLinagoraEcosystemConverter.deserialize,
|
||||||
|
LinagoraEcosystemIdentifier.paywallURL: ApiUrlLinagoraEcosystem.deserialize,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -11,6 +11,7 @@ class LinagoraEcosystemIdentifier with EquatableMixin {
|
|||||||
static final twakeChat = LinagoraEcosystemIdentifier('Twake Chat');
|
static final twakeChat = LinagoraEcosystemIdentifier('Twake Chat');
|
||||||
static final twakeSync = LinagoraEcosystemIdentifier('Twake Sync');
|
static final twakeSync = LinagoraEcosystemIdentifier('Twake Sync');
|
||||||
static final linShare = LinagoraEcosystemIdentifier('LinShare');
|
static final linShare = LinagoraEcosystemIdentifier('LinShare');
|
||||||
|
static final paywallURL = LinagoraEcosystemIdentifier('paywallUrlTemplate');
|
||||||
|
|
||||||
final String value;
|
final String value;
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_work
|
|||||||
import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_manager.dart';
|
import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_manager.dart';
|
||||||
import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart';
|
import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart';
|
||||||
import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart';
|
import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/presentation/paywall_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/quotas/presentation/quotas_bindings.dart';
|
import 'package:tmail_ui_user/features/quotas/presentation/quotas_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart';
|
import 'package:tmail_ui_user/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/search/email/presentation/search_email_bindings.dart';
|
import 'package:tmail_ui_user/features/search/email/presentation/search_email_bindings.dart';
|
||||||
@@ -376,6 +377,7 @@ class MailboxDashBoardBindings extends BaseBindings {
|
|||||||
Get.lazyPut(() => GetIdentityCacheOnWebInteractor(
|
Get.lazyPut(() => GetIdentityCacheOnWebInteractor(
|
||||||
Get.find<IdentityCreatorRepository>()
|
Get.find<IdentityCreatorRepository>()
|
||||||
));
|
));
|
||||||
|
PaywallBindings().dependencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
+8
@@ -127,6 +127,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/validate_saas_premium_available_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/web_auth_redirect_processor_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/web_auth_redirect_processor_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
||||||
@@ -152,6 +153,8 @@ import 'package:tmail_ui_user/features/manage_account/presentation/model/account
|
|||||||
import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart';
|
||||||
import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart'
|
import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart'
|
||||||
if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart';
|
if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/state/get_paywall_url_state.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/controller/web_socket_controller.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/controller/web_socket_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_manager.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_manager.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/services/fcm_service.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/services/fcm_service.dart';
|
||||||
@@ -302,6 +305,7 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
StreamSubscription<DeepLinkData?>? _deepLinkDataStreamSubscription;
|
StreamSubscription<DeepLinkData?>? _deepLinkDataStreamSubscription;
|
||||||
int minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete;
|
int minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete;
|
||||||
EmailSortOrderType currentSortOrder = SearchEmailFilter.defaultSortOrder;
|
EmailSortOrderType currentSortOrder = SearchEmailFilter.defaultSortOrder;
|
||||||
|
PaywallUrlPattern? paywallUrlPattern;
|
||||||
|
|
||||||
final StreamController<Either<Failure, Success>> _progressStateController =
|
final StreamController<Either<Failure, Success>> _progressStateController =
|
||||||
StreamController<Either<Failure, Success>>.broadcast();
|
StreamController<Either<Failure, Success>>.broadcast();
|
||||||
@@ -497,6 +501,8 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
);
|
);
|
||||||
} else if (success is GetStoredEmailSortOrderSuccess) {
|
} else if (success is GetStoredEmailSortOrderSuccess) {
|
||||||
setUpDefaultEmailSortOrder(success.emailSortOrderType);
|
setUpDefaultEmailSortOrder(success.emailSortOrderType);
|
||||||
|
} else if (success is GetPaywallUrlSuccess) {
|
||||||
|
loadPaywallUrlSuccess(success.paywallUrlPattern);
|
||||||
} else {
|
} else {
|
||||||
super.handleSuccessViewState(success);
|
super.handleSuccessViewState(success);
|
||||||
}
|
}
|
||||||
@@ -830,6 +836,8 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
if (PlatformInfo.isMobile) {
|
if (PlatformInfo.isMobile) {
|
||||||
getAllSendingEmails();
|
getAllSendingEmails();
|
||||||
_storeSessionAction(session);
|
_storeSessionAction(session);
|
||||||
|
} else {
|
||||||
|
loadPaywallUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+37
@@ -1,5 +1,11 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/usecases/get_paywall_url_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
||||||
|
|
||||||
extension ValidateSaasPremiumAvailableExtension on MailboxDashBoardController {
|
extension ValidateSaasPremiumAvailableExtension on MailboxDashBoardController {
|
||||||
bool get isPremiumAvailable {
|
bool get isPremiumAvailable {
|
||||||
@@ -13,4 +19,35 @@ extension ValidateSaasPremiumAvailableExtension on MailboxDashBoardController {
|
|||||||
|
|
||||||
return saasAccount?.isPremiumAvailable ?? false;
|
return saasAccount?.isPremiumAvailable ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadPaywallUrl() {
|
||||||
|
final getPaywallUrlInteractor = getBinding<GetPaywallUrlInteractor>();
|
||||||
|
final jmapUrl = dynamicUrlInterceptors.jmapUrl;
|
||||||
|
|
||||||
|
if (getPaywallUrlInteractor != null && jmapUrl != null) {
|
||||||
|
consumeState(getPaywallUrlInteractor.execute(jmapUrl));
|
||||||
|
} else {
|
||||||
|
paywallUrlPattern = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadPaywallUrlSuccess(PaywallUrlPattern newPattern) {
|
||||||
|
paywallUrlPattern = newPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
void navigateToPaywall(BuildContext context) {
|
||||||
|
if (paywallUrlPattern == null) {
|
||||||
|
appToast.showToastErrorMessage(
|
||||||
|
context,
|
||||||
|
AppLocalizations.of(context).paywallUrlNotAvailable,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final qualifiedPaywall = paywallUrlPattern!.getQualifiedUrl(
|
||||||
|
ownerEmail: ownEmailAddress.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
AppUtils.launchLink(qualifiedPaywall);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
|
||||||
|
abstract class PaywallDatasource {
|
||||||
|
Future<PaywallUrlPattern> getPaywallUrl(String baseUrl);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/data/network/linagora_ecosystem_api.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/data/datasource/paywall_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
|
||||||
|
|
||||||
|
class PaywallDatasourceImpl extends PaywallDatasource {
|
||||||
|
final LinagoraEcosystemApi _linagoraEcosystemApi;
|
||||||
|
final ExceptionThrower _exceptionThrower;
|
||||||
|
|
||||||
|
PaywallDatasourceImpl(this._linagoraEcosystemApi, this._exceptionThrower);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PaywallUrlPattern> getPaywallUrl(String baseUrl) {
|
||||||
|
return Future.sync(() async {
|
||||||
|
return await _linagoraEcosystemApi.getPaywallUrl(baseUrl);
|
||||||
|
}).catchError(_exceptionThrower.throwException);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:tmail_ui_user/features/paywall/data/datasource/paywall_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/repository/paywall_repository.dart';
|
||||||
|
|
||||||
|
class PaywallRepositoryImpl extends PaywallRepository {
|
||||||
|
final PaywallDatasource _paywallDatasource;
|
||||||
|
|
||||||
|
PaywallRepositoryImpl(this._paywallDatasource);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PaywallUrlPattern> getPaywallUrl(String baseUrl) {
|
||||||
|
return _paywallDatasource.getPaywallUrl(baseUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:core/utils/mail/domain.dart';
|
||||||
|
import 'package:core/utils/mail/mail_address.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/presentation/paywall_utils.dart';
|
||||||
|
|
||||||
|
class PaywallUrlPattern with EquatableMixin {
|
||||||
|
final String pattern;
|
||||||
|
|
||||||
|
PaywallUrlPattern(this.pattern);
|
||||||
|
|
||||||
|
String getQualifiedUrl({required String ownerEmail, String? domainName}) {
|
||||||
|
final mailAddress = _getMailAddress(ownerEmail: ownerEmail);
|
||||||
|
return PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: pattern,
|
||||||
|
localPart: mailAddress?.localPart,
|
||||||
|
domainName: mailAddress?.domain.domainName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MailAddress? _getMailAddress({required String ownerEmail}) {
|
||||||
|
try {
|
||||||
|
return MailAddress.validateAddress(ownerEmail);
|
||||||
|
} catch (e) {
|
||||||
|
if (GetUtils.isEmail(ownerEmail)) {
|
||||||
|
final listPart = ownerEmail.split('@');
|
||||||
|
if (listPart.length == 2) {
|
||||||
|
return MailAddress(
|
||||||
|
localPart: listPart.first,
|
||||||
|
domain: Domain.of((listPart.last)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [pattern];
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
|
||||||
|
abstract class PaywallRepository {
|
||||||
|
Future<PaywallUrlPattern> getPaywallUrl(String baseUrl);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart';
|
||||||
|
|
||||||
|
class GettingPaywallUrl extends LoadingState {}
|
||||||
|
|
||||||
|
class GetPaywallUrlSuccess extends UIState {
|
||||||
|
final PaywallUrlPattern paywallUrlPattern;
|
||||||
|
|
||||||
|
GetPaywallUrlSuccess(this.paywallUrlPattern);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [paywallUrlPattern];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetPaywallUrlFailure extends FeatureFailure {
|
||||||
|
GetPaywallUrlFailure(dynamic exception) : super(exception: exception);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/repository/paywall_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/state/get_paywall_url_state.dart';
|
||||||
|
|
||||||
|
class GetPaywallUrlInteractor {
|
||||||
|
final PaywallRepository _paywallRepository;
|
||||||
|
|
||||||
|
GetPaywallUrlInteractor(this._paywallRepository);
|
||||||
|
|
||||||
|
Stream<Either<Failure, Success>> execute(String baseUrl) async* {
|
||||||
|
try {
|
||||||
|
yield Right(GettingPaywallUrl());
|
||||||
|
final paywallUrl = await _paywallRepository.getPaywallUrl(baseUrl);
|
||||||
|
yield Right(GetPaywallUrlSuccess(paywallUrl));
|
||||||
|
} catch (e) {
|
||||||
|
yield Left(GetPaywallUrlFailure(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/interactors_bindings.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/data/network/linagora_ecosystem_api.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/data/datasource/paywall_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/data/datasource_impl/paywall_datasource_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/data/repository/paywall_repository_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/repository/paywall_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/domain/usecases/get_paywall_url_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
|
||||||
|
|
||||||
|
class PaywallBindings extends InteractorsBindings {
|
||||||
|
@override
|
||||||
|
void bindingsDataSource() {
|
||||||
|
Get.lazyPut<PaywallDatasource>(() => Get.find<PaywallDatasourceImpl>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsDataSourceImpl() {
|
||||||
|
Get.lazyPut(
|
||||||
|
() => PaywallDatasourceImpl(
|
||||||
|
Get.find<LinagoraEcosystemApi>(),
|
||||||
|
Get.find<RemoteExceptionThrower>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsInteractor() {
|
||||||
|
Get.lazyPut(() => GetPaywallUrlInteractor(Get.find<PaywallRepository>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsRepository() {
|
||||||
|
Get.lazyPut<PaywallRepository>(() => Get.find<PaywallRepositoryImpl>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsRepositoryImpl() {
|
||||||
|
Get.lazyPut(() => PaywallRepositoryImpl(Get.find<PaywallDatasource>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
class PaywallUtils {
|
||||||
|
const PaywallUtils._();
|
||||||
|
|
||||||
|
/// Builds a paywall URL from a template.
|
||||||
|
///
|
||||||
|
/// - Supports both raw placeholders (`{localPart}`, `{domainName}`)
|
||||||
|
/// and URL-encoded placeholders (`%7BlocalPart%7D`, `%7BdomainName%7D`).
|
||||||
|
/// - If [localPart] or [domainName] is not provided, the placeholder
|
||||||
|
/// is removed.
|
||||||
|
static String buildPaywallUrlFromTemplate({
|
||||||
|
required String template,
|
||||||
|
String? localPart,
|
||||||
|
String? domainName,
|
||||||
|
}) {
|
||||||
|
final replacements = {
|
||||||
|
'{localPart}': localPart ?? '',
|
||||||
|
'{domainName}': domainName ?? '',
|
||||||
|
Uri.encodeComponent('{localPart}'): localPart ?? '',
|
||||||
|
Uri.encodeComponent('{domainName}'): domainName ?? '',
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = template;
|
||||||
|
replacements.forEach((placeholder, value) {
|
||||||
|
result = result.replaceAll(placeholder, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"@@last_modified": "2025-09-09T13:40:24.145761",
|
"@@last_modified": "2025-09-09T15:28:33.596868",
|
||||||
"initializing_data": "Initializing data...",
|
"initializing_data": "Initializing data...",
|
||||||
"@initializing_data": {
|
"@initializing_data": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -4687,5 +4687,11 @@
|
|||||||
"placeholders": {
|
"placeholders": {
|
||||||
"count": {}
|
"count": {}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"paywallUrlNotAvailable": "Paywall url not available",
|
||||||
|
"@paywallUrlNotAvailable": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders_order": [],
|
||||||
|
"placeholders": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4943,4 +4943,11 @@ class AppLocalizations {
|
|||||||
args: [count],
|
args: [count],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get paywallUrlNotAvailable {
|
||||||
|
return Intl.message(
|
||||||
|
'Paywall url not available',
|
||||||
|
name: 'paywallUrlNotAvailable',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import 'package:model/principals/capability_principals.dart';
|
|||||||
import 'package:uri/uri.dart';
|
import 'package:uri/uri.dart';
|
||||||
|
|
||||||
extension SessionExtension on Session {
|
extension SessionExtension on Session {
|
||||||
static const String saaSCapabilityProperties = 'com:linagora:params:saas';
|
|
||||||
|
|
||||||
String getDownloadUrl({String? jmapUrl}) {
|
String getDownloadUrl({String? jmapUrl}) {
|
||||||
final Uri downloadUrlValid;
|
final Uri downloadUrlValid;
|
||||||
if (jmapUrl != null) {
|
if (jmapUrl != null) {
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:tmail_ui_user/features/paywall/presentation/paywall_utils.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('PaywallUtils.buildPaywallUrlFromTemplate', () {
|
||||||
|
// --- Raw placeholder cases ---
|
||||||
|
test('replaces raw {localPart} and {domainName}', () {
|
||||||
|
const template = 'https://{localPart}.{domainName}/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'alice',
|
||||||
|
domainName: 'example.com',
|
||||||
|
);
|
||||||
|
expect(url, 'https://alice.example.com/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removes {localPart} when null', () {
|
||||||
|
const template = 'https://{localPart}.{domainName}/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
domainName: 'example.com',
|
||||||
|
);
|
||||||
|
expect(url, 'https://.example.com/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removes {domainName} when null', () {
|
||||||
|
const template = 'https://{localPart}.{domainName}/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'bob',
|
||||||
|
);
|
||||||
|
expect(url, 'https://bob./paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removes both {localPart} and {domainName} when both null', () {
|
||||||
|
const template = 'https://{localPart}.{domainName}/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(template: template);
|
||||||
|
expect(url, 'https://./paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Encoded placeholder cases ---
|
||||||
|
test('replaces encoded %7BlocalPart%7D', () {
|
||||||
|
const template = 'https://%7BlocalPart%7D.twake.app/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'charlie',
|
||||||
|
);
|
||||||
|
expect(url, 'https://charlie.twake.app/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('replaces encoded %7BdomainName%7D', () {
|
||||||
|
const template = 'https://account.%7BdomainName%7D/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
domainName: 'test.org',
|
||||||
|
);
|
||||||
|
expect(url, 'https://account.test.org/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('replaces both encoded placeholders', () {
|
||||||
|
const template = 'https://%7BlocalPart%7D.%7BdomainName%7D/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'david',
|
||||||
|
domainName: 'mysite.com',
|
||||||
|
);
|
||||||
|
expect(url, 'https://david.mysite.com/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removes encoded placeholders when null', () {
|
||||||
|
const template = 'https://%7BlocalPart%7D.%7BdomainName%7D/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(template: template);
|
||||||
|
expect(url, 'https://./paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Mixed raw + encoded ---
|
||||||
|
test('handles raw {localPart} and encoded %7BdomainName%7D together', () {
|
||||||
|
const template = 'https://{localPart}.%7BdomainName%7D/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'eve',
|
||||||
|
domainName: 'hybrid.com',
|
||||||
|
);
|
||||||
|
expect(url, 'https://eve.hybrid.com/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('handles encoded %7BlocalPart%7D and raw {domainName} together', () {
|
||||||
|
const template = 'https://%7BlocalPart%7D.{domainName}/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'frank',
|
||||||
|
domainName: 'hybrid.org',
|
||||||
|
);
|
||||||
|
expect(url, 'https://frank.hybrid.org/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- No placeholders ---
|
||||||
|
test('keeps template unchanged if no placeholders', () {
|
||||||
|
const template = 'https://static.twake.app/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'ghost',
|
||||||
|
domainName: 'ignored.com',
|
||||||
|
);
|
||||||
|
expect(url, 'https://static.twake.app/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Edge cases ---
|
||||||
|
test('empty template returns empty string', () {
|
||||||
|
const template = '';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'x',
|
||||||
|
domainName: 'y.com',
|
||||||
|
);
|
||||||
|
expect(url, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('template with only {localPart}', () {
|
||||||
|
const template = '{localPart}';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'single',
|
||||||
|
);
|
||||||
|
expect(url, 'single');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('template with only {domainName}', () {
|
||||||
|
const template = '{domainName}';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
domainName: 'onedomain.com',
|
||||||
|
);
|
||||||
|
expect(url, 'onedomain.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('template with repeated placeholders', () {
|
||||||
|
const template =
|
||||||
|
'https://{localPart}.{domainName}/{localPart}-{domainName}/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'anna',
|
||||||
|
domainName: 'repeat.com',
|
||||||
|
);
|
||||||
|
expect(url, 'https://anna.repeat.com/anna-repeat.com/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('template with repeated encoded placeholders', () {
|
||||||
|
const template =
|
||||||
|
'https://%7BlocalPart%7D.%7BdomainName%7D/%7BlocalPart%7D-%7BdomainName%7D/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'zoe',
|
||||||
|
domainName: 'repeat.org',
|
||||||
|
);
|
||||||
|
expect(url, 'https://zoe.repeat.org/zoe-repeat.org/paywall');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('template with mix of raw and encoded repeated placeholders', () {
|
||||||
|
const template =
|
||||||
|
'https://{localPart}.%7BdomainName%7D/{localPart}-%7BdomainName%7D/paywall';
|
||||||
|
final url = PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
|
template: template,
|
||||||
|
localPart: 'mix',
|
||||||
|
domainName: 'combo.net',
|
||||||
|
);
|
||||||
|
expect(url, 'https://mix.combo.net/mix-combo.net/paywall');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user