TF-4145 Create paywall url from workplaceFqdn
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import 'package:core/core.dart';
|
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
|
||||||
/// Utility class for generating web links in flat subdomain format.
|
/// Utility class for generating web links in flat subdomain format.
|
||||||
class WebLinkGenerator {
|
class WebLinkGenerator {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ void main() {
|
|||||||
expect(result, 'https://charlie-settings.domain.com/');
|
expect(result, 'https://charlie-settings.domain.com/');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('✅ should throw when workplaceFqdn is empty', () {
|
test('should throw when workplaceFqdn is empty', () {
|
||||||
expect(
|
expect(
|
||||||
() => WebLinkGenerator.generateWebLink(
|
() => WebLinkGenerator.generateWebLink(
|
||||||
workplaceFqdn: '',
|
workplaceFqdn: '',
|
||||||
@@ -131,6 +131,108 @@ void main() {
|
|||||||
expect(result, 'https://bob.example.app/');
|
expect(result, 'https://bob.example.app/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('generateWebLink should include path and no hash when hash is null', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'alice.example.app',
|
||||||
|
slug: 'notes',
|
||||||
|
pathname: 'welcome',
|
||||||
|
hash: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://alice-notes.example.app/welcome');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should include path and no hash when hash is empty', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'bob.example.app',
|
||||||
|
slug: 'drive',
|
||||||
|
pathname: 'folder/123',
|
||||||
|
hash: '',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://bob-drive.example.app/folder/123');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should return root path when pathname is null', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'charlie.example.app',
|
||||||
|
slug: 'settings',
|
||||||
|
pathname: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://charlie-settings.example.app/');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should include path and no hash when slug is null and only pathname is provided', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'alice.example.app',
|
||||||
|
slug: null,
|
||||||
|
pathname: 'welcome',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://alice.example.app/welcome');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should include path and no hash when slug is empty and only pathname is provided', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'bob.example.app',
|
||||||
|
slug: '',
|
||||||
|
pathname: 'dashboard',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://bob.example.app/dashboard');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should handle multi-segment pathname with leading slash when slug is null', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'alice.example.app',
|
||||||
|
slug: null,
|
||||||
|
pathname: '/name1/name2',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://alice.example.app/name1/name2');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should handle multi-segment pathname without leading slash when slug is null', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'bob.example.app',
|
||||||
|
slug: null,
|
||||||
|
pathname: 'name1/name2',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://bob.example.app/name1/name2');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should handle deep multi-segment pathname with leading slash when slug is empty', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'charlie.example.app',
|
||||||
|
slug: '',
|
||||||
|
pathname: '/a/b/c/d',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://charlie.example.app/a/b/c/d');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateWebLink should handle deep multi-segment pathname without leading slash when slug is empty', () {
|
||||||
|
final result = WebLinkGenerator.generateWebLink(
|
||||||
|
workplaceFqdn: 'dave.example.app',
|
||||||
|
slug: '',
|
||||||
|
pathname: 'a/b/c/d',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://dave.example.app/a/b/c/d');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
test('safeGenerateWebLink should return empty string on invalid FQDN', () {
|
test('safeGenerateWebLink should return empty string on invalid FQDN', () {
|
||||||
final result = WebLinkGenerator.safeGenerateWebLink(
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
workplaceFqdn: '',
|
workplaceFqdn: '',
|
||||||
@@ -166,5 +268,85 @@ void main() {
|
|||||||
|
|
||||||
expect(result, 'https://example.com/');
|
expect(result, 'https://example.com/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('safeGenerateWebLink should include path and no hash when hash is null', () {
|
||||||
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: 'dave.example.app',
|
||||||
|
slug: 'profile',
|
||||||
|
pathname: 'user/info',
|
||||||
|
hash: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://dave-profile.example.app/user/info');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('safeGenerateWebLink should include path and no hash when hash is empty', () {
|
||||||
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: 'eve.example.app',
|
||||||
|
slug: 'docs',
|
||||||
|
pathname: 'help',
|
||||||
|
hash: '',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://eve-docs.example.app/help');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('safeGenerateWebLink should return root path when pathname is null', () {
|
||||||
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: 'frank.example.app',
|
||||||
|
slug: 'notes',
|
||||||
|
pathname: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://frank-notes.example.app/');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('safeGenerateWebLink should handle no slug and only pathname (slug = null)', () {
|
||||||
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: 'charlie.example.app',
|
||||||
|
slug: null,
|
||||||
|
pathname: 'home',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://charlie.example.app/home');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('safeGenerateWebLink should handle no slug and only pathname (slug = empty string)', () {
|
||||||
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: 'dave.example.app',
|
||||||
|
slug: '',
|
||||||
|
pathname: 'portal',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://dave.example.app/portal');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('safeGenerateWebLink should handle multi-segment pathname with leading slash and no slug', () {
|
||||||
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: 'eve.example.app',
|
||||||
|
slug: null,
|
||||||
|
pathname: '/x/y/z',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://eve.example.app/x/y/z');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('safeGenerateWebLink should handle multi-segment pathname without leading slash and no slug', () {
|
||||||
|
final result = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: 'frank.example.app',
|
||||||
|
slug: null,
|
||||||
|
pathname: 'x/y/z',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, 'https://frank.example.app/x/y/z');
|
||||||
|
expect(result.contains('#'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1049,7 +1049,7 @@ class ComposerController extends BaseController
|
|||||||
popBack();
|
popBack();
|
||||||
|
|
||||||
if (needIncreaseMySpace) {
|
if (needIncreaseMySpace) {
|
||||||
mailboxDashBoardController.paywallController?.navigateToPaywall(context);
|
mailboxDashBoardController.paywallController?.navigateToPaywall();
|
||||||
} else {
|
} else {
|
||||||
_autoFocusFieldWhenLauncher();
|
_autoFocusFieldWhenLauncher();
|
||||||
}
|
}
|
||||||
@@ -1332,7 +1332,7 @@ class ComposerController extends BaseController
|
|||||||
popBack();
|
popBack();
|
||||||
|
|
||||||
if (needIncreaseMySpace) {
|
if (needIncreaseMySpace) {
|
||||||
mailboxDashBoardController.paywallController?.navigateToPaywall(context);
|
mailboxDashBoardController.paywallController?.navigateToPaywall();
|
||||||
} else {
|
} else {
|
||||||
_autoFocusFieldWhenLauncher();
|
_autoFocusFieldWhenLauncher();
|
||||||
}
|
}
|
||||||
@@ -2279,7 +2279,7 @@ class ComposerController extends BaseController
|
|||||||
popBack();
|
popBack();
|
||||||
|
|
||||||
if (needIncreaseMySpace) {
|
if (needIncreaseMySpace) {
|
||||||
mailboxDashBoardController.paywallController?.navigateToPaywall(context);
|
mailboxDashBoardController.paywallController?.navigateToPaywall();
|
||||||
} else {
|
} else {
|
||||||
_autoFocusFieldWhenLauncher();
|
_autoFocusFieldWhenLauncher();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class MailboxView extends BaseMailboxView {
|
|||||||
onTapAction: () => controller
|
onTapAction: () => controller
|
||||||
.mailboxDashBoardController
|
.mailboxDashBoardController
|
||||||
.paywallController
|
.paywallController
|
||||||
?.navigateToPaywall(context),
|
?.navigateToPaywall(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
|
|||||||
+4
-5
@@ -872,12 +872,11 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
if (PlatformInfo.isMobile) {
|
if (PlatformInfo.isMobile) {
|
||||||
getAllSendingEmails();
|
getAllSendingEmails();
|
||||||
_storeSessionAction(session);
|
_storeSessionAction(session);
|
||||||
} else {
|
|
||||||
paywallController = PaywallController(
|
|
||||||
ownEmailAddress: ownEmailAddress.value,
|
|
||||||
);
|
|
||||||
paywallController?.loadPaywallUrl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paywallController = PaywallController(
|
||||||
|
ownEmailAddress: ownEmailAddress.value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleMailtoURL(MailtoArguments arguments) {
|
void _handleMailtoURL(MailtoArguments arguments) {
|
||||||
|
|||||||
+2
-5
@@ -1,7 +1,6 @@
|
|||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/validate_setting_capability_supported_extension.dart';
|
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/quotas/domain/exceptions/quotas_exception.dart';
|
import 'package:tmail_ui_user/features/quotas/domain/exceptions/quotas_exception.dart';
|
||||||
import 'package:tmail_ui_user/features/quotas/domain/extensions/list_quotas_extensions.dart';
|
import 'package:tmail_ui_user/features/quotas/domain/extensions/list_quotas_extensions.dart';
|
||||||
@@ -13,9 +12,7 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
|||||||
extension ValidateStorageMenuVisibleExtension
|
extension ValidateStorageMenuVisibleExtension
|
||||||
on ManageAccountDashBoardController {
|
on ManageAccountDashBoardController {
|
||||||
void injectQuotaBindings() {
|
void injectQuotaBindings() {
|
||||||
if (isStorageCapabilitySupported) {
|
QuotasInteractorBindings().dependencies();
|
||||||
QuotasInteractorBindings().dependencies();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void getQuotas(AccountId? accountId) {
|
void getQuotas(AccountId? accountId) {
|
||||||
@@ -27,7 +24,7 @@ extension ValidateStorageMenuVisibleExtension
|
|||||||
}
|
}
|
||||||
|
|
||||||
getQuotasInteractor = getBinding<GetQuotasInteractor>();
|
getQuotasInteractor = getBinding<GetQuotasInteractor>();
|
||||||
if (getQuotasInteractor == null || !isStorageCapabilitySupported) {
|
if (getQuotasInteractor == null) {
|
||||||
consumeState(
|
consumeState(
|
||||||
Stream.value(Left(GetQuotasFailure(QuotasNotSupportedException))),
|
Stream.value(Left(GetQuotasFailure(QuotasNotSupportedException))),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/b
|
|||||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/export_trace_log_extension.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/export_trace_log_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/handle_vacation_response_extension.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/handle_vacation_response_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/validate_setting_capability_supported_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/validate_storage_menu_visible_extension.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/validate_storage_menu_visible_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forward_bindings.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forward_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/identities/identity_bindings.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/identities/identity_bindings.dart';
|
||||||
@@ -154,11 +155,10 @@ class ManageAccountDashBoardController extends ReloadableController
|
|||||||
paywallController = PaywallController(
|
paywallController = PaywallController(
|
||||||
ownEmailAddress: ownEmailAddress.value,
|
ownEmailAddress: ownEmailAddress.value,
|
||||||
);
|
);
|
||||||
paywallController?.loadPaywallUrl();
|
|
||||||
|
|
||||||
if (quota != null) {
|
if (quota != null) {
|
||||||
octetsQuota.value = quota;
|
octetsQuota.value = quota;
|
||||||
} else {
|
} else if (isStorageCapabilitySupported) {
|
||||||
getQuotas(accountId.value);
|
getQuotas(accountId.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,7 +194,9 @@ class ManageAccountDashBoardController extends ReloadableController
|
|||||||
injectVacationBindings(session, accountId);
|
injectVacationBindings(session, accountId);
|
||||||
injectForwardBindings(session, accountId);
|
injectForwardBindings(session, accountId);
|
||||||
injectRuleFilterBindings(session, accountId);
|
injectRuleFilterBindings(session, accountId);
|
||||||
injectQuotaBindings();
|
if (isStorageCapabilitySupported) {
|
||||||
|
injectQuotaBindings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/preferences/p
|
|||||||
import 'package:tmail_ui_user/features/manage_account/presentation/storage/storage_view.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/storage/storage_view.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/vacation_view.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/vacation_view.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/quotas/domain/extensions/quota_extensions.dart';
|
||||||
|
|
||||||
class ManageAccountDashBoardView extends GetWidget<ManageAccountDashBoardController> {
|
class ManageAccountDashBoardView extends GetWidget<ManageAccountDashBoardController> {
|
||||||
|
|
||||||
@@ -171,7 +172,9 @@ class ManageAccountDashBoardView extends GetWidget<ManageAccountDashBoardControl
|
|||||||
case AccountMenuItem.mailboxVisibility:
|
case AccountMenuItem.mailboxVisibility:
|
||||||
return MailboxVisibilityView();
|
return MailboxVisibilityView();
|
||||||
case AccountMenuItem.storage:
|
case AccountMenuItem.storage:
|
||||||
if (controller.isStorageCapabilitySupported) {
|
if (controller.octetsQuota.value != null &&
|
||||||
|
controller.octetsQuota.value?.storageAvailable == true &&
|
||||||
|
controller.isStorageCapabilitySupported) {
|
||||||
return const StorageView();
|
return const StorageView();
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/mixin/contact_support_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/contact_support_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart';
|
||||||
|
import 'package:tmail_ui_user/features/quotas/domain/extensions/quota_extensions.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
class ManageAccountMenuController extends GetxController with ContactSupportMixin {
|
class ManageAccountMenuController extends GetxController with ContactSupportMixin {
|
||||||
@@ -33,7 +34,7 @@ class ManageAccountMenuController extends GetxController with ContactSupportMixi
|
|||||||
_quotaRxWorker = ever(
|
_quotaRxWorker = ever(
|
||||||
dashBoardController.octetsQuota,
|
dashBoardController.octetsQuota,
|
||||||
(octetsQuota) {
|
(octetsQuota) {
|
||||||
if (octetsQuota != null) {
|
if (octetsQuota != null && octetsQuota.storageAvailable) {
|
||||||
_addStorageToMenuList();
|
_addStorageToMenuList();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
+17
-3
@@ -9,6 +9,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings
|
|||||||
import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/menu/widgets/setting_first_level_tile_builder.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/menu/widgets/setting_first_level_tile_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart';
|
||||||
|
import 'package:tmail_ui_user/features/quotas/domain/extensions/quota_extensions.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||||
|
|
||||||
@@ -140,14 +141,27 @@ class SettingsFirstLevelView extends GetWidget<SettingsController> {
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}),
|
}),
|
||||||
|
if (PlatformInfo.isWeb)
|
||||||
|
...[
|
||||||
|
divider,
|
||||||
|
_buildSettingItem(
|
||||||
|
context: context,
|
||||||
|
menuItem: AccountMenuItem.keyboardShortcuts,
|
||||||
|
appLocalizations: appLocalizations,
|
||||||
|
),
|
||||||
|
],
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (controller.manageAccountDashboardController.octetsQuota.value != null) {
|
final octetsQuota = controller
|
||||||
|
.manageAccountDashboardController
|
||||||
|
.octetsQuota
|
||||||
|
.value;
|
||||||
|
|
||||||
|
if (octetsQuota != null && octetsQuota.storageAvailable) {
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
divider,
|
divider,
|
||||||
_buildSettingItem(
|
_buildSettingItem(
|
||||||
key: const ValueKey('setting_storage'),
|
|
||||||
context: context,
|
context: context,
|
||||||
menuItem: AccountMenuItem.keyboardShortcuts,
|
menuItem: AccountMenuItem.storage,
|
||||||
appLocalizations: appLocalizations,
|
appLocalizations: appLocalizations,
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/preferences/p
|
|||||||
import 'package:tmail_ui_user/features/manage_account/presentation/storage/storage_view.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/storage/storage_view.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/vacation_view.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/vacation_view.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/quotas/domain/extensions/quota_extensions.dart';
|
||||||
|
|
||||||
class SettingsView extends GetWidget<SettingsController> {
|
class SettingsView extends GetWidget<SettingsController> {
|
||||||
const SettingsView({Key? key}) : super(key: key);
|
const SettingsView({Key? key}) : super(key: key);
|
||||||
@@ -141,7 +142,9 @@ class SettingsView extends GetWidget<SettingsController> {
|
|||||||
case AccountMenuItem.notification:
|
case AccountMenuItem.notification:
|
||||||
return const NotificationView();
|
return const NotificationView();
|
||||||
case AccountMenuItem.storage:
|
case AccountMenuItem.storage:
|
||||||
if (controller.manageAccountDashboardController.isStorageCapabilitySupported) {
|
if (controller.manageAccountDashboardController.octetsQuota.value != null &&
|
||||||
|
controller.manageAccountDashboardController.octetsQuota.value?.storageAvailable == true &&
|
||||||
|
controller.manageAccountDashboardController.isStorageCapabilitySupported) {
|
||||||
return const StorageView();
|
return const StorageView();
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
|
||||||
@@ -17,7 +16,7 @@ class StorageController extends BaseController with SaaSPremiumMixin {
|
|||||||
return isPremiumAvailable(accountId: accountId, session: session);
|
return isPremiumAvailable(accountId: accountId, session: session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpgradeStorage(BuildContext context) {
|
void onUpgradeStorage() {
|
||||||
dashBoardController.paywallController?.navigateToPaywall(context);
|
dashBoardController.paywallController?.navigateToPaywall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ class StorageView extends GetWidget<StorageController> with AppLoaderMixin {
|
|||||||
return UpgradeStorageWidget(
|
return UpgradeStorageWidget(
|
||||||
imagePaths: controller.imagePaths,
|
imagePaths: controller.imagePaths,
|
||||||
isMobile: isMobile,
|
isMobile: isMobile,
|
||||||
onUpgradeStorageAction: () =>
|
onUpgradeStorageAction:
|
||||||
controller.onUpgradeStorage(context),
|
controller.onUpgradeStorage,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class PaywallUrlPattern with EquatableMixin {
|
|||||||
final mailAddress = _getMailAddress(ownerEmail: ownerEmail);
|
final mailAddress = _getMailAddress(ownerEmail: ownerEmail);
|
||||||
return PaywallUtils.buildPaywallUrlFromTemplate(
|
return PaywallUtils.buildPaywallUrlFromTemplate(
|
||||||
template: pattern,
|
template: pattern,
|
||||||
localPart: mailAddress?.localPart,
|
localPart: mailAddress?.localPart.replaceAll('.', ''),
|
||||||
domainName: domainName ?? mailAddress?.domain.domainName,
|
domainName: domainName ?? mailAddress?.domain.domainName,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,56 +17,34 @@ import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
|||||||
class PaywallController extends BaseController {
|
class PaywallController extends BaseController {
|
||||||
final String ownEmailAddress;
|
final String ownEmailAddress;
|
||||||
|
|
||||||
PaywallUrlPattern? paywallUrlPattern;
|
|
||||||
bool isRetryGetPaywallUrl = false;
|
|
||||||
|
|
||||||
PaywallController({required this.ownEmailAddress});
|
PaywallController({required this.ownEmailAddress});
|
||||||
|
|
||||||
void loadPaywallUrl() {
|
void _loadPaywallUrl() {
|
||||||
final getPaywallUrlInteractor = getBinding<GetPaywallUrlInteractor>();
|
final getPaywallUrlInteractor = getBinding<GetPaywallUrlInteractor>();
|
||||||
final jmapUrl = dynamicUrlInterceptors.jmapUrl;
|
final jmapUrl = dynamicUrlInterceptors.jmapUrl;
|
||||||
|
|
||||||
if (getPaywallUrlInteractor != null && jmapUrl != null) {
|
if (getPaywallUrlInteractor != null && jmapUrl != null) {
|
||||||
consumeState(getPaywallUrlInteractor.execute(jmapUrl));
|
consumeState(getPaywallUrlInteractor.execute(jmapUrl));
|
||||||
} else {
|
} else {
|
||||||
paywallUrlPattern = null;
|
_loadPaywallUrlFailure();
|
||||||
if (isRetryGetPaywallUrl) {
|
|
||||||
_showMessagePaywallUrlNotAvailable();
|
|
||||||
isRetryGetPaywallUrl = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadPaywallUrlSuccess(PaywallUrlPattern newPattern) {
|
void _loadPaywallUrlSuccess(PaywallUrlPattern newPattern) {
|
||||||
paywallUrlPattern = newPattern;
|
_redirectPaywallPage(newPattern);
|
||||||
if (isRetryGetPaywallUrl) {
|
|
||||||
isRetryGetPaywallUrl = false;
|
|
||||||
final qualifiedPaywall = getPaywallUrl(paywallUrlPattern!);
|
|
||||||
AppUtils.launchLink(qualifiedPaywall);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadPaywallUrlFailure() {
|
void _loadPaywallUrlFailure() {
|
||||||
paywallUrlPattern = null;
|
_showMessagePaywallUrlNotAvailable();
|
||||||
if (isRetryGetPaywallUrl) {
|
|
||||||
_showMessagePaywallUrlNotAvailable();
|
|
||||||
isRetryGetPaywallUrl = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showMessagePaywallUrlNotAvailable({BuildContext? context}) {
|
void _showMessagePaywallUrlNotAvailable() {
|
||||||
final overlayContext = context ?? currentOverlayContext;
|
if (currentOverlayContext == null || currentContext == null) return;
|
||||||
AppLocalizations? appLocalizations;
|
|
||||||
if (context != null) {
|
|
||||||
appLocalizations = AppLocalizations.of(context);
|
|
||||||
} else if (currentContext != null) {
|
|
||||||
appLocalizations = AppLocalizations.of(currentContext!);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overlayContext == null || appLocalizations == null) return;
|
|
||||||
|
|
||||||
|
final appLocalizations = AppLocalizations.of(currentContext!);
|
||||||
|
|
||||||
appToast.showToastMessage(
|
appToast.showToastMessage(
|
||||||
overlayContext,
|
currentOverlayContext!,
|
||||||
appLocalizations.paywallUrlNotAvailable,
|
appLocalizations.paywallUrlNotAvailable,
|
||||||
actionName: appLocalizations.retry,
|
actionName: appLocalizations.retry,
|
||||||
onActionClick: _handleRetryGetPaywallUrl,
|
onActionClick: _handleRetryGetPaywallUrl,
|
||||||
@@ -82,49 +60,54 @@ class PaywallController extends BaseController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void navigateToPaywall(BuildContext context) {
|
void navigateToPaywall() {
|
||||||
if (paywallUrlPattern == null) {
|
|
||||||
_showMessagePaywallUrlNotAvailable(context: context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final qualifiedPaywall = getPaywallUrl(paywallUrlPattern!);
|
|
||||||
AppUtils.launchLink(qualifiedPaywall);
|
|
||||||
}
|
|
||||||
|
|
||||||
String getPaywallUrl(PaywallUrlPattern pattern) {
|
|
||||||
final defaultUrl = pattern.getQualifiedUrl(
|
|
||||||
ownerEmail: ownEmailAddress,
|
|
||||||
domainName: RouteUtils.getRootDomain(),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final workplaceFqdn = twakeAppManager.oidcUserInfo?.workplaceFqdn?.trim();
|
final workplaceFqdn = twakeAppManager.oidcUserInfo?.workplaceFqdn?.trim();
|
||||||
if (workplaceFqdn == null || workplaceFqdn.isEmpty) {
|
if (workplaceFqdn == null || workplaceFqdn.isEmpty) {
|
||||||
return defaultUrl;
|
_navigateToPaywallUseEcoSystem();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_navigateToPaywallUseWorkplaceFqdn(workplaceFqdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
final paywallUrl = WebLinkGenerator.safeGenerateWebLink(
|
|
||||||
workplaceFqdn: workplaceFqdn,
|
|
||||||
pathname: 'paywall',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Fallback if generated URL is empty or invalid
|
|
||||||
return paywallUrl.isNotEmpty ? paywallUrl : defaultUrl;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError('$runtimeType::getPaywallUrl: Failed to generate paywall URL: $e');
|
logError('$runtimeType::navigateToPaywall: Failed to navigate to paywall $e');
|
||||||
return defaultUrl;
|
_navigateToPaywallUseEcoSystem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _navigateToPaywallUseWorkplaceFqdn(String workplaceFqdn) {
|
||||||
|
final paywallUrl = WebLinkGenerator.safeGenerateWebLink(
|
||||||
|
workplaceFqdn: workplaceFqdn,
|
||||||
|
pathname: '/settings/premium',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (paywallUrl.isNotEmpty) {
|
||||||
|
AppUtils.launchLink(paywallUrl);
|
||||||
|
} else {
|
||||||
|
_navigateToPaywallUseEcoSystem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _navigateToPaywallUseEcoSystem() {
|
||||||
|
_loadPaywallUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _redirectPaywallPage(PaywallUrlPattern urlPattern) {
|
||||||
|
final qualifiedPaywall = urlPattern.getQualifiedUrl(
|
||||||
|
ownerEmail: ownEmailAddress,
|
||||||
|
domainName: RouteUtils.getRootDomain(),
|
||||||
|
);
|
||||||
|
AppUtils.launchLink(qualifiedPaywall);
|
||||||
|
}
|
||||||
|
|
||||||
void _handleRetryGetPaywallUrl() {
|
void _handleRetryGetPaywallUrl() {
|
||||||
isRetryGetPaywallUrl = true;
|
_loadPaywallUrl();
|
||||||
loadPaywallUrl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleSuccessViewState(Success success) {
|
void handleSuccessViewState(Success success) {
|
||||||
if (success is GetPaywallUrlSuccess) {
|
if (success is GetPaywallUrlSuccess) {
|
||||||
loadPaywallUrlSuccess(success.paywallUrlPattern);
|
_loadPaywallUrlSuccess(success.paywallUrlPattern);
|
||||||
} else {
|
} else {
|
||||||
super.handleSuccessViewState(success);
|
super.handleSuccessViewState(success);
|
||||||
}
|
}
|
||||||
@@ -133,28 +116,9 @@ class PaywallController extends BaseController {
|
|||||||
@override
|
@override
|
||||||
void handleFailureViewState(Failure failure) {
|
void handleFailureViewState(Failure failure) {
|
||||||
if (failure is GetPaywallUrlFailure) {
|
if (failure is GetPaywallUrlFailure) {
|
||||||
loadPaywallUrlFailure();
|
_loadPaywallUrlFailure();
|
||||||
} else {
|
} else {
|
||||||
super.handleFailureViewState(failure);
|
super.handleFailureViewState(failure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void handleErrorViewState(Object error, StackTrace stackTrace) {
|
|
||||||
super.handleErrorViewState(error, stackTrace);
|
|
||||||
isRetryGetPaywallUrl = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void handleUrgentExceptionOnWeb({Failure? failure, Exception? exception}) {
|
|
||||||
super.handleUrgentExceptionOnWeb(failure: failure, exception: exception);
|
|
||||||
isRetryGetPaywallUrl = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onClose() {
|
|
||||||
paywallUrlPattern = null;
|
|
||||||
isRetryGetPaywallUrl = false;
|
|
||||||
super.onClose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import 'package:core/presentation/state/failure.dart';
|
|||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:core/utils/app_logger.dart';
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
|
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
|
||||||
@@ -104,8 +103,8 @@ class QuotasController extends BaseController {
|
|||||||
mailboxDashBoardController.validateUserHasIsAlreadyHighestSubscription();
|
mailboxDashBoardController.validateUserHasIsAlreadyHighestSubscription();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleManageMyStorage(BuildContext context) {
|
void handleManageMyStorage() {
|
||||||
mailboxDashBoardController.paywallController?.navigateToPaywall(context);
|
mailboxDashBoardController.paywallController?.navigateToPaywall();
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeBanner() {
|
void closeBanner() {
|
||||||
|
|||||||
@@ -80,8 +80,8 @@ class QuotasBannerWidget extends StatelessWidget {
|
|||||||
backgroundColor: QuotasBannerStyles.backgroundColor,
|
backgroundColor: QuotasBannerStyles.backgroundColor,
|
||||||
textStyle: QuotasBannerStyles.manageStorageButtonTextStyle,
|
textStyle: QuotasBannerStyles.manageStorageButtonTextStyle,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
onTapActionCallback: () =>
|
onTapActionCallback:
|
||||||
_quotasController.handleManageMyStorage(context),
|
_quotasController.handleManageMyStorage,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class AppUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void launchLink(String url, {bool isNewTab = true}) {
|
static void launchLink(String url, {bool isNewTab = true}) {
|
||||||
|
log('AppUtils::launchLink: url = $url');
|
||||||
if (PlatformInfo.isWeb && HtmlUtils.isSafariBelow17()) {
|
if (PlatformInfo.isWeb && HtmlUtils.isSafariBelow17()) {
|
||||||
html.window.open(url, isNewTab ? '_blank' : '_self');
|
html.window.open(url, isNewTab ? '_blank' : '_self');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user