├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── feature_request.yml
└── workflows
│ ├── DeleteWorkflowRuns.yml
│ └── android.yml
├── .gitignore
├── .idea
├── .gitignore
├── .name
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── compiler.xml
├── deploymentTargetDropDown.xml
├── gradle.xml
├── misc.xml
└── vcs.xml
├── .replit
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── app_icon-playstore.png
│ ├── assets
│ ├── font
│ │ └── JetBrainsMono-Regular.ttf
│ └── textmate
│ │ ├── README.md
│ │ ├── dark.json
│ │ ├── json
│ │ ├── language-configuration.json
│ │ └── syntax
│ │ │ └── json.tmLanguage.json
│ │ ├── kotlin
│ │ ├── language-configuration.json
│ │ └── syntax
│ │ │ └── kotlin.tmLanguage
│ │ ├── light.tmTheme
│ │ └── xml
│ │ ├── language-configuration.json
│ │ └── syntax
│ │ └── xml.tmLanguage.json
│ ├── ic_launcher-playstore.png
│ ├── java
│ └── com
│ │ └── raival
│ │ └── fileexplorer
│ │ ├── App.kt
│ │ ├── activity
│ │ ├── BaseActivity.kt
│ │ ├── MainActivity.kt
│ │ ├── SettingsActivity.kt
│ │ ├── TextEditorActivity.kt
│ │ ├── adapter
│ │ │ └── BookmarksAdapter.kt
│ │ ├── editor
│ │ │ ├── autocomplete
│ │ │ │ ├── CustomCompletionItemAdapter.kt
│ │ │ │ └── CustomCompletionLayout.kt
│ │ │ ├── language
│ │ │ │ ├── java
│ │ │ │ │ ├── JavaCodeLanguage.kt
│ │ │ │ │ └── JavaFormatter.kt
│ │ │ │ ├── json
│ │ │ │ │ ├── JsonFormatter.kt
│ │ │ │ │ └── JsonLanguage.kt
│ │ │ │ ├── kotlin
│ │ │ │ │ └── KotlinCodeLanguage.kt
│ │ │ │ └── xml
│ │ │ │ │ └── XmlLanguage.kt
│ │ │ ├── scheme
│ │ │ │ ├── DarkScheme.kt
│ │ │ │ └── LightScheme.kt
│ │ │ └── view
│ │ │ │ └── SymbolInputView.kt
│ │ └── model
│ │ │ ├── MainViewModel.kt
│ │ │ └── TextEditorViewModel.kt
│ │ ├── common
│ │ ├── BackgroundTask.kt
│ │ ├── dialog
│ │ │ ├── CustomDialog.kt
│ │ │ └── OptionsDialog.kt
│ │ └── view
│ │ │ ├── BottomBarView.kt
│ │ │ └── TabView.kt
│ │ ├── extension
│ │ ├── File.kt
│ │ ├── Int.kt
│ │ ├── Long.kt
│ │ └── String.kt
│ │ ├── glide
│ │ ├── FileExplorerGlideModule.java
│ │ ├── apk
│ │ │ ├── ApkIconDataFetcher.java
│ │ │ ├── ApkIconModelLoader.java
│ │ │ └── ApkIconModelLoaderFactory.java
│ │ ├── icon
│ │ │ ├── IconDataFetcher.java
│ │ │ ├── IconModelLoader.java
│ │ │ └── IconModelLoaderFactory.java
│ │ └── model
│ │ │ └── IconRes.kt
│ │ ├── tab
│ │ ├── BaseDataHolder.kt
│ │ ├── BaseTabFragment.kt
│ │ ├── apps
│ │ │ ├── AppsTabDataHolder.kt
│ │ │ ├── AppsTabFragment.kt
│ │ │ ├── adapter
│ │ │ │ └── AppListAdapter.kt
│ │ │ ├── model
│ │ │ │ └── Apk.kt
│ │ │ └── resolver
│ │ │ │ └── ApkResolver.kt
│ │ └── file
│ │ │ ├── FileExplorerTabDataHolder.kt
│ │ │ ├── FileExplorerTabFragment.kt
│ │ │ ├── adapter
│ │ │ ├── FileListAdapter.kt
│ │ │ └── PathHistoryAdapter.kt
│ │ │ ├── dialog
│ │ │ ├── FileInfoDialog.kt
│ │ │ ├── SearchDialog.kt
│ │ │ └── TasksDialog.kt
│ │ │ ├── misc
│ │ │ ├── APKSignerUtils.kt
│ │ │ ├── BuildUtils.kt
│ │ │ ├── FileMimeTypes.kt
│ │ │ ├── FileOpener.kt
│ │ │ ├── FileUtils.kt
│ │ │ ├── IconHelper.kt
│ │ │ ├── ZipUtils.kt
│ │ │ └── md5
│ │ │ │ ├── HashUtils.kt
│ │ │ │ ├── MessageDigestAlgorithm.kt
│ │ │ │ └── StringUtils.kt
│ │ │ ├── model
│ │ │ ├── FileItem.kt
│ │ │ └── Task.kt
│ │ │ ├── observer
│ │ │ └── FileListObserver.kt
│ │ │ ├── options
│ │ │ └── FileOptionsHandler.kt
│ │ │ └── task
│ │ │ ├── CompressTask.kt
│ │ │ ├── CopyTask.kt
│ │ │ ├── CutTask.kt
│ │ │ └── ExtractTask.kt
│ │ └── util
│ │ ├── Log.kt
│ │ ├── PrefsUtils.kt
│ │ └── Utils.kt
│ └── res
│ ├── drawable-v24
│ └── apk_placeholder.webp
│ ├── drawable
│ ├── app_icon_foreground.xml
│ ├── archive_file_extension.png
│ ├── code_file_extension.png
│ ├── doc_file_extension.png
│ ├── fastscroll_thumb.xml
│ ├── font_file_extension.png
│ ├── ic_baseline_add_24.xml
│ ├── ic_baseline_arrow_back_24.xml
│ ├── ic_baseline_assignment_24.xml
│ ├── ic_baseline_bookmark_add_24.xml
│ ├── ic_baseline_bookmark_remove_24.xml
│ ├── ic_baseline_bug_report_24.xml
│ ├── ic_baseline_chevron_right_24.xml
│ ├── ic_baseline_delete_sweep_24.xml
│ ├── ic_baseline_file_copy_24.xml
│ ├── ic_baseline_folder_24.xml
│ ├── ic_baseline_folder_open_24.xml
│ ├── ic_baseline_info_24.xml
│ ├── ic_baseline_layers_24.xml
│ ├── ic_baseline_logout_24.xml
│ ├── ic_baseline_more_vert_24.xml
│ ├── ic_baseline_open_in_browser_24.xml
│ ├── ic_baseline_open_in_new_24.xml
│ ├── ic_baseline_restart_alt_24.xml
│ ├── ic_baseline_save_24.xml
│ ├── ic_baseline_select_all_24.xml
│ ├── ic_baseline_sort_24.xml
│ ├── ic_launcher_foreground.xml
│ ├── ic_round_code_24.xml
│ ├── ic_round_compress_24.xml
│ ├── ic_round_content_cut_24.xml
│ ├── ic_round_delete_forever_24.xml
│ ├── ic_round_edit_24.xml
│ ├── ic_round_edit_note_24.xml
│ ├── ic_round_exit_to_app_24.xml
│ ├── ic_round_home_24.xml
│ ├── ic_round_insert_drive_file_24.xml
│ ├── ic_round_key_24.xml
│ ├── ic_round_manage_search_24.xml
│ ├── ic_round_menu_24.xml
│ ├── ic_round_play_arrow_24.xml
│ ├── ic_round_redo_24.xml
│ ├── ic_round_search_24.xml
│ ├── ic_round_settings_24.xml
│ ├── ic_round_share_24.xml
│ ├── ic_round_tab_24.xml
│ ├── ic_round_timelapse_24.xml
│ ├── ic_round_undo_24.xml
│ ├── image_file_extension.png
│ ├── java_file_extension.png
│ ├── kt_file_extension.png
│ ├── music_file_extension.png
│ ├── pdf_file_extension.png
│ ├── powerpoint_file_extension.png
│ ├── sql_file_extension.png
│ ├── svg_file_extension.png
│ ├── txt_file_extension.png
│ ├── unknown_file_extension.png
│ ├── vector_file_extension.png
│ ├── video_file_extension.png
│ ├── xls_file_extension.png
│ └── xml_file_extension.png
│ ├── layout
│ ├── activity_main.xml
│ ├── activity_main_drawer.xml
│ ├── activity_main_drawer_bookmark_item.xml
│ ├── apps_tab_app_item.xml
│ ├── apps_tab_fragment.xml
│ ├── bottom_bar_menu_item.xml
│ ├── common_custom_dialog.xml
│ ├── common_options_dialog.xml
│ ├── common_options_dialog_item.xml
│ ├── file_explorer_tab_file_item.xml
│ ├── file_explorer_tab_fragment.xml
│ ├── file_explorer_tab_info_dialog.xml
│ ├── file_explorer_tab_info_dialog_item.xml
│ ├── file_explorer_tab_path_history_view.xml
│ ├── file_explorer_tab_placeholder.xml
│ ├── file_explorer_tab_task_dialog.xml
│ ├── file_explorer_tab_task_dialog_item.xml
│ ├── input.xml
│ ├── progress_view.xml
│ ├── search_fragment.xml
│ ├── settings_activity.xml
│ ├── text_editor_activity.xml
│ └── text_editor_completion_item.xml
│ ├── menu
│ ├── main_menu.xml
│ ├── tab_menu.xml
│ └── text_editor_menu.xml
│ ├── mipmap-anydpi-v26
│ ├── app_icon.xml
│ └── app_icon_round.xml
│ ├── mipmap-hdpi
│ ├── app_icon.png
│ └── app_icon_round.png
│ ├── mipmap-mdpi
│ ├── app_icon.png
│ └── app_icon_round.png
│ ├── mipmap-xhdpi
│ ├── app_icon.png
│ └── app_icon_round.png
│ ├── mipmap-xxhdpi
│ ├── app_icon.png
│ └── app_icon_round.png
│ ├── mipmap-xxxhdpi
│ ├── app_icon.png
│ └── app_icon_round.png
│ ├── values-night
│ ├── colors.xml
│ └── themes.xml
│ ├── values
│ ├── app_icon_background.xml
│ ├── colors.xml
│ ├── ic_launcher_background.xml
│ ├── strings.xml
│ └── themes.xml
│ └── xml
│ └── provider_paths.xml
├── assets
├── screenshot1.png
├── screenshot2.png
└── screenshot3.png
├── build.gradle
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── full_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── img1.jpg
│ │ ├── img2.jpg
│ │ └── img3.jpg
│ └── short_description.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── testkey.keystore
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | # Original source: https://github.com/AndroidIDEOfficial/AndroidIDE/blob/main/.github/ISSUE_TEMPLATE/BUG.yml
2 | name: Bug Report
3 | description: File a bug report
4 | title: "[Bug]: "
5 | labels: ["bug"]
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to fill out this bug report! Please provide a proper title and clear description to this issue.
11 |
12 | - type: textarea
13 | id: what-happened
14 | attributes:
15 | label: What happened?
16 | description: Describe the issue properly.
17 | placeholder: Describe the error
18 | validations:
19 | required: true
20 | - type: textarea
21 | id: expected-behavior
22 | attributes:
23 | label: What's the expected behavior?
24 | description: Tell us what is the expected behavior.
25 | placeholder: Describe the expected behavior.
26 | validations:
27 | required: true
28 | - type: dropdown
29 | id: version
30 | attributes:
31 | label: What version of File Explorer you are using?
32 | multiple: false
33 | options:
34 | - latest GitHub action
35 | - latest release (v1.1.0)
36 | - from IzzyOnDroid
37 | validations:
38 | required: true
39 | - type: textarea
40 | id: logs
41 | attributes:
42 | label: Relevant log output
43 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
44 | render: shell
45 | - type: checkboxes
46 | id: not-a-duplicate
47 | attributes:
48 | label: Duplicate issues
49 | description: Please make sure that there are no similar issues opened. Duplicate issues will be closed directly. If there are any similar looking issues, leave a comment there.
50 | options:
51 | - label: This issue has not been reported yet.
52 | required: true
53 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Requesting a new feature
3 | title: "[Feature]: "
4 | labels: ["feature request"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thanks for taking the time to fill out this feature request! Please provide a proper title and clear description to this feature. You must request one feature at a time, if you want to request multiple features, create a new request for each one.
10 |
11 | - type: textarea
12 | id: feature-details
13 | attributes:
14 | label: Feature Description
15 | description: Describe the feature properly.
16 | placeholder: Describe the feature
17 | validations:
18 | required: true
19 |
20 | - type: textarea
21 | id: implementation
22 | attributes:
23 | label: How can this feature be implemented?
24 | description: Tell us any idea on how can we implement this feature
25 | placeholder: Describe the possible implementation
26 | validations:
27 | required: false
28 |
29 | - type: checkboxes
30 | id: not-a-duplicate
31 | attributes:
32 | label: Duplicate feature
33 | description: Please make sure that there are no similar feature opened. Duplicate feature will be closed directly. If there are any similar looking features, leave a comment there.
34 | options:
35 | - label: This feature has not been requested yet.
36 | required: true
37 |
--------------------------------------------------------------------------------
/.github/workflows/DeleteWorkflowRuns.yml:
--------------------------------------------------------------------------------
1 | # Original at https://github.com/Sketchware-Pro/Sketchware-Pro/blob/main/.github/workflows/DeleteWorkflowRuns.yml
2 |
3 | name: 'Delete old workflow runs'
4 | on:
5 | workflow_dispatch:
6 | inputs:
7 | days:
8 | description: 'Number of retains days.'
9 | required: true
10 | default: '20'
11 |
12 | minimum_runs:
13 | description: 'The minimum runs to keep for each workflow.'
14 | required: true
15 | default: '6'
16 |
17 | jobs:
18 | deleteWorkflowRuns:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: Delete workflow runs
22 | uses: Mattraks/delete-workflow-runs@v2.0.3
23 | with:
24 | token: ${{ github.token }}
25 | repository: ${{ github.repository }}
26 | retain_days: ${{ github.event.inputs.days }}
27 | keep_minimum_runs: ${{ github.event.inputs.minimum_runs }}
28 |
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | # Original at https://github.com/Sketchware-Pro/Sketchware-Pro/blob/main/.github/workflows/android.yml
2 |
3 | name: Android CI
4 |
5 | on:
6 | push:
7 | paths:
8 | - '.github/workflows/android.yml'
9 | - 'app/**'
10 | - 'build-logic/**'
11 | - 'kotlinc/**'
12 | - 'gradle/**'
13 | - 'build.gradle'
14 | - 'gradle.properties'
15 | - 'gradlew'
16 | - 'gradlew.bat'
17 | - 'public-stable-ids.txt'
18 | - 'settings.gradle'
19 | pull_request:
20 | paths:
21 | - '.github/workflows/android.yml'
22 | - 'app/**'
23 | - 'build-logic/**'
24 | - 'kotlinc/**'
25 | - 'gradle/**'
26 | - 'build.gradle'
27 | - 'gradle.properties'
28 | - 'gradlew'
29 | - 'gradlew.bat'
30 | - 'public-stable-ids.txt'
31 | - 'settings.gradle'
32 | workflow_dispatch:
33 |
34 | jobs:
35 | build:
36 | name: Build release APK
37 | runs-on: ubuntu-latest
38 | steps:
39 | - uses: actions/checkout@v3
40 |
41 | - name: Set up JDK 18
42 | uses: actions/setup-java@v3
43 | with:
44 | java-version: 18
45 | distribution: temurin
46 | cache: gradle
47 |
48 | - name: Grant execute permissions for gradlew
49 | run: chmod +x gradlew
50 |
51 | - name: Build release apk
52 | uses: gradle/gradle-build-action@v2
53 | with:
54 | arguments: assembleRelease
55 |
56 | - name: Upload APK
57 | uses: actions/upload-artifact@v3
58 | with:
59 | name: apk-release
60 | path: app/build/outputs/apk/release
61 |
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | File Explorer
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | xmlns:android
18 |
19 | ^$
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | xmlns:.*
29 |
30 | ^$
31 |
32 |
33 | BY_NAME
34 |
35 |
36 |
37 |
38 |
39 |
40 | .*:id
41 |
42 | http://schemas.android.com/apk/res/android
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | .*:name
52 |
53 | http://schemas.android.com/apk/res/android
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | name
63 |
64 | ^$
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | style
74 |
75 | ^$
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | .*
85 |
86 | ^$
87 |
88 |
89 | BY_NAME
90 |
91 |
92 |
93 |
94 |
95 |
96 | .*
97 |
98 | http://schemas.android.com/apk/res/android
99 |
100 |
101 | ANDROID_ATTRIBUTE_ORDER
102 |
103 |
104 |
105 |
106 |
107 |
108 | .*
109 |
110 | .*
111 |
112 |
113 | BY_NAME
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.replit:
--------------------------------------------------------------------------------
1 | language = "bash"
2 | run = ""
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](https://github.com/Raival-e/File-Explorer/blob/master/LICENSE)
3 | 
4 | [](https://github.com/Raival-e/File-Explorer/releases)
5 | 
6 |
7 | > [!WARNING]
8 | > This project is no longer maintained. Check out the new version [here](https://github.com/Raival-e/File-Explorer-Compose).
9 |
10 | # File Explorer
11 |
12 | A full-featured and lightweight file manager with Material 3 Dynamic colors
13 |
14 | # Screenshots
15 |
16 |
19 |
20 | # Features
21 |
22 | - Open source and simple.
23 | - All basic file management functionality (e.g. copy, paste,.. etc) are supported.
24 | - Support for multiple tabs, and Tasks which make managing files much easier.
25 | - Powerful Code Editor ([Sora Editor](https://github.com/Rosemoe/sora-editor)).
26 | - Deep search that allows you to search in files contents.
27 |
28 | # Upcoming features
29 | - [ ] Built-in audio/video player and PDF/image viewer
30 | - [ ] Archive viewer
31 | - [ ] Support for exploring root/external storage
32 |
33 | # Download
34 |
35 | [
](https://apt.izzysoft.de/fdroid/index/apk/com.raival.fileexplorer)
36 |
37 | - Latest release from [here](https://github.com/Raival-e/File-Explorer/releases/tag/v1.1.0).
38 | - Latest debug build from [Github Actions](https://github.com/Raival-e/File-Explorer/actions).
39 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | applicationId "com.raival.fileexplorer"
11 | minSdk 26
12 | targetSdk 32
13 | versionCode 2
14 | versionName "1.1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | packagingOptions {
20 | resources.excludes.add("license/*")
21 | }
22 |
23 | signingConfigs {
24 | debug {
25 | storeFile file('../testkey.keystore')
26 | storePassword 'testkey'
27 | keyAlias 'testkey'
28 | keyPassword 'testkey'
29 | }
30 | release {
31 | storeFile file("../testkey.keystore")
32 | storePassword "testkey"
33 | keyAlias "testkey"
34 | keyPassword "testkey"
35 | }
36 | }
37 |
38 | buildTypes {
39 | release {
40 | minifyEnabled false
41 | proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
42 | signingConfig signingConfigs.release
43 | }
44 | }
45 | compileOptions {
46 | coreLibraryDesugaringEnabled true
47 |
48 | sourceCompatibility JavaVersion.VERSION_11
49 | targetCompatibility JavaVersion.VERSION_11
50 | }
51 |
52 | kotlinOptions {
53 | jvmTarget = '1.8'
54 | }
55 | }
56 |
57 | dependencies {
58 | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
59 |
60 | implementation fileTree(dir: "libs", include: ["*.jar"])
61 |
62 | implementation "androidx.appcompat:appcompat:1.5.1"
63 | implementation "com.google.android.material:material:1.7.0"
64 | implementation "com.google.code.gson:gson:2.9.1"
65 | implementation 'commons-io:commons-io:2.11.0'
66 |
67 | implementation 'com.github.bumptech.glide:glide:4.14.0'
68 | annotationProcessor 'com.github.bumptech.glide:compiler:4.14.0'
69 |
70 | implementation "com.pixplicity.easyprefs:EasyPrefs:1.10.0"
71 | implementation 'net.lingala.zip4j:zip4j:2.11.2'
72 |
73 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
74 | implementation "io.github.Rosemoe.sora-editor:editor:0.17.1", {
75 | exclude group: "androidx.annotation", module: "annotation"
76 | }
77 | implementation "io.github.Rosemoe.sora-editor:language-textmate:0.17.1"
78 | implementation "io.github.Rosemoe.sora-editor:language-java:0.17.1"
79 |
80 | testImplementation "junit:junit:4.13.2"
81 | androidTestImplementation "androidx.test.ext:junit:1.1.3"
82 | androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0"
83 | }
84 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
12 |
15 |
16 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
49 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/app_icon-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/app_icon-playstore.png
--------------------------------------------------------------------------------
/app/src/main/assets/font/JetBrainsMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/assets/font/JetBrainsMono-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/textmate/README.md:
--------------------------------------------------------------------------------
1 | # Disclaimer
2 |
3 | These files were copied from [CodeAssist](https://github.com/tyron12233/CodeAssist), and minor
4 | modifications were applied to some of them. Original
5 | source: https://github.com/tyron12233/CodeAssist/tree/main/app/src/main/assets/textmate
--------------------------------------------------------------------------------
/app/src/main/assets/textmate/json/language-configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "comments": {
3 | "lineComment": "//",
4 | "blockComment": [
5 | "/*",
6 | "*/"
7 | ]
8 | },
9 | "brackets": [
10 | [
11 | "{",
12 | "}"
13 | ],
14 | [
15 | "[",
16 | "]"
17 | ]
18 | ],
19 | "autoClosingPairs": [
20 | [
21 | "{",
22 | "}"
23 | ],
24 | [
25 | "[",
26 | "]"
27 | ],
28 | {
29 | "open": "\"",
30 | "close": "\"",
31 | "notIn": [
32 | "string"
33 | ]
34 | },
35 | {
36 | "open": "'",
37 | "close": "'",
38 | "notIn": [
39 | "string"
40 | ]
41 | },
42 | {
43 | "open": "/**",
44 | "close": " */",
45 | "notIn": [
46 | "string"
47 | ]
48 | }
49 | ],
50 | "surroundingPairs": [
51 | [
52 | "{",
53 | "}"
54 | ],
55 | [
56 | "[",
57 | "]"
58 | ],
59 | [
60 | "\"",
61 | "\""
62 | ]
63 | ],
64 | "folding": {
65 | "offSide": false,
66 | "markers": {
67 | "start": "^\\s*//\\s*#region",
68 | "end": "^\\s*//\\s*#endregion"
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/assets/textmate/kotlin/language-configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "comments": {
3 | "lineComment": "//",
4 | "blockComment": [
5 | "/*",
6 | "*/"
7 | ]
8 | },
9 | "brackets": [
10 | [
11 | "{",
12 | "}"
13 | ],
14 | [
15 | "[",
16 | "]"
17 | ],
18 | [
19 | "(",
20 | ")"
21 | ],
22 | [
23 | "<",
24 | ">"
25 | ]
26 | ],
27 | "autoClosingPairs": [
28 | {
29 | "open": "{",
30 | "close": "}"
31 | },
32 | {
33 | "open": "[",
34 | "close": "]"
35 | },
36 | {
37 | "open": "(",
38 | "close": ")"
39 | },
40 | {
41 | "open": "'",
42 | "close": "'",
43 | "notIn": [
44 | "string",
45 | "comment"
46 | ]
47 | },
48 | {
49 | "open": "\"",
50 | "close": "\"",
51 | "notIn": [
52 | "string"
53 | ]
54 | },
55 | {
56 | "open": "/*",
57 | "close": " */",
58 | "notIn": [
59 | "string"
60 | ]
61 | }
62 | ],
63 | "surroundingPairs": [
64 | [
65 | "{",
66 | "}"
67 | ],
68 | [
69 | "[",
70 | "]"
71 | ],
72 | [
73 | "(",
74 | ")"
75 | ],
76 | [
77 | "<",
78 | ">"
79 | ],
80 | [
81 | "'",
82 | "'"
83 | ],
84 | [
85 | "\"",
86 | "\""
87 | ]
88 | ],
89 | "folding": {
90 | "offSide": false,
91 | "markers": {
92 | "start": "^\\s*//\\s*#region",
93 | "end": "^\\s*//\\s*#endregion"
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/app/src/main/assets/textmate/xml/language-configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "comments": {
3 | "lineComment": [
4 | ""
6 | ]
7 | },
8 | "brackets": [
9 | [
10 | "<",
11 | "/>"
12 | ],
13 | [
14 | "[",
15 | "]"
16 | ],
17 | [
18 | "(",
19 | ")"
20 | ]
21 | ],
22 | "autoClosingPairs": [
23 | [
24 | "{",
25 | "}"
26 | ],
27 | [
28 | "[",
29 | "]"
30 | ],
31 | [
32 | "(",
33 | ")"
34 | ],
35 | {
36 | "open": "\"",
37 | "close": "\"",
38 | "notIn": [
39 | "string"
40 | ]
41 | },
42 | {
43 | "open": "'",
44 | "close": "'",
45 | "notIn": [
46 | "string"
47 | ]
48 | },
49 | {
50 | "open": "/**",
51 | "close": " */",
52 | "notIn": [
53 | "string"
54 | ]
55 | }
56 | ],
57 | "surroundingPairs": [
58 | [
59 | "{",
60 | "}"
61 | ],
62 | [
63 | "[",
64 | "]"
65 | ],
66 | [
67 | "(",
68 | ")"
69 | ],
70 | [
71 | "\"",
72 | "\""
73 | ],
74 | [
75 | "'",
76 | "'"
77 | ],
78 | [
79 | "<",
80 | ">"
81 | ]
82 | ],
83 | "folding": {
84 | "offSide": false,
85 | "markers": {
86 | "start": "^\\s*//\\s*#region",
87 | "end": "^\\s*//\\s*#endregion"
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/App.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer
2 |
3 | import android.app.Application
4 | import android.content.ClipData
5 | import android.content.ClipboardManager
6 | import android.content.Context
7 | import android.os.Process
8 | import android.widget.Toast
9 | import com.pixplicity.easyprefs.library.Prefs
10 | import com.raival.fileexplorer.util.Log
11 | import kotlin.system.exitProcess
12 |
13 | class App : Application() {
14 | override fun onCreate() {
15 | Thread.setDefaultUncaughtExceptionHandler { _: Thread?, throwable: Throwable? ->
16 | Log.e("AppCrash", "", throwable)
17 | Process.killProcess(Process.myPid())
18 | exitProcess(2)
19 | }
20 |
21 | super.onCreate()
22 | appContext = this
23 |
24 | Prefs.Builder()
25 | .setContext(applicationContext)
26 | .setPrefsName("Prefs")
27 | .setMode(MODE_PRIVATE)
28 | .build()
29 | Log.start(appContext)
30 | }
31 |
32 | companion object {
33 | lateinit var appContext: Context
34 |
35 | @JvmStatic
36 | fun showMsg(message: String?) {
37 | Toast.makeText(appContext, message, Toast.LENGTH_SHORT).show()
38 | }
39 |
40 | @JvmStatic
41 | fun copyString(string: String?) {
42 | (appContext.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip(
43 | ClipData.newPlainText("clipboard", string)
44 | )
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/adapter/BookmarksAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.graphics.Color
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.ImageView
8 | import android.widget.TextView
9 | import androidx.recyclerview.widget.RecyclerView
10 | import com.raival.fileexplorer.App.Companion.showMsg
11 | import com.raival.fileexplorer.R
12 | import com.raival.fileexplorer.activity.MainActivity
13 | import com.raival.fileexplorer.tab.file.misc.IconHelper
14 | import com.raival.fileexplorer.util.PrefsUtils
15 | import com.raival.fileexplorer.util.Utils
16 | import java.io.File
17 |
18 | class BookmarksAdapter(private val activity: MainActivity) :
19 | RecyclerView.Adapter() {
20 | private var list = arrayListOf()
21 |
22 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
23 | @SuppressLint("InflateParams") val v =
24 | activity.layoutInflater.inflate(R.layout.activity_main_drawer_bookmark_item, null)
25 | v.layoutParams = RecyclerView.LayoutParams(
26 | ViewGroup.LayoutParams.MATCH_PARENT,
27 | ViewGroup.LayoutParams.WRAP_CONTENT
28 | )
29 | return ViewHolder(v)
30 | }
31 |
32 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
33 | holder.bind()
34 | }
35 |
36 | override fun getItemCount(): Int {
37 | return PrefsUtils.TextEditor.fileExplorerTabBookmarks.also { list = it }.size
38 | }
39 |
40 | inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
41 | var name: TextView
42 | var details: TextView
43 | var icon: ImageView
44 | var background: View
45 |
46 | init {
47 | name = v.findViewById(R.id.name)
48 | details = v.findViewById(R.id.details)
49 | icon = v.findViewById(R.id.icon)
50 | background = v.findViewById(R.id.background)
51 | }
52 |
53 | @SuppressLint("NotifyDataSetChanged")
54 | fun bind() {
55 | val position = adapterPosition
56 | val file = File(list[position])
57 | if (file.isFile && file.name.endsWith(".extension")) {
58 | name.text = file.name.substring(0, file.name.length - 10)
59 | } else {
60 | name.text = file.name
61 | }
62 | if (!file.exists()) {
63 | name.setTextColor(Color.RED)
64 | details.setTextColor(Color.RED)
65 | background.setOnClickListener {
66 | showMsg("This file doesn't exist anymore")
67 | list.remove(file.absolutePath)
68 | PrefsUtils.General.setFileExplorerTabBookmarks(list)
69 | list.clear()
70 | notifyDataSetChanged()
71 | }
72 | } else {
73 | name.setTextColor(Utils.getColorAttribute(R.attr.colorOnSurface, activity))
74 | details.setTextColor(Utils.getColorAttribute(R.attr.colorOnSurface, activity))
75 | background.setOnClickListener { activity.onBookmarkSelected(file) }
76 | }
77 | details.text = file.absolutePath
78 | IconHelper.setFileIcon(icon, file)
79 | background.setOnLongClickListener {
80 | list.remove(file.absolutePath)
81 | PrefsUtils.General.setFileExplorerTabBookmarks(list)
82 | list.clear()
83 | notifyDataSetChanged()
84 | true
85 | }
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/autocomplete/CustomCompletionItemAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.autocomplete
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.TextView
7 | import com.raival.fileexplorer.R
8 | import com.raival.fileexplorer.extension.toDp
9 | import io.github.rosemoe.sora.widget.component.EditorCompletionAdapter
10 |
11 | class CustomCompletionItemAdapter : EditorCompletionAdapter() {
12 | override fun getItemHeight(): Int = 45.toDp()
13 |
14 | public override fun getView(
15 | pos: Int,
16 | view: View?,
17 | parent: ViewGroup,
18 | isCurrentCursorPosition: Boolean
19 | ): View {
20 | val v: View = view ?: LayoutInflater.from(context)
21 | .inflate(R.layout.text_editor_completion_item, parent, false)
22 |
23 | val item = getItem(pos)
24 | var tv = v.findViewById(R.id.result_item_label)
25 | val iv = v.findViewById(R.id.result_item_image)
26 |
27 | tv.text = item.label
28 | tv = v.findViewById(R.id.result_item_desc)
29 | tv.text = item.desc
30 | v.tag = pos
31 | iv.text = item.desc.subSequence(0, 1)
32 |
33 | return v
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/autocomplete/CustomCompletionLayout.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.autocomplete
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.GradientDrawable
5 | import android.os.SystemClock
6 | import android.view.MotionEvent
7 | import android.view.View
8 | import android.widget.*
9 | import android.widget.AdapterView.OnItemClickListener
10 | import com.raival.fileexplorer.App.Companion.showMsg
11 | import com.raival.fileexplorer.extension.toDp
12 | import io.github.rosemoe.sora.widget.component.CompletionLayout
13 | import io.github.rosemoe.sora.widget.component.EditorAutoCompletion
14 | import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
15 |
16 | class CustomCompletionLayout : CompletionLayout {
17 | private lateinit var mListView: ListView
18 | private lateinit var mProgressBar: ProgressBar
19 | private lateinit var mBackground: GradientDrawable
20 | private lateinit var mEditorAutoCompletion: EditorAutoCompletion
21 |
22 | override fun onApplyColorScheme(colorScheme: EditorColorScheme) {
23 | mBackground.setStroke(
24 | 1,
25 | colorScheme.getColor(EditorColorScheme.COMPLETION_WND_BACKGROUND)
26 | )
27 | mBackground.setColor(colorScheme.getColor(EditorColorScheme.COMPLETION_WND_BACKGROUND))
28 | }
29 |
30 | override fun setEditorCompletion(completion: EditorAutoCompletion) {
31 | mEditorAutoCompletion = completion
32 | }
33 |
34 | override fun inflate(context: Context): View {
35 | val layout = RelativeLayout(context)
36 | mProgressBar = ProgressBar(context)
37 | layout.addView(mProgressBar)
38 |
39 | val params = mProgressBar.layoutParams as RelativeLayout.LayoutParams
40 | params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
41 | params.height = 30.toDp()
42 | params.width = params.height
43 |
44 | mBackground = GradientDrawable()
45 | mBackground.cornerRadius = 8f.toDp()
46 | layout.background = mBackground
47 |
48 | mListView = ListView(context)
49 | mListView.dividerHeight = 0
50 | layout.addView(mListView, LinearLayout.LayoutParams(-1, -1))
51 | mListView.onItemClickListener =
52 | OnItemClickListener { _: AdapterView<*>?, _: View?, position: Int, _: Long ->
53 | try {
54 | mEditorAutoCompletion.select(position)
55 | } catch (e: Exception) {
56 | showMsg(e.toString())
57 | }
58 | }
59 | setLoading(true)
60 | return layout
61 | }
62 |
63 | override fun getCompletionList(): AdapterView<*> {
64 | return mListView
65 | }
66 |
67 | override fun setLoading(loading: Boolean) {
68 | mProgressBar.visibility = if (loading) View.VISIBLE else View.INVISIBLE
69 | }
70 |
71 | override fun ensureListPositionVisible(position: Int, incrementPixels: Int) {
72 | mListView.post {
73 | while (mListView.firstVisiblePosition + 1 > position && mListView.canScrollList(-1)) {
74 | performScrollList(incrementPixels / 2)
75 | }
76 | while (mListView.lastVisiblePosition - 1 < position && mListView.canScrollList(1)) {
77 | performScrollList(-incrementPixels / 2)
78 | }
79 | }
80 | }
81 |
82 | private fun performScrollList(offset: Int) {
83 | val adpView = completionList
84 | val down = SystemClock.uptimeMillis()
85 | var ev = MotionEvent.obtain(down, down, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
86 |
87 | adpView.onTouchEvent(ev)
88 | ev.recycle()
89 |
90 | ev = MotionEvent.obtain(down, down, MotionEvent.ACTION_MOVE, 0f, offset.toFloat(), 0)
91 | adpView.onTouchEvent(ev)
92 | ev.recycle()
93 |
94 | ev = MotionEvent.obtain(down, down, MotionEvent.ACTION_CANCEL, 0f, offset.toFloat(), 0)
95 | adpView.onTouchEvent(ev)
96 | ev.recycle()
97 | }
98 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/language/java/JavaCodeLanguage.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.language.java
2 |
3 | import io.github.rosemoe.sora.lang.format.Formatter
4 | import io.github.rosemoe.sora.lang.smartEnter.NewlineHandleResult
5 | import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler
6 | import io.github.rosemoe.sora.langs.java.JavaLanguage
7 | import io.github.rosemoe.sora.langs.java.JavaTextTokenizer
8 | import io.github.rosemoe.sora.langs.java.Tokens
9 | import io.github.rosemoe.sora.text.ContentReference
10 | import io.github.rosemoe.sora.text.TextUtils
11 |
12 | open class JavaCodeLanguage : JavaLanguage() {
13 |
14 | private val javaFormatter = JavaFormatter()
15 | private val newlineHandlers = arrayOf(BraceHandler())
16 |
17 | override fun getFormatter(): Formatter {
18 | return javaFormatter
19 | }
20 |
21 | override fun getIndentAdvance(text: ContentReference, line: Int, column: Int): Int {
22 | val content = text.getLine(line).substring(0, column)
23 | return getIndentAdvance(content)
24 | }
25 |
26 | override fun useTab(): Boolean {
27 | return false
28 | }
29 |
30 |
31 | private fun getIndentAdvance(content: String): Int {
32 | val t = JavaTextTokenizer(content)
33 | var token: Tokens
34 | var advance = 0
35 |
36 | while (t.nextToken().also { token = it } !== Tokens.EOF) {
37 | if (token === Tokens.LBRACE) {
38 | advance++
39 | }
40 | if (token === Tokens.LPAREN) {
41 | advance++
42 | }
43 |
44 | if (advance > 0) {
45 | if (token === Tokens.RBRACE) {
46 | advance--
47 | }
48 | if (token === Tokens.RPAREN) {
49 | advance--
50 | }
51 | }
52 | }
53 |
54 | advance = 0.coerceAtLeast(advance)
55 |
56 | if (advance > 0) return 4
57 | return 0
58 | }
59 |
60 | override fun getNewlineHandlers(): Array {
61 | return newlineHandlers
62 | }
63 |
64 | inner class BraceHandler : NewlineHandler {
65 | override fun matchesRequirement(beforeText: String, afterText: String): Boolean {
66 | return (beforeText.endsWith("{") && afterText.startsWith("}"))
67 | || (beforeText.endsWith("(") && afterText.startsWith(")"))
68 | }
69 |
70 | override fun handleNewline(
71 | beforeText: String,
72 | afterText: String,
73 | tabSize: Int
74 | ): NewlineHandleResult {
75 | val count: Int = TextUtils.countLeadingSpaceCount(beforeText, tabSize)
76 | val advanceBefore: Int = getIndentAdvance(beforeText)
77 | val advanceAfter: Int = getIndentAdvance(afterText)
78 | var text: String
79 | val sb: StringBuilder = StringBuilder("\n")
80 | .append(TextUtils.createIndent(count + advanceBefore, tabSize, useTab()))
81 | .append('\n')
82 | .append(
83 | TextUtils.createIndent(count + advanceAfter, tabSize, useTab())
84 | .also { text = it })
85 | val shiftLeft = text.length + 1
86 | return NewlineHandleResult(sb, shiftLeft)
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/language/json/JsonFormatter.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.language.json
2 |
3 | import io.github.rosemoe.sora.lang.format.Formatter
4 | import io.github.rosemoe.sora.text.Content
5 | import io.github.rosemoe.sora.text.TextRange
6 | import org.json.JSONArray
7 | import org.json.JSONObject
8 |
9 | class JsonFormatter : Formatter {
10 | private var receiver: Formatter.FormatResultReceiver? = null
11 | private var isRunning = false
12 |
13 | override fun format(text: Content, cursorRange: TextRange) {
14 | isRunning = true
15 | receiver?.onFormatSucceed(format(text.toString()), cursorRange)
16 | isRunning = false
17 | }
18 |
19 | override fun formatRegion(text: Content, rangeToFormat: TextRange, cursorRange: TextRange) {
20 | }
21 |
22 | private fun format(txt: String): String {
23 | if (txt.isEmpty()) return txt
24 |
25 | val isObject = txt.trim()[0] == '{'
26 |
27 | return try {
28 | if (isObject) JSONObject(txt).toString(2)
29 | else JSONArray(txt).toString(2)
30 | } catch (e: Exception) {
31 | txt
32 | }
33 | }
34 |
35 | override fun setReceiver(receiver: Formatter.FormatResultReceiver?) {
36 | this.receiver = receiver
37 | }
38 |
39 | override fun isRunning(): Boolean {
40 | return isRunning
41 | }
42 |
43 | override fun destroy() {
44 | receiver = null
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/language/json/JsonLanguage.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.language.json
2 |
3 | import com.raival.fileexplorer.App
4 | import io.github.rosemoe.sora.lang.format.Formatter
5 | import io.github.rosemoe.sora.lang.smartEnter.NewlineHandleResult
6 | import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler
7 | import io.github.rosemoe.sora.langs.java.JavaTextTokenizer
8 | import io.github.rosemoe.sora.langs.java.Tokens
9 | import io.github.rosemoe.sora.langs.textmate.TextMateLanguage
10 | import io.github.rosemoe.sora.text.ContentReference
11 | import io.github.rosemoe.sora.text.TextUtils
12 | import org.eclipse.tm4e.core.registry.IGrammarSource
13 | import org.eclipse.tm4e.core.registry.IThemeSource
14 | import java.io.InputStreamReader
15 | import java.io.Reader
16 |
17 | class JsonLanguage(
18 | iThemeSource: IThemeSource,
19 | iGrammarSource: IGrammarSource = IGrammarSource.fromInputStream(
20 | App.appContext.assets.open("textmate/json/syntax/json.tmLanguage.json"),
21 | "json.tmLanguage.json",
22 | null
23 | ),
24 | languageConfiguration: Reader = InputStreamReader(App.appContext.assets.open("textmate/json/language-configuration.json")),
25 | createIdentifiers: Boolean = true
26 | ) : TextMateLanguage(iGrammarSource, languageConfiguration, iThemeSource, createIdentifiers) {
27 |
28 | private val jsonFormatter = JsonFormatter()
29 | private val newlineHandlers = arrayOf(BraceHandler())
30 |
31 |
32 | override fun getFormatter(): Formatter {
33 | return jsonFormatter
34 | }
35 |
36 | override fun getIndentAdvance(text: ContentReference, line: Int, column: Int): Int {
37 | val content = text.getLine(line).substring(0, column)
38 | return getIndentAdvance(content)
39 | }
40 |
41 | override fun useTab(): Boolean {
42 | return false
43 | }
44 |
45 |
46 | private fun getIndentAdvance(content: String): Int {
47 | val t = JavaTextTokenizer(content)
48 | var token: Tokens
49 | var advance = 0
50 |
51 | while (t.nextToken().also { token = it } !== Tokens.EOF) {
52 | if (token === Tokens.LBRACE) {
53 | advance++
54 | }
55 | if (token === Tokens.LBRACK) {
56 | advance++
57 | }
58 |
59 | if (advance > 0) {
60 | if (token === Tokens.RBRACE) {
61 | advance--
62 | }
63 | if (token === Tokens.RBRACE) {
64 | advance--
65 | }
66 | }
67 | }
68 |
69 | advance = 0.coerceAtLeast(advance)
70 |
71 | if (advance > 0) return 4
72 | return 0
73 | }
74 |
75 | override fun getNewlineHandlers(): Array {
76 | return newlineHandlers
77 | }
78 |
79 | inner class BraceHandler : NewlineHandler {
80 | override fun matchesRequirement(beforeText: String, afterText: String): Boolean {
81 | return (beforeText.endsWith("{") && afterText.startsWith("}"))
82 | || (beforeText.endsWith("[") && afterText.startsWith("]"))
83 | }
84 |
85 | override fun handleNewline(
86 | beforeText: String,
87 | afterText: String,
88 | tabSize: Int
89 | ): NewlineHandleResult {
90 | val count: Int = TextUtils.countLeadingSpaceCount(beforeText, tabSize)
91 | val advanceBefore: Int = getIndentAdvance(beforeText)
92 | val advanceAfter: Int = getIndentAdvance(afterText)
93 | var text: String
94 | val sb: StringBuilder = StringBuilder("\n")
95 | .append(TextUtils.createIndent(count + advanceBefore, tabSize, useTab()))
96 | .append('\n')
97 | .append(
98 | TextUtils.createIndent(count + advanceAfter, tabSize, useTab())
99 | .also { text = it })
100 | val shiftLeft = text.length + 1
101 | return NewlineHandleResult(sb, shiftLeft)
102 | }
103 | }
104 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/language/kotlin/KotlinCodeLanguage.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.language.kotlin
2 |
3 | import com.raival.fileexplorer.App
4 | import com.raival.fileexplorer.activity.editor.language.java.JavaFormatter
5 | import io.github.rosemoe.sora.lang.format.Formatter
6 | import io.github.rosemoe.sora.lang.smartEnter.NewlineHandleResult
7 | import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler
8 | import io.github.rosemoe.sora.langs.java.JavaTextTokenizer
9 | import io.github.rosemoe.sora.langs.java.Tokens
10 | import io.github.rosemoe.sora.langs.textmate.TextMateLanguage
11 | import io.github.rosemoe.sora.text.ContentReference
12 | import io.github.rosemoe.sora.text.TextUtils
13 | import org.eclipse.tm4e.core.registry.IGrammarSource
14 | import org.eclipse.tm4e.core.registry.IThemeSource
15 | import java.io.InputStreamReader
16 | import java.io.Reader
17 |
18 |
19 | class KotlinCodeLanguage(
20 | iThemeSource: IThemeSource,
21 | iGrammarSource: IGrammarSource = IGrammarSource.fromInputStream(
22 | App.appContext.assets.open("textmate/kotlin/syntax/kotlin.tmLanguage"),
23 | "kotlin.tmLanguage",
24 | null
25 | ),
26 | languageConfiguration: Reader = InputStreamReader(App.appContext.assets.open("textmate/kotlin/language-configuration.json")),
27 | createIdentifiers: Boolean = true
28 | ) : TextMateLanguage(iGrammarSource, languageConfiguration, iThemeSource, createIdentifiers) {
29 |
30 | private val javaFormatter = JavaFormatter()
31 | private val newlineHandlers = arrayOf(BraceHandler())
32 |
33 | override fun getFormatter(): Formatter {
34 | return javaFormatter
35 | }
36 |
37 | override fun getIndentAdvance(text: ContentReference, line: Int, column: Int): Int {
38 | val content = text.getLine(line).substring(0, column)
39 | return getIndentAdvance(content)
40 | }
41 |
42 | override fun useTab(): Boolean {
43 | return false
44 | }
45 |
46 |
47 | private fun getIndentAdvance(content: String): Int {
48 | val t = JavaTextTokenizer(content)
49 | var token: Tokens
50 | var advance = 0
51 |
52 | while (t.nextToken().also { token = it } !== Tokens.EOF) {
53 | if (token === Tokens.LBRACE) {
54 | advance++
55 | }
56 | if (token === Tokens.LPAREN) {
57 | advance++
58 | }
59 |
60 | if (advance > 0) {
61 | if (token === Tokens.RBRACE) {
62 | advance--
63 | }
64 | if (token === Tokens.RPAREN) {
65 | advance--
66 | }
67 | }
68 | }
69 |
70 | advance = 0.coerceAtLeast(advance)
71 |
72 | if (advance > 0) return 4
73 | return 0
74 | }
75 |
76 | override fun getNewlineHandlers(): Array {
77 | return newlineHandlers
78 | }
79 |
80 | inner class BraceHandler : NewlineHandler {
81 | override fun matchesRequirement(beforeText: String, afterText: String): Boolean {
82 | return (beforeText.endsWith("{") && afterText.startsWith("}"))
83 | || (beforeText.endsWith("(") && afterText.startsWith(")"))
84 | }
85 |
86 | override fun handleNewline(
87 | beforeText: String,
88 | afterText: String,
89 | tabSize: Int
90 | ): NewlineHandleResult {
91 | val count: Int = TextUtils.countLeadingSpaceCount(beforeText, tabSize)
92 | val advanceBefore: Int = getIndentAdvance(beforeText)
93 | val advanceAfter: Int = getIndentAdvance(afterText)
94 | var text: String
95 | val sb: StringBuilder = StringBuilder("\n")
96 | .append(TextUtils.createIndent(count + advanceBefore, tabSize, useTab()))
97 | .append('\n')
98 | .append(
99 | TextUtils.createIndent(count + advanceAfter, tabSize, useTab())
100 | .also { text = it })
101 | val shiftLeft = text.length + 1
102 | return NewlineHandleResult(sb, shiftLeft)
103 | }
104 | }
105 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/language/xml/XmlLanguage.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.language.xml
2 |
3 | import com.raival.fileexplorer.App
4 | import io.github.rosemoe.sora.langs.textmate.TextMateLanguage
5 | import org.eclipse.tm4e.core.registry.IGrammarSource
6 | import org.eclipse.tm4e.core.registry.IThemeSource
7 | import java.io.InputStreamReader
8 | import java.io.Reader
9 |
10 | class XmlLanguage(
11 | iThemeSource: IThemeSource,
12 | iGrammarSource: IGrammarSource = IGrammarSource.fromInputStream(
13 | App.appContext.assets.open("textmate/xml/syntax/xml.tmLanguage.json"),
14 | "xml.tmLanguage.json",
15 | null
16 | ),
17 | languageConfiguration: Reader = InputStreamReader(App.appContext.assets.open("textmate/xml/language-configuration.json")),
18 | createIdentifiers: Boolean = true
19 | ) : TextMateLanguage(iGrammarSource, languageConfiguration, iThemeSource, createIdentifiers) {
20 |
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/scheme/DarkScheme.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.scheme
2 |
3 | import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
4 |
5 | class DarkScheme : EditorColorScheme() {
6 | override fun applyDefault() {
7 | super.applyDefault()
8 | setColor(ANNOTATION, -0x444ad7)
9 | setColor(FUNCTION_NAME, -0x332f27)
10 | setColor(IDENTIFIER_NAME, -0x332f27)
11 | setColor(IDENTIFIER_VAR, -0x678956)
12 | setColor(LITERAL, -0x9578a7)
13 | setColor(OPERATOR, -0x332f27)
14 | setColor(COMMENT, -0x7f7f80)
15 | setColor(KEYWORD, -0x3387ce)
16 | setColor(WHOLE_BACKGROUND, -0xd4d4d5)
17 | setColor(TEXT_NORMAL, -0x332f27)
18 | setColor(LINE_NUMBER_BACKGROUND, -0xcecccb)
19 | setColor(LINE_NUMBER, -0x9f9c9a)
20 | setColor(LINE_DIVIDER, -0x9f9c9a)
21 | setColor(SCROLL_BAR_THUMB, -0x59595a)
22 | setColor(SCROLL_BAR_THUMB_PRESSED, -0xa9a9aa)
23 | setColor(SELECTED_TEXT_BACKGROUND, -0xc98948)
24 | setColor(MATCHED_TEXT_BACKGROUND, -0xcda6c3)
25 | setColor(CURRENT_LINE, -0xcdcdce)
26 | setColor(SELECTION_INSERT, -0x332f27)
27 | setColor(SELECTION_HANDLE, -0x332f27)
28 | setColor(BLOCK_LINE, -0xa8a8a9)
29 | setColor(BLOCK_LINE_CURRENT, -0x22a8a8a9)
30 | setColor(NON_PRINTABLE_CHAR, -0x222223)
31 | setColor(TEXT_SELECTED, -0x332f27)
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/scheme/LightScheme.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.scheme
2 |
3 | import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
4 |
5 | class LightScheme : EditorColorScheme() {
6 | override fun applyDefault() {
7 | super.applyDefault()
8 | setColor(ANNOTATION, -0x9b9b9c)
9 | setColor(FUNCTION_NAME, -0x1000000)
10 | setColor(IDENTIFIER_NAME, -0x1000000)
11 | setColor(IDENTIFIER_VAR, -0x479cc2)
12 | setColor(LITERAL, -0xd5ff01)
13 | setColor(OPERATOR, -0xc60000)
14 | setColor(COMMENT, -0xc080a1)
15 | setColor(KEYWORD, -0x80ff8c)
16 | setColor(WHOLE_BACKGROUND, -0x1)
17 | setColor(TEXT_NORMAL, -0x1000000)
18 | setColor(LINE_NUMBER_BACKGROUND, -0x1)
19 | setColor(LINE_NUMBER, -0x878788)
20 | setColor(SELECTED_TEXT_BACKGROUND, -0xcc6601)
21 | setColor(MATCHED_TEXT_BACKGROUND, -0x2b2b2c)
22 | setColor(CURRENT_LINE, -0x170d02)
23 | setColor(SELECTION_INSERT, -0xfc1415)
24 | setColor(SELECTION_HANDLE, -0xfc1415)
25 | setColor(BLOCK_LINE, -0x272728)
26 | setColor(BLOCK_LINE_CURRENT, 0)
27 | setColor(TEXT_SELECTED, -0x1)
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/editor/view/SymbolInputView.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.editor.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.TypedValue
6 | import android.widget.Button
7 | import android.widget.LinearLayout
8 | import com.raival.fileexplorer.R
9 | import com.raival.fileexplorer.util.Utils
10 | import io.github.rosemoe.sora.widget.CodeEditor
11 |
12 | class SymbolInputView : LinearLayout {
13 | private var textColor = 0
14 | private lateinit var editor: CodeEditor
15 |
16 | constructor(context: Context?) : super(context)
17 |
18 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
19 |
20 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
21 | context,
22 | attrs,
23 | defStyleAttr
24 | )
25 |
26 | init {
27 | setBackgroundColor(Utils.getColorAttribute(R.attr.backgroundColor, context))
28 | setTextColor(Utils.getColorAttribute(R.attr.colorOnSurface, context))
29 | orientation = HORIZONTAL
30 | }
31 |
32 | fun bindEditor(editor: CodeEditor): SymbolInputView {
33 | this.editor = editor
34 | return this
35 | }
36 |
37 | fun setTextColor(color: Int): SymbolInputView {
38 | for (i in 0 until childCount) {
39 | (getChildAt(i) as Button).setTextColor(color)
40 | }
41 | textColor = color
42 | return this
43 | }
44 |
45 | fun addSymbols(symbols: Array): SymbolInputView {
46 | for (symbol in symbols) addSymbol(symbol)
47 | return this
48 | }
49 |
50 | fun addSymbol(
51 | display: String,
52 | content: String = display,
53 | cursorPos: Int = content.length
54 | ): SymbolInputView {
55 | val btn = Button(context, null, android.R.attr.buttonStyleSmall)
56 | btn.text = display
57 | val out = TypedValue()
58 | context.theme.resolveAttribute(android.R.attr.selectableItemBackground, out, true)
59 | btn.setBackgroundResource(out.resourceId)
60 | btn.setTextColor(textColor)
61 | addView(btn, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT))
62 |
63 | btn.setOnClickListener {
64 | if (this::editor.isInitialized) editor.insertText(content, cursorPos)
65 | }
66 | return this
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/model/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.model
2 |
3 | import androidx.lifecycle.ViewModel
4 | import com.raival.fileexplorer.tab.BaseDataHolder
5 | import com.raival.fileexplorer.tab.file.model.Task
6 |
7 | class MainViewModel : ViewModel() {
8 | @JvmField
9 | val tasks = arrayListOf()
10 | private val dataHolders: MutableList = arrayListOf()
11 |
12 | fun addDataHolder(dataHolder: BaseDataHolder) {
13 | dataHolders.add(dataHolder)
14 | }
15 |
16 | fun getDataHolders(): ArrayList {
17 | return dataHolders as ArrayList
18 | }
19 |
20 | fun getDataHolder(tag: String): BaseDataHolder? {
21 | for (dataHolder in dataHolders) {
22 | if (dataHolder.tag == tag) return dataHolder
23 | }
24 | return null
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/activity/model/TextEditorViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.activity.model
2 |
3 | import androidx.lifecycle.ViewModel
4 | import io.github.rosemoe.sora.text.Content
5 | import java.io.File
6 |
7 | class TextEditorViewModel : ViewModel() {
8 | var file: File? = null
9 | var content: Content? = null
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/common/BackgroundTask.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.common
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.os.Handler
6 | import android.os.Looper
7 | import android.view.View
8 | import android.widget.TextView
9 | import androidx.appcompat.app.AlertDialog
10 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
11 | import com.raival.fileexplorer.R
12 | import kotlinx.coroutines.CoroutineScope
13 | import kotlinx.coroutines.Dispatchers
14 | import kotlinx.coroutines.launch
15 |
16 | class BackgroundTask {
17 | private lateinit var preTask: Runnable
18 | private lateinit var task: Runnable
19 | private lateinit var postTask: Runnable
20 | private lateinit var alertDialog: AlertDialog
21 |
22 | fun setTasks(preTask: Runnable, task: Runnable, postTask: Runnable) {
23 | this.preTask = preTask
24 | this.task = task
25 | this.postTask = postTask
26 | }
27 |
28 | fun run() {
29 | CoroutineScope(Dispatchers.IO).launch {
30 | Handler(Looper.getMainLooper()).post(preTask)
31 | task.run()
32 | Handler(Looper.getMainLooper()).post(postTask)
33 | }.start()
34 | }
35 |
36 | fun dismiss() {
37 | if (this::alertDialog.isInitialized) alertDialog.dismiss()
38 | }
39 |
40 | @SuppressLint("ResourceType")
41 | fun showProgressDialog(msg: String, activity: Activity) {
42 | alertDialog = MaterialAlertDialogBuilder(activity)
43 | .setCancelable(false)
44 | .setView(getProgressView(msg, activity))
45 | .show()
46 | }
47 |
48 | private fun getProgressView(msg: String, activity: Activity): View {
49 | @SuppressLint("InflateParams") val v =
50 | activity.layoutInflater.inflate(R.layout.progress_view, null)
51 | (v.findViewById(R.id.msg) as TextView).text = msg
52 | return v
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/common/dialog/OptionsDialog.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.common.dialog
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.ImageView
8 | import android.widget.LinearLayout
9 | import android.widget.TextView
10 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
11 | import com.raival.fileexplorer.R
12 |
13 | class OptionsDialog(var title: String) : BottomSheetDialogFragment() {
14 | private val options = ArrayList()
15 | private var container: LinearLayout? = null
16 |
17 | fun addOption(
18 | label: String?,
19 | listener: View.OnClickListener?,
20 | dismissOnClick: Boolean
21 | ): OptionsDialog {
22 | return addOption(label, 0, listener, dismissOnClick)
23 | }
24 |
25 | fun addOption(
26 | label: String?,
27 | resId: Int,
28 | listener: View.OnClickListener?,
29 | dismissOnClick: Boolean
30 | ): OptionsDialog {
31 | val optionHolder = OptionHolder()
32 | optionHolder.dismissOnClick = dismissOnClick
33 | optionHolder.label = label
34 | optionHolder.listener = listener
35 | optionHolder.res = resId
36 | options.add(optionHolder)
37 | return this
38 | }
39 |
40 | override fun onCreateView(
41 | inflater: LayoutInflater,
42 | container: ViewGroup?,
43 | savedInstanceState: Bundle?
44 | ): View? {
45 | return inflater.inflate(R.layout.common_options_dialog, container, false)
46 | }
47 |
48 | override fun getTheme(): Int {
49 | return R.style.ThemeOverlay_Material3_BottomSheetDialog
50 | }
51 |
52 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
53 | super.onViewCreated(view, savedInstanceState)
54 | container = view.findViewById(R.id.container)
55 | (view.findViewById(R.id.title) as TextView).text = title
56 | view.findViewById(R.id.msg).visibility = View.GONE
57 | addOptions()
58 | }
59 |
60 | private fun addOptions() {
61 | for (optionHolder in options) {
62 | val v = layoutInflater.inflate(R.layout.common_options_dialog_item, container, false)
63 | if (optionHolder.res != 0) {
64 | val icon = v.findViewById(R.id.icon)
65 | icon.visibility = View.VISIBLE
66 | icon.setImageResource(optionHolder.res)
67 | }
68 | (v.findViewById(R.id.label) as TextView).text = optionHolder.label
69 | v.findViewById(R.id.background).setOnClickListener { view: View? ->
70 | if (optionHolder.listener != null) optionHolder.listener!!.onClick(view)
71 | if (optionHolder.dismissOnClick) v.post { dismiss() }
72 | }
73 | container!!.addView(v)
74 | }
75 | }
76 |
77 | private class OptionHolder {
78 | var label: String? = null
79 | var res = 0
80 | var listener: View.OnClickListener? = null
81 | var dismissOnClick = false
82 | }
83 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/common/view/BottomBarView.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.common.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.widget.ImageView
8 | import android.widget.LinearLayout
9 | import android.widget.TextView
10 | import com.raival.fileexplorer.R
11 | import com.raival.fileexplorer.util.PrefsUtils
12 |
13 | class BottomBarView : LinearLayout {
14 | constructor(context: Context?) : super(context)
15 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
16 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
17 | context,
18 | attrs,
19 | defStyleAttr
20 | )
21 |
22 | fun addItem(tag: String?, icon: Int, clickListener: OnClickListener?) {
23 | val view = (context
24 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
25 | .inflate(R.layout.bottom_bar_menu_item, this, false)
26 | view.setOnClickListener(clickListener)
27 | view.tooltipText = tag
28 | val label = view.findViewById(R.id.label)
29 | if (PrefsUtils.Settings.showBottomToolbarLabels) {
30 | label.text = tag
31 | } else {
32 | label.visibility = GONE
33 | }
34 | val image = view.findViewById(R.id.icon)
35 | image.setImageResource(icon)
36 | addView(view)
37 | }
38 |
39 | fun addItem(tag: String?, view: View) {
40 | view.tooltipText = tag
41 | addView(view)
42 | }
43 |
44 | fun clear() {
45 | removeAllViews()
46 | }
47 |
48 | fun onUpdatePrefs() {
49 | for (i in 0 until childCount) {
50 | val view = getChildAt(i)
51 | val label = view.findViewById(R.id.label)
52 | if (label != null) {
53 | label.visibility =
54 | if (PrefsUtils.Settings.showBottomToolbarLabels) VISIBLE else GONE
55 | }
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/extension/Int.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.extension
2 |
3 | import android.util.TypedValue
4 | import com.raival.fileexplorer.App
5 |
6 | fun Int.toDp(): Int = TypedValue.applyDimension(
7 | TypedValue.COMPLEX_UNIT_DIP,
8 | this.toFloat(),
9 | App.appContext.resources.displayMetrics
10 | ).toInt()
11 |
12 | fun Float.toDp(): Float = TypedValue.applyDimension(
13 | TypedValue.COMPLEX_UNIT_DIP,
14 | this,
15 | App.appContext.resources.displayMetrics
16 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/extension/Long.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.extension
2 |
3 | import java.text.DecimalFormat
4 | import kotlin.math.log10
5 | import kotlin.math.pow
6 |
7 | fun Long.toFormattedSize(): String {
8 | if (this <= 0) return "0 B"
9 | val units = arrayOf("B", "kB", "MB", "GB", "TB")
10 | val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
11 | return DecimalFormat("#,##0.#").format(
12 | this / 1024.0.pow(digitGroups.toDouble())
13 | ) + " " + units[digitGroups]
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/extension/String.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.extension
2 |
3 | import com.google.gson.Gson
4 | import com.google.gson.reflect.TypeToken
5 |
6 | fun String.getStringList(): ArrayList {
7 | return Gson().fromJson(this, object : TypeToken>() {}.type)
8 | }
9 |
10 | fun String.surroundWithBrackets(): String {
11 | return "[$this]"
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/FileExplorerGlideModule.java:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import androidx.annotation.NonNull;
7 |
8 | import com.bumptech.glide.Glide;
9 | import com.bumptech.glide.Registry;
10 | import com.bumptech.glide.annotation.GlideModule;
11 | import com.bumptech.glide.module.AppGlideModule;
12 | import com.raival.fileexplorer.glide.apk.ApkIconModelLoaderFactory;
13 | import com.raival.fileexplorer.glide.icon.IconModelLoaderFactory;
14 | import com.raival.fileexplorer.glide.model.IconRes;
15 |
16 | @GlideModule
17 | public class FileExplorerGlideModule extends AppGlideModule {
18 | @Override
19 | public void registerComponents(@NonNull Context context, @NonNull Glide glide, Registry registry) {
20 | registry.prepend(String.class, Drawable.class, new ApkIconModelLoaderFactory(context));
21 | registry.prepend(IconRes.class, Drawable.class, new IconModelLoaderFactory(context));
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/apk/ApkIconDataFetcher.java:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide.apk;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.core.content.ContextCompat;
8 |
9 | import com.bumptech.glide.Priority;
10 | import com.bumptech.glide.load.DataSource;
11 | import com.bumptech.glide.load.data.DataFetcher;
12 | import com.raival.fileexplorer.R;
13 | import com.raival.fileexplorer.tab.file.misc.FileUtils;
14 |
15 | import java.io.File;
16 |
17 | public class ApkIconDataFetcher implements DataFetcher {
18 |
19 | private final Context context;
20 | private final String model;
21 |
22 | public ApkIconDataFetcher(Context context, String model) {
23 | this.context = context;
24 | this.model = model;
25 | }
26 |
27 | @Override
28 | public void loadData(@NonNull Priority priority, @NonNull DataCallback super Drawable> callback) {
29 | Drawable apkIcon = FileUtils.INSTANCE.getApkIcon(new File(model));
30 | if (apkIcon == null)
31 | apkIcon = ContextCompat.getDrawable(context, R.drawable.unknown_file_extension);
32 | callback.onDataReady(apkIcon);
33 | }
34 |
35 | @Override
36 | public void cleanup() {
37 | // Intentionally empty only because we're not opening an InputStream or another I/O resource!
38 | }
39 |
40 | @Override
41 | public void cancel() {
42 | // No cancellation procedure
43 | }
44 |
45 | @NonNull
46 | @Override
47 | public Class getDataClass() {
48 | return Drawable.class;
49 | }
50 |
51 | @NonNull
52 | @Override
53 | public DataSource getDataSource() {
54 | return DataSource.LOCAL;
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/apk/ApkIconModelLoader.java:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide.apk;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.bumptech.glide.load.Options;
10 | import com.bumptech.glide.load.model.ModelLoader;
11 | import com.bumptech.glide.signature.ObjectKey;
12 | import com.raival.fileexplorer.tab.file.misc.FileMimeTypes;
13 |
14 | import java.util.Locale;
15 |
16 | public class ApkIconModelLoader implements ModelLoader {
17 |
18 | private final Context context;
19 |
20 | public ApkIconModelLoader(Context context) {
21 | this.context = context;
22 | }
23 |
24 | @Nullable
25 | @Override
26 | public LoadData buildLoadData(@NonNull String s, int width, int height, @NonNull Options options) {
27 | return new LoadData<>(new ObjectKey(s), new ApkIconDataFetcher(context, s));
28 | }
29 |
30 | @Override
31 | public boolean handles(String s) {
32 | return s.toLowerCase(Locale.ROOT).endsWith(FileMimeTypes.apkType);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/apk/ApkIconModelLoaderFactory.java:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide.apk;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import androidx.annotation.NonNull;
7 |
8 | import com.bumptech.glide.load.model.ModelLoader;
9 | import com.bumptech.glide.load.model.ModelLoaderFactory;
10 | import com.bumptech.glide.load.model.MultiModelLoaderFactory;
11 |
12 | public class ApkIconModelLoaderFactory implements ModelLoaderFactory {
13 |
14 | private final Context context;
15 |
16 | public ApkIconModelLoaderFactory(Context context) {
17 | this.context = context;
18 | }
19 |
20 | @NonNull
21 | @Override
22 | public ModelLoader build(@NonNull MultiModelLoaderFactory multiFactory) {
23 | return new ApkIconModelLoader(context);
24 | }
25 |
26 | @Override
27 | public void teardown() {
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/icon/IconDataFetcher.java:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide.icon;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.core.content.ContextCompat;
8 |
9 | import com.bumptech.glide.Priority;
10 | import com.bumptech.glide.load.DataSource;
11 | import com.bumptech.glide.load.data.DataFetcher;
12 | import com.raival.fileexplorer.glide.model.IconRes;
13 |
14 | public class IconDataFetcher implements DataFetcher {
15 |
16 | private final Context context;
17 | private final IconRes model;
18 |
19 | public IconDataFetcher(Context context, IconRes model) {
20 | this.context = context;
21 | this.model = model;
22 | }
23 |
24 | @Override
25 | public void loadData(@NonNull Priority priority, @NonNull DataCallback super Drawable> callback) {
26 | Context ctx = (model.getContext() != null) ? model.getContext() : context;
27 | Drawable drawable = ContextCompat.getDrawable(ctx, model.getResId());
28 | callback.onDataReady(drawable);
29 | }
30 |
31 | @Override
32 | public void cleanup() {
33 | // Intentionally empty only because we're not opening an InputStream or another I/O resource!
34 | }
35 |
36 | @Override
37 | public void cancel() {
38 | // No cancellation procedure
39 | }
40 |
41 | @NonNull
42 | @Override
43 | public Class getDataClass() {
44 | return Drawable.class;
45 | }
46 |
47 | @NonNull
48 | @Override
49 | public DataSource getDataSource() {
50 | return DataSource.LOCAL;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/icon/IconModelLoader.java:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide.icon;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.bumptech.glide.load.Options;
10 | import com.bumptech.glide.load.model.ModelLoader;
11 | import com.bumptech.glide.signature.ObjectKey;
12 | import com.raival.fileexplorer.glide.model.IconRes;
13 |
14 | public class IconModelLoader implements ModelLoader {
15 |
16 | private final Context context;
17 |
18 | public IconModelLoader(Context context) {
19 | this.context = context;
20 | }
21 |
22 | @Nullable
23 | @Override
24 | public LoadData buildLoadData(@NonNull IconRes s, int width, int height, @NonNull Options options) {
25 | return new LoadData<>(new ObjectKey(s), new IconDataFetcher(context, s));
26 | }
27 |
28 | @Override
29 | public boolean handles(@NonNull IconRes s) {
30 | return true;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/icon/IconModelLoaderFactory.java:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide.icon;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import androidx.annotation.NonNull;
7 |
8 | import com.bumptech.glide.load.model.ModelLoader;
9 | import com.bumptech.glide.load.model.ModelLoaderFactory;
10 | import com.bumptech.glide.load.model.MultiModelLoaderFactory;
11 | import com.raival.fileexplorer.glide.model.IconRes;
12 |
13 | public class IconModelLoaderFactory implements ModelLoaderFactory {
14 |
15 | private final Context context;
16 |
17 | public IconModelLoaderFactory(Context context) {
18 | this.context = context;
19 | }
20 |
21 | @NonNull
22 | @Override
23 | public ModelLoader build(@NonNull MultiModelLoaderFactory multiFactory) {
24 | return new IconModelLoader(context);
25 | }
26 |
27 | @Override
28 | public void teardown() {
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/glide/model/IconRes.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.glide.model
2 |
3 | import android.content.Context
4 |
5 | class IconRes(val resId: Int, val context: Context? = null)
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/BaseDataHolder.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab
2 |
3 | abstract class BaseDataHolder {
4 | abstract val tag: String
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/BaseTabFragment.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.lifecycle.ViewModelProvider
5 | import com.google.android.material.appbar.MaterialToolbar
6 | import com.raival.fileexplorer.activity.MainActivity
7 | import com.raival.fileexplorer.activity.model.MainViewModel
8 | import com.raival.fileexplorer.common.view.BottomBarView
9 | import com.raival.fileexplorer.common.view.TabView
10 |
11 | /**
12 | * Each TabFragment must handle the creation of its DataHolder and the related TabView using
13 | * the provided APIs or custom ones.
14 | */
15 | abstract class BaseTabFragment : Fragment() {
16 | var mainViewModel: MainViewModel? = null
17 | get() {
18 | if (field == null) {
19 | field = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
20 | }
21 | return field
22 | }
23 | private set
24 |
25 | var bottomBarView: BottomBarView? = null
26 | get() {
27 | if (field == null) field = (requireActivity() as MainActivity).bottomBarView
28 | return field
29 | }
30 | private set
31 |
32 | var toolbar: MaterialToolbar? = null
33 | get() {
34 | if (field == null) field = (requireActivity() as MainActivity).toolbar
35 | return field
36 | }
37 | private set
38 |
39 | private var tabView: TabView.Tab? = null
40 |
41 | var dataHolder: BaseDataHolder? = null
42 | get() {
43 | if (field == null && mainViewModel!!.getDataHolder(tag!!).also { field = it } == null) {
44 | field = createNewDataHolder()
45 | mainViewModel!!.addDataHolder(field!!)
46 | }
47 | return field
48 | }
49 | private set
50 |
51 | abstract fun onBackPressed(): Boolean
52 | abstract fun createNewDataHolder(): BaseDataHolder
53 |
54 | fun getTabView(): TabView.Tab? {
55 | if (tabView == null && (requireActivity() as MainActivity).tabView.getTabByTag(tag)
56 | .also { tabView = it } == null
57 | ) {
58 | tabView = (requireActivity() as MainActivity).tabView.addNewTab(tag!!)
59 | // set Default name
60 | tabView!!.setName("Untitled")
61 | }
62 | return tabView
63 | }
64 |
65 | open fun closeTab() {
66 | mainViewModel!!.getDataHolders()
67 | .removeIf { dataHolder1: BaseDataHolder -> dataHolder1.tag == tag }
68 | (requireActivity() as MainActivity).closeTab(tag!!)
69 | }
70 |
71 | override fun onResume() {
72 | super.onResume()
73 | // create TabView if necessary (important when a tab fragment doesn't update its TabView)
74 | getTabView()
75 | }
76 |
77 | companion object {
78 | const val DEFAULT_TAB_FRAGMENT_PREFIX = "0_FileExplorerTabFragment_"
79 | const val FILE_EXPLORER_TAB_FRAGMENT_PREFIX = "FileExplorerTabFragment_"
80 | const val APPS_TAB_FRAGMENT_PREFIX = "AppsTabFragment_"
81 | const val ARCHIVE_TAB_FRAGMENT_PREFIX = "ArchiveTabFragment_"
82 | }
83 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/apps/AppsTabDataHolder.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.apps
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.raival.fileexplorer.tab.BaseDataHolder
6 | import com.raival.fileexplorer.tab.apps.model.Apk
7 | import com.raival.fileexplorer.tab.apps.resolver.ApkResolver
8 | import kotlinx.coroutines.CoroutineScope
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import kotlinx.coroutines.withContext
12 |
13 | class AppsTabDataHolder(override val tag: String) : BaseDataHolder() {
14 | private val apps = MutableLiveData>()
15 |
16 | fun getApps(showSystemApps: Boolean, sortNewerFirst: Boolean): LiveData> {
17 | if (apps.value == null) {
18 | loadApps(showSystemApps, sortNewerFirst)
19 | }
20 | return apps
21 | }
22 |
23 | fun updateAppsList(showSystemApps: Boolean, sortNewerFirst: Boolean) {
24 | loadApps(showSystemApps, sortNewerFirst)
25 | }
26 |
27 | private fun loadApps(showSystemApps: Boolean, sortNewerFirst: Boolean) {
28 | CoroutineScope(Dispatchers.IO).launch {
29 | val apks = ApkResolver().load(showSystemApps, sortNewerFirst).get()
30 | withContext(Dispatchers.Main) { apps.setValue(apks) }
31 | }.start()
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/apps/model/Apk.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.apps.model
2 |
3 | import android.graphics.drawable.Drawable
4 | import java.io.File
5 |
6 | class Apk(
7 | val name: String,
8 | val pkg: String,
9 | val size: String,
10 | val icon: Drawable,
11 | val lastModified: Long,
12 | val source: File
13 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/apps/resolver/ApkResolver.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.apps.resolver
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.pm.ApplicationInfo
5 | import android.content.pm.PackageInfo
6 | import android.content.pm.PackageManager
7 | import com.raival.fileexplorer.App
8 | import com.raival.fileexplorer.extension.toFormattedSize
9 | import com.raival.fileexplorer.tab.apps.model.Apk
10 | import java.io.File
11 |
12 | class ApkResolver {
13 | private val list = ArrayList()
14 | private var sortApps = false
15 |
16 | @SuppressLint("PackageManagerGetSignatures")
17 | fun load(showSystemApps: Boolean, sortNewerFirst: Boolean): ApkResolver {
18 | list.clear()
19 | sortApps = sortNewerFirst
20 | val pm = App.appContext.packageManager
21 | val apps = pm.getInstalledApplications(
22 | PackageManager.MATCH_UNINSTALLED_PACKAGES
23 | or PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
24 | )
25 |
26 | var androidInfo: PackageInfo? = null
27 | try {
28 | androidInfo = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES)
29 | } catch (ignored: PackageManager.NameNotFoundException) {
30 | }
31 | for (info in apps) {
32 | if (info.sourceDir == null) {
33 | continue
34 | }
35 | val pkgInfo: PackageInfo? = try {
36 | pm.getPackageInfo(info.packageName, PackageManager.GET_SIGNATURES)
37 | } catch (e: PackageManager.NameNotFoundException) {
38 | null
39 | }
40 |
41 | val isSystemApp = isAppInSystemPartition(info) || isSignedBySystem(pkgInfo, androidInfo)
42 | if (isSystemApp && !showSystemApps) continue
43 |
44 | val apk = Apk(
45 | pm.getApplicationLabel(info).toString(),
46 | info.packageName,
47 | File(info.publicSourceDir).length().toFormattedSize(),
48 | info.loadIcon(pm),
49 | File(info.publicSourceDir).lastModified(),
50 | File(info.publicSourceDir)
51 | )
52 | list.add(apk)
53 | }
54 | return this
55 | }
56 |
57 | fun get(): ArrayList {
58 | if (sortApps) list.sortWith { apk1: Apk, apk2: Apk ->
59 | apk2.lastModified.compareTo(apk1.lastModified)
60 | }
61 | return list
62 | }
63 |
64 | private fun isSignedBySystem(piApp: PackageInfo?, piSys: PackageInfo?): Boolean {
65 | return piApp != null && piSys != null && piApp.signatures != null && piSys.signatures[0] == piApp.signatures[0]
66 | }
67 |
68 | companion object {
69 | fun isAppInSystemPartition(applicationInfo: ApplicationInfo): Boolean {
70 | return ((applicationInfo.flags
71 | and (ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP))
72 | != 0)
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/FileExplorerTabDataHolder.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file
2 |
3 | import android.os.Parcelable
4 | import com.raival.fileexplorer.tab.BaseDataHolder
5 | import com.raival.fileexplorer.tab.file.model.FileItem
6 | import java.io.File
7 |
8 | class FileExplorerTabDataHolder(override val tag: String) : BaseDataHolder() {
9 | @JvmField
10 | var activeDirectory: File? = null
11 |
12 | @JvmField
13 | var recyclerViewStates: HashMap = HashMap()
14 | var searchList = ArrayList()
15 |
16 | @JvmField
17 | var selectedFiles = ArrayList()
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/adapter/PathHistoryAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.raival.fileexplorer.R
10 | import com.raival.fileexplorer.extension.isExternalStorageFolder
11 | import com.raival.fileexplorer.tab.file.FileExplorerTabFragment
12 | import com.raival.fileexplorer.tab.file.dialog.FileInfoDialog
13 | import com.raival.fileexplorer.tab.file.misc.FileUtils
14 | import com.raival.fileexplorer.util.Utils
15 |
16 | class PathHistoryAdapter(private val parentFragment: FileExplorerTabFragment) :
17 | RecyclerView.Adapter() {
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
19 | @SuppressLint("InflateParams") val v =
20 | LayoutInflater.from(parent.context).inflate(
21 | R.layout.file_explorer_tab_path_history_view,
22 | null
23 | )
24 | v.layoutParams = ViewGroup.LayoutParams(
25 | ViewGroup.LayoutParams.WRAP_CONTENT,
26 | ViewGroup.LayoutParams.MATCH_PARENT
27 | )
28 | return ViewHolder(v)
29 | }
30 |
31 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
32 | holder.bind()
33 | }
34 |
35 | override fun getItemCount(): Int {
36 | return parentFragment.pathHistory.size
37 | }
38 |
39 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
40 | var label: TextView
41 | fun bind() {
42 | val position = adapterPosition
43 | val file = parentFragment.pathHistory[position]
44 | label.text =
45 | if (file.isExternalStorageFolder()) FileUtils.INTERNAL_STORAGE else file.name
46 | label.setTextColor(
47 | if (position == itemCount - 1) Utils.getColorAttribute(
48 | R.attr.colorPrimary,
49 | parentFragment.requireActivity()
50 | ) else Utils.getColorAttribute(
51 | R.attr.colorOutline,
52 | parentFragment.requireActivity()
53 | )
54 | )
55 | itemView.setOnClickListener {
56 | parentFragment.setCurrentDirectory(file)
57 | // Restore RecyclerView state
58 | parentFragment.restoreRecyclerViewState()
59 | }
60 | itemView.setOnLongClickListener {
61 | FileInfoDialog(file).setUseDefaultFileInfo(true).show(
62 | parentFragment.parentFragmentManager, ""
63 | )
64 | true
65 | }
66 | }
67 |
68 | init {
69 | label = itemView.findViewById(R.id.text)
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/misc/APKSignerUtils.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.misc
2 |
3 | import com.raival.fileexplorer.App
4 | import com.raival.fileexplorer.tab.file.misc.BuildUtils.unzipFromAssets
5 | import java.io.File
6 |
7 | object APKSignerUtils {
8 | val pk8: File
9 | get() {
10 | val check = File(App.appContext.filesDir.toString() + "/build/testkey.pk8")
11 | if (check.exists()) {
12 | return check
13 | }
14 | unzipFromAssets(
15 | App.appContext,
16 | "build/testkey.pk8.zip",
17 | check.parentFile?.absolutePath
18 | )
19 | return check
20 | }
21 | val pem: File
22 | get() {
23 | val check = File(App.appContext.filesDir.toString() + "/build/testkey.x509.pem")
24 | if (check.exists()) {
25 | return check
26 | }
27 | unzipFromAssets(
28 | App.appContext,
29 | "build/testkey.x509.pem.zip",
30 | check.parentFile?.absolutePath
31 | )
32 | return check
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/misc/BuildUtils.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.misc
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import com.raival.fileexplorer.App
6 | import java.io.File
7 | import java.io.FileOutputStream
8 | import java.io.IOException
9 | import java.io.InputStream
10 | import java.util.zip.ZipEntry
11 | import java.util.zip.ZipInputStream
12 |
13 | object BuildUtils {
14 | private const val BUFFER_SIZE = 1024 * 10
15 | private const val TAG = "Decompress"
16 | val lambdaStubsJarFile: File
17 | get() {
18 | val check = File(App.appContext.filesDir.toString() + "/build/core-lambda-stubs.jar")
19 | if (check.exists()) {
20 | return check
21 | }
22 | unzipFromAssets(
23 | App.appContext,
24 | "build/lambda-stubs.zip",
25 | check.parentFile?.absolutePath
26 | )
27 | return check
28 | }
29 | val rtJarFile: File
30 | get() {
31 | val customRt = File(App.appContext.getExternalFilesDir(null), "build/rt.jar")
32 | if (customRt.exists() && customRt.isFile) {
33 | return customRt
34 | }
35 | val check = File(App.appContext.filesDir.toString() + "/build/rt.jar")
36 | if (check.exists()) {
37 | return check
38 | }
39 | unzipFromAssets(
40 | App.appContext,
41 | "build/rt.zip",
42 | check.parentFile?.absolutePath
43 | )
44 | return check
45 | }
46 |
47 | @JvmStatic
48 | fun unzipFromAssets(context: Context, zipFile: String, destination: String?) {
49 | var des = destination
50 | try {
51 | if (des == null || des.isEmpty()) des =
52 | context.filesDir.absolutePath
53 | val stream = context.assets.open(zipFile)
54 | unzip(stream, des)
55 | } catch (e: IOException) {
56 | e.printStackTrace()
57 | }
58 | }
59 |
60 | private fun dirChecker(destination: String?, dir: String) {
61 | val f = File(destination, dir)
62 | if (!f.isDirectory) {
63 | val success = f.mkdirs()
64 | if (!success) {
65 | Log.w(TAG, "Failed to create folder " + f.name)
66 | }
67 | }
68 | }
69 |
70 | private fun unzip(stream: InputStream, destination: String?) {
71 | dirChecker(destination, "")
72 | val buffer = ByteArray(BUFFER_SIZE)
73 | try {
74 | val zin = ZipInputStream(stream)
75 | var ze: ZipEntry
76 | while (zin.nextEntry.also { ze = it } != null) {
77 | Log.v(TAG, "Unzipping " + ze.name)
78 | if (ze.isDirectory) {
79 | dirChecker(destination, ze.name)
80 | } else {
81 | val f = File(destination, ze.name)
82 | if (!f.exists()) {
83 | val success = f.createNewFile()
84 | if (!success) {
85 | Log.w(
86 | TAG,
87 | com.raival.fileexplorer.util.Log.UNABLE_TO + " " + FileUtils.CREATE_FILE + " " + f.name
88 | )
89 | continue
90 | }
91 | val fileOutputStream = FileOutputStream(f)
92 | var count: Int
93 | while (zin.read(buffer).also { count = it } != -1) {
94 | fileOutputStream.write(buffer, 0, count)
95 | }
96 | zin.closeEntry()
97 | fileOutputStream.close()
98 | }
99 | }
100 | }
101 | zin.close()
102 | } catch (e: Exception) {
103 | Log.e(TAG, "unzip", e)
104 | }
105 | }
106 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/misc/FileOpener.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.misc
2 |
3 | import android.content.Intent
4 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
5 | import com.raival.fileexplorer.activity.MainActivity
6 | import com.raival.fileexplorer.activity.TextEditorActivity
7 | import com.raival.fileexplorer.extension.openFileWith
8 | import kotlinx.coroutines.CoroutineScope
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import java.io.File
12 |
13 | class FileOpener(private val mainActivity: MainActivity) {
14 | fun openFile(file: File) {
15 | if (!handleKnownFileExtensions(file)) {
16 | file.openFileWith(false)
17 | }
18 | }
19 |
20 | private fun handleKnownFileExtensions(file: File): Boolean {
21 | if (FileMimeTypes.textType.contains(file.extension.lowercase())
22 | || FileMimeTypes.codeType.contains(file.extension.lowercase())
23 | ) {
24 | val intent = Intent()
25 | intent.setClass(mainActivity, TextEditorActivity::class.java)
26 | intent.putExtra("file", file.absolutePath)
27 | mainActivity.startActivity(intent)
28 | return true
29 | }
30 | if (file.extension == FileMimeTypes.apkType) {
31 | val dialog = MaterialAlertDialogBuilder(mainActivity)
32 | .setMessage("Do you want to install this app?")
33 | .setPositiveButton("Install") { _, _ -> file.openFileWith(false) }
34 | CoroutineScope(Dispatchers.Main).launch {
35 | dialog.setTitle(FileUtils.getApkName(file))
36 | dialog.setIcon(FileUtils.getApkIcon(file))
37 | dialog.show()
38 | }
39 | return true
40 | }
41 | return false
42 | }
43 |
44 |
45 | companion object {
46 | private val TAG = FileOpener::class.java.simpleName
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/misc/ZipUtils.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.misc
2 |
3 | import net.lingala.zip4j.ZipFile
4 | import java.io.File
5 |
6 | fun archive(filesToCompress: ArrayList, zipFile: File?) {
7 | val zip = ZipFile(zipFile)
8 | for (file in filesToCompress) {
9 | if (file.isFile) {
10 | zip.addFile(file)
11 | } else {
12 | zip.addFolder(file)
13 | }
14 | }
15 | }
16 |
17 | fun extract(filesToExtract: ArrayList, directory: File) {
18 | for (file in filesToExtract) {
19 | if (file.isFile) {
20 | val output = File(directory, file.name.substring(0, file.name.lastIndexOf(".")))
21 | if (output.mkdir()) {
22 | ZipFile(file).extractAll(output.absolutePath)
23 | } else {
24 | ZipFile(file).extractAll(directory.absolutePath)
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/misc/md5/HashUtils.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.misc.md5
2 |
3 | import java.io.File
4 | import java.io.FileInputStream
5 | import java.io.InputStream
6 | import java.security.MessageDigest
7 |
8 | object HashUtils {
9 |
10 | private const val STREAM_BUFFER_LENGTH = 1024
11 |
12 | fun getCheckSumFromFile(digest: MessageDigest, filePath: String): String {
13 | val file = File(filePath)
14 | return getCheckSumFromFile(digest, file)
15 | }
16 |
17 | fun getCheckSumFromFile(digest: MessageDigest, file: File): String {
18 | val fis = FileInputStream(file)
19 | val byteArray = updateDigest(digest, fis).digest()
20 | fis.close()
21 | val hexCode = StringUtils.encodeHex(byteArray, true)
22 | return String(hexCode)
23 | }
24 |
25 | private fun updateDigest(digest: MessageDigest, data: InputStream): MessageDigest {
26 | val buffer = ByteArray(STREAM_BUFFER_LENGTH)
27 | var read = data.read(buffer, 0, STREAM_BUFFER_LENGTH)
28 | while (read > -1) {
29 | digest.update(buffer, 0, read)
30 | read = data.read(buffer, 0, STREAM_BUFFER_LENGTH)
31 | }
32 | return digest
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/misc/md5/MessageDigestAlgorithm.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.misc.md5
2 |
3 | object MessageDigestAlgorithm {
4 | const val MD2 = "MD2"
5 | const val MD5 = "MD5"
6 | const val SHA_1 = "SHA-1"
7 | const val SHA_224 = "SHA-224"
8 | const val SHA_256 = "SHA-256"
9 | const val SHA_384 = "SHA-384"
10 | const val SHA_512 = "SHA-512"
11 | const val SHA_512_224 = "SHA-512/224"
12 | const val SHA_512_256 = "SHA-512/256"
13 | const val SHA3_224 = "SHA3-224"
14 | const val SHA3_256 = "SHA3-256"
15 | const val SHA3_384 = "SHA3-384"
16 | const val SHA3_512 = "SHA3-512"
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/misc/md5/StringUtils.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.misc.md5
2 |
3 | object StringUtils {
4 |
5 | private val DIGITS_LOWER =
6 | charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')
7 |
8 | private val DIGITS_UPPER =
9 | charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
10 |
11 | fun encodeHex(data: ByteArray, toLowerCase: Boolean): CharArray {
12 | return encodeHex(data, if (toLowerCase) DIGITS_LOWER else DIGITS_UPPER)
13 | }
14 |
15 | fun encodeHex(data: ByteArray, toDigits: CharArray): CharArray {
16 | val l = data.size
17 | val out = CharArray(l shl 1)
18 | // two characters form the hex value.
19 | var i = 0
20 | var j = 0
21 | while (i < l) {
22 | out[j++] = toDigits[0xF0 and data[i].toInt() ushr 4]
23 | out[j++] = toDigits[0x0F and data[i].toInt()]
24 | i++
25 | }
26 | return out
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/model/FileItem.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.model
2 |
3 | import java.io.File
4 |
5 | class FileItem(var f: File) {
6 | @JvmField
7 | var isSelected = false
8 |
9 | @JvmField
10 | var file: File = f
11 | var details = ""
12 | var name = ""
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/model/Task.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.model
2 |
3 | import java.io.File
4 |
5 | abstract class Task {
6 | abstract val name: String?
7 | abstract val details: String?
8 | abstract val isValid: Boolean
9 |
10 | abstract fun setActiveDirectory(directory: File)
11 | abstract fun start(onUpdate: OnUpdateListener, onFinish: OnFinishListener)
12 |
13 | interface OnUpdateListener {
14 | fun onUpdate(progress: String)
15 | }
16 |
17 | interface OnFinishListener {
18 | fun onFinish(result: String)
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/observer/FileListObserver.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.observer
2 |
3 | import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
4 | import com.raival.fileexplorer.tab.file.FileExplorerTabFragment
5 | import com.raival.fileexplorer.tab.file.adapter.FileListAdapter
6 |
7 | class FileListObserver(
8 | private val parentFragment: FileExplorerTabFragment,
9 | private val fileListAdapter: FileListAdapter?
10 | ) : AdapterDataObserver() {
11 |
12 | override fun onChanged() {
13 | super.onChanged()
14 | checkIfEmpty()
15 | }
16 |
17 | private fun checkIfEmpty() {
18 | parentFragment.showPlaceholder(fileListAdapter != null && fileListAdapter.itemCount == 0)
19 | }
20 |
21 | init {
22 | checkIfEmpty()
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/task/CompressTask.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.task
2 |
3 | import com.raival.fileexplorer.tab.file.misc.archive
4 | import com.raival.fileexplorer.tab.file.model.Task
5 | import kotlinx.coroutines.CoroutineScope
6 | import kotlinx.coroutines.Dispatchers
7 | import kotlinx.coroutines.launch
8 | import kotlinx.coroutines.withContext
9 | import java.io.File
10 |
11 | class CompressTask(private val filesToCompress: ArrayList) : Task() {
12 | private var zipFile: File? = null
13 | override val name: String
14 | get() = "Compress"
15 | override val details: String
16 | get() {
17 | val sb = StringBuilder()
18 | var first = true
19 | for (file in filesToCompress) {
20 | if (!first) {
21 | sb.append(", ")
22 | }
23 | sb.append(file.name)
24 | first = false
25 | }
26 | return sb.toString()
27 | }
28 | override val isValid: Boolean
29 | get() {
30 | for (file in filesToCompress) {
31 | if (!file.exists()) return false
32 | }
33 | return true
34 | }
35 |
36 | override fun setActiveDirectory(directory: File) {
37 | zipFile = directory
38 | }
39 |
40 | override fun start(onUpdate: OnUpdateListener, onFinish: OnFinishListener) {
41 | CoroutineScope(Dispatchers.IO).launch {
42 | withContext(Dispatchers.Main) {
43 | onUpdate.onUpdate("Compressing....")
44 | }
45 | try {
46 | archive(filesToCompress, zipFile)
47 | withContext(Dispatchers.Main) {
48 | onFinish.onFinish("Files have been compressed successfully")
49 | }
50 | } catch (e: Exception) {
51 | e.printStackTrace()
52 | withContext(Dispatchers.Main) {
53 | onFinish.onFinish(e.toString())
54 | }
55 | }
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/task/CopyTask.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.task
2 |
3 | import com.raival.fileexplorer.tab.file.misc.FileUtils
4 | import com.raival.fileexplorer.tab.file.model.Task
5 | import kotlinx.coroutines.CoroutineScope
6 | import kotlinx.coroutines.Dispatchers
7 | import kotlinx.coroutines.launch
8 | import kotlinx.coroutines.withContext
9 | import java.io.File
10 |
11 | class CopyTask(private val filesToCopy: ArrayList) : Task() {
12 | private var activeDirectory: File? = null
13 | override val name: String
14 | get() = "Copy"
15 | override val details: String
16 | get() {
17 | val sb = StringBuilder()
18 | var first = true
19 | for (file in filesToCopy) {
20 | if (!first) {
21 | sb.append(", ")
22 | }
23 | sb.append(file.name)
24 | first = false
25 | }
26 | return sb.toString()
27 | }
28 | override val isValid: Boolean
29 | get() {
30 | for (file in filesToCopy) {
31 | if (!file.exists()) return false
32 | }
33 | return true
34 | }
35 |
36 | override fun setActiveDirectory(directory: File) {
37 | activeDirectory = directory
38 | }
39 |
40 | override fun start(onUpdate: OnUpdateListener, onFinish: OnFinishListener) {
41 | CoroutineScope(Dispatchers.IO).launch {
42 | var error = false
43 | try {
44 | var progress = 1
45 | for (file in filesToCopy) {
46 | try {
47 | val finalProgress = progress
48 | withContext(Dispatchers.Main) {
49 | onUpdate.onUpdate(
50 | "["
51 | + finalProgress
52 | + "/"
53 | + filesToCopy.size
54 | + "]"
55 | + "Copying "
56 | + file.name
57 | )
58 | }
59 | FileUtils.copy(file, activeDirectory!!, true)
60 | } catch (exception: Exception) {
61 | error = true
62 | }
63 | ++progress
64 | }
65 | val finalError = error
66 | withContext(Dispatchers.Main) { onFinish.onFinish(if (finalError) "An error occurred, some files didn't get copied" else "Files copied successfully") }
67 | } catch (e: Exception) {
68 | e.printStackTrace()
69 | withContext(Dispatchers.Main) { onFinish.onFinish(e.toString()) }
70 | }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/task/CutTask.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.task
2 |
3 | import com.raival.fileexplorer.tab.file.misc.FileUtils
4 | import com.raival.fileexplorer.tab.file.model.Task
5 | import kotlinx.coroutines.CoroutineScope
6 | import kotlinx.coroutines.Dispatchers
7 | import kotlinx.coroutines.launch
8 | import kotlinx.coroutines.withContext
9 | import java.io.File
10 |
11 | class CutTask(private val filesToCut: ArrayList) : Task() {
12 | private var activeDirectory: File? = null
13 | override val name: String
14 | get() = "Cut"
15 | override val details: String
16 | get() {
17 | val sb = StringBuilder()
18 | var first = true
19 | for (file in filesToCut) {
20 | if (!first) {
21 | sb.append(", ")
22 | }
23 | sb.append(file.name)
24 | first = false
25 | }
26 | return sb.toString()
27 | }
28 | override val isValid: Boolean
29 | get() {
30 | for (file in filesToCut) {
31 | if (!file.exists()) return false
32 | }
33 | return true
34 | }
35 |
36 | override fun setActiveDirectory(directory: File) {
37 | activeDirectory = directory
38 | }
39 |
40 | override fun start(onUpdate: OnUpdateListener, onFinish: OnFinishListener) {
41 | CoroutineScope(Dispatchers.IO).launch {
42 | var error = false
43 | try {
44 | var progress = 1
45 | for (file in filesToCut) {
46 | try {
47 | val finalProgress = progress
48 | withContext(Dispatchers.Main) {
49 | onUpdate.onUpdate(
50 | "["
51 | + finalProgress
52 | + "/"
53 | + filesToCut.size
54 | + "]"
55 | + "Moving "
56 | + file.name
57 | )
58 | }
59 | FileUtils.move(file, activeDirectory)
60 | } catch (exception: Exception) {
61 | error = true
62 | }
63 | ++progress
64 | }
65 | val finalError = error
66 | withContext(Dispatchers.Main) { onFinish.onFinish(if (finalError) "An error occurred, some files haven't been moved" else "Files have been moved successfully") }
67 | } catch (e: Exception) {
68 | e.printStackTrace()
69 | withContext(Dispatchers.Main) { onFinish.onFinish(e.toString()) }
70 | }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/tab/file/task/ExtractTask.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.tab.file.task
2 |
3 | import android.os.Handler
4 | import android.os.Looper
5 | import com.raival.fileexplorer.tab.file.misc.extract
6 | import com.raival.fileexplorer.tab.file.model.Task
7 | import kotlinx.coroutines.CoroutineScope
8 | import kotlinx.coroutines.Dispatchers
9 | import kotlinx.coroutines.launch
10 | import kotlinx.coroutines.withContext
11 | import java.io.File
12 |
13 | class ExtractTask(private val filesToExtract: ArrayList) : Task() {
14 | private var activeDirectory: File? = null
15 | override val name: String
16 | get() = "Extract"
17 | override val details: String
18 | get() {
19 | val sb = StringBuilder()
20 | var first = true
21 | for (file in filesToExtract) {
22 | if (!first) {
23 | sb.append(", ")
24 | }
25 | sb.append(file.name)
26 | first = false
27 | }
28 | return sb.toString()
29 | }
30 | override val isValid: Boolean
31 | get() {
32 | for (file in filesToExtract) {
33 | if (!file.exists()) return false
34 | }
35 | return true
36 | }
37 |
38 | override fun setActiveDirectory(directory: File) {
39 | activeDirectory = directory
40 | }
41 |
42 | override fun start(onUpdate: OnUpdateListener, onFinish: OnFinishListener) {
43 | CoroutineScope(Dispatchers.IO).launch {
44 | Handler(Looper.getMainLooper()).post { onUpdate.onUpdate("Extracting....") }
45 | try {
46 | extract(filesToExtract, activeDirectory!!)
47 | withContext(Dispatchers.Main) { onFinish.onFinish("Files have been extracted successfully") }
48 | } catch (e: Exception) {
49 | e.printStackTrace()
50 | withContext(Dispatchers.Main) { onFinish.onFinish(e.toString()) }
51 | }
52 | }.start()
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/util/PrefsUtils.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.util
2 |
3 | import com.google.gson.Gson
4 | import com.pixplicity.easyprefs.library.Prefs
5 | import com.raival.fileexplorer.activity.SettingsActivity
6 | import com.raival.fileexplorer.extension.getStringList
7 |
8 | object PrefsUtils {
9 | const val SORT_NAME_A2Z = 1
10 | const val SORT_NAME_Z2A = 2
11 | const val SORT_SIZE_SMALLER = 3
12 | const val SORT_SIZE_BIGGER = 4
13 | const val SORT_DATE_OLDER = 5
14 | const val SORT_DATE_NEWER = 6
15 |
16 | object TextEditor {
17 | var textEditorWordwrap: Boolean
18 | get() = Prefs.getBoolean("text_editor_wordwrap", false)
19 | set(wordwrap) {
20 | Prefs.putBoolean("text_editor_wordwrap", wordwrap)
21 | }
22 | var textEditorShowLineNumber: Boolean
23 | get() = Prefs.getBoolean("text_editor_show_line_number", true)
24 | set(showLineNumber) {
25 | Prefs.putBoolean("text_editor_show_line_number", showLineNumber)
26 | }
27 | var textEditorPinLineNumber: Boolean
28 | get() = Prefs.getBoolean("text_editor_pin_line_number", true)
29 | set(pinLineNumber) {
30 | Prefs.putBoolean("text_editor_pin_line_number", pinLineNumber)
31 | }
32 | var textEditorMagnifier: Boolean
33 | get() = Prefs.getBoolean("text_editor_magnifier", true)
34 | set(magnifier) {
35 | Prefs.putBoolean("text_editor_magnifier", magnifier)
36 | }
37 | var textEditorReadOnly: Boolean
38 | get() = Prefs.getBoolean("text_editor_read_only", false)
39 | set(readOnly) {
40 | Prefs.putBoolean("text_editor_read_only", readOnly)
41 | }
42 | var textEditorAutocomplete: Boolean
43 | get() = Prefs.getBoolean("text_editor_autocomplete", false)
44 | set(autocomplete) {
45 | Prefs.putBoolean("text_editor_autocomplete", autocomplete)
46 | }
47 | val fileExplorerTabBookmarks: ArrayList
48 | get() = Prefs.getString("file_explorer_tab_bookmarks", "[]").getStringList()
49 | }
50 |
51 | object FileExplorerTab {
52 | @JvmStatic
53 | var sortingMethod: Int
54 | get() = Prefs.getInt("sorting_method", SORT_NAME_A2Z)
55 | set(method) {
56 | Prefs.putInt("sorting_method", method)
57 | }
58 |
59 | fun setListFoldersFirst(b: Boolean) {
60 | Prefs.putBoolean("list_folders_first", b)
61 | }
62 |
63 | @JvmStatic
64 | fun listFoldersFirst(): Boolean {
65 | return Prefs.getBoolean("list_folders_first", true)
66 | }
67 | }
68 |
69 | object Settings {
70 | var deepSearchFileSizeLimit: Long
71 | get() = Prefs.getLong(
72 | "settings_deep_search_file_size_limit",
73 | (6 * 1024 * 1024).toLong()
74 | )
75 | set(limit) {
76 | Prefs.putLong("settings_deep_search_file_size_limit", limit)
77 | }
78 |
79 | @JvmStatic
80 | var themeMode: String
81 | get() = Prefs.getString("settings_theme_mode", SettingsActivity.THEME_MODE_AUTO)
82 | set(themeMode) {
83 | Prefs.putString("settings_theme_mode", themeMode)
84 | }
85 | var logMode: String
86 | get() = Prefs.getString("settings_log_mode", SettingsActivity.LOG_MODE_ERRORS_ONLY)
87 | set(logMode) {
88 | Prefs.putString("settings_log_mode", logMode)
89 | }
90 | var showBottomToolbarLabels: Boolean
91 | get() = Prefs.getBoolean("settings_show_bottom_toolbar_labels", true)
92 | set(showBottomToolbarLabels) {
93 | Prefs.putBoolean("settings_show_bottom_toolbar_labels", showBottomToolbarLabels)
94 | }
95 | }
96 |
97 | object General {
98 | fun setFileExplorerTabBookmarks(list: ArrayList) {
99 | Prefs.putString("file_explorer_tab_bookmarks", Gson().toJson(list))
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/raival/fileexplorer/util/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.raival.fileexplorer.util
2 |
3 | import android.content.Context
4 | import android.content.res.Configuration
5 | import android.util.TypedValue
6 | import androidx.annotation.ColorInt
7 | import com.raival.fileexplorer.App
8 | import com.raival.fileexplorer.activity.SettingsActivity
9 | import com.raival.fileexplorer.util.PrefsUtils.Settings.themeMode
10 | import java.util.*
11 |
12 | object Utils {
13 | private const val ALLOWED_CHARACTERS = "0123456789qwertyuiopasdfghjklzxcvbnm_"
14 |
15 | @ColorInt
16 | fun getColorAttribute(id: Int, context: Context): Int {
17 | val out = TypedValue()
18 | context.theme.resolveAttribute(id, out, true)
19 | return out.data
20 | }
21 |
22 | val isDarkMode: Boolean
23 | get() = when (themeMode) {
24 | SettingsActivity.THEME_MODE_DARK -> {
25 | true
26 | }
27 | SettingsActivity.THEME_MODE_LIGHT -> {
28 | false
29 | }
30 | else -> {
31 | (App.appContext.resources.configuration.uiMode
32 | and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
33 | }
34 | }
35 |
36 | fun getRandomString(sizeOfRandomString: Int): String {
37 | val random = Random()
38 | val sb = StringBuilder(sizeOfRandomString)
39 | for (i in 0 until sizeOfRandomString) {
40 | sb.append(ALLOWED_CHARACTERS[random.nextInt(ALLOWED_CHARACTERS.length)])
41 | }
42 | return sb.toString()
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/apk_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable-v24/apk_placeholder.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/app_icon_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/archive_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/archive_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/code_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/code_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/doc_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/doc_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/fastscroll_thumb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/font_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/font_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_add_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_assignment_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_bookmark_add_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_bookmark_remove_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_bug_report_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_chevron_right_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_delete_sweep_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_file_copy_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_folder_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_folder_open_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_info_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_layers_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_logout_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_more_vert_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_open_in_browser_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_open_in_new_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_restart_alt_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_save_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_select_all_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_sort_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_code_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_compress_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_content_cut_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_delete_forever_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_edit_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_edit_note_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_exit_to_app_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_home_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_insert_drive_file_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_key_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_manage_search_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_menu_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_play_arrow_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_redo_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_search_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_settings_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_share_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_tab_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_timelapse_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_undo_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/image_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/image_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/java_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/java_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/kt_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/kt_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/music_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/music_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pdf_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/pdf_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/powerpoint_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/powerpoint_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sql_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/sql_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/svg_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/svg_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/txt_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/txt_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/unknown_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/unknown_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/vector_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/vector_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/video_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/video_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/xls_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/xls_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/xml_file_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/drawable/xml_file_extension.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
23 |
24 |
30 |
31 |
36 |
37 |
45 |
46 |
50 |
51 |
52 |
53 |
58 |
59 |
65 |
66 |
70 |
71 |
72 |
73 |
74 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_drawer_bookmark_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
26 |
27 |
32 |
33 |
40 |
41 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/apps_tab_app_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
22 |
23 |
30 |
31 |
32 |
33 |
38 |
39 |
47 |
48 |
55 |
56 |
63 |
64 |
65 |
66 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/apps_tab_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/bottom_bar_menu_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/common_custom_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
21 |
30 |
31 |
32 |
36 |
37 |
41 |
42 |
52 |
53 |
60 |
61 |
62 |
63 |
64 |
70 |
71 |
77 |
78 |
82 |
83 |
90 |
91 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/common_options_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
31 |
32 |
37 |
38 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/common_options_dialog_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
23 |
24 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_file_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
23 |
24 |
31 |
32 |
33 |
34 |
39 |
40 |
48 |
49 |
56 |
57 |
58 |
59 |
65 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
29 |
30 |
36 |
37 |
38 |
44 |
45 |
58 |
59 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_info_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
30 |
31 |
32 |
37 |
38 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_info_dialog_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_path_history_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_placeholder.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_task_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
27 |
28 |
32 |
33 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_explorer_tab_task_dialog_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
23 |
24 |
29 |
30 |
31 |
40 |
41 |
50 |
51 |
60 |
61 |
62 |
63 |
64 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/input.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/progress_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/search_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
19 |
20 |
21 |
25 |
26 |
32 |
33 |
40 |
41 |
42 |
46 |
47 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
75 |
76 |
81 |
82 |
88 |
89 |
93 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/text_editor_completion_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
24 |
25 |
31 |
32 |
38 |
39 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/tab_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/text_editor_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/app_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/app_icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-hdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/app_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-hdpi/app_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-mdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/app_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-mdpi/app_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-xhdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/app_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-xhdpi/app_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-xxhdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/app_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-xxhdpi/app_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-xxxhdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/app_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/app/src/main/res/mipmap-xxxhdpi/app_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2F0066FF
4 | #0FFDFDFD
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/app_icon_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #262A30
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2F0066FF
4 | #0A000000
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1B2221
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | File Explorer
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
14 |
15 |
20 |
21 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
--------------------------------------------------------------------------------
/assets/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/assets/screenshot1.png
--------------------------------------------------------------------------------
/assets/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/assets/screenshot2.png
--------------------------------------------------------------------------------
/assets/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/assets/screenshot3.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.7.20-RC'
4 | repositories {
5 | google()
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.2.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | task clean(type: Delete) {
17 | delete rootProject.buildDir
18 | }
19 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | File Explorer is a full-featured and lightweight file manager with Material 3 Dynamic colors.
2 |
3 |
Features:
4 |
5 | - All basic file management functionality (e.g. copy, paste,.. etc) are supported.
6 | - Support for multiple tabs, and Tasks which make managing files much easier.
7 | - Powerful Code Editor (Sora Editor).
8 | - Deep search that allows you to search in files contents.
9 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/img1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/fastlane/metadata/android/en-US/images/phoneScreenshots/img1.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/img2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/fastlane/metadata/android/en-US/images/phoneScreenshots/img2.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/img3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/fastlane/metadata/android/en-US/images/phoneScreenshots/img3.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | a full-featured file manager for android
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jul 14 16:17:27 UTC 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if %ERRORLEVEL% equ 0 goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if %ERRORLEVEL% equ 0 goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | set EXIT_CODE=%ERRORLEVEL%
84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
86 | exit /b %EXIT_CODE%
87 |
88 | :mainEnd
89 | if "%OS%"=="Windows_NT" endlocal
90 |
91 | :omega
92 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | dependencyResolutionManagement {
2 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
3 | repositories {
4 | google()
5 | mavenCentral()
6 | jcenter() // Warning: this repository is going to shut down soon
7 | }
8 | }
9 | rootProject.name = "File Explorer"
10 | include ':app'
11 |
--------------------------------------------------------------------------------
/testkey.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Raival-e/File-Explorer/3ee7490d759ab0fad7e16335c6347d88ae5de5d3/testkey.keystore
--------------------------------------------------------------------------------