From a500e0b3dac20d48e5cddaf6d42b70011e96643b Mon Sep 17 00:00:00 2001 From: Kieran Date: Mon, 19 May 2025 12:42:35 +0100 Subject: [PATCH] feat: share stream closes #33 --- lib/pages/stream.dart | 14 ++++--- lib/widgets/button.dart | 20 ++++++--- lib/widgets/stream_info.dart | 42 +++++++++++++++---- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 16 +++++++ pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 ++ windows/flutter/generated_plugins.cmake | 1 + 8 files changed, 78 insertions(+), 21 deletions(-) diff --git a/lib/pages/stream.dart b/lib/pages/stream.dart index 2c13e71..502cc49 100644 --- a/lib/pages/stream.dart +++ b/lib/pages/stream.dart @@ -34,10 +34,11 @@ class _StreamPage extends State with RouteAware { final router = GoRouter.of(context); final currentConfiguration = router.routerDelegate.currentConfiguration; final match = currentConfiguration.matches.lastOrNull; - final lastMatch = match is ShellRouteMatch ? match.matches.lastOrNull : match; + final lastMatch = + match is ShellRouteMatch ? match.matches.lastOrNull : match; return lastMatch != null && (lastMatch.route is GoRoute && - (lastMatch.route as GoRoute).path == StreamPage.path); + (lastMatch.route as GoRoute).path == StreamPage.path); } @override @@ -122,10 +123,11 @@ class _StreamPage extends State with RouteAware { ? ProxyImg(url: stream.info.image) : Container(decoration: BoxDecoration(color: LAYER_1)), ), - Text( - stream.info.title ?? "", - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18), - ), + if (stream.info.title?.isNotEmpty ?? false) + Text( + stream.info.title!, + style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18), + ), ProfileWidget.pubkey( stream.info.host, children: [ diff --git a/lib/widgets/button.dart b/lib/widgets/button.dart index 07543ca..71c5e1b 100644 --- a/lib/widgets/button.dart +++ b/lib/widgets/button.dart @@ -27,14 +27,22 @@ class BasicButton extends StatelessWidget { void Function()? onTap, double? fontSize, bool? disabled, + Icon? icon, }) { return BasicButton( - Text( - text, - style: TextStyle( - color: Color.fromARGB(255, 255, 255, 255), - fontSize: fontSize, - fontWeight: FontWeight.bold, + Text.rich( + TextSpan( + style: TextStyle( + color: Color.fromARGB(255, 255, 255, 255), + fontSize: fontSize, + fontWeight: FontWeight.bold, + ), + children: [ + if (icon != null) + WidgetSpan(child: icon, alignment: PlaceholderAlignment.middle), + if (icon != null) TextSpan(text: " "), + TextSpan(text: text), + ], ), ), disabled: disabled, diff --git a/lib/widgets/stream_info.dart b/lib/widgets/stream_info.dart index 74cb6a2..36f66c3 100644 --- a/lib/widgets/stream_info.dart +++ b/lib/widgets/stream_info.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; +import 'package:share_plus/share_plus.dart'; +import 'package:zap_stream_flutter/main.dart'; import 'package:zap_stream_flutter/theme.dart'; import 'package:zap_stream_flutter/utils.dart'; +import 'package:zap_stream_flutter/widgets/button.dart'; import 'package:zap_stream_flutter/widgets/button_follow.dart'; import 'package:zap_stream_flutter/widgets/game_info.dart'; import 'package:zap_stream_flutter/widgets/live_timer.dart'; @@ -18,6 +21,8 @@ class StreamInfoWidget extends StatelessWidget { @override Widget build(BuildContext context) { + final isMe = ndk.accounts.getPublicKey() == stream.info.host; + final startedDate = stream.info.starts != null ? DateTime.fromMillisecondsSinceEpoch(stream.info.starts! * 1000) @@ -29,16 +34,35 @@ class StreamInfoWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ ProfileWidget.pubkey(stream.info.host, linkToProfile: false), - FollowButton( - pubkey: stream.info.host, - onTap: () { - Navigator.pop(context); - }, - ), - Text( - stream.info.title ?? "", - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + Row( + spacing: 8, + children: [ + if (!isMe) + FollowButton( + pubkey: stream.info.host, + onTap: () { + Navigator.pop(context); + }, + ), + BasicButton.text( + "Share", + icon: Icon(Icons.share, size: 16), + onTap: () { + SharePlus.instance.share( + ShareParams( + title: stream.info.title, + uri: Uri.parse("https://zap.stream/${stream.link}"), + ), + ); + }, + ), + ], ), + if (stream.info.title?.isNotEmpty ?? false) + Text( + stream.info.title!, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), if (startedDate != null) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index f5b647f..bd939f2 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import flutter_secure_storage_macos import objectbox_flutter_libs import package_info_plus import path_provider_foundation +import share_plus import shared_preferences_foundation import sqflite_darwin import url_launcher_macos @@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ObjectboxFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "ObjectboxFlutterLibsPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/pubspec.lock b/pubspec.lock index fd316c8..40fec1b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -811,6 +811,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: b2961506569e28948d75ec346c28775bb111986bb69dc6a20754a457e3d97fa0 + url: "https://pub.dev" + source: hosted + version: "11.0.0" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "1032d392bc5d2095a77447a805aa3f804d2ae6a4d5eef5e6ebb3bd94c1bc19ef" + url: "https://pub.dev" + source: hosted + version: "6.0.0" shared_preferences: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d91eae8..1fe23d7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: bech32: ^0.2.2 intl: ^0.20.2 flutter_markdown_plus: ^1.0.3 + share_plus: ^11.0.0 dependency_overrides: ndk: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 90d6b41..13ad6c5 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { @@ -21,6 +22,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); ObjectboxFlutterLibsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ObjectboxFlutterLibsPlugin")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 39eaff0..78f5b22 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows flutter_secure_storage_windows objectbox_flutter_libs + share_plus url_launcher_windows )