Browse Source

Added documentation about embedding images

Anatoly Pulyaevskiy 6 years ago
parent
commit
0d6010c302
3 changed files with 128 additions and 0 deletions
  1. 2
    0
      README.md
  2. 12
    0
      doc/heuristics.md
  3. 114
    0
      doc/images.md

+ 2
- 0
README.md View File

@@ -17,12 +17,14 @@ request or found a bug, please file it at the [issue tracker][].
17 17
 * [Data Format and Document Model][data_and_document]
18 18
 * [Style attributes][attributes]
19 19
 * [Heuristic rules][heuristics]
20
+* [Images][images]
20 21
 * [FAQ][faq]
21 22
 
22 23
 [quick_start]: /doc/quick_start.md
23 24
 [data_and_document]: /doc/data_and_document.md
24 25
 [attributes]: /doc/attributes.md
25 26
 [heuristics]: /doc/heuristics.md
27
+[images]: /doc/images.md
26 28
 [faq]: /doc/faq.md
27 29
 
28 30
 ## Clean and modern look

+ 12
- 0
doc/heuristics.md View File

@@ -87,3 +87,15 @@ When composing a change which came from a different site or server make
87 87
 sure to use `ChangeSource.remote` when calling `compose()`. This allows
88 88
 you to distinguish such changes from local changes made by the user
89 89
 when listening on `NotusDocument.changes` stream.
90
+
91
+### Next up
92
+
93
+* [Images][images]
94
+
95
+[images]: /doc/images.md
96
+
97
+### Previous
98
+
99
+* [Style attributes][attributes]
100
+
101
+[attributes]: /doc/attributes.md

+ 114
- 0
doc/images.md View File

@@ -0,0 +1,114 @@
1
+## Images
2
+
3
+> Note that described API is considered experimental and is likely to be
4
+> changed in backward incompatible ways. If this happens all changes will be
5
+> described in detail in the changelog to simplify upgrading.
6
+
7
+Zefyr (and Notus) supports embedded images. In order to handle images in
8
+your application you need to implement `ZefyrImageDelegate` interface which
9
+looks like this:
10
+
11
+```dart
12
+abstract class ZefyrImageDelegate<S> {
13
+  /// Builds image widget for specified [imageSource] and [context].
14
+  Widget buildImage(BuildContext context, String imageSource);
15
+
16
+  /// Picks an image from specified [source].
17
+  ///
18
+  /// Returns unique string key for the selected image. Returned key is stored
19
+  /// in the document.
20
+  Future<String> pickImage(S source);
21
+}
22
+```
23
+
24
+Zefyr comes with default implementation which exists mostly to provide an
25
+example and a starting point for your own version.
26
+
27
+It is recommended to always have your own implementation specific to your
28
+application.
29
+
30
+### Implementing ZefyrImageDelegate
31
+
32
+Let's start from the `pickImage` method:
33
+
34
+```dart
35
+// Currently Zefyr depends on image_picker plugin to show camera or image gallery.
36
+// (note that in future versions this may change so that users can choose their
37
+// own plugin and define custom sources)
38
+import 'package:image_picker/image_picker.dart';
39
+
40
+class MyAppZefyrImageDelegate implements ZefyrImageDelegate<ImageSource> {
41
+  @override
42
+  Future<String> pickImage(ImageSource source) async {
43
+    final file = await ImagePicker.pickImage(source: source);
44
+    if (file == null) return null;
45
+    // We simply return the absolute path to selected file.
46
+    return file.uri.toString();
47
+  }
48
+}
49
+```
50
+
51
+This method is responsible for initiating image selection flow (either using
52
+camera or gallery), handling result of selection and returning a string value
53
+which essentially serves as an identifier for the image.
54
+
55
+Returned value is stored in the document Delta and later on used to build the
56
+appropriate `Widget`.
57
+
58
+It is up to the developer to define what this value represents.
59
+
60
+In the above example we simply return a full path to the file on user's device,
61
+e.g. `file:///Users/something/something/image.jpg`. Some other examples
62
+may include a web link, `https://myapp.com/images/some.jpg` or just some
63
+arbitrary string like an ID.
64
+
65
+For instance, if you upload files to your server you can initiate this task
66
+in `pickImage`, for instance:
67
+
68
+```dart
69
+class MyAppZefyrImageDelegate implements ZefyrImageDelegate<ImageSource> {
70
+  final MyFileStorage storage;
71
+  MyAppZefyrImageDelegate(this.storage);
72
+
73
+  @override
74
+  Future<String> pickImage(ImageSource source) async {
75
+    final file = await ImagePicker.pickImage(source: source);
76
+    if (file == null) return null;
77
+    // Use my storage service to upload selected file. The uploadImage method
78
+    // returns unique ID of newly uploaded image on my server.
79
+    final String imageId = await storage.uploadImage(file);
80
+    return imageId;
81
+  }
82
+}
83
+```
84
+
85
+Next we need to implement `buildImage`. This method takes `imageSource` argument
86
+which contains that same string you returned from `pickImage`. Here you can
87
+use this value to create a Flutter `Widget` which renders the image. Normally
88
+you would return the standard `Image` widget from this method, but it is not
89
+a requirement. You are free to create a custom widget which, for instance,
90
+shows progress of upload operation that you initiated in the `pickImage` call.
91
+
92
+Assuming our first example where we returned full path to the image file on
93
+user's device, our `buildImage` method can be as simple as following:
94
+
95
+```dart
96
+class MyAppZefyrImageDelegate implements ZefyrImageDelegate<ImageSource> {
97
+  // ...
98
+
99
+  @override
100
+  Widget buildImage(BuildContext context, String imageSource) {
101
+    final file = new File.fromUri(Uri.parse(imageSource));
102
+    /// Create standard [FileImage] provider. If [imageSource] was an HTTP link
103
+    /// we could use [NetworkImage] instead.
104
+    final image = new FileImage(file);
105
+    return new Image(image: image);
106
+  }
107
+}
108
+```
109
+
110
+### Previous
111
+
112
+* [Heuristics][heuristics]
113
+
114
+[heuristics]: /doc/heuristics.md