Skip to content

zipswich/android-file-chooser

 
 

Repository files navigation

android-file-chooser

Android Arsenal Download Release Build Status

android-file-library is a lightweight file/folder chooser.

Overview

banner

Snapshots

Demo Application

A demo-app can be installed from Play Store.

Get it on Google Play

Changes

x1.2.0 branch

  • In progress
  • uses AndroidX
  • Done:
    • Keyboard supports: process SPACE and ENTER up event;
    • file list no focus when dailog first showing;
    • better storage media detect algorithm for Android M+;
    • no WRITE_EXTERNAL_STORAGE requests if not enableOptions(true);
    • after requested permissions, try showing dialog again instead of return directly;

v1.1.x patches on master

  • no WRITE_EXTERNAL_STORAGE requests if not enableOptions(true);

  • after requested permissions, try showing dialog again instead of return directly;

  • #42: onBackPressedListener not fired.

    Now, use withCancelListener to handle back key. see also below

v1.1.x

  • create new folder on the fly, and the optional multiple select mode for developer, thx Guiorgy and his android-smbfile-chooser
  • Up (..) on the primary storage root will be replaced with .. SDCard, it allows to jump to external storage such as a SDCard and going back available too.
  • DPad supports, arrow keys supports (#30)
  • ...

Usages

Configuration

build.gradle

android-file-chooser was released at jcenter, declare deps with:

implementation 'com.obsez.android.lib.filechooser:filechooser:$android_file_chooser_version'

for the newest version(s), looking up the badges above.

taste the fresh

there is a way to taste the master branch with jitpack.io:

  1. add the jitpack repository url to your root build.gradle:
allprojects {
    repositories {
        google()
        jcenter()
        maven { url "https://jitpack.io" }
    }
}
  1. import android-file-chooser
implementation 'com.github.hedzr:android-file-chooser:master-SNAPSHOT'
// implementation 'com.github.hedzr:android-file-chooser:v1.1.10'

Codes

FileChooser android library give a simple file/folder chooser in single call:

Choose a Folder

    new ChooserDialog().with(this)
            .withFilter(true, false)
        	.withStartFile(startingDir)
        	// to handle the result(s)
            .withChosenListener(new ChooserDialog.Result() {
                @Override
                public void onChoosePath(String path, File pathFile) {
                    Toast.makeText(MainActivity.this, "FOLDER: " + path, Toast.LENGTH_SHORT).show();
                }
            })
            .build()
            .show();

Choose a File

    new ChooserDialog().with(this)
            .withStartFile(path)
            .withChosenListener(new ChooserDialog.Result() {
                @Override
                public void onChoosePath(String path, File pathFile) {
                    Toast.makeText(MainActivity.this, "FILE: " + path, Toast.LENGTH_SHORT).show();
                }
            })
        	// to handle the back key pressed or clicked outside the dialog:
        	.withOnCancelListener(new DialogInterface.OnCancelListener() {
    			public void onCancel(DialogInterface dialog) {
			        Log.d("CANCEL", "CANCEL");
			        dialog.cancel(); // MUST have
    			}
			})
            .build()
            .show();

Wild-match

    new ChooserDialog().with(this)
            .withFilter(false, false, "jpg", "jpeg", "png")
            .withStartFile(path)
            .withResources(R.string.title_choose_file, R.string.title_choose, R.string.dialog_cancel)
            .withChosenListener(new ChooserDialog.Result() {
                @Override
                public void onChoosePath(String path, File pathFile) {
                    Toast.makeText(MainActivity.this, "FILE: " + path, Toast.LENGTH_SHORT).show();
                }
            })
            .build()
            .show();

Regex filter

    new ChooserDialog().with(this)
            .withFilterRegex(false, false, ".*\\.(jpe?g|png)")
            .withStartFile(path)
            .withResources(R.string.title_choose_file, R.string.title_choose, R.string.dialog_cancel)
            .withChosenListener(new ChooserDialog.Result() {
                @Override
                public void onChoosePath(String path, File pathFile) {
                    Toast.makeText(NewMainActivity.this, "FILE: " + path, Toast.LENGTH_SHORT).show();
                }
            })
            .build()
            .show();

Date Format String

Since 1.1.3, new builder options withDateFormat(String) added.

    new ChooserDialog().with(this)
            .withFilter(true, false)
            .withStartFile(startingDir)
            .withDateFormat("HH:mm")    // see also SimpleDateFormat format specifiers
            .withChosenListener(new ChooserDialog.Result() {
                @Override
                public void onChoosePath(String path, File pathFile) {
                    Toast.makeText(MainActivity.this, "FOLDER: " + path, Toast.LENGTH_SHORT).show();
                }
            })
            .build()
            .show();

Modify Icon or View Layout of AlertDialog:

Since 1.1.6, 2 new options are available:

    new ChooserDialog().with(this)
            .withFilter(true, false)
            .withStartFile(startingDir)
            .withIcon(R.drawable.ic_file_chooser)
            .withLayoutView(R.layout.alert_file_chooser)
            .withChosenListener(new ChooserDialog.Result() {
                @Override
                public void onChoosePath(String path, File pathFile) {
                    Toast.makeText(MainActivity.this, "FOLDER: " + path, Toast.LENGTH_SHORT).show();
                }
            })
            .build()
            .show();

Customizable NegativeButton

1.1.7 or Higher, try withNegativeButton() and withNegativeButtonListener() instead of withOnBackPressedListener().


withOnBackPressedListener

deprecated.

onCancelListener

onCancelListener will be triggered on back pressed or clicked outside of dialog.

You MUST invoke dialog.cancel() while override the default onCancelListener :

.withOnCancelListener(new DialogInterface.OnCancelListener() {
    public void onCancel(DialogInterface dialog) {
        Log.d("CANCEL", "CANCEL");
        dialog.cancel(); // MUST have
    }
})

New calling chain

1.1.7+, new constructor ChooserDialog(context) can simplify the chain invoking, such as:

    new ChooserDialog(this)
            .withFilter(true, false)
            .withStartFile(startingDir)
            ...

And, old style is still available. No need to modify your existing codes.

withRowLayoutView(resId)

1.1.8+. Now you can customize each row.

withFileIcons

1.1.9+. withFileIcons(resolveMime, fileIcon, folderIcon) and withFileIconsRes(resolveMime, fileIconResId, folderIconResId) allow user-defined file/folder icon.

resolveMime: true means that DirAdapter will try get icon from the associated app with the file's mime type.

    new ChooserDialog(ctx)
            .withStartFile(_path)
            .withResources(R.string.title_choose_any_file, R.string.title_choose, R.string.dialog_cancel)
            .withFileIconsRes(false, R.mipmap.ic_my_file, R.mipmap.ic_my_folder)
            .withChosenListener(new ChooserDialog.Result() {
                @Override
                public void onChoosePath(String path, File pathFile) {
                    Toast.makeText(ctx, "FILE: " + path, Toast.LENGTH_SHORT).show();
                }
            })
            .build()
            .show();

withAdapterSetter(setter)

1.1.9+. a AdapterSetter can be use to customize the DirAdapter.

            .withAdapterSetter(new ChooserDialog.AdapterSetter() {
                @Override
                public void apply(DirAdapter adapter) {
                    adapter.setDefaultFileIcon(fileIcon);
                    adapter.setDefaultFolderIcon(folderIcon);
                    adapter.setResolveFileType(tryResolveFileTypeAndIcon);
                }
            })

withNavigateUpTo(CanNavigateUp)

1.1.10+. withNavigateUpTo

                .withNavigateUpTo(new ChooserDialog.CanNavigateUp() {
                    @Override
                    public boolean canUpTo(File dir) {
                        return true;
                    }
                })

withNavigateTo(CanNavigateTo)

1.1.10+. withNavigateTo

                .withNavigateTo(new ChooserDialog.CanNavigateTo() {
                    @Override
                    public boolean canNavigate(File dir) {
                        return true;
                    }
                })

enableOptions(true)

a tri-dot menu icon will be shown at bottom left corner. this icon button allows end user to create new folder on the fly or delete one.

further tunes:

  • withOptionResources(@StringRes int createDirRes, @StringRes int deleteRes, @StringRes int newFolderCancelRes, @StringRes int newFolderOkRes)
  • withOptionIcons(@DrawableRes int optionsIconRes, @DrawableRes int createDirIconRes, @DrawableRes int deleteRes)
  • withNewFolderFilter(NewFolderFilter filter)
  • withOnBackPressedListener(OnBackPressedListener listener)
  • withOnLastBackPressedListener(OnBackPressedListener listener)

see the sample codes in demo app.

NOTE:

  1. extra WRITE_EXTERNAL_STORAGE permission should be declared in your AndroidManifest.xml.
  2. we'll ask the extra runtime permission to WRITE_EXTERNAL_STORAGE on Android M and higher too.

disableTitle(true)

as named as working.

psuedo .. SDCard Storage and .. Primary Storage


Under Kotlin

class MyFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val root = inflater.inflate(R.layout.fragment_book, container, false)
        root.upload_button.setOnClickListener { _: View ->
            ChooserDialog().with(activity)
                    .withStartFile(Environment.getExternalStorageDirectory().absolutePath)
                    // .withStartFile(Environment.getExternalStorageState()+"/")
                    .withFilterRegex(false, false, ".*\\.(jpe?g|png)")
                    .withChosenListener { path, pathFile -> activity!!.toast("FILE: $path / $pathFile") }
                    .build()
                    .show()
        }

        return root
    }
}

