├── .gitignore ├── .idea ├── copyright │ ├── Apache_License__Version_2_0.xml │ └── profiles_settings.xml └── dictionaries │ └── bod.xml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── android-sharedpreferences ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── android │ └── content │ └── SharedPreferences.java ├── build.gradle ├── etc └── illus.svg ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── illus.jpg ├── prefs-compiler ├── .gitignore ├── build.gradle └── src │ └── main │ ├── java │ └── org │ │ └── jraf │ │ └── android │ │ └── prefs │ │ └── compiler │ │ ├── Pref.java │ │ ├── PrefType.java │ │ ├── PrefsProcessor.java │ │ └── StringUtil.java │ └── resources │ ├── META-INF │ └── services │ │ └── javax.annotation.processing.Processor │ └── org │ └── jraf │ └── android │ └── prefs │ └── compiler │ ├── constants.ftl │ ├── editorwrapper.ftl │ └── prefwrapper.ftl ├── prefs ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── org │ └── jraf │ └── android │ └── prefs │ ├── DefaultBoolean.java │ ├── DefaultFloat.java │ ├── DefaultInt.java │ ├── DefaultLong.java │ ├── DefaultString.java │ ├── DefaultStringSet.java │ ├── EditorWrapper.java │ ├── Mode.java │ ├── Name.java │ ├── Prefs.java │ └── SharedPreferencesWrapper.java ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── kotlin │ └── org │ │ └── jraf │ │ └── android │ │ └── prefs │ │ └── sample │ │ ├── app │ │ └── MainActivity.kt │ │ └── prefs │ │ ├── Main.kt │ │ └── Settings.kt │ └── res │ ├── layout │ └── main.xml │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ └── values │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | 28 | # Android Studio Navigation editor temp files 29 | .navigation/ 30 | 31 | # Android Studio captures folder 32 | captures/ 33 | 34 | # Android Studio 35 | *.iml 36 | .idea 37 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs. 38 | .gradle 39 | 40 | # Windows thumbnail db 41 | Thumbs.db 42 | 43 | # OSX files 44 | .DS_Store 45 | 46 | # Eclipse project files 47 | .classpath 48 | .project -------------------------------------------------------------------------------- /.idea/copyright/Apache_License__Version_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 11 | 13 | 14 | 16 | 17 | 20 | 21 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/dictionaries/bod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | annot 5 | 6 | 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Prefs Changelog 2 | === 3 | 4 | v1.4.0 (2018-12-23) 5 | --- 6 | - Added androidx compatibility 7 | 8 | 9 | v1.3.0 (2018-12-02) 10 | --- 11 | - Updated dependencies to latest versions 12 | - Updated sample project to be in Kotlin 13 | - Added getXyzLiveData methods to observe the preferences 14 | 15 | 16 | v1.2.2 (2017-09-15) 17 | --- 18 | - Fixed a bug where some imports were missing in the generated code 19 | 20 | 21 | v1.2.1 (2017-08-26) 22 | --- 23 | - Added `setXyz` in addition to `putXyz` methods, to improve Kotlin interop. 24 | - New `XyzConstants` file generated with key names and default values. 25 | 26 | 27 | v1.1.1 (2017-01-08) 28 | --- 29 | Bug fix. 30 | - Fixed a crash when using `kapt` 31 | 32 | 33 | v1.1.0 (2015-09-13) 34 | --- 35 | Minor enhancements. 36 | - Fix for issue #5 37 | - Fix for issue #11 38 | - For boolean fields you can now use isXxx (in addition to getXxx). 39 | 40 | 41 | v1.0.1 (2015-05-01) 42 | --- 43 | Minor enhancements. 44 | - Fix for issue #1 45 | - Fix for issue #2 46 | - Fix for issue #3 47 | 48 | 49 | v1.0.0 (2015-04-26) 50 | --- 51 | Initial release 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Prefs 2 | === 3 | 4 | Android preferences for WINNERS! 5 | 6 | ![Be a winner!](/illus.jpg?raw=true "Be a winner!") 7 | 8 | 9 | This little tool generates wrappers for your SharedPreferences, so you can benefit from compile time 10 | verification and code completion in your IDE. You also get nice singletons for free. 11 | 12 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-android--prefs-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/1758) 13 | 14 | Usage 15 | --- 16 | 17 | ### 1/ Add the dependencies to your project 18 | 19 | ```groovy 20 | dependencies { 21 | /* ... */ 22 | annotationProcessor 'org.jraf:prefs-compiler:1.4.0' // or kapt if you use Kotlin 23 | implementation 'org.jraf:prefs:1.4.0' 24 | } 25 | ``` 26 | 27 | 28 | ### 2/ Define your preferences 29 | 30 | Use the `@Prefs` annotation on any plain old Java object. All its (non static) fields will be considered a preference. 31 | 32 | For instance: 33 | 34 | ```java 35 | @Prefs 36 | public class Main { 37 | /** 38 | * User login. 39 | */ 40 | String login; 41 | 42 | /** 43 | * User password. 44 | */ 45 | String password; 46 | 47 | @DefaultBoolean(false) 48 | Boolean isPremium; 49 | 50 | @Name("PREF_AGE") 51 | Integer age; 52 | } 53 | ``` 54 | 55 | Currently, the accepted types are: 56 | - Boolean 57 | - Float 58 | - Integer 59 | - Long 60 | - String 61 | - Set\ 62 | 63 | Optionally, use `@DefaultXxx` and `@Name` annotations (the default default is `null`, and the default name is the name of your field). 64 | 65 | You can pass a file name and mode (as per [Context.getSharedPreference()](http://developer.android.com/reference/android/content/Context.html#getSharedPreferences(java.lang.String, int))) like this: 66 | ```java 67 | @Prefs(fileName = "settings", fileMode = Context.MODE_PRIVATE) 68 | ``` 69 | 70 | If you don't, `PreferenceManager.getDefaultSharedPreferences(Context)` will be used. 71 | 72 | 73 | ### 3/ Be a winner! 74 | 75 | A class named `Prefs` will be generated in the same package (at compile time). Use it like this: 76 | 77 | ```java 78 | MainPrefs mainPrefs = MainPrefs.get(this); 79 | 80 | // Put a single value (apply() is automatically called) 81 | mainPrefs.putAge(42); 82 | 83 | // Put several values in one transaction 84 | mainPrefs.edit().putLogin("john").putPassword("p4Ssw0Rd").apply(); 85 | 86 | // Check if a value is set 87 | if (mainPrefs.containsLogin()) doSomething(); 88 | 89 | // Remove a value 90 | mainPrefs.removeAge(); 91 | // Or (this has the same effect) 92 | mainPrefs.putAge(null); 93 | 94 | // Clear all values! 95 | mainPrefs.clear(); 96 | ``` 97 | 98 | Bonus 1: in Kotlin you can directly use `=`: 99 | ```kotlin 100 | // Put a single value (apply() is automatically called) 101 | mainPrefs.age = 42 102 | ``` 103 | 104 | Bonus 2: you also get `LiveData`s to observe your preferences: 105 | ```kotlin 106 | mainPrefs.loginLiveData.observe(this, Observer { 107 | Log.d(TAG, "observed login=$it") 108 | }) 109 | ``` 110 | Note: currently this is disabled by default (because maybe you don't use `LiveData`?) - add `generateGetLiveData = true` 111 | to your `@Prefs` annotation to enabled it. 112 | 113 | 114 | License 115 | --- 116 | 117 | ``` 118 | Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 119 | 120 | Licensed under the Apache License, Version 2.0 (the "License"); 121 | you may not use this file except in compliance with the License. 122 | You may obtain a copy of the License at 123 | 124 | http://www.apache.org/licenses/LICENSE-2.0 125 | 126 | Unless required by applicable law or agreed to in writing, software 127 | distributed under the License is distributed on an "AS IS" BASIS, 128 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129 | See the License for the specific language governing permissions and 130 | limitations under the License. 131 | ``` 132 | 133 | __*Just to be absolutely clear, this license applies to this program itself, 134 | not to the source it will generate!*__ 135 | -------------------------------------------------------------------------------- /android-sharedpreferences/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android-sharedpreferences/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | 4 | sourceCompatibility = 1.6 5 | targetCompatibility = 1.6 6 | 7 | group = 'org.jraf' 8 | version = '1.0.0' 9 | 10 | javadoc.failOnError = false 11 | 12 | dependencies { 13 | } -------------------------------------------------------------------------------- /android-sharedpreferences/src/main/java/android/content/SharedPreferences.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.content; 18 | 19 | import java.util.Map; 20 | import java.util.Set; 21 | 22 | /** 23 | * Interface for accessing and modifying preference data returned by {@link 24 | * Context#getSharedPreferences}. For any particular set of preferences, 25 | * there is a single instance of this class that all clients share. 26 | * Modifications to the preferences must go through an {@link Editor} object 27 | * to ensure the preference values remain in a consistent state and control 28 | * when they are committed to storage. Objects that are returned from the 29 | * various get methods must be treated as immutable by the application. 30 | * 31 | *

