Skip to content
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
12 changes: 12 additions & 0 deletions .github/workflows/pr-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ jobs:
- name: 📦 Get Dependencies
run: flutter pub get

- name: 📦 Get Sample Dependencies
working-directory: samples/quickstart
run: flutter pub get

- name: 🔐 Create Sample .env
working-directory: samples/quickstart
run: cp .env.example .env

- name: 🔍 Run Flutter Analyze
run: flutter analyze

Expand Down Expand Up @@ -123,6 +131,10 @@ jobs:
working-directory: samples/quickstart
run: flutter pub get

- name: 🔐 Create Sample .env
working-directory: samples/quickstart
run: cp .env.example .env

- name: 🔨 Build Quickstart Sample
working-directory: samples/quickstart
run: flutter build apk --debug
26 changes: 13 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,19 @@ lib/
flow_template_resolver.dart Embedded-flow URL builder
widgets/
thunderid_provider.dart State provider (InheritedWidget root)
thunderid_sign_in_button.dart SignInButton / BaseSignInButton
thunderid_sign_up_button.dart SignUpButton / BaseSignUpButton
thunderid_sign_out_button.dart SignOutButton / BaseSignOutButton
thunderid_sign_in.dart Embedded sign-in form
thunderid_sign_up.dart Embedded sign-up form
thunderid_signed_in.dart Guard: renders child only when authenticated
thunderid_signed_out.dart Guard: inverse of SignedIn
thunderid_loading.dart Guard: renders while SDK is loading
thunderid_user.dart User info display
thunderid_user_dropdown.dart User dropdown menu
thunderid_user_profile.dart Full profile view
thunderid_callback.dart OAuth2 redirect handler
thunderid_language_switcher.dart Locale selector
sign_in_button.dart SignInButton / BaseSignInButton
sign_up_button.dart SignUpButton / BaseSignUpButton
sign_out_button.dart SignOutButton / BaseSignOutButton
sign_in.dart Embedded sign-in form
sign_up.dart Embedded sign-up form
signed_in.dart Guard: renders child only when authenticated
signed_out.dart Guard: inverse of SignedIn
loading.dart Guard: renders while SDK is loading
user_object.dart User info display
user_dropdown.dart User dropdown menu
user_profile.dart Full profile view
callback.dart OAuth2 redirect handler
language_switcher.dart Locale selector
flow_form.dart Reusable form wrapper for flow steps
android/ Kotlin method channel handler (JVM 17, minSdk 26)
ios/Classes/ Swift method channel handler (iOS 16+)
Expand Down
10 changes: 5 additions & 5 deletions lib/src/thunderid_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
*/

import 'channel/thunderid_channel.dart';
import 'models/thunderid_error.dart';
import 'models/thunderid_config.dart';
import 'models/user.dart';
import 'models/user_profile.dart';
import 'models/token_response.dart';
import 'models/flow_models.dart';
import 'models/sign_in_options.dart';
import 'models/sign_out_options.dart';
import 'models/thunderid_config.dart';
import 'models/thunderid_error.dart';
import 'models/token_exchange_config.dart';
import 'models/token_response.dart';
import 'models/user.dart';
import 'models/user_profile.dart';

/// Flutter SDK client — Core Lib layer, delegates all protocol operations to
/// the native iOS and Android Platform SDKs via [ThunderIDChannel] (spec §7.1).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
*/

import 'package:flutter/widgets.dart';
import 'thunderid_provider.dart';

import '../models/user.dart';
import 'thunderid_provider.dart';

/// Handles the OAuth2 redirect callback URL (spec §8.4 Auth Flow).
///
Expand Down
19 changes: 11 additions & 8 deletions lib/src/widgets/flow_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
*/

import 'package:flutter/material.dart';
import '../models/flow_models.dart';

import '../flow_template_resolver.dart';
import '../models/flow_models.dart';
import 'thunderid_provider.dart';

