├── .DS_Store
├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── copyright
│ ├── Apache.xml
│ └── profiles_settings.xml
├── libraries
│ └── Dart_SDK.xml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example
├── .gitignore
├── .metadata
├── LICENSE
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── rallycoder
│ │ │ │ │ └── tests
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── 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
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── Runner
│ │ ├── AppDelegate.swift
│ │ ├── 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
│ │ └── Runner-Bridging-Header.h
├── lib
│ └── main.dart
├── pubspec.yaml
└── test
│ └── main.dart
├── flutter_extentions.iml
├── lib
├── dart_extensions.dart
├── emum.dart
└── src
│ ├── data_stractures
│ └── stack.dart
│ ├── date.dart
│ ├── equality.dart
│ ├── exceptions
│ └── range_exception.dart
│ ├── files.dart
│ ├── flutter
│ ├── align.dart
│ ├── center.dart
│ ├── container.dart
│ ├── context.dart
│ ├── duration.dart
│ ├── gesture_detector.dart
│ ├── icon.dart
│ ├── list.dart
│ ├── navigation.dart
│ ├── padding.dart
│ ├── responsive.dart
│ ├── sized_box.dart
│ ├── sliver.dart
│ ├── text.dart
│ ├── transforms.dart
│ ├── transforms
│ │ └── click_translate.dart
│ └── widgets.dart
│ ├── http.dart
│ ├── int.dart
│ ├── iterable.dart
│ ├── map.dart
│ ├── model
│ └── user.dart
│ ├── ranges.dart
│ ├── search_algorithms.dart
│ ├── sort_algorithms.dart
│ ├── string_ext.dart
│ └── utils.dart
├── pubspec.yaml
└── test
├── algo_test.dart
├── date_tests.dart
├── enum_test.dart
├── int_test.dart
├── iterable_tests.dart
├── ranges_test.dart
└── strings_test.dart
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .classpath
21 | .project
22 | .settings/
23 | .vscode/
24 |
25 | # Flutter repo-specific
26 | /bin/cache/
27 | /bin/mingit/
28 | /dev/benchmarks/mega_gallery/
29 | /dev/bots/.recipe_deps
30 | /dev/bots/android_tools/
31 | /dev/docs/doc/
32 | /dev/docs/flutter.docs.zip
33 | /dev/docs/lib/
34 | /dev/docs/pubspec.yaml
35 | /dev/integration_tests/**/xcuserdata
36 | /dev/integration_tests/**/Pods
37 | /packages/flutter/coverage/
38 | version
39 |
40 | # packages file containing multi-root paths
41 | .packages.generated
42 |
43 | # Flutter/Dart/Pub related
44 | **/doc/api/
45 | .dart_tool/
46 | .flutter-plugins
47 | .flutter-plugins-dependencies
48 | .packages
49 | .pub-cache/
50 | .pub/
51 | build/
52 | flutter_*.png
53 | linked_*.ds
54 | unlinked.ds
55 | unlinked_spec.ds
56 |
57 | # Android related
58 | **/android/**/gradle-wrapper.jar
59 | **/android/.gradle
60 | **/android/captures/
61 | **/android/gradlew
62 | **/android/gradlew.bat
63 | **/android/local.properties
64 | **/android/**/GeneratedPluginRegistrant.java
65 | **/android/key.properties
66 | *.jks
67 |
68 | # iOS/XCode related
69 | **/ios/**/*.mode1v3
70 | **/ios/**/*.mode2v3
71 | **/ios/**/*.moved-aside
72 | **/ios/**/*.pbxuser
73 | **/ios/**/*.perspectivev3
74 | **/ios/**/*sync/
75 | **/ios/**/.sconsign.dblite
76 | **/ios/**/.tags*
77 | **/ios/**/.vagrant/
78 | **/ios/**/DerivedData/
79 | **/ios/**/Icon?
80 | **/ios/**/Pods/
81 | **/ios/**/.symlinks/
82 | **/ios/**/profile
83 | **/ios/**/xcuserdata
84 | **/ios/.generated/
85 | **/ios/Flutter/App.framework
86 | **/ios/Flutter/Flutter.framework
87 | **/ios/Flutter/Flutter.podspec
88 | **/ios/Flutter/Generated.xcconfig
89 | **/ios/Flutter/app.flx
90 | **/ios/Flutter/app.zip
91 | **/ios/Flutter/flutter_assets/
92 | **/ios/Flutter/flutter_export_environment.sh
93 | **/ios/ServiceDefinitions.json
94 | **/ios/Runner/GeneratedPluginRegistrant.*
95 |
96 | # macOS
97 | **/macos/Flutter/GeneratedPluginRegistrant.swift
98 | **/macos/Flutter/Flutter-Debug.xcconfig
99 | **/macos/Flutter/Flutter-Release.xcconfig
100 | **/macos/Flutter/Flutter-Profile.xcconfig
101 |
102 | # Coverage
103 | coverage/
104 |
105 | # Exceptions to above rules.
106 | !**/ios/**/default.mode1v3
107 | !**/ios/**/default.mode2v3
108 | !**/ios/**/default.pbxuser
109 | !**/ios/**/default.perspectivev3
110 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
111 | !/dev/ci/**/Gemfile.lock
112 | .idea/workspace.xml
113 | .idea/libraries/Dart_Packages.xml
114 | .idea/workspace.xml
115 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/.idea/copyright/Apache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.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 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [2.2.4] - 17/05/23
2 | - Sliver extensions
3 | ## [2.2.1] - 17/05/23
4 | - Flutter 3.1 ready
5 | ## [2.0.5] - 11/03/21
6 | - `delay`extension for delay, example: await 3.seconds.delay(() { some code }
7 | - `added getTextSize` - A good use-case will be drawing a divider with the exect width of the text above it.
8 | - `isVideo` - Checks if string is an video file.
9 | - `isAudio` - Checks if string is an audio file.
10 | - `isImage` - Checks if string is an image file.
11 | - `isNumericOnly` - Check if the string has any number in it.
12 | - `isAlphabetOnly` - Checks if string consist only Alphabet. (No Whitespace)
13 | - `hasCapitalletter` - Checks if string contains at least one Capital Letter.
14 | - `isHTML` - Checks if string is an html file.
15 | - `isEmail` - Checks if string is email..
16 | - `isPhoneNumber` - Checks if string is phone number, good for login checks.
17 | - `isUsername` - Checks if string is a valid username, good for login checks.
18 | - `isCurrency` - Checks if string is Currency.
19 | - `isPalindrom` - Checks if string is Palindrom. (good to know for interviews as well)
20 |
21 |
22 | ## [2.0.0] - 11/03/21
23 | - `Support flutter 2`
24 | - `Support null safety`
25 | - `add new extensions`
26 | ## [1.0.0] - 19/03/20
27 | - `Context extensions`
28 | - `Text Extensions`
29 | - `Icon Extensions`
30 | - `List Extensions`
31 | ## [0.3.4] 9/03/20
32 | - sortBy - Sorts elements in the array in-place according to natural sort order of the value returned by specified selector function.
33 | ## [0.3.3] 19/02/20
34 | - algorithm - quick search
35 | - Flutter - Tooltip extension
36 |
37 | ## [0.2.0] - 23/01/20.
38 | - .groupBy() added Iterable + tests
39 | - .intersect() + test
40 | - .toMutableSet() + test
41 |
42 | ## [0.1.8] - 22/01/20.
43 | - .filter() added Iterable + tests
44 | - .notFilter() added Iterable + tests
45 | - .isNullOrWhiteSpace added String + tests
46 | - .insert() added Strings + test
47 |
48 | ## [0.1.7] - 19/01/202.
49 | - find - Iterable extensions + tests
50 | - added Ranges extension for int + tests
51 |
52 | ## [0.1.4] - 19/01/202.
53 | - associate in Iterables extensions + tests
54 | - added Http Extensions: - httpGet httpPost httpPut httpDelete
55 | - added int Extensions: - absolute
56 | - isEven
57 | - isOdd
58 | - isPositive
59 | - isNegative
60 | - tenth
61 | - fourth
62 | - third
63 | - half
64 | - doubled
65 | - tripled
66 | - quadrupled
67 | - squared
68 |
69 |
70 | ## [0.1.3] - 19/01/2020.
71 | - anyChar in Strings extensions + tests
72 | - replaceBefore Strings extensions + tests
73 | - toDoubleOrNull Strings extensions test
74 | - removeAllWhiteSpace Strings extensions + tests
75 | - toCharArray Strings extension + tests
76 |
77 |
78 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2015, Google Inc. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 |
14 | * Neither the name of Google Inc. nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](https://github.com/droididan/dart_extentions)  
3 |
4 |
5 | ## What New (2.2.4)
6 | * Sliver extensions
7 |
8 | Why Method Extensions? When you’re using someone else’s API or when you implement a library that’s widely used, it’s often impractical or impossible to change the API. But you might still want to add some functionality.
9 |
10 | *let me know if you want something specific or you found a bug at bar.idan@gmail.com*
11 | ## Let get started 💪🏻
12 |
13 | 1. Go to `pubspec.yaml`
14 | 2. add a dart_extensions and replace `[version]` with the latest version:
15 |
16 | ```dart
17 | dependencies:
18 | dart_extensions: ^[version]
19 | ```
20 |
21 | 3. click the packages get button or *flutter pub get*
22 | ## Responsive UI
23 | Very common way to calculate size in percentage is using the MediaQuery like so:
24 | ```dart
25 | MediaQuery.of(context).size.width * 0.1
26 | ```
27 |
28 |
29 | Flatten a nested Map into a single level map
30 | ```dart
31 | response.flatJson({
32 | 'key1': {'keyA': 'valueI'},
33 | 'key2': {'keyB': 'valueII'},
34 | 'key3': {
35 | 'a': {
36 | 'b': {'c': 2}
37 | }
38 | }
39 | });
40 |
41 | The result you can also specify max depth, its the maximum number of nested objects to flatten.
42 | ```
43 | // {
44 | // 'key1.keyA': 'valueI',
45 | // 'key2.keyB': 'valueII',
46 | // 'key3.a.b.c': 2
47 | // };
48 |
49 |
50 | Instead of the boilerplate we can use this awesome extension and get the same results.
51 |
52 | Wrap your Application with:
53 | ```dart
54 | ResponsiveApp(
55 | builder: (BuildContext context, Orientation orientation, DeviceType deviceType) {
56 | return YourAppWidget()
57 | )
58 | ```
59 |
60 | ```dart
61 | AnimatedList(
62 | key: chatListKey,
63 | reverse: true,
64 | padding: EdgeInsets.only(top: 10.textSizeResponsive),
65 | shrinkWrap: true,
66 | ```
67 | Also the text should be responsive, no problem
68 | ```dart
69 | Text(
70 | 'Note added by ${message.from ?? ''}',
71 | style: avanirBook.copyWith(fontSize: 8.responsiveText),
72 | ),
73 | ```
74 |
75 | ## Iterable Extensions
76 |
77 | ### .any()
78 | Returns `true` if at least one element matches the given predicate.
79 | ```dart
80 | final users = [User(22, "Kasey"), User(23, "Jadn")];
81 | users.any((u) => u.name == 'Kasey') // true
82 | ```
83 |
84 | ### .groupBy()
85 | Groups the elements in values by the value returned by key.
86 | ```dart
87 | final users = [User(22, "Kasey"), User(23, "Jadn"), User(22, "Rene"), User(32, "Aden")];
88 |
89 | users.groupBy((u) => u.age);
90 | ```
91 | Sort the users by age:
92 | ```dart
93 | {
94 | 22: [User:22, Kasey, User:22, Rene],
95 | 23: [User:23, Jadn],
96 | 32: [User:32, Aden]
97 | }
98 | ```
99 |
100 | ### .sortBy()
101 | Sorts elements in the array in-place according to natural sort order of the value returned by specified selector function.
102 | ```dart
103 | final users = [User(22, "Kasey"), User(16, "Roni"), User(23, "Jadn")];
104 | users.sortBy((u) => u.age) /// [User(16, "Roni"), [User(22, "Kasey"), User(23, "Jadn")]
105 | ```
106 |
107 | ### .find()
108 | Returns the first element matching the given predicate, or `null` if element wasn't found.
109 | ```dart
110 | final users = [User(22, "Kasey"), User(23, "Jadn"), User(22, "Rene"), User(32, "Aden")];
111 |
112 | users.find((u) => u.name == "Rene") // User(22, "Rene")
113 | ```
114 |
115 | ### .chunks()
116 | Splits the Iterable into chunks of the specified `size`
117 | ```dart
118 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].chunks(3))
119 | ```
120 | *result*
121 | ```dart
122 | ([1, 2, 3], [4, 5, 6], [7, 8, 9], [10])
123 | ```
124 |
125 | ### .filter()
126 | Returns a list containing only elements matching the given predicate, the return type will be `List`,
127 | unlike the `where` operator that return `Iterator`, also it filters null.
128 | ```dart
129 | final users = [User(22, "Kasey"), User(23, "Jadn"), User(22, "Rene"), User(32, "Aden")];
130 | final filtered = users.filter((u) => u.name == "Kasey"); // [User(22, "Kasey")] <- Type List
131 |
132 | final listWithNull = [null, User(23, "Jadn"), User(22, "Rene"), User(32, "Aden")];
133 | final filtered = listWithNull.filter((u) => u.name == "Jadn"); // [User(23, "Jadn")]
134 | ```
135 |
136 | ### .intersect()
137 | Returns a set containing all elements that are contained by both this set and the specified collection.
138 | ```dart
139 | Set.from([1, 2, 3, 4]).intersect(Set.from([3, 4, 5, 6]) // 1,2,3,4,5,6
140 | ```
141 |
142 | ### .filterNot()
143 | Returns a list containing only not the elements matching the given predicate, the return type will be `List`,
144 | unlike the `where` operator that return `Iterator`, also it filters null.
145 | ```dart
146 | final users = [User(22, "Kasey"), User(23, "Jadn"), User(22, "Rene"), User(32, "Aden")];
147 | final filtered = users.filterNot((u) => u.name == "Kasey"); // [User(23, "Jadn"), User(22, "Rene"), User(32, "Aden")] <- Type List
148 |
149 | final listWithNull = [null, User(23, "Jadn"), User(22, "Rene"), User(32, "Aden")];
150 | final filtered = listWithNull.filterNot((u) => u.name == "Jadn"); // [User(22, "Rene"), User(32, "Aden")]
151 | ```
152 |
153 | ### .takeOnly()
154 | Returns a list containing first [n] elements.
155 | ```dart
156 | [1, 2, 3, 4].takeOnly(1) // [1]
157 | ```
158 |
159 | ### .drop()
160 | Returns a list containing all elements except first [n] elements.
161 | ```dart
162 | [1, 2, 3, 4].drop(1) // [2, 3, 4]
163 | ```
164 |
165 | ### .forEachIndexed()
166 | Performs the given action on each element on iterable, providing sequential `index` with the `element`.
167 | ```dart
168 | ["red","green","blue"].forEachIndexed((item, index) {
169 | print("$item, $index");
170 | }); // 0: red // 1: green // 2: blue```
171 | ```
172 |
173 | ### .sortedDescending()
174 | Returns a new list with all elements sorted according to descending natural sort order.
175 | ```dart
176 | var list = [1,2,3,4,5];
177 | final descendingList = list.sortedDescending();
178 | print(descendingList); // [5, 4, 3, 2, 1]
179 | ```
180 |
181 | ### .count()
182 | Return a number of the existing elements by a specific predicate
183 | ```dart
184 | final users = [User(33, "Miki"), User(45, "Anna"), User(19, "Amit")];
185 |
186 | final aboveAgeTwenty = users.count((user) => user.age > 20);
187 | print(aboveAgeTwenty); // 2
188 | ```
189 |
190 | ### .associate()
191 | Creates a Map instance in which the keys and values are computed from the iterable.
192 | ```dart
193 | final users = [User(33, "Miki"), User(45, "Anna"), User(19, "Amit")];
194 |
195 | users.associate((k) => k.name, (e) => e.age) // 'Miki': 33, 'Anna': 45, 'Amit': 19}
196 | ```
197 |
198 | ### .concatWithMultipleList()
199 | Return a list concatenates the output of the current list and multiple iterables.
200 | ```dart
201 | final listOfLists = [
202 | [5, 6, 7],
203 | [8, 9, 10]
204 | ];
205 | [1, 2, 3, 4].concatWithMultipleList(listOfLists);
206 |
207 | // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
208 | ```
209 |
210 | ### .distinctBy()
211 | Returns a list containing only the elements from given collection having distinct keys.
212 | ```dart
213 | // example 1
214 | final users = ["Zack", "Ian", "Ronit"];
215 | users.distinctBy((u) => u.toLowerCase().startsWith("z")); // Zack
216 |
217 | // example 2
218 | final users = [User(11, 'idan'), User(12, 'ronit'), User(11, 'asaf')];
219 |
220 | final dist = users.distinctBy((u) => u.age);
221 | dist.forEach((u) => print(u.age)); // 11, 12
222 | ```
223 |
224 | ### .zip()
225 | Zip is used to combine multiple iterables into a single list that contains the combination of them two.
226 | ```dart
227 |
228 | final soldThisMonth = [Motorcycle(2020, 'BMW R1200GS'), Motorcycle(1967, 'Honda GoldWing')];
229 | final soldLastMonth = [Motorcycle(2014, 'Honda Transalp'), Motorcycle(2019, 'Ducati Multistrada')];
230 |
231 | final sales = soldThisMonth.zip(soldLastMonth).toList();
232 |
233 | print(sales); // [
234 | [brand: BMW R1200GS year: 2020, brand: Honda Transalp year: 2014], // first pair from this month and last
235 | [brand: Honda GoldWing year: 1967, brand: Ducati Multistrada year: 2019] // second pair from last month
236 | ]
237 | ```
238 | See [iterable.dart](https://github.com/droididan/dart_extentions/blob/master/lib/iterable.dart) for more examples.
239 |
240 | ## Flutter Extensions
241 |
242 | ### Context extensions
243 | Are you not tired from typing `MediaQuery.of(context).size...` to get height or width? here's a cool extension
244 | ```dart
245 | context.mq // returns the MediaQuery
246 | ```
247 |
248 | ```dart
249 | context isLandscape // returns if Orientation is landscape
250 | ```
251 |
252 | ```dart
253 | context.sizePx // returns same as MediaQuery.of(context).size
254 | ```
255 |
256 | ```dart
257 | context.widthPx // returns same as MediaQuery.of(context).size.width
258 | ```
259 |
260 | ```dart
261 | context.heightPx // returns same as MediaQuery.of(context).height
262 | ```
263 |
264 | ### Text Extensions
265 | ```dart
266 | final text = Text('hello')
267 | .bold()
268 | .fontSize(25)
269 | .italic();
270 | ```
271 |
272 | ### List Extensions
273 | ```dart
274 | final someWidgetList = [
275 | Text('hello'),
276 | Text('world'),
277 | ].toColumnWidget(); // toRowWidget(), toStackWidget()
278 | ```
279 |
280 | ### Widget extensions
281 | So now we can just add round corners, shadows, align, and added gestures to our `Widgets` without the crazy water-fall effect. awesome!
282 | That's just the tip of the iceberg, expect to see very cool stuff soon.
283 | ```dart
284 | class Home extends StatefulWidget {
285 | @override
286 | _HomeState createState() => _HomeState();
287 | }
288 |
289 | class _HomeState extends State {
290 |
291 | @override
292 | Widget build(BuildContext context) {
293 | return Scaffold(
294 | body: Container(
295 | child: Stack(
296 | children: [
297 | Container(
298 | height: 100,
299 | width: 100,
300 | ) .withRoundCorners(backgroundColor: Colors.grey)
301 | .withShadow()
302 | .alignAtCenter()
303 | .toCenter()
304 | .withTooltip('just a tooltip')
305 | .paddingOnly(left: 10)
306 | .paddingAll(20)
307 | .onTap(() => print('tap'))
308 | .onLongPress(() => print('long press'))
309 | ],
310 | ),
311 | ),
312 | );
313 | }
314 | }
315 | ```
316 |
317 | ### Navigation
318 | We can navigate from every widget by calling these methods
319 | ```dart
320 | navigateTo(route: MaterialPageRoute(builder: (c) => Login()));
321 | navigateByRouteName(Routes.home, );
322 | final result = navigateBack();
323 | ```
324 |
325 |
326 | ## Http Extensions
327 |
328 | ### .httpGet()
329 | Sends an HTTP GET request with the given headers to the given URL
330 | ```dart
331 | final json = await "https://jsonplaceholder.typicode.com/posts".httpGet();
332 | ```
333 | *result:*
334 | ```json
335 | [
336 | {
337 | "userId": 1,
338 | "id": 1,
339 | "title": "sunt aut facere",
340 | "body": "quia et suscipit"
341 | },
342 | {
343 | "userId": 1,
344 | "id": 2,
345 | "title": "qui est esse",
346 | "body": "dolor beatae ea dolores neque"
347 | },
348 | ]
349 | ```
350 |
351 | *usage with then:*
352 | ```dart
353 | "https://jsonplaceholder.typicode.com/posts".httpGet().then((result) {
354 | print(result);
355 | }).catchError((e) => print(e));
356 | ```
357 |
358 | ### .httpPost()
359 | Sends an HTTP POST request with the given headers and body to the given URL which can be a [Uri] or a [String].
360 | ```dart
361 | String json = '{"title": "Hello", "body": "body text", "userId": 1}';
362 | final json = await "https://jsonplaceholder.typicode.com/posts".httpPost(json);
363 | ```
364 |
365 | for more examples (put, delete) See [http.dart](https://github.com/droididan/dart_extentions/blob/master/lib/http.dart)
366 |
367 | ## Range Extensions
368 | ### .until()
369 | Returns a sequence of integer, starting from the current number until the [end] number. [step] is optional, it will step number if given
370 | ```dart
371 | for(final num in 1.until(10)) {
372 | numbers.add(num);
373 | }
374 | ```
375 | *result*
376 | ```dart
377 | [1, 2, 3, 4, 5, 6, 7, 8, 9]
378 | ```
379 | with step:
380 | ```dart
381 | for(final num in 1.until(10, step: 2)) {
382 | numbers.add(num);
383 | }
384 | ```
385 | *result*
386 | ```dart
387 | [1, 3, 5, 7, 9]
388 | ```
389 |
390 | ## String Extensions
391 |
392 |
393 | ### .asBool()
394 | Returns true if this string is any of these values: "true", "yes", "1", or if the string is a number and greater than 0, false if less than 1. This is also case insensitive.
395 | ```dart
396 | 'true'.asBool // true
397 | 'True'.asBool // true
398 | 'false'.asBool // false
399 | 'False'.asBool // false
400 | 'yes'.asBool // true
401 | 'YES'.asBool // true
402 | 'no'.asBool // false
403 | 'NO'.asBool // false
404 | ```
405 |
406 |
407 | ### .insert()
408 | Returns a new string in which a specified string is inserted at a specified index position in this instance.
409 | ```dart
410 | 'test'.insert(1, 't') // 'ttest'
411 | '123456890'.insert(6, '7') // '1234567890'
412 | 'dart cool'.insert(4, ' is') // 'dart is cool'
413 | ```
414 |
415 | ### .isNullOrWhiteSpace()
416 | Indicates whether a specified string is `null`, `empty`, or consists only of `white-space` characters.
417 | ```dart
418 | 'test'.isNullOrWhiteSpace // false
419 | ' '.isNullOrWhiteSpace, // true
420 | null.isNullOrWhiteSpace, // true
421 | ' te st '.isNullOrWhiteSpace // false
422 | ```
423 |
424 | ### .replaceAfter()
425 | Replace part of string after the first occurrence of given delimiter.
426 | ```dart
427 | print("myemail@".replaceAfter("@", "gmail.com")); // myemail@gmail.com
428 | ```
429 | ### .replaceBefore()
430 | Replace part of string before the first occurrence of given delimiter.
431 | ```dart
432 | print('@domain.com'.replaceBefore('@', "name")); // "name@domain.com"
433 | ```
434 |
435 | ### .anyChar()
436 | Returns `true` if at least one element matches the given predicate
437 | ```dart
438 | 'test'.anyChar((c) => c == 't'); // true;
439 | 'test'.anyChar((c) => c == 'd'); // false;
440 | ```
441 |
442 | ### .ifEmpty()
443 | If the string is empty perform an action.
444 | ```dart
445 | "".ifEmpty(() => print("do any action here")); // do any action here
446 | ```
447 |
448 | ### .toDoubleOrNull()
449 | Parses the string as an integer or returns `null` if it is not a number.
450 | ```dart
451 | var number = '12345'.toDoubleOrNull(); // 12345
452 | var notANumber = '123-45'.toDoubleOrNull(); // null
453 | ```
454 |
455 | ### .limitFromEnd()
456 | Limit the string to a maximum length, taking from the end of the string.
457 | ```dart
458 | var longString = "0123456789";
459 | var noMoreThanThree = longString.limitFromEnd(3); // "789"
460 | ```
461 |
462 | ### .limitFromStart()
463 | Limit the string to a maximum length, taking from the start of the string.
464 | ```dart
465 | var longString = "0123456789";
466 | var noMoreThanThree = longString.limitFromStart(3); // "012"
467 | ```
468 |
469 | ## int Extensions
470 |
471 | ### .inRangeOf()
472 | Return the min if this number is smaller then minimum
473 | Return the max if this number is bigger the the maximum
474 | Return this number if it's between the range
475 | ```dart
476 | 1.inRangeOf(0, 3) // 1 number in range so will return the number
477 | 2.inRangeOf(3, 4) // 3 number is smaller then the range so will return min
478 | 5.inRangeOf(3, 4) // 4 number is bigger then the range so will return max
479 | ```
480 |
481 | # Flutter Extensions Full List
482 |
483 | ## Flutter
484 | - `Tooltip`
485 | - `algin`
486 | - `center`
487 | - `container`
488 | - `padding`
489 | - `navigation`
490 | - `Context`
491 | - `Text`
492 | - `List`
493 | - `Icon`
494 |
495 | ## Http Extensions
496 | - `httpGet`
497 | - `httpPost`
498 | - `httpPut`
499 | - `httpDelete`
500 |
501 | ## Iterables Extensions
502 | - `sortBy`
503 | - `toMutableSet`
504 | - `intersect`
505 | - `groupBy`
506 | - `find`
507 | - `filter`
508 | - `filterNot`
509 | - `isEmptyOrNull`
510 | - `chunks`
511 | - `zip`
512 | - `half`
513 | - `takeOnly`
514 | - `drop`
515 | - `firstHalf`
516 | - `secondHalf`
517 | - `swap`
518 | - `getRandom`
519 | - `firstOrNull`
520 | - `firstOrNullWhere`
521 | - `firstOrDefault`
522 | - `lastOrNull`
523 | - `lastOrDefault`
524 | - `forEachIndexed`
525 | - `sortedDescending`
526 | - `containsAll`
527 | - `count`
528 | - `distinctBy`
529 | - `subtract`
530 | - `concatWithSingleList`
531 | - `concatWithMultipleList`
532 | - `associate`
533 |
534 | ## Range Extensions
535 | - `until`
536 |
537 | ## Strings Extensions
538 | - `validateEmail`
539 | - `removeSurrounding`
540 | - `isNullOrEmpty`
541 | - `replaceAfter`
542 | - `replaceBefore`
543 | - `orEmpty`
544 | - `ifEmpty`
545 | - `lastIndex`
546 | - `printThis`
547 | - `equalsIgnoreCase`
548 | - `toDoubleOrNull`
549 | - `toIntOrNull`
550 | - `anyChar`
551 | - `removeAllWhiteSpace`
552 | - `isNotBlank`
553 | - `toCharArray`
554 | - `insert`
555 | - `isNullOrWhiteSpace`
556 | - `asBool`
557 |
558 | ## DateTime Extensions
559 | - `toMilliseconds`
560 | - `toSeconds`
561 | - `toMinutes`
562 | - `toHours`
563 | - `toDays`
564 | - `isToday`
565 | - `addOrRemoveYears`
566 | - `addOrRemoveMonth`
567 | - `addOrRemoveDay`
568 | - `addOrRemoveMinutes`
569 | - `addOrRemoveSeconds`
570 | - `startOfDay`
571 | - `startOfMonth`
572 | - `startOfYear`
573 | - `operator to add dates`
574 | - `operator to subtract dates`
575 | - `tomorrow`
576 | - `yesterday`
577 | - `min`
578 | - `max`
579 | - `isLeapYear`
580 | - `limitFromEnd`
581 | - `limitFromStart`
582 |
583 | ## Integers Extensions
584 | - `inRangeOf`
585 | - `absolute`
586 | - `isEven`
587 | - `isOdd`
588 | - `isPositive`
589 | - `isNegative`
590 | - `tenth`
591 | - `fourth`
592 | - `third`
593 | - `half`
594 | - `doubled`
595 | - `tripled`
596 | - `quadrupled`
597 | - `squared`
598 | - `asBool`
599 |
600 | ## Contributing
601 |
602 | If you have read up till here, then 🎉🎉🎉. There are couple of ways in which you can contribute to
603 | the growing community of `dart_extensions.dart`.
604 |
605 |
606 | - Propose any feature, enhancement
607 | - Report a bug
608 | - Fix a bug
609 | - Participate in a discussion and help in decision making
610 | - Write and improve some **documentation**. Documentation is super critical and its importance
611 | cannot be overstated!
612 | - Send in a Pull Request :-)
613 |
614 |
615 | ## Contributors ✨
616 |
626 |
627 |
628 |
629 | ## License
630 | ```
631 | Copyright 2020 Idan Ayalon
632 |
633 | Licensed under the Apache License, Version 2.0 (the "License");
634 | you may not use this file except in compliance with the License.
635 | You may obtain a copy of the License at
636 |
637 | http://www.apache.org/licenses/LICENSE-2.0
638 | Unless required by applicable law or agreed to in writing, software
639 | distributed under the License is distributed on an "AS IS" BASIS,
640 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
641 | See the License for the specific language governing permissions and
642 | limitations under the License.
643 | ```
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | /build/
32 |
33 | # Web related
34 | lib/generated_plugin_registrant.dart
35 |
36 | # Exceptions to above rules.
37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
38 |
--------------------------------------------------------------------------------
/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: fabeb2a16f1d008ab8230f450c49141d35669798
8 | channel: beta
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2015, Google Inc. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 |
14 | * Neither the name of Google Inc. nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | def localProperties = new Properties()
15 | def localPropertiesFile = rootProject.file('local.properties')
16 | if (localPropertiesFile.exists()) {
17 | localPropertiesFile.withReader('UTF-8') { reader ->
18 | localProperties.load(reader)
19 | }
20 | }
21 |
22 | def flutterRoot = localProperties.getProperty('flutter.sdk')
23 | if (flutterRoot == null) {
24 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
25 | }
26 |
27 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
28 | if (flutterVersionCode == null) {
29 | flutterVersionCode = '1'
30 | }
31 |
32 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
33 | if (flutterVersionName == null) {
34 | flutterVersionName = '1.0'
35 | }
36 |
37 | apply plugin: 'com.android.application'
38 | apply plugin: 'kotlin-android'
39 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
40 |
41 | android {
42 | compileSdkVersion 28
43 |
44 | sourceSets {
45 | main.java.srcDirs += 'src/main/kotlin'
46 | }
47 |
48 | lintOptions {
49 | disable 'InvalidPackage'
50 | }
51 |
52 | defaultConfig {
53 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
54 | applicationId "com.rallycoder.tests"
55 | minSdkVersion 16
56 | targetSdkVersion 28
57 | versionCode flutterVersionCode.toInteger()
58 | versionName flutterVersionName
59 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
60 | }
61 |
62 | buildTypes {
63 | release {
64 | // TODO: Add your own signing config for the release build.
65 | // Signing with the debug keys for now, so `flutter run --release` works.
66 | signingConfig signingConfigs.debug
67 | }
68 | }
69 | }
70 |
71 | flutter {
72 | source '../..'
73 | }
74 |
75 | dependencies {
76 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
77 | testImplementation 'junit:junit:4.12'
78 | androidTestImplementation 'androidx.test:runner:1.1.1'
79 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
80 | }
81 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
16 |
21 |
25 |
32 |
36 |
39 |
44 |
47 |
48 |
49 |
50 |
51 |
52 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/rallycoder/tests/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | package com.rallycoder.tests
15 |
16 | import androidx.annotation.NonNull;
17 | import io.flutter.embedding.android.FlutterActivity
18 | import io.flutter.embedding.engine.FlutterEngine
19 | import io.flutter.plugins.GeneratedPluginRegistrant
20 |
21 | class MainActivity : FlutterActivity() {
22 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
23 | GeneratedPluginRegistrant.registerWith(flutterEngine);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
21 |
27 |
30 |
31 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | buildscript {
15 | ext.kotlin_version = '1.3.50'
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 |
21 | dependencies {
22 | classpath 'com.android.tools.build:gradle:3.5.0'
23 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
24 | }
25 | }
26 |
27 | allprojects {
28 | repositories {
29 | google()
30 | jcenter()
31 | }
32 | }
33 |
34 | rootProject.buildDir = '../build'
35 | subprojects {
36 | project.buildDir = "${rootProject.buildDir}/${project.name}"
37 | }
38 | subprojects {
39 | project.evaluationDependsOn(':app')
40 | }
41 |
42 | task clean(type: Delete) {
43 | delete rootProject.buildDir
44 | }
45 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2020 Idan Ayalon. All rights reserved.
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 | #
13 | org.gradle.jvmargs=-Xmx1536M
14 | android.enableR8=true
15 | android.useAndroidX=true
16 | android.enableJetifier=true
17 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2020 Idan Ayalon. All rights reserved.
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 | #
13 | distributionBase=GRADLE_USER_HOME
14 | distributionPath=wrapper/dists
15 | zipStoreBase=GRADLE_USER_HOME
16 | zipStorePath=wrapper/dists
17 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
18 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | include ':app'
15 |
16 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
17 |
18 | def plugins = new Properties()
19 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
20 | if (pluginsFile.exists()) {
21 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
22 | }
23 |
24 | plugins.each { name, path ->
25 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
26 | include ":$name"
27 | project(":$name").projectDir = pluginDirectory
28 | }
29 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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/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 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droididan/dart_extensions/71546e78caa0ef10036cb6d77bfd7ab612f96b09/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 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | tests
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
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/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'package:dart_extensions/dart_extensions.dart';
15 | import 'package:flutter/material.dart';
16 |
17 | void main() => runApp(MyApp());
18 |
19 | class MyApp extends StatelessWidget {
20 | // This widget is the root of your application.
21 | @override
22 | Widget build(BuildContext context) {
23 | return MaterialApp(
24 | routes: {"/login": (_) => Login()},
25 | title: 'Flutter Demo',
26 | theme: ThemeData(primarySwatch: Colors.blue),
27 | home: Padding(
28 | padding: const EdgeInsets.all(8.0),
29 | child: Home(),
30 | ),
31 | );
32 | }
33 | }
34 |
35 | class Routes {
36 | static final login = "/login";
37 | }
38 |
39 | class Home extends StatefulWidget {
40 |
41 |
42 | @override
43 | _HomeState createState() => _HomeState();
44 | }
45 |
46 | class _HomeState extends State {
47 | @override
48 | Widget build(BuildContext context) {
49 |
50 | print([1,2,3,4].mapList((f) => f.toDouble()));
51 | return Scaffold(
52 | body: Container(
53 | child: Stack(
54 | children: [
55 | Container(height: 100, width: 100)
56 | .withRoundCorners(backgroundColor: Colors.grey)
57 | .withShadow()
58 | .alignAtCenter()
59 | .toCenter()
60 | .paddingOnly(left: 10)
61 | .paddingAll(20)
62 | .onTap(
63 | () async {
64 | final result = await navigateByRouteName(Routes.login);
65 | print(result);
66 | },
67 | ) .withTooltip('just a tooltip')
68 | .onLongPress(() => print('long press'))
69 |
70 | ],
71 | ),
72 | ),
73 | );
74 | }
75 | }
76 |
77 | class Login extends StatelessWidget {
78 | @override
79 | Widget build(BuildContext context) {
80 | return Container(
81 | color: Colors.grey,
82 | child: Center(
83 | child: MaterialButton(
84 | child: Text('Go Back'),
85 | onPressed: () => Navigator.pop(context),
86 | ),
87 | ),
88 | );
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: tests
2 | description: A new Flutter application.
3 | publish_to: none
4 |
5 | version: 1.0.0+1
6 | homepage: https://github.com/droididan/dart_extentions
7 | environment:
8 | sdk: ">=2.7.0 <3.0.0"
9 |
10 | dependencies:
11 | flutter:
12 | sdk: flutter
13 |
14 | dart_extensions:
15 | path: ../
16 |
17 | cupertino_icons: ^1.0.0
18 |
19 | dev_dependencies:
20 | flutter_test:
21 | sdk: flutter
22 |
23 | flutter:
24 | uses-material-design: true
25 |
--------------------------------------------------------------------------------
/example/test/main.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
--------------------------------------------------------------------------------
/flutter_extentions.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/dart_extensions.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | export 'package:dart_extensions/src/data_stractures/stack.dart';
15 | export 'package:dart_extensions/src/date.dart';
16 | export 'package:dart_extensions/src/files.dart';
17 | export 'package:dart_extensions/src/flutter/align.dart';
18 | export 'package:dart_extensions/src/flutter/icon.dart';
19 | export 'package:dart_extensions/src/flutter/list.dart';
20 | export 'package:dart_extensions/src/flutter/text.dart';
21 | export 'package:dart_extensions/src/flutter/center.dart';
22 | export 'package:dart_extensions/src/flutter/context.dart';
23 | export 'package:dart_extensions/src/flutter/container.dart';
24 | export 'package:dart_extensions/src/flutter/gesture_detector.dart';
25 | export 'package:dart_extensions/src/flutter/navigation.dart';
26 | export 'package:dart_extensions/src/flutter/padding.dart';
27 | export 'package:dart_extensions/src/http.dart';
28 | export 'package:dart_extensions/src/int.dart';
29 | export 'package:dart_extensions/src/iterable.dart';
30 | export 'package:dart_extensions/src/ranges.dart';
31 | export 'package:dart_extensions/src/search_algorithms.dart';
32 | export 'package:dart_extensions/src/sort_algorithms.dart';
33 | export 'package:dart_extensions/src/string_ext.dart';
34 | export 'package:dart_extensions/src/flutter/widgets.dart';
35 |
36 |
--------------------------------------------------------------------------------
/lib/emum.dart:
--------------------------------------------------------------------------------
1 | extension EnumExt on dynamic {
2 | static bool _isEnumItem(enumItem) {
3 | final splitEnum = enumItem.toString().split('.');
4 | return splitEnum.length > 1 && splitEnum[0] == enumItem.runtimeType.toString();
5 | }
6 |
7 | String convertToString({bool camelCase = false}) {
8 | assert(this != null);
9 | assert(_isEnumItem(this), '$this of type ${this.runtimeType.toString()} is not an enum item');
10 | final temp = this.toString().split('.')[1];
11 | return !camelCase ? temp : camelCaseToWords(temp);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/data_stractures/stack.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'dart:collection';
15 |
16 | class StackX {
17 | final _list = ListQueue();
18 |
19 | bool get isEmpty => _list.isEmpty;
20 |
21 | bool get isNotEmpty => _list.isNotEmpty;
22 |
23 | push(T element) => _list.addLast(element);
24 |
25 | T pop() {
26 | final T element = _list.last;
27 | _list.removeLast();
28 | return element;
29 | }
30 |
31 | top() => _list.last;
32 |
33 | List addAll(Iterable elements) {
34 | _list.addAll(elements);
35 | return _list.toList();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/date.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | extension DateString on String {
15 | /// Parse string to [DateTime]
16 | DateTime? toDateTime() {
17 | try {
18 | return DateTime.tryParse(this);
19 | } on Exception catch (_) {
20 | return null;
21 | }
22 | }
23 | }
24 |
25 | extension DateInt on int {
26 | Duration toMilliseconds() => Duration(milliseconds: this);
27 |
28 | Duration toSeconds() => Duration(seconds: this);
29 |
30 | Duration toMinutes() => Duration(minutes: this);
31 |
32 | Duration toHours() => Duration(hours: this);
33 |
34 | Duration toDays() => Duration(days: this);
35 | }
36 |
37 | extension DateExtensions on DateTime {
38 | /// Adds this DateTime and Duration and returns the sum as a new DateTime object.
39 | DateTime operator +(Duration duration) => add(duration);
40 |
41 | /// Subtracts the Duration from this DateTime returns the difference as a new DateTime object.
42 | DateTime operator -(Duration duration) => subtract(duration);
43 |
44 | /// Returns true if [other] is in the same year as [this].
45 | ///
46 | /// Does not account for timezones.
47 | bool isAtSameYearAs(DateTime other) => year == other.year;
48 |
49 | /// Returns true if [other] is in the same month as [this].
50 | ///
51 | /// This means the exact month, including year.
52 | ///
53 | /// Does not account for timezones.
54 | bool isAtSameMonthAs(DateTime other) =>
55 | isAtSameYearAs(other) && month == other.month;
56 |
57 | /// Returns true if [other] is on the same day as [this].
58 | ///
59 | /// This means the exact day, including year and month.
60 | ///
61 | /// Does not account for timezones.
62 | bool isAtSameDayAs(DateTime other) =>
63 | isAtSameMonthAs(other) && day == other.day;
64 |
65 | /// Returns true if [other] is at the same hour as [this].
66 | ///
67 | /// This means the exact hour, including year, month and day.
68 | ///
69 | /// Does not account for timezones.
70 | bool isAtSameHourAs(DateTime other) =>
71 | isAtSameDayAs(other) && hour == other.hour;
72 |
73 | /// Returns true if [other] is at the same minute as [this].
74 | ///
75 | /// This means the exact minute, including year, month, day and hour.
76 | ///
77 | /// Does not account for timezones.
78 | bool disAtSameMinuteAs(DateTime other) =>
79 | isAtSameHourAs(other) && minute == other.minute;
80 |
81 | /// Returns true if [other] is at the same minute as [this].
82 | ///
83 | /// This means the exact minute, including year, month, day and hour.
84 | ///
85 | /// Does not account for timezones.
86 | bool isAtSameMinuteAs(DateTime other) =>
87 | isAtSameHourAs(other) && minute == other.minute;
88 |
89 | /// Returns true if [other] is at the same second as [this].
90 | ///
91 | /// This means the exact second, including year, month, day, hour and minute.
92 | ///
93 | /// Does not account for timezones.
94 | bool isAtSameSecondAs(DateTime other) =>
95 | isAtSameMinuteAs(other) && second == other.second;
96 |
97 | /// Returns true if [other] is at the same millisecond as [this].
98 | ///
99 | /// This means the exact millisecond,
100 | /// including year, month, day, hour, minute and second.
101 | ///
102 | /// Does not account for timezones.
103 | bool isAtSameMillisecondAs(DateTime other) =>
104 | isAtSameSecondAs(other) && millisecond == other.millisecond;
105 |
106 | /// Returns true if [other] is at the same microsecond as [this].
107 | ///
108 | /// This means the exact microsecond,
109 | /// including year, month, day, hour, minute, second and millisecond.
110 | ///
111 | /// Does not account for timezones.
112 | bool isAtSameMicrosecondAs(DateTime other) =>
113 | isAtSameMillisecondAs(other) && microsecond == other.microsecond;
114 |
115 | bool get isYesterday {
116 | final nowDate = DateTime.now();
117 | return year == nowDate.year &&
118 | month == nowDate.month &&
119 | day == nowDate.day - 1;
120 | }
121 |
122 | /// The list of days in a given month
123 | List get daysInMonth {
124 | var first = firstDayOfMonth;
125 | var daysBefore = first.weekday;
126 | var firstToDisplay = first.subtract(Duration(days: daysBefore));
127 | var last = lastDayOfMonth;
128 |
129 | var daysAfter = 7 - last.weekday;
130 |
131 | // If the last day is sunday (7) the entire week must be rendered
132 | if (daysAfter == 0) {
133 | daysAfter = 7;
134 | }
135 |
136 | var lastToDisplay = last.add(Duration(days: daysAfter));
137 | return daysInRange(firstToDisplay, lastToDisplay).toList();
138 | }
139 |
140 | bool get isFirstDayOfMonth => isSameDay(firstDayOfMonth, this);
141 |
142 | bool get isLastDayOfMonth => isSameDay(lastDayOfMonth, this);
143 |
144 | DateTime get firstDayOfMonth => DateTime(this.year, this.month);
145 |
146 | DateTime get firstDayOfWeek {
147 | /// Handle Daylight Savings by setting hour to 12:00 Noon
148 | /// rather than the default of Midnight
149 | final day = DateTime.utc(this.year, this.month, this.day, 12);
150 |
151 | /// Weekday is on a 1-7 scale Monday - Sunday,
152 | /// This Calendar works from Sunday - Monday
153 | var decreaseNum = day.weekday % 7;
154 | return this.subtract(Duration(days: decreaseNum));
155 | }
156 |
157 | DateTime get lastDayOfWeek {
158 | /// Handle Daylight Savings by setting hour to 12:00 Noon
159 | /// rather than the default of Midnight
160 | final day = DateTime.utc(this.year, this.month, this.day, 12);
161 |
162 | /// Weekday is on a 1-7 scale Monday - Sunday,
163 | /// This Calendar's Week starts on Sunday
164 | var increaseNum = day.weekday % 7;
165 | return day.add(Duration(days: 7 - increaseNum));
166 | }
167 |
168 | /// The last day of a given month
169 | DateTime get lastDayOfMonth {
170 | var beginningNextMonth = (this.month < 12)
171 | ? DateTime(this.year, this.month + 1, 1)
172 | : DateTime(this.year + 1, 1, 1);
173 | return beginningNextMonth.subtract(Duration(days: 1));
174 | }
175 |
176 | DateTime get previousMonth {
177 | var year = this.year;
178 | var month = this.month;
179 | if (month == 1) {
180 | year--;
181 | month = 12;
182 | } else {
183 | month--;
184 | }
185 | return DateTime(year, month);
186 | }
187 |
188 | DateTime get nextMonth {
189 | var year = this.year;
190 | var month = this.month;
191 |
192 | if (month == 12) {
193 | year++;
194 | month = 1;
195 | } else {
196 | month++;
197 | }
198 | return DateTime(year, month);
199 | }
200 |
201 | DateTime get previousWeek => this.subtract(Duration(days: 7));
202 |
203 | DateTime get nextWeek => this.add(Duration(days: 7));
204 |
205 | /// Returns a [DateTime] for each day the given range.
206 | ///
207 | /// [start] inclusive
208 | /// [end] exclusive
209 | static Iterable daysInRange(DateTime start, DateTime end) sync* {
210 | var i = start;
211 | var offset = start.timeZoneOffset;
212 | while (i.isBefore(end)) {
213 | yield i;
214 | i = i.add(Duration(days: 1));
215 | var timeZoneDiff = i.timeZoneOffset - offset;
216 | if (timeZoneDiff.inSeconds != 0) {
217 | offset = i.timeZoneOffset;
218 | i = i.subtract(Duration(seconds: timeZoneDiff.inSeconds));
219 | }
220 | }
221 | }
222 |
223 | static bool isSameWeek(DateTime a, DateTime b) {
224 | /// Handle Daylight Savings by setting hour to 12:00 Noon
225 | /// rather than the default of Midnight
226 | a = DateTime.utc(a.year, a.month, a.day);
227 | b = DateTime.utc(b.year, b.month, b.day);
228 |
229 | var diff = a.toUtc().difference(b.toUtc()).inDays;
230 | if (diff.abs() >= 7) {
231 | return false;
232 | }
233 |
234 | var min = a.isBefore(b) ? a : b;
235 | var max = a.isBefore(b) ? b : a;
236 | var result = max.weekday % 7 - min.weekday % 7 >= 0;
237 | return result;
238 | }
239 |
240 | /// Whether or not two times are on the same day.
241 | static bool isSameDay(DateTime a, DateTime b) =>
242 | a.year == b.year && a.month == b.month && a.day == b.day;
243 |
244 | /// return true if the date is today
245 | bool isToday() {
246 | final now = DateTime.now();
247 | final today = DateTime(now.year, now.month, now.day);
248 | final currentDate = DateTime(year, month, day);
249 | return today.isAtSameMomentAs(currentDate);
250 | }
251 |
252 | /// to add years to a [DateTime] add a positive number
253 | /// to remove years pass a negative number
254 | addOrRemoveYears(int years) {
255 | return DateTime(year + years, month, day, minute, second);
256 | }
257 |
258 | /// to add month to a [DateTime] add a positive number
259 | /// to remove years pass a negative number
260 | addOrRemoveMonth(int months) {
261 | return DateTime(year, month + months, day, minute, second);
262 | }
263 |
264 | /// to add days to a [DateTime] add a positive number
265 | /// to remove days pass a negative number
266 | addOrRemoveDay(int days) {
267 | return DateTime(year, month, day + days, minute, second);
268 | }
269 |
270 | /// to add min to a [DateTime] add a positive number
271 | /// to remove min pass a negative number
272 | addOrRemoveMinutes(int min) {
273 | return DateTime(year, month, day, minute + min, second);
274 | }
275 |
276 | /// to add sec to a [DateTime] add a positive number
277 | /// to remove sec pass a negative number
278 | addOrRemoveSeconds(int sec) {
279 | return DateTime(year, month, day, minute, second + sec);
280 | }
281 |
282 | /// Start time of Date times
283 | DateTime startOfDay() => DateTime(year, month, day);
284 |
285 | DateTime startOfMonth() => DateTime(year, month);
286 |
287 | DateTime startOfYear() => DateTime(year);
288 |
289 | /// next day
290 | DateTime tomorrow() => DateTime(year, month, day + 1);
291 |
292 | /// last day
293 | DateTime yesterday() => DateTime(year, month, day - 1);
294 |
295 | /// return the smaller date between
296 | DateTime min(DateTime that) =>
297 | (millisecondsSinceEpoch < that.millisecondsSinceEpoch) ? this : that;
298 |
299 | DateTime max(DateTime that) =>
300 | (millisecondsSinceEpoch > that.millisecondsSinceEpoch) ? this : that;
301 |
302 | bool get isLeapYear =>
303 | (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
304 | }
305 |
--------------------------------------------------------------------------------
/lib/src/equality.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | typedef Comparer = bool Function(T left, T right);
15 |
16 | typedef Hasher = int Function(T value);
17 |
18 | typedef Sorter = int Function(T left, T right);
19 |
20 | class EqualityComparer {
21 | final Comparer compare;
22 | final Hasher hash;
23 | final Sorter sort;
24 |
25 | EqualityComparer({
26 | Comparer? comparer,
27 | Hasher? hasher,
28 | Sorter? sorter,
29 | }) : compare = comparer ?? _getDefaultComparer(),
30 | hash = hasher ?? _getDefaultHasher(),
31 | sort = sorter ?? _getDefaultSorter();
32 |
33 | static Comparer _getDefaultComparer() =>
34 | (T left, T right) => left == right;
35 |
36 | static Hasher _getDefaultHasher() => (T value) => value.hashCode;
37 |
38 | static Sorter _getDefaultSorter() => (left, right) => 0;
39 |
40 | static EqualityComparer forType() => _registeredEqualityComparers[T] as EqualityComparer;
41 |
42 | static final Map _registeredEqualityComparers = {
43 | dynamic: EqualityComparer(
44 | comparer: (left, right) => left == right,
45 | hasher: (value) => value.hashCode,
46 | sorter: (left, right) => 0,
47 | ),
48 | num: EqualityComparer(
49 | comparer: (left, right) => left == right,
50 | hasher: (value) => value.hashCode,
51 | sorter: (left, right) => left.compareTo(right),
52 | ),
53 | int: EqualityComparer(
54 | comparer: (left, right) => left == right,
55 | hasher: (value) => value.hashCode,
56 | sorter: (left, right) => left.compareTo(right),
57 | ),
58 | double: EqualityComparer(
59 | comparer: (left, right) => left == right,
60 | hasher: (value) => value.hashCode,
61 | sorter: (left, right) => left.compareTo(right),
62 | ),
63 | String: EqualityComparer(
64 | comparer: (left, right) => left == right,
65 | hasher: (value) => value.hashCode,
66 | sorter: (left, right) => left.compareTo(right),
67 | ),
68 | Duration: EqualityComparer(
69 | comparer: (left, right) => left == right,
70 | hasher: (value) => value.hashCode,
71 | sorter: (left, right) => left.compareTo(right),
72 | ),
73 | BigInt: EqualityComparer(
74 | comparer: (left, right) => left == right,
75 | hasher: (value) => value.hashCode,
76 | sorter: (left, right) => left.compareTo(right),
77 | ),
78 | };
79 |
80 | static bool registerEqualityComparer(EqualityComparer comparer,
81 | {bool overwrite = false}) {
82 | var typeExists = _registeredEqualityComparers.containsKey(T);
83 | if (!typeExists || overwrite) _registeredEqualityComparers[T] = comparer;
84 | return typeExists;
85 | }
86 |
87 | /// [EqualityComparer.registerEqualityComparer].
88 | static EqualityComparer unregisterEqualityComparer() {
89 | return _registeredEqualityComparers.remove(T) as EqualityComparer;
90 | }
91 | }
92 |
93 | abstract class OrderedIterable extends Iterable {
94 | Iterable source;
95 |
96 | OrderedIterable(this.source);
97 |
98 | IterableSorter getIterableSorter(IterableSorter next);
99 |
100 | OrderedIterable createOrderedIterable(
101 | TNewKey Function(T) keySelector,
102 | EqualityComparer keyComparer,
103 | bool descending) {
104 | final result = InternalOrderedIterable(
105 | source, keySelector, keyComparer, descending);
106 | result.parent = this;
107 | return result;
108 | }
109 | }
110 |
111 | class InternalOrderedIterable extends OrderedIterable {
112 | OrderedIterable? parent;
113 | TKey Function(TValue) keySelector;
114 | EqualityComparer keyComparer;
115 | bool? descending;
116 |
117 | InternalOrderedIterable(Iterable source, this.keySelector,
118 | this.keyComparer, this.descending)
119 | : super(source) {
120 | this.source = source;
121 | }
122 |
123 | @override
124 | Iterator get iterator => iterate().iterator;
125 |
126 | Iterable iterate() sync* {
127 | final buffer = source.toList();
128 | if (buffer.isNotEmpty) {
129 | final sorter = getIterableSorter(null);
130 | final map = sorter.sort(buffer, buffer.length);
131 | yield* OrderedBuffer(buffer, map);
132 | }
133 | }
134 |
135 | @override
136 | IterableSorter getIterableSorter(IterableSorter? next) {
137 | IterableSorter? sorter = InternalIterableSorter(
138 | keySelector, keyComparer, next,descending: descending);
139 | if (parent != null) sorter = parent!.getIterableSorter(sorter);
140 | return sorter;
141 | }
142 | }
143 |
144 | abstract class IterableSorter {
145 | void computeKeys(List elements, int count);
146 |
147 | int compareKeys(int idx1, int idx2);
148 |
149 | List sort(List elements, int count) {
150 | computeKeys(elements, count);
151 | final map = List.generate(count, (i) => i, growable: false);
152 | quickSort(map, 0, count - 1);
153 | return map;
154 | }
155 |
156 | void quickSort(List map, int left, int right) {
157 | do {
158 | var i = left;
159 | var j = right;
160 | final x = map[i + ((j - i) >> 1)];
161 | do {
162 | while (i < map.length && compareKeys(x, map[i]) > 0) {
163 | i++;
164 | }
165 | while (j >= 0 && compareKeys(x, map[j]) < 0) {
166 | j--;
167 | }
168 | if (i > j) break;
169 | if (i < j) {
170 | final temp = map[i];
171 | map[i] = map[j];
172 | map[j] = temp;
173 | }
174 | i++;
175 | j--;
176 | } while (i <= j);
177 | if (j - left <= right - i) {
178 | if (left < j) quickSort(map, left, j);
179 | left = i;
180 | } else {
181 | if (i < right) quickSort(map, i, right);
182 | right = j;
183 | }
184 | } while (left < right);
185 | }
186 | }
187 |
188 | class InternalIterableSorter extends IterableSorter {
189 | late TKey Function(TValue) keySelector;
190 | EqualityComparer? comparer;
191 | bool? descending;
192 | IterableSorter? next;
193 | late List keys;
194 |
195 | InternalIterableSorter(
196 | this.keySelector,
197 | this.comparer,
198 | this.next, {
199 | this.descending = false,
200 | }) {
201 | comparer ??= EqualityComparer.forType();
202 | }
203 |
204 | @override
205 | void computeKeys(List elements, int count) {
206 | keys = List.generate(count, (i) => keySelector(elements[i]));
207 | if (next != null) next!.computeKeys(elements, count);
208 | }
209 |
210 | @override
211 | int compareKeys(int index1, int index2) {
212 | final c = comparer?.sort(keys[index1], keys[index2]) ?? -1;
213 | if (c == 0) {
214 | if (next == null) return index1 - index2;
215 | return next!.compareKeys(index1, index2);
216 | }
217 | return descending! ? -c : c;
218 | }
219 | }
220 |
221 | class OrderedBuffer extends Iterable {
222 | List data;
223 | List orderedMap;
224 |
225 | OrderedBuffer(this.data, this.orderedMap);
226 |
227 | @override
228 | Iterator get iterator => iterate().iterator;
229 |
230 | Iterable iterate() sync* {
231 | for (var index in orderedMap) {
232 | yield data[index];
233 | }
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/lib/src/exceptions/range_exception.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /// Represents a range exception.
15 | class RException {
16 | RException(this.message);
17 |
18 | RException.steps() : message = 'The range must be more then 0';
19 |
20 | final String? message;
21 |
22 | @override
23 | String toString() {
24 | return 'RException: ${message ?? ''}';
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/files.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
--------------------------------------------------------------------------------
/lib/src/flutter/align.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | import 'package:flutter/material.dart';
14 |
15 | extension AlignExtensions on Widget {
16 | Align alignAtBottomCenter({
17 | Key? key,
18 | double? heightFactor,
19 | double? widthFactor,
20 | }) =>
21 | Align(
22 | key: key,
23 | child: this,
24 | alignment: Alignment.bottomCenter,
25 | heightFactor: heightFactor,
26 | widthFactor: widthFactor,
27 | );
28 |
29 | Align alignAtTopLeft({
30 | Key? key,
31 | double? heightFactor,
32 | double? widthFactor,
33 | }) =>
34 | Align(
35 | key: key,
36 | child: this,
37 | alignment: Alignment.topLeft,
38 | heightFactor: heightFactor,
39 | widthFactor: widthFactor,
40 | );
41 |
42 | Align alignAtBottomLeft({
43 | Key? key,
44 | double? heightFactor,
45 | double? widthFactor,
46 | }) =>
47 | Align(
48 | key: key,
49 | child: this,
50 | alignment: Alignment.bottomLeft,
51 | heightFactor: heightFactor,
52 | widthFactor: widthFactor,
53 | );
54 |
55 | Align alignAtBottomRight({
56 | Key? key,
57 | double? heightFactor,
58 | double? widthFactor,
59 | }) =>
60 | Align(
61 | key: key,
62 | child: this,
63 | alignment: Alignment.bottomRight,
64 | heightFactor: heightFactor,
65 | widthFactor: widthFactor,
66 | );
67 |
68 | Align alignAtCenterLeft({
69 | Key? key,
70 | double? heightFactor,
71 | double? widthFactor,
72 | }) =>
73 | Align(
74 | key: key,
75 | child: this,
76 | alignment: Alignment.centerLeft,
77 | heightFactor: heightFactor,
78 | widthFactor: widthFactor,
79 | );
80 |
81 | Align alignAtCenter({
82 | Key? key,
83 | double? heightFactor,
84 | double? widthFactor,
85 | }) =>
86 | Align(
87 | key: key,
88 | child: this,
89 | alignment: Alignment.center,
90 | heightFactor: heightFactor,
91 | widthFactor: widthFactor,
92 | );
93 |
94 | Align alignAtCenterRight({
95 | Key? key,
96 | double? heightFactor,
97 | double? widthFactor,
98 | }) =>
99 | Align(
100 | key: key,
101 | child: this,
102 | alignment: Alignment.centerRight,
103 | heightFactor: heightFactor,
104 | widthFactor: widthFactor,
105 | );
106 |
107 | Align alignAtLERP(
108 | Alignment a,
109 | Alignment b,
110 | double t, {
111 | Key? key,
112 | double? heightFactor,
113 | double? widthFactor,
114 | }) =>
115 | Align(
116 | key: key,
117 | child: this,
118 | alignment: Alignment.lerp(a, b, t)!,
119 | heightFactor: heightFactor,
120 | widthFactor: widthFactor,
121 | );
122 |
123 | Align alignXY(
124 | double x,
125 | double y, {
126 | Key? key,
127 | double? heightFactor,
128 | double? widthFactor,
129 | }) =>
130 | Align(
131 | key: key,
132 | child: this,
133 | alignment: Alignment(x, y),
134 | heightFactor: heightFactor,
135 | widthFactor: widthFactor,
136 | );
137 |
138 | Align alignAtTopCenter({
139 | Key? key,
140 | double? heightFactor,
141 | double? widthFactor,
142 | }) =>
143 | Align(
144 | key: key,
145 | child: this,
146 | alignment: Alignment.topCenter,
147 | heightFactor: heightFactor,
148 | widthFactor: widthFactor,
149 | );
150 |
151 | Align alignAtTopRight({
152 | Key? key,
153 | double? heightFactor,
154 | double? widthFactor,
155 | }) =>
156 | Align(
157 | key: key,
158 | child: this,
159 | alignment: Alignment.topRight,
160 | heightFactor: heightFactor,
161 | widthFactor: widthFactor,
162 | );
163 | }
164 |
--------------------------------------------------------------------------------
/lib/src/flutter/center.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'package:flutter/material.dart';
15 |
16 | extension CenterExtension on Widget {
17 | Center toCenter() {
18 | return Center(
19 | child: this,
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/src/flutter/container.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | import 'package:flutter/material.dart';
14 |
15 | extension ContainerExtensions on Container {
16 | /// Add round corners to a Container
17 | /// if the Container already has a color use [backgroundColor] instead and remove the
18 | /// [Color] from the Container it self
19 | Container withRoundCorners({required Color backgroundColor}) => Container(
20 | decoration: BoxDecoration(
21 | color: backgroundColor,
22 | borderRadius: BorderRadius.all(
23 | Radius.circular(25),
24 | ),
25 | ),
26 | child: this,
27 | );
28 |
29 | /// A shadow cast by a box
30 | ///
31 | /// [shadowColor]
32 | Container withShadow(
33 | {Color shadowColor = Colors.grey,
34 | double blurRadius = 20.0,
35 | double spreadRadius = 1.0,
36 | Offset offset = const Offset(10.0, 10.0)}) =>
37 | Container(
38 | decoration: BoxDecoration(
39 | boxShadow: [
40 | BoxShadow(color: shadowColor, blurRadius: blurRadius, spreadRadius: spreadRadius, offset: offset),
41 | ],
42 | ),
43 | child: this,
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/lib/src/flutter/context.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension ContextExtensions on BuildContext {
4 |
5 | // Returns the MediaQuery
6 | MediaQueryData get mq => MediaQuery.of(this);
7 |
8 | /// Returns if Orientation is landscape
9 | bool get isLandscape => mq.orientation == Orientation.landscape;
10 |
11 | /// Returns same as MediaQuery.of(context).size
12 | Size get sizePx => mq.size;
13 |
14 | /// Returns same as MediaQuery.of(context).size.width
15 | double get widthPx => sizePx.width;
16 |
17 | /// Returns same as MediaQuery.of(context).height
18 | double get heightPx => sizePx.height;
19 |
20 | }
--------------------------------------------------------------------------------
/lib/src/flutter/duration.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import '../date.dart';
3 | extension DurationExt on Duration {
4 | /// Utility to delay some callback (or code execution).
5 | ///
6 | /// Sample:
7 | /// ```
8 | /// await 3.seconds.delay(() {
9 | /// ....
10 | /// }
11 | ///
12 | ///```
13 | Future delay([FutureOr callback()?]) async => Future.delayed(this, callback);
14 |
15 | static const int daysPerWeek = 7;
16 | static const int nanosecondsPerMicrosecond = 1000;
17 |
18 | /// Returns the representation in weeks
19 | int get inWeeks => (inDays / daysPerWeek).ceil();
20 |
21 | /// Adds the Duration to the current DateTime and returns a DateTime in the future
22 | DateTime get fromNow => DateTime.now() + this;
23 |
24 | /// Subtracts the Duration from the current DateTime and returns a DateTime in the past
25 | DateTime get ago => DateTime.now() - this;
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/flutter/gesture_detector.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'package:dart_extensions/src/flutter/transforms/click_translate.dart';
15 | import 'package:flutter/material.dart';
16 |
17 | extension GestureDetectorExtensions on Widget {
18 | Widget get onTapAddJumpEffect => TranslateOnClick(child: this);
19 |
20 | Widget onDoubleTap(Function() function) => GestureDetector(
21 | onDoubleTap: function,
22 | child: this,
23 | );
24 |
25 | Widget onTap(Function() function) => GestureDetector(
26 | onTap: function,
27 | child: this,
28 | );
29 |
30 | Widget onLongPress(Function() function) => GestureDetector(
31 | onLongPress: function,
32 | child: this,
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/flutter/icon.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension IconExtensions on T {
4 | Icon copyWith({
5 | Color? color,
6 | double? size,
7 | String? semanticLabel,
8 | TextDirection? textDirection,
9 | }) {
10 | return Icon(
11 | this.icon,
12 | color: color ?? this.color,
13 | size: size ?? this.size,
14 | semanticLabel: semanticLabel ?? this.semanticLabel,
15 | textDirection: textDirection ?? this.textDirection,
16 | );
17 | }
18 |
19 | T iconSize(double size) => this.copyWith(size: size) as T;
20 |
21 | T iconColor(Color color) => this.copyWith(color: color) as T;
22 | }
23 |
--------------------------------------------------------------------------------
/lib/src/flutter/list.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension ListExtensions on List {
4 | Widget toRowWidget({
5 | Key? key,
6 | MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
7 | MainAxisSize mainAxisSize = MainAxisSize.max,
8 | CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
9 | TextDirection? textDirection,
10 | VerticalDirection verticalDirection = VerticalDirection.down,
11 | TextBaseline? textBaseline,
12 | List children = const [],
13 | }) =>
14 | Row(
15 | key: key,
16 | mainAxisAlignment: mainAxisAlignment,
17 | mainAxisSize: mainAxisSize,
18 | crossAxisAlignment: crossAxisAlignment,
19 | textDirection: textDirection,
20 | verticalDirection: verticalDirection,
21 | textBaseline: textBaseline,
22 | children: this,
23 | );
24 |
25 | Widget toStackWidget({
26 | Key? key,
27 | AlignmentGeometry alignment = AlignmentDirectional.topStart,
28 | TextDirection? textDirection,
29 | StackFit fit = StackFit.loose,
30 | Clip clip = Clip.hardEdge,
31 | List children = const [],
32 | }) =>
33 | Stack(
34 | key: key,
35 | alignment: alignment,
36 | textDirection: textDirection,
37 | fit: fit,
38 | clipBehavior: clip,
39 | children: this,
40 | );
41 |
42 | Widget toColumnWidget({
43 | Key? key,
44 | MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
45 | MainAxisSize mainAxisSize = MainAxisSize.max,
46 | CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
47 | TextDirection? textDirection,
48 | VerticalDirection verticalDirection = VerticalDirection.down,
49 | TextBaseline? textBaseline,
50 | List children = const [],
51 | }) =>
52 | Column(
53 | key: key,
54 | mainAxisAlignment: mainAxisAlignment,
55 | mainAxisSize: mainAxisSize,
56 | crossAxisAlignment: crossAxisAlignment,
57 | textDirection: textDirection,
58 | verticalDirection: verticalDirection,
59 | textBaseline: textBaseline,
60 | children: this,
61 | );
62 | }
63 |
--------------------------------------------------------------------------------
/lib/src/flutter/navigation.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'package:flutter/material.dart';
15 |
16 | extension NavigationStateExtensions on State {
17 | /// Navigate to another widget
18 | Future navigateTo({required Route route}) => Navigator.push(this.context, route);
19 |
20 | /// Navigate to another widget and replace remove the current one
21 | Future navigatePushReplacement({required Route route}) => Navigator.pushReplacement(this.context, route);
22 |
23 |
24 | /// Navigate to widget by the route name
25 | Future navigateByRouteName(String routeName, {Object? args}) =>
26 | Navigator.pushNamed(context, routeName, arguments: args);
27 | }
28 |
29 | extension NavigationStatelessExtensions on StatelessWidget {
30 | /// Navigate to another widget
31 | Future navigateTo({required BuildContext context, required Route route}) => Navigator.push(context, route);
32 |
33 | /// Navigate to another widget and replace remove the current one
34 | Future navigatePushReplacement({required BuildContext context,required Route route}) => Navigator.pushReplacement(context, route);
35 |
36 | /// Navigate to widget by the route name
37 | Future navigateByRouteName({required BuildContext context, required String routeName, Object? args}) =>
38 | Navigator.pushNamed(context, routeName, arguments: args);
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/lib/src/flutter/padding.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'package:flutter/material.dart';
15 |
16 | extension PaddingExtensions on Widget {
17 | Padding paddingAll(double value, {Key? key}) {
18 | return Padding(
19 | key: key,
20 | padding: EdgeInsets.all(value),
21 | child: this,
22 | );
23 | }
24 |
25 | Padding paddingLTRB(
26 | double left,
27 | double top,
28 | double right,
29 | double bottom, {
30 | Key? key,
31 | }) =>
32 | Padding(
33 | key: key,
34 | padding: EdgeInsets.fromLTRB(left, top, right, bottom),
35 | child: this,
36 | );
37 |
38 | Padding paddingSymmetric({Key? key, double v = 0.0, double h = 0.0}) => Padding(
39 | key: key,
40 | padding: EdgeInsets.symmetric(
41 | vertical: v,
42 | horizontal: h,
43 | ),
44 | child: this,
45 | );
46 |
47 | Padding paddingOnly({Key? key, double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) =>
48 | Padding(
49 | key: key,
50 | padding: EdgeInsets.only(left: left, right: right, top: top, bottom: bottom),
51 | child: this,
52 | );
53 | }
54 |
--------------------------------------------------------------------------------
/lib/src/flutter/responsive.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/foundation.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class ResponsiveTools {
7 | /// Device's BoxConstraints
8 | static late BoxConstraints boxConstraints;
9 |
10 | static late Orientation orientation;
11 |
12 | static late DeviceType deviceType;
13 |
14 | static late double h;
15 |
16 | static late double w;
17 |
18 | static void setAppSize(BoxConstraints constraints, Orientation currentOrientation) {
19 | boxConstraints = constraints;
20 | orientation = currentOrientation;
21 |
22 | // Sets screen width and height
23 | if (orientation == Orientation.portrait) {
24 | w = boxConstraints.maxWidth;
25 | h = boxConstraints.maxHeight;
26 | } else {
27 | w = boxConstraints.maxHeight;
28 | h = boxConstraints.maxWidth;
29 | }
30 |
31 | // Sets ScreenType
32 | if (kIsWeb) {
33 | deviceType = DeviceType.web;
34 | } else if (Platform.isAndroid || Platform.isIOS) {
35 | if ((orientation == Orientation.portrait && w < 600) || (orientation == Orientation.landscape && h < 600)) {
36 | deviceType = DeviceType.mobile;
37 | } else {
38 | deviceType = DeviceType.tablet;
39 | }
40 | } else if (Platform.isMacOS) {
41 | deviceType = DeviceType.mac;
42 | } else if (Platform.isWindows) {
43 | deviceType = DeviceType.windows;
44 | } else if (Platform.isLinux) {
45 | deviceType = DeviceType.linux;
46 | } else {
47 | deviceType = DeviceType.fuchsia;
48 | }
49 | }
50 | }
51 |
52 | enum DeviceType { mobile, tablet, web, mac, windows, linux, fuchsia }
53 |
54 | class ResponsiveApp extends StatelessWidget {
55 | const ResponsiveApp({Key? key, required this.builder}) : super(key: key);
56 | final ResponsiveBuild builder;
57 |
58 | @override
59 | Widget build(BuildContext context) {
60 | return LayoutBuilder(builder: (context, constraints) {
61 | return OrientationBuilder(builder: (context, orientation) {
62 | ResponsiveTools.setAppSize(constraints, orientation);
63 | return builder(context, orientation, ResponsiveTools.deviceType);
64 | });
65 | });
66 | }
67 | }
68 |
69 | typedef ResponsiveBuild = Widget Function(
70 | BuildContext context,
71 | Orientation orientation,
72 | DeviceType deviceType,
73 | );
74 |
75 | extension SizerExt on num {
76 | double get hResponsive => this * ResponsiveTools.h / 100;
77 | double get wResponsive => this * ResponsiveTools.w / 100;
78 | double get textSizeResponsive => this * (ResponsiveTools.w / 3) / 100;
79 | }
80 |
--------------------------------------------------------------------------------
/lib/src/flutter/sized_box.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 |
4 | /// convert Sizedbox height/width to percents.
5 | extension SizedBoxExt on SizedBox {
6 | SizedBox toPercents(BuildContext context) {
7 | final size = MediaQuery.of(context).size;
8 | if (this.width != null) return SizedBox(width: (this.width ?? 0 / size.width) * 1000);
9 | if (this.height != null) return SizedBox(height: (this.height ?? 0 / size.height) * 1000);
10 | return SizedBox.shrink();
11 | }
12 | }
--------------------------------------------------------------------------------
/lib/src/flutter/sliver.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// [Widget] extensions to make it easier to work with [Sliver] widgets.
4 | extension WidgetSliver on Widget {
5 | Widget get sliver {
6 | return SliverToBoxAdapter(
7 | child: this,
8 | );
9 | }
10 |
11 | /// Wraps the widget in a [SliverPadding] widget.
12 | Widget sliverPadding(EdgeInsetsGeometry padding) {
13 | return SliverPadding(
14 | padding: padding,
15 | sliver: this,
16 | );
17 | }
18 |
19 | /// Wraps the widget in a [SliverVisibility] widget.
20 | Widget sliverVisibility(bool isVisible) {
21 | return isVisible ? this : SliverToBoxAdapter();
22 | }
23 |
24 | /// Wraps the widget in a [SliverOpacity] widget.
25 | Widget sliverOpacity(double opacity) {
26 | return SliverOpacity(
27 | opacity: opacity,
28 | sliver: this,
29 | );
30 | }
31 |
32 | /// Wraps the widget in a [SliverAppBar] widget.
33 | Widget sliverFittedBox({BoxFit fit = BoxFit.contain}) {
34 | return SliverToBoxAdapter(
35 | child: FittedBox(
36 | fit: fit,
37 | child: this,
38 | ),
39 | );
40 | }
41 |
42 | /// Wraps the widget in a [SliverAppBar] widget.
43 | Widget sliverExpander() {
44 | return SliverFillRemaining(
45 | hasScrollBody: false,
46 | child: this,
47 | );
48 | }
49 |
50 | /// Wraps the widget in a [SliverAppBar] widget.
51 | Widget sliverCenter() {
52 | return SliverFillRemaining(
53 | hasScrollBody: false,
54 | child: Center(child: this),
55 | );
56 | }
57 |
58 | /// Wraps the widget in a [SliverAppBar] widget.
59 | Widget sliverAspectRatio(double aspectRatio) {
60 | return SliverToBoxAdapter(
61 | child: AspectRatio(
62 | aspectRatio: aspectRatio,
63 | child: this,
64 | ),
65 | );
66 | }
67 |
68 | /// Wraps the widget in a [SliverAppBar] widget.
69 | Widget sliverClipRRect(BorderRadius borderRadius) {
70 | return SliverToBoxAdapter(
71 | child: ClipRRect(
72 | borderRadius: borderRadius,
73 | child: this,
74 | ),
75 | );
76 | }
77 |
78 | /// Wraps the widget in a [SliverAppBar] widget.
79 | Widget sliverPhysicalModel({
80 | required Color color,
81 | required double elevation,
82 | BoxShape shape = BoxShape.rectangle,
83 | Clip clipBehavior = Clip.none,
84 | }) {
85 | return SliverToBoxAdapter(
86 | child: PhysicalModel(
87 | color: color,
88 | elevation: elevation,
89 | shape: shape,
90 | clipBehavior: clipBehavior,
91 | child: this,
92 | ),
93 | );
94 | }
95 |
96 | /// Wraps the widget in a [SliverAppBar] widget.
97 | Widget sliverFlexibleSpaceBar({String? title, bool centerTitle = true}) {
98 | return SliverAppBar(
99 | expandedHeight: 200.0,
100 | floating: false,
101 | pinned: true,
102 | flexibleSpace: FlexibleSpaceBar(
103 | centerTitle: centerTitle,
104 | title: title != null ? Text(title) : null,
105 | background: this,
106 | ),
107 | );
108 | }
109 |
110 | /// Wraps the widget in a [SliverAppBar] widget.
111 | Widget sliverOffstage(bool offstage) {
112 | return SliverToBoxAdapter(
113 | child: Offstage(
114 | offstage: offstage,
115 | child: this,
116 | ),
117 | );
118 | }
119 |
120 | /// Wraps the widget in a [SliverAppBar] widget.
121 | Widget sliverAnimatedSwitcher(
122 | {Duration duration = const Duration(milliseconds: 250)}) {
123 | return SliverToBoxAdapter(
124 | child: AnimatedSwitcher(
125 | duration: duration,
126 | child: this,
127 | ),
128 | );
129 | }
130 |
131 | /// Wraps the widget in a [SliverAppBar] widget.
132 | Widget sliverFadeTransition({required Animation animation}) {
133 | return SliverToBoxAdapter(
134 | child: FadeTransition(
135 | opacity: animation,
136 | child: this,
137 | ),
138 | );
139 | }
140 |
141 | /// Wraps the widget in a [SliverAppBar] widget.
142 | Widget sliverRotatedBox({int quarterTurns = 1}) {
143 | return SliverToBoxAdapter(
144 | child: RotatedBox(
145 | quarterTurns: quarterTurns,
146 | child: this,
147 | ),
148 | );
149 | }
150 |
151 | /// Wraps the widget in a [SliverAppBar] widget.
152 | Widget sliverPositionedTransition(
153 | {required Animation animation}) {
154 | return SliverToBoxAdapter(
155 | child: PositionedTransition(
156 | rect: animation,
157 | child: this,
158 | ),
159 | );
160 | }
161 |
162 | /// Wraps the widget in a [SliverAppBar] widget.
163 | Widget sliverScaleTransition({required Animation scale}) {
164 | return SliverToBoxAdapter(
165 | child: ScaleTransition(
166 | scale: scale,
167 | child: this,
168 | ),
169 | );
170 | }
171 |
172 | /// Wraps the widget in a [SliverAppBar] widget.
173 | Widget sliverSizeTransition(
174 | {required Animation sizeFactor, Axis axis = Axis.vertical}) {
175 | return SliverToBoxAdapter(
176 | child: SizeTransition(
177 | sizeFactor: sizeFactor,
178 | axis: axis,
179 | child: this,
180 | ),
181 | );
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/lib/src/flutter/text.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension StyledText on T {
4 | Text copyWith({
5 | String? data,
6 | TextStyle? style,
7 | StrutStyle? strutStyle,
8 | TextAlign? textAlign,
9 | TextDirection? textDirection,
10 | Locale? locale,
11 | bool? softWrap,
12 | TextOverflow? overflow,
13 | double? textScaleFactor,
14 | int? maxLines,
15 | String? semanticsLabel,
16 | TextWidthBasis? textWidthBasis,
17 | }) =>
18 | Text(
19 | data ?? this.data ?? "",
20 | style: style ?? this.style,
21 | strutStyle: strutStyle ?? this.strutStyle,
22 | textAlign: textAlign ?? this.textAlign,
23 | locale: locale ?? this.locale,
24 | maxLines: maxLines ?? this.maxLines,
25 | overflow: overflow ?? this.overflow,
26 | semanticsLabel: semanticsLabel ?? this.semanticsLabel,
27 | softWrap: softWrap ?? this.softWrap,
28 | textDirection: textDirection ?? this.textDirection,
29 | textScaler: TextScaler.linear(textScaleFactor ?? 0),
30 | textWidthBasis: textWidthBasis ?? this.textWidthBasis,
31 | );
32 |
33 | T textStyle(TextStyle? style) => this.copyWith(
34 | style: (this.style ?? TextStyle()).copyWith(
35 | background: style?.background,
36 | backgroundColor: style?.backgroundColor,
37 | color: style?.color,
38 | debugLabel: style?.debugLabel,
39 | decoration: style?.decoration,
40 | decorationColor: style?.decorationColor,
41 | decorationStyle: style?.decorationStyle,
42 | decorationThickness: style?.decorationThickness,
43 | fontFamily: style?.fontFamily,
44 | fontFamilyFallback: style?.fontFamilyFallback,
45 | fontFeatures: style?.fontFeatures,
46 | fontSize: style?.fontSize,
47 | fontStyle: style?.fontStyle,
48 | fontWeight: style?.fontWeight,
49 | foreground: style?.foreground,
50 | height: style?.height,
51 | inherit: style?.inherit,
52 | letterSpacing: style?.letterSpacing,
53 | locale: style?.locale,
54 | shadows: style?.shadows,
55 | textBaseline: style?.textBaseline,
56 | wordSpacing: style?.wordSpacing,
57 | ),
58 | ) as T;
59 |
60 | T textScale(double scaleFactor) =>
61 | this.copyWith(textScaleFactor: scaleFactor) as T;
62 |
63 | T bold() => this.copyWith(
64 | style: (this.style ?? TextStyle()).copyWith(
65 | fontWeight: FontWeight.bold,
66 | ),
67 | ) as T;
68 |
69 | T italic() => this.copyWith(
70 | style: (this.style ?? TextStyle()).copyWith(
71 | fontStyle: FontStyle.italic,
72 | ),
73 | ) as T;
74 |
75 | T fontWeight(FontWeight fontWeight) => this.copyWith(
76 | style: (this.style ?? TextStyle()).copyWith(
77 | fontWeight: fontWeight,
78 | ),
79 | ) as T;
80 |
81 | T fontSize(double size) => this.copyWith(
82 | style: (this.style ?? TextStyle()).copyWith(
83 | fontSize: size,
84 | ),
85 | ) as T;
86 |
87 | T fontFamily(String font) => this.copyWith(
88 | style: (this.style ?? TextStyle()).copyWith(
89 | fontFamily: font,
90 | ),
91 | ) as T;
92 |
93 | T letterSpacing(double space) => this.copyWith(
94 | style: (this.style ?? TextStyle()).copyWith(
95 | letterSpacing: space,
96 | ),
97 | ) as T;
98 |
99 | T wordSpacing(double space) => this.copyWith(
100 | style: (this.style ?? TextStyle()).copyWith(
101 | wordSpacing: space,
102 | ),
103 | ) as T;
104 |
105 | T textShadow({
106 | Color color = const Color(0x34000000),
107 | double blurRadius = 0.0,
108 | Offset offset = Offset.zero,
109 | }) =>
110 | this.copyWith(
111 | style: (this.style ?? TextStyle()).copyWith(
112 | shadows: [
113 | Shadow(
114 | color: color,
115 | blurRadius: blurRadius,
116 | offset: offset,
117 | ),
118 | ],
119 | ),
120 | ) as T;
121 |
122 | T textColor(Color color) => this.copyWith(
123 | style: (this.style ?? TextStyle()).copyWith(
124 | color: color,
125 | ),
126 | ) as T;
127 |
128 | T textAlignment(TextAlign align) => this.copyWith(textAlign: align) as T;
129 |
130 | T textDirection(TextDirection direction) =>
131 | this.copyWith(textDirection: direction) as T;
132 |
133 | T textBaseline(TextBaseline textBaseline) => this.copyWith(
134 | style: (this.style ?? TextStyle()).copyWith(
135 | textBaseline: textBaseline,
136 | ),
137 | ) as T;
138 |
139 | T textWidthBasis(TextWidthBasis textWidthBasis) =>
140 | this.copyWith(textWidthBasis: textWidthBasis) as T;
141 |
142 | T withUnderLine() => this.copyWith(
143 | style: (this.style ?? TextStyle())
144 | .copyWith(decoration: TextDecoration.underline)) as T;
145 | }
146 |
--------------------------------------------------------------------------------
/lib/src/flutter/transforms.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'package:dart_extensions/src/flutter/transforms/click_translate.dart';
15 | import 'package:flutter/material.dart';
16 |
17 | extension TransformExtensions on Widget {
18 | Widget get pushEffectOnClick => TranslateOnClick(child: this);
19 | }
20 |
--------------------------------------------------------------------------------
/lib/src/flutter/transforms/click_translate.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | import 'package:flutter/material.dart';
14 |
15 | class TranslateOnClick extends StatefulWidget {
16 | final Widget child;
17 |
18 | const TranslateOnClick({Key? key,required this.child}) : super(key: key);
19 |
20 | @override
21 | _TranslateOnClickState createState() => _TranslateOnClickState();
22 | }
23 |
24 | class _TranslateOnClickState extends State {
25 | final nonClickTransform = Matrix4.identity();
26 | final clickTransform = Matrix4.identity()..translate(0, -10, 0);
27 |
28 | bool _clicking = false;
29 |
30 | @override
31 | Widget build(BuildContext context) {
32 | return GestureDetector(
33 | onTapDown: (d) => _userClick(true),
34 | onTapUp: (d) => _userClick(false),
35 | child: AnimatedContainer(
36 | duration: Duration(milliseconds: 200),
37 | child: widget.child,
38 | transform: _clicking ? clickTransform : nonClickTransform,
39 | ),
40 | );
41 | }
42 |
43 | void _userClick(bool click) {
44 | setState(() {
45 | _clicking = click;
46 | });
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/src/flutter/widgets.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'package:flutter/material.dart';
15 |
16 | extension WidgetsExtension on Widget {
17 | Widget withTooltip(String message,
18 | {Decoration? decoration,
19 | double? height,
20 | bool? preferBelow,
21 | EdgeInsetsGeometry? padding,
22 | TextStyle? textStyle,
23 | Duration? waitDuration,
24 | EdgeInsetsGeometry? margin}) =>
25 | Tooltip(
26 | message: message,
27 | decoration: decoration,
28 | height: height,
29 | padding: padding,
30 | preferBelow: preferBelow,
31 | textStyle: textStyle,
32 | waitDuration: waitDuration,
33 | margin: margin,
34 | child: this,
35 | );
36 | }
--------------------------------------------------------------------------------
/lib/src/http.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import 'dart:convert' as convert;
15 | import '../src/string_ext.dart';
16 | import 'package:http/http.dart' as http;
17 |
18 | const _defaultHeaders = {"Content-type": "application/json"};
19 |
20 | extension HttpExtensions on String {
21 | /// Sends an HTTP GET request with the given headers to the given URL, which can
22 | /// be a [Uri] or a [String].
23 | /// [endPoint] - end point of current url
24 | /// example:
25 | /// current string is www.mydomain.com
26 | /// endpoint param - user
27 | /// result request -> www.mydomain.com/user
28 | Future httpGet(String endPoint) async {
29 | if (this.isEmptyOrNull) return;
30 |
31 | try {
32 | final response = await http.get(Uri.http(this, endPoint));
33 | return response.statusCode == 200
34 | ? convert.jsonDecode(response.body)
35 | : print('Request failed with status: ${response.statusCode}.');
36 | } on Exception catch (e) {
37 | return Future.error(e);
38 | }
39 | }
40 |
41 | /// Sends an HTTP POST request with the given headers and body to the given URL,
42 | /// which can be a [Uri] or a [String].
43 | /// [endPoint] - end point of current url
44 | /// example:
45 | /// current string is www.mydomain.com
46 | /// endpoint param - user
47 | /// result request -> www.mydomain.com/user
48 | Future httpPost(String endPoint, String json, [Map headers = _defaultHeaders]) async {
49 | if (this.isEmptyOrNull) return;
50 |
51 | try {
52 | final response = await http.post(Uri.http(this, endPoint), headers: headers, body: json);
53 | return response.statusCode == 200
54 | ? convert.jsonDecode(response.body)
55 | : print('Request failed with status: ${response.statusCode}.');
56 | } on Exception catch (e) {
57 | return Future.error(e);
58 | }
59 | }
60 |
61 | /// Sends an HTTP PUT request with the given headers and body to the given URL,
62 | /// which can be a [Uri] or a [String].
63 | /// [endPoint] - end point of current url
64 | /// example:
65 | /// current string is www.mydomain.com
66 | /// endpoint param - user
67 | /// result request -> www.mydomain.com/user
68 | Future httpPut(String endPoint, String json, [Map headers = _defaultHeaders]) async {
69 | if (this.isEmptyOrNull) return;
70 |
71 | try {
72 | final response = await http.put(Uri.http(this, endPoint), headers: headers, body: json);
73 | return response.statusCode == 200
74 | ? convert.jsonDecode(response.body)
75 | : print('Request failed with status: ${response.statusCode}.');
76 | } on Exception catch (e) {
77 | return Future.error(e);
78 | }
79 | }
80 |
81 | /// Sends an HTTP DELETE request with the given headers to the given URL, which
82 | /// can be a [Uri] or a [String].
83 | /// [endPoint] - end point of current url
84 | /// example:
85 | /// current string is www.mydomain.com
86 | /// endpoint param - user
87 | /// result request -> www.mydomain.com/user
88 | Future httpDelete(String endPoint, {Map? headers}) async {
89 | if (this.isEmptyOrNull) return;
90 |
91 | try {
92 | final response = await http.delete(Uri.http(this, endPoint), headers: headers);
93 | return response.statusCode == 200
94 | ? convert.jsonDecode(response.body)
95 | : print('Request failed with status: ${response.statusCode}.');
96 | } on Exception catch (e) {
97 | return Future.error(e);
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/lib/src/int.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | extension IntExtensions on int {
14 | /// Return the min if this number is smaller then minimum
15 | /// Return the max if this number is bigger the the maximum
16 | /// Return this number if it's between the range
17 | int inRangeOf(int min, int max) {
18 | if (min.isNull || max.isNull) throw Exception('min or max cannot be null');
19 | if (min > max) throw ArgumentError('min must be smaller the max');
20 |
21 | if (this < min) return min;
22 | if (this > max) return max;
23 | return this;
24 | }
25 |
26 | // ignore: unnecessary_null_comparison
27 | bool get isNull => (this == null);
28 |
29 | /// Returns the absolute value
30 | get absolute => abs();
31 |
32 | /// Returns number of digits in this number
33 | int get numberOfDigits => toString().length;
34 |
35 | /// Returns if the number is even
36 | bool get isEven => this % 2 == 0;
37 |
38 | /// Returns if the number is odd
39 | bool get isOdd => this % 2 != 0;
40 |
41 | /// Returns if the number is positive
42 | bool get isPositive => this > 0;
43 |
44 | /// Returns if the number is negative
45 | bool get isNegative => this < 0;
46 |
47 | /// Returns tenth of the number
48 | double get tenth => this / 10;
49 |
50 | /// Returns fourth of the number
51 | double get fourth => this / 4;
52 |
53 | /// Returns third of the number
54 | double get third => this / 3;
55 |
56 | /// Returns half of the number
57 | double get half => this / 2;
58 |
59 | /// Return this number time two
60 | int get doubled => this * 2;
61 |
62 | /// Return this number time three
63 | int get tripled => this * 3;
64 |
65 | /// Return this number time four
66 | int get quadrupled => this * 4;
67 |
68 | /// Return squared number
69 | int get squared => this * this;
70 |
71 | /// Convert this integer into boolean.
72 | ///
73 | /// Returns `true` if this integer is greater than *0*.
74 | bool get asBool => this > 0;
75 | }
76 |
--------------------------------------------------------------------------------
/lib/src/iterable.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Idan Ayalon. All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | import 'dart:collection';
14 | import 'dart:math';
15 |
16 | import 'package:quiver/iterables.dart';
17 |
18 | import 'data_stractures/stack.dart';
19 | import 'equality.dart';
20 |
21 | typedef IndexedPredicate = bool Function(int index, T);
22 |
23 | extension CollectionsNullableExtensions on Iterable? {
24 | /// Returns this Iterable if it's not `null` and the empty list otherwise.
25 | Iterable orEmpty() => this ?? [];
26 |
27 | ///Returns `true` if this nullable iterable is either null or empty.
28 | bool get isEmptyOrNull => (this?.isEmpty ?? true);
29 |
30 | /// Returns `true` if at least one element matches the given [predicate].
31 | bool any(bool predicate(T element)) {
32 | if (this.isEmptyOrNull) return false;
33 | for (final element in this.orEmpty()) if (predicate(element)) return true;
34 | return false;
35 | }
36 |
37 | /// Return a list concatenates the output of the current list and another [iterable]
38 | List concatWithSingleList(Iterable iterable) {
39 | if (isEmptyOrNull || iterable.isEmptyOrNull) return [];
40 |
41 | return [...this.orEmpty(), ...iterable];
42 | }
43 |
44 | /// Return a list concatenates the output of the current list and multiple [iterables]
45 | List concatWithMultipleList(List> iterables) {
46 | if (isEmptyOrNull || iterables.isEmptyOrNull) return [];
47 | final list = iterables.toList(growable: false).expand((i) => i);
48 | return [...this.orEmpty(), ...list];
49 | }
50 |
51 | /// Zip is used to combine multiple iterables into a single list that contains
52 | /// the combination of them two.
53 | zip(Iterable iterable) sync* {
54 | if (iterable.isEmptyOrNull) return;
55 | final iterables = List.empty()
56 | ..add(this.orEmpty())
57 | ..add(iterable);
58 |
59 | final iterators = iterables.map((e) => e.iterator).toList(growable: false);
60 | while (iterators.every((e) => e.moveNext())) {
61 | yield iterators.map((e) => e.current).toList(growable: false);
62 | }
63 | }
64 | }
65 |
66 | extension CollectionsExtensions on Iterable {
67 | ///Sorts elements in the array in-place according to natural sort order of the value returned by specified [selector] function.
68 | Iterable sortBy(
69 | TKey Function(T) keySelector, {
70 | required EqualityComparer keyComparer,
71 | }) {
72 | return InternalOrderedIterable(this, keySelector, keyComparer, false);
73 | }
74 |
75 | /// Convert iterable to set
76 | Set toMutableSet() => Set.from(this);
77 |
78 | /// Returns a set containing all elements that are contained
79 | /// by both this set and the specified collection.
80 | Set intersect(Iterable other) {
81 | final set = this.toMutableSet();
82 | set.addAll(other);
83 | return set;
84 | }
85 |
86 | /// Groups the elements in values by the value returned by key.
87 | ///
88 | /// Returns a map from keys computed by key to a list of all values for which
89 | /// key returns that key. The values appear in the list in the same
90 | /// relative order as in values.
91 | Map> groupBy(K key(T e)) {
92 | var map = >{};
93 |
94 | for (final element in this) {
95 | var list = map.putIfAbsent(key(element as T), () => []);
96 | list.add(element);
97 | }
98 | return map;
99 | }
100 |
101 | /// Returns a list containing only elements matching the given [predicate].
102 | List filter(bool test(T element)) {
103 | final result = [];
104 | forEach((e) {
105 | if (e != null && test(e)) {
106 | result.add(e);
107 | }
108 | });
109 | return result;
110 | }
111 |
112 | /// Returns a list containing all elements not matching the given [predicate] and will filter nulls as well.
113 | List filterNot(bool test(T element)) {
114 | final result = [];
115 | forEach((e) {
116 | if (e != null && !test(e)) {
117 | result.add(e);
118 | }
119 | });
120 | return result;
121 | }
122 |
123 | // return the half size of a list
124 | int get halfLength => (this.length / 2).floor();
125 |
126 | /// Returns a list containing first [n] elements.
127 | List takeOnly(int n) {
128 | if (n == 0) return [];
129 |
130 | var list = List.empty();
131 | var thisList = this.toList();
132 | final resultSize = this.length - n;
133 | if (resultSize <= 0) return [];
134 | if (resultSize == 1) return [this.last];
135 |
136 | List.generate(n, (index) {
137 | list.add(thisList[index]);
138 | });
139 | return list;
140 | }
141 |
142 | /// Returns a list containing all elements except first [n] elements.
143 | List drop(int n) {
144 | if (n == 0) return [];
145 |
146 | var list = List.empty();
147 | var originalList = this.toList();
148 | final resultSize = this.length - n;
149 | if (resultSize <= 0) return [];
150 | if (resultSize == 1) return [this.last];
151 |
152 | originalList.removeRange(0, n);
153 |
154 | originalList.forEach((element) => list.add(element));
155 | return list;
156 | }
157 |
158 | // Retuns map operation as a List
159 | List mapList(E f(T e)) => this.map(f).toList();
160 |
161 | // Takes the first half of a list
162 | List firstHalf() => take(halfLength).toList();
163 |
164 | // Takes the second half of a list
165 | List secondHalf() => drop(halfLength).toList();
166 |
167 | /// returns a list with two swapped items
168 | /// [i] first item
169 | /// [j] second item
170 | List swap(int i, int j) {
171 | final list = this.toList();
172 | final aux = list[i];
173 | list[i] = list[j];
174 | list[j] = aux;
175 | return list;
176 | }
177 |
178 | T getRandom() {
179 | Random generator = Random();
180 | final index = generator.nextInt(this.length);
181 | return this.toList()[index];
182 | }
183 |
184 | /// get the first element return null
185 | T? get firstOrNull => _elementAtOrNull(0);
186 |
187 | /// get the last element if the list is not empty or return null
188 | T? get lastOrNull => isNotEmpty ? last : null;
189 |
190 | T lastOrDefault(T defaultValue) => lastOrNull ?? defaultValue;
191 |
192 | T? firstOrNullWhere(bool predicate(T element)) {
193 | for (T element in this) {
194 | if (predicate(element)) return element;
195 | }
196 | return null;
197 | }
198 |
199 | /// get the first element or provider default
200 | /// example:
201 | /// var name = [danny, ronny, james].firstOrDefault["jack"]; // danny
202 | /// var name = [].firstOrDefault["jack"]; // jack
203 | T firstOrDefault(T defaultValue) => firstOrNull ?? defaultValue;
204 |
205 | /// Will retrun new [Iterable] with all elements that satisfy the predicate [predicate],
206 | Iterable whereIndexed(IndexedPredicate predicate) =>
207 | _IndexedWhereIterable(this, predicate);
208 |
209 | ///
210 | /// Performs the given action on each element on iterable, providing sequential index with the element.
211 | /// [item] the element on the current iteration
212 | /// [index] the index of the current iteration
213 | ///
214 | /// example:
215 | /// ["a","b","c"].forEachIndexed((element, index) {
216 | /// print("$element, $index");
217 | /// });
218 | /// result:
219 | /// a, 0
220 | /// b, 1
221 | /// c, 2
222 | void forEachIndexed(void action(T element, int index)) {
223 | var index = 0;
224 | for (var element in this) {
225 | action(element, index++);
226 | }
227 | }
228 |
229 | /// Returns a new list with all elements sorted according to descending
230 | /// natural sort order.
231 | List sortedDescending() {
232 | var list = toList();
233 | list.sort((a, b) => -(a as Comparable).compareTo(b));
234 | return list;
235 | }
236 |
237 | /// Checks if all elements in the specified [collection] are contained in
238 | /// this collection.
239 | bool containsAll(Iterable collection) {
240 | for (var element in collection) {
241 | if (!contains(element)) return false;
242 | }
243 | return true;
244 | }
245 |
246 | /// Return a number of the existing elements by a specific predicate
247 | /// example:
248 | /// final aboveTwenty = [
249 | /// User(33, "chicko"),
250 | /// User(45, "ronit"),
251 | /// User(19, "amsalam"),
252 | /// ].count((user) => user.age > 20); // 2
253 | int count([bool predicate(T element)?]) {
254 | var count = 0;
255 | if (predicate == null) {
256 | return length;
257 | } else {
258 | for (var current in this) {
259 | if (predicate(current)) {
260 | count++;
261 | }
262 | }
263 | }
264 |
265 | return count;
266 | }
267 |
268 | /// Returns `true` if all elements match the given predicate.
269 | /// Example:
270 | /// [5, 19, 2].all(isEven), isFalse)
271 | /// [6, 12, 2].all(isEven), isTrue)
272 | bool all(bool predicate(T pred)?) {
273 | for (var e in this) {
274 | if (!predicate!(e)) return false;
275 | }
276 | return true;
277 | }
278 |
279 | /// Returns a list containing only the elements from given collection having distinct keys.
280 | ///
281 | /// Basically it's just like distinct function but with a predicate
282 | /// example:
283 | /// [
284 | /// User(22, "Sasha"),
285 | /// User(23, "Mika"),
286 | /// User(23, "Miryam"),
287 | /// User(30, "Josh"),
288 | /// User(36, "Ran"),
289 | /// ].distinctBy((u) => u.age).forEach((user) {
290 | /// print("${user.age} ${user.name}");
291 | /// });
292 | ///
293 | /// result:
294 | /// 22 Sasha
295 | /// 23 Mika
296 | /// 30 Josh
297 | /// 36 Ran
298 | List distinctBy(predicate(T selector)) {
299 | final set = HashSet();
300 | final List list = [];
301 | toList().forEach((e) {
302 | final key = predicate(e);
303 | if (set.add(key)) {
304 | list.add(e);
305 | }
306 | });
307 |
308 | return list;
309 | }
310 |
311 | // get an element at specific index or return null
312 | T? _elementAtOrNull(int index) {
313 | return _elementOrNull(index, (_) => null);
314 | }
315 |
316 | _elementOrNull(int index, T? defaultElement(int index)) {
317 | // if our index is smaller then 0 return the default
318 | if (index < 0) return defaultElement(index);
319 |
320 | var counter = 0;
321 | for (var element in this) {
322 | if (index == counter++) {
323 | return element;
324 | }
325 | }
326 |
327 | return defaultElement(index);
328 | }
329 |
330 | /// Returns a set containing all elements that are contained by this collection
331 | /// and not contained by the specified collection.
332 | /// The returned set preserves the element iteration order of the original collection.
333 | ///
334 | /// example:
335 | ///
336 | /// [1,2,3,4,5,6].subtract([4,5,6])
337 | ///
338 | /// result:
339 | /// 1,2,3
340 | subtract(Iterable other) {
341 | final set = toSet();
342 | set.removeAll(other);
343 | return set;
344 | }
345 |
346 | /// will convert iterable into a Stack data structure
347 | /// example:
348 | /// [1,2,3,4].toStack()
349 | /// stack.pop()
350 | /// stack.push(5)
351 | ///
352 | StackX toStack() {
353 | final stack = StackX();
354 | stack.addAll(this);
355 | return stack;
356 | }
357 |
358 | /// Splits the Iterable into chunks of the specified size
359 | ///
360 | /// example:
361 | /// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].chunks(3))
362 | /// result:
363 | /// ([1, 2, 3], [4, 5, 6], [7, 8, 9], [10])
364 | Iterable> chunks(int size) => partition(this, size);
365 |
366 | /// Creates a Map instance in which the keys and values are computed from the iterable.
367 | Map associate(key(element), value(element)) =>
368 | Map.fromIterable(this, key: key, value: value);
369 |
370 | /// Returns the first element matching the given [predicate], or `null`
371 | /// if element was not found.
372 | T? find(predicate(T selector)) {
373 | for (final element in this) {
374 | if (predicate(element)) {
375 | return element;
376 | }
377 | }
378 |
379 | return null;
380 | }
381 | }
382 |
383 | // A lazy [Iterable] skip elements do **NOT** match the predicate [_f].
384 | class _IndexedWhereIterable extends Iterable {
385 | final Iterable _iterable;
386 | final IndexedPredicate _f;
387 |
388 | _IndexedWhereIterable(this._iterable, this._f);
389 |
390 | @override
391 | Iterator get iterator => _IndexedWhereIterator(_iterable.iterator, _f);
392 | }
393 |
394 | /// [Iterator] for [_IndexedWhereIterable]
395 | class _IndexedWhereIterator implements Iterator {
396 | final Iterator _iterator;
397 | final IndexedPredicate _f;
398 | int _index = 0;
399 |
400 | _IndexedWhereIterator(this._iterator, this._f);
401 |
402 | @override
403 | bool moveNext() {
404 | while (_iterator.moveNext()) {
405 | if (_f(_index++, _iterator.current)) {
406 | return true;
407 | }
408 | }
409 | return false;
410 | }
411 |
412 | @override
413 | E get current => _iterator.current;
414 | }
415 |
--------------------------------------------------------------------------------
/lib/src/map.dart:
--------------------------------------------------------------------------------
1 | extension MapExt on Map {
2 | /// Flatten a nested Map into a single level map
3 | ///
4 | /// If you don't want to flatten arrays (with 0, 1,... indexes),
5 | /// use [safe] mode.
6 | ///
7 | /// To avoid circular reference issues or huge calculations,
8 | /// you can specify the [maxDepth] the function will traverse.
9 | Map flatJson({
10 | String delimiter = ".",
11 | bool safe = false,
12 | int? maxDepth,
13 | }) {
14 | final result = {};
15 |
16 | void step(
17 | Map obj, [
18 | String? previousKey,
19 | int currentDepth = 1,
20 | ]) {
21 | obj.forEach((key, value) {
22 | final newKey = previousKey != null ? "$previousKey$delimiter$key" : key;
23 |
24 | if (maxDepth != null && currentDepth >= maxDepth) {
25 | result[newKey] = value;
26 | return;
27 | }
28 | if (value is Map) {
29 | return step(value, newKey, currentDepth + 1);
30 | }
31 | if (value is List && !safe) {
32 | return step(
33 | _listToMap(value as List