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

feat: Added APKAM enrollment authorisation functionality into the app #1664

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion packages/dart/npt_flutter/l10n.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
arb-dir: lib/localization
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-localization-file: app_localizations.dart
14 changes: 13 additions & 1 deletion packages/dart/npt_flutter/lib/app.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'dart:io';

import 'package:at_onboarding_flutter/at_onboarding_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:npt_flutter/features/authorisation/cubit/pending_requests_count_cubit.dart';
import 'package:npt_flutter/features/features.dart';
import 'package:npt_flutter/routes.dart';
import 'package:npt_flutter/styles/app_theme.dart';
Expand Down Expand Up @@ -32,6 +34,9 @@ class App extends StatelessWidget {
RepositoryProvider<FavoriteRepository>(
create: (_) => FavoriteRepository(),
),
RepositoryProvider<AuthorisationService>(
create: (_) => AuthorisationService(AtClientManager.getInstance().atClient)..init(),
Zambrella marked this conversation as resolved.
Show resolved Hide resolved
),
],
child: MultiBlocProvider(
providers: [
Expand Down Expand Up @@ -93,6 +98,10 @@ class App extends StatelessWidget {
BlocProvider<FavoriteBloc>(
create: (ctx) => FavoriteBloc(ctx.read<FavoriteRepository>()),
),

BlocProvider<PendingRequestsCountCubit>(
create: (ctx) => PendingRequestsCountCubit(ctx.read<AuthorisationService>()),
),
],
child: BlocSelector<SettingsBloc, SettingsState, Language?>(selector: (state) {
if (state is SettingsLoadedState) {
Expand All @@ -107,7 +116,10 @@ class App extends StatelessWidget {
child: MaterialApp(
key: const Key("MaterialApp"),
theme: AppTheme.light(),
localizationsDelegates: AppLocalizations.localizationsDelegates,
localizationsDelegates: const [
AtClientMobileLocalizations.delegate,
...AppLocalizations.localizationsDelegates,
],
supportedLocales: AppLocalizations.supportedLocales,
locale: locale,
localeResolutionCallback: (locale, supportedLocales) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'dart:async';

import 'package:at_client_mobile/at_client_mobile.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class PendingRequestsCountCubit extends Cubit<int> {
Zambrella marked this conversation as resolved.
Show resolved Hide resolved
PendingRequestsCountCubit(this._authorisationService) : super(0) {
// Update the count whenever a new request is made
_subscription = _authorisationService.enrollmentRequests().listen((_) => getPendingRequests());
getPendingRequests();
}

final AuthorisationService _authorisationService;
StreamSubscription<ServerEnrollmentRequest>? _subscription;

Future<void> getPendingRequests() async {
final requests = await _authorisationService.getEnrollmentRequests(
statusFilters: [EnrollmentStatus.pending],
);
emit(requests.length);
}

@override
Future<void> close() {
_subscription?.cancel();
return super.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:at_client_mobile/at_client_mobile.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class AuthorisationView extends StatelessWidget {
const AuthorisationView({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(64.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: AuthorisationHub(
service: context.watch<AuthorisationService>(),
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'dart:async';

import 'package:at_client_mobile/at_client_mobile.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:npt_flutter/features/authorisation/cubit/pending_requests_count_cubit.dart';
import 'package:npt_flutter/routes.dart';
import 'package:visibility_detector/visibility_detector.dart';

class AuthorisationAppBarButton extends StatefulWidget {
const AuthorisationAppBarButton({super.key});

@override
AuthorisationAppBarButtonState createState() => AuthorisationAppBarButtonState();
}

class AuthorisationAppBarButtonState extends State<AuthorisationAppBarButton> {
@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
final strings = AppLocalizations.of(context)!;
return VisibilityDetector(
key: const Key('authorisation_app_bar_button'),
onVisibilityChanged: (visibilityInfo) {
// Need a way of getting the latest count
// When a page is pushed on top of this it doesn't get rebuilt
// so using this as a proxy
if (visibilityInfo.visibleFraction > 0.9) {
unawaited(context.read<PendingRequestsCountCubit>().getPendingRequests());
}
},
child: StreamBuilder(
stream: context.read<AuthorisationService>().enrollmentRequests(statusFilters: [EnrollmentStatus.pending]),
builder: (context, snapshot) {
// TODO: On new request, display a notification
return BlocBuilder<PendingRequestsCountCubit, int>(
builder: (context, authorisationNotificationCount) {
return IconButton(
tooltip: strings.authorisation,
icon: Badge.count(
count: authorisationNotificationCount,
isLabelVisible: authorisationNotificationCount > 0,
backgroundColor: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
textColor: Theme.of(context).colorScheme.primary,
child: const Icon(Icons.key_outlined),
),
onPressed: () {
Navigator.pushNamed(context, Routes.authorisation);
},
);
},
);
},
),
);
}
}
3 changes: 2 additions & 1 deletion packages/dart/npt_flutter/lib/localization/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"atDirectorySubtitle": "Select the domain you want to use",
"atsignDialogSubtitle": "Please select your atSign",
"atsignDialogTitle": "AtSign",
"authorisation": "Authorisation",
"back": "Back",
"backupKeyDialogTitle": "Please select a file to export to:",
"backupYourKey": "Back up your Key",
Expand Down Expand Up @@ -137,4 +138,4 @@
"validationErrorRemoteHostField": "Field must be partially or fully qualified hostname or an IP address",
"validationErrorRemotePortField": "Number must be between 1 and 65535",
"yaml": "YAML"
}
}
21 changes: 21 additions & 0 deletions packages/dart/npt_flutter/lib/pages/authorisation_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:npt_flutter/features/authorisation/view/authorisation_view.dart';
import 'package:npt_flutter/styles/app_color.dart';
import 'package:npt_flutter/widgets/npt_app_bar.dart';

class AuthorisationPage extends StatelessWidget {
const AuthorisationPage({super.key});

@override
Widget build(BuildContext context) {
final strings = AppLocalizations.of(context)!;
return Scaffold(
appBar: NptAppBar(
title: strings.authorisation,
settingsSelectedColor: AppColor.primaryColor,
),
body: const AuthorisationView(),
);
}
}
1 change: 1 addition & 0 deletions packages/dart/npt_flutter/lib/pages/pages.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export 'authorisation_page.dart';
export 'dashboard_page.dart';
export 'loading_page.dart';
export 'onboarding_page.dart';
Expand Down
2 changes: 2 additions & 0 deletions packages/dart/npt_flutter/lib/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ class Routes {
static const onboarding = '/';
static const dashboard = '/dashboard';
static const settings = '/settings';
static const authorisation = '/authorisation';
static const profileForm = '/profile';
static const loadingPage = '/loading';

static final Map<String, WidgetBuilder> routes = {
onboarding: (_) => const OnboardingPage(nextRoute: dashboard),
dashboard: (_) => const DashboardPage(),
settings: (_) => const SettingsPage(),
authorisation: (_) => const AuthorisationPage(),
profileForm: (_) => const ProfileFormPage(),
loadingPage: (_) => const LoadingPage(),
};
Expand Down
35 changes: 16 additions & 19 deletions packages/dart/npt_flutter/lib/widgets/npt_app_bar.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:npt_flutter/features/authorisation/widgets/authorisation_app_bar_button.dart';
import 'package:npt_flutter/routes.dart';
import 'package:npt_flutter/styles/app_color.dart';
import 'package:npt_flutter/styles/style_constants.dart';

Expand Down Expand Up @@ -29,6 +31,7 @@ class NptAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
final strings = AppLocalizations.of(context)!;
final isDashboard = ModalRoute.of(context)?.settings.name == Routes.dashboard;
return SizedBox(
width: Sizes.p853,
child: AppBar(
Expand Down Expand Up @@ -87,25 +90,19 @@ class NptAppBar extends StatelessWidget implements PreferredSizeWidget {
],
),
actions: [
showSettings
? Padding(
padding: EdgeInsets.only(
bottom: Sizes.p30,
right: MediaQuery.of(context).size.width * settingsIconWidthFactor,
),
child: TextButton.icon(
label: Text(strings.settings),
icon: Icon(
Icons.settings_outlined,
color: settingsSelectedColor,
),
onPressed: () {
// the primary color is used when the navbar is on the settings screen and therefore the settings icon is not clickable.
if (settingsSelectedColor != AppColor.primaryColor) Navigator.pushNamed(context, '/settings');
},
),
)
: gap0,
if (isDashboard) const AuthorisationAppBarButton(),
if (showSettings && isDashboard)
IconButton(
tooltip: strings.settings,
icon: Icon(
Icons.settings_outlined,
color: settingsSelectedColor,
),
onPressed: () {
Navigator.pushNamed(context, Routes.settings);
},
),
SizedBox(width: MediaQuery.of(context).size.width * settingsIconWidthFactor),
],
centerTitle: true,
),
Expand Down
26 changes: 13 additions & 13 deletions packages/dart/npt_flutter/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,20 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos

SPEC CHECKSUMS:
at_file_saver: 1fc6ed722f17c7a20ce79cce168d1100fcad4b95
biometric_storage: 43caa6e7ef00e8e19c074216e7e1786dacda9e76
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
at_file_saver: 598610e2f4579e4193faa1187fd4f87ffbfc3a0f
biometric_storage: 9de0cb4e591e52329ca0da7df42e964db6c526cf
device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
share_plus: 1fa619de8392a4398bfaf176d441853922614e89
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
tray_manager: 9064e219c56d75c476e46b9a21182087930baf90
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
webview_flutter_wkwebview: 44d4dee7d7056d5ad185d25b38404436d56c547c
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c

PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367

Expand Down
25 changes: 21 additions & 4 deletions packages/dart/npt_flutter/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,11 @@ packages:
at_client_mobile:
dependency: "direct main"
description:
name: at_client_mobile
sha256: "41f45cc094bfc7748303ce263e490d9744bb6014e4c1183df9e983488714fb7e"
url: "https://pub.dev"
source: hosted
path: "packages/at_client_mobile"
ref: "8e8b68d2f00db0aeca266685be1e9c0b103ad301"
resolved-ref: "8e8b68d2f00db0aeca266685be1e9c0b103ad301"
url: "https://github.com/atsign-foundation/at_client_sdk.git"
source: git
version: "3.2.19"
at_common_flutter:
dependency: transitive
Expand Down Expand Up @@ -481,6 +482,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.2"
duration:
dependency: transitive
description:
name: duration
sha256: "13e5d20723c9c1dde8fb318cf86716d10ce294734e81e44ae1a817f3ae714501"
url: "https://pub.dev"
source: hosted
version: "4.0.3"
ecdsa:
dependency: transitive
description:
Expand Down Expand Up @@ -1585,6 +1594,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
visibility_detector:
dependency: "direct main"
description:
name: visibility_detector
sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420
url: "https://pub.dev"
source: hosted
version: "0.4.0+2"
vm_service:
dependency: transitive
description:
Expand Down
17 changes: 15 additions & 2 deletions packages/dart/npt_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,17 @@ dependencies:
adaptive_theme: ^3.6.0
at_auth: ^2.0.7
at_backupkey_flutter: ^4.0.16
at_client_mobile: ^3.2.18
at_client_mobile:
git:
url: https://github.com/atsign-foundation/at_client_sdk.git
path: packages/at_client_mobile
ref: 8e8b68d2f00db0aeca266685be1e9c0b103ad301
at_contact: ^3.0.8
at_contacts_flutter: ^4.0.15
at_onboarding_flutter: ^6.1.8
at_onboarding_flutter:
git:
url: https://github.com/atsign-foundation/at_widgets.git
path: packages/at_onboarding_flutter
at_server_status: ^1.0.5
at_utils: ^3.0.16
cupertino_icons: ^1.0.8
Expand Down Expand Up @@ -72,6 +79,7 @@ dependencies:
tray_manager: ^0.2.3
url_launcher: ^6.3.0
uuid: ^3.0.7
visibility_detector: ^0.4.0+2
window_manager: ^0.4.2
yaml: ^3.1.2
yaml_writer: ^2.0.0
Expand All @@ -97,6 +105,11 @@ dependency_overrides:
url: https://github.com/atsign-foundation/at_widgets
ref: at_onboarding_flutter_layers
path: packages/at_onboarding_flutter
at_client_mobile:
git:
url: https://github.com/atsign-foundation/at_client_sdk.git
path: packages/at_client_mobile
ref: 8e8b68d2f00db0aeca266685be1e9c0b103ad301
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
Expand Down
Loading