/// Internal widget used by [ThunderIDSignIn] and [ThunderIDSignUp] to render a
Expand Down Expand Up @@ -60,7 +61,9 @@ class _FlowFormState extends State<FlowForm> {

@override
void dispose() {
for (final c in _controllers.values) c.dispose();
for (final c in _controllers.values) {
c.dispose();
}
super.dispose();
}

Expand Down Expand Up @@ -106,7 +109,7 @@ class _FlowFormState extends State<FlowForm> {
context,
{'ref': _inputRef(i), 'label': '', 'type': i['type']},
_str(i['type']),
)),
),),
if (actions.isNotEmpty)
...actions.map((a) => _renderAction(context, a, actions))
else
Expand All @@ -121,7 +124,7 @@ class _FlowFormState extends State<FlowForm> {
Text(
widget.error!,
style: TextStyle(
color: Theme.of(context).colorScheme.error, fontSize: 13),
color: Theme.of(context).colorScheme.error, fontSize: 13,),
),
],
],
Expand Down Expand Up @@ -283,7 +286,7 @@ class _FlowFormState extends State<FlowForm> {
}

String _findActionId(
String metaActionId, List<Map<String, dynamic>> actions) {
String metaActionId, List<Map<String, dynamic>> actions,) {
if (actions.isEmpty) return 'submit';
final byRef = actions.firstWhere(
(a) => _str(a['ref']) == metaActionId,
Expand All @@ -304,7 +307,7 @@ class _FlowFormState extends State<FlowForm> {

String _actionSubmitId(Map<String, dynamic> a) => _str(a['ref'],
fallback: _str(a['id'],
fallback: _str(a['nextNode'], fallback: 'submit')));
fallback: _str(a['nextNode'], fallback: 'submit'),),);

int? _actionIndex(String id) {
if (!id.startsWith('action_')) return null;
Expand Down Expand Up @@ -359,11 +362,11 @@ class _FlowFormState extends State<FlowForm> {

String _fieldRef(Map<String, dynamic> comp) => _str(comp['ref'],
fallback: _str(comp['identifier'],
fallback: _str(comp['name'], fallback: _str(comp['id']))));
fallback: _str(comp['name'], fallback: _str(comp['id'])),),);

String _inputRef(Map<String, dynamic> input) => _str(input['name'],
fallback: _str(input['identifier'],
fallback: _str(input['ref'], fallback: _str(input['id']))));
fallback: _str(input['ref'], fallback: _str(input['id'])),),);

