diff --git a/.github/workflows/deep_link_client.yaml b/.github/workflows/deep_link_client.yaml index 9425eac3c..bfdad6593 100644 --- a/.github/workflows/deep_link_client.yaml +++ b/.github/workflows/deep_link_client.yaml @@ -7,14 +7,14 @@ concurrency: on: pull_request: paths: - - "flutter_news_example/packages/deep_link_client/**" + - "flutter_news_example/packages/deep_link_client/deep_link_client/**" - ".github/workflows/deep_link_client.yaml" branches: - main jobs: build: - uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1 + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 with: - flutter_version: 3.24.2 - working_directory: flutter_news_example/packages/deep_link_client + dart_sdk: 3.4.3 + working_directory: flutter_news_example/packages/deep_link_client/deep_link_client diff --git a/.github/workflows/firebase_deep_link_client.yaml b/.github/workflows/firebase_deep_link_client.yaml new file mode 100644 index 000000000..a10be4b8c --- /dev/null +++ b/.github/workflows/firebase_deep_link_client.yaml @@ -0,0 +1,20 @@ +name: firebase_deep_link_client + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + pull_request: + paths: + - "flutter_news_example/packages/deep_link_client/firebase_deep_link_client/**" + - ".github/workflows/firebase_deep_link_client.yaml" + branches: + - main + +jobs: + build: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1 + with: + flutter_version: 3.22.2 + working_directory: flutter_news_example/packages/deep_link_client/firebase_deep_link_client diff --git a/flutter_news_example/lib/main/main_development.dart b/flutter_news_example/lib/main/main_development.dart index b77df1277..1f7aaa182 100644 --- a/flutter_news_example/lib/main/main_development.dart +++ b/flutter_news_example/lib/main/main_development.dart @@ -2,6 +2,7 @@ import 'package:ads_consent_client/ads_consent_client.dart'; import 'package:article_repository/article_repository.dart'; import 'package:deep_link_client/deep_link_client.dart'; import 'package:firebase_authentication_client/firebase_authentication_client.dart'; +import 'package:firebase_deep_link_client/firebase_deep_link_client.dart'; import 'package:firebase_notifications_client/firebase_notifications_client.dart'; import 'package:flutter_news_example/app/app.dart'; import 'package:flutter_news_example/main/bootstrap/bootstrap.dart'; @@ -43,8 +44,10 @@ void main() { packageVersion: packageVersion, ); - final deepLinkClient = DeepLinkClient( - firebaseDynamicLinks: firebaseDynamicLinks, + final deepLinkService = DeepLinkService( + deepLinkClient: FirebaseDeepLinkClient( + firebaseDynamicLinks: firebaseDynamicLinks, + ), ); final userStorage = UserStorage(storage: persistentStorage); @@ -61,7 +64,7 @@ void main() { apiClient: apiClient, authenticationClient: authenticationClient, packageInfoClient: packageInfoClient, - deepLinkClient: deepLinkClient, + deepLinkService: deepLinkService, storage: userStorage, ); diff --git a/flutter_news_example/lib/main/main_production.dart b/flutter_news_example/lib/main/main_production.dart index d3d404dac..e7acf001c 100644 --- a/flutter_news_example/lib/main/main_production.dart +++ b/flutter_news_example/lib/main/main_production.dart @@ -2,6 +2,7 @@ import 'package:ads_consent_client/ads_consent_client.dart'; import 'package:article_repository/article_repository.dart'; import 'package:deep_link_client/deep_link_client.dart'; import 'package:firebase_authentication_client/firebase_authentication_client.dart'; +import 'package:firebase_deep_link_client/firebase_deep_link_client.dart'; import 'package:firebase_notifications_client/firebase_notifications_client.dart'; import 'package:flutter_news_example/app/app.dart'; import 'package:flutter_news_example/main/bootstrap/bootstrap.dart'; @@ -43,8 +44,10 @@ void main() { packageVersion: packageVersion, ); - final deepLinkClient = DeepLinkClient( - firebaseDynamicLinks: firebaseDynamicLinks, + final deepLinkService = DeepLinkService( + deepLinkClient: FirebaseDeepLinkClient( + firebaseDynamicLinks: firebaseDynamicLinks, + ), ); final userStorage = UserStorage(storage: persistentStorage); @@ -61,7 +64,7 @@ void main() { apiClient: apiClient, authenticationClient: authenticationClient, packageInfoClient: packageInfoClient, - deepLinkClient: deepLinkClient, + deepLinkService: deepLinkService, storage: userStorage, ); diff --git a/flutter_news_example/packages/deep_link_client/deep_link_client/analysis_options.yaml b/flutter_news_example/packages/deep_link_client/deep_link_client/analysis_options.yaml new file mode 100644 index 000000000..799268d3e --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/deep_link_client/analysis_options.yaml @@ -0,0 +1 @@ +include: package:very_good_analysis/analysis_options.5.1.0.yaml diff --git a/flutter_news_example/packages/deep_link_client/deep_link_client/lib/deep_link_client.dart b/flutter_news_example/packages/deep_link_client/deep_link_client/lib/deep_link_client.dart new file mode 100644 index 000000000..083f7826c --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/deep_link_client/lib/deep_link_client.dart @@ -0,0 +1,2 @@ +export 'src/deep_link_client.dart'; +export 'src/deep_link_service.dart'; diff --git a/flutter_news_example/packages/deep_link_client/deep_link_client/lib/src/deep_link_client.dart b/flutter_news_example/packages/deep_link_client/deep_link_client/lib/src/deep_link_client.dart new file mode 100644 index 000000000..c5265c179 --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/deep_link_client/lib/src/deep_link_client.dart @@ -0,0 +1,11 @@ +/// {@template deep_link_client} +/// A generic DeepLinkClient interface. +/// {@endtemplate} +abstract class DeepLinkClient { + /// Provides a stream of URIs intercepted by the app. Will emit the latest + /// received value (if any) as first. + Stream get deepLinkStream; + + /// Retrieves the initial deep link if present. + Future getInitialLink(); +} diff --git a/flutter_news_example/packages/deep_link_client/lib/src/deep_link_client.dart b/flutter_news_example/packages/deep_link_client/deep_link_client/lib/src/deep_link_service.dart similarity index 60% rename from flutter_news_example/packages/deep_link_client/lib/src/deep_link_client.dart rename to flutter_news_example/packages/deep_link_client/deep_link_client/lib/src/deep_link_service.dart index 32aac103a..4da62b071 100644 --- a/flutter_news_example/packages/deep_link_client/lib/src/deep_link_client.dart +++ b/flutter_news_example/packages/deep_link_client/deep_link_client/lib/src/deep_link_service.dart @@ -2,9 +2,8 @@ import 'dart:async'; +import 'package:deep_link_client/deep_link_client.dart'; import 'package:equatable/equatable.dart'; -import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; - import 'package:rxdart/rxdart.dart'; /// {@template deep_link_client_failure} @@ -21,21 +20,20 @@ class DeepLinkClientFailure with EquatableMixin implements Exception { List get props => [error]; } -/// {@template deep_link_client} -/// A client that exposes a stream of deep link URIs redirected to the app. +/// {@template deep_link_service} +/// A DeepLinkService that provides access to deep links intercepted by the app. /// {@endtemplate} -class DeepLinkClient { - /// {@macro deep_link_client} - DeepLinkClient({FirebaseDynamicLinks? firebaseDynamicLinks}) - : _deepLinkSubject = BehaviorSubject() { - _firebaseDynamicLinks = - firebaseDynamicLinks ?? FirebaseDynamicLinks.instance; - +class DeepLinkService { + /// {@macro deep_link_service} + DeepLinkService({ + required DeepLinkClient deepLinkClient, + }) : _deepLinkClient = deepLinkClient, + _deepLinkSubject = BehaviorSubject() { unawaited(_getInitialLink()); - _firebaseDynamicLinks.onLink.listen(_onAppLink).onError(_handleError); + _deepLinkClient.deepLinkStream.listen(_onAppLink).onError(_handleError); } - late final FirebaseDynamicLinks _firebaseDynamicLinks; + final DeepLinkClient _deepLinkClient; final BehaviorSubject _deepLinkSubject; /// Provides a stream of URIs intercepted by the app. Will emit the latest @@ -44,7 +42,7 @@ class DeepLinkClient { Future _getInitialLink() async { try { - final deepLink = await _firebaseDynamicLinks.getInitialLink(); + final deepLink = await _deepLinkClient.getInitialLink(); if (deepLink != null) { _onAppLink(deepLink); } @@ -53,8 +51,8 @@ class DeepLinkClient { } } - void _onAppLink(PendingDynamicLinkData dynamicLinkData) { - _deepLinkSubject.add(dynamicLinkData.link); + void _onAppLink(Uri deepLink) { + _deepLinkSubject.add(deepLink); } void _handleError(Object error, StackTrace stackTrace) { diff --git a/flutter_news_example/packages/deep_link_client/deep_link_client/pubspec.yaml b/flutter_news_example/packages/deep_link_client/deep_link_client/pubspec.yaml new file mode 100644 index 000000000..5fc8421cc --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/deep_link_client/pubspec.yaml @@ -0,0 +1,15 @@ +name: deep_link_client +description: A deep link client interface +publish_to: none + +environment: + sdk: ">=3.0.0 <4.0.0" + +dependencies: + equatable: ^2.0.5 + rxdart: ^0.27.5 + +dev_dependencies: + mocktail: ^1.0.4 + test: ^1.25.8 + very_good_analysis: ^6.0.0 diff --git a/flutter_news_example/packages/deep_link_client/deep_link_client/test/deep_link_service_test.dart b/flutter_news_example/packages/deep_link_client/deep_link_client/test/deep_link_service_test.dart new file mode 100644 index 000000000..30ab3c1c7 --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/deep_link_client/test/deep_link_service_test.dart @@ -0,0 +1,91 @@ +import 'dart:async'; + +import 'package:deep_link_client/deep_link_client.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +typedef OnAppLinkFunction = void Function(Uri uri, String stringUri); + +class MockDeepLinkClient extends Mock implements DeepLinkClient {} + +void main() { + late DeepLinkClient deepLinkClient; + late StreamController onDeepLinkStreamController; + + setUp(() { + deepLinkClient = MockDeepLinkClient(); + onDeepLinkStreamController = StreamController(); + when(() => deepLinkClient.deepLinkStream) + .thenAnswer((_) => onDeepLinkStreamController.stream); + }); + + tearDown(() { + onDeepLinkStreamController.close(); + }); + + group('DeepLinkService', () { + test('retrieves and publishes latest link if present', () { + final expectedUri = Uri.https('ham.app.test', '/test/path'); + when(deepLinkClient.getInitialLink).thenAnswer( + (_) => Future.value(expectedUri), + ); + + final service = DeepLinkService(deepLinkClient: deepLinkClient); + expect(service.deepLinkStream, emits(expectedUri)); + + // Testing also the replay of the latest value. + expect(service.deepLinkStream, emits(expectedUri)); + }); + + test('publishes DeepLinkClientFailure to stream if upstream throws', () { + final expectedError = Error(); + final expectedStackTrace = StackTrace.current; + + when(deepLinkClient.getInitialLink).thenAnswer((_) { + return Future.error(expectedError, expectedStackTrace); + }); + + final deepLinkService = DeepLinkService(deepLinkClient: deepLinkClient); + expect( + deepLinkService.deepLinkStream, + emitsError( + isA() + .having((failure) => failure.error, 'error', expectedError), + ), + ); + }); + + test('publishes values received through onAppLink callback', () { + final expectedUri1 = Uri.https('ham.app.test', '/test/1'); + final expectedUri2 = Uri.https('ham.app.test', '/test/2'); + + when(deepLinkClient.getInitialLink).thenAnswer((_) async => null); + + final deepLinkService = DeepLinkService(deepLinkClient: deepLinkClient); + + expect( + deepLinkService.deepLinkStream, + emitsInOrder( + [expectedUri1, expectedUri1, expectedUri2, expectedUri1], + ), + ); + + onDeepLinkStreamController + ..add(expectedUri1) + ..add(expectedUri1) + ..add(expectedUri2) + ..add(expectedUri1); + }); + }); + + group('DeepLinkClientFailure', () { + final error = Exception('errorMessage'); + + test('has correct props', () { + expect( + DeepLinkClientFailure(error).props, + [error], + ); + }); + }); +} diff --git a/flutter_news_example/packages/deep_link_client/analysis_options.yaml b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/analysis_options.yaml similarity index 100% rename from flutter_news_example/packages/deep_link_client/analysis_options.yaml rename to flutter_news_example/packages/deep_link_client/firebase_deep_link_client/analysis_options.yaml diff --git a/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/lib/firebase_deep_link_client.dart b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/lib/firebase_deep_link_client.dart new file mode 100644 index 000000000..527252c3a --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/lib/firebase_deep_link_client.dart @@ -0,0 +1 @@ +export 'src/firebase_deep_link_client.dart'; diff --git a/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/lib/src/firebase_deep_link_client.dart b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/lib/src/firebase_deep_link_client.dart new file mode 100644 index 000000000..f371c87a2 --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/lib/src/firebase_deep_link_client.dart @@ -0,0 +1,27 @@ +// ignore_for_file: deprecated_member_use + +import 'dart:async'; + +import 'package:deep_link_client/deep_link_client.dart'; +import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; + +/// {@template firebase_deep_link_client} +/// A FirebaseDynamicLinks implementation of [DeepLinkClient]. +/// {@endtemplate} +class FirebaseDeepLinkClient implements DeepLinkClient { + /// {@macro firebase_deep_link_client} + FirebaseDeepLinkClient({required FirebaseDynamicLinks firebaseDynamicLinks}) + : _firebaseDynamicLinks = firebaseDynamicLinks; + + final FirebaseDynamicLinks _firebaseDynamicLinks; + + @override + Stream get deepLinkStream => + _firebaseDynamicLinks.onLink.map((event) => event.link); + + @override + Future getInitialLink() async { + final deepLink = await _firebaseDynamicLinks.getInitialLink(); + return deepLink?.link; + } +} diff --git a/flutter_news_example/packages/deep_link_client/pubspec.yaml b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/pubspec.yaml similarity index 82% rename from flutter_news_example/packages/deep_link_client/pubspec.yaml rename to flutter_news_example/packages/deep_link_client/firebase_deep_link_client/pubspec.yaml index 1b0f6c334..4d54fc85e 100644 --- a/flutter_news_example/packages/deep_link_client/pubspec.yaml +++ b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/pubspec.yaml @@ -1,4 +1,4 @@ -name: deep_link_client +name: firebase_deep_link_client description: A Dart package which provides a deep link stream publish_to: none @@ -6,11 +6,12 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: + deep_link_client: + path: ../deep_link_client equatable: ^2.0.3 firebase_core: ^3.4.1 firebase_dynamic_links: ^6.0.6 plugin_platform_interface: ^2.1.3 - rxdart: ^0.27.3 dev_dependencies: firebase_core_platform_interface: ^5.2.1 diff --git a/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/test/firebase_deep_link_client_test.dart b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/test/firebase_deep_link_client_test.dart new file mode 100644 index 000000000..ff8a43e3b --- /dev/null +++ b/flutter_news_example/packages/deep_link_client/firebase_deep_link_client/test/firebase_deep_link_client_test.dart @@ -0,0 +1,70 @@ +// ignore_for_file: deprecated_member_use + +import 'dart:async'; +import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; +import 'package:firebase_deep_link_client/firebase_deep_link_client.dart'; +import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +class MockFirebaseDynamicLinks extends Mock implements FirebaseDynamicLinks {} + +class MockFirebaseCore extends Mock + with MockPlatformInterfaceMixin + implements FirebasePlatform {} + +void main() { + late MockFirebaseDynamicLinks dynamicLinks; + late StreamController onLinkStreamController; + + setUp(() { + dynamicLinks = MockFirebaseDynamicLinks(); + onLinkStreamController = StreamController(); + when(() => dynamicLinks.onLink) + .thenAnswer((_) => onLinkStreamController.stream); + }); + + tearDown(() { + onLinkStreamController.close(); + }); + + group('FirebaseDeepLinkClient', () { + group('getInitialLink', () { + test('retrieves the latest link if present', () async { + final expectedUri = Uri.https('ham.app.test', '/test/path'); + when(dynamicLinks.getInitialLink).thenAnswer( + (_) => Future.value(PendingDynamicLinkData(link: expectedUri)), + ); + + final client = + FirebaseDeepLinkClient(firebaseDynamicLinks: dynamicLinks); + final link = await client.getInitialLink(); + expect(link, expectedUri); + }); + }); + + group('deepLinkStream', () { + test('publishes values received through onLink stream', () { + final expectedUri1 = Uri.https('news.app.test', '/test/1'); + final expectedUri2 = Uri.https('news.app.test', '/test/2'); + + final client = + FirebaseDeepLinkClient(firebaseDynamicLinks: dynamicLinks); + + onLinkStreamController + ..add(PendingDynamicLinkData(link: expectedUri1)) + ..add(PendingDynamicLinkData(link: expectedUri1)) + ..add(PendingDynamicLinkData(link: expectedUri2)) + ..add(PendingDynamicLinkData(link: expectedUri1)); + + expect( + client.deepLinkStream, + emitsInOrder( + [expectedUri1, expectedUri1, expectedUri2, expectedUri1], + ), + ); + }); + }); + }); +} diff --git a/flutter_news_example/packages/deep_link_client/lib/deep_link_client.dart b/flutter_news_example/packages/deep_link_client/lib/deep_link_client.dart deleted file mode 100644 index d85be935a..000000000 --- a/flutter_news_example/packages/deep_link_client/lib/deep_link_client.dart +++ /dev/null @@ -1 +0,0 @@ -export 'src/deep_link_client.dart'; diff --git a/flutter_news_example/packages/deep_link_client/test/deep_link_client_test.dart b/flutter_news_example/packages/deep_link_client/test/deep_link_client_test.dart deleted file mode 100644 index 345f7910b..000000000 --- a/flutter_news_example/packages/deep_link_client/test/deep_link_client_test.dart +++ /dev/null @@ -1,138 +0,0 @@ -// ignore_for_file: deprecated_member_use - -import 'dart:async'; - -import 'package:deep_link_client/deep_link_client.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; -import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -typedef OnAppLinkFunction = void Function(Uri uri, String stringUri); - -class MockAppLinks extends Mock implements FirebaseDynamicLinks {} - -class MockFirebaseCore extends Mock - with MockPlatformInterfaceMixin - implements FirebasePlatform {} - -void main() { - late MockAppLinks appLinksMock; - late StreamController onLinkStreamController; - - setUp(() { - appLinksMock = MockAppLinks(); - onLinkStreamController = StreamController(); - when(() => appLinksMock.onLink) - .thenAnswer((_) => onLinkStreamController.stream); - }); - - tearDown(() { - onLinkStreamController.close(); - }); - - group('DeepLinkClient', () { - test('retrieves and publishes latest link if present', () { - final expectedUri = Uri.https('ham.app.test', '/test/path'); - when(appLinksMock.getInitialLink).thenAnswer( - (_) => Future.value(PendingDynamicLinkData(link: expectedUri)), - ); - - final client = DeepLinkClient(firebaseDynamicLinks: appLinksMock); - expect(client.deepLinkStream, emits(expectedUri)); - - // Testing also the replay of the latest value. - expect(client.deepLinkStream, emits(expectedUri)); - }); - - test('publishes DeepLinkClientFailure to stream if upstream throws', () { - final expectedError = Error(); - final expectedStackTrace = StackTrace.current; - - when(appLinksMock.getInitialLink).thenAnswer((_) { - return Future.error(expectedError, expectedStackTrace); - }); - - final client = DeepLinkClient(firebaseDynamicLinks: appLinksMock); - expect( - client.deepLinkStream, - emitsError( - isA() - .having((failure) => failure.error, 'error', expectedError), - ), - ); - }); - - test('publishes values received through onAppLink callback', () { - final expectedUri1 = Uri.https('ham.app.test', '/test/1'); - final expectedUri2 = Uri.https('ham.app.test', '/test/2'); - - when(appLinksMock.getInitialLink).thenAnswer((_) async => null); - - final client = DeepLinkClient(firebaseDynamicLinks: appLinksMock); - - expect( - client.deepLinkStream, - emitsInOrder( - [expectedUri1, expectedUri1, expectedUri2, expectedUri1], - ), - ); - - onLinkStreamController - ..add(PendingDynamicLinkData(link: expectedUri1)) - ..add(PendingDynamicLinkData(link: expectedUri1)) - ..add(PendingDynamicLinkData(link: expectedUri2)) - ..add(PendingDynamicLinkData(link: expectedUri1)); - }); - - group('with default FirebaseDynamicLinks', () { - setUp(() { - TestWidgetsFlutterBinding.ensureInitialized(); - - final mock = MockFirebaseCore(); - Firebase.delegatePackingProperty = mock; - - final platformApp = FirebaseAppPlatform( - 'testAppName', - const FirebaseOptions( - apiKey: 'apiKey', - appId: 'appId', - messagingSenderId: 'messagingSenderId', - projectId: 'projectId', - ), - ); - - when(() => mock.apps).thenReturn([platformApp]); - when(() => mock.app(any())).thenReturn(platformApp); - when( - () => mock.initializeApp( - name: any(named: 'name'), - options: any(named: 'options'), - ), - ).thenAnswer((_) => Future.value(platformApp)); - }); - - tearDown(() { - Firebase.delegatePackingProperty = null; - }); - - test('can be instantiated', () async { - await Firebase.initializeApp(); - expect(DeepLinkClient.new, returnsNormally); - }); - }); - }); - - group('DeepLinkClientFailure', () { - final error = Exception('errorMessage'); - - test('has correct props', () { - expect( - DeepLinkClientFailure(error).props, - [error], - ); - }); - }); -} diff --git a/flutter_news_example/packages/user_repository/lib/src/user_repository.dart b/flutter_news_example/packages/user_repository/lib/src/user_repository.dart index cc3228f2d..d9a3debfc 100644 --- a/flutter_news_example/packages/user_repository/lib/src/user_repository.dart +++ b/flutter_news_example/packages/user_repository/lib/src/user_repository.dart @@ -58,18 +58,18 @@ class UserRepository { required FlutterNewsExampleApiClient apiClient, required AuthenticationClient authenticationClient, required PackageInfoClient packageInfoClient, - required DeepLinkClient deepLinkClient, + required DeepLinkService deepLinkService, required UserStorage storage, }) : _apiClient = apiClient, _authenticationClient = authenticationClient, _packageInfoClient = packageInfoClient, - _deepLinkClient = deepLinkClient, + _deepLinkService = deepLinkService, _storage = storage; final FlutterNewsExampleApiClient _apiClient; final AuthenticationClient _authenticationClient; final PackageInfoClient _packageInfoClient; - final DeepLinkClient _deepLinkClient; + final DeepLinkService _deepLinkService; final UserStorage _storage; /// Stream of [User] which will emit the current user when @@ -94,7 +94,7 @@ class UserRepository { /// /// Emits when a new email link is emitted on [DeepLinkClient.deepLinkStream], /// which is validated using [AuthenticationClient.isLogInWithEmailLink]. - Stream get incomingEmailLinks => _deepLinkClient.deepLinkStream.where( + Stream get incomingEmailLinks => _deepLinkService.deepLinkStream.where( (deepLink) => _authenticationClient.isLogInWithEmailLink( emailLink: deepLink.toString(), ), diff --git a/flutter_news_example/packages/user_repository/pubspec.yaml b/flutter_news_example/packages/user_repository/pubspec.yaml index 70dfb41c7..40b5730cf 100644 --- a/flutter_news_example/packages/user_repository/pubspec.yaml +++ b/flutter_news_example/packages/user_repository/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: authentication_client: path: ../authentication_client/authentication_client deep_link_client: - path: ../deep_link_client + path: ../deep_link_client/deep_link_client equatable: ^2.0.3 flutter_news_example_api: path: ../../api diff --git a/flutter_news_example/packages/user_repository/test/src/user_repository_test.dart b/flutter_news_example/packages/user_repository/test/src/user_repository_test.dart index aa7910933..1f4ea90a3 100644 --- a/flutter_news_example/packages/user_repository/test/src/user_repository_test.dart +++ b/flutter_news_example/packages/user_repository/test/src/user_repository_test.dart @@ -14,7 +14,7 @@ class MockAuthenticationClient extends Mock implements AuthenticationClient {} class MockPackageInfoClient extends Mock implements PackageInfoClient {} -class MockDeepLinkClient extends Mock implements DeepLinkClient {} +class MockDeepLinkService extends Mock implements DeepLinkService {} class MockUserStorage extends Mock implements UserStorage {} @@ -57,7 +57,7 @@ void main() { group('UserRepository', () { late AuthenticationClient authenticationClient; late PackageInfoClient packageInfoClient; - late DeepLinkClient deepLinkClient; + late DeepLinkService deepLinkService; late UserStorage storage; late StreamController deepLinkClientController; late UserRepository userRepository; @@ -66,19 +66,19 @@ void main() { setUp(() { authenticationClient = MockAuthenticationClient(); packageInfoClient = MockPackageInfoClient(); - deepLinkClient = MockDeepLinkClient(); + deepLinkService = MockDeepLinkService(); storage = MockUserStorage(); deepLinkClientController = StreamController.broadcast(); apiClient = MockFlutterNewsExampleApiClient(); - when(() => deepLinkClient.deepLinkStream) + when(() => deepLinkService.deepLinkStream) .thenAnswer((_) => deepLinkClientController.stream); userRepository = UserRepository( apiClient: apiClient, authenticationClient: authenticationClient, packageInfoClient: packageInfoClient, - deepLinkClient: deepLinkClient, + deepLinkService: deepLinkService, storage: storage, ); }); @@ -468,7 +468,7 @@ void main() { apiClient: apiClient, authenticationClient: authenticationClient, packageInfoClient: packageInfoClient, - deepLinkClient: deepLinkClient, + deepLinkService: deepLinkService, storage: storage, ).fetchAppOpenedCount(); expect(result, 1); @@ -484,7 +484,7 @@ void main() { apiClient: apiClient, authenticationClient: authenticationClient, packageInfoClient: packageInfoClient, - deepLinkClient: deepLinkClient, + deepLinkService: deepLinkService, storage: storage, ).fetchAppOpenedCount(), throwsA(isA()), @@ -505,7 +505,7 @@ void main() { apiClient: apiClient, authenticationClient: authenticationClient, packageInfoClient: packageInfoClient, - deepLinkClient: deepLinkClient, + deepLinkService: deepLinkService, storage: storage, ).incrementAppOpenedCount(), completes, @@ -524,7 +524,7 @@ void main() { apiClient: apiClient, authenticationClient: authenticationClient, packageInfoClient: packageInfoClient, - deepLinkClient: deepLinkClient, + deepLinkService: deepLinkService, storage: storage, ).incrementAppOpenedCount(), throwsA(isA()), diff --git a/flutter_news_example/pubspec.lock b/flutter_news_example/pubspec.lock index 3541a1452..b96a9c771 100644 --- a/flutter_news_example/pubspec.lock +++ b/flutter_news_example/pubspec.lock @@ -319,7 +319,7 @@ packages: deep_link_client: dependency: "direct main" description: - path: "packages/deep_link_client" + path: "packages/deep_link_client/deep_link_client" relative: true source: path version: "0.0.0" @@ -473,6 +473,13 @@ packages: url: "https://pub.dev" source: hosted version: "3.6.42" + firebase_deep_link_client: + dependency: "direct main" + description: + path: "packages/deep_link_client/firebase_deep_link_client" + relative: true + source: path + version: "0.0.0" firebase_dynamic_links: dependency: "direct main" description: @@ -1781,10 +1788,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.5" watcher: dependency: transitive description: diff --git a/flutter_news_example/pubspec.yaml b/flutter_news_example/pubspec.yaml index 67993ce2f..80550eb43 100644 --- a/flutter_news_example/pubspec.yaml +++ b/flutter_news_example/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: clock: ^1.1.0 collection: ^1.16.0 deep_link_client: - path: packages/deep_link_client + path: packages/deep_link_client/deep_link_client email_launcher: path: packages/email_launcher equatable: ^2.0.3 @@ -32,6 +32,8 @@ dependencies: path: packages/authentication_client/firebase_authentication_client firebase_core: ^3.4.1 firebase_crashlytics: ^4.1.1 + firebase_deep_link_client: + path: packages/deep_link_client/firebase_deep_link_client firebase_dynamic_links: ^6.0.6 firebase_messaging: ^15.1.1 firebase_notifications_client: