├── .github
├── FUNDING.yml
└── workflows
│ └── android.yml
├── .gitignore
├── AndroidResourceExtensions
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── net
│ │ └── kibotu
│ │ └── resourceextension
│ │ ├── ManifestPermission.kt
│ │ └── Resource+Extensions.kt
│ └── res
│ ├── values-ldltr
│ └── ltr-config.xml
│ ├── values-ldrtl
│ └── rtl-config.xml
│ └── values
│ ├── colors.xml
│ └── ltr-config.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── my_text.json
│ ├── java
│ └── net
│ │ └── kibotu
│ │ └── resourceextensions
│ │ └── demo
│ │ └── MainActivity.kt
│ └── res
│ ├── anim
│ ├── grow.xml
│ └── layout_animation.xml
│ ├── animator
│ └── flip_animation.xml
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── ic_share.xml
│ ├── font
│ └── lato.ttf
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── raw
│ └── my_raw.json
│ ├── values-de
│ └── localized.xml
│ ├── values
│ ├── colors.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── values.xml
│ └── xml
│ └── lorem_ipsum.xml
├── build.gradle
├── dependencies.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
├── proguard-debug.pro
├── proguard-release.pro
└── settings.gradle
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: https://paypal.me/janrabe/5
2 |
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | tags: [ "*" ]
7 | pull_request:
8 | branches: [ "master" ]
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 | - name: set up JDK 17
17 | uses: actions/setup-java@v4
18 | with:
19 | java-version: '17'
20 | distribution: 'temurin'
21 | cache: gradle
22 |
23 | - name: Grant execute permission for gradlew
24 | run: chmod +x gradlew
25 | - name: Build with Gradle
26 | run: ./gradlew build --refresh-dependencies --s
27 |
28 | publish:
29 | needs: build # Ensures that the 'publish' job runs after the 'build' job is successful
30 | if: startsWith(github.ref, 'refs/tags/') # Ensure this job only runs for tags
31 | runs-on: ubuntu-latest
32 | env:
33 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USER_NAME }}
34 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
35 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_IN_MEMORY_KEY }}
36 | ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_IN_MEMORY_KEY_ID }}
37 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_IN_MEMORY_KEY_PASSWORD }}
38 | steps:
39 | - uses: actions/checkout@v4
40 | - name: Extract version from tag
41 | id: extract_version
42 | run: |
43 | TAG_NAME=${GITHUB_REF#refs/tags/}
44 | if [[ $TAG_NAME =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
45 | echo "SEMVER_TAG=$TAG_NAME" >> $GITHUB_STATE
46 | else
47 | echo "Not a semver tag. Exiting..."
48 | exit 1 # Exit if it is not a semver tag.
49 | fi
50 |
51 | - name: Set up Maven Central Repository
52 | uses: actions/setup-java@v4
53 | with:
54 | java-version: '17'
55 | distribution: 'temurin'
56 | - name: Publish package to Maven Central Repository
57 | run: ./gradlew publishToMavenCentral --no-configuration-cache --s -Pversion=$GITHUB_REF_NAME
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bintray.properties
2 |
3 | # Created by https://www.gitignore.io/api/macos,gradle,windows,android,jetbrains,androidstudio
4 |
5 | ### Android ###
6 | # Built application files
7 | *.apk
8 | *.ap_
9 |
10 | # Files for the ART/Dalvik VM
11 | *.dex
12 |
13 | # Java class files
14 | *.class
15 |
16 | # Generated files
17 | bin/
18 | gen/
19 | out/
20 |
21 | # Gradle files
22 | .gradle/
23 | build/
24 |
25 | # Local configuration file (sdk path, etc)
26 | local.properties
27 |
28 | # Proguard folder generated by Eclipse
29 | proguard/
30 |
31 | # Log Files
32 | *.log
33 |
34 | # Android Studio Navigation editor temp files
35 | .navigation/
36 |
37 | # Android Studio captures folder
38 | captures/
39 |
40 | # Intellij
41 | *.iml
42 | .idea/workspace.xml
43 | .idea/tasks.xml
44 | .idea/gradle.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 |
48 | # External native build folder generated in Android Studio 2.2 and later
49 | .externalNativeBuild
50 |
51 | # Freeline
52 | freeline.py
53 | freeline/
54 | freeline_project_description.json
55 |
56 | ### Android Patch ###
57 | gen-external-apklibs
58 |
59 | ### AndroidStudio ###
60 | # Covers files to be ignored for android development using Android Studio.
61 |
62 | # Built application files
63 |
64 | # Files for the ART/Dalvik VM
65 |
66 | # Java class files
67 |
68 | # Generated files
69 |
70 | # Gradle files
71 | .gradle
72 |
73 | # Signing files
74 | .signing/
75 |
76 | # Local configuration file (sdk path, etc)
77 |
78 | # Proguard folder generated by Eclipse
79 |
80 | # Log Files
81 |
82 | # Android Studio
83 | /*/build/
84 | /*/local.properties
85 | /*/out
86 | /*/*/build
87 | /*/*/production
88 | *.ipr
89 | *~
90 | *.swp
91 |
92 | # Android Patch
93 |
94 | # External native build folder generated in Android Studio 2.2 and later
95 |
96 | # NDK
97 | obj/
98 |
99 | # IntelliJ IDEA
100 | *.iws
101 | /out/
102 |
103 | # User-specific configurations
104 | .idea/libraries/
105 | .idea/.name
106 | .idea/compiler.xml
107 | .idea/copyright/profiles_settings.xml
108 | .idea/encodings.xml
109 | .idea/misc.xml
110 | .idea/modules.xml
111 | .idea/scopes/scope_settings.xml
112 | .idea/vcs.xml
113 | .idea/jsLibraryMappings.xml
114 | .idea/datasources.xml
115 | .idea/dataSources.ids
116 | .idea/sqlDataSources.xml
117 | .idea/dynamic.xml
118 | .idea/uiDesigner.xml
119 |
120 | # OS-specific files
121 | .DS_Store
122 | .DS_Store?
123 | ._*
124 | .Spotlight-V100
125 | .Trashes
126 | ehthumbs.db
127 | Thumbs.db
128 |
129 | # Legacy Eclipse project files
130 | .classpath
131 | .project
132 |
133 | # Mobile Tools for Java (J2ME)
134 | .mtj.tmp/
135 |
136 | # Package Files #
137 | *.war
138 | *.ear
139 |
140 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
141 | hs_err_pid*
142 |
143 | ## Plugin-specific files:
144 |
145 | # mpeltonen/sbt-idea plugin
146 | .idea_modules/
147 |
148 | # JIRA plugin
149 | atlassian-ide-plugin.xml
150 |
151 | # Mongo Explorer plugin
152 | .idea/mongoSettings.xml
153 |
154 | # Crashlytics plugin (for Android Studio and IntelliJ)
155 | com_crashlytics_export_strings.xml
156 | crashlytics.properties
157 | crashlytics-build.properties
158 | fabric.properties
159 |
160 | ### AndroidStudio Patch ###
161 |
162 | !/gradle/wrapper/gradle-wrapper.jar
163 |
164 | ### JetBrains ###
165 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
166 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
167 |
168 | # User-specific stuff:
169 | .idea/**/workspace.xml
170 | .idea/**/tasks.xml
171 |
172 | # Sensitive or high-churn files:
173 | .idea/**/dataSources/
174 | .idea/**/dataSources.ids
175 | .idea/**/dataSources.xml
176 | .idea/**/dataSources.local.xml
177 | .idea/**/sqlDataSources.xml
178 | .idea/**/dynamic.xml
179 | .idea/**/uiDesigner.xml
180 |
181 | # Gradle:
182 | .idea/**/gradle.xml
183 | .idea/**/libraries
184 |
185 | # CMake
186 | cmake-build-debug/
187 |
188 | # Mongo Explorer plugin:
189 | .idea/**/mongoSettings.xml
190 |
191 | ## File-based project format:
192 |
193 | ## Plugin-specific files:
194 |
195 | # IntelliJ
196 |
197 | # mpeltonen/sbt-idea plugin
198 |
199 | # JIRA plugin
200 |
201 | # Cursive Clojure plugin
202 | .idea/replstate.xml
203 |
204 | # Ruby plugin and RubyMine
205 | /.rakeTasks
206 |
207 | # Crashlytics plugin (for Android Studio and IntelliJ)
208 |
209 | ### JetBrains Patch ###
210 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
211 |
212 | # *.iml
213 | # modules.xml
214 | # .idea/misc.xml
215 | # *.ipr
216 |
217 | # Sonarlint plugin
218 | .idea/sonarlint
219 |
220 | ### macOS ###
221 | *.DS_Store
222 | .AppleDouble
223 | .LSOverride
224 |
225 | # Icon must end with two \r
226 | Icon
227 |
228 | # Thumbnails
229 |
230 | # Files that might appear in the root of a volume
231 | .DocumentRevisions-V100
232 | .fseventsd
233 | .TemporaryItems
234 | .VolumeIcon.icns
235 | .com.apple.timemachine.donotpresent
236 |
237 | # Directories potentially created on remote AFP share
238 | .AppleDB
239 | .AppleDesktop
240 | Network Trash Folder
241 | Temporary Items
242 | .apdisk
243 |
244 | ### Windows ###
245 | # Windows thumbnail cache files
246 | ehthumbs_vista.db
247 |
248 | # Folder config file
249 | Desktop.ini
250 |
251 | # Recycle Bin used on file shares
252 | $RECYCLE.BIN/
253 |
254 | # Windows Installer files
255 | *.cab
256 | *.msi
257 | *.msm
258 | *.msp
259 |
260 | # Windows shortcuts
261 | *.lnk
262 |
263 | ### Gradle ###
264 | **/build/
265 |
266 | # Ignore Gradle GUI config
267 | gradle-app.setting
268 |
269 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
270 | !gradle-wrapper.jar
271 |
272 | # Cache of project
273 | .gradletasknamecache
274 |
275 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
276 | # gradle/wrapper/gradle-wrapper.properties
277 |
278 | # End of https://www.gitignore.io/api/macos,gradle,windows,android,jetbrains,androidstudio
279 |
280 | .idea/
--------------------------------------------------------------------------------
/AndroidResourceExtensions/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | namespace "net.kibotu.resourceextension"
6 | compileSdk compileSdkVer
7 | buildToolsVersion = buildToolsVer
8 |
9 | defaultConfig {
10 | minSdk minSdkVer
11 | targetSdk targetSdkVer
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | consumerProguardFiles 'consumer-rules.pro'
15 | }
16 |
17 | buildTypes {
18 | debug {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', '../proguard-debug.pro'
21 | }
22 | release {
23 | minifyEnabled false
24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', '../proguard-release.pro'
25 | }
26 | }
27 |
28 | // region java compile options
29 |
30 | java {
31 | toolchain {
32 | languageVersion.set(JavaLanguageVersion.of(17))
33 | }
34 | }
35 |
36 | compileOptions {
37 | sourceCompatibility JavaVersion.VERSION_17
38 | targetCompatibility JavaVersion.VERSION_17
39 | }
40 |
41 | // endregion
42 |
43 | // region kotlin compile options
44 |
45 | kotlinOptions {
46 | jvmTarget = "17"
47 | allWarningsAsErrors = false
48 | kotlinOptions.verbose = true
49 | freeCompilerArgs += [
50 | "-Xjvm-default=all-compatibility"
51 | ]
52 | }
53 |
54 | // endregion
55 |
56 | // region exclude duplicated meta inf files
57 |
58 | packagingOptions {
59 | // DebugProbesKt.bin is used for java debugging (not needed for android)
60 | // Hint: https://github.com/Kotlin/kotlinx.coroutines/issues/2274
61 | exclude 'DebugProbesKt.bin'
62 |
63 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
64 | // https://stackoverflow.com/a/61893957/1006741
65 | excludes -= "/META-INF/*.kotlin_module"
66 | }
67 |
68 | // endregion
69 | }
70 |
71 | dependencies {
72 | coreLibraryDesugaring desugaring.jdk
73 | implementation libs.supportAppCompat
74 | implementation libs.applicationProvider
75 | }
76 |
77 | if (!isJitpack) {
78 | apply plugin: 'com.vanniktech.maven.publish'
79 | mavenPublishing {
80 | publishToMavenCentral(com.vanniktech.maven.publish.SonatypeHost.CENTRAL_PORTAL, true)
81 | signAllPublications()
82 | }
83 | }
84 |
85 | if (isJitpack) {
86 | apply plugin: 'maven-publish'
87 | afterEvaluate {
88 | publishing {
89 | publications {
90 | release(MavenPublication) {
91 | from components.release
92 | groupId = GROUP
93 | artifactId = POM_ARTIFACT_ID
94 | version = version
95 | }
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kibotu/AndroidResourceExtensions/640539e70ac5c92d98a5951cec4ce0a86f3793b1/AndroidResourceExtensions/consumer-rules.pro
--------------------------------------------------------------------------------
/AndroidResourceExtensions/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/src/main/java/net/kibotu/resourceextension/ManifestPermission.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("DEPRECATION")
2 |
3 | /**
4 | * Created by [Jan Rabe](https://kibotu.net/).
5 | */
6 |
7 | package net.kibotu.resourceextension
8 |
9 | import android.Manifest
10 | import android.Manifest.permission.*
11 | import android.annotation.TargetApi
12 | import android.content.pm.PackageManager
13 | import android.os.Build
14 | import androidx.annotation.StringDef
15 | import androidx.core.app.ActivityCompat
16 |
17 |
18 | @TargetApi(Build.VERSION_CODES.TIRAMISU)
19 | @StringDef(
20 | value = [
21 | ACCEPT_HANDOVER,
22 | ACCESS_BACKGROUND_LOCATION,
23 | ACCESS_BLOBS_ACROSS_USERS,
24 | ACCESS_CHECKIN_PROPERTIES,
25 | ACCESS_COARSE_LOCATION,
26 | ACCESS_FINE_LOCATION,
27 | ACCESS_LOCATION_EXTRA_COMMANDS,
28 | ACCESS_MEDIA_LOCATION,
29 | ACCESS_NETWORK_STATE,
30 | ACCESS_NOTIFICATION_POLICY,
31 | ACCESS_WIFI_STATE,
32 | ACCOUNT_MANAGER,
33 | ACTIVITY_RECOGNITION,
34 | ADD_VOICEMAIL,
35 | ANSWER_PHONE_CALLS,
36 | BATTERY_STATS,
37 | BIND_ACCESSIBILITY_SERVICE,
38 | BIND_APPWIDGET,
39 | BIND_AUTOFILL_SERVICE,
40 | BIND_CALL_REDIRECTION_SERVICE,
41 | BIND_CARRIER_MESSAGING_CLIENT_SERVICE,
42 | BIND_CARRIER_MESSAGING_SERVICE,
43 | BIND_CARRIER_SERVICES,
44 | BIND_CHOOSER_TARGET_SERVICE,
45 | BIND_COMPANION_DEVICE_SERVICE,
46 | BIND_CONDITION_PROVIDER_SERVICE,
47 | BIND_CONTROLS,
48 | BIND_DEVICE_ADMIN,
49 | BIND_DREAM_SERVICE,
50 | BIND_INCALL_SERVICE,
51 | BIND_INPUT_METHOD,
52 | BIND_MIDI_DEVICE_SERVICE,
53 | BIND_NFC_SERVICE,
54 | BIND_NOTIFICATION_LISTENER_SERVICE,
55 | BIND_PRINT_SERVICE,
56 | BIND_QUICK_ACCESS_WALLET_SERVICE,
57 | BIND_QUICK_SETTINGS_TILE,
58 | BIND_REMOTEVIEWS,
59 | BIND_SCREENING_SERVICE,
60 | BIND_TELECOM_CONNECTION_SERVICE,
61 | BIND_TEXT_SERVICE,
62 | BIND_TV_INPUT,
63 | BIND_VISUAL_VOICEMAIL_SERVICE,
64 | BIND_VOICE_INTERACTION,
65 | BIND_VPN_SERVICE,
66 | BIND_VR_LISTENER_SERVICE,
67 | BIND_WALLPAPER,
68 | BLUETOOTH,
69 | BLUETOOTH_ADMIN,
70 | BLUETOOTH_ADVERTISE,
71 | BLUETOOTH_CONNECT,
72 | BLUETOOTH_PRIVILEGED,
73 | BLUETOOTH_SCAN,
74 | BODY_SENSORS,
75 | BROADCAST_PACKAGE_REMOVED,
76 | BROADCAST_SMS,
77 | BROADCAST_STICKY,
78 | BROADCAST_WAP_PUSH,
79 | CALL_COMPANION_APP,
80 | CALL_PHONE,
81 | CALL_PRIVILEGED,
82 | CAMERA,
83 | CAPTURE_AUDIO_OUTPUT,
84 | CHANGE_COMPONENT_ENABLED_STATE,
85 | CHANGE_CONFIGURATION,
86 | CHANGE_NETWORK_STATE,
87 | CHANGE_WIFI_MULTICAST_STATE,
88 | CHANGE_WIFI_STATE,
89 | CLEAR_APP_CACHE,
90 | CONTROL_LOCATION_UPDATES,
91 | DELETE_CACHE_FILES,
92 | DELETE_PACKAGES,
93 | DIAGNOSTIC,
94 | DISABLE_KEYGUARD,
95 | DUMP,
96 | EXPAND_STATUS_BAR,
97 | FACTORY_TEST,
98 | FOREGROUND_SERVICE,
99 | GET_ACCOUNTS,
100 | GET_ACCOUNTS_PRIVILEGED,
101 | GET_PACKAGE_SIZE,
102 | GET_TASKS,
103 | GLOBAL_SEARCH,
104 | HIDE_OVERLAY_WINDOWS,
105 | HIGH_SAMPLING_RATE_SENSORS,
106 | INSTALL_LOCATION_PROVIDER,
107 | INSTALL_PACKAGES,
108 | INSTALL_SHORTCUT,
109 | INSTANT_APP_FOREGROUND_SERVICE,
110 | INTERACT_ACROSS_PROFILES,
111 | INTERNET,
112 | KILL_BACKGROUND_PROCESSES,
113 | LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK,
114 | LOADER_USAGE_STATS,
115 | LOCATION_HARDWARE,
116 | MANAGE_DOCUMENTS,
117 | MANAGE_EXTERNAL_STORAGE,
118 | MANAGE_MEDIA,
119 | MANAGE_ONGOING_CALLS,
120 | MANAGE_OWN_CALLS,
121 | MASTER_CLEAR,
122 | MEDIA_CONTENT_CONTROL,
123 | MODIFY_AUDIO_SETTINGS,
124 | MODIFY_PHONE_STATE,
125 | MOUNT_FORMAT_FILESYSTEMS,
126 | MOUNT_UNMOUNT_FILESYSTEMS,
127 | NFC,
128 | NFC_PREFERRED_PAYMENT_INFO,
129 | NFC_TRANSACTION_EVENT,
130 | PACKAGE_USAGE_STATS,
131 | PERSISTENT_ACTIVITY,
132 | PROCESS_OUTGOING_CALLS,
133 | QUERY_ALL_PACKAGES,
134 | READ_CALENDAR,
135 | READ_CALL_LOG,
136 | READ_CONTACTS,
137 | READ_EXTERNAL_STORAGE,
138 | READ_INPUT_STATE,
139 | READ_LOGS,
140 | READ_PHONE_NUMBERS,
141 | READ_PHONE_STATE,
142 | READ_PRECISE_PHONE_STATE,
143 | READ_SMS,
144 | READ_SYNC_SETTINGS,
145 | READ_SYNC_STATS,
146 | READ_VOICEMAIL,
147 | REBOOT,
148 | RECEIVE_BOOT_COMPLETED,
149 | RECEIVE_MMS,
150 | RECEIVE_SMS,
151 | RECEIVE_WAP_PUSH,
152 | RECORD_AUDIO,
153 | REORDER_TASKS,
154 | REQUEST_COMPANION_PROFILE_WATCH,
155 | REQUEST_COMPANION_RUN_IN_BACKGROUND,
156 | REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND,
157 | REQUEST_COMPANION_USE_DATA_IN_BACKGROUND,
158 | REQUEST_DELETE_PACKAGES,
159 | REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
160 | REQUEST_INSTALL_PACKAGES,
161 | REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE,
162 | REQUEST_PASSWORD_COMPLEXITY,
163 | RESTART_PACKAGES,
164 | SCHEDULE_EXACT_ALARM,
165 | SEND_RESPOND_VIA_MESSAGE,
166 | SEND_SMS,
167 | SET_ALARM,
168 | SET_ALWAYS_FINISH,
169 | SET_ANIMATION_SCALE,
170 | SET_DEBUG_APP,
171 | SET_PREFERRED_APPLICATIONS,
172 | SET_PROCESS_LIMIT,
173 | SET_TIME,
174 | SET_TIME_ZONE,
175 | SET_WALLPAPER,
176 | SET_WALLPAPER_HINTS,
177 | SIGNAL_PERSISTENT_PROCESSES,
178 | SMS_FINANCIAL_TRANSACTIONS,
179 | START_FOREGROUND_SERVICES_FROM_BACKGROUND,
180 | START_VIEW_PERMISSION_USAGE,
181 | STATUS_BAR,
182 | SYSTEM_ALERT_WINDOW,
183 | TRANSMIT_IR,
184 | UNINSTALL_SHORTCUT,
185 | UPDATE_DEVICE_STATS,
186 | UPDATE_PACKAGES_WITHOUT_USER_ACTION,
187 | USE_BIOMETRIC,
188 | USE_FINGERPRINT,
189 | USE_FULL_SCREEN_INTENT,
190 | USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
191 | USE_SIP,
192 | UWB_RANGING,
193 | VIBRATE,
194 | WAKE_LOCK,
195 | WRITE_APN_SETTINGS,
196 | WRITE_CALENDAR,
197 | WRITE_CALL_LOG,
198 | WRITE_CONTACTS,
199 | WRITE_EXTERNAL_STORAGE,
200 | WRITE_GSERVICES,
201 | WRITE_SECURE_SETTINGS,
202 | WRITE_SETTINGS,
203 | WRITE_SYNC_SETTINGS,
204 | WRITE_VOICEMAIL,
205 | ]
206 | )
207 | @Retention(AnnotationRetention.SOURCE)
208 | @Target(
209 | allowedTargets = [AnnotationTarget.TYPE_PARAMETER,
210 | AnnotationTarget.PROPERTY,
211 | AnnotationTarget.FIELD,
212 | AnnotationTarget.LOCAL_VARIABLE,
213 | AnnotationTarget.VALUE_PARAMETER,
214 | AnnotationTarget.PROPERTY_GETTER,
215 | AnnotationTarget.PROPERTY_SETTER
216 | ]
217 | )
218 | annotation class Permission
219 |
220 | @JvmInline
221 | value class ManifestPermission(@Permission val permission: String)
222 |
223 | /**
224 | * [Manifest.permission]
225 | */
226 | val ManifestPermission.isGranted: Boolean
227 | get() {
228 | return ActivityCompat.checkSelfPermission(
229 | context,
230 | this.permission
231 | ) == PackageManager.PERMISSION_GRANTED
232 | }
233 |
234 | /**
235 | * [Manifest.permission]
236 | */
237 | val String.isGranted: Boolean
238 | get() = ManifestPermission(this).isGranted
239 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/src/main/java/net/kibotu/resourceextension/Resource+Extensions.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("ResourceExtensions")
2 |
3 | package net.kibotu.resourceextension
4 |
5 |
6 | import android.animation.Animator
7 | import android.animation.AnimatorInflater
8 | import android.annotation.SuppressLint
9 | import android.content.Context
10 | import android.content.ContextWrapper
11 | import android.content.res.ColorStateList
12 | import android.content.res.Configuration
13 | import android.content.res.Resources
14 | import android.content.res.XmlResourceParser
15 | import android.graphics.Typeface
16 | import android.graphics.drawable.ColorDrawable
17 | import android.graphics.drawable.Drawable
18 | import android.graphics.drawable.GradientDrawable
19 | import android.net.Uri
20 | import android.os.Build
21 | import android.os.Build.VERSION.SDK_INT
22 | import android.os.Build.VERSION_CODES.JELLY_BEAN_MR1
23 | import android.os.Build.VERSION_CODES.N
24 | import android.text.Html
25 | import android.text.Spanned
26 | import android.transition.Transition
27 | import android.transition.TransitionInflater
28 | import android.util.TypedValue
29 | import android.view.LayoutInflater
30 | import android.view.View
31 | import android.view.ViewGroup
32 | import android.view.ViewParent
33 | import android.view.animation.Animation
34 | import android.view.animation.AnimationUtils
35 | import android.view.animation.Interpolator
36 | import android.view.animation.LayoutAnimationController
37 | import android.widget.TextView
38 | import androidx.annotation.*
39 | import androidx.core.content.ContextCompat
40 | import androidx.core.content.res.ResourcesCompat
41 | import androidx.core.content.res.use
42 | import com.github.florent37.application.provider.ActivityProvider.currentActivity
43 | import com.github.florent37.application.provider.application
44 | import java.io.ByteArrayOutputStream
45 | import java.io.InputStream
46 | import java.util.*
47 |
48 |
49 | /**
50 | * Created by [Jan Rabe](https://kibotu.net/).
51 | */
52 |
53 | internal inline val context: ContextWrapper
54 | get() = currentActivity ?: requireNotNull(application)
55 |
56 | // region Values
57 |
58 | val @receiver:BoolRes Int.resBoolean: Boolean
59 | get() = context.resources.getBoolean(this)
60 |
61 |
62 | val @receiver:IntegerRes Int.resInt: Int
63 | get() = context.resources.getInteger(this)
64 |
65 | val @receiver:IntegerRes Int.resLong: Long
66 | get() = this.resInt.toLong()
67 |
68 | val @receiver:StringRes Int.resString: String
69 | get() = context.resources.getString(this)
70 |
71 | inline fun @receiver:StringRes Int.resString(vararg formatArgs: T): String {
72 | val context: ContextWrapper = currentActivity ?: requireNotNull(application)
73 | return context.resources.getString(this, *formatArgs)
74 | }
75 |
76 | /**
77 | * https://stackoverflow.com/a/9475663/1006741
78 | *
79 | * @param id string resource id
80 | * @param locale locale
81 | * @return localized string
82 | */
83 | fun @receiver:StringRes Int.localizedString(locale: Locale = Locale.UK): String {
84 |
85 | if (SDK_INT > JELLY_BEAN_MR1) {
86 | return localizedResources(context, locale).getString(this)
87 | }
88 |
89 | val res = context.resources
90 | val conf = res.configuration
91 | val savedLocale = conf.locale
92 | conf.locale = locale // whatever you want here
93 | res.updateConfiguration(conf, null) // second arg null means don't change
94 |
95 | // retrieve resources from desired locale
96 | val text = res.getString(this)
97 |
98 | // restore original locale
99 | conf.locale = savedLocale
100 | res.updateConfiguration(conf, null)
101 |
102 | return text
103 | }
104 |
105 | fun @receiver:PluralsRes Int.quantityString(amount: Int): String =
106 | context.resources.getQuantityString(this, amount)
107 |
108 | inline fun @receiver:PluralsRes Int.quantityString(
109 | amount: Int,
110 | vararg formatArgs: T
111 | ): String {
112 | val context: ContextWrapper = currentActivity ?: requireNotNull(application)
113 | return context.resources.getQuantityString(this, amount, *formatArgs)
114 | }
115 |
116 | @RequiresApi(api = JELLY_BEAN_MR1)
117 | fun localizedResources(
118 | ctx: Context = context,
119 | desiredLocale: Locale = Locale.UK
120 | ): Resources {
121 | var conf = ctx.resources.configuration
122 | conf = Configuration(conf)
123 | conf.setLocale(desiredLocale)
124 | val localizedContext = ctx.createConfigurationContext(conf)
125 | return localizedContext.resources
126 | }
127 |
128 | val @receiver:ColorRes Int.resColorStateList: ColorStateList?
129 | get() = ContextCompat.getColorStateList(context, this)
130 |
131 | @get:ColorInt
132 | val @receiver:ColorRes Int.resColor: Int
133 | get() = ContextCompat.getColor(context, this)
134 |
135 | @get:ColorLong
136 | val @receiver:ColorRes Int.resColorLong: Long
137 | get() = ContextCompat.getColor(context, this).toLong()
138 |
139 | @get:Dimension
140 | val @receiver:DimenRes Int.resDimension: Float
141 | get() = context.resources.getDimension(this)
142 |
143 | fun @receiver:FractionRes Int.resFraction(base: Int, pbase: Int): Float =
144 | context.resources.getFraction(this, base, pbase)
145 |
146 | val @receiver:StringRes Int.html: Spanned
147 | get() = resString.html
148 |
149 | val String.html: Spanned
150 | get() = if (SDK_INT >= N) {
151 | Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
152 | } else {
153 | @Suppress("DEPRECATION")
154 | Html.fromHtml(this)
155 | }
156 |
157 | val @receiver:StringRes Int.csv: List
158 | get() = resString.split(",").map(String::trim)
159 |
160 | val @receiver:XmlRes Int.resXml: XmlResourceParser
161 | get() = context.resources.getXml(this)
162 |
163 | // endregion
164 |
165 | // region Arrays
166 |
167 | val @receiver:ArrayRes Int.resIntArray: IntArray
168 | get() = context.resources.getIntArray(this)
169 |
170 | val @receiver:ArrayRes Int.resStringArray: Array
171 | get() = context.resources.getStringArray(this)
172 |
173 | val @receiver:ArrayRes Int.resTextArray: Array
174 | get() = context.resources.getTextArray(this)
175 |
176 | /**
177 | * Returns -1 if not found
178 | */
179 | @get:ColorRes
180 | val @receiver:ColorRes Int.resColorArray: List
181 | @SuppressLint("Recycle")
182 | get() = context.resources.obtainTypedArray(this).use { array ->
183 | (0 until array.length()).map { array.getResourceId(it, -1) }
184 | }
185 |
186 | @get:ColorInt
187 | val @receiver:ArrayRes Int.resColorIntArray: List
188 | get() = resColorArray.map { it.resColor }
189 |
190 | /**
191 | * Returns -1 if not found
192 | */
193 | @get:DrawableRes
194 | val @receiver:ArrayRes Int.resDrawableIdArray: List
195 | @SuppressLint("Recycle")
196 | get() = context.resources.obtainTypedArray(this).use { array ->
197 | (0 until array.length()).map { array.getResourceId(it, -1) }
198 | }
199 |
200 | val @receiver:ArrayRes Int.resDrawableArray: List
201 | @SuppressLint("Recycle")
202 | get() = resDrawableIdArray.map { it.resDrawable }
203 |
204 | // endregion
205 |
206 | // region Ids
207 |
208 | /**
209 | * Returns -1 if not found
210 | */
211 | @get:IdRes
212 | val String.resId: Int
213 | get() = context.resources.getIdentifier(this, "id", context.packageName)
214 |
215 | val @receiver:AnyRes Int.resName: String
216 | get() = context.resources.getResourceEntryName(this)
217 |
218 | val @receiver:AnyRes Int.resTypeName: String
219 | get() = context.resources.getResourceTypeName(this)
220 |
221 | val @receiver:AnyRes Int.resPackageName: String
222 | get() = context.resources.getResourcePackageName(this)
223 |
224 | @StringRes
225 | fun String.resStringId(onError: ((Exception) -> Unit)? = null): Int {
226 | try {
227 | return context.resources.getIdentifier(this, "string", context.packageName)
228 | } catch (e: Exception) {
229 | onError?.invoke(e)
230 | }
231 | return 0
232 | }
233 |
234 | @get:DrawableRes
235 | val String.resDrawableId: Int
236 | get() = context.resources.getIdentifier(this, "drawable", context.packageName)
237 |
238 | @DrawableRes
239 | fun String.resDrawableId(onError: ((Exception) -> Unit)? = null): Int {
240 | try {
241 | return context.resources.getIdentifier(this, "drawable", context.packageName)
242 | } catch (e: Exception) {
243 | onError?.invoke(e)
244 | }
245 | return 0
246 | }
247 |
248 | // endregion
249 |
250 | // region Objects
251 |
252 | val @receiver:DrawableRes Int.resDrawable: Drawable
253 | get() = requireNotNull(ContextCompat.getDrawable(context, this))
254 |
255 | val @receiver:ColorRes Int.resColorDrawable: ColorDrawable
256 | get() = resColor.colorDrawable
257 |
258 | val @receiver:ColorRes Int.resGradientDrawable: GradientDrawable
259 | get() = ContextCompat.getDrawable(context, this) as GradientDrawable
260 |
261 | val @receiver:ColorInt Int.colorDrawable
262 | get() = ColorDrawable(this)
263 |
264 | val @receiver:AnimatorRes Int.resAnim: Animation
265 | get() = AnimationUtils.loadAnimation(context, this)
266 |
267 | val @receiver:AnimRes Int.resAnimator: Animator
268 | get() = AnimatorInflater.loadAnimator(context, this)
269 |
270 | val @receiver:FontRes Int.resFont: Typeface?
271 | @RequiresApi(Build.VERSION_CODES.O)
272 | get() = ResourcesCompat.getFont(context, this)
273 |
274 | val @receiver:RawRes Int.resRaw: InputStream
275 | get() = context.resources.openRawResource(this)
276 |
277 | val @receiver:InterpolatorRes Int.resInterpolator: Interpolator
278 | get() = AnimationUtils.loadInterpolator(context, this)
279 |
280 | val @receiver:AnimRes Int.resLayoutAnimation: LayoutAnimationController
281 | get() = AnimationUtils.loadLayoutAnimation(context, this)
282 |
283 | val @receiver:TransitionRes Int.resTransition: Transition
284 | @RequiresApi(Build.VERSION_CODES.KITKAT)
285 | get() = TransitionInflater.from(context).inflateTransition(this)
286 |
287 | // endregion
288 |
289 | // region Layout
290 |
291 | val @receiver:LayoutRes Int.resLayout: XmlResourceParser
292 | get() = context.resources.getLayout(this)
293 |
294 | fun @receiver:LayoutRes Int.inflate(parent: ViewParent?, attachToRoot: Boolean = false): View =
295 | LayoutInflater.from((parent as ViewGroup).context).inflate(this, parent, attachToRoot)
296 |
297 | // endregion
298 |
299 | // region Screen
300 |
301 | val Float.pt: Float
302 | get() = TypedValue.applyDimension(
303 | TypedValue.COMPLEX_UNIT_PT,
304 | this,
305 | context.resources.displayMetrics
306 | )
307 |
308 | val Int.pt: Int get() = toFloat().pt.toInt()
309 |
310 | val Float.inches: Float
311 | get() = TypedValue.applyDimension(
312 | TypedValue.COMPLEX_UNIT_IN,
313 | this,
314 | context.resources.displayMetrics
315 | )
316 |
317 | val Int.inches: Int get() = toFloat().inches.toInt()
318 |
319 | val Float.mm: Float
320 | get() = TypedValue.applyDimension(
321 | TypedValue.COMPLEX_UNIT_MM,
322 | this,
323 | context.resources.displayMetrics
324 | )
325 |
326 | val Int.mm: Int get() = toFloat().mm.toInt()
327 |
328 | /**
329 | * Converts dp to pixel.
330 | */
331 | val Float.dp: Float
332 | get() = TypedValue.applyDimension(
333 | TypedValue.COMPLEX_UNIT_DIP,
334 | this,
335 | context.resources.displayMetrics
336 | )
337 |
338 | /**
339 | * Converts pixel to dp.
340 | */
341 | val Float.px: Float get() = this / Resources.getSystem().displayMetrics.density // TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, this, context.resources.displayMetrics)
342 |
343 | /**
344 | * Converts dp to pixel.
345 | */
346 | val Int.dp: Int get() = toFloat().dp.toInt()
347 |
348 | /**
349 | * Converts pixel to dp.
350 | */
351 | val Int.px: Int get() = toFloat().px.toInt()
352 |
353 | val Int.sp: Float
354 | get() = TypedValue.applyDimension(
355 | TypedValue.COMPLEX_UNIT_SP,
356 | this.toFloat(),
357 | context.resources.displayMetrics
358 | )
359 |
360 | val Float.sp: Float
361 | get() = TypedValue.applyDimension(
362 | TypedValue.COMPLEX_UNIT_SP,
363 | this,
364 | context.resources.displayMetrics
365 | )
366 |
367 | var TextView.sp: Float
368 | set(value) = setTextSize(TypedValue.COMPLEX_UNIT_SP, value)
369 | get() = textSize.sp
370 |
371 | val screenWidthDp: Int
372 | get() = Resources.getSystem().configuration.screenWidthDp
373 |
374 | val screenHeightDp: Int
375 | get() = Resources.getSystem().configuration.screenHeightDp
376 |
377 | val screenWidthPixels: Int
378 | get() = Resources.getSystem().displayMetrics.widthPixels
379 |
380 | val screenHeightPixels: Int
381 | get() = Resources.getSystem().displayMetrics.heightPixels
382 |
383 | // endregion
384 |
385 | // region Assets
386 |
387 | private val BUFFER_SIZE by lazy { 16 * 1024 }
388 |
389 | private val copyBuffer by lazy { ThreadLocal() }
390 |
391 | /**
392 | * Thread-Safe
393 | */
394 | fun String.bytesFromAssets(
395 | ctx: Context? = context,
396 | onError: ((Exception) -> Unit)? = null
397 | ): ByteArray? = try {
398 |
399 | ctx?.assets?.open(this)?.use { inputStream ->
400 |
401 | ByteArrayOutputStream().use { buffer ->
402 |
403 | var byteBuffer = copyBuffer.get()
404 | if (byteBuffer == null) {
405 | byteBuffer = ByteArray(BUFFER_SIZE)
406 | copyBuffer.set(byteBuffer)
407 | }
408 |
409 | var readBytes: Int
410 | do {
411 | readBytes = inputStream.read(byteBuffer, 0, byteBuffer.size)
412 | if (readBytes != -1)
413 | buffer.write(byteBuffer, 0, readBytes)
414 | } while (readBytes != -1)
415 |
416 | buffer.flush()
417 |
418 | buffer.toByteArray()
419 | }
420 | }
421 |
422 | } catch (e: Exception) {
423 | onError?.invoke(e)
424 | null
425 | }
426 |
427 | fun String.stringFromAssets(ctx: Context? = context): String? = try {
428 | ctx?.assets?.open(this)?.bufferedReader()?.use { it.readText() }
429 | } catch (e: Exception) {
430 | e.printStackTrace()
431 | null
432 | }
433 |
434 | fun String.fontFromAssets(ctx: Context? = context) = Typeface.createFromAsset(requireNotNull(ctx).assets, this)
435 |
436 | // endregion
437 |
438 | // region Misc
439 |
440 | val isRightToLeft: Boolean
441 | get() = R.bool.rtl.resBoolean
442 |
443 | val Uri.isTelephoneLink: Boolean
444 | get() = toString().startsWith("tel:")
445 |
446 | val Uri.isMailToLink: Boolean
447 | get() = toString().startsWith("mailto:")
448 |
449 | // endregion
450 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/src/main/res/values-ldltr/ltr-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0
4 | 1
5 | -1
6 | false
7 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/src/main/res/values-ldrtl/rtl-config.xml:
--------------------------------------------------------------------------------
1 |
2 | true
3 | -1
4 | 1
5 | 180
6 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
27 |
--------------------------------------------------------------------------------
/AndroidResourceExtensions/src/main/res/values/ltr-config.xml:
--------------------------------------------------------------------------------
1 |
2 | 0
3 | 1
4 | -1
5 | false
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.paypal.me/janrabe/5) [](https://kibotu.net) [](https://android-arsenal.com/details/1/7880)
2 |
3 | # Android Resource Extensions
4 | [](https://central.sonatype.com/artifact/net.kibotu/AndroidResourceExtensions) [](https://jitpack.io/#kibotu/AndroidResourceExtensions) [](https://github.com/kibotu/AndroidResourceExtensions/actions/workflows/android.yml) [](https://android-arsenal.com/api?level=21) [](https://android-arsenal.com/api?level=35) [](https://www.oracle.com/java/technologies/javase/17all-relnotes.html) [](https://docs.gradle.org/current/release-notes) [](https://kotlinlang.org/) [](https://jitpack.io/#kibotu/AndroidResourceExtensions) [](https://hitsofcode.com/view/github/kibotu/AndroidResourceExtensions)
5 |
6 | Convenience extension methods for android's auto-generated /res folder *R.* class.
7 |
8 | Basically everything in your res/ and /assets folder can be accessed via an extension function. *Note: everything gets loaded with current activity context, if that is not available it uses application context.*
9 |
10 | # How to install
11 |
12 | ## MavenCentral
13 |
14 | ```groovy
15 | allprojects {
16 | repositories {
17 | mavenCentral()
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation 'net.kibotu:AndroidResourceExtensions:{latest-version}'
23 | }
24 |
25 | ```
26 |
27 | ## Jitpack
28 |
29 | ```groovy
30 | allprojects {
31 | repositories {
32 | ...
33 | maven { url 'https://jitpack.io' }
34 | }
35 | }
36 |
37 | dependencies {
38 | implementation 'com.github.kibotu:AndroidResourceExtensions:{latest-version}'
39 | }
40 | ```
41 |
42 | ### Features:
43 |
44 | ##### Values
45 |
46 | - resBoolean
47 | - resInt
48 | - resLong
49 | - resString
50 | - resString(args)
51 | - localizedString(locale)
52 | - localizedResources(locale)
53 | - quantityString
54 | - quantityString(args)
55 | - resColorLong
56 | - resColor
57 | - resDimension
58 | - html
59 | - html
60 | - csv
61 | - resXml
62 | - resFraction
63 |
64 | ##### Arrays
65 |
66 | - resIntArray
67 | - resStringArray
68 | - resTextArray
69 | - resColorArray
70 | - resColorIntArray
71 | - resDrawableArray
72 | - resDrawableIdArray
73 |
74 | ##### Ids
75 |
76 | - resId
77 | - resName
78 | - resTypeName
79 | - resPackageName
80 | - resStringId
81 | - resDrawableId
82 | - resDrawableId((Exception)->Unit)
83 | - resColorDrawable
84 | - resGradientDrawable
85 |
86 | ##### Objects
87 |
88 | - resDrawable
89 | - colorDrawable
90 | - resAnim
91 | - resAnimator
92 | - resFont
93 | - resRaw
94 | - resInterpolator
95 | - resLayoutAnimation
96 | - resTransition
97 |
98 | ##### Layout
99 |
100 | - resLayout
101 | - inflate
102 |
103 | ##### Screen
104 |
105 | - dp
106 | - px
107 | - sp
108 | - pt
109 | - inches
110 | - mm
111 | - screenWidthDp
112 | - screenHeightDp
113 | - screenWidthPixels
114 | - screenHeightPixels
115 |
116 | ##### Assets
117 |
118 | - bytesFromAssets // thread-safe
119 | - stringFromAssets
120 |
121 | ##### Misc
122 |
123 | - isRightToLeft
124 | - isTelephoneLink
125 | - isMailToLink
126 |
127 |
128 | ### ManifestPermissions
129 |
130 | - isGranted // checks if granted, doesn't trigger request
131 |
132 |
133 | ### How to use
134 |
135 |
136 | ```kotlin
137 | val my_integer: Int = R.integer.my_integer.resInt
138 | val my_long: Long = R.integer.my_long.resLong
139 | val my_string: String = R.string.my_string.resString
140 | val my_string_args: String = R.string.my_string_args.resString("ipsum")
141 | val my_string_args_float: String = R.string.my_string_args_float.resString(2f)
142 | val my_localized_string: String = R.string.my_localized_string.localizedString(Locale.GERMAN)
143 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
144 | val my_localized_resources: Resources = localizedResources(this, Locale.GERMAN)
145 | }
146 | val my_quantityString: String = R.plurals.my_quantityString.quantityString(2)
147 | val my_quantityString_args: String = R.plurals.my_quantityString_args.quantityString(2, "total")
148 |
149 | val my_boolean: Boolean = R.bool.my_boolean.resBoolean
150 | val my_color_long: Long = R.color.my_color_long.resColorLong
151 | val my_color: Int = R.color.my_color.resColor
152 | val my_dimension: Float = R.dimen.my_dimension.resDimension
153 | val my_string_html: Spanned = """Google""".html
154 | val my_html: Spanned = R.string.my_html.html
155 | val my_csv: List = R.string.my_csv.csv
156 | val my_xml: XmlResourceParser = R.xml.lorem_ipsum.resXml
157 | // 0.10f
158 | val my_fraction: Float = R.fraction.my_fraction.resFraction(2, 2)
159 | val my_int_array: IntArray = R.array.my_int_array.resIntArray
160 | val my_string_array: Array = R.array.my_string_array.resStringArray
161 | val my_character_array: Array = R.array.my_string_array.resTextArray
162 | /*ColorRes*/
163 | val my_icons_array: List = R.array.my_colors.resColorArray
164 | /*ColorInt*/
165 | val my_icons_array_color_int: List = R.array.my_colors.resColorIntArray
166 | /*@DrawableRes*/
167 | val my_colors_array: List = R.array.my_icons.resDrawableIdArray
168 | /*@Drawable*/
169 | val my_colors_array_drawable: List = R.array.my_icons.resDrawableArray
170 | @IdRes val my_id: Int = "my_id".resId
171 | val my_res_name: String = R.integer.my_res_name.resName
172 | val my_res_type_name: String = R.integer.my_res_type_name.resTypeName
173 | val my_res_package_name: String = R.integer.my_res_package_name.resPackageName
174 | @StringRes val my_res_string_id: Int = "my_res_string_id".resStringId { it.printStackTrace() }
175 | @DrawableRes val my_res_drawable_id: Int = "ic_share".resDrawableId
176 | @DrawableRes val my_res_drawable_id_with_error_handling: Int = "ic_share".resDrawableId { it.printStackTrace() }
177 | val my_drawable: Drawable = R.drawable.ic_share.resDrawable
178 | val my_anim: Animation = R.anim.grow.resAnim
179 | val my_animator: Animator = R.animator.flip_animation.resAnimator
180 | val my_font: Typeface = R.font.lato.resFont
181 | val my_raw: InputStream = R.raw.my_raw.resRaw
182 | val my_interpolator: Interpolator = android.R.interpolator.anticipate_overshoot.resInterpolator
183 | val my_res_layout_animation_controller: LayoutAnimationController = R.anim.layout_animation.resLayoutAnimation
184 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
185 | val my_transition: Transition = android.R.transition.explode.resTransition
186 | }
187 | val my_layout: XmlResourceParser = R.layout.activity_main.resLayout
188 | val my_inflated_layout: View = R.layout.activity_main.inflate(root)
189 | val my_dp: Float = 16f.dp
190 | val my_dp_int: Int = 16.dp
191 | val my_px: Float = 200f.px
192 | val my_px_int: Int = 200.px
193 | val my_sp: Float = 14f.sp
194 | val my_pt: Float = 14f.pt
195 | val my_inches: Float = 14f.inches
196 | val my_mm: Float = 14f.mm
197 | val my_screen_width_dp: Int = screenWidthDp
198 | val my_screen_height_dp: Int = screenHeightDp
199 | val my_screen_width_pixels: Int = screenWidthPixels
200 | val my_screen_height_pixels: Int = screenHeightPixels
201 | val my_bytes_from_assets: ByteArray? = "my_text.json".bytesFromAssets()
202 | val my_string_from_assets: String? = "my_text.json".stringFromAssets()
203 | val my_device_is_rtl: Boolean = isRightToLeft
204 | val my_string_is_a_telephone_link: Boolean = Uri.parse("""Google""").isTelephoneLink
205 | val my_string_is_a_mailto_link: Boolean = Uri.parse("""Google""").isMailToLink
206 |
207 | val locationPermission : Boolean = Manifest.permission.ACCESS_FINE_LOCATION.isGranted
208 |
209 | ```
210 |
211 | ### Notes
212 |
213 | Follow me on Twitter: [@wolkenschauer](https://twitter.com/wolkenschauer)
214 |
215 | Let me know what you think: [jan.rabe@kibotu.net](mailto:jan.rabe@kibotu.net)
216 |
217 | Contributions welcome!
218 |
219 | ### License
220 |
221 |
222 | Copyright 2022 Jan Rabe
223 |
224 | Licensed under the Apache License, Version 2.0 (the "License");
225 | you may not use this file except in compliance with the License.
226 | You may obtain a copy of the License at
227 |
228 | http://www.apache.org/licenses/LICENSE-2.0
229 |
230 | Unless required by applicable law or agreed to in writing, software
231 | distributed under the License is distributed on an "AS IS" BASIS,
232 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
233 | See the License for the specific language governing permissions and
234 | limitations under the License.
235 |
3 |
4 | Brian Cantoni
5 | Generate random Lorem Ipsum text from lipsum.com. Parameters: amount=number of things to fetch; what: paras, words, bytes, or lists; start: set to "no" to not start all strings with Lorem Ipsum.
6 | http://www.lipsum.com/
7 | select * from {table} where amount='5' and what='paras';
8 |
9 |
10 |
28 |
29 |