Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3fb1e8d
Merge pull request #68 from ChochaNaresh/Dev
ChochaNaresh May 27, 2025
1df651a
Merge pull request #69 from ChochaNaresh/Dev
ChochaNaresh May 30, 2025
16258af
Merge pull request #71 from ChochaNaresh/Dev
ChochaNaresh Jun 22, 2025
6b72166
docs: add migration guide for FilePicker library to outline key chang…
Jun 23, 2025
8d78abf
docs: add Privacy Policy document for the application
ChochaNaresh Jun 24, 2025
af69166
Merge remote-tracking branch 'origin/master'
ChochaNaresh Jun 24, 2025
0640837
refactor: enhance file picker result handling and simplify intent cre…
ChochaNaresh Jun 24, 2025
27e2620
refactor: update app name format and enhance build configuration
ChochaNaresh Jun 24, 2025
6c2ae72
feat: enhance sample app with file result display and update dependen…
Jun 26, 2025
3518943
refactor: update Proguard rules and enable edge-to-edge display
ChochaNaresh Jun 26, 2025
48da113
feat: update Kotlin JVM target, dependencies, and remove annotations
ChochaNaresh Jun 26, 2025
cd17392
fix: simplify Maven Central publishing configuration
Jun 27, 2025
a4b5e44
fix: update Maven Central publishing configuration to use automatic r…
Jun 27, 2025
f876430
fix: update Maven Central publishing configuration to use automatic r…
Jun 27, 2025
174b9c2
feat: enhance CI configuration to manage Gradle properties and upload…
Jun 27, 2025
bf2381f
fix: update CI configuration to correctly reference gradle.properties…
Jun 27, 2025
2123815
fix: remove unnecessary steps for restoring and uploading gradle.prop…
Jun 27, 2025
e85edd3
feat: handle empty selection in file pickers
Jul 2, 2025
8526eaf
build: update Gradle and dependencies
Aug 5, 2025
607735f
refactor: use BundleCompat.getParcelable for safer Parcelable retrieval
Aug 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ jobs:
- name: Checkout source
uses: actions/checkout@v4

- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
java-version: '21'

- name: Cache Gradle
uses: actions/cache@v3
Expand Down Expand Up @@ -56,11 +56,11 @@ jobs:
- name: Checkout source
uses: actions/checkout@v4

- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
java-version: '21'

- name: Cache Gradle
uses: actions/cache@v3
Expand Down Expand Up @@ -105,11 +105,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
java-version: '21'

- name: Make gradlew executable
run: chmod +x ./gradlew
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
.externalNativeBuild
.cxx
local.properties
/release-keystore.properties
68 changes: 68 additions & 0 deletions PrivacyPolicy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
**Privacy Policy**

This privacy policy applies to the File Picker app (hereby referred to as "Application") for mobile devices that was created by Naresh Chocha (hereby referred to as "Service Provider") as an Open Source service. This service is intended for use "AS IS".

**Information Collection and Use**

The Application collects information when you download and use it. This information may include information such as

* Your device's Internet Protocol address (e.g. IP address)
* The pages of the Application that you visit, the time and date of your visit, the time spent on those pages
* The time spent on the Application
* The operating system you use on your mobile device

The Application does not gather precise information about the location of your mobile device.

The Application collects your device's location, which helps the Service Provider determine your approximate geographical location and make use of in below ways:

* Geolocation Services: The Service Provider utilizes location data to provide features such as personalized content, relevant recommendations, and location-based services.
* Analytics and Improvements: Aggregated and anonymized location data helps the Service Provider to analyze user behavior, identify trends, and improve the overall performance and functionality of the Application.
* Third-Party Services: Periodically, the Service Provider may transmit anonymized location data to external services. These services assist them in enhancing the Application and optimizing their offerings.

The Service Provider may use the information you provided to contact you from time to time to provide you with important information, required notices and marketing promotions.

