Skip to content

Commit 90fb42d

Browse files
committed
feat:fix share in mobile browser
1 parent f63acd8 commit 90fb42d

2 files changed

Lines changed: 55 additions & 13 deletions

File tree

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
1-
# PictoTap
1+
<p align="center">
2+
<img src="web/icons/Icon-192.png" alt="PictoTap" width="96" height="96">
3+
</p>
24

3-
A communication app for accessibility built with Flutter. PictoTap enables users to communicate using pictograms — ideal for people who express themselves more easily with visual symbols.
5+
<h1 align="center">PictoTap</h1>
6+
7+
<p align="center">
8+
A communication app for accessibility using pictograms.<br>
9+
Built with Flutter for web, installable as a PWA.
10+
</p>
11+
12+
<p align="center">
13+
<a href="https://endika.github.io/pictotap"><strong>Live Demo</strong></a> ·
14+
<a href="#features">Features</a> ·
15+
<a href="#getting-started">Getting Started</a>
16+
</p>
17+
18+
---
419

520
## Features
621

722
- **Pictogram keyboard** with categorized icons (descriptive, people, prepositions, determiners, nouns, verbs)
823
- **Visual board** to compose messages by selecting pictograms
924
- **Share** the board as an image with text description
25+
- **Installable PWA** — add to home screen on Android and iOS
1026
- **Multi-language support**: English, Spanish, Catalan, Basque, French, Galician, Portuguese, Valencian
1127
- **Accessibility-focused** design with semantic labels for screen readers
1228

lib/image_saver_web.dart

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,44 @@ import 'package:web/web.dart' as web;
44

55
Future<void> saveAndShareImage(
66
Uint8List bytes, String fileName, String shareText) async {
7+
final shared = await _tryNativeShare(bytes, fileName, shareText);
8+
if (!shared) {
9+
_download(bytes, fileName);
10+
}
11+
}
12+
13+
/// Uses the Web Share API to open the native share sheet on mobile browsers.
14+
/// Returns false if the API is not available or the share was cancelled.
15+
Future<bool> _tryNativeShare(
16+
Uint8List bytes, String fileName, String shareText) async {
717
try {
8-
final blob = web.Blob(
9-
[bytes.toJS].toJS,
10-
web.BlobPropertyBag(type: 'image/png'),
18+
final file = web.File(
19+
<JSAny>[bytes.toJS].toJS,
20+
fileName,
21+
web.FilePropertyBag(type: 'image/png'),
1122
);
12-
final url = web.URL.createObjectURL(blob);
13-
final anchor = web.HTMLAnchorElement()
14-
..href = url
15-
..download = fileName;
16-
anchor.click();
17-
web.URL.revokeObjectURL(url);
18-
} catch (e) {
19-
throw Exception('Failed to download image: $e');
23+
final data = web.ShareData(
24+
files: <web.File>[file].toJS,
25+
text: shareText,
26+
);
27+
if (!web.window.navigator.canShare(data)) return false;
28+
await web.window.navigator.share(data).toDart;
29+
return true;
30+
} catch (_) {
31+
return false;
2032
}
2133
}
34+
35+
/// Fallback: triggers a file download (used on desktop browsers).
36+
void _download(Uint8List bytes, String fileName) {
37+
final blob = web.Blob(
38+
<JSAny>[bytes.toJS].toJS,
39+
web.BlobPropertyBag(type: 'image/png'),
40+
);
41+
final url = web.URL.createObjectURL(blob);
42+
final anchor = web.HTMLAnchorElement()
43+
..href = url
44+
..download = fileName;
45+
anchor.click();
46+
web.URL.revokeObjectURL(url);
47+
}

0 commit comments

Comments
 (0)