Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Reorganize subscription status #1017

Merged
merged 6 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gui/packages/ubuntupro/end_to_end/end_to_end_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Future<void> testOrganizationProvidedToken(WidgetTester tester) async {

// asserts that we transitioned to the organization-managed status page.
final l10n = tester.l10n<SubscriptionStatusPage>();
expect(find.text(l10n.orgManaged), findsOneWidget);
expect(find.text(l10n.manageUbuntuPro), findsNothing);
}

Future<void> testManualTokenInput(WidgetTester tester) async {
Expand Down Expand Up @@ -99,5 +99,5 @@ Future<void> testPurchase(WidgetTester tester) async {

// asserts that we transitioned to the store-managed status page.
l10n = tester.l10n<SubscriptionStatusPage>();
expect(find.text(l10n.storeManaged), findsOneWidget);
expect(find.text(l10n.manageUbuntuPro), findsOneWidget);
}
15 changes: 3 additions & 12 deletions gui/packages/ubuntupro/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,9 @@
"getUbuntuPro": "Get Ubuntu Pro",
"learnMore": "Learn more",

"subscriptionIsActive": "Your subscription is active!",
"storeManaged": "This subscription is managed through Microsoft Store.",
"manageSubscription": "Manage your subscription",
"orgManaged": "This subscription is owned and managed by your organization.",
"manuallyManaged": "Visit {proDashboardLink} to manage your subscription.",
"@manuallyManaged": {
"placeholders": {
"proDashboardLink": {
"type": "String"
}
}
},
"ubuntuProEnabled": "Ubuntu Pro is enabled on this machine.",
"ubuntuProEnabledInfo": "All Ubuntu WSL instances have access to Ubuntu Pro security features.",
"manageUbuntuPro": "Manage Ubuntu Pro subscription",
"detachPro": "Detach Ubuntu Pro",

"updatingSubscriptionInfo": "Updating the subscription information.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'package:agentapi/agentapi.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:provider/provider.dart';
import 'package:ubuntu_service/ubuntu_service.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:wizard_router/wizard_router.dart';
import 'package:yaru/yaru.dart';

Expand All @@ -24,19 +26,17 @@ class SubscriptionStatusPage extends StatelessWidget {
duration: const Duration(milliseconds: 700),
child: switch (model) {
StoreSubscriptionStatusModel() => SubscriptionStatus(
caption: lang.storeManaged,
actionButtons: [
if (model.canConfigureLandscape) _landscapeButton(context),
OutlinedButton(
onPressed: model.launchManagementWebPage,
child: Text(lang.manageSubscription),
],
footerLinks: [
MarkdownBody(
data: '[${lang.manageUbuntuPro}]()',
onTapLink: (_, href, __) => model.launchManagementWebPage(),
),
],
),
UserSubscriptionStatusModel() => SubscriptionStatus(
caption: lang.manuallyManaged(
'[ubuntu.com/pro/dashboard](https://ubuntu.com/pro/dashboard)',
),
actionButtons: [
if (model.canConfigureLandscape) _landscapeButton(context),
ElevatedButton(
Expand All @@ -59,9 +59,15 @@ class SubscriptionStatusPage extends StatelessWidget {
child: Text(lang.detachPro),
),
],
footerLinks: [
MarkdownBody(
data: '[${lang.manageUbuntuPro}]()',
onTapLink: (_, href, __) =>
launchUrlString('https://ubuntu.com/pro/dashboard'),
),
],
),
OrgSubscriptionStatusModel() => SubscriptionStatus(
caption: lang.orgManaged,
actionButtons: model.canConfigureLandscape
? [_landscapeButton(context)]
: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,38 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:yaru/yaru.dart';
import '../widgets/page_widgets.dart';
import '/pages/widgets/page_widgets.dart';

/// A page content widget built on top of the Dark styled landing page showing the current user active subscription
/// feedback and an optional action button in a column layout.
class SubscriptionStatus extends StatelessWidget {
const SubscriptionStatus({
super.key,
required this.caption,
this.actionButtons,
this.footerLinks,
});

/// The caption to render below the active subscription subtitle.
final String caption;

/// The optional action button matching the capabilities of the current subscription type.
final List<Widget>? actionButtons;

final List<Widget>? footerLinks;

@override
Widget build(BuildContext context) {
final lang = AppLocalizations.of(context);

final theme = Theme.of(context);
final linkStyle = MarkdownStyleSheet.fromTheme(
theme.copyWith(
textTheme: theme.textTheme.copyWith(
bodyMedium: theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w100,
),
),
),
).copyWith(
a: TextStyle(
decoration: TextDecoration.underline,
color: theme.colorScheme.onSurface,
),
);

return LandingPage(
centered: true,
return CenteredPage(
footer: footerLinks != null
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: footerLinks!,
)
: null,
children: [
const SizedBox(height: 16.0),
YaruInfoBox(
title: Text(lang.subscriptionIsActive),
subtitle: MarkdownBody(
data: caption,
onTapLink: (_, href, __) => launchUrlString(href!),
styleSheet: linkStyle,
),
title: Text(lang.ubuntuProEnabled),
subtitle: Text(lang.ubuntuProEnabledInfo),
yaruInfoType: YaruInfoType.success,
),
if (actionButtons != null)
Expand Down
120 changes: 43 additions & 77 deletions gui/packages/ubuntupro/lib/pages/widgets/page_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,103 +69,69 @@ class Pro4WSLPage extends StatelessWidget {
}
}

// A more stylized page that mimics the design of the https://ubuntu.com/pro
// landing page, with a dark background and an [svgAsset] logo followed by
// a title with some opacity, rendering the [children] in a column layout.
class LandingPage extends StatelessWidget {
const LandingPage({
class CenteredPage extends StatelessWidget {
const CenteredPage({
super.key,
required this.children,
this.svgAsset = 'assets/Ubuntu-tag.svg',
this.title = 'Ubuntu Pro',
this.centered = false,
this.footer,
});

final List<Widget> children;
final Widget? footer;
final String svgAsset;
final String title;
final bool centered;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);

return Pro4WSLPage(
body: Padding(
padding: const EdgeInsets.fromLTRB(32.0, 32.0, 32.0, 8.0),
child: centered
? Center(
padding: const EdgeInsets.fromLTRB(32.0, 24.0, 32.0, 32.0),
child: Column(
children: [
Expanded(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 480.0),
child: _PageContent(
svgAsset: svgAsset,
title: title,
data: theme,
centered: true,
children: children,
constraints: const BoxConstraints(maxWidth: 540.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RichText(
text: TextSpan(
children: [
WidgetSpan(
child: SvgPicture.asset(
svgAsset,
height: 70,
),
),
const WidgetSpan(
child: SizedBox(
width: 8,
),
),
TextSpan(
text: title,
style: theme.textTheme.displaySmall
?.copyWith(fontWeight: FontWeight.w100),
),
],
),
),
const SizedBox(height: 16),
...children,
],
),
),
)
: _PageContent(
svgAsset: svgAsset,
title: title,
data: theme,
children: children,
),
),
);
}
}

class _PageContent extends StatelessWidget {
const _PageContent({
required this.svgAsset,
required this.title,
required ThemeData data,
required this.children,
this.centered = false,
}) : _data = data;

final String svgAsset;
final String title;
final ThemeData _data;
final List<Widget> children;
final bool centered;

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment:
centered ? CrossAxisAlignment.center : CrossAxisAlignment.start,
mainAxisAlignment:
centered ? MainAxisAlignment.center : MainAxisAlignment.start,
children: [
RichText(
text: TextSpan(
children: [
WidgetSpan(
child: SvgPicture.asset(
svgAsset,
height: 70,
),
),
const WidgetSpan(
child: SizedBox(
width: 8,
),
),
TextSpan(
text: title,
style: _data.textTheme.displaySmall
?.copyWith(fontWeight: FontWeight.w100),
),
],
),
),
const SizedBox(
height: 12,
),
if (footer != null) footer!,
],
),
...children,
],
),
);
}
}
Expand Down
Loading
Loading