diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2c92c16..4f61729 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -49,26 +49,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json
index 25a4d52..7c9194a 100644
--- a/assets/translations/en-US.json
+++ b/assets/translations/en-US.json
@@ -445,5 +445,8 @@
"postShare": "Share",
"postShareImage": "Share via Image",
"appInitializing": "Initializing",
- "poweredBy": "Powered by {}"
+ "poweredBy": "Powered by {}",
+ "shareIntent": "Share",
+ "shareIntentDescription": "What do you want to do with the content you are sharing?",
+ "shareIntentPostStory": "Post a Story"
}
diff --git a/assets/translations/zh-CN.json b/assets/translations/zh-CN.json
index c29a278..4b486c6 100644
--- a/assets/translations/zh-CN.json
+++ b/assets/translations/zh-CN.json
@@ -443,5 +443,8 @@
"postShare": "分享",
"postShareImage": "分享帖图",
"appInitializing": "正在初始化",
- "poweredBy": "由 {} 提供支持"
+ "poweredBy": "由 {} 提供支持",
+ "shareIntent": "分享",
+ "shareIntentDescription": "您想对您分享的内容做些什么?",
+ "shareIntentPostStory": "发布动态"
}
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 2197bc3..60489d0 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -592,7 +592,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
};
43B5CF57FD79BC21654EE037 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
diff --git a/ios/SolarShare/Info.plist b/ios/SolarShare/Info.plist
index b256dc6..97566e8 100644
--- a/ios/SolarShare/Info.plist
+++ b/ios/SolarShare/Info.plist
@@ -11,14 +11,14 @@
NSExtensionActivationSupportsText
- NSExtensionActivationSupportsWebURLWithMaxCount
- 1
- NSExtensionActivationSupportsImageWithMaxCount
- 100
- NSExtensionActivationSupportsMovieWithMaxCount
- 100
- NSExtensionActivationSupportsFileWithMaxCount
- 100
+ NSExtensionActivationSupportsWebURLWithMaxCount
+ 1
+ NSExtensionActivationSupportsImageWithMaxCount
+ 100
+ NSExtensionActivationSupportsMovieWithMaxCount
+ 100
+ NSExtensionActivationSupportsFileWithMaxCount
+ 100
NSExtension
@@ -32,5 +32,7 @@
NSExtensionPointIdentifier
com.apple.share-services
+ AppGroupId
+ group.solsynth.solian
diff --git a/lib/main.dart b/lib/main.dart
index f4d8184..bad11c0 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,5 +1,4 @@
import 'dart:async';
-import 'dart:developer';
import 'dart:io';
import 'package:bitsdojo_window/bitsdojo_window.dart';
@@ -12,9 +11,7 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:hive_flutter/hive_flutter.dart';
-import 'package:home_widget/home_widget.dart';
import 'package:provider/provider.dart';
-import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:relative_time/relative_time.dart';
import 'package:responsive_framework/responsive_framework.dart';
import 'package:styled_widget/styled_widget.dart';
@@ -40,6 +37,7 @@ import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy;
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/version_label.dart';
+
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
@@ -191,17 +189,10 @@ class _AppSplashScreenState extends State<_AppSplashScreen> {
}
}
- void _listenShareIntent() async {
- _shareIntentSubscription = ReceiveSharingIntent.instance.getMediaStream().listen((value) {}, onError: (err) {
- log("[ShareIntent] Unable to subscribe: $err");
- });
- }
-
@override
void initState() {
super.initState();
_initialize();
- _listenShareIntent();
}
@override
diff --git a/lib/router.dart b/lib/router.dart
index 25a0b18..8047a41 100644
--- a/lib/router.dart
+++ b/lib/router.dart
@@ -28,6 +28,7 @@ import 'package:surface/screens/realm.dart';
import 'package:surface/screens/realm/manage.dart';
import 'package:surface/screens/realm/realm_detail.dart';
import 'package:surface/screens/settings.dart';
+import 'package:surface/screens/sharing.dart';
import 'package:surface/types/post.dart';
import 'package:surface/widgets/about.dart';
import 'package:surface/widgets/navigation/app_background.dart';
@@ -69,6 +70,7 @@ final _appRoutes = [
postRepostId: int.tryParse(
state.uri.queryParameters['reposting'] ?? '',
),
+ extraProps: state.extra as PostEditorExtraProps?,
),
),
),
@@ -315,7 +317,9 @@ final appRouter = GoRouter(
routes: [
ShellRoute(
routes: _appRoutes,
- builder: (context, state, child) => AppRootScaffold(body: child),
+ builder: (context, state, child) => AppRootScaffold(
+ body: AppSharingListener(child: child),
+ ),
),
],
);
diff --git a/lib/screens/post/post_editor.dart b/lib/screens/post/post_editor.dart
index 60c0a33..c11c508 100644
--- a/lib/screens/post/post_editor.dart
+++ b/lib/screens/post/post_editor.dart
@@ -23,11 +23,26 @@ import 'package:surface/widgets/post/post_meta_editor.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:provider/provider.dart';
+class PostEditorExtraProps {
+ final String? text;
+ final String? title;
+ final String? description;
+ final List? attachments;
+
+ const PostEditorExtraProps({
+ this.text,
+ this.title,
+ this.description,
+ this.attachments,
+ });
+}
+
class PostEditorScreen extends StatefulWidget {
final String mode;
final int? postEditId;
final int? postReplyId;
final int? postRepostId;
+ final PostEditorExtraProps? extraProps;
const PostEditorScreen({
super.key,
@@ -35,6 +50,7 @@ class PostEditorScreen extends StatefulWidget {
required this.postEditId,
required this.postReplyId,
required this.postRepostId,
+ this.extraProps,
});
@override
@@ -130,6 +146,12 @@ class _PostEditorScreenState extends State {
replying: widget.postReplyId,
reposting: widget.postRepostId,
);
+ if (widget.extraProps != null) {
+ _writeController.contentController.text = widget.extraProps!.text ?? '';
+ _writeController.titleController.text = widget.extraProps!.title ?? '';
+ _writeController.descriptionController.text = widget.extraProps!.description ?? '';
+ _writeController.addAttachments(widget.extraProps!.attachments ?? []);
+ }
}
@override
@@ -150,15 +172,15 @@ class _PostEditorScreenState extends State {
TextSpan(
text: _writeController.title.isNotEmpty ? _writeController.title : 'untitled'.tr(),
style: Theme.of(context).textTheme.titleLarge!.copyWith(
- color: Theme.of(context).appBarTheme.foregroundColor!,
- ),
+ color: Theme.of(context).appBarTheme.foregroundColor!,
+ ),
),
const TextSpan(text: '\n'),
TextSpan(
text: PostWriteController.kTitleMap[widget.mode]!.tr(),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
- color: Theme.of(context).appBarTheme.foregroundColor!,
- ),
+ color: Theme.of(context).appBarTheme.foregroundColor!,
+ ),
),
]),
),
diff --git a/lib/screens/sharing.dart b/lib/screens/sharing.dart
new file mode 100644
index 0000000..a699bc5
--- /dev/null
+++ b/lib/screens/sharing.dart
@@ -0,0 +1,115 @@
+import 'dart:async';
+import 'dart:developer';
+
+import 'package:cross_file/cross_file.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/scheduler.dart';
+import 'package:gap/gap.dart';
+import 'package:go_router/go_router.dart';
+import 'package:receive_sharing_intent/receive_sharing_intent.dart';
+import 'package:surface/controllers/post_write_controller.dart';
+import 'package:surface/screens/post/post_editor.dart';
+import 'package:surface/widgets/dialog.dart';
+
+class AppSharingListener extends StatefulWidget {
+ final Widget child;
+
+ const AppSharingListener({super.key, required this.child});
+
+ @override
+ State createState() => _AppSharingListenerState();
+}
+
+class _AppSharingListenerState extends State {
+ late StreamSubscription _shareIntentSubscription;
+
+ void _gotoPost(Iterable value) {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ showDialog(
+ context: context,
+ builder: (context) => AlertDialog(
+ title: Text('shareIntent').tr(),
+ content: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text('shareIntentDescription').tr(),
+ const Gap(8),
+ Card(
+ child: Column(
+ children: [
+ ListTile(
+ contentPadding: const EdgeInsets.symmetric(horizontal: 24),
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
+ leading: Icon(Icons.post_add),
+ trailing: const Icon(Icons.chevron_right),
+ title: Text('shareIntentPostStory').tr(),
+ onTap: () {
+ GoRouter.of(context).pushNamed(
+ 'postEditor',
+ pathParameters: {
+ 'mode': 'stories',
+ },
+ extra: PostEditorExtraProps(
+ attachments: value.map((e) => PostWriteMedia.fromFile(XFile(e.path))).toList(),
+ ),
+ );
+ Navigator.pop(context);
+ },
+ ),
+ ],
+ ),
+ )
+ ],
+ ),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context),
+ child: Text('dialogDismiss').tr(),
+ )
+ ],
+ ),
+ );
+ });
+ }
+
+ void _initialize() async {
+ _shareIntentSubscription = ReceiveSharingIntent.instance.getMediaStream().listen((value) {
+ if (value.isEmpty) return;
+ if (mounted) {
+ _gotoPost(value);
+ }
+ }, onError: (err) {
+ log("[ShareIntent] Unable to subscribe: $err");
+ });
+ }
+
+ void _initialHandle() {
+ ReceiveSharingIntent.instance.getInitialMedia().then((value) {
+ if (value.isEmpty) return;
+ if (mounted) {
+ _gotoPost(value);
+ }
+ ReceiveSharingIntent.instance.reset();
+ });
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _initialize();
+ _initialHandle();
+ }
+
+ @override
+ void dispose() {
+ _shareIntentSubscription.cancel();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return widget.child;
+ }
+}