├── .gitignore
├── .idea
├── encodings.xml
├── libraries
│ ├── Dart_Packages.xml
│ ├── Dart_SDK.xml
│ └── Flutter_Plugins.xml
├── misc.xml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dev
└── bots
│ ├── travis_install.sh
│ └── travis_script.sh
├── disk_lru_cache.iml
├── example
├── .gitignore
├── .idea
│ ├── codeStyles
│ │ └── Project.xml
│ ├── libraries
│ │ ├── Dart_Packages.xml
│ │ ├── Dart_SDK.xml
│ │ ├── Flutter_Plugins.xml
│ │ └── Flutter_for_Android.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── runConfigurations
│ │ └── main_dart.xml
│ └── workspace.xml
├── .metadata
├── README.md
├── android
│ ├── .gitignore
│ ├── .idea
│ │ ├── codeStyles
│ │ │ └── Project.xml
│ │ ├── gradle.xml
│ │ ├── misc.xml
│ │ ├── modules.xml
│ │ └── runConfigurations.xml
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── example
│ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── example.iml
├── example_android.iml
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── Runner
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
├── lib
│ ├── main.dart
│ └── test_disk_cache.dart
├── pubspec.lock
├── pubspec.yaml
└── test
│ └── widget_test.dart
├── flutter_01.log
├── lib
├── _src
│ ├── disk_lru_cache.dart
│ ├── ioutil.dart
│ └── lru_map.dart
└── disk_lru_cache.dart
├── pubspec.lock
├── pubspec.yaml
└── test
├── disk_lru_cache_test.dart
└── lru_map_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 | ios/.generated/
9 | ios/Flutter/Generated.xcconfig
10 | ios/Runner/GeneratedPluginRegistrant.*
11 | coverage/lcov.info
12 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_Packages.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/libraries/Flutter_Plugins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: dart
2 | env:
3 | - SHARD=dartfmt
4 | - SHARD=test
5 | install:
6 | - ./dev/bots/travis_install.sh
7 | script:
8 | - ./dev/bots/travis_script.sh
9 | after_success:
10 | - coveralls-lcov coverage/lcov.info
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # [0.0.2]
2 |
3 | * Use synchronized library.
4 |
5 |
6 | ## [0.0.1] - Basic usage.
7 |
8 | * LRU Map
9 | * Store One `CacheEntry` with multiple files by using `CacheEditor`
10 | * Get `CacheSnapshot` and open streams directly from `CacheEntry`
11 | * Using a key to remove from cache
12 | * A record file to store all operation info,including 'DIRTY','CLEAN','REMOVE','READ'
13 | * Get total size from cache
14 | * When cache.size > caches.maxSize , auto trim to size.
15 |
16 |
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Xueliang Ren
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | # disk_lru_cache
20 | Disk lru cache for flutter. [wiki](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU))
21 |
22 | A cache that uses a bounded amount of space on a filesystem.
23 | Each cache entry has a string key and a fixed number of files, witch is accessible as stream.
24 |
25 | ## Use cases
26 |
27 |
28 | #### Working with memery
29 |
30 | We provided a `LruMap` ,in order to support LRU order in memory, witch is a subclass of Map.So ,wo can use the `LruMap` just like Map
31 |
32 |
33 |
34 | ```
35 | final LruMap map = new LruMap();
36 |
37 | expect(map.values.toList().length, 0);
38 |
39 | map['a'] = 1;
40 | map['b'] = 2;
41 | map['c'] = 3;
42 |
43 | /// use the key 'a'
44 | var f = map['a'];
45 |
46 | /// We use the key 'a', so at this moment it is the last element.
47 | alues = map.values;
48 | expect(values.toList()[0], 2);
49 | expect(values.toList()[1], 3);
50 | expect(values.toList()[2], 1);
51 |
52 | ```
53 |
54 |
55 | #### Working with file system
56 |
57 | The basic usage is like this:
58 |
59 |
60 | With string:
61 |
62 | ```
63 | int maxSize =
64 | 10 * 1024 * 1024; // 10M
65 |
66 | // Make sure it's writable
67 | Directory cacheDirectory =
68 | new Directory("${Directory.systemTemp.path}/cache");
69 |
70 | DiskLruCache cache = new DiskLruCache(
71 | maxSize: maxSize, directory: cacheDirectory, filesCount: 1);
72 |
73 | // write stream
74 | CacheEditor editor = await cache.edit('filekey');
75 | if(editor!=null){
76 | IOSink sink = await editor.newSink(0);
77 | sink.write('your value');
78 | await sink.close();
79 | await editor.commit();
80 | }
81 |
82 | // read stream
83 | CacheSnapshot snapshot = await cache.get('filekey');
84 | String str = await snapshot.getString(0);
85 | print(str);
86 |
87 | ```
88 |
89 |
90 | With bytes
91 |
92 | ```
93 | // write bytes
94 | CacheEditor editor = await cache.edit('imagekey');
95 | if(editor!=null){
96 | HttpClient client = new HttpClient();
97 | HttpClientRequest request = await client.openUrl("GET", Uri.parse("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1534075481&di=1a90bd266d62bc5edfe1ce84ac38330e&src=http://photocdn.sohu.com/20130517/Img376200804.jpg"));
98 | HttpClientResponse response = await request.close();
99 | Stream> stream = await editor.copyStream(0, response);
100 | // The bytes has been written to disk at this point.
101 | await new ByteStream(stream).toBytes();
102 | await editor.commit();
103 |
104 | // read stream
105 | CacheSnapshot snapshot = await cache.get('imagekey');
106 | Uint8List bytes = await snapshot.getBytes(0);
107 | print(bytes);
108 | }
109 |
110 | ```
111 |
112 |
113 | ## Manage the cache
114 |
115 |
116 | #### Get the bytes of the cache in file system
117 |
118 | ```
119 | DiskLruCache cache = ...;
120 | print(cache.size)
121 | ```
122 |
123 | #### Clean the cache
124 |
125 | ```
126 | DiskLruCache cache = ...;
127 | cache.clean();
128 |
129 | ```
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/dev/bots/travis_install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "$PWD"
4 | export ROOT="$PWD"
5 |
6 | mkdir ~/development
7 |
8 | cd ~/development
9 | wget https://storage.googleapis.com/flutter_infra/releases/beta/linux/flutter_linux_v0.5.1-beta.tar.xz
10 | tar xf ~/development/flutter_linux_v0.5.1-beta.tar.xz
11 |
12 | export PATH=~/development/flutter/bin:$PATH
13 |
14 |
15 | cd $ROOT
16 | flutter packages get
17 |
18 | gem install coveralls-lcov
19 |
--------------------------------------------------------------------------------
/dev/bots/travis_script.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -ex
3 |
4 | export PATH=~/development/flutter/bin:$PATH
5 | export ROOT="$PWD"
6 |
7 | if [[ "$SHARD" == "dartfmt" ]]; then
8 | echo 'Formating code'
9 | cd $ROOT
10 | flutter format . || exit $?
11 | else
12 | # tests shard
13 | cd $ROOT
14 |
15 | flutter test --coverage test/* || exit $?
16 |
17 | fi
18 |
--------------------------------------------------------------------------------
/disk_lru_cache.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 |
9 | .flutter-plugins
10 |
--------------------------------------------------------------------------------
/example/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/example/.idea/libraries/Dart_Packages.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
--------------------------------------------------------------------------------
/example/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/example/.idea/libraries/Flutter_Plugins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/example/.idea/libraries/Flutter_for_Android.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/example/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/.idea/runConfigurations/main_dart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/example/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | 1533820268156
194 |
195 |
196 | 1533820268156
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: c7ea3ca377e909469c68f2ab878a5bc53d3cf66b
8 | channel: beta
9 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # example
2 |
3 | A new Flutter project.
4 |
5 | ## Getting Started
6 |
7 | For help getting started with Flutter, view our online
8 | [documentation](https://flutter.io/).
9 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.class
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | GeneratedPluginRegistrant.java
11 |
--------------------------------------------------------------------------------
/example/android/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/example/android/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | apply plugin: 'com.android.application'
15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
16 |
17 | android {
18 | compileSdkVersion 27
19 |
20 | lintOptions {
21 | disable 'InvalidPackage'
22 | }
23 |
24 | defaultConfig {
25 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
26 | applicationId "com.example.example"
27 | minSdkVersion 16
28 | targetSdkVersion 27
29 | versionCode 1
30 | versionName "1.0"
31 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
32 | }
33 |
34 | buildTypes {
35 | release {
36 | // TODO: Add your own signing config for the release build.
37 | // Signing with the debug keys for now, so `flutter run --release` works.
38 | signingConfig signingConfigs.debug
39 | }
40 | }
41 | }
42 |
43 | flutter {
44 | source '../..'
45 | }
46 |
47 | dependencies {
48 | testImplementation 'junit:junit:4.12'
49 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
50 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
51 | }
52 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
26 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.example;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.0.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/example/example.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/example/example_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/app.flx
37 | /Flutter/app.zip
38 | /Flutter/flutter_assets/
39 | /Flutter/App.framework
40 | /Flutter/Flutter.framework
41 | /Flutter/Generated.xcconfig
42 | /ServiceDefinitions.json
43 |
44 | Pods/
45 | .symlinks/
46 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=/Users/jzoom/working/flutter"
4 | export "FLUTTER_APPLICATION_PATH=/Users/jzoom/SourceCode/disk_lru_cache/example"
5 | export "FLUTTER_TARGET=lib/main.dart"
6 | export "FLUTTER_BUILD_DIR=build"
7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios"
8 | export "FLUTTER_FRAMEWORK_DIR=/Users/jzoom/working/flutter/bin/cache/artifacts/engine/ios"
9 | export "FLUTTER_BUILD_NAME=1.0.0"
10 | export "FLUTTER_BUILD_NUMBER=1"
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
18 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
19 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
20 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
21 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
22 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
23 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
24 | /* End PBXBuildFile section */
25 |
26 | /* Begin PBXCopyFilesBuildPhase section */
27 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
28 | isa = PBXCopyFilesBuildPhase;
29 | buildActionMask = 2147483647;
30 | dstPath = "";
31 | dstSubfolderSpec = 10;
32 | files = (
33 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
34 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
35 | );
36 | name = "Embed Frameworks";
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXCopyFilesBuildPhase section */
40 |
41 | /* Begin PBXFileReference section */
42 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
43 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
44 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
45 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
46 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
47 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
48 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
49 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
50 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
51 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
52 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
53 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
54 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
55 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
56 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
57 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
58 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
59 | /* End PBXFileReference section */
60 |
61 | /* Begin PBXFrameworksBuildPhase section */
62 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
67 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
68 | );
69 | runOnlyForDeploymentPostprocessing = 0;
70 | };
71 | /* End PBXFrameworksBuildPhase section */
72 |
73 | /* Begin PBXGroup section */
74 | 9740EEB11CF90186004384FC /* Flutter */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
78 | 3B80C3931E831B6300D905FE /* App.framework */,
79 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
80 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
81 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
82 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
83 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
84 | );
85 | name = Flutter;
86 | sourceTree = "";
87 | };
88 | 97C146E51CF9000F007C117D = {
89 | isa = PBXGroup;
90 | children = (
91 | 9740EEB11CF90186004384FC /* Flutter */,
92 | 97C146F01CF9000F007C117D /* Runner */,
93 | 97C146EF1CF9000F007C117D /* Products */,
94 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
95 | );
96 | sourceTree = "";
97 | };
98 | 97C146EF1CF9000F007C117D /* Products */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 97C146EE1CF9000F007C117D /* Runner.app */,
102 | );
103 | name = Products;
104 | sourceTree = "";
105 | };
106 | 97C146F01CF9000F007C117D /* Runner */ = {
107 | isa = PBXGroup;
108 | children = (
109 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
110 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
111 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
112 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
113 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
114 | 97C147021CF9000F007C117D /* Info.plist */,
115 | 97C146F11CF9000F007C117D /* Supporting Files */,
116 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
117 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
118 | );
119 | path = Runner;
120 | sourceTree = "";
121 | };
122 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
123 | isa = PBXGroup;
124 | children = (
125 | 97C146F21CF9000F007C117D /* main.m */,
126 | );
127 | name = "Supporting Files";
128 | sourceTree = "";
129 | };
130 | /* End PBXGroup section */
131 |
132 | /* Begin PBXNativeTarget section */
133 | 97C146ED1CF9000F007C117D /* Runner */ = {
134 | isa = PBXNativeTarget;
135 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
136 | buildPhases = (
137 | 9740EEB61CF901F6004384FC /* Run Script */,
138 | 97C146EA1CF9000F007C117D /* Sources */,
139 | 97C146EB1CF9000F007C117D /* Frameworks */,
140 | 97C146EC1CF9000F007C117D /* Resources */,
141 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
142 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
143 | );
144 | buildRules = (
145 | );
146 | dependencies = (
147 | );
148 | name = Runner;
149 | productName = Runner;
150 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
151 | productType = "com.apple.product-type.application";
152 | };
153 | /* End PBXNativeTarget section */
154 |
155 | /* Begin PBXProject section */
156 | 97C146E61CF9000F007C117D /* Project object */ = {
157 | isa = PBXProject;
158 | attributes = {
159 | LastUpgradeCheck = 0910;
160 | ORGANIZATIONNAME = "The Chromium Authors";
161 | TargetAttributes = {
162 | 97C146ED1CF9000F007C117D = {
163 | CreatedOnToolsVersion = 7.3.1;
164 | };
165 | };
166 | };
167 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
168 | compatibilityVersion = "Xcode 3.2";
169 | developmentRegion = English;
170 | hasScannedForEncodings = 0;
171 | knownRegions = (
172 | en,
173 | Base,
174 | );
175 | mainGroup = 97C146E51CF9000F007C117D;
176 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
177 | projectDirPath = "";
178 | projectRoot = "";
179 | targets = (
180 | 97C146ED1CF9000F007C117D /* Runner */,
181 | );
182 | };
183 | /* End PBXProject section */
184 |
185 | /* Begin PBXResourcesBuildPhase section */
186 | 97C146EC1CF9000F007C117D /* Resources */ = {
187 | isa = PBXResourcesBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
191 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
192 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
193 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
194 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
195 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
196 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
197 | );
198 | runOnlyForDeploymentPostprocessing = 0;
199 | };
200 | /* End PBXResourcesBuildPhase section */
201 |
202 | /* Begin PBXShellScriptBuildPhase section */
203 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
204 | isa = PBXShellScriptBuildPhase;
205 | buildActionMask = 2147483647;
206 | files = (
207 | );
208 | inputPaths = (
209 | );
210 | name = "Thin Binary";
211 | outputPaths = (
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | shellPath = /bin/sh;
215 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
216 | };
217 | 9740EEB61CF901F6004384FC /* Run Script */ = {
218 | isa = PBXShellScriptBuildPhase;
219 | buildActionMask = 2147483647;
220 | files = (
221 | );
222 | inputPaths = (
223 | );
224 | name = "Run Script";
225 | outputPaths = (
226 | );
227 | runOnlyForDeploymentPostprocessing = 0;
228 | shellPath = /bin/sh;
229 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
230 | };
231 | /* End PBXShellScriptBuildPhase section */
232 |
233 | /* Begin PBXSourcesBuildPhase section */
234 | 97C146EA1CF9000F007C117D /* Sources */ = {
235 | isa = PBXSourcesBuildPhase;
236 | buildActionMask = 2147483647;
237 | files = (
238 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
239 | 97C146F31CF9000F007C117D /* main.m in Sources */,
240 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
241 | );
242 | runOnlyForDeploymentPostprocessing = 0;
243 | };
244 | /* End PBXSourcesBuildPhase section */
245 |
246 | /* Begin PBXVariantGroup section */
247 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
248 | isa = PBXVariantGroup;
249 | children = (
250 | 97C146FB1CF9000F007C117D /* Base */,
251 | );
252 | name = Main.storyboard;
253 | sourceTree = "";
254 | };
255 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
256 | isa = PBXVariantGroup;
257 | children = (
258 | 97C147001CF9000F007C117D /* Base */,
259 | );
260 | name = LaunchScreen.storyboard;
261 | sourceTree = "";
262 | };
263 | /* End PBXVariantGroup section */
264 |
265 | /* Begin XCBuildConfiguration section */
266 | 97C147031CF9000F007C117D /* Debug */ = {
267 | isa = XCBuildConfiguration;
268 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
269 | buildSettings = {
270 | ALWAYS_SEARCH_USER_PATHS = NO;
271 | CLANG_ANALYZER_NONNULL = YES;
272 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
273 | CLANG_CXX_LIBRARY = "libc++";
274 | CLANG_ENABLE_MODULES = YES;
275 | CLANG_ENABLE_OBJC_ARC = YES;
276 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
277 | CLANG_WARN_BOOL_CONVERSION = YES;
278 | CLANG_WARN_COMMA = YES;
279 | CLANG_WARN_CONSTANT_CONVERSION = YES;
280 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
281 | CLANG_WARN_EMPTY_BODY = YES;
282 | CLANG_WARN_ENUM_CONVERSION = YES;
283 | CLANG_WARN_INFINITE_RECURSION = YES;
284 | CLANG_WARN_INT_CONVERSION = YES;
285 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
286 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
287 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
288 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
289 | CLANG_WARN_STRICT_PROTOTYPES = YES;
290 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
291 | CLANG_WARN_UNREACHABLE_CODE = YES;
292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
293 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
294 | COPY_PHASE_STRIP = NO;
295 | DEBUG_INFORMATION_FORMAT = dwarf;
296 | ENABLE_STRICT_OBJC_MSGSEND = YES;
297 | ENABLE_TESTABILITY = YES;
298 | GCC_C_LANGUAGE_STANDARD = gnu99;
299 | GCC_DYNAMIC_NO_PIC = NO;
300 | GCC_NO_COMMON_BLOCKS = YES;
301 | GCC_OPTIMIZATION_LEVEL = 0;
302 | GCC_PREPROCESSOR_DEFINITIONS = (
303 | "DEBUG=1",
304 | "$(inherited)",
305 | );
306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
307 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
308 | GCC_WARN_UNDECLARED_SELECTOR = YES;
309 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
310 | GCC_WARN_UNUSED_FUNCTION = YES;
311 | GCC_WARN_UNUSED_VARIABLE = YES;
312 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
313 | MTL_ENABLE_DEBUG_INFO = YES;
314 | ONLY_ACTIVE_ARCH = YES;
315 | SDKROOT = iphoneos;
316 | TARGETED_DEVICE_FAMILY = "1,2";
317 | };
318 | name = Debug;
319 | };
320 | 97C147041CF9000F007C117D /* Release */ = {
321 | isa = XCBuildConfiguration;
322 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
323 | buildSettings = {
324 | ALWAYS_SEARCH_USER_PATHS = NO;
325 | CLANG_ANALYZER_NONNULL = YES;
326 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
327 | CLANG_CXX_LIBRARY = "libc++";
328 | CLANG_ENABLE_MODULES = YES;
329 | CLANG_ENABLE_OBJC_ARC = YES;
330 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
331 | CLANG_WARN_BOOL_CONVERSION = YES;
332 | CLANG_WARN_COMMA = YES;
333 | CLANG_WARN_CONSTANT_CONVERSION = YES;
334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
335 | CLANG_WARN_EMPTY_BODY = YES;
336 | CLANG_WARN_ENUM_CONVERSION = YES;
337 | CLANG_WARN_INFINITE_RECURSION = YES;
338 | CLANG_WARN_INT_CONVERSION = YES;
339 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
340 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
341 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
342 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
343 | CLANG_WARN_STRICT_PROTOTYPES = YES;
344 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
345 | CLANG_WARN_UNREACHABLE_CODE = YES;
346 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
347 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
348 | COPY_PHASE_STRIP = NO;
349 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
350 | ENABLE_NS_ASSERTIONS = NO;
351 | ENABLE_STRICT_OBJC_MSGSEND = YES;
352 | GCC_C_LANGUAGE_STANDARD = gnu99;
353 | GCC_NO_COMMON_BLOCKS = YES;
354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
356 | GCC_WARN_UNDECLARED_SELECTOR = YES;
357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
358 | GCC_WARN_UNUSED_FUNCTION = YES;
359 | GCC_WARN_UNUSED_VARIABLE = YES;
360 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
361 | MTL_ENABLE_DEBUG_INFO = NO;
362 | SDKROOT = iphoneos;
363 | TARGETED_DEVICE_FAMILY = "1,2";
364 | VALIDATE_PRODUCT = YES;
365 | };
366 | name = Release;
367 | };
368 | 97C147061CF9000F007C117D /* Debug */ = {
369 | isa = XCBuildConfiguration;
370 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
371 | buildSettings = {
372 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
373 | CURRENT_PROJECT_VERSION = 1;
374 | ENABLE_BITCODE = NO;
375 | FRAMEWORK_SEARCH_PATHS = (
376 | "$(inherited)",
377 | "$(PROJECT_DIR)/Flutter",
378 | );
379 | INFOPLIST_FILE = Runner/Info.plist;
380 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
381 | LIBRARY_SEARCH_PATHS = (
382 | "$(inherited)",
383 | "$(PROJECT_DIR)/Flutter",
384 | );
385 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
386 | PRODUCT_NAME = "$(TARGET_NAME)";
387 | VERSIONING_SYSTEM = "apple-generic";
388 | };
389 | name = Debug;
390 | };
391 | 97C147071CF9000F007C117D /* Release */ = {
392 | isa = XCBuildConfiguration;
393 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
394 | buildSettings = {
395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
396 | CURRENT_PROJECT_VERSION = 1;
397 | ENABLE_BITCODE = NO;
398 | FRAMEWORK_SEARCH_PATHS = (
399 | "$(inherited)",
400 | "$(PROJECT_DIR)/Flutter",
401 | );
402 | INFOPLIST_FILE = Runner/Info.plist;
403 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
404 | LIBRARY_SEARCH_PATHS = (
405 | "$(inherited)",
406 | "$(PROJECT_DIR)/Flutter",
407 | );
408 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
409 | PRODUCT_NAME = "$(TARGET_NAME)";
410 | VERSIONING_SYSTEM = "apple-generic";
411 | };
412 | name = Release;
413 | };
414 | /* End XCBuildConfiguration section */
415 |
416 | /* Begin XCConfigurationList section */
417 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
418 | isa = XCConfigurationList;
419 | buildConfigurations = (
420 | 97C147031CF9000F007C117D /* Debug */,
421 | 97C147041CF9000F007C117D /* Release */,
422 | );
423 | defaultConfigurationIsVisible = 0;
424 | defaultConfigurationName = Release;
425 | };
426 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
427 | isa = XCConfigurationList;
428 | buildConfigurations = (
429 | 97C147061CF9000F007C117D /* Debug */,
430 | 97C147071CF9000F007C117D /* Release */,
431 | );
432 | defaultConfigurationIsVisible = 0;
433 | defaultConfigurationName = Release;
434 | };
435 | /* End XCConfigurationList section */
436 | };
437 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
438 | }
439 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/best-flutter/disk_lru_cache/1b3c45adbe20e7769e44d7373553f710f57ee34e/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/example/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'test_disk_cache.dart';
4 |
5 | void main() async {
6 | await testCache();
7 | }
8 |
9 | class MyApp extends StatelessWidget {
10 | // This widget is the root of your application.
11 | @override
12 | Widget build(BuildContext context) {
13 | return new MaterialApp(
14 | title: 'Flutter Demo',
15 | theme: new ThemeData(
16 | // This is the theme of your application.
17 | //
18 | // Try running your application with "flutter run". You'll see the
19 | // application has a blue toolbar. Then, without quitting the app, try
20 | // changing the primarySwatch below to Colors.green and then invoke
21 | // "hot reload" (press "r" in the console where you ran "flutter run",
22 | // or press Run > Flutter Hot Reload in IntelliJ). Notice that the
23 | // counter didn't reset back to zero; the application is not restarted.
24 | primarySwatch: Colors.blue,
25 | ),
26 | home: new MyHomePage(title: 'Flutter Demo Home Page'),
27 | );
28 | }
29 | }
30 |
31 | class MyHomePage extends StatefulWidget {
32 | MyHomePage({Key key, this.title}) : super(key: key);
33 |
34 | // This widget is the home page of your application. It is stateful, meaning
35 | // that it has a State object (defined below) that contains fields that affect
36 | // how it looks.
37 |
38 | // This class is the configuration for the state. It holds the values (in this
39 | // case the title) provided by the parent (in this case the App widget) and
40 | // used by the build method of the State. Fields in a Widget subclass are
41 | // always marked "final".
42 |
43 | final String title;
44 |
45 | @override
46 | _MyHomePageState createState() => new _MyHomePageState();
47 | }
48 |
49 | class _MyHomePageState extends State {
50 | int _counter = 0;
51 |
52 | void _incrementCounter() {
53 | setState(() {
54 | // This call to setState tells the Flutter framework that something has
55 | // changed in this State, which causes it to rerun the build method below
56 | // so that the display can reflect the updated values. If we changed
57 | // _counter without calling setState(), then the build method would not be
58 | // called again, and so nothing would appear to happen.
59 | _counter++;
60 | });
61 | }
62 |
63 | @override
64 | Widget build(BuildContext context) {
65 | // This method is rerun every time setState is called, for instance as done
66 | // by the _incrementCounter method above.
67 | //
68 | // The Flutter framework has been optimized to make rerunning build methods
69 | // fast, so that you can just rebuild anything that needs updating rather
70 | // than having to individually change instances of widgets.
71 | return new Scaffold(
72 | appBar: new AppBar(
73 | // Here we take the value from the MyHomePage object that was created by
74 | // the App.build method, and use it to set our appbar title.
75 | title: new Text(widget.title),
76 | ),
77 | body: new Center(
78 | // Center is a layout widget. It takes a single child and positions it
79 | // in the middle of the parent.
80 | child: new Column(
81 | // Column is also layout widget. It takes a list of children and
82 | // arranges them vertically. By default, it sizes itself to fit its
83 | // children horizontally, and tries to be as tall as its parent.
84 | //
85 | // Invoke "debug paint" (press "p" in the console where you ran
86 | // "flutter run", or select "Toggle Debug Paint" from the Flutter tool
87 | // window in IntelliJ) to see the wireframe for each widget.
88 | //
89 | // Column has various properties to control how it sizes itself and
90 | // how it positions its children. Here we use mainAxisAlignment to
91 | // center the children vertically; the main axis here is the vertical
92 | // axis because Columns are vertical (the cross axis would be
93 | // horizontal).
94 | mainAxisAlignment: MainAxisAlignment.center,
95 | children: [
96 | new Text(
97 | 'You have pushed the button this many times:',
98 | ),
99 | new Text(
100 | '$_counter',
101 | style: Theme.of(context).textTheme.display1,
102 | ),
103 | ],
104 | ),
105 | ),
106 | floatingActionButton: new FloatingActionButton(
107 | onPressed: _incrementCounter,
108 | tooltip: 'Increment',
109 | child: new Icon(Icons.add),
110 | ), // This trailing comma makes auto-formatting nicer for build methods.
111 | );
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/example/lib/test_disk_cache.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 | import 'dart:math' as Math;
4 | import 'dart:typed_data';
5 |
6 | import 'package:disk_lru_cache/_src/disk_lru_cache.dart';
7 | import 'package:disk_lru_cache/disk_lru_cache.dart';
8 | import 'package:http/http.dart';
9 |
10 | Future testCache() async {
11 | int maxSize =
12 | 10 * 1024 * 1024; // 10M,make sure to test rebuild progress below
13 | DiskLruCache cache = new DiskLruCache(
14 | maxSize: maxSize,
15 | directory: new Directory("${Directory.systemTemp.path}/cache"),
16 | filesCount: 1,
17 | opCompactThreshold: 200);
18 | print(cache.directory);
19 | CacheEditor editor;
20 | // write stream
21 | editor = await cache.edit('errorkey');
22 | if (editor != null) {
23 | IOSink sink = await editor.newSink(0);
24 | sink.write('your value');
25 | await sink.flush();
26 |
27 | //remove the file
28 | Iterable values = await cache.values;
29 | values = values.where((CacheEntry entry) {
30 | return entry.key == "errorkey";
31 | });
32 | await values.toList()[0].dirtyFiles[0].delete();
33 |
34 | await sink.close();
35 | await editor.commit();
36 | }
37 |
38 | // write stream
39 | editor = await cache.edit('imagekey');
40 | if (editor != null) {
41 | HttpClient client = new HttpClient();
42 | HttpClientRequest request = await client.openUrl(
43 | "GET",
44 | Uri.parse(
45 | "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1534075481&di=1a90bd266d62bc5edfe1ce84ac38330e&src=http://photocdn.sohu.com/20130517/Img376200804.jpg"));
46 | HttpClientResponse response = await request.close();
47 | Stream> stream = await editor.copyStream(0, response);
48 | // The bytes has been written to disk at this point.
49 | await new ByteStream(stream).toBytes();
50 | await editor.commit();
51 |
52 | // read stream
53 | CacheSnapshot snapshot = await cache.get('imagekey');
54 | Uint8List bytes = await snapshot.getBytes(0);
55 | print(bytes);
56 | }
57 |
58 | String str200k;
59 |
60 | String get200k() {
61 | if (str200k == null) {
62 | StringBuffer sb = new StringBuffer();
63 |
64 | for (int i = 0, c = 200 * 1024; i < c; ++i) {
65 | sb.write("a");
66 | }
67 |
68 | str200k = sb.toString();
69 | }
70 | return str200k;
71 | }
72 |
73 | Future test() async {
74 | // we must wait the file created
75 | List list = [];
76 | List writeDisk = [];
77 | List openWrite = [];
78 |
79 | void editValue(DiskLruCache cache, String key, String value) {
80 | list.add(cache.edit(key).then((CacheEditor editor) {
81 | if (editor != null) {
82 | openWrite.add(editor.newSink(0).then((IOSink sink) async {
83 | writeDisk.add((() async {
84 | if (sink != null) {
85 | sink.write(value);
86 | await sink.close();
87 |
88 | await editor.commit();
89 | } else {
90 | print("Sink is null");
91 | }
92 | })());
93 | }).catchError((e) {
94 | print(e);
95 | }));
96 | } else {
97 | print("Cannot open editor for key $key");
98 | }
99 | }));
100 | }
101 |
102 | Future useCache(DiskLruCache cache) async {
103 | int random() {
104 | // 200k * 100 = 20M
105 | return new Math.Random().nextInt(100);
106 | }
107 |
108 | //we open 10 files a time
109 | for (int i = 0; i < 10; ++i) {
110 | editValue(cache, "${random()}", get200k());
111 | String key = "${random()}";
112 | cache.get(key).then((CacheSnapshot s) {
113 | if (s == null) {
114 | print('Cache miss $key');
115 | return;
116 | }
117 | s.getString(0).then((String str) {
118 | print("Cache hit $key=$str");
119 | });
120 | });
121 | //cache.remove("${random()}");
122 | }
123 | }
124 |
125 | await useCache(cache);
126 |
127 | await Future.wait(list);
128 | await Future.wait(openWrite);
129 | await Future.wait(writeDisk);
130 | }
131 |
132 | // our operation times must > 2000,so that we can test rebuild record file.
133 | for (int i = 0; i < 10; ++i) {
134 | await test();
135 | }
136 |
137 | Iterable entries = await cache.values;
138 |
139 | List> list = [];
140 | for (CacheEntry entry in entries) {
141 | list.add(cache.remove(entry.key));
142 | }
143 | await Future.wait(list);
144 |
145 | assert(cache.size == 0);
146 |
147 | await cache.close();
148 |
149 | print("Cache size : ${cache.size / 1024 / 1024} m ");
150 |
151 | assert(cache.size < maxSize);
152 | }
153 |
--------------------------------------------------------------------------------
/example/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "2.0.11"
11 | args:
12 | dependency: transitive
13 | description:
14 | name: args
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "1.5.2"
18 | async:
19 | dependency: transitive
20 | description:
21 | name: async
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "2.4.0"
25 | boolean_selector:
26 | dependency: transitive
27 | description:
28 | name: boolean_selector
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.0.5"
32 | charcode:
33 | dependency: transitive
34 | description:
35 | name: charcode
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "1.1.2"
39 | collection:
40 | dependency: transitive
41 | description:
42 | name: collection
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "1.14.11"
46 | convert:
47 | dependency: transitive
48 | description:
49 | name: convert
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "2.1.1"
53 | crypto:
54 | dependency: transitive
55 | description:
56 | name: crypto
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "2.1.3"
60 | cupertino_icons:
61 | dependency: "direct main"
62 | description:
63 | name: cupertino_icons
64 | url: "https://pub.flutter-io.cn"
65 | source: hosted
66 | version: "0.1.2"
67 | disk_lru_cache:
68 | dependency: "direct main"
69 | description:
70 | path: ".."
71 | relative: true
72 | source: path
73 | version: "0.0.2"
74 | flutter:
75 | dependency: "direct main"
76 | description: flutter
77 | source: sdk
78 | version: "0.0.0"
79 | flutter_test:
80 | dependency: "direct dev"
81 | description: flutter
82 | source: sdk
83 | version: "0.0.0"
84 | http:
85 | dependency: "direct main"
86 | description:
87 | name: http
88 | url: "https://pub.flutter-io.cn"
89 | source: hosted
90 | version: "0.12.0+4"
91 | http_parser:
92 | dependency: transitive
93 | description:
94 | name: http_parser
95 | url: "https://pub.flutter-io.cn"
96 | source: hosted
97 | version: "3.1.3"
98 | image:
99 | dependency: transitive
100 | description:
101 | name: image
102 | url: "https://pub.flutter-io.cn"
103 | source: hosted
104 | version: "2.1.4"
105 | matcher:
106 | dependency: transitive
107 | description:
108 | name: matcher
109 | url: "https://pub.flutter-io.cn"
110 | source: hosted
111 | version: "0.12.6"
112 | meta:
113 | dependency: transitive
114 | description:
115 | name: meta
116 | url: "https://pub.flutter-io.cn"
117 | source: hosted
118 | version: "1.1.8"
119 | path:
120 | dependency: transitive
121 | description:
122 | name: path
123 | url: "https://pub.flutter-io.cn"
124 | source: hosted
125 | version: "1.6.4"
126 | pedantic:
127 | dependency: transitive
128 | description:
129 | name: pedantic
130 | url: "https://pub.flutter-io.cn"
131 | source: hosted
132 | version: "1.8.0+1"
133 | petitparser:
134 | dependency: transitive
135 | description:
136 | name: petitparser
137 | url: "https://pub.flutter-io.cn"
138 | source: hosted
139 | version: "2.4.0"
140 | quiver:
141 | dependency: transitive
142 | description:
143 | name: quiver
144 | url: "https://pub.flutter-io.cn"
145 | source: hosted
146 | version: "2.0.5"
147 | sky_engine:
148 | dependency: transitive
149 | description: flutter
150 | source: sdk
151 | version: "0.0.99"
152 | source_span:
153 | dependency: transitive
154 | description:
155 | name: source_span
156 | url: "https://pub.flutter-io.cn"
157 | source: hosted
158 | version: "1.5.5"
159 | stack_trace:
160 | dependency: transitive
161 | description:
162 | name: stack_trace
163 | url: "https://pub.flutter-io.cn"
164 | source: hosted
165 | version: "1.9.3"
166 | stream_channel:
167 | dependency: transitive
168 | description:
169 | name: stream_channel
170 | url: "https://pub.flutter-io.cn"
171 | source: hosted
172 | version: "2.0.0"
173 | string_scanner:
174 | dependency: transitive
175 | description:
176 | name: string_scanner
177 | url: "https://pub.flutter-io.cn"
178 | source: hosted
179 | version: "1.0.5"
180 | synchronized:
181 | dependency: transitive
182 | description:
183 | name: synchronized
184 | url: "https://pub.flutter-io.cn"
185 | source: hosted
186 | version: "2.1.1"
187 | term_glyph:
188 | dependency: transitive
189 | description:
190 | name: term_glyph
191 | url: "https://pub.flutter-io.cn"
192 | source: hosted
193 | version: "1.1.0"
194 | test_api:
195 | dependency: transitive
196 | description:
197 | name: test_api
198 | url: "https://pub.flutter-io.cn"
199 | source: hosted
200 | version: "0.2.11"
201 | typed_data:
202 | dependency: transitive
203 | description:
204 | name: typed_data
205 | url: "https://pub.flutter-io.cn"
206 | source: hosted
207 | version: "1.1.6"
208 | vector_math:
209 | dependency: transitive
210 | description:
211 | name: vector_math
212 | url: "https://pub.flutter-io.cn"
213 | source: hosted
214 | version: "2.0.8"
215 | xml:
216 | dependency: transitive
217 | description:
218 | name: xml
219 | url: "https://pub.flutter-io.cn"
220 | source: hosted
221 | version: "3.5.0"
222 | sdks:
223 | dart: ">=2.5.0 <3.0.0"
224 | flutter: ">=0.1.4 <3.0.0"
225 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: example
2 | description: A new Flutter project.
3 |
4 | dependencies:
5 | flutter:
6 | sdk: flutter
7 |
8 | disk_lru_cache:
9 | path: ../
10 |
11 | http:
12 | cupertino_icons: ^0.1.2
13 |
14 | dev_dependencies:
15 | flutter_test:
16 | sdk: flutter
17 |
18 |
19 |
20 | flutter:
21 | uses-material-design: true
22 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties
5 | // are correct.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_test/flutter_test.dart';
9 |
10 | import 'package:example/main.dart';
11 |
12 | void main() {
13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
14 | // Build our app and trigger a frame.
15 | await tester.pumpWidget(new MyApp());
16 |
17 | // Verify that our counter starts at 0.
18 | expect(find.text('0'), findsOneWidget);
19 | expect(find.text('1'), findsNothing);
20 |
21 | // Tap the '+' icon and trigger a frame.
22 | await tester.tap(find.byIcon(Icons.add));
23 | await tester.pump();
24 |
25 | // Verify that our counter has incremented.
26 | expect(find.text('0'), findsNothing);
27 | expect(find.text('1'), findsOneWidget);
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/flutter_01.log:
--------------------------------------------------------------------------------
1 | Flutter crash report; please file at https://github.com/flutter/flutter/issues.
2 |
3 | ## command
4 |
5 | flutter --no-color packages get
6 |
7 | ## exception
8 |
9 | YamlException: Error on line 14, column 1: Could not find expected ':' for simple key.
10 | s
11 | ^
12 |
13 | ```
14 | #0 Scanner._removeSimpleKey (package:yaml/src/scanner.dart:526:7)
15 | #1 Scanner._fetchStreamEnd (package:yaml/src/scanner.dart:598:5)
16 | #2 Scanner._fetchNextToken (package:yaml/src/scanner.dart:356:7)
17 | #3 Scanner._fetchMoreTokens (package:yaml/src/scanner.dart:339:7)
18 | #4 Scanner.peek (package:yaml/src/scanner.dart:317:27)
19 | #5 Parser._parseBlockMappingKey (package:yaml/src/parser.dart:418:26)
20 | #6 Parser._stateMachine (package:yaml/src/parser.dart:86:16)
21 | #7 Parser.parse (package:yaml/src/parser.dart:47:19)
22 | #8 Loader._loadMapping (package:yaml/src/loader.dart:171:23)
23 | #9 Loader._loadNode (package:yaml/src/loader.dart:86:16)
24 | #10 Loader._loadDocument (package:yaml/src/loader.dart:62:20)
25 | #11 Loader.load (package:yaml/src/loader.dart:54:20)
26 | #12 loadYamlDocument (package:yaml/yaml.dart:51:25)
27 | #13 loadYamlNode (package:yaml/yaml.dart:42:5)
28 | #14 loadYaml (package:yaml/yaml.dart:34:5)
29 | #15 FlutterManifest.createFromString (package:flutter_tools/src/flutter_manifest.dart:42:28)
30 |
31 | #16 FlutterManifest.createFromPath (package:flutter_tools/src/flutter_manifest.dart:36:12)
32 |
33 | #17 FlutterProject._readManifest (package:flutter_tools/src/project.dart:120:60)
34 |
35 | #18 FlutterProject.fromDirectory (package:flutter_tools/src/project.dart:41:44)
36 |
37 | #19 FlutterProject.fromPath (package:flutter_tools/src/project.dart:56:58)
38 | #20 PackagesGetCommand.runCommand (package:flutter_tools/src/commands/packages.dart:83:61)
39 |
40 | #21 FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:348:18)
41 | #22 _asyncThenWrapperHelper. (dart:async/runtime/libasync_patch.dart:77:64)
42 | #23 _rootRunUnary (dart:async/zone.dart:1132:38)
43 | #24 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
44 | #25 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
45 | #26 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:642:45)
46 | #27 Future._propagateToListeners (dart:async/future_impl.dart:671:32)
47 | #28 Future._complete (dart:async/future_impl.dart:476:7)
48 | #29 _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
49 | #30 _AsyncAwaitCompleter.complete. (dart:async/runtime/libasync_patch.dart:33:20)
50 | #31 _rootRun (dart:async/zone.dart:1124:13)
51 | #32 _CustomZone.run (dart:async/zone.dart:1021:19)
52 | #33 _CustomZone.bindCallback. (dart:async/zone.dart:947:23)
53 | #34 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
54 | #35 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
55 | #36 _runPendingImmediateCallback (dart:isolate/runtime/libisolate_patch.dart:114:13)
56 | #37 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:170:5)
57 | ```
58 |
59 | ## flutter doctor
60 |
61 | ```
62 | [✓] Flutter (Channel beta, v0.6.0, on Mac OS X 10.13.3 17D47, locale zh-Hans-CN)
63 | • Flutter version 0.6.0 at /Users/jzoom/working/flutter
64 | • Framework revision 9299c02cf7 (4 weeks ago), 2018-08-16 00:35:12 +0200
65 | • Engine revision e3687f70c7
66 | • Dart version 2.1.0-dev.0.0.flutter-be6309690f
67 |
68 | [✓] Android toolchain - develop for Android devices (Android SDK 27.0.3)
69 | • Android SDK at /Users/jzoom/Library/Android/sdk
70 | • Android NDK at /Users/jzoom/Library/Android/sdk/ndk-bundle
71 | • Platform android-27, build-tools 27.0.3
72 | • ANDROID_HOME = /Users/jzoom/Library/Android/sdk
73 | • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
74 | • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
75 | • All Android licenses accepted.
76 |
77 | [✓] iOS toolchain - develop for iOS devices (Xcode 9.4.1)
78 | • Xcode at /Applications/Xcode.app/Contents/Developer
79 | • Xcode 9.4.1, Build version 9F2000
80 | • ios-deploy 1.9.2
81 | • CocoaPods version 1.5.2
82 |
83 | [✓] Android Studio (version 3.1)
84 | • Android Studio at /Applications/Android Studio.app/Contents
85 | • Flutter plugin version 27.1.1
86 | • Dart plugin version 173.4700
87 | • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
88 |
89 | [!] IntelliJ IDEA Community Edition (version 2018.1.5)
90 | • IntelliJ at /Applications/IntelliJ IDEA CE.app
91 | ✗ Flutter plugin not installed; this adds Flutter specific functionality.
92 | ✗ Dart plugin not installed; this adds Dart specific functionality.
93 | • For information about installing plugins, see
94 | https://flutter.io/intellij-setup/#installing-the-plugins
95 |
96 | [✓] VS Code (version 1.26.1)
97 | • VS Code at /Applications/Visual Studio Code.app/Contents
98 | • Flutter extension version 2.18.0
99 |
100 | [✓] Connected devices (2 available)
101 | • Android SDK built for x86 • emulator-5554 • android-x86 • Android 8.1.0 (API 27) (emulator)
102 | • iPhone 6s • A797D8CC-2D5D-401B-9634-6D56B30FC76E • ios • iOS 11.4 (simulator)
103 |
104 | ! Doctor found issues in 1 category.
105 | ```
106 |
--------------------------------------------------------------------------------
/lib/_src/disk_lru_cache.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 | import 'dart:io';
4 | import 'dart:typed_data';
5 | import 'dart:ui' as ui show instantiateImageCodec, Codec;
6 |
7 | import 'package:disk_lru_cache/_src/ioutil.dart';
8 | import 'package:disk_lru_cache/_src/lru_map.dart';
9 | import 'package:flutter/foundation.dart';
10 | import 'package:flutter/material.dart';
11 | import 'package:synchronized/synchronized.dart';
12 |
13 | ///
14 | const _ = null;
15 |
16 | ///
17 | class DiskLruCache implements Closeable {
18 | static const MAGIC = "dart.lrucache";
19 | static const VERSION = "0.0.1";
20 | static const ANY_SEQUENCE_NUMBER = -1;
21 |
22 | static const READ = "READ";
23 | static const DIRTY = "DIRTY";
24 | static const CLEAN = "CLEAN";
25 | static const REMOVE = "REMOVE";
26 |
27 | static const MAX_OP_COUNT = 2000;
28 |
29 | /// Record every operation in this file.
30 | final File _recordFile;
31 |
32 | final int opCompactThreshold;
33 |
34 | /// Used when rebuild record file if necessary
35 | final File _recordFileTmp;
36 |
37 | final File _recordFileBackup;
38 |
39 | /// directory to store caches
40 | final Directory directory;
41 |
42 | /// The maximum number of bytes that this cache should use to store its data.
43 | final int maxSize;
44 |
45 | /// How many files a key/CacheEntry contains?
46 | final int _filesCount;
47 |
48 | /// store entries in memory,so that we can find our cache quickly
49 | final LruMap _lruEntries;
50 |
51 | int _opCount = 0;
52 |
53 | bool _initialized = false;
54 | bool _hasRecordError = false;
55 |
56 | bool _closed = false;
57 |
58 | /// Cache size in bytes
59 | int _size = 0;
60 |
61 | final Lock lock = new Lock(reentrant: true);
62 |
63 | /// Total size in bytes in file system.
64 | int get size => _size;
65 |
66 | bool _mostRecentTrimFailed = false;
67 |
68 | /// IOSink for record file
69 | IOSink _recordWriter;
70 |
71 | int _sequenceNumber = 0;
72 |
73 | DiskLruCache(
74 | {Directory directory,
75 | this.maxSize: 20 * 1024 * 1024,
76 | int filesCount: 2,
77 | this.opCompactThreshold: MAX_OP_COUNT})
78 | : assert(directory != null),
79 | this.directory = directory,
80 | _filesCount = filesCount,
81 | _lruEntries = new LruMap(),
82 | _recordFile = new File("${directory.path}/record"),
83 | _recordFileTmp = new File("${directory.path}/record.tmp"),
84 | _recordFileBackup = new File("${directory.path}/record.bak");
85 |
86 | /// Returns a snapshot of the entry named key, or null if it doesn't exist is not currently
87 | /// readable. If a value is returned, it is moved to the tail of the LRU queue.
88 | Future get(String key) {
89 | return lock.synchronized(() async {
90 | await _lazyInit();
91 | CacheEntry entry = _lruEntries[key];
92 | if (entry == null || !entry.ready) {
93 | return _;
94 | }
95 |
96 | CacheSnapshot snapshot = await entry.snapshot();
97 | if (snapshot == null) {
98 | return null;
99 | }
100 |
101 | await _recordRead(key);
102 |
103 | return snapshot;
104 | });
105 | }
106 |
107 | Future clean() {
108 | return lock.synchronized(() async {
109 | Iterable entries = await values;
110 | List> list = [];
111 | for (CacheEntry entry in entries) {
112 | list.add(remove(entry.key));
113 | }
114 | return await Future.wait(list);
115 | });
116 | }
117 |
118 | Future edit(String key,
119 | {int sequenceNumber: ANY_SEQUENCE_NUMBER}) {
120 | return lock.synchronized(() async {
121 | await _lazyInit();
122 |
123 | CacheEntry entry = _lruEntries[key];
124 |
125 | if ((entry == null || entry.sequenceNumber != sequenceNumber) &&
126 | sequenceNumber != ANY_SEQUENCE_NUMBER) {
127 | //the cache is stale
128 | return null;
129 | }
130 | if (entry != null && entry.currentEditor != null) {
131 | return null; // Another edit is in progress.
132 | }
133 |
134 | //Flush the record before creating files to prevent file leaks.
135 | await _recordDirty(key);
136 |
137 | if (entry == null) {
138 | entry = new CacheEntry(
139 | key: key,
140 | cache: this,
141 | );
142 | _lruEntries[key] = entry;
143 | }
144 |
145 | CacheEditor editor = new CacheEditor._(entry: entry, cache: this);
146 | entry.currentEditor = editor;
147 | return editor;
148 | });
149 | }
150 |
151 | Future _recordRead(String key) async {
152 | ++_opCount;
153 | _recordWriter.write("$READ $key\n");
154 | await _recordWriter.flush();
155 | if (_needsRebuild()) {
156 | await _cleanUp();
157 | }
158 | }
159 |
160 | Future _recordDirty(String key) async {
161 | ++_opCount;
162 | _recordWriter.write("$DIRTY $key\n");
163 | await _recordWriter.flush();
164 | if (_needsRebuild()) {
165 | await _cleanUp();
166 | }
167 | }
168 |
169 | Future _recordClean(String key, List lengths) async {
170 | ++_opCount;
171 | _recordWriter.write("$CLEAN $key");
172 | for (int length in lengths) {
173 | _recordWriter.write(" $length");
174 | }
175 | _recordWriter.write("\n");
176 | await _recordWriter.flush();
177 | if (_needsRebuild() || _size > maxSize) {
178 | await _cleanUp();
179 | }
180 | }
181 |
182 | Future _recordRemove(String key) async {
183 | ++_opCount;
184 | _recordWriter.write("$REMOVE $key\n");
185 | await _recordWriter.flush();
186 | if (_needsRebuild()) {
187 | await _cleanUp();
188 | }
189 | }
190 |
191 | /// We only rebuild record file when opCount is at least MAX_OP_COUNT
192 | bool _needsRebuild() {
193 | return _opCount >= opCompactThreshold && _opCount >= _lruEntries.length;
194 | }
195 |
196 | Future _trimToSize() async {
197 | while (_size > maxSize) {
198 | CacheEntry toEvict = _lruEntries.removeHead();
199 | await _removeEntry(toEvict);
200 | }
201 | _mostRecentTrimFailed = false;
202 | }
203 |
204 | Future _cleanUp() {
205 | return lock.synchronized(() async {
206 | try {
207 | print("Start cleanup");
208 | await _trimToSize();
209 | if (_needsRebuild()) {
210 | await _rebuildRecord();
211 | }
212 | print("Cleanup success");
213 | } catch (e) {
214 | print("Cleanup failed! $e");
215 | }
216 | });
217 | }
218 |
219 | Future _rebuildRecord() {
220 | return lock.synchronized(() async {
221 | print("Start to rebuild record");
222 | if (_recordWriter != null) {
223 | await _recordWriter.close();
224 | }
225 |
226 | if (!await this.directory.exists()) {
227 | await this.directory.create(recursive: true);
228 | }
229 |
230 | IOSink writer = _recordFileTmp.openWrite();
231 | try {
232 | // write headers
233 | writer.write("$MAGIC\n$VERSION\n$_filesCount\n\n");
234 | //write entries
235 | for (CacheEntry entry in _lruEntries.values) {
236 | entry._writeTo(writer);
237 | }
238 | await writer.flush();
239 | } catch (e) {
240 | print("Cannot write file at this time $e");
241 | return _;
242 | } finally {
243 | try {
244 | await writer.close();
245 | } catch (e) {
246 | print("Cannot write file at this time $e");
247 | return _;
248 | }
249 | }
250 |
251 | if (await _recordFile.exists()) {
252 | await _recordFile.rename(_recordFileBackup.path);
253 | }
254 |
255 | await _recordFileTmp.rename(_recordFile.path);
256 | await _deleteSafe(_recordFileBackup);
257 |
258 | _recordWriter = _newRecordWriter();
259 | _hasRecordError = false;
260 |
261 | print("Rebuild record success!");
262 | });
263 | }
264 |
265 | ///
266 | IOSink _newRecordWriter() {
267 | return new IOSinkProxy(_recordFile.openWrite(mode: FileMode.append),
268 | onError: (e) async {
269 | _hasRecordError = true;
270 | //_rebuildRecord();
271 | });
272 | }
273 |
274 | /// Read record file, rebuild it if broken.
275 | Future _lazyInit() {
276 | return lock.synchronized(() async {
277 | if (_initialized) {
278 | return _;
279 | }
280 | if (!await this.directory.exists()) {
281 | await this.directory.create(recursive: true);
282 | }
283 |
284 | // If a bkp file exists, use it instead.
285 | if (await _recordFileBackup.exists()) {
286 | // If recod file also exists just delete backup file.
287 | if (await _recordFile.exists()) {
288 | await _recordFileBackup.delete();
289 | } else {
290 | _recordFileBackup.rename(_recordFile.path);
291 | }
292 | }
293 |
294 | if (await _recordFile.exists()) {
295 | try {
296 | await _parseRecordFile();
297 | await _processRecords();
298 | _initialized = true;
299 | return _;
300 | } catch (e) {
301 | print("DiskLruCache error when init $e");
302 | try {
303 | await _deleteCache();
304 | } catch (e) {}
305 | }
306 | }
307 | await _rebuildRecord();
308 | _initialized = true;
309 | });
310 | }
311 |
312 | Future _deleteCache() async {
313 | await close();
314 | await directory.delete(recursive: true);
315 | }
316 |
317 | /// make copy of current values
318 | Future> get values {
319 | return lock.synchronized(() async {
320 | await _lazyInit();
321 | return List.from(_lruEntries.values);
322 | });
323 | }
324 |
325 | Future _parseRecordFile() async {
326 | try {
327 | List lines = await _recordFile.readAsLines();
328 | if (lines.length < 4) {
329 | throw new Exception("The record file is broken: Too small to parse");
330 | }
331 | String magic = lines[0];
332 | String version = lines[1];
333 | String filesCountString = lines[2];
334 | String blank = lines[3];
335 |
336 | if (magic != MAGIC ||
337 | version != VERSION ||
338 | filesCountString != this._filesCount.toString() ||
339 | blank != '') {
340 | throw new Exception(
341 | "The record file is broken: unexpected file header:[$magic,$version,$filesCountString,$blank]");
342 | }
343 |
344 | int lineCount = 0;
345 | for (int i = 4, c = lines.length; i < c; ++i) {
346 | _parseRecordLine(lines[i]);
347 | ++lineCount;
348 | }
349 |
350 | _opCount = lineCount - _lruEntries.length;
351 |
352 | _recordWriter = _newRecordWriter();
353 | } catch (e) {
354 | print(e);
355 | rethrow;
356 | }
357 | }
358 |
359 | void _parseRecordLine(String line) {
360 | int firstSpace = line.indexOf(' ');
361 | if (firstSpace == -1) {
362 | throw new Exception("unexpected record line: " + line);
363 | }
364 |
365 | int keyBegin = firstSpace + 1;
366 | int secondSpace = line.indexOf(' ', keyBegin);
367 | String key;
368 | if (secondSpace == -1) {
369 | key = line.substring(keyBegin);
370 | if (firstSpace == REMOVE.length && line.startsWith(REMOVE)) {
371 | _lruEntries.remove(key);
372 | return;
373 | }
374 | } else {
375 | key = line.substring(keyBegin, secondSpace);
376 | }
377 |
378 | CacheEntry entry = _lruEntries[key];
379 | if (entry == null) {
380 | entry = new CacheEntry(
381 | key: key,
382 | cache: this,
383 | );
384 | _lruEntries[key] = entry;
385 | }
386 |
387 | if (secondSpace != -1 &&
388 | firstSpace == CLEAN.length &&
389 | line.startsWith(CLEAN)) {
390 | List parts = line.substring(secondSpace + 1).split(" ");
391 | entry.ready = true;
392 | entry.currentEditor = null;
393 | entry
394 | .setLengths(parts.map((String length) => int.parse(length)).toList());
395 | } else if (secondSpace == -1 &&
396 | firstSpace == DIRTY.length &&
397 | line.startsWith(DIRTY)) {
398 | entry.currentEditor = new CacheEditor._(entry: entry, cache: this);
399 | } else if (secondSpace == -1 &&
400 | firstSpace == READ.length &&
401 | line.startsWith(READ)) {
402 | // This work was already done by calling lruEntries.get().
403 | } else {
404 | throw new Exception("unexpected journal line: " + line);
405 | }
406 | }
407 |
408 | /// Close the cache, do some clean stuff, it is an error to use cache when cache is closed.
409 | @override
410 | Future close() {
411 | return lock.synchronized(() async {
412 | if (_closed) return _;
413 | try {
414 | if (_recordWriter != null) {
415 | await _recordWriter.close();
416 | _recordWriter = null;
417 | }
418 | } finally {
419 | _closed = true;
420 | _initialized = false;
421 | }
422 | print("Cache is closed");
423 | return _;
424 | });
425 | }
426 |
427 | Future remove(String key) {
428 | return lock.synchronized(() async {
429 | await _lazyInit();
430 | CacheEntry entry = _lruEntries[key];
431 | if (entry == null) return false;
432 | await _removeEntry(entry);
433 | return true;
434 | });
435 | }
436 |
437 | /// Error when read the cache stream, the cache must be removed
438 | void _onCacheReadError(String key, e) {
439 | remove(key);
440 | }
441 |
442 | Future _processRecords() async {
443 | await _deleteSafe(_recordFileTmp);
444 |
445 | List list = List.of(_lruEntries.values);
446 | int size = 0;
447 | for (CacheEntry entry in list) {
448 | if (entry.currentEditor == null) {
449 | for (int t = 0; t < _filesCount; t++) {
450 | size += entry.lengths[t];
451 | }
452 | } else {
453 | entry.currentEditor = null;
454 | for (int t = 0; t < _filesCount; t++) {
455 | await _deleteSafe(entry.cleanFiles[t]);
456 | await _deleteSafe(entry.dirtyFiles[t]);
457 | }
458 | _lruEntries.remove(entry.key);
459 | }
460 | }
461 |
462 | _size = size;
463 | }
464 |
465 | Future _deleteSafe(File file) async {
466 | if (await file.exists()) {
467 | try {
468 | await file.delete();
469 | } catch (e) {
470 | //if the file cannot be deleted,may be OS errors.
471 | }
472 | }
473 | }
474 |
475 | /// clean the entry,remove from cache
476 | Future _rollback(CacheEditor editor) {
477 | return lock.synchronized(() async {
478 | CacheEntry entry = editor.entry;
479 | entry.currentEditor = null;
480 | await Future.wait(entry.dirtyFiles.map(_deleteSafe));
481 |
482 | if (entry.ready) {
483 | await _recordClean(entry.key, entry.lengths);
484 | } else {
485 | await _recordRemove(entry.key);
486 | }
487 | });
488 | }
489 |
490 | Future _complete(CacheEditor editor) async {
491 | try {
492 | await _commit(editor);
493 | } catch (e) {
494 | print("Error $e when commit $editor");
495 | await _rollback(editor);
496 | }
497 | }
498 |
499 | Future _commit(CacheEditor editor) {
500 | return lock.synchronized(() async {
501 | CacheEntry entry = editor.entry;
502 | if (entry.currentEditor != editor) {
503 | throw new Exception("Commit editor's entry did not match the editor");
504 | }
505 |
506 | if (!entry.ready) {
507 | if (!editor.hasValues.every((bool value) => value)) {
508 | _rollback(editor);
509 | return _;
510 | }
511 | for (File file in editor.entry.dirtyFiles) {
512 | if (!await file.exists()) {
513 | _rollback(editor);
514 | return _;
515 | }
516 | }
517 | }
518 | int index = 0;
519 | for (File dirty in editor.entry.dirtyFiles) {
520 | File clean = entry.cleanFiles[index];
521 | await dirty.rename(clean.path);
522 | int oldLength = entry.lengths[index];
523 | int newLength = await clean.length();
524 | entry.lengths[index] = newLength;
525 | _size = _size - oldLength + newLength;
526 | ++index;
527 | }
528 |
529 | entry.sequenceNumber = _sequenceNumber++;
530 |
531 | entry.ready = true;
532 | entry.currentEditor = null;
533 |
534 | await _recordClean(entry.key, entry.lengths);
535 | });
536 | }
537 |
538 | Future _removeEntry(CacheEntry entry) async {
539 | if (entry.currentEditor != null) {
540 | // Prevent the edit from completing normally.
541 | entry.currentEditor.detach();
542 | }
543 |
544 | for (int i = 0; i < _filesCount; i++) {
545 | await _deleteSafe(entry.cleanFiles[i]);
546 | _size -= entry.lengths[i];
547 | entry.lengths[i] = 0;
548 | }
549 | await _recordRemove(entry.key);
550 | return true;
551 | }
552 | }
553 |
554 | class CacheEditor {
555 | final CacheEntry entry;
556 |
557 | final DiskLruCache cache;
558 |
559 | // If a cache is first created, it must has value for all of the files.
560 | final List hasValues;
561 |
562 | ///
563 | bool _done = false;
564 |
565 | final Lock lock = new Lock();
566 |
567 | CacheEditor._({this.entry, this.cache})
568 | : assert(entry != null),
569 | assert(cache != null),
570 | hasValues = new List(cache._filesCount)
571 | ..fillRange(0, cache._filesCount, false);
572 |
573 | Future detach() {
574 | return lock.synchronized(() async {
575 | if (entry.currentEditor == this) {
576 | for (int i = 0, c = cache._filesCount; i < c; i++) {
577 | await cache._deleteSafe(entry.dirtyFiles[i]);
578 | }
579 | entry.currentEditor = null;
580 | }
581 | });
582 | }
583 |
584 | @override
585 | String toString() {
586 | return "Editor {key: ${entry.key}, done: $_done}";
587 | }
588 |
589 | Future commit() async {
590 | return cache.lock.synchronized(() async {
591 | if (_done) {
592 | return;
593 | }
594 | if (entry.currentEditor == this) {
595 | await cache._complete(this);
596 | }
597 | _done = true;
598 | });
599 | }
600 |
601 | ///
602 | /// Return a stream that copy it's data to IOSink when read
603 | ///
604 | Future>> copyStream(
605 | int index, Stream> stream) async {
606 | IOSink sink = await newSink(index);
607 | return new CloseableStream(stream, onData: (List data) {
608 | sink.add(data);
609 | }, onDone: () {
610 | sink.close();
611 | }, onError: (e) {
612 | sink.addError(e);
613 | });
614 | }
615 |
616 | Future newSink(int index) {
617 | return cache.lock.synchronized(() {
618 | if (_done) {
619 | throw new Exception("The editor is finish done it's job");
620 | }
621 |
622 | if (entry.currentEditor != this) {
623 | return new EmptyIOSink();
624 | }
625 |
626 | if (!entry.ready) {
627 | hasValues[index] = true;
628 | }
629 |
630 | File dirtyFile = entry.dirtyFiles[index];
631 | // this sink do not throw exception
632 | return new IOSinkProxy(dirtyFile.openWrite(), onError: (e) async {
633 | print("Error when write to disk cache");
634 | await detach();
635 | });
636 | });
637 | }
638 | }
639 |
640 | class CacheEntry {
641 | final List cleanFiles;
642 | final List dirtyFiles;
643 | final List lengths;
644 |
645 | CacheEditor currentEditor;
646 |
647 | // This value is true when all the files in this entry can be read.
648 | bool ready = false;
649 |
650 | final String key;
651 |
652 | final DiskLruCache cache;
653 |
654 | int sequenceNumber;
655 |
656 | CacheEntry({this.key, this.cache, this.sequenceNumber})
657 | : cleanFiles = new List(cache._filesCount),
658 | dirtyFiles = new List(cache._filesCount),
659 | lengths = new List(cache._filesCount) {
660 | // The names are repetitive so re-use the same builder to avoid allocations.
661 | for (int i = 0; i < cache._filesCount; i++) {
662 | cleanFiles[i] = new File("${cache.directory.path}/$key.$i");
663 | dirtyFiles[i] = new File("${cache.directory.path}/$key.$i.tmp");
664 |
665 | this.lengths[i] = 0;
666 | }
667 | }
668 |
669 | int get size {
670 | int _size = 0;
671 | for (int i = 0, c = lengths.length; i < c; ++i) {
672 | _size += lengths[i];
673 | }
674 | return _size;
675 | }
676 |
677 | String toString() {
678 | return "CacheEntry{key:$key}";
679 | }
680 |
681 | void _onStreamError(e) {
682 | this.cache._onCacheReadError(key, e);
683 | }
684 |
685 | void setLengths(List lengths) {
686 | List.writeIterable(this.lengths, 0, lengths);
687 | }
688 |
689 | Future snapshot() async {
690 | int filesCount = cache._filesCount;
691 | List>> streams = new List(filesCount);
692 | for (int i = 0; i < filesCount; ++i) {
693 | if (await cleanFiles[i].exists()) {
694 | try {
695 | streams[i] = new CloseableStream(cleanFiles[i].openRead(),
696 | onError: _onStreamError);
697 | } catch (e) {
698 | print("Open file read error $e");
699 | return null;
700 | }
701 | } else {
702 | await Future.wait(cleanFiles.map(cache._deleteSafe));
703 | //File not found,then the cache is not exists,remove this cache
704 | this.cache._onCacheReadError(
705 | key, new FileSystemException("File [${cleanFiles[i]}] not found"));
706 | return null;
707 | }
708 | }
709 | try {
710 | return new CacheSnapshot(streams: streams, lengths: lengths, key: key);
711 | } catch (e) {
712 | print(e);
713 | rethrow;
714 | }
715 | }
716 |
717 | void _writeTo(IOSink writer) {
718 | if (currentEditor != null) {
719 | writer.write("${DiskLruCache.DIRTY} $key\n");
720 | } else {
721 | writer.write("${DiskLruCache.CLEAN} $key");
722 | for (int length in lengths) {
723 | writer.write(" $length");
724 | }
725 | writer.write("\n");
726 | }
727 | }
728 | }
729 |
730 | ///
731 | class CacheSnapshot implements Closeable {
732 | final List>> streams;
733 | final List lengths;
734 | final String key;
735 |
736 | CacheSnapshot(
737 | {this.key, List>> streams, this.lengths})
738 | : assert(
739 | streams != null && streams.length > 0, "Streams is null or empty"),
740 | streams = List.unmodifiable(streams);
741 |
742 | Future getBytes(int index) async {
743 | final completer = Completer();
744 | final sink = ByteConversionSink.withCallback(
745 | (bytes) => completer.complete(Uint8List.fromList(bytes)),
746 | );
747 | getStream(index).listen(
748 | sink.add,
749 | onError: completer.completeError,
750 | onDone: sink.close,
751 | cancelOnError: true,
752 | );
753 | return completer.future;
754 | }
755 |
756 | @override
757 | String toString() {
758 | return "CacheSnapshot:{count:${lengths.length}, key:$key}";
759 | }
760 |
761 | Future getString(int index, {Encoding encoding: utf8}) {
762 | return IoUtil.stream2String(getStream(index), encoding);
763 | }
764 |
765 | Stream> getStream(int index) {
766 | assert(index >= 0 && index < streams.length);
767 | return streams[index];
768 | }
769 |
770 | @override
771 | Future close() {
772 | List list = [];
773 | for (CloseableStream> stream in streams) {
774 | list.add(stream.close());
775 | }
776 | return Future.wait(list);
777 | }
778 | }
779 |
--------------------------------------------------------------------------------
/lib/_src/ioutil.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 | import 'dart:io';
4 |
5 | ///
6 | /// When a Stream is receiving events, this class also receiving the same events.
7 | ///
8 | class CloseableStream extends Stream implements Closeable {
9 | StreamSubscription _streamSubscription;
10 |
11 | final Stream _stream;
12 | final void Function(T event) onData;
13 | final void Function() onDone;
14 | final Function onError;
15 |
16 | CloseableStream(
17 | this._stream, {
18 | this.onData,
19 | this.onDone,
20 | this.onError,
21 | });
22 |
23 | @override
24 | StreamSubscription listen(void Function(T event) onData,
25 | {Function onError, void Function() onDone, bool cancelOnError}) {
26 | assert(onData != null);
27 | void Function(T event) _onData;
28 | if (this.onData != null && onData != null) {
29 | _onData = (T event) {
30 | this.onData(event);
31 | onData(event);
32 | };
33 | } else {
34 | _onData = onData ?? this.onData;
35 | }
36 |
37 | Function _onError;
38 | if (this.onError != null && onError != null) {
39 | _onError = (e) {
40 | this.onError(e);
41 | onError(e);
42 | };
43 | } else {
44 | _onError = onError ?? this.onError;
45 | }
46 |
47 | void Function() _onDone;
48 | if (this.onDone != null && onDone != null) {
49 | _onDone = () {
50 | this.onDone();
51 | onDone();
52 | };
53 | } else {
54 | _onDone = onDone ?? this.onDone;
55 | }
56 |
57 | try {
58 | _streamSubscription = _stream.listen(_onData,
59 | onError: _onError, onDone: _onDone, cancelOnError: cancelOnError);
60 | return _streamSubscription;
61 | } catch (e) {
62 | _onError(e);
63 | rethrow;
64 | }
65 | }
66 |
67 | @override
68 | Future close() {
69 | if (_streamSubscription == null) {
70 | return new Future.value();
71 | }
72 | return _streamSubscription.cancel();
73 | }
74 | }
75 |
76 | class IoUtil {
77 | static Future stream2String(
78 | CloseableStream> stream, Encoding encoding) {
79 | Completer completer = new Completer();
80 | StringBuffer stringBuffer = new StringBuffer();
81 | stream.transform(encoding.decoder).listen((String content) {
82 | stringBuffer.write(content);
83 | }, onDone: () {
84 | stream.close();
85 | completer.complete(stringBuffer.toString());
86 | }, onError: (e) {
87 | stream.close();
88 | completer.completeError(e);
89 | }, cancelOnError: true);
90 |
91 | return completer.future;
92 | }
93 | }
94 |
95 | abstract class Closeable {
96 | Future close();
97 | }
98 |
99 | /// This IOSink do nothing when operation
100 | class EmptyIOSink implements IOSink {
101 | @override
102 | Encoding encoding;
103 |
104 | @override
105 | void add(List data) {}
106 |
107 | @override
108 | void addError(Object error, [StackTrace stackTrace]) {}
109 |
110 | @override
111 | Future addStream(Stream> stream) {
112 | return new Future.value();
113 | }
114 |
115 | @override
116 | Future close() {
117 | return new Future.value();
118 | }
119 |
120 | @override
121 | Future get done => new Future.value();
122 |
123 | @override
124 | Future flush() {
125 | return new Future.value();
126 | }
127 |
128 | @override
129 | void write(Object obj) {}
130 |
131 | @override
132 | void writeAll(Iterable objects, [String separator = ""]) {}
133 |
134 | @override
135 | void writeCharCode(int charCode) {}
136 |
137 | @override
138 | void writeln([Object obj = ""]) {}
139 | }
140 |
141 | typedef void IOSinkOnError(e);
142 |
143 | /// This IOSink do not throw errors
144 | class IOSinkProxy implements IOSink {
145 | final IOSink sink;
146 | final IOSinkOnError onError;
147 |
148 | IOSinkProxy(this.sink, {this.onError})
149 | : assert(onError != null),
150 | encoding = sink.encoding;
151 |
152 | @override
153 | Encoding encoding;
154 |
155 | @override
156 | void add(List data) {
157 | try {
158 | sink.add(data);
159 | } catch (e) {
160 | this.onError(e);
161 | }
162 | }
163 |
164 | @override
165 | void addError(Object error, [StackTrace stackTrace]) {
166 | sink.addError(error, stackTrace);
167 | }
168 |
169 | @override
170 | Future addStream(Stream> stream) async {
171 | try {
172 | return await sink.addStream(stream);
173 | } catch (e) {
174 | this.onError(e);
175 | }
176 | }
177 |
178 | @override
179 | Future close() async {
180 | try {
181 | return await sink.close();
182 | } catch (e) {
183 | this.onError(e);
184 | }
185 | }
186 |
187 | @override
188 | Future get done => sink.done;
189 |
190 | @override
191 | Future flush() async {
192 | try {
193 | return await sink.flush();
194 | } catch (e) {
195 | this.onError(e);
196 | }
197 | }
198 |
199 | @override
200 | void write(Object obj) {
201 | try {
202 | sink.write(obj);
203 | } catch (e) {
204 | this.onError(e);
205 | }
206 | }
207 |
208 | @override
209 | void writeAll(Iterable objects, [String separator = ""]) {
210 | try {
211 | sink.writeAll(objects, separator);
212 | } catch (e) {
213 | this.onError(e);
214 | }
215 | }
216 |
217 | @override
218 | void writeCharCode(int charCode) {
219 | try {
220 | sink.writeCharCode(charCode);
221 | } catch (e) {
222 | this.onError(e);
223 | }
224 | }
225 |
226 | @override
227 | void writeln([Object obj = ""]) {
228 | try {
229 | sink.writeln(obj);
230 | } catch (e) {
231 | this.onError(e);
232 | }
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/lib/_src/lru_map.dart:
--------------------------------------------------------------------------------
1 | import 'dart:core';
2 |
3 | ///
4 | /// A collection of key/value pairs,
5 | /// The order of the items in this class dependents on how `recent` we use the key,
6 | /// the more recent we use the key , the order is bigger.
7 | ///
8 | /// Witch means the head of the LRU list is the lest recent visited,
9 | /// and will be more likely to be removed in future
10 | ///
11 | /// For example:
12 | /// LruMap map = new LruMap();
13 | /// map['a']=1;
14 | /// map['b']=2;
15 | /// map['c']=3;
16 | /// print(map.values); -> 1,2,3
17 | ///
18 | /// var f = map['a']; // this action will take key:a to the tail of the LRU list
19 | /// print(map.values); -> 2,3,1
20 | ///
21 | ///
22 | class LruMap implements Map {
23 | _Entry head;
24 | _Entry tail;
25 |
26 | final Map> _inner = new Map();
27 |
28 | int get length => _inner.length;
29 |
30 | LruMap();
31 |
32 | factory LruMap.of(Map map) {
33 | if (map is LruMap) {
34 | return map;
35 | }
36 | LruMap result = new LruMap();
37 | result.addAll(map);
38 | return result;
39 | }
40 |
41 | Iterable get values {
42 | List list = [];
43 | for (_Entry e = head; e != null; e = e.after) {
44 | list.add(e.value);
45 | }
46 | return list;
47 | }
48 |
49 | Iterable get keys {
50 | List list = [];
51 | for (_Entry e = head; e != null; e = e.after) {
52 | list.add(e.key);
53 | }
54 | return list;
55 | }
56 |
57 | void clear() {
58 | _inner.clear();
59 | head = tail = null;
60 | }
61 |
62 | @override
63 | V operator [](Object key) {
64 | //
65 | _Entry node = _inner[key];
66 | if (node == null) return null;
67 | _afterNodeAccess(node);
68 | return node.value;
69 | }
70 |
71 | void _afterNodeRemoval(_Entry e) {
72 | // unlink
73 | _Entry p = e, b = p.before, a = p.after;
74 | p.before = p.after = null;
75 | if (b == null)
76 | head = a;
77 | else
78 | b.after = a;
79 | if (a == null)
80 | tail = b;
81 | else
82 | a.before = b;
83 | }
84 |
85 | V remove(Object key) {
86 | _Entry node = _inner.remove(key);
87 | if (node == null) return null;
88 | _afterNodeRemoval(node);
89 | return node.value;
90 | }
91 |
92 | void _linkNodeLast(_Entry p) {
93 | _Entry last = tail;
94 | tail = p;
95 | if (last == null)
96 | head = p;
97 | else {
98 | p.before = last;
99 | last.after = p;
100 | }
101 | }
102 |
103 | V removeHead() {
104 | _Entry head = this.head;
105 | if (head == null) {
106 | return null;
107 | }
108 | if (head == tail) {
109 | //just one
110 | head.before = head.after = null;
111 | this.head = this.tail = null;
112 | } else {
113 | this.head = head.after;
114 | this.head.before = null;
115 | head.after = null;
116 | }
117 |
118 | _inner.remove(head.key);
119 |
120 | return head.value;
121 | }
122 |
123 | // move to end of the list
124 | void _afterNodeAccess(_Entry e) {
125 | _Entry last;
126 | if ((last = tail) != e) {
127 | _Entry p = e, b = p.before, a = p.after;
128 | p.after = null;
129 | if (b == null)
130 | head = a;
131 | else
132 | b.after = a;
133 | if (a != null)
134 | a.before = b;
135 | else
136 | last = b;
137 | if (last == null)
138 | head = p;
139 | else {
140 | p.before = last;
141 | last.after = p;
142 | }
143 | tail = p;
144 | }
145 | }
146 |
147 | @override
148 | void addAll(Map other) {
149 | assert(other != null);
150 | other.forEach((K key, V value) {
151 | this[key] = value;
152 | });
153 | }
154 |
155 | @override
156 | void addEntries(Iterable> newEntries) {
157 | newEntries.forEach((MapEntry entry) {
158 | this[entry.key] = entry.value;
159 | });
160 | }
161 |
162 | @override
163 | bool containsKey(Object key) {
164 | return _inner.containsKey(key);
165 | }
166 |
167 | @override
168 | bool containsValue(Object value) {
169 | for (_Entry e = head; e != null; e = e.after) {
170 | if (e.value == value) {
171 | return true;
172 | }
173 | }
174 | return false;
175 | }
176 |
177 | @override
178 | bool get isEmpty => _inner.isEmpty;
179 |
180 | @override
181 | bool get isNotEmpty => _inner.isNotEmpty;
182 |
183 | @override
184 | void forEach(void Function(K key, V value) f) {
185 | for (_Entry e = head; e != null; e = e.after) {
186 | f(e.key, e.value);
187 | }
188 | }
189 |
190 | @override
191 | void removeWhere(bool Function(K key, V value) predicate) {
192 | _inner.removeWhere((K _key, _Entry _value) {
193 | if (predicate(_key, _value.value)) {
194 | _afterNodeRemoval(_value);
195 | return true;
196 | }
197 | return false;
198 | });
199 | }
200 |
201 | @override
202 | Iterable> get entries {
203 | List> list = [];
204 | for (_Entry e = head; e != null; e = e.after) {
205 | list.add(new MapEntry(e.key, e.value));
206 | }
207 | return list;
208 | }
209 |
210 | _Entry _createNew(K key, V value) {
211 | _Entry entry = new _Entry(key: key, value: value);
212 | _linkNodeLast(entry);
213 | return entry;
214 | }
215 |
216 | void operator []=(K key, dynamic value) {
217 | _Entry node = _inner[key];
218 | if (node == null) {
219 | _inner[key] = _createNew(key, value);
220 | } else {
221 | //new Node
222 | _afterNodeAccess(node);
223 | }
224 | }
225 |
226 | @override
227 | V putIfAbsent(K key, V Function() ifAbsent) {
228 | assert(ifAbsent != null);
229 | return _inner.putIfAbsent(key, () {
230 | V value = ifAbsent();
231 | return _createNew(key, value);
232 | })?.value;
233 | }
234 |
235 | @override
236 | V update(K key, V Function(V value) update, {V Function() ifAbsent}) {
237 | assert(update != null);
238 | var updateFunc = (_Entry _value) {
239 | V value = update(_value.value);
240 | _value.value = value;
241 | _afterNodeAccess(_value);
242 | return _value;
243 | };
244 | if (ifAbsent != null) {
245 | return _inner.update(key, updateFunc, ifAbsent: () {
246 | V value = ifAbsent();
247 | return _createNew(key, value);
248 | })?.value;
249 | } else {
250 | return _inner.update(key, updateFunc)?.value;
251 | }
252 | }
253 |
254 | @override
255 | void updateAll(V Function(K key, V value) update) {
256 | assert(update != null);
257 | _inner.updateAll((K _key, _Entry _value) {
258 | V value = update(_key, _value.value);
259 | _value.value = value;
260 |
261 | /// update all values,we need to update all element orders,
262 | /// witch is not necessary here.
263 |
264 | return _value;
265 | });
266 | }
267 |
268 | Map retype() {
269 | throw new Exception("Not implement");
270 | }
271 |
272 | @override
273 | Map cast() {
274 | return _inner.cast();
275 | }
276 |
277 | @override
278 | Map map(MapEntry Function(K key, V value) f) {
279 | throw new Exception("Not implement");
280 | }
281 | }
282 |
283 | /// Store key and value
284 | class _Entry {
285 | final K key;
286 | V value;
287 |
288 | _Entry before;
289 | _Entry after;
290 |
291 | _Entry({this.key, this.value});
292 | }
293 |
--------------------------------------------------------------------------------
/lib/disk_lru_cache.dart:
--------------------------------------------------------------------------------
1 | library disk_lru_cache;
2 |
3 | export '_src/disk_lru_cache.dart';
4 | export '_src/ioutil.dart';
5 | export '_src/lru_map.dart';
6 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "2.0.11"
11 | args:
12 | dependency: transitive
13 | description:
14 | name: args
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "1.5.2"
18 | async:
19 | dependency: transitive
20 | description:
21 | name: async
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "2.4.0"
25 | boolean_selector:
26 | dependency: transitive
27 | description:
28 | name: boolean_selector
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.0.5"
32 | charcode:
33 | dependency: transitive
34 | description:
35 | name: charcode
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "1.1.2"
39 | collection:
40 | dependency: transitive
41 | description:
42 | name: collection
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "1.14.11"
46 | convert:
47 | dependency: transitive
48 | description:
49 | name: convert
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "2.1.1"
53 | crypto:
54 | dependency: transitive
55 | description:
56 | name: crypto
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "2.1.3"
60 | flutter:
61 | dependency: "direct main"
62 | description: flutter
63 | source: sdk
64 | version: "0.0.0"
65 | flutter_test:
66 | dependency: "direct dev"
67 | description: flutter
68 | source: sdk
69 | version: "0.0.0"
70 | http:
71 | dependency: "direct dev"
72 | description:
73 | name: http
74 | url: "https://pub.flutter-io.cn"
75 | source: hosted
76 | version: "0.12.0+4"
77 | http_parser:
78 | dependency: transitive
79 | description:
80 | name: http_parser
81 | url: "https://pub.flutter-io.cn"
82 | source: hosted
83 | version: "3.1.3"
84 | image:
85 | dependency: transitive
86 | description:
87 | name: image
88 | url: "https://pub.flutter-io.cn"
89 | source: hosted
90 | version: "2.1.4"
91 | matcher:
92 | dependency: transitive
93 | description:
94 | name: matcher
95 | url: "https://pub.flutter-io.cn"
96 | source: hosted
97 | version: "0.12.6"
98 | meta:
99 | dependency: transitive
100 | description:
101 | name: meta
102 | url: "https://pub.flutter-io.cn"
103 | source: hosted
104 | version: "1.1.8"
105 | path:
106 | dependency: transitive
107 | description:
108 | name: path
109 | url: "https://pub.flutter-io.cn"
110 | source: hosted
111 | version: "1.6.4"
112 | pedantic:
113 | dependency: transitive
114 | description:
115 | name: pedantic
116 | url: "https://pub.flutter-io.cn"
117 | source: hosted
118 | version: "1.8.0+1"
119 | petitparser:
120 | dependency: transitive
121 | description:
122 | name: petitparser
123 | url: "https://pub.flutter-io.cn"
124 | source: hosted
125 | version: "2.4.0"
126 | quiver:
127 | dependency: transitive
128 | description:
129 | name: quiver
130 | url: "https://pub.flutter-io.cn"
131 | source: hosted
132 | version: "2.0.5"
133 | sky_engine:
134 | dependency: transitive
135 | description: flutter
136 | source: sdk
137 | version: "0.0.99"
138 | source_span:
139 | dependency: transitive
140 | description:
141 | name: source_span
142 | url: "https://pub.flutter-io.cn"
143 | source: hosted
144 | version: "1.5.5"
145 | stack_trace:
146 | dependency: transitive
147 | description:
148 | name: stack_trace
149 | url: "https://pub.flutter-io.cn"
150 | source: hosted
151 | version: "1.9.3"
152 | stream_channel:
153 | dependency: transitive
154 | description:
155 | name: stream_channel
156 | url: "https://pub.flutter-io.cn"
157 | source: hosted
158 | version: "2.0.0"
159 | string_scanner:
160 | dependency: transitive
161 | description:
162 | name: string_scanner
163 | url: "https://pub.flutter-io.cn"
164 | source: hosted
165 | version: "1.0.5"
166 | synchronized:
167 | dependency: "direct main"
168 | description:
169 | name: synchronized
170 | url: "https://pub.flutter-io.cn"
171 | source: hosted
172 | version: "2.1.1"
173 | term_glyph:
174 | dependency: transitive
175 | description:
176 | name: term_glyph
177 | url: "https://pub.flutter-io.cn"
178 | source: hosted
179 | version: "1.1.0"
180 | test_api:
181 | dependency: transitive
182 | description:
183 | name: test_api
184 | url: "https://pub.flutter-io.cn"
185 | source: hosted
186 | version: "0.2.11"
187 | typed_data:
188 | dependency: transitive
189 | description:
190 | name: typed_data
191 | url: "https://pub.flutter-io.cn"
192 | source: hosted
193 | version: "1.1.6"
194 | vector_math:
195 | dependency: transitive
196 | description:
197 | name: vector_math
198 | url: "https://pub.flutter-io.cn"
199 | source: hosted
200 | version: "2.0.8"
201 | xml:
202 | dependency: transitive
203 | description:
204 | name: xml
205 | url: "https://pub.flutter-io.cn"
206 | source: hosted
207 | version: "3.5.0"
208 | sdks:
209 | dart: ">=2.5.0 <3.0.0"
210 | flutter: ">=0.1.4 <3.0.0"
211 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: disk_lru_cache
2 | description: Disk lru cache for flutter.
3 | version: 0.0.2
4 | author: JZoom
5 | homepage: https://github.com/best-flutter/disk_lru_cache
6 |
7 |
8 |
9 | environment:
10 | sdk: ">=2.0.0-dev.48.0 <3.0.0"
11 | flutter: ">=0.1.4 <3.0.0"
12 |
13 |
14 | dependencies:
15 | flutter:
16 | sdk: flutter
17 | synchronized: ^2.1.1
18 |
19 | dev_dependencies:
20 | flutter_test:
21 | sdk: flutter
22 | http:
23 |
24 | flutter:
25 |
--------------------------------------------------------------------------------
/test/disk_lru_cache_test.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 | import 'dart:typed_data';
4 |
5 | import 'package:disk_lru_cache/_src/disk_lru_cache.dart';
6 | import 'package:http/http.dart';
7 | import 'package:flutter_test/flutter_test.dart';
8 | import 'dart:math' as Math;
9 | import 'package:disk_lru_cache/disk_lru_cache.dart';
10 |
11 | void main() {
12 | int maxSize =
13 | 10 * 1024 * 1024; // 10M,make sure to test rebuild progress below
14 |
15 | Directory cacheDirectory =
16 | new Directory("${Directory.systemTemp.path}/cache");
17 |
18 | test("Basic usage with bytes", () async {
19 | DiskLruCache cache = new DiskLruCache(
20 | maxSize: maxSize,
21 | directory: cacheDirectory,
22 | filesCount: 1,
23 | opCompactThreshold: 200);
24 |
25 | print('============================\n${cacheDirectory.path}');
26 |
27 | // write stream
28 | CacheEditor editor = await cache.edit('imagekey');
29 | if (editor != null) {
30 | HttpClient client = new HttpClient();
31 | HttpClientRequest request = await client.openUrl(
32 | "GET",
33 | Uri.parse(
34 | "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1534075481&di=1a90bd266d62bc5edfe1ce84ac38330e&src=http://photocdn.sohu.com/20130517/Img376200804.jpg"));
35 | HttpClientResponse response = await request.close();
36 | Stream> stream = await editor.copyStream(0, response);
37 | // The bytes has been written to disk at this point.
38 | await new ByteStream(stream).toBytes();
39 | await editor.commit();
40 |
41 | // read stream
42 | CacheSnapshot snapshot = await cache.get('imagekey');
43 | Uint8List bytes = await snapshot.getBytes(0);
44 | print(bytes.length);
45 | }
46 | });
47 |
48 | test("Basic usage width string", () async {
49 | DiskLruCache cache = new DiskLruCache(
50 | maxSize: maxSize,
51 | directory: cacheDirectory,
52 | filesCount: 1,
53 | opCompactThreshold: 200);
54 |
55 | // write stream
56 | CacheEditor editor = await cache.edit('filekey');
57 | if (editor != null) {
58 | IOSink sink = await editor.newSink(0);
59 | sink.write('your value');
60 | await sink.close();
61 | await editor.commit();
62 | }
63 |
64 | // read stream
65 | CacheSnapshot snapshot = await cache.get('filekey');
66 | String str = await snapshot.getString(0);
67 | print(str);
68 | });
69 |
70 | Future testCache() async {
71 | DiskLruCache cache = new DiskLruCache(
72 | maxSize: maxSize,
73 | directory: cacheDirectory,
74 | filesCount: 1,
75 | opCompactThreshold: 200);
76 | print(cache.directory);
77 |
78 | String str200k;
79 | String get200k() {
80 | if (str200k == null) {
81 | StringBuffer sb = new StringBuffer();
82 |
83 | for (int i = 0, c = 200 * 1024; i < c; ++i) {
84 | sb.write("a");
85 | }
86 |
87 | str200k = sb.toString();
88 | }
89 | return str200k;
90 | }
91 |
92 | Future test() async {
93 | // we must wait the file created
94 | List list = [];
95 | List writeDisk = [];
96 | List openWrite = [];
97 |
98 | void editValue(DiskLruCache cache, String key, String value) {
99 | list.add(cache.edit(key).then((CacheEditor editor) {
100 | if (editor != null) {
101 | openWrite.add(editor.newSink(0).then((IOSink sink) async {
102 | writeDisk.add((() async {
103 | if (sink != null) {
104 | sink.write(value);
105 | await sink.close();
106 |
107 | await editor.commit();
108 | } else {
109 | print("Sink is null");
110 | }
111 | })());
112 | }).catchError((e) {
113 | print(e);
114 | }));
115 | } else {
116 | print("Cannot open editor for key $key");
117 | }
118 | }));
119 | }
120 |
121 | Future useCache(DiskLruCache cache) async {
122 | int random() {
123 | // 200k * 100 = 20M
124 | return new Math.Random().nextInt(100);
125 | }
126 |
127 | //we open 10 files at the same time
128 | for (int i = 0; i < 10; ++i) {
129 | editValue(cache, "${random()}", get200k());
130 | String key = "${random()}";
131 | cache.get(key).then((CacheSnapshot s) {
132 | if (s == null) {
133 | print('Cache miss $key');
134 | return;
135 | }
136 | s.getString(0).then((String str) {
137 | print("Cache hit $key");
138 | });
139 | });
140 | //cache.remove("${random()}");
141 | }
142 | }
143 |
144 | await useCache(cache);
145 |
146 | await Future.wait(list);
147 | await Future.wait(openWrite);
148 | await Future.wait(writeDisk);
149 | }
150 |
151 | // our operation times must > 2000,so that we can test rebuild record file.
152 | for (int i = 0; i < 10; ++i) {
153 | await test();
154 | }
155 |
156 |
157 | Iterable entries = await cache.values;
158 | int calcSize = 0;
159 | entries.forEach((CacheEntry entry) {
160 | calcSize += entry.size;
161 | });
162 |
163 | expect(cache.size, calcSize);
164 |
165 | expect(cache.size < maxSize, true);
166 |
167 | await cache.close();
168 | print("Cache size : ${cache.size / 1024 / 1024} m ");
169 | }
170 |
171 | Future testRemoveAll() async {
172 | DiskLruCache cache = new DiskLruCache(
173 | maxSize: maxSize, directory: cacheDirectory, filesCount: 1);
174 | List results = await cache.clean();
175 | expect(results.every((bool value) => value), true);
176 | expect(cache.size, 0);
177 | }
178 |
179 | test('Lru cache', () async {
180 | await (() async {
181 | await testCache();
182 | })();
183 |
184 | // do it again
185 | await (() async {
186 | await testCache();
187 | })();
188 |
189 | //test remove
190 | await (() async {
191 | await testRemoveAll();
192 | })();
193 | });
194 |
195 | test("Test commit errors", () async {
196 | DiskLruCache cache = new DiskLruCache(
197 | maxSize: maxSize, directory: cacheDirectory, filesCount: 2);
198 | // write stream
199 | CacheEditor editor = await cache.edit('filekey');
200 | if (editor != null) {
201 | IOSink sink = await editor.newSink(0);
202 | sink.write('your value');
203 | await sink.close();
204 | await editor.commit();
205 |
206 | CacheSnapshot snapshot = await cache.get("filekey");
207 | expect(snapshot, null);
208 | }
209 | });
210 |
211 | test("Simulate errors when write to disk", () async {
212 | DiskLruCache cache = new DiskLruCache(
213 | maxSize: maxSize, directory: cacheDirectory, filesCount: 1);
214 | // write stream
215 | CacheEditor editor = await cache.edit('errorkey');
216 | if (editor != null) {
217 | IOSink sink = await editor.newSink(0);
218 |
219 |
220 | sink.write('your value');
221 | await sink.flush();
222 |
223 | //remove the file
224 | Iterable values = await cache.values;
225 | values = values.where((CacheEntry entry) {
226 | return entry.key == "errorkey";
227 | });
228 | await values.toList()[0].dirtyFiles[0].delete();
229 |
230 | await sink.close();
231 | await editor.commit();
232 |
233 | expect(await cache.get("errorkey"), null);
234 | }
235 | });
236 |
237 | test("Delete file when read", () async {
238 | //Delete file when read
239 |
240 | DiskLruCache cache = new DiskLruCache(
241 | maxSize: maxSize, directory: cacheDirectory, filesCount: 1);
242 |
243 | CacheEditor editor = await cache.edit('readkey');
244 | if (editor != null) {
245 | IOSink sink = await editor.newSink(0);
246 |
247 | sink.write('your value');
248 | await sink.flush();
249 | await sink.close();
250 | await editor.commit();
251 |
252 | //remove the file
253 | Iterable values = await cache.values;
254 | values = values.where((CacheEntry entry) {
255 | return entry.key == "readkey";
256 | });
257 | try {
258 | await values.toList()[0].cleanFiles[0].delete();
259 | } catch (e) {
260 | print(e);
261 | }
262 |
263 | expect(await cache.get("readkey"), null);
264 | }
265 | });
266 |
267 | test("Leave some dirty and don't handle and close the cache", () async {
268 | DiskLruCache cache = new DiskLruCache(
269 | maxSize: maxSize, directory: cacheDirectory, filesCount: 1);
270 |
271 | CacheEditor editor = await cache.edit('readkey');
272 |
273 | await cache.close();
274 |
275 | cache = new DiskLruCache(
276 | maxSize: maxSize, directory: cacheDirectory, filesCount: 1);
277 |
278 | editor = await cache.edit("readkey");
279 | IOSink sink = await editor.newSink(0);
280 |
281 | sink.write('your value');
282 | await sink.flush();
283 | await sink.close();
284 | await editor.commit();
285 | });
286 | }
287 |
--------------------------------------------------------------------------------
/test/lru_map_test.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | import 'package:disk_lru_cache/disk_lru_cache.dart';
5 |
6 | void main() {
7 | test('Lru map', () {
8 | final LruMap map = new LruMap();
9 |
10 | expect(map.values.toList().length, 0);
11 |
12 | map['a'] = 1;
13 | map['b'] = 2;
14 | map['c'] = 3;
15 |
16 | Iterable values = map.values;
17 | print(values);
18 |
19 | expect(values.toList()[0], 1);
20 | expect(values.toList()[1], 2);
21 | expect(values.toList()[2], 3);
22 |
23 | /// use the key 'a'
24 | var f = map['a'];
25 |
26 | expect(f, 1);
27 |
28 | values = map.values;
29 | print(values);
30 | expect(values.length, 3);
31 | expect(values.length, map.length);
32 | expect(values.toList()[0], 2);
33 | expect(values.toList()[1], 3);
34 | expect(values.toList()[2], 1);
35 |
36 | Iterable keys = map.keys;
37 |
38 | expect(keys.toList()[0], 'b');
39 | expect(keys.toList()[1], 'c');
40 | expect(keys.toList()[2], 'a');
41 | expect(map.isEmpty, false);
42 | expect(map.isNotEmpty, true);
43 |
44 | int value = map.removeHead();
45 | expect(value, 2);
46 | keys = map.keys;
47 | expect(keys.length, 2);
48 | expect(keys.length, map.length);
49 | expect(keys.toList()[0], 'c');
50 | expect(keys.toList()[1], 'a');
51 |
52 | map.remove('a');
53 | keys = map.keys;
54 | expect(keys.length, 1);
55 | expect(keys.length, map.length);
56 | expect(keys.toList()[0], 'c');
57 |
58 | bool excuted = false;
59 | //other operation
60 | map.putIfAbsent("d", () {
61 | excuted = true;
62 | return 4;
63 | });
64 |
65 | keys = map.keys;
66 | expect(keys.length, 2);
67 | expect(keys.length, map.length);
68 | expect(keys.toList()[0], 'c');
69 | expect(keys.toList()[1], 'd');
70 | expect(excuted, true);
71 |
72 | excuted = false;
73 | map.putIfAbsent("c", () {
74 | excuted = true;
75 | return 5;
76 | });
77 | expect(excuted, false);
78 | keys = map.keys;
79 | expect(keys.length, 2);
80 | expect(keys.length, map.length);
81 | expect(keys.toList()[0], 'c');
82 | expect(keys.toList()[1], 'd');
83 |
84 | map.update("c", (int value) {
85 | return 4;
86 | }, ifAbsent: () {
87 | return 0;
88 | });
89 |
90 | expect(map['c'], 4);
91 |
92 | map.update("e", (int value) {
93 | return 8;
94 | }, ifAbsent: () {
95 | return 0;
96 | });
97 |
98 | expect(map['e'], 0);
99 |
100 | map.updateAll((String key, int value) {
101 | return value + 1;
102 | });
103 |
104 | expect(map['e'], 1);
105 |
106 | Map casted = map.cast();
107 |
108 | expect(casted != null, true);
109 |
110 | int now = new DateTime.now().millisecondsSinceEpoch;
111 | for (int i = 0; i < 10000; ++i) {
112 | map['key$i'] = i;
113 | }
114 |
115 | print(new DateTime.now().millisecondsSinceEpoch - now);
116 |
117 | now = new DateTime.now().millisecondsSinceEpoch;
118 | Map org = {};
119 | for (int i = 0; i < 10000; ++i) {
120 | org['key$i'] = i;
121 | }
122 |
123 | print(new DateTime.now().millisecondsSinceEpoch - now);
124 | });
125 |
126 | test("test map ", () {
127 | LruMap map = LruMap.of({"a": "1", "b": "2", "c": "3"});
128 |
129 | expect(map.removeHead(), "1");
130 | expect(map.removeHead(), "2");
131 | expect(map.removeHead(), "3");
132 | expect(map.removeHead(), null);
133 | });
134 |
135 | test("test clear ", () {
136 | LruMap map = LruMap.of({"a": "1", "b": "2", "c": "3"});
137 |
138 | expect(map.length, 3);
139 |
140 | map.clear();
141 |
142 | expect(map.length, 0);
143 | });
144 |
145 | test("Lru map other", () {
146 | LruMap map = LruMap.of({"a": "1", "b": "2", "c": "3"});
147 |
148 | LruMap other = new LruMap();
149 | other.addEntries(map.entries);
150 |
151 | print(other.values);
152 |
153 | expect(other.values.toList()[0], "1");
154 | expect(other.values.toList()[1], "2");
155 | expect(other.values.toList()[2], "3");
156 | expect(other.containsKey('a'), true);
157 |
158 | other.forEach((key, value) {
159 | print(value);
160 | });
161 |
162 | expect(other.containsValue("1"), true);
163 |
164 | other.removeWhere((key, value) {
165 | return key == "a";
166 | });
167 |
168 | expect(other['a'], null);
169 |
170 | expect(other.containsKey('a'), false);
171 | expect(other.containsValue('1'), false);
172 | });
173 | }
174 |
--------------------------------------------------------------------------------