From b32de5e24ed882dd29f79143e1907dc5f15c4467 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Thu, 29 Feb 2024 17:50:44 +0100 Subject: [PATCH 01/10] created analytics service and implements first events --- example/ios/Podfile.lock | 6 + example/lib/home_page.dart | 16 + example/lib/widgets/logger_widget.dart | 219 ++++++++++++ .../Flutter/GeneratedPluginRegistrant.swift | 2 + example/pubspec.lock | 12 +- ios/Podfile.lock | 6 + lib/pages/about_networks.dart | 15 +- lib/pages/about_wallets.dart | 15 +- lib/pages/get_wallet_page.dart | 15 +- lib/pages/select_network_page.dart | 17 +- lib/pages/wallets_list_short_page.dart | 10 +- .../analytics_service/analytics_service.dart | 105 ++++++ .../analytics_service_singleton.dart | 7 + .../i_analytics_service.dart | 9 + .../models/analytics_event.dart | 335 ++++++++++++++++++ .../blockchain_api_utils.dart | 19 +- .../i_blockchain_api_utils.dart | 10 +- .../explorer_service/explorer_service.dart | 5 +- .../ledger_service/ledger_service.dart | 1 + .../logger_service/i_logger_service.dart | 68 ++++ .../logger_service/logger_service.dart | 106 ++++++ .../logger_service_singleton.dart | 7 + lib/services/w3m_service/w3m_service.dart | 94 ++++- lib/utils/core/core_utils.dart | 54 ++- lib/utils/core/i_core_utils.dart | 8 + lib/utils/w3m_logger.dart | 1 + lib/web3modal_flutter.dart | 1 - .../miscellaneous/all_wallets_header.dart | 8 + lib/widgets/w3m_qr_code.dart | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 14 +- pubspec.yaml | 2 + test/mock_classes.mocks.dart | 8 - 33 files changed, 1144 insertions(+), 54 deletions(-) create mode 100644 example/lib/widgets/logger_widget.dart create mode 100644 lib/services/analytics_service/analytics_service.dart create mode 100644 lib/services/analytics_service/analytics_service_singleton.dart create mode 100644 lib/services/analytics_service/i_analytics_service.dart create mode 100644 lib/services/analytics_service/models/analytics_event.dart create mode 100644 lib/services/logger_service/i_logger_service.dart create mode 100644 lib/services/logger_service/logger_service.dart create mode 100644 lib/services/logger_service/logger_service_singleton.dart diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 0a76f782..91be99cf 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -8,6 +8,8 @@ PODS: - CoinbaseWalletSDK/CrossPlatform (1.0.4): - CoinbaseWalletSDK/Client - Flutter (1.0.0) + - flutter_timezone (0.0.1): + - Flutter - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) @@ -29,6 +31,7 @@ DEPENDENCIES: - appcheck (from `.symlinks/plugins/appcheck/ios`) - coinbase_wallet_sdk (from `.symlinks/plugins/coinbase_wallet_sdk/ios`) - Flutter (from `Flutter`) + - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) @@ -47,6 +50,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/coinbase_wallet_sdk/ios" Flutter: :path: Flutter + flutter_timezone: + :path: ".symlinks/plugins/flutter_timezone/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: @@ -63,6 +68,7 @@ SPEC CHECKSUMS: coinbase_wallet_sdk: 7ccd4e1a7940deba6ba9bd81beece999a2268c15 CoinbaseWalletSDK: ea1f37512bbc69ebe07416e3b29bf840f5cc3152 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + flutter_timezone: ffb07bdad3c6276af8dada0f11978d8a1f8a20bb FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index 0fee3dae..6949f91b 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:walletconnect_flutter_dapp/widgets/logger_widget.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; @@ -20,14 +21,28 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { + final CustomAnimatedOverlay overlay = CustomAnimatedOverlay( + const Duration(milliseconds: 200), + ); + late W3MService _w3mService; @override void initState() { super.initState(); + // WidgetsBinding.instance.addPostFrameCallback((_) { + // _addOverlay(); + // }); _initializeService(); } + // void _addOverlay() { + // overlay.insert( + // context, + // child: DraggableCard(overlayController: overlay), + // ); + // } + void _initializeService() async { // See https://docs.walletconnect.com/web3modal/flutter/custom-chains W3MChainPresets.chains.putIfAbsent(_celo.chainId, () => _celo); @@ -36,6 +51,7 @@ class _MyHomePageState extends State { _w3mService = W3MService( projectId: DartDefines.projectId, logLevel: LogLevel.error, + enableAnalytics: true, metadata: const PairingMetadata( name: StringConstants.w3mPageTitleV3, description: StringConstants.w3mPageTitleV3, diff --git a/example/lib/widgets/logger_widget.dart b/example/lib/widgets/logger_widget.dart new file mode 100644 index 00000000..913507de --- /dev/null +++ b/example/lib/widgets/logger_widget.dart @@ -0,0 +1,219 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; + +class DraggableCard extends StatefulWidget { + final CustomAnimatedOverlay overlayController; + const DraggableCard({ + super.key, + required this.overlayController, + }); + + @override + State createState() => _DraggableCardState(); +} + +class _DraggableCardState extends State { + final List _logs = []; + // + @override + void initState() { + super.initState(); + loggerService.instance.logEvents.listen((event) { + final message = '${event.message}'; + if (message.contains('sendEvent')) { + final match = RegExp(r'::([^]*?)::').firstMatch(message)?[1]; + if (match != null) { + final json = jsonDecode(match.trim()) as Map; + final data = json['props']; + _logs.add( + Text( + '=> $data', + style: const TextStyle( + color: Colors.white, + fontSize: 12.0, + ), + ), + ); + setState(() {}); + } + } + }); + } + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + + return Card( + elevation: 6.0, + color: Colors.black87, + clipBehavior: Clip.antiAlias, + child: SizedBox( + width: MediaQuery.of(context).size.width, + height: 200.0, + child: Row( + children: [ + Expanded( + child: SizedBox( + height: 200.0, + child: ListView( + reverse: true, + padding: const EdgeInsets.all(6.0), + children: _logs.reversed.toList(), + ), + ), + ), + GestureDetector( + onPanUpdate: (details) { + widget.overlayController.alignChildTo( + details.globalPosition, + size * 0.5, + ); + }, + onPanEnd: (_) { + // overlayController.alignToScreenEdge(); + }, + child: Container( + width: 25.0, + color: Colors.black, + child: const Center( + child: Icon( + Icons.drag_indicator_rounded, + color: Colors.white, + ), + ), + ), + ), + ], + ), + ), + ); + } +} + +class CustomAnimatedOverlay extends AnimatedOverlay { + CustomAnimatedOverlay(super.duration); + + OverlayEntry? _entry; + + Alignment align = Alignment.centerRight; + + Animation? alignAnimation; + + OverlayEntry createAlignOverlay({Widget? child}) { + return OverlayEntry( + builder: (_) { + return CustomAlign( + animation: alignAnimation ?? AlwaysStoppedAnimation(align), + child: child ?? + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: Colors.red, + ), + child: const Text('Align Overlay'), + ), + ); + }, + ); + } + + void insert(BuildContext context, {Widget? child}) { + _entry = createAlignOverlay(child: child); + Overlay.of(context).insert(_entry!); + } + + void alignChildTo(Offset globalPosition, Size size) { + double dx = (globalPosition.dx - size.width) / size.width; + double dy = (globalPosition.dy - size.height) / size.height; + + dx = dx.abs() < 1 ? dx : dx / dx.abs(); + dy = dy.abs() < 1 ? dy : dy / dy.abs(); + + final newAlign = Alignment(dx, dy); + + if (align == newAlign) return; + + alignAnimation = createAnimation(begin: align, end: newAlign); + + align = newAlign; + + controller.forward(); + _entry?.markNeedsBuild(); + } + + void alignToScreenEdge() { + alignAnimation = + createAnimation(begin: align, end: Alignment.centerRight); + + align = Alignment.centerRight; + + controller.forward(); + _entry?.markNeedsBuild(); + } +} + +abstract class AnimatedOverlay extends TickerProvider { + @override + Ticker createTicker(onTick) => Ticker(onTick); + + late final AnimationController controller; + + AnimatedOverlay(Duration duration) : super() { + controller = AnimationController( + vsync: this, + duration: duration, + ); + } + + Animation createAnimation({ + required T begin, + required T end, + Curve curve = Curves.easeInOutCubic, + }) { + controller.reset(); + if (begin == end) { + return AlwaysStoppedAnimation(end); + } else { + return Tween(begin: begin, end: end).animate( + CurvedAnimation( + parent: controller, + curve: curve, + ), + ); + } + } +} + +abstract class CustomAnimatedWidget extends AnimatedWidget { + final Widget child; + final Animation animation; + const CustomAnimatedWidget({ + super.key, + required this.child, + required this.animation, + }) : super(listenable: animation); +} + +class CustomAlign extends AnimatedWidget { + final Widget child; + final Animation animation; + + const CustomAlign({ + super.key, + required this.child, + required this.animation, + }) : super(listenable: animation); + + @override + Widget build(BuildContext context) { + return Align( + alignment: animation.value, + child: child, + ); + } +} diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 3ebb6b9e..03439581 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import flutter_timezone import package_info_plus import path_provider_foundation import shared_preferences_foundation @@ -12,6 +13,7 @@ import sqflite import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/example/pubspec.lock b/example/pubspec.lock index 619681ad..e17dc9e8 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -387,6 +387,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_timezone: + dependency: transitive + description: + name: flutter_timezone + sha256: "06b35132c98fa188db3c4b654b7e1af7ccd01dfe12a004d58be423357605fb24" + url: "https://pub.dev" + source: hosted + version: "1.0.8" flutter_web_plugins: dependency: transitive description: flutter @@ -1025,10 +1033,10 @@ packages: dependency: transitive description: name: uuid - sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921 + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 url: "https://pub.dev" source: hosted - version: "4.2.1" + version: "4.3.3" vector_graphics: dependency: transitive description: diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0a76f782..91be99cf 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -8,6 +8,8 @@ PODS: - CoinbaseWalletSDK/CrossPlatform (1.0.4): - CoinbaseWalletSDK/Client - Flutter (1.0.0) + - flutter_timezone (0.0.1): + - Flutter - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) @@ -29,6 +31,7 @@ DEPENDENCIES: - appcheck (from `.symlinks/plugins/appcheck/ios`) - coinbase_wallet_sdk (from `.symlinks/plugins/coinbase_wallet_sdk/ios`) - Flutter (from `Flutter`) + - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) @@ -47,6 +50,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/coinbase_wallet_sdk/ios" Flutter: :path: Flutter + flutter_timezone: + :path: ".symlinks/plugins/flutter_timezone/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: @@ -63,6 +68,7 @@ SPEC CHECKSUMS: coinbase_wallet_sdk: 7ccd4e1a7940deba6ba9bd81beece999a2268c15 CoinbaseWalletSDK: ea1f37512bbc69ebe07416e3b29bf840f5cc3152 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + flutter_timezone: ffb07bdad3c6276af8dada0f11978d8a1f8a20bb FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 diff --git a/lib/pages/about_networks.dart b/lib/pages/about_networks.dart index 6ff54cce..01d1c915 100644 --- a/lib/pages/about_networks.dart +++ b/lib/pages/about_networks.dart @@ -3,14 +3,27 @@ import 'package:url_launcher/url_launcher_string.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/constants/string_constants.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; import 'package:web3modal_flutter/widgets/buttons/simple_icon_button.dart'; import 'package:web3modal_flutter/widgets/help/help_section.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; -class AboutNetworks extends StatelessWidget { +class AboutNetworks extends StatefulWidget { const AboutNetworks() : super(key: KeyConstants.helpPageKey); + @override + State createState() => _AboutNetworksState(); +} + +class _AboutNetworksState extends State { + @override + void initState() { + super.initState(); + analyticsService.instance.sendEvent(ClickNetworkHelpEvent()); + } + @override Widget build(BuildContext context) { return Web3ModalNavbar( diff --git a/lib/pages/about_wallets.dart b/lib/pages/about_wallets.dart index 6ec4b977..b5df8705 100644 --- a/lib/pages/about_wallets.dart +++ b/lib/pages/about_wallets.dart @@ -1,15 +1,28 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/pages/get_wallet_page.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/widgets/widget_stack/widget_stack_singleton.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/widgets/buttons/simple_icon_button.dart'; import 'package:web3modal_flutter/widgets/help/help_section.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; -class AboutWallets extends StatelessWidget { +class AboutWallets extends StatefulWidget { const AboutWallets() : super(key: KeyConstants.helpPageKey); + @override + State createState() => _AboutWalletsState(); +} + +class _AboutWalletsState extends State { + @override + void initState() { + super.initState(); + analyticsService.instance.sendEvent(ClickWalletHelpEvent()); + } + @override Widget build(BuildContext context) { return Web3ModalNavbar( diff --git a/lib/pages/get_wallet_page.dart b/lib/pages/get_wallet_page.dart index b317025a..608259b9 100644 --- a/lib/pages/get_wallet_page.dart +++ b/lib/pages/get_wallet_page.dart @@ -7,6 +7,8 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/constants/string_constants.dart'; import 'package:web3modal_flutter/models/grid_item.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/theme/constants.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; import 'package:web3modal_flutter/widgets/lists/list_items/all_wallets_item.dart'; @@ -17,9 +19,20 @@ import 'package:web3modal_flutter/widgets/miscellaneous/content_loading.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; import 'package:web3modal_flutter/utils/url/url_utils_singleton.dart'; -class GetWalletPage extends StatelessWidget { +class GetWalletPage extends StatefulWidget { const GetWalletPage() : super(key: KeyConstants.getAWalletPageKey); + @override + State createState() => _GetWalletPageState(); +} + +class _GetWalletPageState extends State { + @override + void initState() { + super.initState(); + analyticsService.instance.sendEvent(ClickGetWalletEvent()); + } + @override Widget build(BuildContext context) { final themeColors = Web3ModalTheme.colorsOf(context); diff --git a/lib/pages/select_network_page.dart b/lib/pages/select_network_page.dart index ab2ceed6..3b669746 100644 --- a/lib/pages/select_network_page.dart +++ b/lib/pages/select_network_page.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/pages/about_networks.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/theme/constants.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; import 'package:web3modal_flutter/widgets/widget_stack/widget_stack_singleton.dart'; @@ -13,11 +15,22 @@ import 'package:web3modal_flutter/widgets/miscellaneous/content_loading.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; import 'package:web3modal_flutter/widgets/web3modal_provider.dart'; -class SelectNetworkPage extends StatelessWidget { +class SelectNetworkPage extends StatefulWidget { const SelectNetworkPage({required this.onTapNetwork}) : super(key: KeyConstants.selectNetworkPage); final Function(W3MChainInfo)? onTapNetwork; + @override + State createState() => _SelectNetworkPageState(); +} + +class _SelectNetworkPageState extends State { + @override + void initState() { + super.initState(); + analyticsService.instance.sendEvent(ClickNetworksEvent()); + } + @override Widget build(BuildContext context) { final themeData = Web3ModalTheme.getDataOf(context); @@ -45,7 +58,7 @@ class SelectNetworkPage extends StatelessWidget { return const ContentLoading(); } return NetworksGrid( - onTapNetwork: onTapNetwork, + onTapNetwork: widget.onTapNetwork, itemList: items, ); }, diff --git a/lib/pages/wallets_list_short_page.dart b/lib/pages/wallets_list_short_page.dart index 7756cf1c..a4b156ca 100644 --- a/lib/pages/wallets_list_short_page.dart +++ b/lib/pages/wallets_list_short_page.dart @@ -4,6 +4,8 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/pages/about_wallets.dart'; import 'package:web3modal_flutter/pages/connect_wallet_page.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service_singleton.dart'; import 'package:web3modal_flutter/theme/constants.dart'; import 'package:web3modal_flutter/widgets/widget_stack/widget_stack_singleton.dart'; @@ -80,8 +82,12 @@ class _WalletsListShortPageState extends State { }, ), onTap: () { - widgetStack.instance - .push(const WalletsListLongPage()); + analyticsService.instance.sendEvent( + ClickAllWalletsEvent(), + ); + widgetStack.instance.push( + const WalletsListLongPage(), + ); }, ), ], diff --git a/lib/services/analytics_service/analytics_service.dart b/lib/services/analytics_service/analytics_service.dart new file mode 100644 index 00000000..b81a9bcd --- /dev/null +++ b/lib/services/analytics_service/analytics_service.dart @@ -0,0 +1,105 @@ +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; +import 'package:uuid/uuid.dart'; + +import 'package:web3modal_flutter/services/analytics_service/i_analytics_service.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; +import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; +import 'package:web3modal_flutter/utils/core/core_utils_singleton.dart'; +import 'package:web3modal_flutter/web3modal_flutter.dart'; + +class AnalyticsService implements IAnalyticsService { + static const _debugApiEndpoint = + 'https://analytics-api-cf-workers-staging.walletconnect-v1-bridge.workers.dev'; + static const _debugProjectId = 'e087b4b0503b860119be49d906717c12'; + bool _isEnabled = false; + + @override + final String projectId; + + @override + final bool? enableAnalytics; + + AnalyticsService({ + required this.projectId, + this.enableAnalytics, + }); + + @override + Future init() async { + try { + if (enableAnalytics == null) { + _isEnabled = await fetchAnalyticsConfig(); + } else { + _isEnabled = enableAnalytics!; + } + loggerService.instance.i('[$runtimeType] init enabled: $_isEnabled'); + sendEvent(ModalLoadedEvent()); + } catch (e, s) { + loggerService.instance.e( + '[$runtimeType] init error', + error: e, + stackTrace: s, + ); + } + } + + @override + Future fetchAnalyticsConfig() async { + try { + final endpoint = await coreUtils.instance.getApiUrl(); + final headers = coreUtils.instance.getAPIHeaders(projectId); + final response = await http.get( + Uri.parse('$endpoint/getAnalyticsConfig'), + headers: headers, + ); + final json = jsonDecode(response.body) as Map; + final enabled = json['isAnalyticsEnabled'] as bool?; + loggerService.instance.i('[$runtimeType] fetchAnalyticsConfig $enabled'); + return enabled ?? false; + } catch (e, s) { + loggerService.instance.e( + '[$runtimeType] fetchAnalyticsConfig error', + error: e, + stackTrace: s, + ); + return false; + } + } + + @override + void sendEvent(AnalyticsEvent analyticsEvent) async { + if (!_isEnabled) return; + try { + final endpoint = kDebugMode + ? _debugApiEndpoint + : await coreUtils.instance.getAnalyticsUrl(); + final headers = kDebugMode + ? coreUtils.instance.getAPIHeaders(_debugProjectId) + : coreUtils.instance.getAPIHeaders(projectId); + + final packageName = await WalletConnectUtils.getPackageName(); + final body = jsonEncode({ + 'eventId': Uuid().v4(), + 'bundleId': packageName, + 'timestamp': DateTime.now().toUtc().millisecondsSinceEpoch, + 'props': analyticsEvent.toMap(), + }); + + final response = await http.post( + Uri.parse('$endpoint/e'), + headers: headers, + body: body, + ); + final code = response.statusCode; + loggerService.instance.i('[$runtimeType] sendEvent ::$body:: $code'); + } catch (e, s) { + loggerService.instance.e( + '[$runtimeType] sendEvent error', + error: e, + stackTrace: s, + ); + } + } +} diff --git a/lib/services/analytics_service/analytics_service_singleton.dart b/lib/services/analytics_service/analytics_service_singleton.dart new file mode 100644 index 00000000..ffdc01ce --- /dev/null +++ b/lib/services/analytics_service/analytics_service_singleton.dart @@ -0,0 +1,7 @@ +import 'package:web3modal_flutter/services/analytics_service/i_analytics_service.dart'; + +class AnalyticsServiceSingleton { + late IAnalyticsService instance; +} + +final analyticsService = AnalyticsServiceSingleton(); diff --git a/lib/services/analytics_service/i_analytics_service.dart b/lib/services/analytics_service/i_analytics_service.dart new file mode 100644 index 00000000..ea3d3b10 --- /dev/null +++ b/lib/services/analytics_service/i_analytics_service.dart @@ -0,0 +1,9 @@ +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; + +abstract class IAnalyticsService { + String get projectId; + bool? get enableAnalytics; + Future init(); + void sendEvent(AnalyticsEvent analyticsEvent); + Future fetchAnalyticsConfig(); +} diff --git a/lib/services/analytics_service/models/analytics_event.dart b/lib/services/analytics_service/models/analytics_event.dart new file mode 100644 index 00000000..8f85485e --- /dev/null +++ b/lib/services/analytics_service/models/analytics_event.dart @@ -0,0 +1,335 @@ +enum AnalyticsPlatform { + mobile, + web, + qrcode, + email, + unsupported, +} + +abstract class AnalyticsEvent { + abstract final String type; + abstract final String event; + abstract final Map? properties; + + Map toMap(); +} + +class ModalCreatedEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'MODAL_CREATED'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ModalLoadedEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'MODAL_LOADED'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ModalOpenEvent implements AnalyticsEvent { + final bool _connected; + ModalOpenEvent({ + required bool connected, + }) : _connected = connected; + + @override + String get type => 'track'; + + @override + String get event => 'MODAL_OPEN'; + + @override + Map? get properties => { + 'connected': _connected, + }; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ModalCloseEvent implements AnalyticsEvent { + final bool _connected; + ModalCloseEvent({ + required bool connected, + }) : _connected = connected; + + @override + String get type => 'track'; + + @override + String get event => 'MODAL_CLOSE'; + + @override + Map? get properties => { + 'connected': _connected, + }; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ClickAllWalletsEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'CLICK_ALL_WALLETS'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ClickNetworksEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'CLICK_NETWORKS'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class SwitchNetworkEvent implements AnalyticsEvent { + final String _network; + SwitchNetworkEvent({ + required String network, + }) : _network = network; + + @override + String get type => 'track'; + + @override + String get event => 'SWITCH_NETWORK'; + + @override + Map? get properties => { + 'network': _network, + }; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class SelectWalletEvent implements AnalyticsEvent { + final String _name; + final String? _platform; + SelectWalletEvent({ + required String name, + String? platform, + }) : _name = name, + _platform = platform; + + @override + String get type => 'track'; + + @override + String get event => 'SELECT_WALLET'; + + @override + Map? get properties => { + 'name': _name, + if (_platform != null) 'platform': _platform, + }; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ConnectSuccessEvent implements AnalyticsEvent { + final String _name; + final String? _method; + ConnectSuccessEvent({ + required String name, + String? method, + }) : _name = name, + _method = method; + + @override + String get type => 'track'; + + @override + String get event => 'CONNECT_SUCCESS'; + + @override + Map? get properties => { + 'name': _name, + if (_method != null) 'method': _method, + }; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ConnectErrorEvent implements AnalyticsEvent { + final String _message; + ConnectErrorEvent({ + required String message, + }) : _message = message; + + @override + String get type => 'track'; + + @override + String get event => 'CONNECT_ERROR'; + + @override + Map? get properties => { + 'message': _message, + }; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class DisconnectSuccessEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'DISCONNECT_SUCCESS'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class DisconnectErrorEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'DISCONNECT_ERROR'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ClickWalletHelpEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'CLICK_WALLET_HELP'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ClickNetworkHelpEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'CLICK_NETWORK_HELP'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} + +class ClickGetWalletEvent implements AnalyticsEvent { + @override + String get type => 'track'; + + @override + String get event => 'CLICK_GET_WALLET'; + + @override + Map? get properties => null; + + @override + Map toMap() => { + 'type': type, + 'event': event, + if (properties != null) 'properties': properties, + }; +} diff --git a/lib/services/blockchain_api_service/blockchain_api_utils.dart b/lib/services/blockchain_api_service/blockchain_api_utils.dart index 618fb476..dffd609a 100644 --- a/lib/services/blockchain_api_service/blockchain_api_utils.dart +++ b/lib/services/blockchain_api_service/blockchain_api_utils.dart @@ -4,30 +4,25 @@ import 'package:http/http.dart' as http; import 'package:web3modal_flutter/constants/string_constants.dart'; import 'package:web3modal_flutter/services/blockchain_api_service/blockchain_identity.dart'; import 'package:web3modal_flutter/services/blockchain_api_service/i_blockchain_api_utils.dart'; +import 'package:web3modal_flutter/utils/core/core_utils_singleton.dart'; class BlockchainApiUtils extends IBlockchainApiUtils { - @override - final String blockchainApiUriRoot; - + // @override final String projectId; - BlockchainApiUtils({ - this.blockchainApiUriRoot = 'https://rpc.walletconnect.com', - required this.projectId, - }); + BlockchainApiUtils({required this.projectId}); @override Future getIdentity(String address, int chainId) async { final scope = '${StringConstants.namespace}:$chainId'; - final endpoint = '$blockchainApiUriRoot/v1/identity/$address' - '?chainId=$scope&projectId=$projectId'; + final url = await coreUtils.instance.getBlockchainApiUrl(); + final endpoint = '$url/v1/identity/$address'; + '?chainId=$scope&projectId=$projectId'; final response = await http.get(Uri.parse(endpoint)); if (response.statusCode == 200) { - return BlockchainIdentity.fromJson( - jsonDecode(response.body), - ); + return BlockchainIdentity.fromJson(jsonDecode(response.body)); } else { throw Exception('Failed to load data'); } diff --git a/lib/services/blockchain_api_service/i_blockchain_api_utils.dart b/lib/services/blockchain_api_service/i_blockchain_api_utils.dart index 98c35ac7..b61c4f4a 100644 --- a/lib/services/blockchain_api_service/i_blockchain_api_utils.dart +++ b/lib/services/blockchain_api_service/i_blockchain_api_utils.dart @@ -1,17 +1,9 @@ import 'package:web3modal_flutter/services/blockchain_api_service/blockchain_identity.dart'; abstract class IBlockchainApiUtils { - static const blockchainApiEndpoint = 'https://rpc.walletconnect.com'; - - /// The root URI of the blockchain API. - String get blockchainApiUriRoot; - /// The project ID used when querying the API. String get projectId; /// Gets the name and avatar of a provided address on the given chain - Future getIdentity( - String address, - int chainId, - ); + Future getIdentity(String address, int chainId); } diff --git a/lib/services/explorer_service/explorer_service.dart b/lib/services/explorer_service/explorer_service.dart index 153188f8..cdfcfb15 100644 --- a/lib/services/explorer_service/explorer_service.dart +++ b/lib/services/explorer_service/explorer_service.dart @@ -16,12 +16,14 @@ import 'package:web3modal_flutter/services/storage_service/storage_service_singl import 'package:web3modal_flutter/utils/core/core_utils_singleton.dart'; import 'package:web3modal_flutter/utils/platform/i_platform_utils.dart'; import 'package:web3modal_flutter/utils/platform/platform_utils_singleton.dart'; +import 'package:web3modal_flutter/utils/w3m_logger.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; const int _defaultEntriesCount = 48; class ExplorerService implements IExplorerService { - static const _apiUrl = 'https://api.web3modal.com'; + // TODO fix this with coreUtils.instance.getApiUrl() + String _apiUrl = 'https://api.web3modal.com'; final http.Client _client; final String _referer; @@ -102,6 +104,7 @@ class ExplorerService implements IExplorerService { } W3MLoggerUtil.logger.t('[$runtimeType] init()'); + _apiUrl = await coreUtils.instance.getApiUrl(); await _setInstalledWalletIdsParam(); await _fetchInitialWallets(); diff --git a/lib/services/ledger_service/ledger_service.dart b/lib/services/ledger_service/ledger_service.dart index 197c638b..21034c35 100644 --- a/lib/services/ledger_service/ledger_service.dart +++ b/lib/services/ledger_service/ledger_service.dart @@ -1,5 +1,6 @@ import 'package:http/http.dart'; import 'package:web3modal_flutter/services/ledger_service/i_ledger_service.dart'; +import 'package:web3modal_flutter/utils/w3m_logger.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; class LedgerService extends ILedgerService { diff --git a/lib/services/logger_service/i_logger_service.dart b/lib/services/logger_service/i_logger_service.dart new file mode 100644 index 00000000..1e194dfc --- /dev/null +++ b/lib/services/logger_service/i_logger_service.dart @@ -0,0 +1,68 @@ +import 'package:web3modal_flutter/web3modal_flutter.dart'; + +abstract class ILoggerService { + // + Stream get logEvents; + // + // Logger get logger; + + /// Log a message at level [Level.trace]. + void t( + dynamic message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }); + + /// Log a message at level [Level.debug]. + void d( + dynamic message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }); + + /// Log a message at level [Level.info]. + void i( + dynamic message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }); + + /// Log a message at level [Level.warning]. + void w( + dynamic message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }); + + /// Log a message at level [Level.error]. + void e( + dynamic message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }); + + /// Log a message at level [Level.fatal]. + void f( + dynamic message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }); + + /// Log a message with [level]. + void log( + Level level, + dynamic message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }); + + /// Closes the logger and releases all resources. + Future close(); +} diff --git a/lib/services/logger_service/logger_service.dart b/lib/services/logger_service/logger_service.dart new file mode 100644 index 00000000..894a3fd8 --- /dev/null +++ b/lib/services/logger_service/logger_service.dart @@ -0,0 +1,106 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:web3modal_flutter/services/logger_service/i_logger_service.dart'; +import 'package:web3modal_flutter/web3modal_flutter.dart'; + +class LoggerService implements ILoggerService { + static final _loggerController = StreamController.broadcast(); + + @override + final Stream logEvents = _loggerController.stream; + + late Logger _logger; + + LoggerService({required LogLevel level, bool debugMode = true}) { + _logger = Logger( + level: level.toLevel(), + printer: PrettyPrinter(methodCount: null), + ); + if (kDebugMode && debugMode) { + Logger.addLogListener(_logListener); + } + } + + void _logListener(LogEvent event) { + _loggerController.sink.add(event); + } + + @override + void d( + message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }) { + _logger.d(message, time: time, error: error, stackTrace: stackTrace); + } + + @override + void e( + message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }) { + _logger.e(message, time: time, error: error, stackTrace: stackTrace); + } + + @override + void f( + message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }) { + _logger.f(message, time: time, error: error, stackTrace: stackTrace); + } + + @override + void i( + message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }) { + _logger.i(message, time: time, error: error, stackTrace: stackTrace); + } + + @override + void log( + Level level, + message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }) { + _logger.log(level, message, + time: time, error: error, stackTrace: stackTrace); + } + + @override + void t( + message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }) { + _logger.t(message, time: time, error: error, stackTrace: stackTrace); + } + + @override + void w( + message, { + DateTime? time, + Object? error, + StackTrace? stackTrace, + }) { + _logger.w(message, time: time, error: error, stackTrace: stackTrace); + } + + @override + Future close() async { + Logger.removeLogListener(_logListener); + return await _logger.close(); + } +} diff --git a/lib/services/logger_service/logger_service_singleton.dart b/lib/services/logger_service/logger_service_singleton.dart new file mode 100644 index 00000000..d21c03b2 --- /dev/null +++ b/lib/services/logger_service/logger_service_singleton.dart @@ -0,0 +1,7 @@ +import 'package:web3modal_flutter/services/logger_service/i_logger_service.dart'; + +class LoggerServiceSingleton { + late ILoggerService instance; +} + +final loggerService = LoggerServiceSingleton(); diff --git a/lib/services/w3m_service/w3m_service.dart b/lib/services/w3m_service/w3m_service.dart index 18434975..88c5931e 100644 --- a/lib/services/w3m_service/w3m_service.dart +++ b/lib/services/w3m_service/w3m_service.dart @@ -7,17 +7,24 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:web3modal_flutter/constants/string_constants.dart'; import 'package:web3modal_flutter/pages/account_page.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/services/coinbase_service/coinbase_service.dart'; import 'package:web3modal_flutter/services/coinbase_service/i_coinbase_service.dart'; import 'package:web3modal_flutter/services/coinbase_service/models/coinbase_data.dart'; import 'package:web3modal_flutter/services/coinbase_service/models/coinbase_events.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service_singleton.dart'; +import 'package:web3modal_flutter/services/explorer_service/models/redirect.dart'; import 'package:web3modal_flutter/services/ledger_service/ledger_service_singleton.dart'; +import 'package:web3modal_flutter/services/logger_service/logger_service.dart'; +import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; import 'package:web3modal_flutter/services/w3m_service/models/w3m_session.dart'; import 'package:web3modal_flutter/utils/core/core_utils_singleton.dart'; import 'package:web3modal_flutter/utils/platform/i_platform_utils.dart'; import 'package:web3modal_flutter/utils/url/launch_url_exception.dart'; +import 'package:web3modal_flutter/utils/w3m_logger.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; import 'package:web3modal_flutter/widgets/widget_stack/widget_stack_singleton.dart'; import 'package:web3modal_flutter/services/blockchain_api_service/blockchain_api_utils.dart'; @@ -100,6 +107,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { Set? featuredWalletIds, Set? includedWalletIds, Set? excludedWalletIds, + bool? enableAnalytics, LogLevel logLevel = LogLevel.nothing, }) { if (web3App == null) { @@ -113,6 +121,13 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { } } + loggerService.instance = LoggerService(level: logLevel, debugMode: false); + // loggerService.instance.logEvents.listen((event) { + // debugPrint('[LoggerService] ${event.message}'); + // }); + + W3MLoggerUtil.setLogLevel(logLevel, debugMode: true); + _web3App = web3App ?? Web3App( core: Core(projectId: projectId!), @@ -124,6 +139,11 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { _setOptionalNamespaces(optionalNamespaces); + analyticsService.instance = AnalyticsService( + projectId: _projectId, + enableAnalytics: enableAnalytics, + )..init(); + explorerService.instance = ExplorerService( projectId: _projectId, referer: _web3App.metadata.name.replaceAll(' ', ''), @@ -135,8 +155,6 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { blockchainApiUtils.instance = BlockchainApiUtils( projectId: _projectId, ); - - W3MLoggerUtil.setLogLevel(logLevel, debugMode: true); } ////////* PUBLIC METHODS *///////// @@ -161,6 +179,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { await storageService.instance.init(); await networkService.instance.init(); await explorerService.instance.init(); + // await analyticsService.instance.init(); if (_initializeCoinbaseSDK) { final cbWallet = await explorerService.instance.getCoinbaseWalletObject(); await cbInit(metadata: _web3App.metadata, cbWallet: cbWallet); @@ -374,6 +393,10 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { final data = MediaQueryData.fromView(View.of(_context!)); final isTabletSize = data.size.shortestSide < 600 ? false : true; + analyticsService.instance.sendEvent( + ModalOpenEvent(connected: _isConnected), + ); + if (isBottomSheet) { await showModalBottomSheet( backgroundColor: Colors.transparent, @@ -391,12 +414,14 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { context: _context!, builder: (_) => rootWidget, ); + _close(); } else { await showDialog( useRootNavigator: true, context: _context!, builder: (_) => rootWidget, ); + _close(); } _isOpen = false; @@ -412,18 +437,46 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { } } + void _trackSelectedWallet( + WalletRedirect? walletRedirect, { + bool inBrowser = false, + }) { + final walletName = _selectedWallet!.listing.name; + var event = SelectWalletEvent( + name: walletName, + platform: inBrowser + ? AnalyticsPlatform.web.name + : AnalyticsPlatform.mobile.name, + ); + // if (walletRedirect?.mobileOnly == true) { + // event = SelectWalletEvent( + // name: walletName, + // platform: AnalyticsPlatform.mobile.name, + // ); + // } + // if (walletRedirect?.webOnly == true) { + // event = SelectWalletEvent( + // name: walletName, + // platform: AnalyticsPlatform.web.name, + // ); + // } + analyticsService.instance.sendEvent(event); + } + @override Future connectSelectedWallet({bool inBrowser = false}) async { _checkInitialized(); - final selectedWalletRedirect = explorerService.instance.getWalletRedirect( + final walletRedirect = explorerService.instance.getWalletRedirect( selectedWallet, ); - if (selectedWalletRedirect == null) { + if (walletRedirect == null) { throw W3MServiceException( 'You didn\'t select a wallet or walletInfo argument is null', ); } + _trackSelectedWallet(walletRedirect, inBrowser: inBrowser); + var pType = platformUtils.instance.getPlatformType(); if (inBrowser) { pType = PlatformType.web; @@ -435,7 +488,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { } else { await buildConnectionUri(); await urlUtils.instance.openRedirect( - selectedWalletRedirect, + walletRedirect, wcURI: wcUri!, pType: pType, ); @@ -581,11 +634,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { @override void closeModal() { // If we aren't open, then we can't and shouldn't close - if (!_isOpen) { - return; - } - - toastUtils.instance.clear(); + _close(); if (_context != null) { // _isOpen and notify() are handled when we call Navigator.pop() // by the open() method @@ -595,6 +644,17 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { } } + void _close() { + if (!_isOpen) { + return; + } + _isOpen = false; + toastUtils.instance.clear(); + analyticsService.instance.sendEvent( + ModalCloseEvent(connected: _isConnected), + ); + } + @override void selectWallet(W3MWalletInfo walletInfo) { _selectedWallet = walletInfo; @@ -1034,9 +1094,23 @@ extension _W3MServiceExtension on W3MService { W3MLoggerUtil.logger.t('[$runtimeType] onSessionConnect: $args'); if (args != null) { if (_selectedWallet == null) { + analyticsService.instance.sendEvent( + // TODO check method options + ConnectSuccessEvent(name: 'Unknown', method: 'qrcode'), + ); await storageService.instance.clearKey(StringConstants.recentWalletId); await storageService.instance .clearKey(StringConstants.connectedWalletData); + } else { + // TODO check this logic + var pType = platformUtils.instance.getPlatformType(); + // if (inBrowser) { + // pType = PlatformType.web; + // } + final walletName = _selectedWallet!.listing.name; + analyticsService.instance.sendEvent( + ConnectSuccessEvent(name: walletName, method: pType.name), + ); } await _storeSession(W3MSession(sessionData: args.session)); await _selectChainFromStoredId(); diff --git a/lib/utils/core/core_utils.dart b/lib/utils/core/core_utils.dart index eb20899a..9c30441c 100644 --- a/lib/utils/core/core_utils.dart +++ b/lib/utils/core/core_utils.dart @@ -1,14 +1,66 @@ +import 'package:flutter_timezone/flutter_timezone.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'package:web3modal_flutter/constants/string_constants.dart'; import 'package:web3modal_flutter/utils/core/i_core_utils.dart'; import 'package:web3modal_flutter/utils/w3m_logger.dart'; class CoreUtils extends ICoreUtils { + static const restrictedTimezone = [ + 'ASIA/SHANGHAI', + 'ASIA/URUMQI', + 'ASIA/CHONGQING', + 'ASIA/HARBIN', + 'ASIA/KASHGAR', + 'ASIA/MACAU', + 'ASIA/HONG_KONG', + 'ASIA/MACAO', + 'ASIA/BEIJING', + 'ASIA/HARBIN', + ]; + @override bool isValidProjectID(String projectId) { return RegExp(r'^[0-9a-fA-F]{32}$').hasMatch(projectId); } + @override + Future isRestrictedRegion() async { + try { + String tz = await FlutterTimezone.getLocalTimezone(); + tz = tz.toUpperCase(); + return restrictedTimezone.contains(tz); + } catch (e) { + return false; + } + } + + @override + Future getApiUrl() async { + final restricted = await isRestrictedRegion(); + if (restricted) { + return 'https://api.web3modal.org'; + } + return 'https://api.web3modal.com'; + } + + @override + Future getBlockchainApiUrl() async { + final restricted = await isRestrictedRegion(); + if (restricted) { + return 'https://rpc.walletconnect.org'; + } + return 'https://rpc.walletconnect.com'; + } + + @override + Future getAnalyticsUrl() async { + final restricted = await isRestrictedRegion(); + if (restricted) { + return 'https://pulse.walletconnect.org'; + } + return 'https://pulse.walletconnect.com'; + } + @override bool isHttpUrl(String url) { return url.startsWith('http://') || url.startsWith('https://'); @@ -99,7 +151,7 @@ class CoreUtils extends ICoreUtils { 'x-sdk-type': StringConstants.X_SDK_TYPE, 'x-sdk-version': 'flutter-${StringConstants.X_SDK_VERSION}', 'user-agent': getUserAgent(), - 'referer': referer ?? '', + if (referer != null) 'referer': referer, }; } } diff --git a/lib/utils/core/i_core_utils.dart b/lib/utils/core/i_core_utils.dart index e22f636e..954f14b1 100644 --- a/lib/utils/core/i_core_utils.dart +++ b/lib/utils/core/i_core_utils.dart @@ -2,6 +2,14 @@ abstract class ICoreUtils { /// Returns true if the given [url] is a valid HTTP or HTTPS URL. bool isValidProjectID(String projectId); + Future isRestrictedRegion(); + + Future getApiUrl(); + + Future getBlockchainApiUrl(); + + Future getAnalyticsUrl(); + /// Returns true if the given [url] is a valid HTTP or HTTPS URL. bool isHttpUrl(String url); diff --git a/lib/utils/w3m_logger.dart b/lib/utils/w3m_logger.dart index 9aeea981..f7f0aee3 100644 --- a/lib/utils/w3m_logger.dart +++ b/lib/utils/w3m_logger.dart @@ -1,6 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; +// @Deprecated('W3MLoggerUtil is going to be deprecated soon. Don\'t use it') class W3MLoggerUtil { static Logger logger = Logger( level: Level.off, diff --git a/lib/web3modal_flutter.dart b/lib/web3modal_flutter.dart index f5e31795..cb8c593a 100644 --- a/lib/web3modal_flutter.dart +++ b/lib/web3modal_flutter.dart @@ -10,7 +10,6 @@ export 'models/w3m_wallet_info.dart'; /// Utils export 'utils/w3m_chains_presets.dart'; -export 'utils/w3m_logger.dart'; /// Theme export 'theme/w3m_theme.dart'; diff --git a/lib/widgets/miscellaneous/all_wallets_header.dart b/lib/widgets/miscellaneous/all_wallets_header.dart index cd2a98bf..5c296880 100644 --- a/lib/widgets/miscellaneous/all_wallets_header.dart +++ b/lib/widgets/miscellaneous/all_wallets_header.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/pages/qr_code_page.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service_singleton.dart'; import 'package:web3modal_flutter/theme/constants.dart'; import 'package:web3modal_flutter/widgets/icons/themed_icon.dart'; @@ -35,6 +37,12 @@ class AllWalletsHeader extends StatelessWidget { size: kSearchFieldHeight, iconPath: 'assets/icons/code.svg', onPressed: () { + analyticsService.instance.sendEvent( + SelectWalletEvent( + name: 'Unknown', + platform: AnalyticsPlatform.qrcode.name, + ), + ); widgetStack.instance.push(const QRCodePage()); }, ), diff --git a/lib/widgets/w3m_qr_code.dart b/lib/widgets/w3m_qr_code.dart index af5c2658..d0060b28 100644 --- a/lib/widgets/w3m_qr_code.dart +++ b/lib/widgets/w3m_qr_code.dart @@ -8,6 +8,7 @@ import 'package:web3modal_flutter/web3modal_flutter.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/content_loading.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; +// TODO This file should be called qr_code_view.dart class QRCodeWidget extends StatelessWidget { const QRCodeWidget({ super.key, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 3ebb6b9e..03439581 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import flutter_timezone import package_info_plus import path_provider_foundation import shared_preferences_foundation @@ -12,6 +13,7 @@ import sqflite import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 9544dc9f..41af2e18 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -355,6 +355,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_timezone: + dependency: "direct main" + description: + name: flutter_timezone + sha256: "06b35132c98fa188db3c4b654b7e1af7ccd01dfe12a004d58be423357605fb24" + url: "https://pub.dev" + source: hosted + version: "1.0.8" flutter_web_plugins: dependency: transitive description: flutter @@ -998,13 +1006,13 @@ packages: source: hosted version: "3.1.0" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid - sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921 + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 url: "https://pub.dev" source: hosted - version: "4.2.1" + version: "4.3.3" vector_graphics: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 902cbe4f..5f7efea1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,12 +16,14 @@ dependencies: flutter: sdk: flutter flutter_svg: ^2.0.9 + flutter_timezone: ^1.0.8 freezed_annotation: ^2.2.0 http: ^1.1.2 json_annotation: ^4.8.1 qr_flutter_wc: ^0.0.3 shimmer: ^3.0.0 url_launcher: ^6.2.3 + uuid: ^4.3.3 walletconnect_flutter_v2: ^2.2.0 dev_dependencies: diff --git a/test/mock_classes.mocks.dart b/test/mock_classes.mocks.dart index d94c168c..2d1230a8 100644 --- a/test/mock_classes.mocks.dart +++ b/test/mock_classes.mocks.dart @@ -2323,14 +2323,6 @@ class MockBlockchainApiUtils extends _i1.Mock _i1.throwOnMissingStub(this); } - @override - String get blockchainApiUriRoot => (super.noSuchMethod( - Invocation.getter(#blockchainApiUriRoot), - returnValue: _i13.dummyValue( - this, - Invocation.getter(#blockchainApiUriRoot), - ), - ) as String); @override String get projectId => (super.noSuchMethod( Invocation.getter(#projectId), From 06d6a781ccb21b5ae80c59f6b30790b298ea393d Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Mon, 4 Mar 2024 11:08:22 +0100 Subject: [PATCH 02/10] events listener --- example/lib/home_page.dart | 36 +++-- example/lib/widgets/logger_widget.dart | 62 ++++---- lib/pages/about_networks.dart | 16 +-- lib/pages/about_wallets.dart | 19 +-- lib/pages/account_page.dart | 16 ++- lib/pages/get_wallet_page.dart | 15 +- lib/pages/select_network_page.dart | 27 ++-- lib/pages/wallets_list_short_page.dart | 10 +- .../analytics_service/analytics_service.dart | 4 +- .../models/analytics_event.dart | 8 +- .../logger_service/i_logger_service.dart | 1 + .../logger_service/logger_service.dart | 5 +- lib/services/w3m_service/w3m_service.dart | 133 +++++++++++------- .../miscellaneous/all_wallets_header.dart | 9 +- lib/widgets/w3m_network_select_button.dart | 3 + lib/widgets/widget_stack/i_widget_stack.dart | 7 +- lib/widgets/widget_stack/widget_stack.dart | 11 +- test/mock_classes.mocks.dart | 14 +- 18 files changed, 212 insertions(+), 184 deletions(-) diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index 6949f91b..6812a94f 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:walletconnect_flutter_dapp/widgets/logger_widget.dart'; +import 'package:web3modal_flutter/services/coinbase_service/models/coinbase_events.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; @@ -21,27 +22,22 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - final CustomAnimatedOverlay overlay = CustomAnimatedOverlay( - const Duration(milliseconds: 200), - ); + final overlay = OverlayController(const Duration(milliseconds: 200)); late W3MService _w3mService; @override void initState() { super.initState(); - // WidgetsBinding.instance.addPostFrameCallback((_) { - // _addOverlay(); - // }); + WidgetsBinding.instance.addPostFrameCallback((_) { + _showOverlay(); + }); _initializeService(); } - // void _addOverlay() { - // overlay.insert( - // context, - // child: DraggableCard(overlayController: overlay), - // ); - // } + void _showOverlay() { + overlay.insert(context); + } void _initializeService() async { // See https://docs.walletconnect.com/web3modal/flutter/custom-chains @@ -80,7 +76,6 @@ class _MyHomePageState extends State { // '38f5d18bd8522c244bdd70cb4a68e0e718865155811c043f052fb9f1c51de662', // Bitget // }, ); - await _w3mService.init(); // If you want to support just one chain uncomment this line and avoid using W3MNetworkSelectButton() // _w3mService.selectChain(W3MChainPresets.chains['137']); @@ -90,6 +85,8 @@ class _MyHomePageState extends State { _w3mService.onSessionUpdateEvent.subscribe(_onSessionUpdate); _w3mService.onSessionConnectEvent.subscribe(_onSessionConnect); _w3mService.onSessionDeleteEvent.subscribe(_onSessionDelete); + _w3mService.onCoinbaseConnect.subscribe(_onCoinbaseConnect); + await _w3mService.init(); } @override @@ -98,9 +95,14 @@ class _MyHomePageState extends State { _w3mService.onSessionUpdateEvent.unsubscribe(_onSessionUpdate); _w3mService.onSessionConnectEvent.unsubscribe(_onSessionConnect); _w3mService.onSessionDeleteEvent.unsubscribe(_onSessionDelete); + _w3mService.onCoinbaseConnect.unsubscribe(_onCoinbaseConnect); super.dispose(); } + void _onCoinbaseConnect(CoinbaseConnectEvent? event) { + debugPrint('[$runtimeType] coinbase connect ${event?.data}'); + } + void _serviceListener() { setState(() {}); } @@ -115,6 +117,8 @@ class _MyHomePageState extends State { void _onSessionConnect(SessionConnect? args) { debugPrint('[$runtimeType] _onSessionConnect $args'); + debugPrint( + '[$runtimeType] _onSessionConnect ${_w3mService.session?.toJson()}'); } void _onSessionDelete(SessionDelete? args) { @@ -132,6 +136,12 @@ class _MyHomePageState extends State { backgroundColor: Web3ModalTheme.colorsOf(context).background175, foregroundColor: Web3ModalTheme.colorsOf(context).foreground100, actions: [ + IconButton( + icon: const Icon(Icons.logo_dev_sharp), + onPressed: () { + overlay.toggle(context); + }, + ), IconButton( icon: isCustom ? const Icon(Icons.yard) diff --git a/example/lib/widgets/logger_widget.dart b/example/lib/widgets/logger_widget.dart index 913507de..90055337 100644 --- a/example/lib/widgets/logger_widget.dart +++ b/example/lib/widgets/logger_widget.dart @@ -6,7 +6,7 @@ import 'package:flutter/scheduler.dart'; import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; class DraggableCard extends StatefulWidget { - final CustomAnimatedOverlay overlayController; + final OverlayController overlayController; const DraggableCard({ super.key, required this.overlayController, @@ -44,6 +44,12 @@ class _DraggableCardState extends State { }); } + @override + void dispose() { + widget.overlayController.remove(); + super.dispose(); + } + @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; @@ -95,8 +101,8 @@ class _DraggableCardState extends State { } } -class CustomAnimatedOverlay extends AnimatedOverlay { - CustomAnimatedOverlay(super.duration); +class OverlayController extends AnimatedOverlay { + OverlayController(super.duration); OverlayEntry? _entry; @@ -104,29 +110,37 @@ class CustomAnimatedOverlay extends AnimatedOverlay { Animation? alignAnimation; - OverlayEntry createAlignOverlay({Widget? child}) { + OverlayEntry createAlignOverlay(Widget child) { return OverlayEntry( + maintainState: true, builder: (_) { return CustomAlign( animation: alignAnimation ?? AlwaysStoppedAnimation(align), - child: child ?? - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: Colors.red, - ), - child: const Text('Align Overlay'), - ), + child: child, ); }, ); } - void insert(BuildContext context, {Widget? child}) { - _entry = createAlignOverlay(child: child); + void insert(BuildContext context) { + _entry = createAlignOverlay(DraggableCard(overlayController: this)); Overlay.of(context).insert(_entry!); } + void toggle(BuildContext context) { + if (_entry != null) { + remove(); + } else { + insert(context); + } + } + + void remove() { + _entry?.remove(); + _entry?.dispose(); + _entry = null; + } + void alignChildTo(Offset globalPosition, Size size) { double dx = (globalPosition.dx - size.width) / size.width; double dy = (globalPosition.dy - size.height) / size.height; @@ -145,16 +159,6 @@ class CustomAnimatedOverlay extends AnimatedOverlay { controller.forward(); _entry?.markNeedsBuild(); } - - void alignToScreenEdge() { - alignAnimation = - createAnimation(begin: align, end: Alignment.centerRight); - - align = Alignment.centerRight; - - controller.forward(); - _entry?.markNeedsBuild(); - } } abstract class AnimatedOverlay extends TickerProvider { @@ -189,16 +193,6 @@ abstract class AnimatedOverlay extends TickerProvider { } } -abstract class CustomAnimatedWidget extends AnimatedWidget { - final Widget child; - final Animation animation; - const CustomAnimatedWidget({ - super.key, - required this.child, - required this.animation, - }) : super(listenable: animation); -} - class CustomAlign extends AnimatedWidget { final Widget child; final Animation animation; diff --git a/lib/pages/about_networks.dart b/lib/pages/about_networks.dart index 01d1c915..7e4595f5 100644 --- a/lib/pages/about_networks.dart +++ b/lib/pages/about_networks.dart @@ -3,27 +3,13 @@ import 'package:url_launcher/url_launcher_string.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/constants/string_constants.dart'; -import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; -import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; import 'package:web3modal_flutter/widgets/buttons/simple_icon_button.dart'; import 'package:web3modal_flutter/widgets/help/help_section.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; -class AboutNetworks extends StatefulWidget { +class AboutNetworks extends StatelessWidget { const AboutNetworks() : super(key: KeyConstants.helpPageKey); - - @override - State createState() => _AboutNetworksState(); -} - -class _AboutNetworksState extends State { - @override - void initState() { - super.initState(); - analyticsService.instance.sendEvent(ClickNetworkHelpEvent()); - } - @override Widget build(BuildContext context) { return Web3ModalNavbar( diff --git a/lib/pages/about_wallets.dart b/lib/pages/about_wallets.dart index b5df8705..6434cadc 100644 --- a/lib/pages/about_wallets.dart +++ b/lib/pages/about_wallets.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/pages/get_wallet_page.dart'; -import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/widgets/widget_stack/widget_stack_singleton.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; @@ -9,20 +8,9 @@ import 'package:web3modal_flutter/widgets/buttons/simple_icon_button.dart'; import 'package:web3modal_flutter/widgets/help/help_section.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; -class AboutWallets extends StatefulWidget { +class AboutWallets extends StatelessWidget { const AboutWallets() : super(key: KeyConstants.helpPageKey); - @override - State createState() => _AboutWalletsState(); -} - -class _AboutWalletsState extends State { - @override - void initState() { - super.initState(); - analyticsService.instance.sendEvent(ClickWalletHelpEvent()); - } - @override Widget build(BuildContext context) { return Web3ModalNavbar( @@ -69,7 +57,10 @@ class _AboutWalletsState extends State { const SizedBox(height: 8), SimpleIconButton( onTap: () { - widgetStack.instance.push(const GetWalletPage()); + widgetStack.instance.push( + const GetWalletPage(), + event: ClickGetWalletEvent(), + ); }, leftIcon: 'assets/icons/wallet.svg', title: 'Get a wallet', diff --git a/lib/pages/account_page.dart b/lib/pages/account_page.dart index e486bf66..7bb95109 100644 --- a/lib/pages/account_page.dart +++ b/lib/pages/account_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/pages/select_network_page.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service_singleton.dart'; import 'package:web3modal_flutter/services/w3m_service/i_w3m_service.dart'; import 'package:web3modal_flutter/theme/constants.dart'; @@ -110,12 +111,15 @@ class _AccountPageState extends State with WidgetsBindingObserver { ), title: _service?.selectedChain?.chainName ?? '', onTap: () { - widgetStack.instance.push(SelectNetworkPage( - onTapNetwork: (W3MChainInfo chainInfo) { - _service?.selectChain(chainInfo, switchChain: true); - widgetStack.instance.pop(); - }, - )); + widgetStack.instance.push( + SelectNetworkPage( + onTapNetwork: (W3MChainInfo chainInfo) { + _service?.selectChain(chainInfo, switchChain: true); + widgetStack.instance.pop(); + }, + ), + event: ClickNetworksEvent(), + ); }, ), const SizedBox.square(dimension: kPadding8), diff --git a/lib/pages/get_wallet_page.dart b/lib/pages/get_wallet_page.dart index 608259b9..b317025a 100644 --- a/lib/pages/get_wallet_page.dart +++ b/lib/pages/get_wallet_page.dart @@ -7,8 +7,6 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/constants/string_constants.dart'; import 'package:web3modal_flutter/models/grid_item.dart'; -import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; -import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/theme/constants.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; import 'package:web3modal_flutter/widgets/lists/list_items/all_wallets_item.dart'; @@ -19,20 +17,9 @@ import 'package:web3modal_flutter/widgets/miscellaneous/content_loading.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; import 'package:web3modal_flutter/utils/url/url_utils_singleton.dart'; -class GetWalletPage extends StatefulWidget { +class GetWalletPage extends StatelessWidget { const GetWalletPage() : super(key: KeyConstants.getAWalletPageKey); - @override - State createState() => _GetWalletPageState(); -} - -class _GetWalletPageState extends State { - @override - void initState() { - super.initState(); - analyticsService.instance.sendEvent(ClickGetWalletEvent()); - } - @override Widget build(BuildContext context) { final themeColors = Web3ModalTheme.colorsOf(context); diff --git a/lib/pages/select_network_page.dart b/lib/pages/select_network_page.dart index 3b669746..469993db 100644 --- a/lib/pages/select_network_page.dart +++ b/lib/pages/select_network_page.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/constants/key_constants.dart'; import 'package:web3modal_flutter/pages/about_networks.dart'; -import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/theme/constants.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; @@ -15,21 +14,12 @@ import 'package:web3modal_flutter/widgets/miscellaneous/content_loading.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; import 'package:web3modal_flutter/widgets/web3modal_provider.dart'; -class SelectNetworkPage extends StatefulWidget { - const SelectNetworkPage({required this.onTapNetwork}) - : super(key: KeyConstants.selectNetworkPage); - final Function(W3MChainInfo)? onTapNetwork; - - @override - State createState() => _SelectNetworkPageState(); -} +class SelectNetworkPage extends StatelessWidget { + const SelectNetworkPage({ + required this.onTapNetwork, + }) : super(key: KeyConstants.selectNetworkPage); -class _SelectNetworkPageState extends State { - @override - void initState() { - super.initState(); - analyticsService.instance.sendEvent(ClickNetworksEvent()); - } + final Function(W3MChainInfo)? onTapNetwork; @override Widget build(BuildContext context) { @@ -58,7 +48,7 @@ class _SelectNetworkPageState extends State { return const ContentLoading(); } return NetworksGrid( - onTapNetwork: widget.onTapNetwork, + onTapNetwork: onTapNetwork, itemList: items, ); }, @@ -76,7 +66,10 @@ class _SelectNetworkPageState extends State { ), SimpleIconButton( onTap: () { - widgetStack.instance.push(const AboutNetworks()); + widgetStack.instance.push( + const AboutNetworks(), + event: ClickNetworkHelpEvent(), + ); }, size: BaseButtonSize.small, leftIcon: 'assets/icons/help.svg', diff --git a/lib/pages/wallets_list_short_page.dart b/lib/pages/wallets_list_short_page.dart index a4b156ca..91ce39ea 100644 --- a/lib/pages/wallets_list_short_page.dart +++ b/lib/pages/wallets_list_short_page.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/pages/about_wallets.dart'; import 'package:web3modal_flutter/pages/connect_wallet_page.dart'; -import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service_singleton.dart'; import 'package:web3modal_flutter/theme/constants.dart'; @@ -41,7 +40,10 @@ class _WalletsListShortPageState extends State { leftAction: NavbarActionButton( asset: 'assets/icons/help.svg', action: () { - widgetStack.instance.push(const AboutWallets()); + widgetStack.instance.push( + const AboutWallets(), + event: ClickWalletHelpEvent(), + ); }, ), safeAreaLeft: true, @@ -82,11 +84,9 @@ class _WalletsListShortPageState extends State { }, ), onTap: () { - analyticsService.instance.sendEvent( - ClickAllWalletsEvent(), - ); widgetStack.instance.push( const WalletsListLongPage(), + event: ClickAllWalletsEvent(), ); }, ), diff --git a/lib/services/analytics_service/analytics_service.dart b/lib/services/analytics_service/analytics_service.dart index b81a9bcd..e5e843db 100644 --- a/lib/services/analytics_service/analytics_service.dart +++ b/lib/services/analytics_service/analytics_service.dart @@ -35,7 +35,6 @@ class AnalyticsService implements IAnalyticsService { _isEnabled = enableAnalytics!; } loggerService.instance.i('[$runtimeType] init enabled: $_isEnabled'); - sendEvent(ModalLoadedEvent()); } catch (e, s) { loggerService.instance.e( '[$runtimeType] init error', @@ -94,6 +93,9 @@ class AnalyticsService implements IAnalyticsService { ); final code = response.statusCode; loggerService.instance.i('[$runtimeType] sendEvent ::$body:: $code'); + if (!kDebugMode) { + loggerService.instance.sink(LogEvent(Level.all, 'sendEvent ::$body::')); + } } catch (e, s) { loggerService.instance.e( '[$runtimeType] sendEvent error', diff --git a/lib/services/analytics_service/models/analytics_event.dart b/lib/services/analytics_service/models/analytics_event.dart index 8f85485e..32d7d908 100644 --- a/lib/services/analytics_service/models/analytics_event.dart +++ b/lib/services/analytics_service/models/analytics_event.dart @@ -166,9 +166,9 @@ class SelectWalletEvent implements AnalyticsEvent { final String? _platform; SelectWalletEvent({ required String name, - String? platform, + AnalyticsPlatform? platform, }) : _name = name, - _platform = platform; + _platform = platform?.name; @override String get type => 'track'; @@ -195,9 +195,9 @@ class ConnectSuccessEvent implements AnalyticsEvent { final String? _method; ConnectSuccessEvent({ required String name, - String? method, + AnalyticsPlatform? method, }) : _name = name, - _method = method; + _method = method?.name; @override String get type => 'track'; diff --git a/lib/services/logger_service/i_logger_service.dart b/lib/services/logger_service/i_logger_service.dart index 1e194dfc..9fe2c6c3 100644 --- a/lib/services/logger_service/i_logger_service.dart +++ b/lib/services/logger_service/i_logger_service.dart @@ -4,6 +4,7 @@ abstract class ILoggerService { // Stream get logEvents; // + void sink(LogEvent event); // Logger get logger; /// Log a message at level [Level.trace]. diff --git a/lib/services/logger_service/logger_service.dart b/lib/services/logger_service/logger_service.dart index 894a3fd8..9892f867 100644 --- a/lib/services/logger_service/logger_service.dart +++ b/lib/services/logger_service/logger_service.dart @@ -10,6 +10,9 @@ class LoggerService implements ILoggerService { @override final Stream logEvents = _loggerController.stream; + @override + void sink(LogEvent event) => _loggerController.sink.add(event); + late Logger _logger; LoggerService({required LogLevel level, bool debugMode = true}) { @@ -23,7 +26,7 @@ class LoggerService implements ILoggerService { } void _logListener(LogEvent event) { - _loggerController.sink.add(event); + sink(event); } @override diff --git a/lib/services/w3m_service/w3m_service.dart b/lib/services/w3m_service/w3m_service.dart index 88c5931e..726450b9 100644 --- a/lib/services/w3m_service/w3m_service.dart +++ b/lib/services/w3m_service/w3m_service.dart @@ -121,10 +121,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { } } - loggerService.instance = LoggerService(level: logLevel, debugMode: false); - // loggerService.instance.logEvents.listen((event) { - // debugPrint('[LoggerService] ${event.message}'); - // }); + loggerService.instance = LoggerService(level: logLevel, debugMode: true); W3MLoggerUtil.setLogLevel(logLevel, debugMode: true); @@ -142,7 +139,9 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { analyticsService.instance = AnalyticsService( projectId: _projectId, enableAnalytics: enableAnalytics, - )..init(); + )..init().then((_) { + analyticsService.instance.sendEvent(ModalLoadedEvent()); + }); explorerService.instance = ExplorerService( projectId: _projectId, @@ -261,10 +260,10 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { defaultValue: '', )!; if (chainId.isNotEmpty && W3MChainPresets.chains.containsKey(chainId)) { - await selectChain(W3MChainPresets.chains[chainId]!); + await selectChain(W3MChainPresets.chains[chainId]!, event: false); } else { final chainId = _currentSession!.chainId; - await selectChain(W3MChainPresets.chains[chainId]!); + await selectChain(W3MChainPresets.chains[chainId]!, event: false); } } } @@ -273,6 +272,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { Future selectChain( W3MChainInfo? chainInfo, { bool switchChain = false, + bool event = true, }) async { _checkInitialized(); @@ -299,10 +299,10 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { await launchConnectedWallet(); } } else { - _setEthChain(chainInfo); + _setEthChain(chainInfo, event: event); } } else { - _setEthChain(chainInfo); + _setEthChain(chainInfo, event: event); } } @@ -341,7 +341,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { return _currentSession!.getApprovedEvents(); } - void _setEthChain(W3MChainInfo chainInfo) async { + void _setEthChain(W3MChainInfo chainInfo, {bool event = false}) async { W3MLoggerUtil.logger.t('[$runtimeType] set chain ${chainInfo.namespace}'); _currentSelectedChain = chainInfo; @@ -351,6 +351,10 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { StringConstants.selectedChainId, _currentSelectedChain!.chainId, ); + if (event) { + final network = chainInfo.chainId; + analyticsService.instance.sendEvent(SwitchNetworkEvent(network: network)); + } _notify(); _loadAccountData(); @@ -365,6 +369,10 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { } _isOpen = true; + analyticsService.instance.sendEvent(ModalOpenEvent( + connected: _isConnected, + )); + // Reset the explorer explorerService.instance.search(query: null); widgetStack.instance.clear(); @@ -393,10 +401,6 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { final data = MediaQueryData.fromView(View.of(_context!)); final isTabletSize = data.size.shortestSide < 600 ? false : true; - analyticsService.instance.sendEvent( - ModalOpenEvent(connected: _isConnected), - ); - if (isBottomSheet) { await showModalBottomSheet( backgroundColor: Colors.transparent, @@ -442,11 +446,9 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { bool inBrowser = false, }) { final walletName = _selectedWallet!.listing.name; - var event = SelectWalletEvent( + final event = SelectWalletEvent( name: walletName, - platform: inBrowser - ? AnalyticsPlatform.web.name - : AnalyticsPlatform.mobile.name, + platform: inBrowser ? AnalyticsPlatform.web : AnalyticsPlatform.mobile, ); // if (walletRedirect?.mobileOnly == true) { // event = SelectWalletEvent( @@ -514,13 +516,22 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { if (_isUserRejectedError(e)) { W3MLoggerUtil.logger.t('[$runtimeType] User declined connection'); onWalletConnectionError.broadcast(UserRejectedConnection()); + analyticsService.instance.sendEvent(ConnectErrorEvent( + message: 'User declined connection', + )); } else { onWalletConnectionError.broadcast(ErrorOpeningWallet()); + analyticsService.instance.sendEvent(ConnectErrorEvent( + message: e.message, + )); } } } else if (_isUserRejectedError(e)) { W3MLoggerUtil.logger.t('[$runtimeType] User declined connection'); onWalletConnectionError.broadcast(UserRejectedConnection()); + analyticsService.instance.sendEvent(ConnectErrorEvent( + message: 'User declined connection', + )); } else { W3MLoggerUtil.logger.e( '[$runtimeType] Error connecting wallet', @@ -565,12 +576,19 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { if (_isUserRejectedError(e)) { W3MLoggerUtil.logger.t('[$runtimeType] User declined connection'); onWalletConnectionError.broadcast(UserRejectedConnection()); + analyticsService.instance.sendEvent(ConnectErrorEvent( + message: 'User declined connection', + )); } else { + final message = e.message ?? 'Error connecting to wallet'; W3MLoggerUtil.logger.e( - '[$runtimeType] Error connecting to wallet', + '[$runtimeType] $message', error: e, stackTrace: s, ); + analyticsService.instance.sendEvent(ConnectErrorEvent( + message: message, + )); } return await expirePreviousInactivePairings(); } @@ -616,43 +634,53 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { Future disconnect({bool disconnectAllSessions = true}) async { _checkInitialized(); - // If we want to disconnect all sessions, loop through them and disconnect them - if (disconnectAllSessions) { - for (final SessionData session in _web3App.sessions.getAll()) { - await _disconnectSession(session); - } - } else { - // Disconnect the session - if (_currentSession?.sessionData != null) { - await _disconnectSession(_currentSession!.sessionData!); + try { + // If we want to disconnect all sessions, loop through them and disconnect them + if (disconnectAllSessions) { + for (final session in _web3App.sessions.getAll()) { + await _disconnectSession(session); + } + } else { + // Disconnect the session + if (_currentSession?.sessionData != null) { + await _disconnectSession(_currentSession!.sessionData!); + } } - } - return await _cleanSession(); + analyticsService.instance.sendEvent(DisconnectSuccessEvent()); + return await _cleanSession(); + } catch (e) { + analyticsService.instance.sendEvent(DisconnectErrorEvent()); + } } @override void closeModal() { // If we aren't open, then we can't and shouldn't close - _close(); + _close(event: false); if (_context != null) { // _isOpen and notify() are handled when we call Navigator.pop() // by the open() method Navigator.of(_context!, rootNavigator: true).pop(); + analyticsService.instance.sendEvent(ModalCloseEvent( + connected: _isConnected, + )); } else { _notify(); } } - void _close() { + void _close({bool event = true}) { if (!_isOpen) { return; } _isOpen = false; toastUtils.instance.clear(); - analyticsService.instance.sendEvent( - ModalCloseEvent(connected: _isConnected), - ); + if (event) { + analyticsService.instance.sendEvent(ModalCloseEvent( + connected: _isConnected, + )); + } } @override @@ -743,7 +771,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { ); } catch (e, s) { if (_isUserRejectedError(e)) { - W3MLoggerUtil.logger.t('[$runtimeType] User declined connection'); + W3MLoggerUtil.logger.t('[$runtimeType] User declined request'); onWalletConnectionError.broadcast(UserRejectedConnection()); if (request.method == 'wallet_switchEthereumChain' || request.method == 'wallet_addEthereumChain') { @@ -899,7 +927,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { ], ), ).then((_) { - _setEthChain(newChain); + _setEthChain(newChain, event: true); }).catchError( (e, s) { // if request errors due to user rejection then set the previous chain @@ -916,7 +944,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { params: [newChain.toJson()], ), ).then((_) { - _setEthChain(newChain); + _setEthChain(newChain, event: true); }).catchError((_) { _setEthChain(_currentSelectedChain!); }); @@ -1089,28 +1117,31 @@ extension _W3MServiceExtension on W3MService { .t('[$runtimeType] onCoinbaseResponseEvent: ${args?.data}'); } + // TODO this should be converted to void onSessionConnect(W3MSession? session) async {} + // or having an onModalConnect(W3MSession? session) event @protected void onSessionConnect(SessionConnect? args) async { W3MLoggerUtil.logger.t('[$runtimeType] onSessionConnect: $args'); if (args != null) { if (_selectedWallet == null) { - analyticsService.instance.sendEvent( - // TODO check method options - ConnectSuccessEvent(name: 'Unknown', method: 'qrcode'), + final walletName = args.session.peer.metadata.name; + analyticsService.instance.sendEvent(ConnectSuccessEvent( + name: walletName, + method: AnalyticsPlatform.qrcode, + )); + await storageService.instance.clearKey( + StringConstants.recentWalletId, + ); + await storageService.instance.clearKey( + StringConstants.connectedWalletData, ); - await storageService.instance.clearKey(StringConstants.recentWalletId); - await storageService.instance - .clearKey(StringConstants.connectedWalletData); } else { // TODO check this logic - var pType = platformUtils.instance.getPlatformType(); - // if (inBrowser) { - // pType = PlatformType.web; - // } final walletName = _selectedWallet!.listing.name; - analyticsService.instance.sendEvent( - ConnectSuccessEvent(name: walletName, method: pType.name), - ); + analyticsService.instance.sendEvent(ConnectSuccessEvent( + name: walletName, + method: AnalyticsPlatform.mobile, + )); } await _storeSession(W3MSession(sessionData: args.session)); await _selectChainFromStoredId(); diff --git a/lib/widgets/miscellaneous/all_wallets_header.dart b/lib/widgets/miscellaneous/all_wallets_header.dart index 5c296880..4d39af00 100644 --- a/lib/widgets/miscellaneous/all_wallets_header.dart +++ b/lib/widgets/miscellaneous/all_wallets_header.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/pages/qr_code_page.dart'; -import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/services/explorer_service/explorer_service_singleton.dart'; import 'package:web3modal_flutter/theme/constants.dart'; @@ -37,13 +36,13 @@ class AllWalletsHeader extends StatelessWidget { size: kSearchFieldHeight, iconPath: 'assets/icons/code.svg', onPressed: () { - analyticsService.instance.sendEvent( - SelectWalletEvent( + widgetStack.instance.push( + const QRCodePage(), + event: SelectWalletEvent( name: 'Unknown', - platform: AnalyticsPlatform.qrcode.name, + platform: AnalyticsPlatform.qrcode, ), ); - widgetStack.instance.push(const QRCodePage()); }, ), const SizedBox.square(dimension: 2.0), diff --git a/lib/widgets/w3m_network_select_button.dart b/lib/widgets/w3m_network_select_button.dart index 25384416..d6f76cb5 100644 --- a/lib/widgets/w3m_network_select_button.dart +++ b/lib/widgets/w3m_network_select_button.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/models/w3m_chain_info.dart'; import 'package:web3modal_flutter/pages/select_network_page.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/services/w3m_service/i_w3m_service.dart'; import 'package:web3modal_flutter/widgets/widget_stack/widget_stack_singleton.dart'; import 'package:web3modal_flutter/widgets/buttons/base_button.dart'; @@ -48,6 +50,7 @@ class _W3MNetworkSelectButtonState extends State { } void _onConnectPressed(BuildContext context) { + analyticsService.instance.sendEvent(ClickNetworksEvent()); widget.service.openModal( context, SelectNetworkPage( diff --git a/lib/widgets/widget_stack/i_widget_stack.dart b/lib/widgets/widget_stack/i_widget_stack.dart index 641a0603..d3980361 100644 --- a/lib/widgets/widget_stack/i_widget_stack.dart +++ b/lib/widgets/widget_stack/i_widget_stack.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; abstract class IWidgetStack with ChangeNotifier { abstract final ValueNotifier onRenderScreen; @@ -7,7 +8,11 @@ abstract class IWidgetStack with ChangeNotifier { Widget getCurrent(); /// Pushes a widget to the stack. - void push(Widget widget, {bool renderScreen = false}); + void push( + Widget widget, { + bool renderScreen = false, + AnalyticsEvent? event, + }); /// Removes a widget from the stack. void pop(); diff --git a/lib/widgets/widget_stack/widget_stack.dart b/lib/widgets/widget_stack/widget_stack.dart index 6bd7d21e..8adcd3c8 100644 --- a/lib/widgets/widget_stack/widget_stack.dart +++ b/lib/widgets/widget_stack/widget_stack.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:web3modal_flutter/pages/wallets_list_short_page.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart'; import 'package:web3modal_flutter/widgets/widget_stack/i_widget_stack.dart'; // import 'package:web3modal_flutter/utils/platform/i_platform_utils.dart'; @@ -16,7 +18,14 @@ class WidgetStack extends IWidgetStack { Widget getCurrent() => _stack.last; @override - void push(Widget widget, {bool renderScreen = false}) { + void push( + Widget widget, { + bool renderScreen = false, + AnalyticsEvent? event, + }) { + if (event != null) { + analyticsService.instance.sendEvent(event); + } onRenderScreen.value = renderScreen; _stack.add(widget); notifyListeners(); diff --git a/test/mock_classes.mocks.dart b/test/mock_classes.mocks.dart index 2d1230a8..0cd3b261 100644 --- a/test/mock_classes.mocks.dart +++ b/test/mock_classes.mocks.dart @@ -27,6 +27,8 @@ import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart' import 'package:walletconnect_flutter_v2/apis/core/store/i_store.dart' as _i6; import 'package:walletconnect_flutter_v2/apis/sign_api/i_sessions.dart' as _i5; import 'package:web3modal_flutter/models/grid_item.dart' as _i30; +import 'package:web3modal_flutter/services/analytics_service/models/analytics_event.dart' + as _i35; import 'package:web3modal_flutter/services/blockchain_api_service/blockchain_api_utils.dart' as _i31; import 'package:web3modal_flutter/services/blockchain_api_service/blockchain_identity.dart' @@ -645,12 +647,16 @@ class MockW3MService extends _i1.Mock implements _i3.W3MService { _i14.Future selectChain( _i3.W3MChainInfo? chainInfo, { bool? switchChain = false, + bool? event = true, }) => (super.noSuchMethod( Invocation.method( #selectChain, [chainInfo], - {#switchChain: switchChain}, + { + #switchChain: switchChain, + #event: event, + }, ), returnValue: _i14.Future.value(), returnValueForMissingStub: _i14.Future.value(), @@ -2531,12 +2537,16 @@ class MockWidgetStack extends _i1.Mock implements _i34.WidgetStack { void push( _i11.Widget? widget, { bool? renderScreen = false, + _i35.AnalyticsEvent? event, }) => super.noSuchMethod( Invocation.method( #push, [widget], - {#renderScreen: renderScreen}, + { + #renderScreen: renderScreen, + #event: event, + }, ), returnValueForMissingStub: null, ); From 364e6da92a2c9181282b9a5524302900015dfc09 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Mon, 4 Mar 2024 11:27:04 +0100 Subject: [PATCH 03/10] minor change --- lib/pages/about_networks.dart | 1 + lib/services/ledger_service/ledger_service.dart | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pages/about_networks.dart b/lib/pages/about_networks.dart index 7e4595f5..6ff54cce 100644 --- a/lib/pages/about_networks.dart +++ b/lib/pages/about_networks.dart @@ -10,6 +10,7 @@ import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; class AboutNetworks extends StatelessWidget { const AboutNetworks() : super(key: KeyConstants.helpPageKey); + @override Widget build(BuildContext context) { return Web3ModalNavbar( diff --git a/lib/services/ledger_service/ledger_service.dart b/lib/services/ledger_service/ledger_service.dart index 21034c35..ef50ac4b 100644 --- a/lib/services/ledger_service/ledger_service.dart +++ b/lib/services/ledger_service/ledger_service.dart @@ -1,6 +1,6 @@ import 'package:http/http.dart'; import 'package:web3modal_flutter/services/ledger_service/i_ledger_service.dart'; -import 'package:web3modal_flutter/utils/w3m_logger.dart'; +import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; class LedgerService extends ILedgerService { @@ -11,7 +11,7 @@ class LedgerService extends ILedgerService { final amount = await client.getBalance(EthereumAddress.fromHex(address)); return amount.getValueInUnit(EtherUnit.ether); } catch (e, s) { - W3MLoggerUtil.logger.e( + loggerService.instance.e( '[$runtimeType] getBalance error', error: e, stackTrace: s, From a1a4558e31775f09f37b85379da938eaa6f293dc Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Wed, 6 Mar 2024 17:14:45 +0100 Subject: [PATCH 04/10] some minor modifications --- example/lib/widgets/logger_widget.dart | 32 ++++++------------- .../analytics_service/analytics_service.dart | 9 ++++-- .../i_analytics_service.dart | 1 + .../blockchain_api_utils.dart | 7 ++-- .../logger_service/i_logger_service.dart | 6 ---- .../logger_service/logger_service.dart | 11 +------ lib/services/w3m_service/w3m_service.dart | 32 +++++++++---------- .../miscellaneous/all_wallets_header.dart | 2 +- lib/widgets/w3m_network_select_button.dart | 2 +- test/mock_classes.mocks.dart | 4 +-- 10 files changed, 40 insertions(+), 66 deletions(-) diff --git a/example/lib/widgets/logger_widget.dart b/example/lib/widgets/logger_widget.dart index 90055337..520a1811 100644 --- a/example/lib/widgets/logger_widget.dart +++ b/example/lib/widgets/logger_widget.dart @@ -1,9 +1,6 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; - -import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; +import 'package:web3modal_flutter/services/analytics_service/analytics_service_singleton.dart'; class DraggableCard extends StatefulWidget { final OverlayController overlayController; @@ -22,25 +19,14 @@ class _DraggableCardState extends State { @override void initState() { super.initState(); - loggerService.instance.logEvents.listen((event) { - final message = '${event.message}'; - if (message.contains('sendEvent')) { - final match = RegExp(r'::([^]*?)::').firstMatch(message)?[1]; - if (match != null) { - final json = jsonDecode(match.trim()) as Map; - final data = json['props']; - _logs.add( - Text( - '=> $data', - style: const TextStyle( - color: Colors.white, - fontSize: 12.0, - ), - ), - ); - setState(() {}); - } - } + analyticsService.instance.events.listen((event) { + _logs.add( + Text( + '=> $event', + style: const TextStyle(color: Colors.white, fontSize: 12.0), + ), + ); + setState(() {}); }); } diff --git a/lib/services/analytics_service/analytics_service.dart b/lib/services/analytics_service/analytics_service.dart index e5e843db..74a3a819 100644 --- a/lib/services/analytics_service/analytics_service.dart +++ b/lib/services/analytics_service/analytics_service.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; @@ -10,11 +11,15 @@ import 'package:web3modal_flutter/utils/core/core_utils_singleton.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; class AnalyticsService implements IAnalyticsService { + static final _eventsController = StreamController.broadcast(); static const _debugApiEndpoint = 'https://analytics-api-cf-workers-staging.walletconnect-v1-bridge.workers.dev'; static const _debugProjectId = 'e087b4b0503b860119be49d906717c12'; bool _isEnabled = false; + @override + final Stream events = _eventsController.stream; + @override final String projectId; @@ -93,9 +98,7 @@ class AnalyticsService implements IAnalyticsService { ); final code = response.statusCode; loggerService.instance.i('[$runtimeType] sendEvent ::$body:: $code'); - if (!kDebugMode) { - loggerService.instance.sink(LogEvent(Level.all, 'sendEvent ::$body::')); - } + _eventsController.sink.add(analyticsEvent.toMap()); } catch (e, s) { loggerService.instance.e( '[$runtimeType] sendEvent error', diff --git a/lib/services/analytics_service/i_analytics_service.dart b/lib/services/analytics_service/i_analytics_service.dart index ea3d3b10..39c090aa 100644 --- a/lib/services/analytics_service/i_analytics_service.dart +++ b/lib/services/analytics_service/i_analytics_service.dart @@ -3,6 +3,7 @@ import 'package:web3modal_flutter/services/analytics_service/models/analytics_ev abstract class IAnalyticsService { String get projectId; bool? get enableAnalytics; + Stream get events; Future init(); void sendEvent(AnalyticsEvent analyticsEvent); Future fetchAnalyticsConfig(); diff --git a/lib/services/blockchain_api_service/blockchain_api_utils.dart b/lib/services/blockchain_api_service/blockchain_api_utils.dart index dffd609a..0edd54aa 100644 --- a/lib/services/blockchain_api_service/blockchain_api_utils.dart +++ b/lib/services/blockchain_api_service/blockchain_api_utils.dart @@ -17,14 +17,13 @@ class BlockchainApiUtils extends IBlockchainApiUtils { Future getIdentity(String address, int chainId) async { final scope = '${StringConstants.namespace}:$chainId'; final url = await coreUtils.instance.getBlockchainApiUrl(); - final endpoint = '$url/v1/identity/$address'; - '?chainId=$scope&projectId=$projectId'; - + final endpoint = + '$url/v1/identity/$address?chainId=$scope&projectId=$projectId'; final response = await http.get(Uri.parse(endpoint)); if (response.statusCode == 200) { return BlockchainIdentity.fromJson(jsonDecode(response.body)); } else { - throw Exception('Failed to load data'); + throw Exception('Failed to load avatar'); } } } diff --git a/lib/services/logger_service/i_logger_service.dart b/lib/services/logger_service/i_logger_service.dart index 9fe2c6c3..ce760de0 100644 --- a/lib/services/logger_service/i_logger_service.dart +++ b/lib/services/logger_service/i_logger_service.dart @@ -1,12 +1,6 @@ import 'package:web3modal_flutter/web3modal_flutter.dart'; abstract class ILoggerService { - // - Stream get logEvents; - // - void sink(LogEvent event); - // Logger get logger; - /// Log a message at level [Level.trace]. void t( dynamic message, { diff --git a/lib/services/logger_service/logger_service.dart b/lib/services/logger_service/logger_service.dart index 9892f867..584d9b79 100644 --- a/lib/services/logger_service/logger_service.dart +++ b/lib/services/logger_service/logger_service.dart @@ -5,16 +5,7 @@ import 'package:web3modal_flutter/services/logger_service/i_logger_service.dart' import 'package:web3modal_flutter/web3modal_flutter.dart'; class LoggerService implements ILoggerService { - static final _loggerController = StreamController.broadcast(); - - @override - final Stream logEvents = _loggerController.stream; - - @override - void sink(LogEvent event) => _loggerController.sink.add(event); - late Logger _logger; - LoggerService({required LogLevel level, bool debugMode = true}) { _logger = Logger( level: level.toLevel(), @@ -26,7 +17,7 @@ class LoggerService implements ILoggerService { } void _logListener(LogEvent event) { - sink(event); + // debugPrint('${event.message}'); } @override diff --git a/lib/services/w3m_service/w3m_service.dart b/lib/services/w3m_service/w3m_service.dart index 726450b9..a1847eef 100644 --- a/lib/services/w3m_service/w3m_service.dart +++ b/lib/services/w3m_service/w3m_service.dart @@ -117,7 +117,9 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { ); } if (metadata == null) { - throw ArgumentError('Metada is required when using projectId.'); + throw ArgumentError( + 'Metada is required when using projectId.', + ); } } @@ -260,10 +262,10 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { defaultValue: '', )!; if (chainId.isNotEmpty && W3MChainPresets.chains.containsKey(chainId)) { - await selectChain(W3MChainPresets.chains[chainId]!, event: false); + await selectChain(W3MChainPresets.chains[chainId]!, logEvent: false); } else { final chainId = _currentSession!.chainId; - await selectChain(W3MChainPresets.chains[chainId]!, event: false); + await selectChain(W3MChainPresets.chains[chainId]!, logEvent: false); } } } @@ -272,7 +274,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { Future selectChain( W3MChainInfo? chainInfo, { bool switchChain = false, - bool event = true, + bool logEvent = true, }) async { _checkInitialized(); @@ -299,10 +301,10 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { await launchConnectedWallet(); } } else { - _setEthChain(chainInfo, event: event); + _setEthChain(chainInfo, logEvent: logEvent); } } else { - _setEthChain(chainInfo, event: event); + _setEthChain(chainInfo, logEvent: logEvent); } } @@ -341,7 +343,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { return _currentSession!.getApprovedEvents(); } - void _setEthChain(W3MChainInfo chainInfo, {bool event = false}) async { + void _setEthChain(W3MChainInfo chainInfo, {bool logEvent = false}) async { W3MLoggerUtil.logger.t('[$runtimeType] set chain ${chainInfo.namespace}'); _currentSelectedChain = chainInfo; @@ -351,7 +353,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { StringConstants.selectedChainId, _currentSelectedChain!.chainId, ); - if (event) { + if (_isConnected) { final network = chainInfo.chainId; analyticsService.instance.sendEvent(SwitchNetworkEvent(network: network)); } @@ -904,11 +906,9 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { int.parse(_currentSelectedChain!.chainId), ); _avatarUrl = blockchainId.avatar; - } catch (_) { - W3MLoggerUtil.logger - .e('[$runtimeType] Couldn\'t load avatar, will use default icon'); + } catch (e) { + W3MLoggerUtil.logger.e('[$runtimeType] $e'); } - W3MLoggerUtil.logger.t('[$runtimeType] account data laoded'); _notify(); } @@ -927,7 +927,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { ], ), ).then((_) { - _setEthChain(newChain, event: true); + _setEthChain(newChain, logEvent: true); }).catchError( (e, s) { // if request errors due to user rejection then set the previous chain @@ -944,7 +944,7 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { params: [newChain.toJson()], ), ).then((_) { - _setEthChain(newChain, event: true); + _setEthChain(newChain, logEvent: true); }).catchError((_) { _setEthChain(_currentSelectedChain!); }); @@ -1124,9 +1124,9 @@ extension _W3MServiceExtension on W3MService { W3MLoggerUtil.logger.t('[$runtimeType] onSessionConnect: $args'); if (args != null) { if (_selectedWallet == null) { - final walletName = args.session.peer.metadata.name; + // final walletName = args.session.peer.metadata.name; analyticsService.instance.sendEvent(ConnectSuccessEvent( - name: walletName, + name: 'WalletConnect', method: AnalyticsPlatform.qrcode, )); await storageService.instance.clearKey( diff --git a/lib/widgets/miscellaneous/all_wallets_header.dart b/lib/widgets/miscellaneous/all_wallets_header.dart index 4d39af00..c42cd46f 100644 --- a/lib/widgets/miscellaneous/all_wallets_header.dart +++ b/lib/widgets/miscellaneous/all_wallets_header.dart @@ -39,7 +39,7 @@ class AllWalletsHeader extends StatelessWidget { widgetStack.instance.push( const QRCodePage(), event: SelectWalletEvent( - name: 'Unknown', + name: 'WalletConnect', platform: AnalyticsPlatform.qrcode, ), ); diff --git a/lib/widgets/w3m_network_select_button.dart b/lib/widgets/w3m_network_select_button.dart index d6f76cb5..a77d048b 100644 --- a/lib/widgets/w3m_network_select_button.dart +++ b/lib/widgets/w3m_network_select_button.dart @@ -35,8 +35,8 @@ class _W3MNetworkSelectButtonState extends State { @override void dispose() { - super.dispose(); widget.service.removeListener(_onServiceUpdate); + super.dispose(); } @override diff --git a/test/mock_classes.mocks.dart b/test/mock_classes.mocks.dart index 0cd3b261..52a1250a 100644 --- a/test/mock_classes.mocks.dart +++ b/test/mock_classes.mocks.dart @@ -647,7 +647,7 @@ class MockW3MService extends _i1.Mock implements _i3.W3MService { _i14.Future selectChain( _i3.W3MChainInfo? chainInfo, { bool? switchChain = false, - bool? event = true, + bool? logEvent = true, }) => (super.noSuchMethod( Invocation.method( @@ -655,7 +655,7 @@ class MockW3MService extends _i1.Mock implements _i3.W3MService { [chainInfo], { #switchChain: switchChain, - #event: event, + #logEvent: logEvent, }, ), returnValue: _i14.Future.value(), From a4bd51769631e057fd3d00f51d9005ace7e8afeb Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Wed, 6 Mar 2024 18:11:56 +0100 Subject: [PATCH 05/10] minor change --- .../explorer_service/explorer_service.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/services/explorer_service/explorer_service.dart b/lib/services/explorer_service/explorer_service.dart index cdfcfb15..6eae95b8 100644 --- a/lib/services/explorer_service/explorer_service.dart +++ b/lib/services/explorer_service/explorer_service.dart @@ -22,8 +22,7 @@ import 'package:web3modal_flutter/web3modal_flutter.dart'; const int _defaultEntriesCount = 48; class ExplorerService implements IExplorerService { - // TODO fix this with coreUtils.instance.getApiUrl() - String _apiUrl = 'https://api.web3modal.com'; + String? _apiUrl; final http.Client _client; final String _referer; @@ -196,10 +195,11 @@ class ExplorerService implements IExplorerService { Future> _fetchNativeAppData() async { try { + final apiUrl = await coreUtils.instance.getApiUrl(); final headers = coreUtils.instance.getAPIHeaders(projectId, _referer); final uri = Platform.isIOS - ? Uri.parse('$_apiUrl/getIosData') - : Uri.parse('$_apiUrl/getAndroidData'); + ? Uri.parse('$apiUrl/getIosData') + : Uri.parse('$apiUrl/getAndroidData'); final response = await _client.get(uri, headers: headers); final apiResponse = ApiResponse.fromJson( jsonDecode(response.body), @@ -266,8 +266,9 @@ class ExplorerService implements IExplorerService { }) async { final p = params?.toJson() ?? {}; try { + final apiUrl = await coreUtils.instance.getApiUrl(); final headers = coreUtils.instance.getAPIHeaders(projectId, _referer); - final uri = Uri.parse('$_apiUrl/getWallets').replace(queryParameters: p); + final uri = Uri.parse('$apiUrl/getWallets').replace(queryParameters: p); final response = await _client.get(uri, headers: headers); final apiResponse = ApiResponse.fromJson( jsonDecode(response.body), @@ -419,7 +420,8 @@ class ExplorerService implements IExplorerService { if (imageId.startsWith('http')) { return imageId; } - return '$_apiUrl/getWalletImage/$imageId'; + final apiUrl = _apiUrl ?? 'https://api.web3modal.com'; + return '$apiUrl/getWalletImage/$imageId'; } @override @@ -427,7 +429,8 @@ class ExplorerService implements IExplorerService { if (imageId.startsWith('http')) { return imageId; } - return '$_apiUrl/public/getAssetImage/$imageId'; + final apiUrl = _apiUrl ?? 'https://api.web3modal.com'; + return '$apiUrl/public/getAssetImage/$imageId'; } @override From 68d9d7d78f2074eaed1fc5794408c4d5c5908dc4 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Wed, 6 Mar 2024 18:20:20 +0100 Subject: [PATCH 06/10] minor change --- example/android/gradle.properties | 4 ++-- example/ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ example/ios/Runner/Info.plist | 4 ++-- example/pubspec.lock | 2 +- example/pubspec.yaml | 2 +- lib/version.dart | 2 +- pubspec.yaml | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 83a7b658..8b2961e2 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,5 +1,5 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true -versionName=3.1.1 -versionCode=33 +versionName=3.1.2 +versionCode=37 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 9641d294..3d7ecacc 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -470,7 +470,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 33; + CURRENT_PROJECT_VERSION = 37; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; @@ -496,7 +496,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 33; + CURRENT_PROJECT_VERSION = 37; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -514,7 +514,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 33; + CURRENT_PROJECT_VERSION = 37; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -530,7 +530,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 33; + CURRENT_PROJECT_VERSION = 37; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -655,7 +655,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 33; + CURRENT_PROJECT_VERSION = 37; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; @@ -686,7 +686,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 33; + CURRENT_PROJECT_VERSION = 37; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 6ef49a37..553b7291 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 3.1.1 + 3.1.2 CFBundleSignature ???? CFBundleURLTypes @@ -36,7 +36,7 @@ CFBundleVersion - 33 + 37 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/example/pubspec.lock b/example/pubspec.lock index e17dc9e8..c1ef3d62 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1115,7 +1115,7 @@ packages: path: ".." relative: true source: path - version: "3.1.1" + version: "3.1.2" web_socket_channel: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1b7788f9..c58a5fe1 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,7 +3,7 @@ description: A dApp showing how to use WalletConnect v2 with Flutter publish_to: "none" -version: 3.1.1 +version: 3.1.2 environment: sdk: ">=3.0.1 <4.0.0" diff --git a/lib/version.dart b/lib/version.dart index 3c880f01..50e65e2a 100644 --- a/lib/version.dart +++ b/lib/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '3.1.1'; +const packageVersion = '3.1.2'; diff --git a/pubspec.yaml b/pubspec.yaml index 5f7efea1..1cff40ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: web3modal_flutter description: "WalletConnect Web3Modal: Simple, intuitive wallet login. With this drop-in UI SDK, enable any wallet's users to seamlessly log in to your app and enjoy a unified experience" -version: 3.1.1 +version: 3.1.2 repository: https://github.com/WalletConnect/Web3ModalFlutter environment: From f05e59d426002619aaae7e3c978ca70734bbf0c0 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Fri, 8 Mar 2024 10:52:20 +0100 Subject: [PATCH 07/10] merge with master and fix conflicts --- example/lib/home_page.dart | 4 ++-- lib/services/w3m_service/w3m_service.dart | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index da49b0a9..cbbd8ed8 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -91,7 +91,7 @@ class _MyHomePageState extends State { _w3mService.onSessionExpireEvent.subscribe(_onSessionExpired); _w3mService.onSessionUpdateEvent.subscribe(_onSessionUpdate); _w3mService.onSessionConnectEvent.subscribe(_onSessionConnect); - _w3mService.onSessionDeleteEvent.subscribe(_onSessionDelete); + // _w3mService.onSessionDeleteEvent.subscribe(_onSessionDelete); _w3mService.onCoinbaseConnect.subscribe(_onCoinbaseConnect); _w3mService.onSessionEventEvent.subscribe(_onSessionEvent); // @@ -115,7 +115,7 @@ class _MyHomePageState extends State { _w3mService.onSessionExpireEvent.unsubscribe(_onSessionExpired); _w3mService.onSessionUpdateEvent.unsubscribe(_onSessionUpdate); _w3mService.onSessionConnectEvent.unsubscribe(_onSessionConnect); - _w3mService.onSessionDeleteEvent.unsubscribe(_onSessionDelete); + // _w3mService.onSessionDeleteEvent.unsubscribe(_onSessionDelete); _w3mService.onCoinbaseConnect.unsubscribe(_onCoinbaseConnect); _w3mService.onSessionEventEvent.unsubscribe(_onSessionEvent); // diff --git a/lib/services/w3m_service/w3m_service.dart b/lib/services/w3m_service/w3m_service.dart index bd171d1b..fa00f5f6 100644 --- a/lib/services/w3m_service/w3m_service.dart +++ b/lib/services/w3m_service/w3m_service.dart @@ -20,7 +20,6 @@ import 'package:web3modal_flutter/services/explorer_service/models/redirect.dart import 'package:web3modal_flutter/services/ledger_service/ledger_service_singleton.dart'; import 'package:web3modal_flutter/services/logger_service/logger_service.dart'; import 'package:web3modal_flutter/services/logger_service/logger_service_singleton.dart'; -import 'package:web3modal_flutter/services/w3m_service/models/w3m_session.dart'; import 'package:web3modal_flutter/utils/core/core_utils_singleton.dart'; import 'package:web3modal_flutter/utils/platform/i_platform_utils.dart'; import 'package:web3modal_flutter/utils/url/launch_url_exception.dart'; From faefe538bfe9c56a931640872392a2c9d5d8092c Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Fri, 8 Mar 2024 11:20:21 +0100 Subject: [PATCH 08/10] minor change --- example/lib/home_page.dart | 29 +------------------ lib/pages/qr_code_page.dart | 4 +-- .../{w3m_qr_code.dart => qr_code_view.dart} | 4 +-- 3 files changed, 5 insertions(+), 32 deletions(-) rename lib/widgets/{w3m_qr_code.dart => qr_code_view.dart} (97%) diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index cbbd8ed8..6fc67139 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:walletconnect_flutter_dapp/widgets/logger_widget.dart'; -import 'package:web3modal_flutter/services/coinbase_service/models/coinbase_events.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; +import 'package:walletconnect_flutter_dapp/widgets/logger_widget.dart'; import 'package:walletconnect_flutter_dapp/widgets/session_widget.dart'; import 'package:walletconnect_flutter_dapp/utils/dart_defines.dart'; import 'package:walletconnect_flutter_dapp/utils/string_constants.dart'; @@ -86,18 +85,10 @@ class _MyHomePageState extends State { _w3mService.onModalDisconnect.subscribe(_onModalDisconnect); _w3mService.onModalError.subscribe(_onModalError); // - // _w3mService.onSessionConnectEvent.subscribe(_onSessionConnect); - // _w3mService.onSessionDeleteEvent.subscribe(_onSessionDelete); _w3mService.onSessionExpireEvent.subscribe(_onSessionExpired); _w3mService.onSessionUpdateEvent.subscribe(_onSessionUpdate); - _w3mService.onSessionConnectEvent.subscribe(_onSessionConnect); - // _w3mService.onSessionDeleteEvent.subscribe(_onSessionDelete); - _w3mService.onCoinbaseConnect.subscribe(_onCoinbaseConnect); _w3mService.onSessionEventEvent.subscribe(_onSessionEvent); // - // _w3mService.onCoinbaseConnect.subscribe((args) {}); - // _w3mService.onCoinbaseError.subscribe((args) {}); - // _w3mService.onCoinbaseSessionUpdate.subscribe((args) {}); // await _w3mService.init(); } @@ -110,25 +101,13 @@ class _MyHomePageState extends State { _w3mService.onModalDisconnect.unsubscribe(_onModalDisconnect); _w3mService.onModalError.unsubscribe(_onModalError); // - // _w3mService.onSessionConnectEvent.unsubscribe(_onSessionConnect); - // _w3mService.onSessionDeleteEvent.unsubscribe(_onSessionDelete); _w3mService.onSessionExpireEvent.unsubscribe(_onSessionExpired); _w3mService.onSessionUpdateEvent.unsubscribe(_onSessionUpdate); - _w3mService.onSessionConnectEvent.unsubscribe(_onSessionConnect); - // _w3mService.onSessionDeleteEvent.unsubscribe(_onSessionDelete); - _w3mService.onCoinbaseConnect.unsubscribe(_onCoinbaseConnect); _w3mService.onSessionEventEvent.unsubscribe(_onSessionEvent); // - // _w3mService.onCoinbaseConnect.unsubscribe((args) {}); - // _w3mService.onCoinbaseError.unsubscribe((args) {}); - // _w3mService.onCoinbaseSessionUpdate.unsubscribe((args) {}); super.dispose(); } - void _onCoinbaseConnect(CoinbaseConnectEvent? event) { - debugPrint('[$runtimeType] coinbase connect ${event?.data}'); - } - void _serviceListener() { setState(() {}); } @@ -143,12 +122,6 @@ class _MyHomePageState extends State { debugPrint('[$runtimeType] modal disconnect ${event?.toString()}'); } - void _onSessionConnect(SessionConnect? args) { - debugPrint('[$runtimeType] _onSessionConnect $args'); - debugPrint( - '[$runtimeType] _onSessionConnect ${_w3mService.session?.toJson()}'); - } - void _onModalError(ModalError? event) { debugPrint('[$runtimeType] _onModalError ${event?.toString()}'); // When user connected to Coinbase Wallet but Coinbase Wallet does not have a session anymore diff --git a/lib/pages/qr_code_page.dart b/lib/pages/qr_code_page.dart index c980dd42..9aabf993 100644 --- a/lib/pages/qr_code_page.dart +++ b/lib/pages/qr_code_page.dart @@ -6,7 +6,7 @@ import 'package:web3modal_flutter/services/w3m_service/i_w3m_service.dart'; import 'package:web3modal_flutter/theme/constants.dart'; import 'package:web3modal_flutter/web3modal_flutter.dart'; import 'package:web3modal_flutter/widgets/buttons/simple_icon_button.dart'; -import 'package:web3modal_flutter/widgets/w3m_qr_code.dart'; +import 'package:web3modal_flutter/widgets/qr_code_view.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; import 'package:web3modal_flutter/widgets/web3modal_provider.dart'; import 'package:web3modal_flutter/widgets/navigation/navbar.dart'; @@ -40,7 +40,7 @@ class _QRCodePageState extends State { } void _buildWidget() => setState(() { - _qrQodeWidget = QRCodeWidget( + _qrQodeWidget = QRCodeView( uri: _service!.wcUri!, logoPath: 'assets/png/logo_wc.png', ); diff --git a/lib/widgets/w3m_qr_code.dart b/lib/widgets/qr_code_view.dart similarity index 97% rename from lib/widgets/w3m_qr_code.dart rename to lib/widgets/qr_code_view.dart index d0060b28..21a5a170 100644 --- a/lib/widgets/w3m_qr_code.dart +++ b/lib/widgets/qr_code_view.dart @@ -9,8 +9,8 @@ import 'package:web3modal_flutter/widgets/miscellaneous/content_loading.dart'; import 'package:web3modal_flutter/widgets/miscellaneous/responsive_container.dart'; // TODO This file should be called qr_code_view.dart -class QRCodeWidget extends StatelessWidget { - const QRCodeWidget({ +class QRCodeView extends StatelessWidget { + const QRCodeView({ super.key, required this.uri, this.logoPath = '', From 5ddf8794f342800afe41669ec27ce6c030ff1138 Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Mon, 11 Mar 2024 13:22:41 +0100 Subject: [PATCH 09/10] version up --- .github/workflows/build-android-debug.yml | 2 +- .github/workflows/build-android-internal.yml | 2 +- .github/workflows/build-android.yml | 2 +- .github/workflows/build-ios-debug.yml | 2 +- .github/workflows/build-ios-internal.yml | 2 +- .github/workflows/build-ios.yml | 2 +- .github/workflows/publish-internal.yml | 2 +- .github/workflows/publish.yml | 2 +- CHANGELOG.md | 4 ++++ example/android/gradle.properties | 4 ++-- example/ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ example/ios/Runner/Info.plist | 4 ++-- example/pubspec.lock | 2 +- example/pubspec.yaml | 2 +- lib/version.dart | 2 +- pubspec.yaml | 2 +- 16 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build-android-debug.yml b/.github/workflows/build-android-debug.yml index 51b39f74..9342587b 100644 --- a/.github/workflows/build-android-debug.yml +++ b/.github/workflows/build-android-debug.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+(-alpha)+[0-9]{2}' + - 'v[0-9]+.[0-9]+.[0-9]+(-alpha)+[0-9]*' jobs: build_with_signing: diff --git a/.github/workflows/build-android-internal.yml b/.github/workflows/build-android-internal.yml index 69917c9e..4a2cfd6e 100644 --- a/.github/workflows/build-android-internal.yml +++ b/.github/workflows/build-android-internal.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+(-beta)+[0-9]{2}' + - 'v[0-9]+.[0-9]+.[0-9]+(-beta)+[0-9]*' jobs: build_with_signing: diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index 8220b9f9..a75a5796 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: tags: - - 'v((([0-9]+)\.([0-9]+)\.([0-9]+)?)?)$' + - 'v[0-9]+.[0-9]+.[0-9]+*' jobs: build_with_signing: diff --git a/.github/workflows/build-ios-debug.yml b/.github/workflows/build-ios-debug.yml index af60c466..a6951517 100644 --- a/.github/workflows/build-ios-debug.yml +++ b/.github/workflows/build-ios-debug.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+(-alpha)+[0-9]{2}' + - 'v[0-9]+.[0-9]+.[0-9]+(-alpha)+[0-9]*' jobs: build_with_signing: diff --git a/.github/workflows/build-ios-internal.yml b/.github/workflows/build-ios-internal.yml index 8889c255..73f29fca 100644 --- a/.github/workflows/build-ios-internal.yml +++ b/.github/workflows/build-ios-internal.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+(-beta)+[0-9]{2}' + - 'v[0-9]+.[0-9]+.[0-9]+(-beta)+[0-9]*' jobs: build_with_signing: diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml index 2113cc77..25512535 100644 --- a/.github/workflows/build-ios.yml +++ b/.github/workflows/build-ios.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: tags: - - 'v((([0-9]+)\.([0-9]+)\.([0-9]+)?)?)$' + - 'v[0-9]+.[0-9]+.[0-9]+*' jobs: build_with_signing: diff --git a/.github/workflows/publish-internal.yml b/.github/workflows/publish-internal.yml index e2c2fe32..2d6663b8 100644 --- a/.github/workflows/publish-internal.yml +++ b/.github/workflows/publish-internal.yml @@ -6,7 +6,7 @@ on: # Always run this on master branch push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+(-beta)+[0-9]{2}' + - 'v[0-9]+.[0-9]+.[0-9]+(-beta)+[0-9]*' jobs: publish: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d8deab48..83cd23b7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -6,7 +6,7 @@ on: # Always run this on a release_vX.X.X branch push: tags: - - 'v((([0-9]+)\.([0-9]+)\.([0-9]+)?)?)$' + - 'v[0-9]+.[0-9]+.[0-9]+*' jobs: publish: diff --git a/CHANGELOG.md b/CHANGELOG.md index 90e98a77..fedf5495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.1.3-beta01 + +- Analytics API support + ## 3.1.2 - Bug fixes for Coinbase Wallet integration diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 8b2961e2..d5f66c0f 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,5 +1,5 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true -versionName=3.1.2 -versionCode=37 +versionName=3.1.3 +versionCode=38 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 3d7ecacc..de4ead65 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -470,7 +470,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; @@ -496,7 +496,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -514,7 +514,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -530,7 +530,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.web3modal.flutterExample.RunnerTests; @@ -655,7 +655,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; @@ -686,7 +686,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_BITCODE = NO; diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 553b7291..90f82e3d 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 3.1.2 + 3.1.3 CFBundleSignature ???? CFBundleURLTypes @@ -36,7 +36,7 @@ CFBundleVersion - 37 + 38 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/example/pubspec.lock b/example/pubspec.lock index c1ef3d62..9bf538bf 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1115,7 +1115,7 @@ packages: path: ".." relative: true source: path - version: "3.1.2" + version: "3.1.3-beta01" web_socket_channel: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c58a5fe1..83e3155a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,7 +3,7 @@ description: A dApp showing how to use WalletConnect v2 with Flutter publish_to: "none" -version: 3.1.2 +version: 3.1.3 environment: sdk: ">=3.0.1 <4.0.0" diff --git a/lib/version.dart b/lib/version.dart index 50e65e2a..cc991587 100644 --- a/lib/version.dart +++ b/lib/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '3.1.2'; +const packageVersion = '3.1.3-beta01'; diff --git a/pubspec.yaml b/pubspec.yaml index 1cff40ad..2d3a3070 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: web3modal_flutter description: "WalletConnect Web3Modal: Simple, intuitive wallet login. With this drop-in UI SDK, enable any wallet's users to seamlessly log in to your app and enjoy a unified experience" -version: 3.1.2 +version: 3.1.3-beta01 repository: https://github.com/WalletConnect/Web3ModalFlutter environment: From e7ac61fd38b8de8c5d2ca5023c53d515ee0a04ee Mon Sep 17 00:00:00 2001 From: Alfreedom <00tango.bromine@icloud.com> Date: Tue, 12 Mar 2024 09:47:30 +0100 Subject: [PATCH 10/10] updated dependencies and minor changes --- example/lib/home_page.dart | 25 ++++---- example/lib/main.dart | 12 ++-- example/lib/widgets/logger_widget.dart | 63 ++++++++++++------- lib/models/w3m_chain_info.freezed.dart | 6 +- lib/models/w3m_wallet_info.freezed.dart | 4 +- .../blockchain_identity.freezed.dart | 4 +- lib/services/w3m_service/w3m_service.dart | 6 +- lib/theme/w3m_colors.freezed.dart | 4 +- lib/theme/w3m_radiuses.freezed.dart | 4 +- lib/theme/w3m_text_styles.freezed.dart | 4 +- lib/theme/w3m_theme_data.freezed.dart | 4 +- pubspec.lock | 4 +- pubspec.yaml | 4 +- 13 files changed, 83 insertions(+), 61 deletions(-) diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index 6fc67139..72fe9385 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -10,11 +10,11 @@ import 'package:walletconnect_flutter_dapp/utils/string_constants.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({ super.key, - required this.swapTheme, - required this.changeTheme, + required this.toggleBrightness, + required this.toggleTheme, }); - final VoidCallback swapTheme; - final VoidCallback changeTheme; + final VoidCallback toggleBrightness; + final VoidCallback toggleTheme; @override State createState() => _MyHomePageState(); @@ -22,20 +22,19 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final overlay = OverlayController(const Duration(milliseconds: 200)); - late W3MService _w3mService; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { - _showOverlay(); + _toggleOverlay(); }); _initializeService(); } - void _showOverlay() { - overlay.insert(context); + void _toggleOverlay() { + overlay.show(context); } void _initializeService() async { @@ -156,22 +155,20 @@ class _MyHomePageState extends State { foregroundColor: Web3ModalTheme.colorsOf(context).foreground100, actions: [ IconButton( - icon: const Icon(Icons.logo_dev_sharp), - onPressed: () { - overlay.toggle(context); - }, + icon: const Icon(Icons.logo_dev_rounded), + onPressed: _toggleOverlay, ), IconButton( icon: isCustom ? const Icon(Icons.yard) : const Icon(Icons.yard_outlined), - onPressed: widget.changeTheme, + onPressed: widget.toggleTheme, ), IconButton( icon: Web3ModalTheme.maybeOf(context)?.isDarkMode ?? false ? const Icon(Icons.light_mode_outlined) : const Icon(Icons.dark_mode_outlined), - onPressed: widget.swapTheme, + onPressed: widget.toggleBrightness, ), ], ), diff --git a/example/lib/main.dart b/example/lib/main.dart index 1a40259f..9aa4c72a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,19 +59,19 @@ class _MyAppState extends State with WidgetsBindingObserver { debugShowCheckedModeBanner: false, title: StringConstants.w3mPageTitleV3, home: MyHomePage( - swapTheme: () => _swapTheme(), - changeTheme: () => _changeTheme(), + toggleTheme: () => _toggleTheme(), + toggleBrightness: () => _toggleBrightness(), ), ), ); } - void _swapTheme() => setState(() { - _isDarkMode = !_isDarkMode; + void _toggleTheme() => setState(() { + _themeData = (_themeData == null) ? _customTheme : null; }); - void _changeTheme() => setState(() { - _themeData = (_themeData == null) ? _customTheme : null; + void _toggleBrightness() => setState(() { + _isDarkMode = !_isDarkMode; }); Web3ModalThemeData get _customTheme => Web3ModalThemeData( diff --git a/example/lib/widgets/logger_widget.dart b/example/lib/widgets/logger_widget.dart index 520a1811..a6930e31 100644 --- a/example/lib/widgets/logger_widget.dart +++ b/example/lib/widgets/logger_widget.dart @@ -19,15 +19,21 @@ class _DraggableCardState extends State { @override void initState() { super.initState(); - analyticsService.instance.events.listen((event) { - _logs.add( - Text( - '=> $event', - style: const TextStyle(color: Colors.white, fontSize: 12.0), + analyticsService.instance.events.listen(_eventsListener); + } + + void _eventsListener(event) { + if (!mounted) return; + _logs.add( + Text( + '=> $event', + style: const TextStyle( + color: Colors.white, + fontSize: 12.0, ), - ); - setState(() {}); - }); + ), + ); + setState(() {}); } @override @@ -67,7 +73,7 @@ class _DraggableCardState extends State { ); }, onPanEnd: (_) { - // overlayController.alignToScreenEdge(); + // widget.overlayController.alignToScreenEdge(); }, child: Container( width: 25.0, @@ -89,22 +95,18 @@ class _DraggableCardState extends State { class OverlayController extends AnimatedOverlay { OverlayController(super.duration); - OverlayEntry? _entry; - - Alignment align = Alignment.centerRight; - + final _defaultAlign = const Alignment(0.0, -1.8); + Alignment align = const Alignment(0.0, -1.8); Animation? alignAnimation; OverlayEntry createAlignOverlay(Widget child) { return OverlayEntry( maintainState: true, - builder: (_) { - return CustomAlign( - animation: alignAnimation ?? AlwaysStoppedAnimation(align), - child: child, - ); - }, + builder: (_) => CustomAlign( + animation: alignAnimation ?? AlwaysStoppedAnimation(align), + child: child, + ), ); } @@ -113,9 +115,9 @@ class OverlayController extends AnimatedOverlay { Overlay.of(context).insert(_entry!); } - void toggle(BuildContext context) { + void show(BuildContext context) { if (_entry != null) { - remove(); + toggle(); } else { insert(context); } @@ -145,6 +147,25 @@ class OverlayController extends AnimatedOverlay { controller.forward(); _entry?.markNeedsBuild(); } + + void toggle() { + if (align == Alignment.center) { + alignAnimation = createAnimation( + begin: align, + end: _defaultAlign, + ); + align = _defaultAlign; + } else { + alignAnimation = createAnimation( + begin: align, + end: Alignment.center, + ); + align = Alignment.center; + } + + controller.forward(); + _entry?.markNeedsBuild(); + } } abstract class AnimatedOverlay extends TickerProvider { diff --git a/lib/models/w3m_chain_info.freezed.dart b/lib/models/w3m_chain_info.freezed.dart index 9b2fce76..7b72b6cc 100644 --- a/lib/models/w3m_chain_info.freezed.dart +++ b/lib/models/w3m_chain_info.freezed.dart @@ -12,7 +12,7 @@ part of 'w3m_chain_info.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$W3MChainInfo { @@ -219,7 +219,7 @@ class _$W3MChainInfoImpl implements _W3MChainInfo { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$W3MChainInfoImpl && @@ -380,7 +380,7 @@ class _$W3MBlockExplorerImpl implements _W3MBlockExplorer { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$W3MBlockExplorerImpl && diff --git a/lib/models/w3m_wallet_info.freezed.dart b/lib/models/w3m_wallet_info.freezed.dart index 8cab6669..9089b705 100644 --- a/lib/models/w3m_wallet_info.freezed.dart +++ b/lib/models/w3m_wallet_info.freezed.dart @@ -12,7 +12,7 @@ part of 'w3m_wallet_info.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); W3MWalletInfo _$W3MWalletInfoFromJson(Map json) { return _W3MWalletInfo.fromJson(json); @@ -138,7 +138,7 @@ class _$W3MWalletInfoImpl implements _W3MWalletInfo { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$W3MWalletInfoImpl && diff --git a/lib/services/blockchain_api_service/blockchain_identity.freezed.dart b/lib/services/blockchain_api_service/blockchain_identity.freezed.dart index 8d15e42a..1c372f97 100644 --- a/lib/services/blockchain_api_service/blockchain_identity.freezed.dart +++ b/lib/services/blockchain_api_service/blockchain_identity.freezed.dart @@ -12,7 +12,7 @@ part of 'blockchain_identity.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); BlockchainIdentity _$BlockchainIdentityFromJson(Map json) { return _BlockchainIdentity.fromJson(json); @@ -124,7 +124,7 @@ class _$BlockchainIdentityImpl implements _BlockchainIdentity { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$BlockchainIdentityImpl && diff --git a/lib/services/w3m_service/w3m_service.dart b/lib/services/w3m_service/w3m_service.dart index fa00f5f6..f84b40f7 100644 --- a/lib/services/w3m_service/w3m_service.dart +++ b/lib/services/w3m_service/w3m_service.dart @@ -789,9 +789,13 @@ class W3MService with ChangeNotifier, CoinbaseService implements IW3MService { } @override - void dispose() { + void dispose() async { if (_status == W3MServiceStatus.initialized) { + await disconnect(); + await expirePreviousInactivePairings(); _unregisterListeners(); + _status = W3MServiceStatus.idle; + loggerService.instance.d('[$runtimeType] dispose'); } super.dispose(); } diff --git a/lib/theme/w3m_colors.freezed.dart b/lib/theme/w3m_colors.freezed.dart index de436543..1dcf9d03 100644 --- a/lib/theme/w3m_colors.freezed.dart +++ b/lib/theme/w3m_colors.freezed.dart @@ -12,7 +12,7 @@ part of 'w3m_colors.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$Web3ModalColors { @@ -606,7 +606,7 @@ class _$Web3ModalColorsImpl implements _Web3ModalColors { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$Web3ModalColorsImpl && diff --git a/lib/theme/w3m_radiuses.freezed.dart b/lib/theme/w3m_radiuses.freezed.dart index 4a3ec825..05d2c082 100644 --- a/lib/theme/w3m_radiuses.freezed.dart +++ b/lib/theme/w3m_radiuses.freezed.dart @@ -12,7 +12,7 @@ part of 'w3m_radiuses.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$Web3ModalRadiuses { @@ -226,7 +226,7 @@ class _$Web3ModalRadiusesImpl implements _Web3ModalRadiuses { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$Web3ModalRadiusesImpl && diff --git a/lib/theme/w3m_text_styles.freezed.dart b/lib/theme/w3m_text_styles.freezed.dart index ba3dae5f..f436b7a3 100644 --- a/lib/theme/w3m_text_styles.freezed.dart +++ b/lib/theme/w3m_text_styles.freezed.dart @@ -12,7 +12,7 @@ part of 'w3m_text_styles.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$Web3ModalTextStyles { @@ -378,7 +378,7 @@ class _$Web3ModalTextStylesImpl implements _Web3ModalTextStyles { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$Web3ModalTextStylesImpl && diff --git a/lib/theme/w3m_theme_data.freezed.dart b/lib/theme/w3m_theme_data.freezed.dart index 96df6db7..22243e91 100644 --- a/lib/theme/w3m_theme_data.freezed.dart +++ b/lib/theme/w3m_theme_data.freezed.dart @@ -12,7 +12,7 @@ part of 'w3m_theme_data.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$Web3ModalThemeData { @@ -204,7 +204,7 @@ class _$Web3ModalThemeDataImpl implements _Web3ModalThemeData { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$Web3ModalThemeDataImpl && diff --git a/pubspec.lock b/pubspec.lock index 41af2e18..3c3cf8a6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -372,10 +372,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "21bf2825311de65501d22e563e3d7605dff57fb5e6da982db785ae5372ff018a" + sha256: "57247f692f35f068cae297549a46a9a097100685c6780fe67177503eea5ed4e5" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.7" freezed_annotation: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2d3a3070..8235154d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: sdk: flutter flutter_svg: ^2.0.9 flutter_timezone: ^1.0.8 - freezed_annotation: ^2.2.0 + freezed_annotation: ^2.4.1 http: ^1.1.2 json_annotation: ^4.8.1 qr_flutter_wc: ^0.0.3 @@ -31,7 +31,7 @@ dev_dependencies: build_version: ^2.1.1 flutter_test: sdk: flutter - freezed: ^2.4.5 + freezed: ^2.4.7 json_serializable: ^6.7.0 lints: ^3.0.0 mockito: ^5.4.3