For a better experience, while using the Application, the Service Provider may require you to provide us with certain personally identifiable information. The information that the Service Provider request will be retained by them and used as described in this privacy policy.

**Third Party Access**

Only aggregated, anonymized data is periodically transmitted to external services to aid the Service Provider in improving the Application and their service. The Service Provider may share your information with third parties in the ways that are described in this privacy statement.

The Service Provider may disclose User Provided and Automatically Collected Information:

* as required by law, such as to comply with a subpoena, or similar legal process;
* when they believe in good faith that disclosure is necessary to protect their rights, protect your safety or the safety of others, investigate fraud, or respond to a government request;
* with their trusted services providers who work on their behalf, do not have an independent use of the information we disclose to them, and have agreed to adhere to the rules set forth in this privacy statement.

**Opt-Out Rights**

You can stop all collection of information by the Application easily by uninstalling it. You may use the standard uninstall processes as may be available as part of your mobile device or via the mobile application marketplace or network.

**Data Retention Policy**

The Service Provider will retain User Provided data for as long as you use the Application and for a reasonable time thereafter. If you'd like them to delete User Provided Data that you have provided via the Application, please contact them at [email protected] and they will respond in a reasonable time.

**Children**

The Service Provider does not use the Application to knowingly solicit data from or market to children under the age of 13.

The Service Provider does not knowingly collect personally identifiable information from children. The Service Provider encourages all children to never submit any personally identifiable information through the Application and/or Services. The Service Provider encourage parents and legal guardians to monitor their children's Internet usage and to help enforce this Policy by instructing their children never to provide personally identifiable information through the Application and/or Services without their permission. If you have reason to believe that a child has provided personally identifiable information to the Service Provider through the Application and/or Services, please contact the Service Provider ([email protected]) so that they will be able to take the necessary actions. You must also be at least 16 years of age to consent to the processing of your personally identifiable information in your country (in some countries we may allow your parent or guardian to do so on your behalf).

**Security**

The Service Provider is concerned about safeguarding the confidentiality of your information. The Service Provider provides physical, electronic, and procedural safeguards to protect information the Service Provider processes and maintains.

**Changes**

This Privacy Policy may be updated from time to time for any reason. The Service Provider will notify you of any changes to the Privacy Policy by updating this page with the new Privacy Policy. You are advised to consult this Privacy Policy regularly for any changes, as continued use is deemed approval of all changes.

This privacy policy is effective as of 2025-06-24

**Your Consent**

By using the Application, you are consenting to the processing of your information as set forth in this Privacy Policy now and as amended by us.

**Contact Us**

If you have any questions regarding privacy while using the Application, or have questions about the practices, please contact the Service Provider via email at [email protected].