And:

        ChooserDialog(context)
                .withFilterRegex(false, true, ".*\\.(jpe?g|png)")
                .withStartFile(startPath)
                .withResources(R.string.title_choose_file, R.string.title_choose, R.string.dialog_cancel)
                .withChosenListener { path, pathFile ->
                    Toast.makeText(context, "FILE: $path; PATHFILE: $pathFile", Toast.LENGTH_SHORT).show()

                    //_path = path
                    //_tv.setText(_path)
                    ////_iv.setImageURI(Uri.fromFile(pathFile));
                    //_iv.setImageBitmap(ImageUtil.decodeFile(pathFile))
                }
                .withNavigateUpTo { true }
                .withNavigateTo { true }
                .build()
                .show()

Build me

1. legacy

cat >keystore.properties<<EOF
keyAlias=youKeyAlias
keyPassword=password
storeFile=/Users/me/android-file-chooser.keystore
storePassword=password
EOF
git clone [email protected]:hedzr/android-file-chooser.git somewhere
cd somewhere
./gradlew assembleDebug

you'd better generate a new file android-file-chooser.keystore at homedir or else. such as: keytool -genkey -alias android.keystore -keyalg RSA -validity 20000 -keystore android.keystore, see also Sign an app. Or, erase the KS_PATH lines and signature section in app/build.gradle.

2. current

just fork and build me currently.

Contrib

Contributions and translations are welcome.

Feedback

feel free to make an new issue.

Acknowledges

many peoples report or contribute to improve me, but only a few of them be put here — it's hard to list all.

License

Copyright 2015-2018 Hedzr Yeh.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

About

a lightweight file/folder chooser or picker

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 99.4%
  • Kotlin 0.6%