Note: currently this class does not support use across multiple 32 | * processes. This will be added later. 33 | * 34 | *

35 | *

Developer Guides

36 | *

For more information about using SharedPreferences, read the 37 | * Data Storage 38 | * developer guide.

39 | * 40 | * @see Context#getSharedPreferences 41 | */ 42 | public interface SharedPreferences { 43 | /** 44 | * Interface definition for a callback to be invoked when a shared 45 | * preference is changed. 46 | */ 47 | public interface OnSharedPreferenceChangeListener { 48 | /** 49 | * Called when a shared preference is changed, added, or removed. This 50 | * may be called even if a preference is set to its existing value. 51 | * 52 | *

This callback will be run on your main thread. 53 | * 54 | * @param sharedPreferences The {@link SharedPreferences} that received 55 | * the change. 56 | * @param key The key of the preference that was changed, added, or 57 | * removed. 58 | */ 59 | void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key); 60 | } 61 | 62 | /** 63 | * Interface used for modifying values in a {@link SharedPreferences} 64 | * object. All changes you make in an editor are batched, and not copied 65 | * back to the original {@link SharedPreferences} until you call {@link #commit} 66 | * or {@link #apply} 67 | */ 68 | public interface Editor { 69 | /** 70 | * Set a String value in the preferences editor, to be written back once 71 | * {@link #commit} or {@link #apply} are called. 72 | * 73 | * @param key The name of the preference to modify. 74 | * @param value The new value for the preference. Supplying {@code null} 75 | * as the value is equivalent to calling {@link #remove(String)} with 76 | * this key. 77 | * @return Returns a reference to the same Editor object, so you can 78 | * chain put calls together. 79 | */ 80 | Editor putString(String key, String value); 81 | 82 | /** 83 | * Set a set of String values in the preferences editor, to be written 84 | * back once {@link #commit} or {@link #apply} is called. 85 | * 86 | * @param key The name of the preference to modify. 87 | * @param values The set of new values for the preference. Passing {@code null} 88 | * for this argument is equivalent to calling {@link #remove(String)} with 89 | * this key. 90 | * @return Returns a reference to the same Editor object, so you can 91 | * chain put calls together. 92 | */ 93 | Editor putStringSet(String key, Set values); 94 | 95 | /** 96 | * Set an int value in the preferences editor, to be written back once 97 | * {@link #commit} or {@link #apply} are called. 98 | * 99 | * @param key The name of the preference to modify. 100 | * @param value The new value for the preference. 101 | * @return Returns a reference to the same Editor object, so you can 102 | * chain put calls together. 103 | */ 104 | Editor putInt(String key, int value); 105 | 106 | /** 107 | * Set a long value in the preferences editor, to be written back once 108 | * {@link #commit} or {@link #apply} are called. 109 | * 110 | * @param key The name of the preference to modify. 111 | * @param value The new value for the preference. 112 | * @return Returns a reference to the same Editor object, so you can 113 | * chain put calls together. 114 | */ 115 | Editor putLong(String key, long value); 116 | 117 | /** 118 | * Set a float value in the preferences editor, to be written back once 119 | * {@link #commit} or {@link #apply} are called. 120 | * 121 | * @param key The name of the preference to modify. 122 | * @param value The new value for the preference. 123 | * @return Returns a reference to the same Editor object, so you can 124 | * chain put calls together. 125 | */ 126 | Editor putFloat(String key, float value); 127 | 128 | /** 129 | * Set a boolean value in the preferences editor, to be written back 130 | * once {@link #commit} or {@link #apply} are called. 131 | * 132 | * @param key The name of the preference to modify. 133 | * @param value The new value for the preference. 134 | * @return Returns a reference to the same Editor object, so you can 135 | * chain put calls together. 136 | */ 137 | Editor putBoolean(String key, boolean value); 138 | 139 | /** 140 | * Mark in the editor that a preference value should be removed, which 141 | * will be done in the actual preferences once {@link #commit} is 142 | * called. 143 | * 144 | *

Note that when committing back to the preferences, all removals 145 | * are done first, regardless of whether you called remove before 146 | * or after put methods on this editor. 147 | * 148 | * @param key The name of the preference to remove. 149 | * @return Returns a reference to the same Editor object, so you can 150 | * chain put calls together. 151 | */ 152 | Editor remove(String key); 153 | 154 | /** 155 | * Mark in the editor to remove all values from the 156 | * preferences. Once commit is called, the only remaining preferences 157 | * will be any that you have defined in this editor. 158 | * 159 | *

Note that when committing back to the preferences, the clear 160 | * is done first, regardless of whether you called clear before 161 | * or after put methods on this editor. 162 | * 163 | * @return Returns a reference to the same Editor object, so you can 164 | * chain put calls together. 165 | */ 166 | Editor clear(); 167 | 168 | /** 169 | * Commit your preferences changes back from this Editor to the 170 | * {@link SharedPreferences} object it is editing. This atomically 171 | * performs the requested modifications, replacing whatever is currently 172 | * in the SharedPreferences. 173 | * 174 | *

Note that when two editors are modifying preferences at the same 175 | * time, the last one to call commit wins. 176 | * 177 | *

If you don't care about the return value and you're 178 | * using this from your application's main thread, consider 179 | * using {@link #apply} instead. 180 | * 181 | * @return Returns true if the new values were successfully written 182 | * to persistent storage. 183 | */ 184 | boolean commit(); 185 | 186 | /** 187 | * Commit your preferences changes back from this Editor to the 188 | * {@link SharedPreferences} object it is editing. This atomically 189 | * performs the requested modifications, replacing whatever is currently 190 | * in the SharedPreferences. 191 | * 192 | *

Note that when two editors are modifying preferences at the same 193 | * time, the last one to call apply wins. 194 | * 195 | *

Unlike {@link #commit}, which writes its preferences out 196 | * to persistent storage synchronously, {@link #apply} 197 | * commits its changes to the in-memory 198 | * {@link SharedPreferences} immediately but starts an 199 | * asynchronous commit to disk and you won't be notified of 200 | * any failures. If another editor on this 201 | * {@link SharedPreferences} does a regular {@link #commit} 202 | * while a {@link #apply} is still outstanding, the 203 | * {@link #commit} will block until all async commits are 204 | * completed as well as the commit itself. 205 | * 206 | *

As {@link SharedPreferences} instances are singletons within 207 | * a process, it's safe to replace any instance of {@link #commit} with 208 | * {@link #apply} if you were already ignoring the return value. 209 | * 210 | *

You don't need to worry about Android component 211 | * lifecycles and their interaction with apply() 212 | * writing to disk. The framework makes sure in-flight disk 213 | * writes from apply() complete before switching 214 | * states. 215 | * 216 | *

The SharedPreferences.Editor interface 217 | * isn't expected to be implemented directly. However, if you 218 | * previously did implement it and are now getting errors 219 | * about missing apply(), you can simply call 220 | * {@link #commit} from apply(). 221 | */ 222 | void apply(); 223 | } 224 | 225 | /** 226 | * Retrieve all values from the preferences. 227 | * 228 | *

Note that you must not modify the collection returned 229 | * by this method, or alter any of its contents. The consistency of your 230 | * stored data is not guaranteed if you do. 231 | * 232 | * @return Returns a map containing a list of pairs key/value representing 233 | * the preferences. 234 | */ 235 | Map getAll(); 236 | 237 | /** 238 | * Retrieve a String value from the preferences. 239 | * 240 | * @param key The name of the preference to retrieve. 241 | * @param defValue Value to return if this preference does not exist. 242 | * @return Returns the preference value if it exists, or defValue. Throws 243 | * ClassCastException if there is a preference with this name that is not 244 | * a String. 245 | */ 246 | String getString(String key, String defValue); 247 | 248 | /** 249 | * Retrieve a set of String values from the preferences. 250 | * 251 | *

Note that you must not modify the set instance returned 252 | * by this call. The consistency of the stored data is not guaranteed 253 | * if you do, nor is your ability to modify the instance at all. 254 | * 255 | * @param key The name of the preference to retrieve. 256 | * @param defValues Values to return if this preference does not exist. 257 | * @return Returns the preference values if they exist, or defValues. 258 | * Throws ClassCastException if there is a preference with this name 259 | * that is not a Set. 260 | */ 261 | Set getStringSet(String key, Set defValues); 262 | 263 | /** 264 | * Retrieve an int value from the preferences. 265 | * 266 | * @param key The name of the preference to retrieve. 267 | * @param defValue Value to return if this preference does not exist. 268 | * @return Returns the preference value if it exists, or defValue. Throws 269 | * ClassCastException if there is a preference with this name that is not 270 | * an int. 271 | */ 272 | int getInt(String key, int defValue); 273 | 274 | /** 275 | * Retrieve a long value from the preferences. 276 | * 277 | * @param key The name of the preference to retrieve. 278 | * @param defValue Value to return if this preference does not exist. 279 | * @return Returns the preference value if it exists, or defValue. Throws 280 | * ClassCastException if there is a preference with this name that is not 281 | * a long. 282 | */ 283 | long getLong(String key, long defValue); 284 | 285 | /** 286 | * Retrieve a float value from the preferences. 287 | * 288 | * @param key The name of the preference to retrieve. 289 | * @param defValue Value to return if this preference does not exist. 290 | * @return Returns the preference value if it exists, or defValue. Throws 291 | * ClassCastException if there is a preference with this name that is not 292 | * a float. 293 | */ 294 | float getFloat(String key, float defValue); 295 | 296 | /** 297 | * Retrieve a boolean value from the preferences. 298 | * 299 | * @param key The name of the preference to retrieve. 300 | * @param defValue Value to return if this preference does not exist. 301 | * @return Returns the preference value if it exists, or defValue. Throws 302 | * ClassCastException if there is a preference with this name that is not 303 | * a boolean. 304 | */ 305 | boolean getBoolean(String key, boolean defValue); 306 | 307 | /** 308 | * Checks whether the preferences contains a preference. 309 | * 310 | * @param key The name of the preference to check. 311 | * @return Returns true if the preference exists in the preferences, 312 | * otherwise false. 313 | */ 314 | boolean contains(String key); 315 | 316 | /** 317 | * Create a new Editor for these preferences, through which you can make 318 | * modifications to the data in the preferences and atomically commit those 319 | * changes back to the SharedPreferences object. 320 | * 321 | *

Note that you must call {@link Editor#commit} to have any 322 | * changes you perform in the Editor actually show up in the 323 | * SharedPreferences. 324 | * 325 | * @return Returns a new instance of the {@link Editor} interface, allowing 326 | * you to modify the values in this SharedPreferences object. 327 | */ 328 | Editor edit(); 329 | 330 | /** 331 | * Registers a callback to be invoked when a change happens to a preference. 332 | * 333 | *

Caution: The preference manager does 334 | * not currently store a strong reference to the listener. You must store a 335 | * strong reference to the listener, or it will be susceptible to garbage 336 | * collection. We recommend you keep a reference to the listener in the 337 | * instance data of an object that will exist as long as you need the 338 | * listener.

339 | * 340 | * @param listener The callback that will run. 341 | * @see #unregisterOnSharedPreferenceChangeListener 342 | */ 343 | void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener); 344 | 345 | /** 346 | * Unregisters a previous callback. 347 | * 348 | * @param listener The callback that should be unregistered. 349 | * @see #registerOnSharedPreferenceChangeListener 350 | */ 351 | void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener); 352 | } 353 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.2.1' 11 | classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' 12 | classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.10' 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | jcenter() 20 | mavenLocal() 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | 28 | wrapper { 29 | gradleVersion = '5.0' 30 | distributionType = Wrapper.DistributionType.ALL 31 | } 32 | 33 | // Run './gradlew dependencyUpdates' to see new versions of dependencies 34 | apply plugin: 'com.github.ben-manes.versions' 35 | dependencyUpdates.resolutionStrategy = { 36 | componentSelection { rules -> 37 | rules.all { selection -> 38 | boolean rejected = ['alpha', 'beta', 'rc', '20050927'].any { qualifier -> 39 | selection.candidate.version.toLowerCase() ==~ /.*-${qualifier}.*/ 40 | } 41 | if (rejected) { 42 | selection.reject('Release candidate') 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /etc/illus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 26 | 33 | 34 | 35 | 53 | 55 | 56 | 58 | image/svg+xml 59 | 61 | 62 | 63 | 64 | 65 | 70 | 77 | 432 | prefs.edit() .putInt("FOO", 42) .commit(); 451 | 454 | prefs.putFoo(42); 465 | 1038 | 1474 | 1475 | 1480 | 1481 | 1482 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | org.gradle.parallel=true 19 | # Enable build cache 20 | org.gradle.caching=true 21 | # Use AndroidX 22 | android.useAndroidX=true 23 | android.enableJetifier=true 24 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BoD/android-prefs/4587bac2807a845ec0cd8944578997ef49a96ce9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /illus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BoD/android-prefs/4587bac2807a845ec0cd8944578997ef49a96ce9/illus.jpg -------------------------------------------------------------------------------- /prefs-compiler/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /prefs-compiler/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | 4 | sourceCompatibility = 1.6 5 | targetCompatibility = 1.6 6 | 7 | group = 'org.jraf' 8 | version = '1.4.0' 9 | 10 | javadoc.failOnError = false 11 | 12 | task sourcesJar(type: Jar, dependsOn: classes) { 13 | classifier = 'sources' 14 | from sourceSets.main.allSource 15 | } 16 | 17 | task javadocJar(type: Jar, dependsOn: javadoc) { 18 | classifier = 'javadoc' 19 | from javadoc.destinationDir 20 | } 21 | 22 | artifacts { 23 | archives sourcesJar 24 | archives javadocJar 25 | } 26 | 27 | dependencies { 28 | compile 'org.freemarker:freemarker:2.3.28' 29 | compile 'commons-io:commons-io:2.6' 30 | compile 'org.apache.commons:commons-lang3:3.8.1' 31 | compile project(':prefs') 32 | } 33 | 34 | // Use "./gradlew install" to deploy the artifacts to your local maven repository 35 | -------------------------------------------------------------------------------- /prefs-compiler/src/main/java/org/jraf/android/prefs/compiler/Pref.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs.compiler; 25 | 26 | public class Pref { 27 | private final String mFieldName; 28 | private final String mPrefName; 29 | private final PrefType mType; 30 | private final String mDefaultValue; 31 | private final String mComment; 32 | 33 | public Pref(String fieldName, String prefName, PrefType type, String defaultValue, String comment) { 34 | mFieldName = fieldName; 35 | mPrefName = prefName; 36 | mType = type; 37 | mDefaultValue = defaultValue; 38 | mComment = comment; 39 | } 40 | 41 | 42 | public String getFieldName() { 43 | return mFieldName; 44 | } 45 | 46 | public String getFieldNameUpperCase() { 47 | return mFieldName.replaceAll("([A-Z]+)", "\\_$1").toUpperCase(); 48 | } 49 | 50 | public String getPrefName() { 51 | return mPrefName; 52 | } 53 | 54 | public PrefType getType() { 55 | return mType; 56 | } 57 | 58 | public String getDefaultValue() { 59 | return mDefaultValue; 60 | } 61 | 62 | public String getComment() { 63 | return mComment; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return "Pref{" + 69 | "mFieldName='" + mFieldName + '\'' + 70 | ", mPrefName='" + mPrefName + '\'' + 71 | ", mType=" + mType + 72 | ", mDefaultValue='" + mDefaultValue + '\'' + 73 | ", mComment='" + mComment + '\'' + 74 | '}'; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /prefs-compiler/src/main/java/org/jraf/android/prefs/compiler/PrefType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs.compiler; 25 | 26 | import org.apache.commons.lang3.StringUtils; 27 | 28 | import javax.lang.model.type.TypeMirror; 29 | import java.util.ArrayList; 30 | 31 | public enum PrefType { 32 | BOOLEAN(Boolean.class.getName(), Boolean.class.getSimpleName(), "Boolean", "false"), 33 | FLOAT(Float.class.getName(), Float.class.getSimpleName(), "Float", "0f"), 34 | INTEGER(Integer.class.getName(), Integer.class.getSimpleName(), "Int", "0"), 35 | LONG(Long.class.getName(), Long.class.getSimpleName(), "Long", "0L"), 36 | STRING(String.class.getName(), String.class.getSimpleName(), "String", "null"), 37 | STRING_SET("java.util.Set", "Set", "StringSet", "null"),; 38 | 39 | private final String mFullName; 40 | private final String mSimpleName; 41 | private final String mMethodName; 42 | private final String mDefaultValue; 43 | 44 | PrefType(String fullName, String simpleName, String methodName, String defaultValue) { 45 | mFullName = fullName; 46 | mSimpleName = simpleName; 47 | mMethodName = methodName; 48 | mDefaultValue = defaultValue; 49 | } 50 | 51 | public String getFullName() { 52 | return mFullName; 53 | } 54 | 55 | public String getSimpleName() { 56 | return mSimpleName; 57 | } 58 | 59 | public String getMethodName() { 60 | return mMethodName; 61 | } 62 | 63 | public String getDefaultValue() { 64 | return mDefaultValue; 65 | } 66 | 67 | public boolean isCompatible(TypeMirror type) { 68 | return getFullName().equals(type.toString()); 69 | } 70 | 71 | public static PrefType from(TypeMirror fieldType) { 72 | String fullName = fieldType.toString(); 73 | for (PrefType prefType : values()) { 74 | if (prefType.getFullName().equals(fullName)) return prefType; 75 | } 76 | throw new IllegalArgumentException("Unsupported type: " + fullName); 77 | } 78 | 79 | public static boolean isAllowedType(TypeMirror fieldType) { 80 | String fullName = fieldType.toString(); 81 | boolean found = false; 82 | for (PrefType prefType : values()) { 83 | if (prefType.getFullName().equals(fullName)) { 84 | found = true; 85 | break; 86 | } 87 | } 88 | return found; 89 | } 90 | 91 | public static String getAllowedTypes() { 92 | ArrayList allowedTypes = new ArrayList(values().length); 93 | for (PrefType prefType : values()) { 94 | allowedTypes.add(prefType.getFullName()); 95 | } 96 | return StringUtils.join(allowedTypes, ", "); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /prefs-compiler/src/main/java/org/jraf/android/prefs/compiler/PrefsProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs.compiler; 25 | 26 | import freemarker.template.Configuration; 27 | import freemarker.template.Template; 28 | import freemarker.template.Version; 29 | import org.apache.commons.io.IOUtils; 30 | import org.jraf.android.prefs.DefaultInt; 31 | 32 | import javax.annotation.processing.AbstractProcessor; 33 | import javax.annotation.processing.RoundEnvironment; 34 | import javax.annotation.processing.SupportedAnnotationTypes; 35 | import javax.lang.model.SourceVersion; 36 | import javax.lang.model.element.*; 37 | import javax.lang.model.type.TypeMirror; 38 | import javax.lang.model.util.ElementFilter; 39 | import javax.tools.Diagnostic; 40 | import javax.tools.JavaFileObject; 41 | import java.io.Writer; 42 | import java.lang.annotation.Annotation; 43 | import java.util.*; 44 | 45 | @SupportedAnnotationTypes("org.jraf.android.prefs.Prefs") 46 | public class PrefsProcessor extends AbstractProcessor { 47 | private static final String SUFFIX_PREF_WRAPPER = "Prefs"; 48 | private static final String SUFFIX_EDITOR_WRAPPER = "EditorWrapper"; 49 | private static final String SUFFIX_CONSTANTS = "Constants"; 50 | 51 | private Configuration mFreemarkerConfiguration; 52 | 53 | @Override 54 | public SourceVersion getSupportedSourceVersion() { 55 | return SourceVersion.latestSupported(); 56 | } 57 | 58 | private Configuration getFreemarkerConfiguration() { 59 | if (mFreemarkerConfiguration == null) { 60 | mFreemarkerConfiguration = new Configuration(new Version(2, 3, 26)); 61 | mFreemarkerConfiguration.setClassForTemplateLoading(getClass(), ""); 62 | } 63 | return mFreemarkerConfiguration; 64 | } 65 | 66 | @Override 67 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 68 | for (TypeElement annotation : annotations) { 69 | if (!annotation.getQualifiedName().contentEquals("org.jraf.android.prefs.Prefs")) { 70 | // Should never happen - but does with kapt :) 71 | continue; 72 | } 73 | for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) { 74 | TypeElement classElement = (TypeElement) element; 75 | PackageElement packageElement = (PackageElement) classElement.getEnclosingElement(); 76 | 77 | String classComment = processingEnv.getElementUtils().getDocComment(classElement); 78 | 79 | List prefList = new ArrayList(); 80 | // Iterate over the fields of the class 81 | for (VariableElement variableElement : ElementFilter.fieldsIn(classElement.getEnclosedElements())) { 82 | if (variableElement.getModifiers().contains(Modifier.STATIC)) { 83 | // Ignore constants 84 | continue; 85 | } 86 | 87 | TypeMirror fieldType = variableElement.asType(); 88 | boolean isAllowedType = PrefType.isAllowedType(fieldType); 89 | if (!isAllowedType) { 90 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 91 | fieldType + " is not allowed here, only these types are allowed: " + PrefType.getAllowedTypes(), variableElement); 92 | // Problem detected: halt 93 | return true; 94 | } 95 | 96 | String fieldName = variableElement.getSimpleName().toString(); 97 | org.jraf.android.prefs.Name fieldNameAnnot = variableElement.getAnnotation(org.jraf.android.prefs.Name.class); 98 | String prefName = getPrefName(fieldName, fieldNameAnnot); 99 | 100 | String prefDefaultValue = getDefaultValue(variableElement, fieldType); 101 | if (prefDefaultValue == null) { 102 | // Problem detected: halt 103 | return true; 104 | } 105 | 106 | String fieldComment = StringUtil.cleanComment(processingEnv.getElementUtils().getDocComment(variableElement)); 107 | Pref pref = new Pref(fieldName, prefName, PrefType.from(fieldType), prefDefaultValue, fieldComment); 108 | prefList.add(pref); 109 | } 110 | 111 | Map args = new HashMap(); 112 | 113 | // File name (optional - also use 'value' for this) 114 | org.jraf.android.prefs.Prefs prefsAnnot = classElement.getAnnotation(org.jraf.android.prefs.Prefs.class); 115 | String fileName = prefsAnnot.value(); 116 | if (fileName.isEmpty()) { 117 | fileName = prefsAnnot.fileName(); 118 | } 119 | if (!fileName.isEmpty()) args.put("fileName", fileName); 120 | 121 | // File mode (must only appear if fileName is defined) 122 | int fileMode = prefsAnnot.fileMode(); 123 | if (fileMode != -1) { 124 | if (fileName.isEmpty()) { 125 | // File mode set, but not file name (which makes no sense) 126 | processingEnv.getMessager() 127 | .printMessage(Diagnostic.Kind.ERROR, "fileMode must only be set if fileName (or value) is also set", classElement); 128 | // Problem detected: halt 129 | return true; 130 | } 131 | args.put("fileMode", fileMode); 132 | } 133 | 134 | // Disable @Nullable generation 135 | args.put("disableNullable", prefsAnnot.disableNullable()); 136 | 137 | // Generate getLiveData methods 138 | args.put("generateGetLiveData", prefsAnnot.generateGetLiveData()); 139 | 140 | // Use AndroidX 141 | args.put("useAndroidX", prefsAnnot.useAndroidX()); 142 | 143 | JavaFileObject javaFileObject = null; 144 | try { 145 | args.put("package", packageElement.getQualifiedName()); 146 | args.put("comment", StringUtil.cleanComment(classComment)); 147 | args.put("prefWrapperClassName", classElement.getSimpleName() + SUFFIX_PREF_WRAPPER); 148 | args.put("editorWrapperClassName", classElement.getSimpleName() + SUFFIX_EDITOR_WRAPPER); 149 | args.put("constantsClassName", classElement.getSimpleName() + SUFFIX_CONSTANTS); 150 | args.put("prefList", prefList); 151 | 152 | // SharedPreferencesWrapper 153 | javaFileObject = processingEnv.getFiler().createSourceFile(classElement.getQualifiedName() + SUFFIX_PREF_WRAPPER); 154 | Template template = getFreemarkerConfiguration().getTemplate("prefwrapper.ftl"); 155 | Writer writer = javaFileObject.openWriter(); 156 | template.process(args, writer); 157 | IOUtils.closeQuietly(writer); 158 | 159 | // EditorWrapper 160 | javaFileObject = processingEnv.getFiler().createSourceFile(classElement.getQualifiedName() + SUFFIX_EDITOR_WRAPPER); 161 | template = getFreemarkerConfiguration().getTemplate("editorwrapper.ftl"); 162 | writer = javaFileObject.openWriter(); 163 | template.process(args, writer); 164 | IOUtils.closeQuietly(writer); 165 | 166 | // Constants 167 | javaFileObject = processingEnv.getFiler().createSourceFile(classElement.getQualifiedName() + SUFFIX_CONSTANTS); 168 | template = getFreemarkerConfiguration().getTemplate("constants.ftl"); 169 | writer = javaFileObject.openWriter(); 170 | template.process(args, writer); 171 | IOUtils.closeQuietly(writer); 172 | 173 | } catch (Exception e) { 174 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 175 | "En error occurred while generating Prefs code " + e.getClass() + e.getMessage(), element); 176 | e.printStackTrace(); 177 | // Problem detected: halt 178 | return true; 179 | } 180 | } 181 | } 182 | return true; 183 | } 184 | 185 | private String getDefaultValue(VariableElement variableElement, TypeMirror fieldType) { 186 | Class annotClass = org.jraf.android.prefs.DefaultBoolean.class; 187 | PrefType compatiblePrefType = PrefType.BOOLEAN; 188 | org.jraf.android.prefs.DefaultBoolean defaultBooleanAnnot = (org.jraf.android.prefs.DefaultBoolean) variableElement.getAnnotation(annotClass); 189 | if (defaultBooleanAnnot != null) { 190 | if (!ensureCompatibleAnnotation(compatiblePrefType, fieldType, annotClass, variableElement)) return null; 191 | return String.valueOf(defaultBooleanAnnot.value()); 192 | } 193 | 194 | annotClass = org.jraf.android.prefs.DefaultFloat.class; 195 | compatiblePrefType = PrefType.FLOAT; 196 | org.jraf.android.prefs.DefaultFloat defaultFloatAnnot = (org.jraf.android.prefs.DefaultFloat) variableElement.getAnnotation(annotClass); 197 | if (defaultFloatAnnot != null) { 198 | if (!ensureCompatibleAnnotation(compatiblePrefType, fieldType, annotClass, variableElement)) return null; 199 | return String.valueOf(defaultFloatAnnot.value()) + "f"; 200 | } 201 | 202 | annotClass = DefaultInt.class; 203 | compatiblePrefType = PrefType.INTEGER; 204 | DefaultInt defaultIntAnnot = (DefaultInt) variableElement.getAnnotation(annotClass); 205 | if (defaultIntAnnot != null) { 206 | if (!ensureCompatibleAnnotation(compatiblePrefType, fieldType, annotClass, variableElement)) return null; 207 | return String.valueOf(defaultIntAnnot.value()); 208 | } 209 | 210 | annotClass = org.jraf.android.prefs.DefaultLong.class; 211 | compatiblePrefType = PrefType.LONG; 212 | org.jraf.android.prefs.DefaultLong defaultLongAnnot = (org.jraf.android.prefs.DefaultLong) variableElement.getAnnotation(annotClass); 213 | if (defaultLongAnnot != null) { 214 | if (!ensureCompatibleAnnotation(compatiblePrefType, fieldType, annotClass, variableElement)) return null; 215 | return String.valueOf(defaultLongAnnot.value()) + "L"; 216 | } 217 | 218 | annotClass = org.jraf.android.prefs.DefaultString.class; 219 | compatiblePrefType = PrefType.STRING; 220 | org.jraf.android.prefs.DefaultString defaultStringAnnot = (org.jraf.android.prefs.DefaultString) variableElement.getAnnotation(annotClass); 221 | if (defaultStringAnnot != null) { 222 | if (!ensureCompatibleAnnotation(compatiblePrefType, fieldType, annotClass, variableElement)) return null; 223 | return "\"" + unescapeString(defaultStringAnnot.value()) + "\""; 224 | } 225 | 226 | annotClass = org.jraf.android.prefs.DefaultStringSet.class; 227 | compatiblePrefType = PrefType.STRING_SET; 228 | org.jraf.android.prefs.DefaultStringSet defaultStringSetAnnot = (org.jraf.android.prefs.DefaultStringSet) variableElement.getAnnotation(annotClass); 229 | if (defaultStringSetAnnot != null) { 230 | if (!ensureCompatibleAnnotation(compatiblePrefType, fieldType, annotClass, variableElement)) return null; 231 | StringBuilder res = new StringBuilder("new HashSet(Arrays.asList("); 232 | int i = 0; 233 | for (String s : defaultStringSetAnnot.value()) { 234 | if (i > 0) res.append(", "); 235 | res.append("\""); 236 | res.append(unescapeString(s)); 237 | res.append("\""); 238 | i++; 239 | } 240 | res.append("))"); 241 | return res.toString(); 242 | } 243 | 244 | // Default default value :) 245 | return "null"; 246 | } 247 | 248 | private boolean ensureCompatibleAnnotation(PrefType prefType, TypeMirror fieldType, Class annotClass, VariableElement variableElement) { 249 | if (!prefType.isCompatible(fieldType)) { 250 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 251 | annotClass.getSimpleName() + " annotation is only allowed on " + prefType.getSimpleName() + " fields", variableElement); 252 | return false; 253 | } 254 | return true; 255 | } 256 | 257 | private static String getPrefName(String fieldName, org.jraf.android.prefs.Name fieldNameAnnot) { 258 | if (fieldNameAnnot != null) { 259 | return fieldNameAnnot.value(); 260 | } 261 | return fieldName; 262 | } 263 | 264 | private String unescapeString(String s) { 265 | StringBuilder sb = new StringBuilder(); 266 | for (int i = 0, count = s.length(); i < count; i++) 267 | switch (s.charAt(i)){ 268 | case '\t': sb.append("\\t"); break; 269 | case '\b': sb.append("\\b"); break; 270 | case '\n': sb.append("\\n"); break; 271 | case '\r': sb.append("\\r"); break; 272 | case '\f': sb.append("\\f"); break; 273 | case '\'': sb.append("\\'"); break; 274 | case '\"': sb.append("\\\""); break; 275 | case '\\': sb.append("\\\\"); break; 276 | default: sb.append(s.charAt(i)); 277 | } 278 | return sb.toString(); 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /prefs-compiler/src/main/java/org/jraf/android/prefs/compiler/StringUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2018-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs.compiler; 25 | 26 | public class StringUtil { 27 | public static String cleanComment(String s) { 28 | if (s == null) return null; 29 | if (s.startsWith(" * ")) return s.substring(2); 30 | return s; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /prefs-compiler/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | org.jraf.android.prefs.compiler.PrefsProcessor -------------------------------------------------------------------------------- /prefs-compiler/src/main/resources/org/jraf/android/prefs/compiler/constants.ftl: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | <#if comment??> 8 | /** 9 | * ${comment?trim} 10 | */ 11 | 12 | public class ${constantsClassName} { 13 | <#list prefList as pref> 14 | 15 | 16 | //================================================================================ 17 | // region ${pref.fieldName?cap_first} 18 | //================================================================================ 19 | 20 | <#if pref.comment??> 21 | /** 22 | * ${pref.comment?trim} 23 | */ 24 | <#t> 25 | public static final String KEY_${pref.fieldNameUpperCase} = "${pref.prefName}"; 26 | 27 | public static final ${pref.type.simpleName} DEFAULT_${pref.fieldNameUpperCase} = ${pref.defaultValue}; 28 | 29 | // endregion 30 | 31 | } -------------------------------------------------------------------------------- /prefs-compiler/src/main/resources/org/jraf/android/prefs/compiler/editorwrapper.ftl: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import java.util.Set; 4 | 5 | import android.content.SharedPreferences; 6 | 7 | import org.jraf.android.prefs.EditorWrapper; 8 | 9 | <#if comment??> 10 | /** 11 | * ${comment?trim} 12 | */ 13 | 14 | public class ${editorWrapperClassName} extends EditorWrapper { 15 | public ${editorWrapperClassName}(SharedPreferences.Editor wrapped) { 16 | super(wrapped); 17 | } 18 | <#list prefList as pref> 19 | 20 | 21 | //================================================================================ 22 | // region ${pref.fieldName?cap_first} 23 | //================================================================================ 24 | 25 | <#if pref.comment??> 26 | /** 27 | * ${pref.comment?trim} 28 | */ 29 | <#t> 30 | public ${editorWrapperClassName} put${pref.fieldName?cap_first}(${pref.type.simpleName} ${pref.fieldName}) { 31 | if (${pref.fieldName} == null) { 32 | remove(${constantsClassName}.KEY_${pref.fieldNameUpperCase}); 33 | } else { 34 | put${pref.type.methodName}(${constantsClassName}.KEY_${pref.fieldNameUpperCase}, ${pref.fieldName}); 35 | } 36 | return this; 37 | } 38 | 39 | <#if pref.comment??> 40 | /** 41 | * ${pref.comment?trim} 42 | */ 43 | <#t> 44 | public ${editorWrapperClassName} set${pref.fieldName?cap_first}(${pref.type.simpleName} ${pref.fieldName}) { 45 | return put${pref.fieldName?cap_first}(${pref.fieldName}); 46 | } 47 | 48 | <#if pref.comment??> 49 | /** 50 | * ${pref.comment?trim} 51 | */ 52 | <#t> 53 | public ${editorWrapperClassName} remove${pref.fieldName?cap_first}() { 54 | remove(${constantsClassName}.KEY_${pref.fieldNameUpperCase}); 55 | return this; 56 | } 57 | 58 | // endregion 59 | 60 | } -------------------------------------------------------------------------------- /prefs-compiler/src/main/resources/org/jraf/android/prefs/compiler/prefwrapper.ftl: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import java.util.Set; 4 | 5 | import android.annotation.SuppressLint; 6 | <#if generateGetLiveData> 7 | import <#if useAndroidX>androidx<#else>android.arch.lifecycle.LiveData; 8 | import <#if useAndroidX>androidx<#else>android.arch.lifecycle.MutableLiveData; 9 | <#t> 10 | import android.content.Context; 11 | import android.content.SharedPreferences; 12 | import android.preference.PreferenceManager; 13 | <#if !disableNullable> 14 | import <#if useAndroidX>androidx<#else>android.support.annotation.NonNull; 15 | import <#if useAndroidX>androidx<#else>android.support.annotation.Nullable; 16 | <#t> 17 | 18 | import org.jraf.android.prefs.SharedPreferencesWrapper; 19 | 20 | <#if comment??> 21 | /** 22 | * ${comment?trim} 23 | */ 24 | 25 | public class ${prefWrapperClassName} extends SharedPreferencesWrapper { 26 | private static ${prefWrapperClassName} sInstance; 27 | 28 | <#if !disableNullable>@NonNull 29 | public static ${prefWrapperClassName} get(Context context) { 30 | if (sInstance == null) { 31 | SharedPreferences wrapped = getWrapped(context); 32 | sInstance = new ${prefWrapperClassName}(wrapped); 33 | } 34 | return sInstance; 35 | } 36 | 37 | protected static SharedPreferences getWrapped(Context context) { 38 | <#if fileName??> 39 | return context.getSharedPreferences("${fileName}", ${fileMode}); 40 | <#else> 41 | return PreferenceManager.getDefaultSharedPreferences(context); 42 | 43 | } 44 | 45 | public ${prefWrapperClassName}(SharedPreferences wrapped) { 46 | super(wrapped); 47 | } 48 | 49 | <#if !disableNullable>@NonNull 50 | @SuppressLint("CommitPrefEdits") 51 | public ${editorWrapperClassName} edit() { 52 | return new ${editorWrapperClassName}(super.edit()); 53 | } 54 | <#list prefList as pref> 55 | 56 | 57 | //================================================================================ 58 | // region ${pref.fieldName?cap_first} 59 | //================================================================================ 60 | 61 | <#if pref.type == "BOOLEAN"> 62 | <#if pref.comment??> 63 | /** 64 | * ${pref.comment?trim} 65 | */ 66 | <#t> 67 | <#if !disableNullable && pref.defaultValue == "null"> 68 | @Nullable 69 | <#t> 70 | public ${pref.type.simpleName} get${pref.fieldName?cap_first}() { 71 | return is${pref.fieldName?cap_first}(); 72 | } 73 | 74 | 75 | <#if pref.comment??> 76 | /** 77 | * ${pref.comment?trim} 78 | */ 79 | <#t> 80 | <#if !disableNullable && pref.defaultValue == "null"> 81 | @Nullable 82 | <#t> 83 | public ${pref.type.simpleName} <#if pref.type == "BOOLEAN">is<#else>get${pref.fieldName?cap_first}() { 84 | if (!contains(${constantsClassName}.KEY_${pref.fieldNameUpperCase})) return ${constantsClassName}.DEFAULT_${pref.fieldNameUpperCase}; 85 | return get${pref.type.methodName}(${constantsClassName}.KEY_${pref.fieldNameUpperCase}, ${pref.type.defaultValue}); 86 | } 87 | 88 | <#if generateGetLiveData> 89 | <#if pref.comment??> 90 | /** 91 | * ${pref.comment?trim} 92 | */ 93 | <#t> 94 | public LiveData<${pref.type.simpleName}> get${pref.fieldName?cap_first}LiveData() { 95 | return new PreferenceLiveData<${pref.type.simpleName}>(${constantsClassName}.KEY_${pref.fieldNameUpperCase}) { 96 | @Override 97 | public ${pref.type.simpleName} getPreferenceValue() { 98 | return get${pref.fieldName?cap_first}(); 99 | } 100 | }; 101 | } 102 | 103 | 104 | <#if pref.comment??> 105 | /** 106 | * ${pref.comment?trim} 107 | */ 108 | <#t> 109 | public boolean contains${pref.fieldName?cap_first}() { 110 | return contains(${constantsClassName}.KEY_${pref.fieldNameUpperCase}); 111 | } 112 | 113 | <#if pref.comment??> 114 | /** 115 | * ${pref.comment?trim} 116 | */ 117 | <#t> 118 | public ${prefWrapperClassName} put${pref.fieldName?cap_first}(${pref.type.simpleName} ${pref.fieldName}) { 119 | edit().put${pref.fieldName?cap_first}(${pref.fieldName}).apply(); 120 | return this; 121 | } 122 | 123 | <#if pref.comment??> 124 | /** 125 | * ${pref.comment?trim} 126 | */ 127 | <#t> 128 | public ${prefWrapperClassName} set${pref.fieldName?cap_first}(${pref.type.simpleName} ${pref.fieldName}) { 129 | return put${pref.fieldName?cap_first}(${pref.fieldName}); 130 | } 131 | 132 | <#if pref.comment??> 133 | /** 134 | * ${pref.comment?trim} 135 | */ 136 | <#t> 137 | public ${prefWrapperClassName} remove${pref.fieldName?cap_first}() { 138 | edit().remove(${constantsClassName}.KEY_${pref.fieldNameUpperCase}).apply(); 139 | return this; 140 | } 141 | 142 | // endregion 143 | 144 | 145 | <#if generateGetLiveData> 146 | 147 | //================================================================================ 148 | // region PreferenceLiveData 149 | //================================================================================ 150 | 151 | private abstract class PreferenceLiveData extends MutableLiveData { 152 | private final String mKey; 153 | 154 | public PreferenceLiveData(String key) { 155 | mKey = key; 156 | } 157 | 158 | private final OnSharedPreferenceChangeListener mListener = new OnSharedPreferenceChangeListener() { 159 | @Override 160 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 161 | if (mKey.equals(key)) setValue(getPreferenceValue()); 162 | } 163 | }; 164 | 165 | @Override 166 | protected void onActive() { 167 | getWrapped().registerOnSharedPreferenceChangeListener(mListener); 168 | if (!getPreferenceValue().equals(getValue())) setValue(getPreferenceValue()); 169 | } 170 | 171 | @Override 172 | protected void onInactive() { 173 | getWrapped().unregisterOnSharedPreferenceChangeListener(mListener); 174 | } 175 | 176 | public abstract T getPreferenceValue(); 177 | } 178 | 179 | // endregion 180 | <#t> 181 | } -------------------------------------------------------------------------------- /prefs/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /prefs/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | 4 | sourceCompatibility = 1.6 5 | targetCompatibility = 1.6 6 | 7 | group = 'org.jraf' 8 | version = '1.4.0' 9 | 10 | javadoc.failOnError = false 11 | 12 | task sourcesJar(type: Jar, dependsOn: classes) { 13 | classifier = 'sources' 14 | from sourceSets.main.allSource 15 | } 16 | 17 | task javadocJar(type: Jar, dependsOn: javadoc) { 18 | classifier = 'javadoc' 19 | from javadoc.destinationDir 20 | } 21 | 22 | artifacts { 23 | archives sourcesJar 24 | archives javadocJar 25 | } 26 | 27 | dependencies { 28 | compileOnly project(':android-sharedpreferences') 29 | } 30 | 31 | // Use "./gradlew install" to deploy the artifacts to your local maven repository 32 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/DefaultBoolean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.FIELD) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface DefaultBoolean { 34 | boolean value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/DefaultFloat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.FIELD) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface DefaultFloat { 34 | float value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/DefaultInt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.FIELD) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface DefaultInt { 34 | int value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/DefaultLong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.FIELD) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface DefaultLong { 34 | long value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/DefaultString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.FIELD) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface DefaultString { 34 | String value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/DefaultStringSet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.FIELD) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface DefaultStringSet { 34 | String[] value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/EditorWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import android.content.SharedPreferences; 27 | 28 | import java.io.Closeable; 29 | import java.util.Set; 30 | 31 | public class EditorWrapper implements SharedPreferences.Editor, Closeable { 32 | private final SharedPreferences.Editor mWrapped; 33 | 34 | public EditorWrapper(SharedPreferences.Editor wrapped) { 35 | mWrapped = wrapped; 36 | } 37 | 38 | public EditorWrapper putString(String key, String value) { 39 | mWrapped.putString(key, value); 40 | return this; 41 | } 42 | 43 | public EditorWrapper putStringSet(String key, Set values) { 44 | mWrapped.putStringSet(key, values); 45 | return this; 46 | } 47 | 48 | public EditorWrapper putInt(String key, int value) { 49 | mWrapped.putInt(key, value); 50 | return this; 51 | } 52 | 53 | public EditorWrapper putLong(String key, long value) { 54 | mWrapped.putLong(key, value); 55 | return this; 56 | } 57 | 58 | public EditorWrapper putFloat(String key, float value) { 59 | mWrapped.putFloat(key, value); 60 | return this; 61 | } 62 | 63 | public EditorWrapper putBoolean(String key, boolean value) { 64 | mWrapped.putBoolean(key, value); 65 | return this; 66 | } 67 | 68 | public EditorWrapper remove(String key) { 69 | mWrapped.remove(key); 70 | return this; 71 | } 72 | 73 | public EditorWrapper clear() { 74 | mWrapped.clear(); 75 | return this; 76 | } 77 | 78 | public boolean commit() { 79 | return mWrapped.commit(); 80 | } 81 | 82 | public void apply() { 83 | mWrapped.apply(); 84 | } 85 | 86 | @Override 87 | public void close() { 88 | commit(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/Mode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.TYPE) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface Mode { 34 | int value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/Name.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target({ElementType.TYPE, ElementType.FIELD}) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface Name { 34 | String value(); 35 | } 36 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/Prefs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import java.lang.annotation.ElementType; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | @Target(ElementType.TYPE) 32 | @Retention(RetentionPolicy.SOURCE) 33 | public @interface Prefs { 34 | /** 35 | * Desired preferences file name.
36 | * {@link #value()} and {@link #fileName()} are synonyms. 37 | * 38 | * @see android.content.Context#getSharedPreferences(java.lang.String, int) 39 | */ 40 | String value() default ""; 41 | 42 | /** 43 | * Desired preferences file name.
44 | * {@link #value()} and {@link #fileName()} are synonyms. 45 | * 46 | * @see android.content.Context#getSharedPreferences(java.lang.String, int) 47 | */ 48 | String fileName() default ""; 49 | 50 | /** 51 | * Operating mode (should be {@link android.content.Context#MODE_PRIVATE}, 52 | * {@link android.content.Context#MODE_WORLD_READABLE}, 53 | * {@link android.content.Context#MODE_WORLD_WRITEABLE}, 54 | * or {@link android.content.Context#MODE_MULTI_PROCESS}.
55 | *
56 | * This must only be set if {@link #fileName()} (or {@link #value()}) is also set 57 | * 58 | * @see android.content.Context#getSharedPreferences(java.lang.String, int) 59 | */ 60 | int fileMode() default -1; 61 | 62 | /** 63 | * Normally, {@code @Nullable} annotations are included in the generated code where appropriate. 64 | * This behavior can be disabled by setting this to {@code true}. 65 | * This is useful if your project does not use the support library. 66 | */ 67 | boolean disableNullable() default false; 68 | 69 | /** 70 | * Whether to generate observe methods. 71 | * The default value if {@code true} as this adds a dependency to the architecture components. 72 | */ 73 | boolean generateGetLiveData() default false; 74 | 75 | /** 76 | * Whether to use androidx package for {@code @Nullable} and {@code LiveData}. 77 | * The default value if {@code false}. 78 | */ 79 | boolean useAndroidX() default false; 80 | } 81 | -------------------------------------------------------------------------------- /prefs/src/main/java/org/jraf/android/prefs/SharedPreferencesWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs; 25 | 26 | import android.content.SharedPreferences; 27 | 28 | import java.util.Map; 29 | import java.util.Set; 30 | 31 | /** 32 | * Wrapper for {@link SharedPreferences}. 33 | */ 34 | public class SharedPreferencesWrapper implements SharedPreferences { 35 | private final SharedPreferences mWrapped; 36 | 37 | public SharedPreferencesWrapper(SharedPreferences wrapped) { 38 | mWrapped = wrapped; 39 | } 40 | 41 | public SharedPreferences getWrapped() { 42 | return mWrapped; 43 | } 44 | 45 | public Map getAll() { 46 | return mWrapped.getAll(); 47 | } 48 | 49 | public String getString(String key, String defValue) { 50 | return mWrapped.getString(key, defValue); 51 | } 52 | 53 | public Set getStringSet(String key, Set defValues) { 54 | return mWrapped.getStringSet(key, defValues); 55 | } 56 | 57 | public int getInt(String key, int defValue) { 58 | return mWrapped.getInt(key, defValue); 59 | } 60 | 61 | public long getLong(String key, long defValue) { 62 | return mWrapped.getLong(key, defValue); 63 | } 64 | 65 | public float getFloat(String key, float defValue) { 66 | return mWrapped.getFloat(key, defValue); 67 | } 68 | 69 | public boolean getBoolean(String key, boolean defValue) { 70 | return mWrapped.getBoolean(key, defValue); 71 | } 72 | 73 | public boolean contains(String key) { 74 | return mWrapped.contains(key); 75 | } 76 | 77 | public SharedPreferences.Editor edit() { 78 | return mWrapped.edit(); 79 | } 80 | 81 | public void registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { 82 | mWrapped.registerOnSharedPreferenceChangeListener(listener); 83 | } 84 | 85 | public void unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { 86 | mWrapped.unregisterOnSharedPreferenceChangeListener(listener); 87 | } 88 | 89 | /** 90 | * Remove all values from the preferences. 91 | */ 92 | public void clear() { 93 | edit().clear().apply(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-kapt' 4 | 5 | android { 6 | compileSdkVersion 28 7 | 8 | defaultConfig { 9 | applicationId 'org.jraf.android.prefs.sample' 10 | minSdkVersion 14 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName '1.4.0' 14 | } 15 | 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | sourceSets { 24 | main.java.srcDirs += 'src/main/kotlin' 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.10' 30 | implementation 'androidx.appcompat:appcompat:1.0.0' 31 | implementation 'androidx.annotation:annotation:1.0.0' 32 | implementation 'androidx.lifecycle:lifecycle-livedata:2.0.0' 33 | 34 | kapt project(':prefs-compiler') 35 | implementation project(':prefs') 36 | } 37 | 38 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/bod/Dev/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/kotlin/org/jraf/android/prefs/sample/app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs.sample.app 25 | 26 | import android.os.Bundle 27 | import android.util.Log 28 | import androidx.appcompat.app.AppCompatActivity 29 | import androidx.lifecycle.Observer 30 | import org.jraf.android.prefs.sample.R 31 | import org.jraf.android.prefs.sample.prefs.MainPrefs 32 | import org.jraf.android.prefs.sample.prefs.SettingsPrefs 33 | import java.util.* 34 | 35 | class MainActivity : AppCompatActivity() { 36 | 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | setContentView(R.layout.main) 40 | 41 | val mainPrefs = MainPrefs.get(this) 42 | 43 | mainPrefs.loginLiveData.observe(this, Observer { 44 | Log.d(TAG, "observed login=$it") 45 | }) 46 | 47 | mainPrefs.edit().use { 48 | it.setLogin("john ${Date()}") 49 | it.setPassword("p4Ssw0Rd") 50 | } 51 | 52 | mainPrefs.age = null 53 | 54 | with(mainPrefs) { 55 | Log.d(TAG, "login=$login") 56 | Log.d(TAG, "age=$age") 57 | Log.d(TAG, "premium=$premium") 58 | Log.d(TAG, "mainPrefs=$all") 59 | } 60 | 61 | val settingsPrefs = SettingsPrefs.get(this) 62 | settingsPrefs.preferredColor = 0xFFFFFF 63 | with(settingsPrefs) { 64 | Log.d(TAG, "preferredColor=$preferredColor") 65 | Log.d(TAG, "settingsPrefs=$all") 66 | } 67 | } 68 | 69 | companion object { 70 | private val TAG = MainActivity::class.java.name 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /sample/src/main/kotlin/org/jraf/android/prefs/sample/prefs/Main.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs.sample.prefs 25 | 26 | import org.jraf.android.prefs.DefaultBoolean 27 | import org.jraf.android.prefs.Name 28 | import org.jraf.android.prefs.Prefs 29 | 30 | /** 31 | * The main preferences of the app. 32 | */ 33 | @Prefs( 34 | generateGetLiveData = true, 35 | useAndroidX = true 36 | ) 37 | class Main { 38 | 39 | /** 40 | * User login. 41 | * 42 | * This is the main way to identify the user. 43 | */ 44 | @Name(PREF_LOGIN) 45 | var login: String? = null 46 | 47 | /** 48 | * User password. 49 | */ 50 | var password: String? = null 51 | 52 | @DefaultBoolean(false) 53 | var premium: Boolean? = null 54 | 55 | @Name(PREF_AGE) 56 | var age: Int? = null 57 | 58 | 59 | companion object { 60 | private const val PREF_LOGIN = "PREF_LOGIN" 61 | private const val PREF_AGE = "PREF_AGE" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /sample/src/main/kotlin/org/jraf/android/prefs/sample/prefs/Settings.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This source is part of the 3 | * _____ ___ ____ 4 | * __ / / _ \/ _ | / __/___ _______ _ 5 | * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ 6 | * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / 7 | * /___/ 8 | * repository. 9 | * 10 | * Copyright (C) 2015-present Benoit 'BoD' Lubek (BoD@JRAF.org) 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | package org.jraf.android.prefs.sample.prefs 25 | 26 | import android.content.Context 27 | import org.jraf.android.prefs.DefaultInt 28 | import org.jraf.android.prefs.DefaultStringSet 29 | import org.jraf.android.prefs.Prefs 30 | 31 | /** 32 | * Other settings useful for the app. 33 | */ 34 | @Prefs( 35 | fileName = "settings", 36 | fileMode = Context.MODE_PRIVATE, 37 | useAndroidX = true 38 | ) 39 | class Settings { 40 | @DefaultInt(-0x44ff23) 41 | var preferredColor: Int? = null 42 | 43 | /** 44 | * The week days that the user prefers. 45 | */ 46 | @DefaultStringSet("Friday", "Saturday") 47 | var weekDays: Set? = null 48 | } 49 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BoD/android-prefs/4587bac2807a845ec0cd8944578997ef49a96ce9/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Prefs sample app 3 | 4 | 5 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':sample', ':prefs-compiler', ':prefs', ':android-sharedpreferences' 2 | --------------------------------------------------------------------------------