social_share_kit 0.2.0
social_share_kit: ^0.2.0 copied to clipboard
Share text, links and files directly to X, WhatsApp, Instagram, Threads, Telegram, LinkedIn, Messenger, TikTok, SMS and mail, or to the system share sheet. Reports per-target capabilities up front. Bu [...]
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:social_share_kit/social_share_kit.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'social_share_kit',
theme: ThemeData(
colorSchemeSeed: Colors.indigo,
useMaterial3: true,
),
darkTheme: ThemeData(
colorSchemeSeed: Colors.indigo,
brightness: Brightness.dark,
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController _text = TextEditingController(
text: 'Shipping social_share_kit today.',
);
final TextEditingController _url = TextEditingController(
text: 'https://pub.flutter-io.cn/packages/social_share_kit',
);
Map<ShareTarget, bool> _installed = const <ShareTarget, bool>{};
bool _attachImage = false;
String? _imagePath;
@override
void initState() {
super.initState();
_refreshInstalled();
}
@override
void dispose() {
_text.dispose();
_url.dispose();
super.dispose();
}
Future<void> _refreshInstalled() async {
final Map<ShareTarget, bool> installed =
await SocialShareKit.installedTargets();
if (mounted) setState(() => _installed = installed);
}
/// Draws a PNG to a temp file, so the example can demonstrate file sharing
/// without pulling in an image picker.
Future<String> _sampleImage() async {
final String? existing = _imagePath;
if (existing != null && File(existing).existsSync()) return existing;
final ui.PictureRecorder recorder = ui.PictureRecorder();
final Canvas canvas = Canvas(recorder);
const Size size = Size(600, 600);
canvas.drawRect(
Offset.zero & size,
Paint()..color = const Color(0xFF3F51B5),
);
canvas.drawCircle(
size.center(Offset.zero),
180,
Paint()..color = const Color(0xFFFFC107),
);
final ui.Image image = await recorder
.endRecording()
.toImage(size.width.toInt(), size.height.toInt());
final ByteData? data =
await image.toByteData(format: ui.ImageByteFormat.png);
// systemTemp is the app's cache directory on both platforms, which is one
// of the roots the plugin's FileProvider is allowed to hand out.
final File file = File('${Directory.systemTemp.path}/sample.png');
await file.writeAsBytes(data!.buffer.asUint8List(), flush: true);
_imagePath = file.path;
return file.path;
}
Future<void> _share(ShareTarget target) async {
final List<String> files =
_attachImage ? <String>[await _sampleImage()] : const <String>[];
final ShareResult result = await SocialShareKit.shareTo(
target,
ShareContent(
text: _text.text.isEmpty ? null : _text.text,
url: _url.text.isEmpty ? null : _url.text,
subject: 'Shared from social_share_kit',
files: files,
),
);
if (!mounted) return;
ScaffoldMessenger.of(context)
..clearSnackBars()
..showSnackBar(
SnackBar(
content: Text(
result.message == null
? '${target.id}: ${result.status.name}'
: '${target.id}: ${result.status.name}\n${result.message}',
),
backgroundColor: result.isSuccess ? null : Colors.red.shade700,
duration: Duration(seconds: result.isSuccess ? 2 : 6),
),
);
}
Future<void> _shareStory(ShareTarget target) async {
final ShareResult result = await SocialShareKit.shareStory(
target,
StoryContent(
// Replace with your own Facebook app id; both story composers reject
// the share without one.
appId: '0000000000000000',
backgroundImage: await _sampleImage(),
text: _text.text,
),
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('${target.id}: ${result.status.name}')),
);
}
@override
Widget build(BuildContext context) {
final List<ShareTarget> targets = SocialShareKit.supportedTargets();
return Scaffold(
appBar: AppBar(
title: const Text('social_share_kit'),
actions: <Widget>[
IconButton(
onPressed: _refreshInstalled,
icon: const Icon(Icons.refresh),
tooltip: 'Re-check installed apps',
),
],
),
body: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
TextField(
controller: _text,
maxLines: 3,
decoration: const InputDecoration(
labelText: 'Text',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 12),
TextField(
controller: _url,
decoration: const InputDecoration(
labelText: 'Link',
border: OutlineInputBorder(),
),
),
SwitchListTile(
value: _attachImage,
onChanged: (bool value) => setState(() => _attachImage = value),
title: const Text('Attach a generated PNG'),
subtitle: const Text(
'Targets that cannot take files will say so instead of sharing',
),
contentPadding: EdgeInsets.zero,
),
const Divider(height: 32),
for (final ShareTarget target in targets)
_TargetTile(
target: target,
installed: _installed[target],
capabilities: SocialShareKit.capabilities(target),
onShare: () => target.isStoryTarget
? _shareStory(target)
: _share(target),
),
],
),
);
}
}
class _TargetTile extends StatelessWidget {
const _TargetTile({
required this.target,
required this.installed,
required this.capabilities,
required this.onShare,
});
final ShareTarget target;
final bool? installed;
final ShareCapabilities capabilities;
final VoidCallback onShare;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final bool missing = installed == false;
final List<String> facts = <String>[
if (capabilities.supportsText)
capabilities.prefillsText ? 'text' : 'text (via clipboard)',
if (capabilities.supportsUrl) 'link',
if (capabilities.supportsFiles)
'files${capabilities.maxFiles == null ? '' : ' ×${capabilities.maxFiles}'}',
if (capabilities.supportsSubject) 'subject',
if (capabilities.textLimit != null) '${capabilities.textLimit} chars',
];
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
title: Text(target.id),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(facts.join(' · ')),
if (missing)
Text(
'not installed',
style: TextStyle(color: theme.colorScheme.error),
),
if (capabilities.note != null)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
capabilities.note!,
style: theme.textTheme.bodySmall,
),
),
],
),
isThreeLine: capabilities.note != null,
trailing: FilledButton(
// Left enabled even when the app is missing, so the resulting
// appNotInstalled status is visible in the example.
onPressed: onShare,
child: const Text('Share'),
),
),
);
}
}