├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_launcher-web.png
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_action_camera.png
│ │ │ │ ├── ic_action_close.png
│ │ │ │ ├── ic_action_file.png
│ │ │ │ ├── ic_action_name.png
│ │ │ │ ├── ic_action_gallery.png
│ │ │ │ └── ic_action_photo_camera.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_action_camera.png
│ │ │ │ ├── ic_action_close.png
│ │ │ │ ├── ic_action_file.png
│ │ │ │ ├── ic_action_name.png
│ │ │ │ ├── ic_action_gallery.png
│ │ │ │ └── ic_action_photo_camera.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ic_action_close.png
│ │ │ │ ├── ic_action_file.png
│ │ │ │ ├── ic_action_name.png
│ │ │ │ ├── ic_action_camera.png
│ │ │ │ ├── ic_action_gallery.png
│ │ │ │ └── ic_action_photo_camera.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── ic_action_file.png
│ │ │ │ ├── ic_action_name.png
│ │ │ │ ├── ic_action_camera.png
│ │ │ │ ├── ic_action_close.png
│ │ │ │ ├── ic_action_gallery.png
│ │ │ │ └── ic_action_photo_camera.png
│ │ │ ├── menu
│ │ │ │ └── main_menu.xml
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── strings.xml
│ │ │ ├── layout
│ │ │ │ ├── item_row_gallery.xml
│ │ │ │ ├── item_row_layout.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_gallery.xml
│ │ │ │ └── dialog_details.xml
│ │ │ └── drawable
│ │ │ │ └── background_text_view.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── androidbuffer
│ │ │ └── kotlinfilepickersample
│ │ │ ├── ThumbnailAdapter.kt
│ │ │ ├── PickerAdapter.kt
│ │ │ ├── DetailsDialog.kt
│ │ │ ├── GalleryActivity.kt
│ │ │ └── MainActivity.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── androidbuffer
│ │ │ └── kotlinfilepickersample
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── androidbuffer
│ │ └── kotlinfilepickersample
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── kotlinfilepicker
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── xml
│ │ │ │ └── provider_paths.xml
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── androidbuffer
│ │ │ └── kotlinfilepicker
│ │ │ ├── KotConstants.kt
│ │ │ ├── KotResult.kt
│ │ │ ├── KotlinFilePicker.kt
│ │ │ ├── KotRequest.kt
│ │ │ └── KotUtil.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── androidbuffer
│ │ │ └── kotlinfilepicker
│ │ │ └── KotUtilTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── androidbuffer
│ │ └── kotlinfilepicker
│ │ └── InstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── .gitignore
├── LICENSE
├── README.md
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/kotlinfilepicker/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':kotlinfilepicker'
2 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-hdpi/ic_action_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-hdpi/ic_action_close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-hdpi/ic_action_file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-hdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-mdpi/ic_action_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-mdpi/ic_action_close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-mdpi/ic_action_file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-mdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xhdpi/ic_action_close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xhdpi/ic_action_file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xhdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_gallery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-hdpi/ic_action_gallery.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_gallery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-mdpi/ic_action_gallery.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xhdpi/ic_action_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_gallery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xhdpi/ic_action_gallery.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_gallery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_gallery.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_photo_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-hdpi/ic_action_photo_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_photo_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-mdpi/ic_action_photo_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_photo_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xhdpi/ic_action_photo_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_photo_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/androidbuffer/Kotlinfilepicker/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_photo_camera.png
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #admob setup
2 | admobAppId=ca-app-pub-3940256099942544~3347511713
3 | admobDashboardAdId=ca-app-pub-3940256099942544/6300978111
4 | android.enableJetifier=true
5 | android.useAndroidX=true
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jan 24 00:33:50 IST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 20sp
4 | 8dp
5 | 16dp
6 | 4dp
7 | 80dp
8 | 2dp
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFC107
4 | #FFA000
5 | #FF4081
6 | #fafafa
7 | #212121
8 | #bdbdbd
9 | #fff
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_row_gallery.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/test/java/com/androidbuffer/kotlinfilepickersample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepickersample
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_text_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 |
9 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Kotlin File Picker
3 | Kotlin file picker is not initialized with proper arguments
4 | File selection not supported
5 | No Activity found to handle Intent
6 | not now
7 | SETTINGS
8 | Allow Application to access to your device\'s photos, media and files. Tap settings > Permissions, and turn storage on.
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .gradle
38 | /.idea/workspace.xml
39 | /.idea/libraries
40 | .DS_Store
41 | /build
42 | .externalNativeBuild
43 | .idea/
44 |
45 | #release apk folders
46 | /app/release
47 |
--------------------------------------------------------------------------------
/app/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 |
--------------------------------------------------------------------------------
/kotlinfilepicker/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 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/androidbuffer/kotlinfilepickersample/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepickersample
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.runner.AndroidJUnit4
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().context
20 | assertEquals("com.androidbuffer.kotlinfilepickersample", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/kotlinfilepicker/src/test/java/com/androidbuffer/kotlinfilepicker/KotUtilTest.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepicker
2 |
3 | import org.junit.Assert
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 |
12 | class KotUtilTest {
13 |
14 | val extension = "pdf"
15 | val url = "/storage/emulated/0/Download/3c45fcac801adcd03c00391e9dbb119b.${extension}"
16 |
17 | @Test
18 | fun isExtensionCorrect() {
19 | val extension = "pdf"
20 | val url = "/storage/emulated/0/Download/3c45fcac801adcd03c00391e9dbb119b.${extension}"
21 | val extensionExpected = KotUtil.getFileExtensionFromUrl(url)
22 | Assert.assertEquals(extension, extensionExpected)
23 | }
24 |
25 | @Test
26 | fun isDateFormatCorrect(){
27 | val currentDate = System.currentTimeMillis()
28 | val formattedDate = KotUtil.getDateModified(currentDate)
29 | Assert.assertNotNull(formattedDate)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
16 |
17 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/kotlinfilepicker/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 |
5 | android {
6 | compileSdkVersion 29
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 29
10 | versionCode 4
11 | versionName "0.0.4"
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | }
14 |
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 |
22 | }
23 |
24 | dependencies {
25 | implementation fileTree(dir: 'libs', include: ['*.jar'])
26 | implementation 'androidx.appcompat:appcompat:1.1.0'
27 | testImplementation 'junit:junit:4.12'
28 | androidTestImplementation 'androidx.test:runner:1.2.0'
29 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
31 | }
32 |
33 | repositories {
34 | mavenCentral()
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 androidbuffer.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Kotlin File Picker
3 | Pick any below option to choose file
4 | Camera
5 | File
6 | Gallery
7 | Video
8 | Gallery (Single)
9 | Modified Date : %1$s
10 | Type : %1$s
11 | Location : %1$s
12 | Size : %1$s
13 | File Details
14 | Close
15 |
16 | //recyclerview options
17 |
18 | - Gallery(Single)
19 | - Gallery (Multiple)
20 | - File (Single)
21 | - File (Multiple)
22 | - Camera
23 | - Video
24 |
25 |
26 |
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/java/com/androidbuffer/kotlinfilepicker/KotConstants.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepicker
2 |
3 | /**
4 | * Created by AndroidBuffer on 28/12/17.
5 | */
6 |
7 |
8 | class KotConstants {
9 |
10 | companion object {
11 | //extra intent constants
12 | public const val EXTRA_MULTIPLE_ENABLED = "extraMultipleEnabled"
13 | public const val EXTRA_FILE_MIME_TYPE = "extraFileMimeType"
14 | public const val EXTRA_FILE_SELECTION = "extraFileSelection"
15 | public const val EXTRA_FILE_RESULTS = "extraFileResults"
16 |
17 | //file selection type
18 | public const val SELECTION_TYPE_CAMERA = "Gallery"
19 | public const val SELECTION_TYPE_GALLERY = "Camera"
20 | public const val SELECTION_TYPE_FILE = "File"
21 | public const val SELECTION_TYPE_VIDEO = "Video"
22 |
23 | //files types supported
24 | val FILE_TYPE_IMAGE_ALL = "image/*"
25 | val FILE_TYPE_VIDEO_ALL = "video/*"
26 | val FILE_TYPE_FILE_ALL = "*/*"
27 | val FILE_TYPE_PDF = "application/pdf"
28 | val FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
29 | val FILE_TYPE_EXCEL = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
30 | }
31 | }
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/java/com/androidbuffer/kotlinfilepicker/KotResult.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepicker
2 |
3 | import android.net.Uri
4 | import android.os.Parcel
5 | import android.os.Parcelable
6 |
7 | /**
8 | * Created by AndroidBuffer on 13/4/18.
9 | */
10 | data class KotResult(val uri: Uri
11 | , val name: String?
12 | , val size: String?
13 | , val location: String?
14 | , val type: String?
15 | , val modified: String?) : Parcelable {
16 | constructor(parcel: Parcel) : this(
17 | parcel.readParcelable(Uri::class.java.classLoader),
18 | parcel.readString(),
19 | parcel.readString(),
20 | parcel.readString(),
21 | parcel.readString(),
22 | parcel.readString()) {
23 | }
24 |
25 | override fun writeToParcel(parcel: Parcel, flags: Int) {
26 | parcel.writeParcelable(uri, flags)
27 | parcel.writeString(name)
28 | parcel.writeString(size)
29 | parcel.writeString(location)
30 | parcel.writeString(type)
31 | parcel.writeString(modified)
32 | }
33 |
34 | override fun describeContents(): Int {
35 | return 0
36 | }
37 |
38 | companion object CREATOR : Parcelable.Creator {
39 | override fun createFromParcel(parcel: Parcel): KotResult {
40 | return KotResult(parcel)
41 | }
42 |
43 | override fun newArray(size: Int): Array {
44 | return arrayOfNulls(size)
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/androidbuffer/kotlinfilepickersample/ThumbnailAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepickersample
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.ImageView
8 | import com.androidbuffer.kotlinfilepicker.KotResult
9 |
10 | /**
11 | * Created by AndroidBuffer on 24/6/18.
12 | */
13 |
14 | class ThumbnailAdapter(listOfImages: ArrayList,listener:OnThumbnailListener) : RecyclerView.Adapter() {
15 |
16 | val localList = listOfImages
17 | val clickListener = listener
18 |
19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
20 | val view = LayoutInflater.from(parent.context).inflate(R.layout.item_row_gallery, parent, false)
21 | return ViewHolder(view)
22 | }
23 |
24 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
25 | holder.imageView.setImageURI(localList.get(position).uri)
26 | }
27 |
28 | override fun getItemCount(): Int {
29 | return localList.size
30 | }
31 |
32 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
33 | val imageView: ImageView
34 |
35 | init {
36 | imageView = itemView.findViewById(R.id.ivThumbnail)
37 | imageView.setOnClickListener((View.OnClickListener {
38 | clickListener.onThumbnailClick(adapterPosition)
39 | }))
40 | }
41 | }
42 |
43 | /**
44 | * interface for onClick listener
45 | */
46 | interface OnThumbnailListener {
47 | fun onThumbnailClick(position: Int)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_row_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
19 |
20 |
27 |
28 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 | android {
8 | compileSdkVersion 29
9 | defaultConfig {
10 | applicationId "com.androidbuffer.kotlinfilepickersample"
11 | minSdkVersion 15
12 | targetSdkVersion 29
13 | versionCode 4
14 | versionName "0.0.4"
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled true
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | buildConfigField("String", "AD_MOB_APP_ID", "\"${admobAppId}\"")
22 | resValue "string", "AD_MOB_DASHBOARD_AD_ID", "${admobDashboardAdId}"
23 | }
24 | debug {
25 | buildConfigField("String", "AD_MOB_APP_ID", "\"${admobAppId}\"")
26 | resValue "string", "AD_MOB_DASHBOARD_AD_ID", "${admobDashboardAdId}"
27 | applicationIdSuffix ".debug"
28 | }
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(include: ['*.jar'], dir: 'libs')
34 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
35 | implementation 'androidx.appcompat:appcompat:1.1.0'
36 | implementation 'androidx.recyclerview:recyclerview:1.0.0'
37 | implementation 'androidx.cardview:cardview:1.0.0'
38 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
39 | testImplementation 'junit:junit:4.12'
40 | androidTestImplementation 'androidx.test:runner:1.2.0'
41 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
42 | testImplementation 'org.mockito:mockito-core:3.0.0'
43 | androidTestImplementation 'org.mockito:mockito-android:3.0.0'
44 | testImplementation 'com.nhaarman:mockito-kotlin:1.6.0'
45 | implementation 'com.google.android.gms:play-services-ads:18.2.0'
46 | implementation project(':kotlinfilepicker')
47 | }
48 |
--------------------------------------------------------------------------------
/kotlinfilepicker/src/androidTest/java/com/androidbuffer/kotlinfilepicker/InstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepicker
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import androidx.test.platform.app.InstrumentationRegistry
6 | import androidx.test.ext.junit.runners.AndroidJUnit4
7 | import org.junit.Assert.assertEquals
8 | import org.junit.Assert.assertNotNull
9 | import org.junit.Before
10 | import org.junit.Test
11 | import org.junit.runner.RunWith
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see [Testing documentation](http://d.android.com/tools/testing)
17 | */
18 | @RunWith(AndroidJUnit4::class)
19 | class InstrumentedTest {
20 |
21 | val extension = "pdf"
22 | val url = "/storage/emulated/0/Download/3c45fcac801adcd03c00391e9dbb119b.${extension}"
23 | lateinit var appContext: Context
24 |
25 | @Before
26 | fun inItValues() {
27 | appContext = InstrumentationRegistry.getTargetContext()
28 | }
29 |
30 | @Test
31 | @Throws(Exception::class)
32 | fun useAppContext() {
33 | // Context of the app under test.
34 | assertEquals("com.androidbuffer.kotlinfilepicker.test", appContext.packageName)
35 | }
36 |
37 | @Test
38 | fun isMimeCorrect() {
39 | val correct = "application/pdf"
40 | val result = KotUtil.getMimeType(url)
41 | assertEquals(correct, result)
42 | }
43 |
44 | @Test
45 | fun fileIntentNotNull() {
46 | val mimeType = "image/*"
47 | val intent = KotUtil.getFileIntent(mimeType, true)
48 | assertNotNull(intent)
49 | }
50 |
51 | @Test
52 | fun galleryIntentNotNull() {
53 | val mimeType = "application/pdf"
54 | val intent = KotUtil.getGalleryIntent(mimeType, true)
55 | assertNotNull(intent)
56 | }
57 |
58 | @Test
59 | fun videoIntentNotNull(){
60 | assertNotNull(KotUtil.getVideoIntent(appContext))
61 | }
62 |
63 | @Test
64 | fun cameraIntentNotNull(){
65 | assertNotNull(KotUtil.getCameraIntent(appContext))
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_gallery.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
31 |
32 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidbuffer/kotlinfilepickersample/PickerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepickersample
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import androidx.recyclerview.widget.RecyclerView
9 |
10 | /**
11 | * Created by AndroidBuffer on 26/1/18.
12 | */
13 | class PickerAdapter(titleArray: Array,
14 | drawableArray: Array,
15 | clickItemListener: OnClickItemListener) : RecyclerView.Adapter() {
16 |
17 | val arrayList: Array = titleArray
18 | val drawableList: Array = drawableArray
19 | val itemClickListener: OnClickItemListener = clickItemListener
20 |
21 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
22 | //map values to views here
23 | holder.tvTitle.text = arrayList[position]
24 | holder.ivTitleIcon.setImageResource(drawableList[position])
25 | }
26 |
27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
28 | return ViewHolder(LayoutInflater.from(parent?.context).inflate(R.layout.item_row_layout, parent, false))
29 | }
30 |
31 | override fun getItemCount(): Int {
32 | return arrayList.size;
33 | }
34 |
35 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
36 | //here goes view holder
37 | var tvTitle: TextView
38 | var ivTitleIcon: ImageView
39 |
40 | init {
41 | //set the item click listener
42 | tvTitle = itemView.findViewById(R.id.tvTitle)
43 | ivTitleIcon = itemView.findViewById(R.id.ivTitleIcon)
44 | itemView.setOnClickListener(this)
45 | }
46 |
47 | override fun onClick(p0: View) {
48 | //handle the click listener on items
49 | itemClickListener.onItemClick(adapterPosition)
50 | }
51 | }
52 |
53 | interface OnClickItemListener {
54 | fun onItemClick(position: Int)
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
21 |
22 |
29 |
30 |
37 |
38 |
45 |
46 |
53 |
54 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidbuffer/kotlinfilepickersample/DetailsDialog.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepickersample
2 |
3 | import android.app.DialogFragment
4 | import android.os.Bundle
5 | import androidx.appcompat.widget.AppCompatButton
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.view.WindowManager
10 | import android.widget.TextView
11 | import com.androidbuffer.kotlinfilepicker.KotResult
12 |
13 | /**
14 | * Created by AndroidBuffer on 13/4/18.
15 | */
16 | class DetailsDialog : DialogFragment() {
17 |
18 | private lateinit var nameOfFile: TextView
19 | private lateinit var sizeOfFile: TextView
20 | private lateinit var locationOfFile: TextView
21 | private lateinit var typeOfFile: TextView
22 | private lateinit var modifiedDateOfFile: TextView
23 |
24 | companion object {
25 |
26 | val EXTRA_RESULT_OF_FILE = "EXTRA_FILE_RESULT"
27 |
28 | fun getInstance(kotResult: KotResult): DetailsDialog {
29 | val fragment = DetailsDialog()
30 | val bundle = Bundle()
31 | bundle.putParcelable(EXTRA_RESULT_OF_FILE, kotResult)
32 | fragment.arguments = bundle
33 | return fragment
34 | }
35 | }
36 |
37 | override fun onStart() {
38 | super.onStart()
39 | dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT)
40 | isCancelable = false
41 | }
42 |
43 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View {
44 | val view = inflater?.inflate(R.layout.dialog_details, container, false)
45 | return view!!
46 | }
47 |
48 | override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
49 | super.onViewCreated(view, savedInstanceState)
50 | assert(arguments != null)
51 | if (view == null) return
52 | //view init
53 | nameOfFile = view.findViewById(R.id.tvNameOfFile)
54 | sizeOfFile = view.findViewById(R.id.tvSizeOfFile)
55 | locationOfFile = view.findViewById(R.id.tvLocationOfFile)
56 | typeOfFile = view.findViewById(R.id.tvTypeOfFile)
57 | modifiedDateOfFile = view.findViewById(R.id.tvModiedDateOfFile)
58 |
59 | view.findViewById(R.id.btClose).setOnClickListener({ dismiss() })
60 |
61 | val kotResult = arguments?.getParcelable(EXTRA_RESULT_OF_FILE)
62 | nameOfFile.text = kotResult?.name
63 | sizeOfFile.text = String.format(getString(R.string.size_of_file, kotResult?.size))
64 | locationOfFile.text = String.format(getString(R.string.location_of_file, kotResult?.location))
65 | typeOfFile.text = String.format(getString(R.string.type_of_file, kotResult?.type))
66 | modifiedDateOfFile.text = String.format(getString(R.string.modified_date, kotResult?.modified))
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidbuffer/kotlinfilepickersample/GalleryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepickersample
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.recyclerview.widget.LinearLayoutManager
6 | import androidx.recyclerview.widget.RecyclerView
7 | import android.util.Log
8 | import android.view.Menu
9 | import android.view.MenuItem
10 | import android.widget.ImageView
11 | import com.androidbuffer.kotlinfilepicker.KotResult
12 | import com.google.android.gms.ads.AdRequest
13 | import com.google.android.gms.ads.AdView
14 |
15 |
16 | /**
17 | * Created by AndroidBuffer on 26/1/18.
18 | */
19 | class GalleryActivity : AppCompatActivity(), ThumbnailAdapter.OnThumbnailListener {
20 |
21 | private val EXTRA_IMAGE_RESULT = "EXTRA_IMAGE_RESULT"
22 | lateinit var rvThumbnailsImages: androidx.recyclerview.widget.RecyclerView
23 | lateinit var listOfImages: ArrayList
24 | lateinit var adapter: ThumbnailAdapter
25 | lateinit var imageViewFullScreen: ImageView
26 | lateinit var adViewBottom: AdView
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 | setContentView(R.layout.activity_gallery)
31 | listOfImages = intent.getParcelableArrayListExtra(EXTRA_IMAGE_RESULT)
32 |
33 | if (listOfImages.size > 1) {
34 | setupRecyclerView()
35 | }
36 |
37 | //image view
38 | imageViewFullScreen = findViewById(R.id.ivFullScreenImage)
39 |
40 | //by default image
41 | imageViewFullScreen.setImageURI(listOfImages.get(0).uri)
42 |
43 | setupAdView()
44 | }
45 |
46 | fun setupAdView() {
47 | //setup the adview
48 | adViewBottom = findViewById(R.id.adViewBottom)
49 | val adRequest = AdRequest.Builder().build()
50 | adViewBottom.loadAd(adRequest)
51 | }
52 |
53 | private fun setupRecyclerView() {
54 | //adapter for thumbnail
55 | adapter = ThumbnailAdapter(listOfImages, this)
56 | rvThumbnailsImages = findViewById(R.id.rvThumbnailsImages)
57 | rvThumbnailsImages.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this,
58 | androidx.recyclerview.widget.LinearLayoutManager.HORIZONTAL, false)
59 | rvThumbnailsImages.adapter = adapter
60 | }
61 |
62 | override fun onCreateOptionsMenu(menu: Menu?): Boolean {
63 | menuInflater.inflate(R.menu.main_menu, menu);
64 | return true
65 | }
66 |
67 | override fun onOptionsItemSelected(item: MenuItem?): Boolean {
68 | if (item?.itemId == R.id.menuClose) {
69 | finish()
70 | }
71 | return super.onOptionsItemSelected(item)
72 | }
73 |
74 | /**
75 | * on click for image thumbnail
76 | */
77 | override fun onThumbnailClick(position: Int) {
78 | imageViewFullScreen.setImageURI(listOfImages.get(position).uri)
79 | Log.d("TAG", listOfImages.get(position).uri.toString())
80 | }
81 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kotlinfilepicker [](https://jitpack.io/#androidbuffer/kotlinfilepicker)
2 |
3 |
4 | An Android file picker written all in [Kotlin](https://kotlinlang.org/docs/reference/). KotlinFilePicker can be used to pick media files from Gallery and storage device.
5 |
6 | ## How to Download:
7 | Download the latest .aar and sample .apk from [release](https://github.com/androidbuffer/Kotlinfilepicker/releases).
8 |
9 | Gradle
10 |
11 | Add it in your root build.gradle at the end of repositories:
12 | ```
13 | allprojects {
14 | repositories {
15 | ...
16 | maven {
17 | url 'https://jitpack.io'
18 | }
19 | }
20 | }
21 | ```
22 | Add the dependency
23 | ```
24 | dependencies {
25 | implementation 'com.github.androidbuffer:kotlinfilepicker:v0.0.4-alpha'
26 | }
27 | ```
28 | Maven
29 | ```
30 |
31 |
32 | jitpack.io
33 | https://jitpack.io
34 |
35 |
36 | ```
37 | Add the dependency
38 | ```
39 |
40 | com.github.androidbuffer
41 | kotlinfilepicker
42 | v0.0.1-alpha
43 |
44 | ```
45 | ## Usage
46 | * make a camera request
47 | ```
48 | KotRequest.Camera(this, REQUEST_CAMERA).pick()
49 | //or
50 | KotRequest.Camera(this).setRequestCode(REQUEST_CAMERA).pick()
51 | //or get a intent back
52 | var intent = KotRequest.Camera(this, REQUEST_CAMERA).getCameraIntent()
53 | ```
54 | * make a video request
55 | ```
56 | KotRequest.Video(this, REQUEST_VIDEO).pick()
57 | ```
58 | * make a gallery request
59 | ```
60 | KotRequest.Gallery(this, REQUEST_GALLERY).isMultiple(isMultiple).pick()
61 | ```
62 | * make a file pick request
63 | ```
64 | KotRequest.File(this, REQUEST_FILE)
65 | .isMultiple(isMultiple)
66 | .setMimeType(KotConstants.FILE_TYPE_FILE_ALL)
67 | .pick()
68 | ```
69 | * Get back results like this.
70 | ```
71 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
72 | super.onActivityResult(requestCode, resultCode, data)
73 |
74 | if (REQUEST_CAMERA == requestCode && resultCode == Activity.RESULT_OK) {
75 |
76 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
77 | startGalleryView(result!!)
78 |
79 | } else if (REQUEST_FILE == requestCode && resultCode == Activity.RESULT_OK) {
80 |
81 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
82 | createDetailsFromResult(result!!.get(0))
83 |
84 | } else if (REQUEST_GALLERY == requestCode && resultCode == Activity.RESULT_OK) {
85 |
86 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
87 | startGalleryView(result!!)
88 |
89 | } else if (REQUEST_VIDEO == requestCode && resultCode == Activity.RESULT_OK) {
90 |
91 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
92 | createDetailsFromResult(result!!.get(0))
93 | }
94 | }
95 |
96 | ```
97 |
98 | ## Contributing / Issues
99 | we would be thankful for contributing to this project or if you find some bug or suggestions we welcome you also.
100 |
101 | ## Authors
102 |
103 | * **Vikas kumar**
104 |
105 | See also the list of [contributors](https://github.com/androidbuffer/Kotlinfilepicker/graphs/contributors) who participated in this project.
106 |
107 | ## License
108 |
109 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE) file for details
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidbuffer/kotlinfilepickersample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepickersample
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.appcompat.app.AppCompatActivity
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.androidbuffer.kotlinfilepicker.KotConstants
10 | import com.androidbuffer.kotlinfilepicker.KotRequest
11 | import com.androidbuffer.kotlinfilepicker.KotResult
12 | import com.google.android.gms.ads.AdRequest
13 | import com.google.android.gms.ads.AdView
14 | import com.google.android.gms.ads.MobileAds
15 |
16 |
17 | class MainActivity : AppCompatActivity(), PickerAdapter.OnClickItemListener {
18 |
19 | private val EXTRA_IMAGE_RESULT = "EXTRA_IMAGE_RESULT"
20 | lateinit var rvFilePickerMain: androidx.recyclerview.widget.RecyclerView
21 | private val REQUEST_CAMERA = 101
22 | private val REQUEST_GALLERY = 102
23 | private val REQUEST_FILE = 103
24 | private val REQUEST_VIDEO = 104
25 | private var adapter: PickerAdapter? = null
26 | lateinit var titleArray: Array
27 | lateinit var adBottom: AdView
28 |
29 | private val drawableArray = arrayOf(R.drawable.ic_action_gallery,
30 | R.drawable.ic_action_gallery,
31 | R.drawable.ic_action_file,
32 | R.drawable.ic_action_file,
33 | R.drawable.ic_action_photo_camera,
34 | R.drawable.ic_action_camera)
35 |
36 | override fun onCreate(savedInstanceState: Bundle?) {
37 | super.onCreate(savedInstanceState)
38 | setContentView(R.layout.activity_main)
39 | //init the view elements
40 | rvFilePickerMain = findViewById(R.id.rvFilePickerMain)
41 | adBottom = findViewById(R.id.adViewBottom)
42 | titleArray = resources.getStringArray(R.array.arrayOptions)
43 | setRecyclerView()
44 | setupAdView()
45 | }
46 |
47 | private fun setupAdView() {
48 | //here setup the adview
49 | MobileAds.initialize(this, BuildConfig.AD_MOB_APP_ID)
50 | val adRequest = AdRequest.Builder().addTestDevice("D50CED5C7D63D1D9B4DE1A5251B16354").build()
51 | adBottom.loadAd(adRequest)
52 | }
53 |
54 | private fun setRecyclerView() {
55 | //here set the recycler view
56 | adapter = PickerAdapter(titleArray, drawableArray, this)
57 | rvFilePickerMain.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
58 | rvFilePickerMain.adapter = adapter
59 | }
60 |
61 | private fun openCamera() {
62 | //opens camera from camera class
63 | KotRequest.Camera(this, REQUEST_CAMERA).pick()
64 | }
65 |
66 | private fun openVideo() {
67 | //opens a camera intent
68 | KotRequest.Video(this, REQUEST_VIDEO).pick()
69 | }
70 |
71 | private fun openGallery(isMultiple: Boolean) {
72 | //opens a gallery intent
73 | KotRequest.Gallery(this, REQUEST_GALLERY).isMultiple(isMultiple).pick()
74 | }
75 |
76 | private fun openFile(isMultiple: Boolean) {
77 | //opens a file intent
78 | KotRequest.File(this, REQUEST_FILE).isMultiple(isMultiple).setMimeType(KotConstants.FILE_TYPE_FILE_ALL).pick()
79 | }
80 |
81 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
82 | super.onActivityResult(requestCode, resultCode, data)
83 |
84 | if (REQUEST_CAMERA == requestCode && resultCode == Activity.RESULT_OK) {
85 |
86 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
87 | startGalleryView(result!!)
88 |
89 | } else if (REQUEST_FILE == requestCode && resultCode == Activity.RESULT_OK) {
90 |
91 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
92 | createDetailsFromResult(result!!.get(0))
93 |
94 | } else if (REQUEST_GALLERY == requestCode && resultCode == Activity.RESULT_OK) {
95 |
96 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
97 | startGalleryView(result!!)
98 |
99 | } else if (REQUEST_VIDEO == requestCode && resultCode == Activity.RESULT_OK) {
100 |
101 | val result = data?.getParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS)
102 | createDetailsFromResult(result!!.get(0))
103 | }
104 | }
105 |
106 | fun startGalleryView(kotResultList: ArrayList) {
107 | val intent = Intent(this, GalleryActivity::class.java)
108 | intent.putExtra(EXTRA_IMAGE_RESULT, kotResultList)
109 | startActivity(intent)
110 | }
111 |
112 | fun createDetailsFromResult(kotResult: KotResult) {
113 | //this function creates the details dialog from the result
114 | val detailsDialog = DetailsDialog.getInstance(kotResult)
115 | detailsDialog.show(fragmentManager, "DetailsDialog")
116 | }
117 |
118 | override fun onItemClick(position: Int) {
119 | //listener for items in adapter
120 | when (position) {
121 | 0 -> openGallery(false)
122 | 1 -> openGallery(true)
123 | 2 -> openFile(false)
124 | 3 -> openFile(true)
125 | 4 -> openCamera()
126 | 5 -> openVideo()
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/java/com/androidbuffer/kotlinfilepicker/KotlinFilePicker.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepicker
2 |
3 | import android.Manifest
4 | import android.app.Activity
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.content.pm.PackageManager
8 | import android.net.Uri
9 | import android.os.Build
10 | import android.os.Bundle
11 | import androidx.core.app.ActivityCompat
12 | import androidx.core.content.ContextCompat
13 | import androidx.appcompat.app.AppCompatActivity
14 | import android.util.Log
15 | import android.widget.Toast
16 |
17 |
18 | /**
19 | * Created by AndroidBuffer on 28/12/17.
20 | */
21 |
22 | public class KotlinFilePicker : AppCompatActivity() {
23 |
24 | private val TAG = KotlinFilePicker::class.java.canonicalName
25 | private val REQUEST_MEDIA_CAPTURE = 101
26 | private val REQUEST_MEDIA_FILE = 102
27 | private val REQUEST_MEDIA_GALLERY = 103
28 | private val REQUEST_MEDIA_VIDEO = 104
29 | private val PERMISSION_REQUEST_STORAGE = 100
30 | private var intentPick: Intent? = null
31 | private var isPermissionDenied = false
32 |
33 | override fun onCreate(savedInstanceState: Bundle?) {
34 | super.onCreate(savedInstanceState)
35 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
36 | if (handlePermissionCheck()) {
37 | handleIntent(intent)
38 | } else {
39 | val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
40 | ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_STORAGE)
41 | }
42 | } else {
43 | handleIntent(intent)
44 | }
45 | }
46 |
47 | override fun onStart() {
48 | super.onStart()
49 | if (isPermissionDenied) {
50 | KotUtil.openSettingsDialog(KotlinFilePicker@ this, true)
51 | }
52 | }
53 |
54 | private fun handlePermissionCheck(): Boolean {
55 | //check for the permission before accessing storage
56 | val permissionGranted = ContextCompat.checkSelfPermission(this,
57 | Manifest.permission.WRITE_EXTERNAL_STORAGE)
58 | if (permissionGranted == PackageManager.PERMISSION_GRANTED) {
59 | return true
60 | }
61 | return false
62 | }
63 |
64 | private fun handleIntent(intent: Intent) {
65 | //handle the intent passed from the client
66 | val selection = intent.getStringExtra(KotConstants.EXTRA_FILE_SELECTION)
67 | val isMultipleEnabled = intent.getBooleanExtra(KotConstants.EXTRA_MULTIPLE_ENABLED, false)
68 | when (selection) {
69 | KotConstants.SELECTION_TYPE_CAMERA -> {
70 | //camera intent
71 | val cameraIntent = KotUtil.getCameraIntent(this)
72 | if (cameraIntent == null) {
73 | throwException(getString(R.string.exception_msg_no_activity))
74 | return
75 | }
76 | intentPick = cameraIntent
77 | startActivityForResult(cameraIntent, REQUEST_MEDIA_CAPTURE)
78 | }
79 | KotConstants.SELECTION_TYPE_GALLERY -> {
80 | //gallery intent
81 | val mimeType = if (intent.hasExtra(KotConstants.EXTRA_FILE_MIME_TYPE)) {
82 | intent.getStringExtra(KotConstants.EXTRA_FILE_MIME_TYPE)
83 | } else {
84 | KotConstants.FILE_TYPE_IMAGE_ALL
85 | }
86 | val galleryIntent = KotUtil.getGalleryIntent(mimeType, isMultipleEnabled)
87 | startActivityForResult(galleryIntent, REQUEST_MEDIA_GALLERY)
88 | }
89 | KotConstants.SELECTION_TYPE_FILE -> {
90 | //file intent
91 | val mimeType = if (intent.hasExtra(KotConstants.EXTRA_FILE_MIME_TYPE)) {
92 | intent.getStringExtra(KotConstants.EXTRA_FILE_MIME_TYPE)
93 | } else {
94 | KotConstants.FILE_TYPE_FILE_ALL
95 | }
96 | val fileIntent = KotUtil.getFileIntent(mimeType, isMultipleEnabled)
97 | startActivityForResult(fileIntent, REQUEST_MEDIA_FILE)
98 | }
99 | KotConstants.SELECTION_TYPE_VIDEO -> {
100 | val videoIntent = KotUtil.getVideoIntent(this)
101 | if (videoIntent == null) {
102 | throwException(getString(R.string.exception_msg_no_activity))
103 | return
104 | }
105 | intentPick = videoIntent
106 | startActivityForResult(videoIntent, REQUEST_MEDIA_VIDEO)
107 | }
108 | else -> {
109 | throwException(getString(R.string.exception_msg_illegal_))
110 | }
111 | }
112 | }
113 |
114 | private fun showToast(msg: String) {
115 | //show a toast
116 | Toast.makeText(this, msg, Toast.LENGTH_LONG).show()
117 | }
118 |
119 | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
120 | super.onRequestPermissionsResult(requestCode, permissions, grantResults)
121 | if (PERMISSION_REQUEST_STORAGE == requestCode) {
122 | for (permission in grantResults) {
123 | if (permission == PackageManager.PERMISSION_DENIED) {
124 | isPermissionDenied = true
125 | KotUtil.openSettingsDialog(KotlinFilePicker@ this, true)
126 | return
127 | }
128 | }
129 | handleIntent(intent)
130 | }
131 | }
132 |
133 | private fun throwException(msg: String) {
134 | //throws a exception in case of exception
135 | try {
136 | finish()
137 | throw IllegalArgumentException(msg)
138 | } catch (exp: IllegalArgumentException) {
139 | exp.printStackTrace()
140 | }
141 | }
142 |
143 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
144 | super.onActivityResult(requestCode, resultCode, data)
145 | if (REQUEST_MEDIA_CAPTURE == requestCode && resultCode == Activity.RESULT_OK) {
146 | //received the camera intent data
147 | val cameraUri = getUriList(intentPick)
148 | deliverResultSuccess(cameraUri)
149 | } else if (REQUEST_MEDIA_FILE == requestCode && resultCode == Activity.RESULT_OK) {
150 | //do something
151 | val fileUri = getUriList(data)
152 | deliverResultSuccess(fileUri)
153 | } else if (REQUEST_MEDIA_GALLERY == requestCode && resultCode == Activity.RESULT_OK) {
154 | //do something
155 | val galleryUri = getUriList(data)
156 | deliverResultSuccess(galleryUri)
157 | } else if (REQUEST_MEDIA_VIDEO == requestCode && resultCode == Activity.RESULT_OK) {
158 | //do something
159 | val videoUri = getUriList(intentPick)
160 | deliverResultSuccess(videoUri)
161 | } else {
162 | deliverResultFailed()
163 | }
164 | }
165 |
166 | private fun deliverResultSuccess(uri: ArrayList) {
167 | //returns the result back to calling activity
168 | val intent = Intent()
169 | intent.putParcelableArrayListExtra(KotConstants.EXTRA_FILE_RESULTS,
170 | getKotResultFromUri(this, uri))
171 | setResult(Activity.RESULT_OK, intent)
172 | finish()
173 | }
174 |
175 | private fun getKotResultFromUri(context: Context, uri: ArrayList): ArrayList {
176 | //convert the uri to kotResult data class for file information
177 | val result = ArrayList()
178 | for (item in uri) {
179 | val file = KotUtil.getFileDetails(context, item!!)
180 | val fileSize = String.format("%1d KB", file!!.length() / 1024)
181 | val fileName = file.name
182 | val fileLocation = file.path
183 | val fileMimeType = KotUtil.getMimeType(fileLocation)
184 | val fileModified = KotUtil.getDateModified(file.lastModified())
185 | val kotResult = KotResult(item, fileName, fileSize, fileLocation, fileMimeType, fileModified)
186 | result.add(kotResult)
187 | Log.d(TAG, fileLocation)
188 | }
189 | return result
190 | }
191 |
192 | private fun deliverResultFailed() {
193 | //marks the unsuccessful results delivery to parent activity
194 | setResult(Activity.RESULT_CANCELED, Intent())
195 | finish()
196 | }
197 |
198 | override fun onBackPressed() {
199 | super.onBackPressed()
200 | deliverResultFailed()
201 | }
202 |
203 | private fun getUriList(intent: Intent?): ArrayList {
204 | //this returns a list of uri for passing back to parent intent
205 | val listUri = ArrayList()
206 | if (intent?.data == null) {
207 | //that means we may have data in clipdata
208 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
209 | val clipData = intent?.clipData
210 | (0 until clipData?.itemCount!!)
211 | .map { clipData.getItemAt(it) }
212 | .mapTo(listUri) { it.uri }
213 | } else {
214 | listUri.add(intent?.data)
215 | }
216 | } else {
217 | listUri.add(intent.data)
218 | }
219 | return listUri
220 | }
221 |
222 | }
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/java/com/androidbuffer/kotlinfilepicker/KotRequest.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepicker
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 |
6 | /**
7 | * Created by AndroidBuffer on 11/1/18.
8 | */
9 | public class KotRequest {
10 |
11 | /**
12 | * inner class for building the camera request
13 | */
14 | class Camera(context: Activity) {
15 |
16 | var requestCode = 101
17 | var intent: Intent
18 | var activity: Activity
19 |
20 | init {
21 | this.activity = context
22 | intent = Intent(context, KotlinFilePicker::class.java)
23 | intent.putExtra(KotConstants.EXTRA_FILE_SELECTION, KotConstants.SELECTION_TYPE_CAMERA)
24 | }
25 |
26 | /**
27 | * secondary constructor pass for initialization of camera class
28 | * @param requestCode by default it is 101 give a value to change it
29 | * @param context
30 | */
31 | constructor(context: Activity, requestCode: Int = 101) : this(context) {
32 | this.activity = context
33 | this.requestCode = requestCode
34 | }
35 |
36 | /**
37 | * set the request code & returns object of Camera class for launching the camera intent
38 | * @param requestCode for tracking in onActivityResult(...)
39 | * @return {@link Camera}
40 | */
41 | fun setRequestCode(requestCode: Int): Camera {
42 | this.requestCode = requestCode
43 | return this
44 | }
45 |
46 | /**
47 | * returns a intent for camera if initialized using constructor
48 | */
49 | fun getCameraIntent(): Intent {
50 | return intent
51 | }
52 |
53 | /**
54 | * starts intent to capture image from camera KotlinFilePicker.class
55 | */
56 | fun pick() {
57 | activity.startActivityForResult(intent, requestCode)
58 | }
59 | }
60 |
61 | /**
62 | * inner class for starting recording video
63 | */
64 | class Video(context: Activity) {
65 | private var activity: Activity
66 | private var requestCode = 102;
67 | private var intent: Intent
68 |
69 | init {
70 | this.activity = context
71 | intent = Intent(activity, KotlinFilePicker::class.java)
72 | intent.putExtra(KotConstants.EXTRA_FILE_SELECTION, KotConstants.SELECTION_TYPE_VIDEO)
73 | }
74 |
75 | /**
76 | * secondary constructor for changing the request code
77 | */
78 | constructor(context: Activity, requestCode: Int) : this(context) {
79 | this.activity = context
80 | this.requestCode = requestCode
81 | }
82 |
83 | /**
84 | * set the request code if missed in constructor initialization
85 | */
86 | fun setRequestCode(requestCode: Int): Video {
87 | this.requestCode = requestCode
88 | return this
89 | }
90 |
91 | /**
92 | * set the mime type of the file selection,
93 | * please note by default value is @see KotConstants FILE_TYPE_VIDEO_ALL
94 | * setting mime type will override the default one
95 | * @param mimeType
96 | */
97 | fun setMimeType(mimeType: String): Video {
98 | intent.putExtra(KotConstants.EXTRA_FILE_MIME_TYPE, mimeType)
99 | return this
100 | }
101 |
102 | /**
103 | * if set and initialized through constructor then we can get intent back,
104 | * use pick() instead if intent is not required
105 | * @return Intent
106 | */
107 | fun getVideoIntent(): Intent {
108 | return intent
109 | }
110 |
111 | /**
112 | * call this method after initialization in last
113 | */
114 | fun pick() {
115 | activity.startActivityForResult(intent, requestCode)
116 | }
117 | }
118 |
119 | /**
120 | * inner class for picking images from gallery
121 | */
122 | class Gallery(context: Activity) {
123 | private var activity: Activity
124 | private var requestCode = 103;
125 | private var intent: Intent
126 |
127 | init {
128 | this.activity = context
129 | intent = Intent(activity, KotlinFilePicker::class.java)
130 | intent.putExtra(KotConstants.EXTRA_FILE_SELECTION, KotConstants.SELECTION_TYPE_GALLERY)
131 | putMultiple(false)
132 | }
133 |
134 | /**
135 | * for selection single or multiple
136 | * @param multipleEnabled
137 | */
138 | private fun putMultiple(multipleEnabled: Boolean) {
139 | intent.putExtra(KotConstants.EXTRA_MULTIPLE_ENABLED, multipleEnabled)
140 | }
141 |
142 | /**
143 | * secondary constructor for changing the request code
144 | * @constructor pass activity and request code
145 | */
146 | constructor(context: Activity, requestCode: Int) : this(context) {
147 | this.activity = context
148 | this.requestCode = requestCode
149 | }
150 |
151 | /**
152 | * set the request code if missed in constructor initialization
153 | * @param requestCode
154 | * @return Gallery
155 | */
156 | fun setRequestCode(requestCode: Int): Gallery {
157 | this.requestCode = requestCode
158 | return this
159 | }
160 |
161 | /**
162 | * set the type selection single or multiple
163 | * @param isMultipleEnabled
164 | * @return Gallery
165 | */
166 | fun isMultiple(isMultipleEnabled: Boolean): Gallery {
167 | putMultiple(isMultipleEnabled)
168 | return this
169 | }
170 |
171 | /**
172 | * set the mime type of the file selection,
173 | * please note by default value is @see KotConstants FILE_TYPE_IMAGE_ALL
174 | * setting mime type will override the default one
175 | * @param mimeType
176 | */
177 | fun setMimeType(mimeType: String): Gallery {
178 | intent.putExtra(KotConstants.EXTRA_FILE_MIME_TYPE, mimeType)
179 | return this
180 | }
181 |
182 | /**
183 | * if set and initialized through constructor then we can get intent back
184 | * use pick() instead if intent is not required
185 | * @return @see Intent
186 | */
187 | fun getGalleryIntent(): Intent {
188 | return intent
189 | }
190 |
191 | /**
192 | * By default multiple selection is false @see multipleEnabled()
193 | * call this method after initialization in last
194 | */
195 | fun pick() {
196 | activity.startActivityForResult(intent, requestCode)
197 | }
198 | }
199 |
200 |
201 | class File(context: Activity) {
202 | private var activity: Activity
203 | private var requestCode = 104;
204 | private var intent: Intent
205 |
206 | init {
207 | this.activity = context
208 | intent = Intent(activity, KotlinFilePicker::class.java)
209 | intent.putExtra(KotConstants.EXTRA_FILE_SELECTION, KotConstants.SELECTION_TYPE_FILE)
210 | putMultiple(false)
211 | }
212 |
213 | /**
214 | * for selection single or multiple
215 | * @param multipleEnabled
216 | */
217 | private fun putMultiple(multipleEnabled: Boolean) {
218 | intent.putExtra(KotConstants.EXTRA_MULTIPLE_ENABLED, multipleEnabled)
219 | }
220 |
221 | /**
222 | * secondary constructor for changing the request code
223 | * @constructor pass activity and request code
224 | */
225 | constructor(context: Activity, requestCode: Int) : this(context) {
226 | this.activity = context
227 | this.requestCode = requestCode
228 | }
229 |
230 | /**
231 | * set the request code if missed in constructor initialization
232 | * @param requestCode
233 | * @return Gallery
234 | */
235 | fun setRequestCode(requestCode: Int): File {
236 | this.requestCode = requestCode
237 | return this
238 | }
239 |
240 | /**
241 | * set the type selection single or multiple
242 | * @param isMultipleEnabled
243 | * @return Gallery
244 | */
245 | fun isMultiple(isMultipleEnabled: Boolean): File {
246 | putMultiple(isMultipleEnabled)
247 | return this
248 | }
249 |
250 | /**
251 | * set the mime type of the file selection,
252 | * please note by default value is @see KotConstants FILE_TYPE_FILE_ALL
253 | * setting mime type will override the default one
254 | * @param mimeType
255 | */
256 | fun setMimeType(mimeType: String): File {
257 | intent.putExtra(KotConstants.EXTRA_FILE_MIME_TYPE, mimeType)
258 | return this
259 | }
260 |
261 | /**
262 | * if set and initialized through constructor then we can get intent back
263 | * use pick() instead if intent is not required
264 | * @return @see Intent
265 | */
266 | fun getFileIntent(): Intent {
267 | return intent
268 | }
269 |
270 | /**
271 | * By default multiple selection is false @see multipleEnabled()
272 | * call this method after initialization in last
273 | */
274 | fun pick() {
275 | activity.startActivityForResult(intent, requestCode)
276 | }
277 | }
278 |
279 |
280 | }
--------------------------------------------------------------------------------
/kotlinfilepicker/src/main/java/com/androidbuffer/kotlinfilepicker/KotUtil.kt:
--------------------------------------------------------------------------------
1 | package com.androidbuffer.kotlinfilepicker
2 |
3 | import android.app.Activity
4 | import android.content.*
5 | import android.database.Cursor
6 | import android.database.CursorIndexOutOfBoundsException
7 | import android.net.Uri
8 | import android.os.Build
9 | import android.os.Environment
10 | import android.provider.DocumentsContract
11 | import android.provider.MediaStore
12 | import android.provider.Settings
13 | import androidx.core.content.FileProvider
14 | import androidx.appcompat.app.AlertDialog
15 | import android.text.TextUtils
16 | import android.webkit.MimeTypeMap
17 | import java.io.File
18 | import java.text.SimpleDateFormat
19 | import java.util.*
20 | import java.util.regex.Pattern
21 |
22 |
23 | /**
24 | * Created by AndroidBuffer on 3/1/18.
25 | */
26 | class KotUtil {
27 |
28 | companion object {
29 |
30 | private fun authority(context: Context) = context.packageName + ".fileprovider"
31 |
32 | /**
33 | * @return {@link Intent}
34 | * @param context
35 | * returns a intent for camera
36 | */
37 | fun getCameraIntent(context: Context): Intent? {
38 | //returns a camera intent with temp file location
39 | val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
40 | if (cameraIntent.resolveActivity(context.packageManager) == null) {
41 | return null
42 | }
43 | val file = createImageFile(context)
44 | if (file != null) {
45 | val uri = getUriFromFile(context, file)
46 | grantUriPermission(context, cameraIntent, uri)
47 | cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
48 | }
49 | cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
50 | return cameraIntent
51 | }
52 |
53 | /**
54 | * @return {@link Intent}
55 | * @param context
56 | * returns a intent for video
57 | */
58 | fun getVideoIntent(context: Context): Intent? {
59 | //returns a video recording intent with temp file location
60 | val videoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
61 | if (videoIntent.resolveActivity(context.packageManager) == null) {
62 | return null
63 | }
64 | val file = createVideoFile(context)
65 | if (file != null) {
66 | val uri = getUriFromFile(context, file)
67 | grantUriPermission(context, videoIntent, uri)
68 | videoIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
69 | }
70 | videoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
71 | return videoIntent
72 | }
73 |
74 | /**
75 | * @return {@link Intent}
76 | * @param isMultiple
77 | * @param mimeType
78 | * multiple select works for only API level 18 and above
79 | */
80 | fun getGalleryIntent(mimeType: String, isMultiple: Boolean): Intent {
81 | val intent: Intent
82 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
83 | intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
84 | intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
85 | } else {
86 | intent = Intent(Intent.ACTION_GET_CONTENT)
87 | }
88 | intent.type = mimeType
89 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
90 | intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMultiple)
91 | }
92 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
93 | intent.addCategory(Intent.CATEGORY_OPENABLE)
94 | return intent
95 | }
96 |
97 | /**
98 | * @return {@link Intent}
99 | * @param mimeType
100 | * returns a intent for file
101 | */
102 | fun getFileIntent(mimeType: String, isMultiple: Boolean): Intent {
103 | val intent: Intent
104 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
105 | intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
106 | intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
107 | } else {
108 | intent = Intent(Intent.ACTION_GET_CONTENT)
109 | }
110 | intent.type = mimeType
111 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
112 | intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMultiple)
113 | }
114 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
115 | intent.addCategory(Intent.CATEGORY_OPENABLE)
116 | return intent
117 | }
118 |
119 | private fun createImageFile(context: Context): File? {
120 | //this returns a temp file object
121 | val fileName = "image_" + createFileName()
122 | val file = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
123 | return if (file == null) return null else File.createTempFile(fileName, ".jpg", file)
124 | }
125 |
126 | private fun createVideoFile(context: Context): File? {
127 | //this returns a temp file object
128 | val fileName = "video" + createFileName()
129 | val file = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)
130 | return if (file == null) return null else File.createTempFile(fileName, ".mp4", file)
131 | }
132 |
133 | private fun createFileName(): String {
134 | //this returns a string file name
135 | return SimpleDateFormat("ddMMyyyy_HHmmssSS", Locale.getDefault()).format(Date())
136 | }
137 |
138 | private fun getUriFromFile(context: Context, file: File): Uri {
139 | //returns uri from file object
140 | return FileProvider.getUriForFile(context, authority(context), file)
141 | }
142 |
143 | private fun grantUriPermission(context: Context, intent: Intent, uri: Uri) {
144 | //grant the uri permission to all the api versions
145 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
146 | intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
147 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
148 | val clip = ClipData.newUri(context.contentResolver, "camera", uri)
149 | intent.clipData = clip
150 | intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
151 | }
152 | }
153 |
154 | fun getFileDetails(context: Context, uri: Uri): File? {
155 | //get the details from uri
156 | var fileToReturn: File? = null
157 | try {
158 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
159 | val tables = arrayOf(MediaStore.Images.Media.DATA)
160 | val cursorLoader = CursorLoader(context, uri, tables, null, null, null)
161 | val cursor = cursorLoader.loadInBackground()
162 | val columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
163 |
164 | if (cursor.moveToNext()) {
165 | val result = cursor.getString(columnIndex)
166 | fileToReturn = File(result)
167 | }
168 | cursor.close()
169 |
170 | } else {
171 | fileToReturn = File(readPathFromUri(context, uri))
172 | }
173 | } catch (exp: CursorIndexOutOfBoundsException) {
174 | exp.printStackTrace()
175 | fileToReturn = File(uri.path)
176 | } catch (exp: NullPointerException) {
177 | exp.printStackTrace()
178 | fileToReturn = File(uri.path)
179 | } catch (exp: NumberFormatException) {
180 | exp.printStackTrace()
181 | fileToReturn = File(uri.path)
182 | }
183 | return fileToReturn
184 | }
185 |
186 | /**
187 | * get the extension from path of the file
188 | * @param url
189 | */
190 | fun getMimeType(url: String): String {
191 | val extension = getFileExtensionFromUrl(url)
192 | if (!extension.isEmpty()) {
193 | val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase())
194 | if (type.isNullOrBlank()) {
195 | return "*/*"
196 | } else {
197 | return type
198 | }
199 | } else {
200 | return "*/*"
201 | }
202 | }
203 |
204 | /**
205 | * get the date in format dd/MM/yyyy from long date
206 | * @param date
207 | * @return string date
208 | */
209 | fun getDateModified(date: Long): String {
210 | val simpleDate = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
211 | return simpleDate.format(date)
212 | }
213 |
214 | /**
215 | * get a file extension from the file path
216 | * @param url
217 | */
218 | fun getFileExtensionFromUrl(passedUrl: String): String {
219 | var url = passedUrl
220 | if (!TextUtils.isEmpty(url)) {
221 | val fragment = url.lastIndexOf('#')
222 | if (fragment > 0) {
223 | url = url.substring(0, fragment)
224 | }
225 |
226 | val query = url.lastIndexOf('?')
227 | if (query > 0) {
228 | url = url.substring(0, query)
229 | }
230 |
231 | val filenamePos = url.lastIndexOf('/')
232 | val filename = if (0 <= filenamePos) url.substring(filenamePos + 1) else url
233 |
234 | // if the filename contains special characters, we don't
235 | // consider it valid for our matching purposes except space:
236 | if (!filename.isEmpty() && Pattern.matches("[\\sa-zA-Z_0-9\\.\\-\\(\\)\\%]+", filename)) {
237 | val dotPos = filename.lastIndexOf('.')
238 | if (0 <= dotPos) {
239 | return filename.substring(dotPos + 1)
240 | }
241 | }
242 | }
243 |
244 | return ""
245 | }
246 |
247 | /**
248 | * returns the path from uri for API level 19 and up
249 | */
250 | @SuppressWarnings("NewApi")
251 | private fun readPathFromUri(context: Context, uri: Uri): String? {
252 |
253 | // DocumentProvider
254 | if (DocumentsContract.isDocumentUri(context, uri)) {
255 | // ExternalStorageProvider
256 | if (isExternalStorageDocument(uri)) {
257 | val docId = DocumentsContract.getDocumentId(uri)
258 | val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
259 | val type = split[0]
260 |
261 | if ("primary".equals(type, ignoreCase = true)) {
262 | return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
263 | }
264 | } else if (isDownloadsDocument(uri)) {
265 | val id = DocumentsContract.getDocumentId(uri)
266 | val contentUri = ContentUris.withAppendedId(
267 | Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)!!)
268 |
269 | return getDataColumn(context, contentUri, null, null)
270 | } else if (isMediaDocument(uri)) {
271 | val docId = DocumentsContract.getDocumentId(uri)
272 | val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
273 | val type = split[0]
274 |
275 | val contentUri = getContentUri(type)
276 |
277 | val selection = "_id=?"
278 | val selectionArgs = arrayOf(split[1])
279 | return getDataColumn(context, contentUri, selection, selectionArgs)
280 | }// MediaProvider
281 | // DownloadsProvider
282 | } else if ("content".equals(uri.scheme, ignoreCase = true)) {
283 | // Return the remote address
284 | return if (isGooglePhotosUri(uri)) {
285 | uri.lastPathSegment
286 | } else getDataColumn(context, uri, null, null)
287 | } else if ("file".equals(uri.scheme, ignoreCase = true)) {
288 | return uri.path
289 | }
290 |
291 | return null
292 | }
293 |
294 | /**
295 | * checks if the given uri is of type external storage
296 | */
297 | private fun isExternalStorageDocument(uri: Uri): Boolean {
298 | return "com.android.externalstorage.documents" == uri.authority
299 | }
300 |
301 | /**
302 | * checks if the given uri is of type downloads
303 | */
304 | private fun isDownloadsDocument(uri: Uri): Boolean {
305 | return "com.android.providers.downloads.documents" == uri.authority
306 | }
307 |
308 | /**
309 | * checks if the given uri is of type media document
310 | */
311 | private fun isMediaDocument(uri: Uri): Boolean {
312 | return "com.android.providers.media.documents" == uri.authority
313 | }
314 |
315 | /**
316 | * returns the column for specified uri
317 | */
318 | private fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array?): String? {
319 | var cursor: Cursor? = null
320 | val column = MediaStore.Images.Media.DATA
321 | val projection = arrayOf(column)
322 |
323 | try {
324 | cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
325 | if (cursor != null && cursor!!.moveToFirst()) {
326 | val column_index = cursor!!.getColumnIndexOrThrow(column)
327 | return cursor!!.getString(column_index)
328 | }
329 | } catch (e: IllegalArgumentException) {
330 | e.printStackTrace()
331 | } finally {
332 | if (cursor != null) {
333 | cursor!!.close()
334 | }
335 | }
336 | return null
337 | }
338 |
339 | /**
340 | * checks the type of uri
341 | */
342 | private fun getContentUri(type: String): Uri? {
343 | when (type) {
344 | "image" -> return MediaStore.Images.Media.EXTERNAL_CONTENT_URI
345 | "video" -> return MediaStore.Video.Media.EXTERNAL_CONTENT_URI
346 | "audio" -> return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
347 | }
348 | return null
349 | }
350 |
351 | /**
352 | * checks if the uri is of type google photos
353 | */
354 | private fun isGooglePhotosUri(uri: Uri): Boolean {
355 | return "com.google.android.apps.photos.content" == uri.authority
356 | }
357 |
358 | /**
359 | * opens the settings activity for app
360 | * @param activity
361 | * @param
362 | */
363 | fun openSettingsDialog(activity: Activity, wantToFinishOnOk: Boolean) {
364 | val alertBuilder = AlertDialog.Builder(activity)
365 |
366 | alertBuilder.setPositiveButton(R.string.dialog_settings_button, { dialogInterface, i ->
367 | val intent = Intent()
368 | intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
369 | val uri = Uri.fromParts("package", activity.packageName, null)
370 | intent.data = uri
371 | activity.startActivity(intent)
372 | })
373 | alertBuilder.setNegativeButton(R.string.dialog_finish_button, { dialogInterface, i ->
374 | dialogInterface.dismiss()
375 | if (wantToFinishOnOk) {
376 | activity.finish()
377 | }
378 | })
379 | alertBuilder.setMessage(R.string.dialog_permissions_message)
380 | alertBuilder.setCancelable(false)
381 | alertBuilder.create().show()
382 | }
383 |
384 | }
385 |
386 | }
--------------------------------------------------------------------------------