* * *
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,47 @@ val pickerData = PickerData(
)
)
```
# Migration Guide: FilePicker Library

## Overview

This guide outlines the changes from the old code to the new `FilePicker` implementation, focusing on the transition from the Builder pattern to `ActivityResultContract`.

## Key Changes

1. **Package and Class Changes**:
The package has changed from `com.nareshchocha.filepickerlibrary.ui` to `com.nareshchocha.filepickerlibrary`.

2. **Removal of `Builder` Class**:
The `Builder` class is no longer needed. The new code utilizes `ActivityResultContract` for handling file picker actions.

3. **Introduction of `ActivityResultContracts`**:
File picker operations are now handled by specific `ActivityResultContract` classes, such as `ImageCapture`, `VideoCapture`, and `PickMedia`.

4. **Logging Support**:
A new `isLoggingEnabled` flag allows enabling logging in the contracts for debugging.

## Migration Steps

### 1. **Remove Builder Pattern**

The `Builder` class is no longer needed. You should transition to using `ActivityResultContracts` instead.

### 2. **Use `ActivityResultContracts`**

You can now handle file picker actions with specific contracts. For example:

- **Old Code**:
```kotlin
fun imageCaptureBuild(mImageCaptureConfig: ImageCaptureConfig?): Intent =
ImageCaptureActivity.getInstance(context, mImageCaptureConfig)
```
- **New Code**:
```kotlin
val imageCaptureResult = registerForActivityResult(FilePickerResultContracts.ImageCapture()) { result ->
// Handle result
}
```

---

Expand Down
39 changes: 7 additions & 32 deletions filepickerlibrary/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import com.vanniktech.maven.publish.SonatypeHost
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.android.library)
Expand Down Expand Up @@ -45,9 +45,10 @@ android {
sourceCompatibility = JavaVersion.valueOf(libs.versions.jdkVersion.get())
targetCompatibility = JavaVersion.valueOf(libs.versions.jdkVersion.get())
}

kotlinOptions {
jvmTarget = JavaVersion.valueOf(libs.versions.jdkVersion.get()).toString()
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
}

Expand All @@ -61,40 +62,14 @@ dependencies {
implementation(libs.androidx.material3)
implementation(libs.androidx.material.icons.extended)

// testing
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
testImplementation(libs.truth)
androidTestImplementation(libs.truth)

// testing compose
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)

// JUnit
testImplementation("junit:junit:4.13.2")

// AndroidX Test
testImplementation("androidx.test:core:1.5.0")
testImplementation("androidx.test:runner:1.5.2")
testImplementation("androidx.test.ext:junit:1.1.5")

// Robolectric for (Android framework simulation in unit tests)
testImplementation("org.robolectric:robolectric:4.10.3")

// Mockito for mock(ing)
testImplementation("org.mockito:mockito-core:5.7.0")
testImplementation("org.mockito:mockito-inline:5.2.0")
// For mocking final classes)
// Optional: If you( need to mock Kotlin classes better)
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
}

val automaticRelease: Boolean = true
mavenPublishing {
publishToMavenCentral(SonatypeHost.S01, true)
publishToMavenCentral(automaticRelease)
signAllPublications()
coordinates("io.github.chochanaresh", "filepicker", versionName)

Expand Down
35 changes: 1 addition & 34 deletions filepickerlibrary/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -1,34 +1 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
# -renamesourcefileattribute SourceFile
-keepclasseswithmembernames class com.nareshchocha.filepickerlibrary.models.**{
*;
}
#-keepclassmembers class * extends com.nareshchocha.filepickerlibrary.models.BaseConfig {
# *;
#}
#-keepclassmembers class * extends com.nareshchocha.filepickerlibrary.models.PickMediaType {
# *;
#}

-keepclassmembers class * extends androidx.appcompat.app.AppCompatActivity {
*;
}
-keep,allowobfuscation class com.nareshchocha.filepickerlibrary.** {*;}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.nareshchocha.filepickerlibrary
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.activity.result.contract.ActivityResultContract
import com.nareshchocha.filepickerlibrary.models.BaseConfig
import com.nareshchocha.filepickerlibrary.models.DocumentFilePickerConfig
Expand All @@ -17,12 +16,8 @@ import com.nareshchocha.filepickerlibrary.ui.activitys.ImageCaptureActivity
import com.nareshchocha.filepickerlibrary.ui.activitys.MediaFilePickerActivity
import com.nareshchocha.filepickerlibrary.ui.activitys.PopUpActivity
import com.nareshchocha.filepickerlibrary.ui.activitys.VideoCaptureActivity
import com.nareshchocha.filepickerlibrary.utilities.FileUtils
import com.nareshchocha.filepickerlibrary.utilities.appConst.Const
import com.nareshchocha.filepickerlibrary.utilities.getClipDataUris
import com.nareshchocha.filepickerlibrary.utilities.getDocumentFilePick
import com.nareshchocha.filepickerlibrary.utilities.getFilePathList
import com.nareshchocha.filepickerlibrary.utilities.getMediaIntent

/**
* A collection of ActivityResultContracts for different file picking operations.
Expand Down Expand Up @@ -90,21 +85,10 @@ class FilePickerResultContracts private constructor() {
* Returns a FilePickerResult that contains the URIs and file paths of the selected media.
*/
class PickMedia : ActivityResultContract<PickMediaConfig?, FilePickerResult>() {
private var context: Context? = null

override fun createIntent(
context: Context,
input: PickMediaConfig?
): Intent {
this.context = context
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
context.getMediaIntent(
input ?: PickMediaConfig()
)
} else {
MediaFilePickerActivity.getInstance(context, input ?: PickMediaConfig())
}
}
): Intent = MediaFilePickerActivity.getInstance(context, input ?: PickMediaConfig())

override fun parseResult(
resultCode: Int,
Expand All @@ -114,23 +98,17 @@ class FilePickerResultContracts private constructor() {
FilePickerResult(errorMessage = "Media selection failed or cancelled")
} else {
if (intent.clipData != null) {
val uris = intent.getClipDataUris()
val filePaths = uris.getFilePathList(context!!)
if (uris.isEmpty()) {
FilePickerResult(errorMessage = "No media selected")
} else {
FilePickerResult(
selectedFileUris = uris,
selectedFilePaths = filePaths
)
}
FilePickerResult(
selectedFileUris = intent.getClipDataUris(),
selectedFilePaths = intent.getStringArrayListExtra(Const.BundleExtras.FILE_PATH_LIST)
)
} else if (intent.data != null) {
FilePickerResult(
selectedFileUri = intent.data,
selectedFilePath = intent.data?.let { FileUtils.getRealPath(context!!, it) }
selectedFilePath = intent.getStringExtra(Const.BundleExtras.FILE_PATH)
)
} else {
FilePickerResult(errorMessage = "No media selected")
FilePickerResult(errorMessage = "No file selected")
}
}
}
Expand All @@ -140,19 +118,10 @@ class FilePickerResultContracts private constructor() {
* Returns a FilePickerResult that contains the URIs and file paths of the selected documents.
*/
class PickDocumentFile : ActivityResultContract<DocumentFilePickerConfig?, FilePickerResult>() {
private var context: Context? = null

override fun createIntent(
context: Context,
input: DocumentFilePickerConfig?
): Intent {
this.context = context
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
getDocumentFilePick(input ?: DocumentFilePickerConfig())
} else {
DocumentFilePickerActivity.getInstance(context, input ?: DocumentFilePickerConfig())
}
}
): Intent = DocumentFilePickerActivity.getInstance(context, input ?: DocumentFilePickerConfig())

override fun parseResult(
resultCode: Int,
Expand All @@ -162,23 +131,17 @@ class FilePickerResultContracts private constructor() {
FilePickerResult(errorMessage = "Document selection failed or cancelled")
} else {
if (intent.clipData != null) {
val uris = intent.getClipDataUris()
val filePaths = uris.getFilePathList(context!!)
if (uris.isEmpty()) {
FilePickerResult(errorMessage = "No document selected")
} else {
FilePickerResult(
selectedFileUris = uris,
selectedFilePaths = filePaths
)
}
FilePickerResult(
selectedFileUris = intent.getClipDataUris(),
selectedFilePaths = intent.getStringArrayListExtra(Const.BundleExtras.FILE_PATH_LIST)
)
} else if (intent.data != null) {
FilePickerResult(
selectedFileUri = intent.data,
selectedFilePath = intent.data?.let { FileUtils.getRealPath(context!!, it) }
selectedFilePath = intent.getStringExtra(Const.BundleExtras.FILE_PATH)
)
} else {
FilePickerResult(errorMessage = "No document selected")
FilePickerResult(errorMessage = "No file selected")
}
}
}
Expand Down Expand Up @@ -266,6 +229,7 @@ class FilePickerResultContracts private constructor() {
resultCode,
intent
)

else -> FilePickerResult(errorMessage = "Unknown file type")
}
}
Expand Down
Loading
Loading