├── .github └── FUNDING.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── example ├── AppSettings.config.dart ├── DevSettings.config.dart └── main.dart ├── lib └── global_configuration.dart ├── pubspec.lock ├── pubspec.yaml └── test └── global_configuration_test.dart /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://www.paypal.me/ephenodrom'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | ios/.generated/ 9 | ios/Flutter/Generated.xcconfig 10 | ios/Runner/GeneratedPluginRegistrant.* 11 | 12 | .idea 13 | *.iml -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [2.0.0-nullsafety.1] - 2021-04-06 4 | 5 | * Update dependencies 6 | 7 | ## [2.0.0-nullsafety.0] - 2021-03-05 8 | 9 | * Migrate to nullsafety 10 | 11 | ## [1.6.0] - 2020-09-02 12 | 13 | * Improve access to nested configuration (#16) 14 | * Merged pull request #15 15 | 16 | ## [1.5.0] - 2020-01-29 17 | 18 | * Add possability to update null values (#10) 19 | * Improve config loading from file (#9) 20 | 21 | ## [1.4.0] - 2019-09-16 22 | 23 | * Add new method updateValue(), that replaces setValue() 24 | * Add new method addValue() 25 | * Add new method clear() 26 | * Add new Unit tests 27 | * Update documentation 28 | 29 | ## [1.3.0] - 2019-08-20 30 | 31 | * Add new method loadFromUrlIntoKey 32 | 33 | ## [1.2.0] - 2019-07-25 34 | 35 | * Add new method loadFromPathIntoKey 36 | 37 | ## [1.1.0] - 2019-06-17 38 | 39 | * Fix bug in setValue and improve usage of setValue method 40 | 41 | ## [1.0.0] - 2019-06-01 42 | 43 | * Add new method loadFromPath 44 | 45 | ## [0.1.4] - 2018-12-17 46 | 47 | * Add new method setValue 48 | 49 | ## [0.1.3] - 2018-12-09 50 | 51 | * Add new method loadFromUrl 52 | 53 | ## [0.1.2] - 2018-11-26 54 | 55 | * Improve README.md 56 | 57 | ## [0.1.1] - 2018-11-25 58 | 59 | * Add loading file from asset folder 60 | 61 | ## [0.1.0] - 2018-11-25 62 | 63 | * Add example folder 64 | 65 | ## [0.0.2] - 2018-11-25 66 | 67 | * Fill README.md with content and examples 68 | 69 | ## [0.0.1] - 2018-11-25 70 | 71 | * Initial release 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ephenodrom 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Global Configuration 2 | 3 | A flutter package for managing different configurations by merging them together and making 4 | them available everythere inside the app via a singleton. 5 | 6 | ## Table of Contents 7 | 8 | - [Flutter Global Configuration](#flutter-global-configuration) 9 | - [Table of Contents](#table-of-contents) 10 | - [Preamble](#preamble) 11 | - [Install](#install) 12 | - [pubspec.yaml](#pubspecyaml) 13 | - [Import](#import) 14 | - [Loading configuration](#loading-configuration) 15 | - [Load from asset](#load-from-asset) 16 | - [Creating a configuration file inside assets/cfg folder](#creating-a-configuration-file-inside-assetscfg-folder) 17 | - [Load configuration from assets at app start](#load-configuration-from-assets-at-app-start) 18 | - [Load from path](#load-from-path) 19 | - [Creating a configuration file anywhere](#creating-a-configuration-file-anywhere) 20 | - [Load configuration from path at app start](#load-configuration-from-path-at-app-start) 21 | - [Load from path into key](#load-from-path-into-key) 22 | - [Load from map](#load-from-map) 23 | - [Creating a configuration inside .dart file](#creating-a-configuration-inside-dart-file) 24 | - [Load configuration from map at app start](#load-configuration-from-map-at-app-start) 25 | - [Load from url](#load-from-url) 26 | - [Load configuration from url at app start](#load-configuration-from-url-at-app-start) 27 | - [Using the configuration in your app](#using-the-configuration-in-your-app) 28 | - [Overriding configuration](#overriding-configuration) 29 | - [Full example](#full-example) 30 | - [Changelog](#changelog) 31 | - [Copyright and license](#copyright-and-license) 32 | 33 | ## Preamble 34 | 35 | This package is also part of the [EZ Flutter Framework](https://ez-flutter.de). 36 | 37 | ## Install 38 | 39 | ### pubspec.yaml 40 | 41 | Update pubspec.yaml and add the following line to your dependencies. 42 | 43 | ```yaml 44 | dependencies: 45 | global_configuration: ^2.0.0 46 | ``` 47 | 48 | ## Import 49 | 50 | Import the package with : 51 | 52 | ```dart 53 | import 'package:global_configuration/global_configuration.dart'; 54 | ``` 55 | 56 | ## Loading configuration 57 | 58 | There are many ways where you can store your configuration files and load them. 59 | 60 | ### Load from asset 61 | 62 | #### Creating a configuration file inside assets/cfg folder 63 | 64 | Create a .json file and place it under assets/cfg/ 65 | Example filename: assets/cfg/app_settings.json 66 | 67 | ```json 68 | { 69 | "key1": "value1", 70 | "key2": "value2" 71 | } 72 | ``` 73 | 74 | Remember to update your pubspec.yaml file, so the config can be loaded from the assets directory! 75 | The config files must be placed under the assets/cfg/ directory. 76 | 77 | ```yaml 78 | flutter: 79 | assets: 80 | - assets/cfg/ 81 | ``` 82 | 83 | #### Load configuration from assets at app start 84 | 85 | ```dart 86 | import 'package:flutter/material.dart'; 87 | import 'package:global_configuration/global_configuration.dart'; 88 | 89 | void main() async{ 90 | await GlobalConfiguration().loadFromAsset("app_settings"); 91 | runApp(MyApp()); 92 | } 93 | class MyApp extends StatelessWidget { 94 | ... 95 | } 96 | ``` 97 | 98 | ### Load from path 99 | 100 | #### Creating a configuration file anywhere 101 | 102 | Create a file anywhere inside your app. 103 | 104 | #### Load configuration from path at app start 105 | 106 | ```dart 107 | import 'package:flutter/material.dart'; 108 | import 'package:global_configuration/global_configuration.dart'; 109 | 110 | void main() async { 111 | await GlobalConfiguration().loadFromPath("/path/file.json"); 112 | runApp(MyApp()); 113 | } 114 | class MyApp extends StatelessWidget { 115 | ... 116 | } 117 | ``` 118 | 119 | ### Load from path into key 120 | 121 | The same as loadFromPath, but the config is added under the given key. 122 | 123 | ```dart 124 | import 'package:flutter/material.dart'; 125 | import 'package:global_configuration/global_configuration.dart'; 126 | 127 | void main() async { 128 | await GlobalConfiguration().loadFromPathIntoKey("/path/file.json", "env_settings"); 129 | runApp(MyApp()); 130 | } 131 | class MyApp extends StatelessWidget { 132 | ... 133 | } 134 | ``` 135 | 136 | ### Load from map 137 | 138 | #### Creating a configuration inside .dart file 139 | 140 | Create a dart file which includes your configuration and import it in your main file. 141 | Example filename: /config/app_settings.config.dart 142 | 143 | ```dart 144 | final Map appSettings = { 145 | "key1": "value1", 146 | "key2": "value2" 147 | }; 148 | ``` 149 | 150 | #### Load configuration from map at app start 151 | 152 | ```dart 153 | import 'package:flutter/material.dart'; 154 | import 'package:global_configuration/global_configuration.dart'; 155 | import 'config/app_settings.config.dart'; 156 | 157 | void main() async { 158 | GlobalConfiguration().loadFromMap(appSettings); 159 | runApp(MyApp()); 160 | } 161 | class MyApp extends StatelessWidget { 162 | ... 163 | } 164 | ``` 165 | 166 | ### Load from url 167 | 168 | It is possible to load any json configuration file from a url. Use the method loadFromUrl to load 169 | the config via GET request. 170 | Please consider using a try / catch. This method will throw an exception if the status code of the 171 | GET request is not 200. 172 | 173 | The method also accepts query parameters and headers! The header "Accept: application/json" is always 174 | included. 175 | 176 | #### Load configuration from url at app start 177 | 178 | ```dart 179 | import 'package:flutter/material.dart'; 180 | import 'package:global_configuration/global_configuration.dart'; 181 | 182 | void main() async{ 183 | try{ 184 | await GlobalConfiguration().loadFromUrl("http://urlToMyConfig.com"); 185 | }catch(e){ 186 | // something went wrong while fetching the config from the url ... do something 187 | } 188 | runApp(MyApp()); 189 | } 190 | class MyApp extends StatelessWidget { 191 | ... 192 | } 193 | ``` 194 | 195 | ## Using the configuration in your app 196 | 197 | Instatiate the GlobalConfiguration class and call any get($key) method. 198 | 199 | ```dart 200 | import 'package:flutter/material.dart'; 201 | import 'package:global_configuration/global_configuration.dart'; 202 | 203 | class CustomWidget extends StatelessWidget { 204 | 205 | CustomWiget(){ 206 | // Access the config in the constructor 207 | print(GlobalConfiguration().getString("key1")); // prints value1 208 | } 209 | 210 | @override 211 | Widget build(BuildContext context) { 212 | // Access the config in the build method 213 | return Text(GlobalConfiguration().getString("key2")); // prints value2 214 | } 215 | } 216 | ``` 217 | 218 | ## Overriding configuration 219 | 220 | Sometimes it is necessary to override data in the configuration. This can be done by the updateValue method. 221 | This method makes a check for the given type of the value and then performs an update the configuration map. 222 | 223 | ```dart 224 | Map appSettings = { 225 | "key1": "value1", 226 | "key2": 1 227 | }; 228 | GlobalConfiguration().loadFromMap(appSettings); // loading the configuration 229 | print(GlobalConfiguration().getString("key1")); // output : value1 230 | print(GlobalConfiguration().getString("key2")); // output : 1 231 | GlobalConfiguration().updateValue("key1", "value2"); // update the value for key1 232 | GlobalConfiguration().updateValue("key2", 2); // update the value for key2 233 | print(GlobalConfiguration().getString("key1")); // output : value2 234 | print(GlobalConfiguration().getString("key2")); // output : 2 235 | ``` 236 | 237 | ### Full example 238 | 239 | You can find a full example in the [example folder](/example/main.dart). 240 | 241 | ## Changelog 242 | 243 | For a detailed changelog, see the [CHANGELOG.md](CHANGELOG.md) file 244 | 245 | ## Copyright and license 246 | 247 | MIT License 248 | 249 | Copyright (c) 2023 Ephenodrom 250 | 251 | Permission is hereby granted, free of charge, to any person obtaining a copy 252 | of this software and associated documentation files (the "Software"), to deal 253 | in the Software without restriction, including without limitation the rights 254 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 255 | copies of the Software, and to permit persons to whom the Software is 256 | furnished to do so, subject to the following conditions: 257 | 258 | The above copyright notice and this permission notice shall be included in all 259 | copies or substantial portions of the Software. 260 | 261 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 262 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 263 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 264 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 265 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 266 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 267 | SOFTWARE. 268 | -------------------------------------------------------------------------------- /example/AppSettings.config.dart: -------------------------------------------------------------------------------- 1 | final Map appSettings = { 2 | "key1": "value1", 3 | "key2": "value2" 4 | }; -------------------------------------------------------------------------------- /example/DevSettings.config.dart: -------------------------------------------------------------------------------- 1 | final Map devSettings = { 2 | "key3": "value3", 3 | "key4": "value4" 4 | }; -------------------------------------------------------------------------------- /example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:global_configuration/global_configuration.dart'; 3 | import 'AppSettings.config.dart'; 4 | import 'DevSettings.config.dart'; 5 | 6 | void main() async { 7 | GlobalConfiguration().loadFromMap(appSettings).loadFromMap(devSettings); 8 | runApp(MyApp()); 9 | } 10 | 11 | class MyApp extends StatelessWidget { 12 | MyApp() { 13 | // Access configuration at constructor 14 | GlobalConfiguration cfg = new GlobalConfiguration(); 15 | print("Key1 has value ${cfg.getString("key1")}"); 16 | print("Key2 has value ${GlobalConfiguration().getString("key2")}"); 17 | print("Key5 has value ${cfg.getString("key5")}, this should be null!"); 18 | } 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | // Access configuration at build method 23 | GlobalConfiguration cfg = new GlobalConfiguration(); 24 | print("Key3 has value ${cfg.getString("key3")}"); 25 | return MaterialApp( 26 | title: 'Welcome to Flutter', 27 | home: Scaffold( 28 | appBar: AppBar( 29 | title: Text('Welcome to Flutter'), 30 | ), 31 | body: Center( 32 | child: Text('Hello World'), 33 | ), 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/global_configuration.dart: -------------------------------------------------------------------------------- 1 | library global_configuration; 2 | 3 | import 'dart:ui'; 4 | 5 | import 'package:flutter/services.dart' show rootBundle; 6 | import 'package:http/http.dart' as http; 7 | import 'dart:convert'; 8 | 9 | /// 10 | /// Class for managing different configuration. 11 | /// 12 | /// Use it with GlobalConfiguration() to access the singleton. 13 | /// 14 | class GlobalConfiguration { 15 | static GlobalConfiguration _singleton = GlobalConfiguration._internal(); 16 | 17 | /// 18 | /// Convert string hex color like #AABBCC to Color widget 19 | /// 20 | Color _hexStringToColor(String code) => 21 | Color(int.parse(code.substring(1, 7), radix: 16) + 0xFF000000); 22 | 23 | factory GlobalConfiguration() { 24 | return _singleton; 25 | } 26 | 27 | GlobalConfiguration._internal(); 28 | 29 | Map appConfig = Map(); 30 | 31 | /// 32 | /// Loading a configuration [map] into the current app config. 33 | /// 34 | GlobalConfiguration loadFromMap(Map map) { 35 | appConfig.addAll(map); 36 | return _singleton; 37 | } 38 | 39 | /// 40 | /// Loading a json configuration file with the given [name] into the current app config. 41 | /// 42 | /// If the given [name] does not have the file extension .json, it will be automatically added. 43 | /// 44 | /// The file has to be placed at assets/cfg/. 45 | /// 46 | /// Use the **loadFromPath** method if you want to store the file at another place. 47 | /// 48 | Future loadFromAsset(String name) async { 49 | if (!name.endsWith(".json")) { 50 | name = "$name.json"; 51 | } 52 | String content = await rootBundle.loadString("assets/cfg/$name"); 53 | Map configAsMap = json.decode(content); 54 | appConfig.addAll(configAsMap); 55 | return _singleton; 56 | } 57 | 58 | /// 59 | /// Loading a json configuration file from a custom [path] into the current app config. 60 | /// 61 | Future loadFromPath(String path) async { 62 | String content = await rootBundle.loadString(path); 63 | Map configAsMap = json.decode(content); 64 | appConfig.addAll(configAsMap); 65 | return _singleton; 66 | } 67 | 68 | /// 69 | /// Loading a json configuration file from a custom [path] into the current app config with the given [key]. 70 | /// 71 | Future loadFromPathIntoKey( 72 | String path, String key) async { 73 | String content = await rootBundle.loadString(path); 74 | Map configAsMap = json.decode(content); 75 | appConfig.putIfAbsent(key, () => configAsMap); 76 | return _singleton; 77 | } 78 | 79 | /// 80 | /// Loading a configuration file from the given [url] into the current app config using 81 | /// a http GET request to fetch the configuration. 82 | /// 83 | /// The request can be modified with [queryParameters] and [headers]. 84 | /// 85 | Future loadFromUrl(String url, 86 | {Map? queryParameters, 87 | Map? headers}) async { 88 | Map configAsMap = await _getFromUrl(url, 89 | queryParameters: queryParameters, headers: headers); 90 | appConfig.addAll(configAsMap); 91 | return _singleton; 92 | } 93 | 94 | /// 95 | /// Loading a configuration file from the given [url] into the current app config with the given [key]. 96 | /// 97 | /// It uses a http GET request to fetch the configuration. 98 | /// The request can be modified with [queryParameters] and [headers]. 99 | /// 100 | Future loadFromUrlIntoKey(String url, String key, 101 | {Map? queryParameters, 102 | Map? headers}) async { 103 | Map configAsMap = await _getFromUrl(url, 104 | queryParameters: queryParameters, headers: headers); 105 | appConfig.putIfAbsent(key, () => configAsMap); 106 | return _singleton; 107 | } 108 | 109 | /// 110 | /// Reads a value of any type from persistent storage for the given [key]. 111 | /// 112 | dynamic get(String key) => appConfig[key]; 113 | 114 | /// 115 | /// Reads a value of T type from persistent storage for the given [key]. 116 | /// 117 | T getValue(String key) => appConfig[key] as T; 118 | 119 | /// 120 | /// Reads a value of T type from persistent storage for the given [keyPath] 121 | /// when [keyPath] is a Json path separated by ':' like 'appColors:primaryColor' 122 | /// when our Json file is: 123 | /// 124 | /// ``` 125 | /// { 126 | /// "appColors": { 127 | /// "primaryColor": "#2e7d32" 128 | /// } 129 | /// } 130 | /// ``` 131 | /// 132 | /// You can also use getDeepValue when the json color value is 133 | /// a string hexadecimal like "#2e7d32". 134 | /// 135 | T? getDeepValue(String keyPath) { 136 | dynamic _value; 137 | 138 | keyPath.split(":").forEach((element) { 139 | if (_value == null) 140 | _value = appConfig[element]; 141 | else 142 | _value = _value[element]; 143 | }); 144 | 145 | if (_value != null) { 146 | if (T == Color) _value = _hexStringToColor(_value); 147 | 148 | return _value as T; 149 | } 150 | 151 | return null; 152 | } 153 | 154 | /// 155 | /// Reads a [bool] value from persistent storage for the given [key], throwing an exception if it's not a bool. 156 | /// 157 | @Deprecated("Use getValue instead") 158 | bool getBool(String key) => appConfig[key]; 159 | 160 | /// 161 | /// Reads a [int] value from persistent storage for the given [key], throwing an exception if it's not an int. 162 | /// 163 | @Deprecated("Use getValue instead") 164 | int getInt(String key) => appConfig[key]; 165 | 166 | /// 167 | /// Reads a [double] value from persistent storage for the given [key], throwing an exception if it's not a double. 168 | /// 169 | @Deprecated("Use getValue instead") 170 | double getDouble(String key) => appConfig[key]; 171 | 172 | /// 173 | /// Reads a [String] value from persistent storage for the given [key], throwing an exception if it's not a String. 174 | /// 175 | @Deprecated("Use getValue instead") 176 | String getString(String key) => appConfig[key]; 177 | 178 | /// 179 | /// Clear the persistent storage. Only for Unit testing! 180 | /// 181 | void clear() => appConfig.clear(); 182 | 183 | /// Write a value from persistent storage, throwing an exception if it's not 184 | /// the correct type 185 | @Deprecated("Use updateValue instead") 186 | void setValue(key, value) => value.runtimeType != appConfig[key].runtimeType 187 | ? throw ("wrong type") 188 | : appConfig.update(key, (dynamic) => value); 189 | 190 | /// 191 | /// Update the given [value] for the given [key] in the storage. 192 | /// 193 | /// The updated value is *NOT* persistent 194 | /// Throws an exception if the given [value] has not the same [Type]. 195 | /// 196 | void updateValue(String key, dynamic value) { 197 | if (appConfig[key] != null && 198 | value.runtimeType != appConfig[key].runtimeType) { 199 | throw ("The persistent type of ${appConfig[key].runtimeType} does not match the given type ${value.runtimeType}"); 200 | } 201 | appConfig.update(key, (dynamic) => value); 202 | } 203 | 204 | /// 205 | /// Adds the given [value] at the given [key] to the storage. 206 | /// 207 | /// The key and value is *NOT* persistent 208 | /// 209 | void addValue(String key, dynamic value) => 210 | appConfig.putIfAbsent(key, () => value); 211 | 212 | /// 213 | /// Adds the given [map] to the storage. 214 | /// 215 | add(Map map) => appConfig.addAll(map); 216 | 217 | /// 218 | /// Sends a HTTP GET request to the given [url] with the given [queryParameters] and [headers]. 219 | /// 220 | Future> _getFromUrl(String url, 221 | {Map? queryParameters, 222 | Map? headers}) async { 223 | String finalUrl = url; 224 | if (queryParameters != null) { 225 | queryParameters.forEach((k, v) { 226 | finalUrl += !finalUrl.endsWith("?") ? "?$k=$v" : "&$k=$v"; 227 | }); 228 | } 229 | if (headers == null) { 230 | headers = Map(); 231 | } 232 | headers.putIfAbsent("Accept", () => "application/json"); 233 | var encodedUri = Uri.encodeFull(finalUrl); 234 | var response = await http.get(Uri.parse(encodedUri), headers: headers); 235 | if (response.statusCode != 200) { 236 | throw new Exception( 237 | 'HTTP request failed, statusCode: ${response.statusCode}, $finalUrl'); 238 | } 239 | return json.decode(response.body); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | charcode: 29 | dependency: transitive 30 | description: 31 | name: charcode 32 | sha256: "8e36feea6de5ea69f2199f29cf42a450a855738c498b57c0b980e2d3cca9c362" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.2.0" 36 | clock: 37 | dependency: transitive 38 | description: 39 | name: clock 40 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.1.1" 44 | collection: 45 | dependency: transitive 46 | description: 47 | name: collection 48 | sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.17.2" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | http: 71 | dependency: "direct main" 72 | description: 73 | name: http 74 | sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" 75 | url: "https://pub.dev" 76 | source: hosted 77 | version: "1.1.0" 78 | http_parser: 79 | dependency: transitive 80 | description: 81 | name: http_parser 82 | sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "4.0.0" 86 | matcher: 87 | dependency: transitive 88 | description: 89 | name: matcher 90 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "0.12.16" 94 | material_color_utilities: 95 | dependency: transitive 96 | description: 97 | name: material_color_utilities 98 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "0.5.0" 102 | meta: 103 | dependency: transitive 104 | description: 105 | name: meta 106 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "1.9.1" 110 | path: 111 | dependency: transitive 112 | description: 113 | name: path 114 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "1.8.3" 118 | sky_engine: 119 | dependency: transitive 120 | description: flutter 121 | source: sdk 122 | version: "0.0.99" 123 | source_span: 124 | dependency: transitive 125 | description: 126 | name: source_span 127 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "1.10.0" 131 | stack_trace: 132 | dependency: transitive 133 | description: 134 | name: stack_trace 135 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "1.11.0" 139 | stream_channel: 140 | dependency: transitive 141 | description: 142 | name: stream_channel 143 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "2.1.1" 147 | string_scanner: 148 | dependency: transitive 149 | description: 150 | name: string_scanner 151 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "1.2.0" 155 | term_glyph: 156 | dependency: transitive 157 | description: 158 | name: term_glyph 159 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "1.2.1" 163 | test_api: 164 | dependency: transitive 165 | description: 166 | name: test_api 167 | sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "0.6.0" 171 | typed_data: 172 | dependency: transitive 173 | description: 174 | name: typed_data 175 | sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "1.3.0" 179 | vector_math: 180 | dependency: transitive 181 | description: 182 | name: vector_math 183 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "2.1.4" 187 | web: 188 | dependency: transitive 189 | description: 190 | name: web 191 | sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "0.1.4-beta" 195 | sdks: 196 | dart: ">=3.1.0-185.0.dev <4.0.0" 197 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: global_configuration 2 | description: A flutter package for managing different configurations and making them available everythere inside the app. 3 | version: 2.0.0 4 | homepage: https://github.com/Ephenodrom/Flutter-Global-Config 5 | 6 | environment: 7 | sdk: '>=2.12.0 <4.0.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | http: ^1.1.0 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter -------------------------------------------------------------------------------- /test/global_configuration_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:ui'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_test/flutter_test.dart'; 6 | 7 | import 'package:global_configuration/global_configuration.dart'; 8 | 9 | void main() { 10 | test('Testing get value for key.', () { 11 | GlobalConfiguration().clear(); 12 | final Map config1 = {"key1": "value1", "key2": "value2"}; 13 | 14 | final Map config2 = {"key3": "value3", "key4": "value4"}; 15 | GlobalConfiguration().loadFromMap(config1); 16 | GlobalConfiguration().loadFromMap(config2); 17 | expect(GlobalConfiguration().getString("key1"), "value1"); 18 | expect(GlobalConfiguration().getString("key3"), "value3"); 19 | }); 20 | 21 | test('Testing get value for key.', () { 22 | GlobalConfiguration().clear(); 23 | final Map config1 = {"key1": "value1", "key2": "value2"}; 24 | 25 | final Map config2 = {"key3": "value3", "key4": "value4"}; 26 | GlobalConfiguration().loadFromMap(config1); 27 | GlobalConfiguration().loadFromMap(config2); 28 | expect(GlobalConfiguration().getValue("key1"), "value1"); 29 | expect(GlobalConfiguration().getValue("key3"), "value3"); 30 | }); 31 | 32 | test('Testing read a deep value', () async { 33 | GlobalConfiguration().clear(); 34 | final jsonString = '{"values" : { "key1" : "value1", "key2" : "value2" } }'; 35 | Map config1 = json.decode(jsonString); 36 | 37 | GlobalConfiguration().loadFromMap(config1); 38 | expect(GlobalConfiguration().getDeepValue("values:key2"), "value2"); 39 | }); 40 | 41 | test('Testing read a color', () async { 42 | GlobalConfiguration().clear(); 43 | final jsonString = '{"color" : "#F44336" }'; 44 | Map config1 = json.decode(jsonString); 45 | 46 | GlobalConfiguration().loadFromMap(config1); 47 | expect( 48 | GlobalConfiguration().getDeepValue("color"), Color(0xFFF44336)); 49 | }); 50 | 51 | test('Testing updateValue().', () async { 52 | GlobalConfiguration().clear(); 53 | final Map config1 = {"hello": "world", "foo": 123}; 54 | GlobalConfiguration().loadFromMap(config1); 55 | 56 | GlobalConfiguration().updateValue("hello", "world!"); 57 | expect(GlobalConfiguration().getString("hello"), "world!"); 58 | GlobalConfiguration().updateValue("foo", 321); 59 | expect(GlobalConfiguration().getInt("foo"), 321); 60 | 61 | try { 62 | GlobalConfiguration().updateValue("foo", "321"); 63 | } catch (e) { 64 | expect(GlobalConfiguration().getInt("foo"), 321); 65 | return; 66 | } 67 | fail("Expected Exception!"); 68 | }); 69 | 70 | test('Testing updateValue().', () async { 71 | GlobalConfiguration().clear(); 72 | final Map config1 = {"hello": "world", "foo": 123}; 73 | GlobalConfiguration().loadFromMap(config1); 74 | 75 | GlobalConfiguration().updateValue("hello", "world!"); 76 | expect(GlobalConfiguration().getValue("hello"), "world!"); 77 | GlobalConfiguration().updateValue("foo", 321); 78 | expect(GlobalConfiguration().getValue("foo"), 321); 79 | 80 | try { 81 | GlobalConfiguration().updateValue("foo", "321"); 82 | } catch (e) { 83 | expect(GlobalConfiguration().getInt("foo"), 321); 84 | return; 85 | } 86 | fail("Expected Exception!"); 87 | }); 88 | 89 | test('Testing update null value.', () async { 90 | GlobalConfiguration().clear(); 91 | final Map config1 = {"hello": "world", "foo": null}; 92 | GlobalConfiguration().loadFromMap(config1); 93 | 94 | GlobalConfiguration().updateValue("foo", 321); 95 | expect(GlobalConfiguration().getInt("foo"), 321); 96 | }); 97 | 98 | test('Testing update null value.', () async { 99 | GlobalConfiguration().clear(); 100 | final Map config1 = {"hello": "world", "foo": null}; 101 | GlobalConfiguration().loadFromMap(config1); 102 | 103 | GlobalConfiguration().updateValue("foo", 321); 104 | expect(GlobalConfiguration().getValue("foo"), 321); 105 | }); 106 | 107 | test('Testing addValue', () async { 108 | GlobalConfiguration().clear(); 109 | GlobalConfiguration().addValue("hello", "world"); 110 | expect(GlobalConfiguration().getString("hello"), "world"); 111 | }); 112 | 113 | test('Testing addValue', () async { 114 | GlobalConfiguration().clear(); 115 | GlobalConfiguration().addValue("hello", "world"); 116 | expect(GlobalConfiguration().getValue("hello"), "world"); 117 | }); 118 | } 119 | --------------------------------------------------------------------------------