String _resolve(dynamic value, {String fallback = ''}) {
final s = value is String ? value.trim() : '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class _DefaultSpinner extends StatelessWidget {
// Stub — avoids a Material/Cupertino import at this layer.
// Replace with CircularProgressIndicator when using with Flutter Material.
class CircularProgressIndicatorStub extends StatelessWidget {
const CircularProgressIndicatorStub();
const CircularProgressIndicatorStub({super.key});

@override
Widget build(BuildContext context) => const SizedBox.shrink();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
* under the License.
*/

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'thunderid_provider.dart';
import 'flow_form.dart';
import 'package:flutter/material.dart';

import '../models/flow_models.dart';
import '../models/token_exchange_config.dart';
import '../models/user.dart';
import 'flow_form.dart';
import 'thunderid_provider.dart';

/// State exposed to [BaseThunderIDSignIn]'s builder.
class ThunderIDSignInState {
Expand Down Expand Up @@ -108,7 +109,7 @@ class _BaseSignInState extends State<BaseSignIn> {
try {
final state = ThunderIDProvider.of(context);
final response = await state.client.signIn(
payload: EmbeddedSignInPayload(actionId: 'init'),
payload: const EmbeddedSignInPayload(actionId: 'init'),
request: EmbeddedFlowRequestConfig(applicationId: widget.applicationId),
);
if (kDebugMode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
*/

import 'package:flutter/widgets.dart';
import 'thunderid_provider.dart';

import '../models/sign_out_options.dart';
import 'thunderid_provider.dart';

/// Triggers sign-out on tap. Accessible per WCAG 2.1 AA (spec §8.1).
class SignOutButton extends StatelessWidget {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
*/

import 'package:flutter/widgets.dart';
import 'thunderid_provider.dart';
import 'flow_form.dart';

import '../models/flow_models.dart';
import '../models/token_exchange_config.dart';
import 'flow_form.dart';
import 'thunderid_provider.dart';

/// Full registration form driving the REGISTRATION flow (spec §8.4 Presentation).
class SignUp extends StatelessWidget {
Expand Down Expand Up @@ -49,13 +50,13 @@ class SignUp extends StatelessWidget {
}
}

class _FlowState {
class ThunderIDSignUpState {
final EmbeddedFlowResponse? currentStep;
final bool isLoading;
final String? error;
final Future<void> Function(String actionId, Map<String, String> inputs) submit;

const _FlowState({
const ThunderIDSignUpState({
required this.currentStep,
required this.isLoading,
required this.error,
Expand All @@ -68,7 +69,7 @@ class BaseSignUp extends StatefulWidget {
final String applicationId;
final VoidCallback? onSuccess;
final VoidCallback? onError;
final Widget Function(BuildContext context, _FlowState state) builder;
final Widget Function(BuildContext context, ThunderIDSignUpState state) builder;

const BaseSignUp({
super.key,
Expand Down Expand Up @@ -98,7 +99,7 @@ class _BaseSignUpState extends State<BaseSignUp> {
try {
final state = ThunderIDProvider.of(context);
final response = await state.client.signUp(
payload: EmbeddedSignInPayload(actionId: 'init'),
payload: const EmbeddedSignInPayload(actionId: 'init'),
request: EmbeddedFlowRequestConfig(
applicationId: widget.applicationId,
flowType: FlowType.registration,
Expand Down Expand Up @@ -165,7 +166,7 @@ class _BaseSignUpState extends State<BaseSignUp> {
@override
Widget build(BuildContext context) => widget.builder(
context,
_FlowState(
ThunderIDSignUpState(
currentStep: _currentStep,
isLoading: _isLoading,
error: _error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
*/

import 'package:flutter/widgets.dart';
import 'thunderid_provider.dart';
import '../models/sign_up_options.dart';

import '../models/flow_models.dart';
import '../models/sign_up_options.dart';
import 'thunderid_provider.dart';

/// Initiates the sign-up flow on tap (spec §8.4 Actions).
class SignUpButton extends StatelessWidget {
Expand Down
7 changes: 4 additions & 3 deletions lib/src/widgets/thunderid_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
import 'dart:async';

import 'package:flutter/widgets.dart';
import '../thunderid_client.dart';
import '../models/thunderid_config.dart';

import '../i18n/thunderid_i18n.dart';
import '../models/preferences.dart';
import '../models/thunderid_config.dart';
import '../models/user.dart';
import '../i18n/thunderid_i18n.dart';
import '../thunderid_client.dart';

/// Provides a [ThunderIDClient] and reactive authentication state to the widget tree.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
*/

import 'package:flutter/widgets.dart';
import 'thunderid_provider.dart';

import '../models/user.dart';
import 'thunderid_provider.dart';

/// Avatar chip that opens a menu with profile and sign-out actions (spec §8.4 Presentation).
class UserDropdown extends StatelessWidget {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
*/

import 'package:flutter/widgets.dart';
import 'thunderid_provider.dart';

import '../i18n/thunderid_i18n.dart';
import '../models/user.dart';
import 'thunderid_provider.dart';

/// Read-only display of the authenticated user's name and avatar (spec §8.4 Presentation).
class UserObject extends StatelessWidget {
Expand All @@ -35,7 +37,7 @@ class UserObject extends StatelessWidget {

class _DefaultUserLayout extends StatelessWidget {
final User? user;
final dynamic i18n;
final ThunderIDI18n i18n;

const _DefaultUserLayout({required this.user, required this.i18n});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
*/

import 'dart:convert';

import 'package:flutter/material.dart';
import 'thunderid_provider.dart';

import '../models/user_profile.dart' as model;
import 'thunderid_provider.dart';

/// Read-only profile view built from the decoded access token.
class UserProfile extends StatelessWidget {
Expand Down Expand Up @@ -140,7 +142,9 @@ class _BaseUserProfileState extends State<BaseUserProfile> {

@override
void dispose() {
for (final c in _controllers.values) c.dispose();
for (final c in _controllers.values) {
c.dispose();
}
super.dispose();
}

Expand All @@ -164,7 +168,7 @@ class _BaseUserProfileState extends State<BaseUserProfile> {
final profile = model.UserProfile(id: payload['sub'] as String? ?? '', claims: profileClaims);
for (final entry in profileClaims.entries) {
_controllers.putIfAbsent(
entry.key, () => TextEditingController(text: entry.value?.toString() ?? ''));
entry.key, () => TextEditingController(text: entry.value?.toString() ?? ''),);
}
if (mounted) setState(() => _profile = profile);
} catch (e) {
Expand Down
Loading
Loading