├── .idea
├── .name
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── inspectionProfiles
│ ├── profiles_settings.xml
│ └── Project_Default.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_add-web.png
│ │ ├── ic_save-web.png
│ │ ├── ic_add_empty-web.png
│ │ ├── ic_empty_add-web.png
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_add.png
│ │ │ │ ├── ic_save.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_add_empty.png
│ │ │ │ └── ic_empty_add.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_add.png
│ │ │ │ ├── ic_save.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_add_empty.png
│ │ │ │ └── ic_empty_add.png
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_cut.png
│ │ │ │ ├── ic_back.png
│ │ │ │ ├── ic_cancel.png
│ │ │ │ ├── ic_copy.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ ├── ic_info.png
│ │ │ │ ├── ic_paste.png
│ │ │ │ ├── ic_search.png
│ │ │ │ └── ic_sort.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_cut.png
│ │ │ │ ├── ic_back.png
│ │ │ │ ├── ic_cancel.png
│ │ │ │ ├── ic_copy.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ ├── ic_info.png
│ │ │ │ ├── ic_paste.png
│ │ │ │ ├── ic_search.png
│ │ │ │ └── ic_sort.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_add.png
│ │ │ │ ├── ic_save.png
│ │ │ │ ├── ic_add_empty.png
│ │ │ │ ├── ic_empty_add.png
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_add.png
│ │ │ │ ├── ic_save.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_add_empty.png
│ │ │ │ └── ic_empty_add.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ic_back.png
│ │ │ │ ├── ic_copy.png
│ │ │ │ ├── ic_cut.png
│ │ │ │ ├── ic_info.png
│ │ │ │ ├── ic_paste.png
│ │ │ │ ├── ic_sort.png
│ │ │ │ ├── ic_cancel.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ └── ic_search.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── ic_back.png
│ │ │ │ ├── ic_copy.png
│ │ │ │ ├── ic_cut.png
│ │ │ │ ├── ic_info.png
│ │ │ │ ├── ic_sort.png
│ │ │ │ ├── ic_cancel.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ ├── ic_paste.png
│ │ │ │ └── ic_search.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_add.png
│ │ │ │ ├── ic_save.png
│ │ │ │ ├── ic_add_empty.png
│ │ │ │ ├── ic_empty_add.png
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ ├── drawable
│ │ │ │ ├── state_file_selection.xml
│ │ │ │ ├── path_gradinet.xml
│ │ │ │ ├── path_onpress_colors.xml
│ │ │ │ └── colored_progress_bar.xml
│ │ │ ├── values-v21
│ │ │ │ └── styles.xml
│ │ │ ├── menu
│ │ │ │ ├── folder_popup_menu.xml
│ │ │ │ ├── sort_files_options.xml
│ │ │ │ ├── menu_edit_connections.xml
│ │ │ │ ├── remote_files_menu.xml
│ │ │ │ ├── menu_main.xml
│ │ │ │ └── files_action_mode_menu.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ ├── anim
│ │ │ │ ├── fab_hide.xml
│ │ │ │ └── fab_show.xml
│ │ │ └── layout
│ │ │ │ ├── content_main.xml
│ │ │ │ ├── path_recycler_item.xml
│ │ │ │ ├── file_rename_dialog.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── file_info_dialog.xml
│ │ │ │ ├── fragment_ftpview_pager.xml
│ │ │ │ ├── fragment_connections.xml
│ │ │ │ ├── files_recycler_item.xml
│ │ │ │ ├── fragment_files.xml
│ │ │ │ ├── dialog_transfer_progress.xml
│ │ │ │ ├── file_dialog.xml
│ │ │ │ ├── fragment_edit_connection.xml
│ │ │ │ └── ftpconnection_item.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── peppe
│ │ │ │ └── ftpclient
│ │ │ │ └── androidftp
│ │ │ │ ├── FTPFilesExplorer
│ │ │ │ ├── FTPBusEvents
│ │ │ │ │ └── UploadFilesEvent.java
│ │ │ │ ├── FTPPagerAdapter.java
│ │ │ │ ├── PathAdapter.java
│ │ │ │ ├── FTPLocalExplorer
│ │ │ │ │ ├── UploadProgressDialog.java
│ │ │ │ │ ├── UploadDialog.java
│ │ │ │ │ └── LocalFilesAdapter.java
│ │ │ │ ├── FTPRemoteExplorer
│ │ │ │ │ ├── DownloadProgressDialog.java
│ │ │ │ │ ├── DownloadDialog.java
│ │ │ │ │ └── RemoteFilesAdapter.java
│ │ │ │ ├── FTPViewPager.java
│ │ │ │ └── FilesAdapter.java
│ │ │ │ ├── FTPConnectionsList
│ │ │ │ ├── FTPConnectionsDBHelper.java
│ │ │ │ ├── ConnectionsFragment.java
│ │ │ │ ├── ConnectionCursorAdapter.java
│ │ │ │ └── EditConnectionFragment.java
│ │ │ │ └── FTPClientMain
│ │ │ │ ├── FTPConnection.java
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── peppe
│ │ │ └── ftpclient
│ │ │ └── androidftp
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── peppe
│ │ └── ftpclient
│ │ └── androidftp
│ │ └── ApplicationTest.java
├── proguard-rules.pro
├── build.gradle
└── app.iml
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── .gitattributes
├── README.md
├── gradle.properties
├── AndroidFTP.iml
├── gradlew.bat
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | AndroidFTP
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/ic_add-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/ic_add-web.png
--------------------------------------------------------------------------------
/app/src/main/ic_save-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/ic_save-web.png
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/ic_add_empty-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/ic_add_empty-web.png
--------------------------------------------------------------------------------
/app/src/main/ic_empty_add-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/ic_empty_add-web.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-hdpi/ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-mdpi/ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_cut.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_cut.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-hdpi/ic_save.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-mdpi/ic_save.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xhdpi/ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xhdpi/ic_save.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxhdpi/ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_cancel.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_copy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_paste.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_paste.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-hdpi/ic_sort.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_cancel.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_copy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_paste.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_paste.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-mdpi/ic_sort.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_copy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_cut.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_paste.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_paste.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_sort.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_copy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_cut.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_sort.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxhdpi/ic_save.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_save.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_cancel.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xhdpi/ic_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_cancel.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_paste.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_paste.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/drawable-xxhdpi/ic_search.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_add_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-hdpi/ic_add_empty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_empty_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-hdpi/ic_empty_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_add_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-mdpi/ic_add_empty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_empty_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-mdpi/ic_empty_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_add_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xhdpi/ic_add_empty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_empty_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xhdpi/ic_empty_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_add_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxhdpi/ic_add_empty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_empty_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxhdpi/ic_empty_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_add_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_add_empty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_empty_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_empty_add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/papigers/androidftp/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Oct 11 15:40:31 IDT 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
7 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/state_file_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/folder_popup_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #FF6C79C2
5 | #303F9F
6 | #263380
7 | #FF4081
8 | #cfcfcf
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/path_gradinet.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/test/java/com/peppe/ftpclient/androidftp/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/peppe/ftpclient/androidftp/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPBusEvents/UploadFilesEvent.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPBusEvents;
2 |
3 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPLocalExplorer.LocalFilesFragment;
4 |
5 | /**
6 | * Created by Geri on 27/10/2015.
7 | */
8 | public class UploadFilesEvent {
9 | public LocalFilesFragment.LFileMap files;
10 |
11 | public UploadFilesEvent(LocalFilesFragment.LFileMap files){
12 | this.files = files;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/sort_files_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
9 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_edit_connections.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/path_onpress_colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
7 |
9 |
10 |
11 |
12 | -
13 |
14 |
16 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/remote_files_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
4 |
6 |
7 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\gersh_000\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fab_hide.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
14 |
15 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fab_show.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
14 |
15 |
16 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndroidFTP
2 | ## Android FTP Client
3 |
4 | This is a project I've created, trying to learn Android.
5 | AndroidFTP is an FTP client for android, allowing you to manage connections to FTP servers. It allows the user to download/upload files to the FTP server, delete and rename/move files.
6 | This application is essentially an Android interface for Appache's [FTPClient](https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html) which is used as a black box.
7 | Apart from learning to create user interfaces in android, I've also learned how to perform async actions in Android, as well as writing storage and network related code.
8 |
9 | While being fully functional, I've abandoned the project, and therefore it lacks of finishing touches, such as some minor bug fixing, design, and has some missing features.
10 |
11 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/path_recycler_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
21 |
--------------------------------------------------------------------------------
/AndroidFTP.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.peppe.ftpclient.androidftp"
9 | minSdkVersion 11
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.0.1'
26 | compile 'com.android.support:recyclerview-v7:+'
27 | compile 'com.android.support:design:23.0.1'
28 | compile 'commons-net:commons-net:3.3'
29 | compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar'
30 | compile 'de.greenrobot:eventbus:2.4.0'
31 | //compile 'commons-validator:commons-validator:1.4.1'
32 | }
33 |
34 | configurations {
35 | all*.exclude group: 'commons-logging', module: 'commons-logging'
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_rename_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
18 |
19 |
20 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/colored_progress_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
11 | -
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 | -
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_info_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
21 |
22 |
29 |
30 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_ftpview_pager.xml:
--------------------------------------------------------------------------------
1 |
9 |
15 |
16 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_connections.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
18 |
19 |
20 |
24 |
25 |
26 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/files_action_mode_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
18 |
19 |
23 |
24 |
29 |
30 |
36 |
37 |
42 |
43 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/files_recycler_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
19 |
20 |
34 |
35 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 |
7 | import com.peppe.ftpclient.androidftp.FTPClientMain.FTPConnection;
8 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
9 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPLocalExplorer.LocalFilesFragment;
10 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPRemoteExplorer.RemoteFilesFragment;
11 |
12 | import org.apache.commons.net.ftp.FTPClient;
13 |
14 | /**
15 | * Created by Geri on 19/10/2015.
16 | */
17 | public class FTPPagerAdapter extends FragmentPagerAdapter {
18 |
19 | private FTPClient client;
20 | private MainActivity activity;
21 | private FTPConnection connection;
22 |
23 | @Override
24 | public Fragment getItem(int position) {
25 | switch(position){
26 | //remote
27 | case 0:
28 | RemoteFilesFragment remote = new RemoteFilesFragment();
29 | remote.setClient(client);
30 | remote.connection = connection;
31 | activity.setRemoteFragment(remote);
32 | return remote;
33 | //local
34 | case 1:
35 | LocalFilesFragment local = new LocalFilesFragment();
36 | local.connection = connection;
37 | activity.setLocalFragment(local);
38 | return local;
39 | default:
40 | return new Fragment();
41 | }
42 | }
43 |
44 | @Override
45 | public int getCount() {
46 | return 2;
47 | }
48 |
49 | public FTPPagerAdapter(FTPClient client, FTPConnection connection, MainActivity activity , FragmentManager mgr){
50 | super(mgr);
51 | this.client = client;
52 | this.connection = connection;
53 | this.activity = activity;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_files.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
18 |
19 |
27 |
28 |
39 |
40 |
46 |
47 |
55 |
56 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_transfer_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
21 |
22 |
31 |
32 |
33 |
34 |
41 |
42 |
49 |
50 |
59 |
60 |
61 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidFTP
3 | Settings
4 | Save
5 | \@
6 | Name
7 | Host
8 | User
9 | Password
10 | Port
11 | 21
12 | Protocol
13 | Anonymous Connection
14 | anonymous
15 | Please enter a valid port between 1 and 65535
16 | Please enter a valid host
17 | Please enter a valid user
18 | No Connections
19 | Download
20 | Open
21 | Rename
22 | Delete
23 | Cancel
24 | No Files
25 | Click to allow storage access
26 | Upload
27 | 0%
28 | Are you sure you want to delete
29 | Yes
30 | No
31 | %d Selected
32 | Select
33 |
34 |
35 | No storage access. Can\'t display files.
36 | No storage access. Can\'t download files.
37 | Now, try again! :)
38 |
39 |
40 | Download
41 | Upload
42 | Delete
43 | Rename
44 | New Name
45 | Cut
46 | Copy
47 | Paste
48 | Info
49 | Copy URL
50 | Share
51 |
52 | Share File %s:
53 | Sort
54 | Search
55 | Sort by name
56 | Sort by size
57 | Sort by type
58 | Sort by modification time
59 |
60 |
61 | - FTP
62 | - FTPS
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/PathAdapter.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.util.Log;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 |
10 | import com.peppe.ftpclient.androidftp.R;
11 |
12 | import java.util.ArrayList;
13 |
14 | /**
15 | * Created by Geri on 19/10/2015.
16 | */
17 | public class PathAdapter extends RecyclerView.Adapter {
18 | private static final String TAG = "PATH_ADAPTER";
19 | protected ArrayList dataset;
20 | protected FilesFragment fragment;
21 |
22 | public PathAdapter(FilesFragment fragment) {
23 | this.fragment = fragment;
24 | }
25 |
26 |
27 | public void setDataset(ArrayList dataset) {
28 | if (dataset == null)
29 | Log.d(TAG, "path dataset null");
30 | this.dataset = dataset;
31 | }
32 |
33 | @Override
34 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
35 | View v = LayoutInflater.from(parent.getContext())
36 | .inflate(R.layout.path_recycler_item, parent, false);
37 |
38 | return new ViewHolder(v);
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(ViewHolder holder, int position) {
43 | holder.getTextView().setText(dataset.get(position) + " > ");
44 | String path = "";
45 | for (int i = 1; i <= position; i++) {
46 | path += dataset.get(i);
47 | if (dataset.get(i).charAt(dataset.get(i).length() - 1) != '/' && i != position)
48 | path += "/";
49 | }
50 | path = "/" + path;
51 | holder.setOnClickListener(new changeDirOnClickListener(path, fragment));
52 | }
53 |
54 | @Override
55 | public int getItemCount() {
56 | if (dataset == null)
57 | return 0;
58 | return dataset.size();
59 | }
60 |
61 | protected static class ViewHolder extends RecyclerView.ViewHolder {
62 | private final TextView textView;
63 | public final String TAG = "PATH_VH";
64 | private View v;
65 |
66 | public ViewHolder(View v) {
67 | super(v);
68 | // Define click listener for the ViewHolder's View.
69 | v.setOnClickListener(new View.OnClickListener() {
70 | @Override
71 | public void onClick(View v) {
72 | Log.d(TAG, "Element " + getPosition() + " clicked.");
73 | }
74 | });
75 | this.v = v;
76 | textView = (TextView) v.findViewById(R.id.pathTextView);
77 | }
78 |
79 | public void setOnClickListener(View.OnClickListener listener) {
80 | v.setOnClickListener(listener);
81 | }
82 |
83 | public TextView getTextView() {
84 | return textView;
85 | }
86 | }
87 |
88 | protected class changeDirOnClickListener implements View.OnClickListener {
89 | String path;
90 | FilesFragment fragment;
91 |
92 | public changeDirOnClickListener(String path, FilesFragment fragment) {
93 | this.path = path;
94 | this.fragment = fragment;
95 | }
96 |
97 | @Override
98 | public void onClick(View v) {
99 | Log.d(TAG, "Directory Path " + path + " clicked.");
100 | fragment.changeWorkingDirectory(path, false);
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
16 |
17 |
27 |
95 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_edit_connection.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
17 |
18 |
23 |
24 |
25 |
26 |
30 |
31 |
36 |
37 |
38 |
39 |
47 |
48 |
52 |
53 |
58 |
59 |
60 |
61 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
81 |
82 |
90 |
91 |
92 |
93 |
97 |
98 |
105 |
106 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPConnectionsList/FTPConnectionsDBHelper.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPConnectionsList;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.SQLException;
7 | import android.database.sqlite.SQLiteDatabase;
8 | import android.database.sqlite.SQLiteOpenHelper;
9 | import android.util.Log;
10 |
11 | import com.peppe.ftpclient.androidftp.FTPClientMain.FTPConnection;
12 |
13 | /**
14 | * Created by Geri on 13/10/2015.
15 | */
16 | public class FTPConnectionsDBHelper {
17 | public static final String KEY_ROWID = "_id";
18 | public static final String KEY_NAME = "_name";
19 | public static final String KEY_HOST = "_host";
20 | public static final String KEY_USER = "_user";
21 | public static final String KEY_PASS = "_pass";
22 | public static final String KEY_PORT = "_port";
23 | public static final String KEY_PROTOCOL = "_protocol";
24 |
25 | public static final String TAG = "ConnectionsDBHelper";
26 | private DatabaseHelper DbHelper;
27 | private SQLiteDatabase Db;
28 |
29 | public static final String DATABASE_NAME = "FTPClient";
30 | public static final String SQLITE_TABLE = "Connections";
31 |
32 | private Context context;
33 |
34 | public static final String DATABASE_CREATE =
35 | "CREATE TABLE if not exists " + SQLITE_TABLE + " (" +
36 | KEY_ROWID + " integer PRIMARY KEY autoincrement," +
37 | KEY_NAME + "," +
38 | KEY_HOST + "," +
39 | KEY_USER + "," +
40 | KEY_PASS + "," +
41 | KEY_PORT + "," +
42 | KEY_PROTOCOL + ");";
43 |
44 | private static class DatabaseHelper extends SQLiteOpenHelper {
45 |
46 | DatabaseHelper(Context context) {
47 | super(context, DATABASE_NAME, null, 1);
48 | }
49 |
50 |
51 | @Override
52 | public void onCreate(SQLiteDatabase db) {
53 | Log.w(TAG, DATABASE_CREATE);
54 | db.execSQL(DATABASE_CREATE);
55 | }
56 |
57 | @Override
58 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
59 | Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
60 | + newVersion + ", which will destroy all old data");
61 | db.execSQL("DROP TABLE IF EXISTS " + SQLITE_TABLE);
62 | onCreate(db);
63 | }
64 | }
65 |
66 | public FTPConnectionsDBHelper(Context ctx) {
67 | this.context = ctx;
68 | }
69 |
70 | public FTPConnectionsDBHelper open() throws SQLException {
71 | DbHelper = new DatabaseHelper(context);
72 | Db = DbHelper.getWritableDatabase();
73 | return this;
74 | }
75 |
76 | public void close() {
77 | if (DbHelper != null) {
78 | DbHelper.close();
79 | }
80 | }
81 |
82 | public SQLiteDatabase getWritableDatabase(){
83 | return DbHelper.getWritableDatabase();
84 | }
85 |
86 | public SQLiteDatabase getReadableDatabase(){
87 | return DbHelper.getReadableDatabase();
88 | }
89 |
90 | public long insertFTPConnection(FTPConnection insert){
91 | ContentValues initialValues = new ContentValues();
92 | initialValues.put(KEY_NAME, insert.getName());
93 | initialValues.put(KEY_HOST, insert.getHost());
94 | initialValues.put(KEY_USER, insert.getUser());
95 | initialValues.put(KEY_PASS, insert.getPass());
96 | initialValues.put(KEY_PORT, Integer.toString(insert.getPort()));
97 | initialValues.put(KEY_PROTOCOL, insert.getStringProtocol());
98 |
99 | return Db.insert(SQLITE_TABLE, null, initialValues);
100 | }
101 |
102 | public long deleteFTPConnection(int del){
103 | long deleted = 0;
104 | try {
105 | deleted =Db.delete(SQLITE_TABLE, "_id = " + del, null);
106 | }
107 | catch (Exception e){
108 | Log.e(TAG, e.toString());
109 | }
110 | return deleted;
111 | }
112 |
113 | public int updateFTPConnection(int update, ContentValues cv){
114 | int updated =Db.update(SQLITE_TABLE,cv, "_id = "+ update, null);
115 | return updated;
116 | }
117 |
118 | public Cursor fetchAllData(){
119 | Cursor cur = Db.query(SQLITE_TABLE, new String[] {KEY_ROWID,
120 | KEY_NAME, KEY_HOST, KEY_USER, KEY_PASS, KEY_PORT, KEY_PROTOCOL},
121 | null, null, null, null, null);
122 |
123 | if (cur != null) {
124 | cur.moveToFirst();
125 | }
126 | return cur;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPLocalExplorer/UploadProgressDialog.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPLocalExplorer;
2 |
3 | import android.content.DialogInterface;
4 | import android.os.AsyncTask;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.DialogFragment;
8 | import android.util.Log;
9 | import android.view.Gravity;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.ProgressBar;
14 | import android.widget.TextView;
15 |
16 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
17 | import com.peppe.ftpclient.androidftp.R;
18 |
19 | import java.io.File;
20 | import java.util.ArrayList;
21 |
22 | /**
23 | * Created by Geri on 20/10/2015.
24 | */
25 | public class UploadProgressDialog extends DialogFragment {
26 | public static final String FILE = "FILE";
27 | public static final String COUNT = "COUNT";
28 | public static final String TAG = "UPLOAD_DIALOG";
29 |
30 | private AsyncTask task;
31 | private ArrayList files = new ArrayList<>();
32 | public ProgressBar main;
33 | public ProgressBar second;
34 | private TextView mainText;
35 | private TextView secondText;
36 | private TextView cancel;
37 | public boolean cancelled = false;
38 |
39 | public static UploadProgressDialog newInstance(ArrayList files){
40 | UploadProgressDialog dialog = new UploadProgressDialog();
41 | Bundle args = new Bundle();
42 | args.putInt(COUNT, files.size());
43 | for(int i = 0 ; i1) {
94 | getDialog().setTitle("Uploading Files...");
95 | main.setVisibility(View.VISIBLE);
96 | mainText.setVisibility(View.VISIBLE);
97 | }
98 | else{
99 | getDialog().setTitle("Uploading " + files.get(0).getName() + "...");
100 | main.setVisibility(View.GONE);
101 | mainText.setVisibility(View.GONE);
102 | }
103 | TextView title = (TextView) getDialog().findViewById(android.R.id.title);
104 | title.setGravity(Gravity.CENTER);
105 | cancel.setOnClickListener(new View.OnClickListener() {
106 | @Override
107 | public void onClick(View v) {
108 | cancelled = true;
109 | if(task != null && !task.isCancelled()) {
110 | task.cancel(true);
111 | dismiss();
112 | }
113 | }
114 | });
115 | main.setProgress(0);
116 | main.setMax(100);
117 | second.setProgress(0);
118 | second.setMax(100);
119 | return v;
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPRemoteExplorer/DownloadProgressDialog.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPRemoteExplorer;
2 |
3 | import android.content.DialogInterface;
4 | import android.os.AsyncTask;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.DialogFragment;
8 | import android.util.Log;
9 | import android.view.Gravity;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.ProgressBar;
14 | import android.widget.TextView;
15 |
16 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
17 | import com.peppe.ftpclient.androidftp.R;
18 |
19 | import org.apache.commons.net.ftp.FTPFile;
20 |
21 | import java.util.ArrayList;
22 |
23 | /**
24 | * Created by Geri on 20/10/2015.
25 | */
26 | public class DownloadProgressDialog extends DialogFragment {
27 | public static final String FILE = "FILE";
28 | public static final String COUNT = "COUNT";
29 | public static final String TAG = "DOWNLOAD_DIALOG";
30 |
31 | private AsyncTask task;
32 | private ArrayList files = new ArrayList<>();
33 | public ProgressBar main;
34 | public ProgressBar second;
35 | private TextView mainText;
36 | private TextView secondText;
37 | private TextView cancel;
38 | public boolean cancelled = false;
39 |
40 | public static DownloadProgressDialog newInstance(ArrayList files){
41 | DownloadProgressDialog dialog = new DownloadProgressDialog();
42 | Bundle args = new Bundle();
43 | args.putInt(COUNT, files.size());
44 | for(int i = 0 ; i1) {
95 | getDialog().setTitle("Downloading Files...");
96 | main.setVisibility(View.VISIBLE);
97 | mainText.setVisibility(View.VISIBLE);
98 | }
99 | else{
100 | getDialog().setTitle("Downloading " + files.get(0).getName() + "...");
101 | main.setVisibility(View.GONE);
102 | mainText.setVisibility(View.GONE);
103 | }
104 | TextView title = (TextView) getDialog().findViewById(android.R.id.title);
105 | title.setGravity(Gravity.CENTER);
106 | cancel.setOnClickListener(new View.OnClickListener(){
107 | @Override
108 | public void onClick(View v) {
109 | cancelled = true;
110 | if(task != null && !task.isCancelled()) {
111 | task.cancel(true);
112 | dismiss();
113 | }
114 | }
115 | });
116 | main.setProgress(0);
117 | main.setMax(100);
118 | second.setProgress(0);
119 | second.setMax(100);
120 | return v;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPClientMain/FTPConnection.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPClientMain;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * Created by Geri on 11/10/2015.
9 | */
10 | public class FTPConnection implements Serializable{
11 | private final String TAG = "CONNECTION";
12 | private static int counter = 0;
13 | private int id;
14 | private String name;
15 | private String host;
16 | private String user;
17 |
18 | public void setId(int id) {
19 | this.id = id;
20 | }
21 |
22 | private String pass;
23 | private int port;
24 | private enum Protocol {
25 | FTP, FTPS;
26 | public int toIndex(){
27 | if(this == FTP)
28 | return 0;
29 | else
30 | return 1;
31 | }
32 | public String toString(){
33 | if(this == FTP)
34 | return "FTP";
35 | else
36 | return "FTPS";
37 | }
38 | };
39 | private Protocol protocol;
40 | private final String ANONYMOUS_USER = "anonymous";
41 | private String dir;
42 | private String[] files;
43 |
44 |
45 | public FTPConnection(){
46 | id = counter++;
47 | name = "TEST";
48 | host = "speedtest.tele2.net";
49 | user = ANONYMOUS_USER;
50 | pass = "";
51 | port = 21;
52 | protocol = Protocol.FTP;
53 | }
54 |
55 | public FTPConnection(int id, String name, String host, String user, String pass, int port, String prot){
56 | this.id = id;
57 | this.name = name;
58 | this.host = host;
59 | this.user = user;
60 | this.pass = pass;
61 | this.port = port;
62 | this.protocol = (prot.equals("FTP") ? Protocol.FTP : Protocol.FTPS);
63 | }
64 |
65 | public FTPConnection(String name, String host, String user, String pass, int port, Protocol prot){
66 | this.id = counter++;
67 | this.name = name;
68 | this.host = host;
69 | this.user = user;
70 | this.pass = pass;
71 | this.port = port;
72 | this.protocol = prot;
73 | }
74 | public FTPConnection(String name, String host, String user, String pass, int port, String prot){
75 | this.id = counter++;
76 | this.name = name;
77 | this.host = host;
78 | this.user = user;
79 | this.pass = pass;
80 | this.port = port;
81 | this.protocol = (prot.equals("FTP") ? Protocol.FTP : Protocol.FTPS);
82 | }
83 |
84 | public FTPConnection(String name, String host, String user, String pass, int port, int prot){
85 | this.id = counter++;
86 | this.name = name;
87 | this.host = host;
88 | this.user = user;
89 | this.pass = pass;
90 | this.port = port;
91 | this.protocol = (prot == 0 ? Protocol.FTP : Protocol.FTPS);
92 | }
93 |
94 | public FTPConnection(FTPConnection connection){
95 | this.id = connection.id;
96 | this.name = connection.name;
97 | this.host = connection.host;
98 | this.user = connection.user;
99 | this.pass = connection.pass;
100 | this.port = connection.port;
101 | this.protocol = connection.protocol;
102 | }
103 |
104 | public void editConnection(FTPConnection connection){
105 | this.id = connection.id;
106 | this.name = connection.name;
107 | this.host = connection.host;
108 | this.user = connection.user;
109 | this.pass = connection.pass;
110 | this.port = connection.port;
111 | this.protocol = connection.protocol;
112 | }
113 |
114 | public boolean isAnonymous(){
115 | return user.equals("anonymous");
116 | }
117 |
118 | public int getId() { return id; }
119 |
120 | public String getName(){
121 | return name;
122 | }
123 |
124 | public String getHost(){
125 | return host;
126 | }
127 |
128 | public String getUser(){
129 | return user;
130 | }
131 |
132 | public String getPass(){
133 | return pass;
134 | }
135 |
136 | public int getPort(){
137 | return port;
138 | }
139 |
140 | public String getStringProtocol() {
141 | return protocol.toString();
142 | }
143 |
144 | public int getIndexProtocol(){
145 | return protocol.toIndex();
146 | }
147 |
148 | public String getWorkingDir(){
149 | return dir;
150 | }
151 |
152 | public void setWorkingDir(String dir){
153 | this.dir = dir;
154 | }
155 |
156 | public String[] getFiles(){
157 | return files;
158 | }
159 |
160 | public void setFiles(String[] files){
161 | if(files == null) Log.d(TAG, "files is null");
162 | this.files = new String[files.length];
163 | for(int i = 0; i \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPConnectionsList/ConnectionsFragment.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPConnectionsList;
2 |
3 | //import android.app.ListFragment;
4 |
5 | import android.content.ContentValues;
6 | import android.database.Cursor;
7 | import android.os.Bundle;
8 | import android.support.design.widget.FloatingActionButton;
9 | import android.support.v4.app.ListFragment;
10 | import android.view.LayoutInflater;
11 | import android.view.Menu;
12 | import android.view.MenuInflater;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.AdapterView;
17 | import android.widget.ListView;
18 | import android.widget.SimpleCursorAdapter;
19 | import android.widget.TextView;
20 | import android.widget.Toast;
21 |
22 | import com.peppe.ftpclient.androidftp.FTPClientMain.FTPConnection;
23 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
24 | import com.peppe.ftpclient.androidftp.R;
25 |
26 | /**
27 | * Created by Geri on 12/10/2015.
28 | */
29 | public class ConnectionsFragment extends ListFragment{
30 | private SimpleCursorAdapter adapter;
31 | private FTPConnectionsDBHelper dbHelper;
32 | public static final String TAG = "CONNECTION_FRAGMENT";
33 |
34 | public ConnectionsFragment(){}
35 |
36 | @Override
37 | public void onActivityCreated(Bundle savedInstanceState){
38 | super.onActivityCreated(savedInstanceState);
39 | }
40 |
41 | @Override
42 | public void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 |
45 |
46 |
47 | dbHelper = new FTPConnectionsDBHelper(getActivity());
48 | dbHelper.open();
49 | }
50 |
51 | @Override
52 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
53 | Bundle savedInstanceState) {
54 | return inflater.inflate(R.layout.fragment_connections, container, false);
55 | }
56 |
57 | @Override
58 | public void onResume() {
59 | super.onResume();
60 | final MainActivity activity = ((MainActivity) getActivity());
61 | FloatingActionButton fab = activity.fab;
62 | fab.show();
63 | fab.setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View view) {
66 | activity.startEditConnection(null);
67 | }
68 | });
69 | }
70 |
71 | @Override
72 | public void onViewCreated(View view, Bundle savedInstanceState){
73 | super.onViewCreated(view, savedInstanceState);
74 |
75 |
76 | TextView empty=(TextView)view.findViewById(R.id.connections_empty);
77 | ListView list = getListView();
78 | View.OnClickListener listener = new View.OnClickListener() {
79 | @Override
80 | public void onClick(View v) {
81 | if(getListView().getAdapter().isEmpty())
82 | ((MainActivity)getActivity()).startEditConnection(null);
83 | }
84 | };
85 | view.setOnClickListener(listener);
86 | empty.setOnClickListener(listener);
87 | list.setEmptyView(empty);
88 |
89 | Cursor cursor = dbHelper.fetchAllData();
90 |
91 | String[] columns = new String[] {
92 | FTPConnectionsDBHelper.KEY_NAME,
93 | FTPConnectionsDBHelper.KEY_USER,
94 | FTPConnectionsDBHelper.KEY_HOST
95 | };
96 |
97 | int[] to = new int[] {
98 | R.id.connectionNameTextView,
99 | R.id.connectionUserTextView,
100 | R.id.connectionHostTextView
101 | };
102 |
103 |
104 | adapter = new ConnectionCursorAdapter(
105 | dbHelper,
106 | list,
107 | getActivity(), R.layout.ftpconnection_item,
108 | cursor,
109 | columns,
110 | to,
111 | 0);
112 |
113 | list.setAdapter(adapter);
114 | list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
115 | @Override
116 | public void onItemClick(AdapterView> listView, View view,
117 | int position, long id) {
118 |
119 | // Get the cursor, positioned to the corresponding row in the result set
120 | Cursor cursor = (Cursor) listView.getItemAtPosition(position);
121 | int cid = cursor.getInt(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_ROWID));
122 | String name = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_NAME));
123 | String host = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_HOST));
124 | String user = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_USER));
125 | String pass = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PASS));
126 | int port = cursor.getInt(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PORT));
127 | String protocol = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PROTOCOL));
128 |
129 | FTPConnection connection = new FTPConnection(cid, name, host, user, pass, port, protocol);
130 |
131 | Toast t = ((MainActivity)getActivity()).commonToast;
132 | t.setText("Connecting...");
133 | t.show();
134 |
135 | //Toast.makeText(getActivity(), "Connecting...", Toast.LENGTH_SHORT).show();
136 | ((MainActivity)getActivity()).connectTo(connection);
137 | }
138 | });
139 | }
140 |
141 | public void editDatabase(FTPConnection old, FTPConnection edited){
142 | if(old == null)
143 | dbHelper.insertFTPConnection(edited);
144 | else {
145 | ContentValues cv = new ContentValues();
146 | cv.put(FTPConnectionsDBHelper.KEY_NAME, edited.getName());
147 | cv.put(FTPConnectionsDBHelper.KEY_HOST, edited.getHost());
148 | cv.put(FTPConnectionsDBHelper.KEY_USER, edited.getUser());
149 | cv.put(FTPConnectionsDBHelper.KEY_PASS, edited.getPass());
150 | cv.put(FTPConnectionsDBHelper.KEY_PORT, edited.getPort());
151 | cv.put(FTPConnectionsDBHelper.KEY_PROTOCOL, edited.getStringProtocol());
152 |
153 | dbHelper.updateFTPConnection(old.getId(), cv);
154 | }
155 | adapter.changeCursor(dbHelper.fetchAllData());
156 | adapter.notifyDataSetChanged();
157 | }
158 |
159 |
160 | @Override
161 | public void onDestroy() {
162 | super.onDestroy();
163 | dbHelper.close();
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/ftpconnection_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
22 |
32 |
33 |
43 |
44 |
54 |
55 |
66 |
67 |
78 |
79 |
80 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPLocalExplorer/UploadDialog.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPLocalExplorer;
2 |
3 | import android.content.DialogInterface;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.DialogFragment;
7 | import android.util.Log;
8 | import android.view.Gravity;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
16 | import com.peppe.ftpclient.androidftp.R;
17 |
18 | import java.io.File;
19 | import java.util.ArrayList;
20 |
21 | /**
22 | * Created by Geri on 27/10/2015.
23 | */
24 | public class UploadDialog extends DialogFragment{
25 | public static final String FILE = "FILE";
26 | public static final String TAG = "UPLOAD_DIALOG";
27 |
28 | private File file;
29 |
30 | public static UploadDialog newInstance(File file){
31 | UploadDialog dialog = new UploadDialog();
32 | Bundle args = new Bundle();
33 | args.putSerializable(FILE, file);
34 | dialog.setArguments(args);
35 | return dialog;
36 | }
37 |
38 | @Override
39 | public void onCreate(@Nullable Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | ((MainActivity)getActivity()).isLocalAlive = false;
42 | Log.d(TAG, "dialog created");
43 | if (getArguments() != null) {
44 | this.file = (File)getArguments().getSerializable(FILE);
45 | }
46 | }
47 |
48 | @Override
49 | public void onDismiss(DialogInterface dialog) {
50 | super.onDismiss(dialog);
51 | ((MainActivity)getActivity()).isLocalAlive = true;
52 | Log.d(TAG, "dialog dismissed");
53 | }
54 |
55 |
56 |
57 | @Nullable
58 | @Override
59 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
60 | View v = inflater.inflate(R.layout.file_dialog, container, false);
61 | getDialog().setTitle(file.getName());
62 | TextView name = (TextView) getDialog().findViewById(android.R.id.title);
63 | name.setGravity(Gravity.CENTER);
64 | final LocalFilesFragment fragment = (LocalFilesFragment) getTargetFragment();
65 |
66 | final TextView up = (TextView)v.findViewById(R.id.dialogFileDownUpView);
67 | up.setText(R.string.dialog_upload_up);
68 | up.setOnClickListener(new View.OnClickListener() {
69 | @Override
70 | public void onClick(View v) {
71 | Toast.makeText(getActivity(), "Upload " + file.getName(), Toast.LENGTH_LONG).show();
72 | dismiss();
73 | ArrayList files = new ArrayList<>();
74 | files.add(file);
75 | fragment.uploadFiles(files);
76 | }
77 | });
78 |
79 | final TextView open = (TextView)v.findViewById(R.id.dialogFileOpenView);
80 | open.setOnClickListener(new View.OnClickListener() {
81 | @Override
82 | public void onClick(View v) {
83 | if(file.isDirectory()) {
84 | dismiss();
85 | fragment.openDirecory(file.getName());
86 | }
87 | else {
88 | Toast.makeText(getActivity(), "Open " + file.getName(), Toast.LENGTH_LONG).show();
89 | dismiss();
90 | fragment.openLocalFile(file.getPath());
91 | }
92 | }
93 | });
94 |
95 | /*
96 | final TextView rename = (TextView)v.findViewById(R.id.dialogUploadRenameView);
97 | final EditText renameEdit = (EditText)v.findViewById(R.id.renameEditText);
98 | final TextView renameOK = (TextView)v.findViewById(R.id.renameOkTextView);
99 | final TextView renameCancel = (TextView)v.findViewById(R.id.renameCancelTextView);
100 | final TextView delete = (TextView)v.findViewById(R.id.dialogUploadDeleteView);
101 |
102 | renameEdit.setText(file.getName());
103 |
104 |
105 | rename.setOnClickListener(new View.OnClickListener() {
106 | @Override
107 | public void onClick(View v) {
108 | up.setVisibility(View.GONE);
109 | open.setVisibility(View.GONE);
110 | rename.setVisibility(View.GONE);
111 | delete.setVisibility(View.GONE);
112 | renameEdit.setVisibility(View.VISIBLE);
113 | renameOK.setVisibility(View.VISIBLE);
114 | renameCancel.setVisibility(View.VISIBLE);
115 | renameEdit.requestFocus();
116 | }
117 | });
118 |
119 | renameEdit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
120 | @Override
121 | public void onFocusChange(View v, boolean hasFocus) {
122 | if (hasFocus) {
123 | String text = renameEdit.getText().toString();
124 | if (!text.isEmpty()) {
125 | int index = text.lastIndexOf('.');
126 | if (index == -1)
127 | renameEdit.selectAll();
128 | else
129 | renameEdit.setSelection(0, index);
130 | InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
131 | inputMethodManager.toggleSoftInputFromWindow(renameEdit.getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0);
132 | }
133 | }
134 | }
135 | });
136 | renameOK.setOnClickListener(new View.OnClickListener() {
137 | @Override
138 | public void onClick(View v) {
139 | Log.d(TAG, "called to rename " + file.getName() + " to " + renameEdit.getText().toString());
140 | fragment.renameFile(file.getName(), renameEdit.getText().toString());
141 | dismiss();
142 | }
143 | });
144 |
145 | delete.setOnClickListener(new View.OnClickListener() {
146 | @Override
147 | public void onClick(View v) {
148 | up.setVisibility(View.GONE);
149 | open.setVisibility(View.GONE);
150 | rename.setVisibility(View.GONE);
151 | delete.setVisibility(View.GONE);
152 | renameOK.setVisibility(View.VISIBLE);
153 | renameCancel.setVisibility(View.VISIBLE);
154 | getDialog().setTitle(getString(R.string.delete_confirm) + " " + file.getName() + "?");
155 | renameOK.setOnClickListener(new View.OnClickListener() {
156 | @Override
157 | public void onClick(View v) {
158 | ArrayList files = new ArrayList();
159 | files.add(file.getName());
160 | fragment.deleteFiles(files);
161 | dismiss();
162 | }
163 | });
164 | renameOK.setText(R.string.yes);
165 | renameCancel.setText(R.string.no);
166 | }
167 | });
168 | renameCancel.setOnClickListener(new View.OnClickListener() {
169 | @Override
170 | public void onClick(View v) {
171 | dismiss();
172 | }
173 | });
174 | */
175 | return v;
176 | }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPRemoteExplorer/DownloadDialog.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPRemoteExplorer;
2 |
3 | import android.content.DialogInterface;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.DialogFragment;
7 | import android.util.Log;
8 | import android.view.Gravity;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
16 | import com.peppe.ftpclient.androidftp.R;
17 |
18 | import org.apache.commons.net.ftp.FTPFile;
19 |
20 | import java.util.ArrayList;
21 |
22 | /**
23 | * Created by Geri on 20/10/2015.
24 | */
25 | public class DownloadDialog extends DialogFragment {
26 | public static final String FILE = "FILE";
27 | public static final String TAG = "DOWNLOAD_DIALOG";
28 |
29 | private FTPFile file;
30 |
31 | public static DownloadDialog newInstance(FTPFile file){
32 | DownloadDialog dialog = new DownloadDialog();
33 | Bundle args = new Bundle();
34 | args.putSerializable(FILE, file);
35 | dialog.setArguments(args);
36 | return dialog;
37 | }
38 |
39 | @Override
40 | public void onCreate(@Nullable Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | ((MainActivity)getActivity()).isRemoteAlive = false;
43 | Log.d(TAG, "dialog created");
44 | if (getArguments() != null) {
45 | this.file = (FTPFile)getArguments().getSerializable(FILE);
46 | }
47 | }
48 |
49 | @Override
50 | public void onDismiss(DialogInterface dialog) {
51 | super.onDismiss(dialog);
52 | ((MainActivity)getActivity()).isRemoteAlive = true;
53 | Log.d(TAG, "dialog dismissed");
54 | }
55 |
56 | @Nullable
57 | @Override
58 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
59 | View v = inflater.inflate(R.layout.file_dialog, container, false);
60 | getDialog().setTitle(file.getName());
61 | TextView name = (TextView) getDialog().findViewById(android.R.id.title);
62 | //name.setGravity(Gravity.CENTER);
63 | //// TODO: 11/02/2016 check this
64 | final RemoteFilesFragment fragment = (RemoteFilesFragment)getTargetFragment();
65 |
66 | final TextView down = (TextView)v.findViewById(R.id.dialogFileDownUpView);
67 | down.setOnClickListener(new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | Toast.makeText(getActivity(), "Download " + file.getName(), Toast.LENGTH_LONG).show();
71 | dismiss();
72 | ArrayList files = new ArrayList<>();
73 | files.add(file);
74 | fragment.downloadFiles(false, files);
75 | }
76 | });
77 |
78 | final TextView open = (TextView)v.findViewById(R.id.dialogFileOpenView);
79 | open.setOnClickListener(new View.OnClickListener() {
80 | @Override
81 | public void onClick(View v) {
82 | if (file.isDirectory()) {
83 | dismiss();
84 | fragment.openDirecory(file.getName());
85 | } else {
86 | Toast.makeText(getActivity(), "Open " + file.getName(), Toast.LENGTH_LONG).show();
87 | dismiss();
88 | ArrayList files = new ArrayList<>();
89 | files.add(file);
90 | fragment.downloadFiles(true, files);
91 | }
92 | }
93 | });
94 |
95 | /*
96 | final TextView rename = (TextView)v.findViewById(R.id.dialogDownloadRenameView);
97 | final EditText renameEdit = (EditText)v.findViewById(R.id.renameEditText);
98 | final TextView renameOK = (TextView)v.findViewById(R.id.renameOkTextView);
99 | final TextView renameCancel = (TextView)v.findViewById(R.id.renameCancelTextView);
100 | final TextView delete = (TextView)v.findViewById(R.id.dialogDownloadDeleteView);
101 |
102 | renameEdit.setText(file.getName());
103 |
104 |
105 | rename.setOnClickListener(new View.OnClickListener() {
106 | @Override
107 | public void onClick(View v) {
108 | down.setVisibility(View.GONE);
109 | open.setVisibility(View.GONE);
110 | rename.setVisibility(View.GONE);
111 | delete.setVisibility(View.GONE);
112 | renameEdit.setVisibility(View.VISIBLE);
113 | renameOK.setVisibility(View.VISIBLE);
114 | renameCancel.setVisibility(View.VISIBLE);
115 | renameEdit.requestFocus();
116 | }
117 | });
118 |
119 | renameEdit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
120 | @Override
121 | public void onFocusChange(View v, boolean hasFocus) {
122 | if (hasFocus) {
123 | String text = renameEdit.getText().toString();
124 | if (!text.isEmpty()) {
125 | int index = text.lastIndexOf('.');
126 | if (index == -1)
127 | renameEdit.selectAll();
128 | else
129 | renameEdit.setSelection(0, index);
130 | InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
131 | inputMethodManager.toggleSoftInputFromWindow(renameEdit.getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0);
132 | }
133 | }
134 | }
135 | });
136 | renameOK.setOnClickListener(new View.OnClickListener() {
137 | @Override
138 | public void onClick(View v) {
139 | Log.d(TAG, "called to rename " + file.getName() + " to " + renameEdit.getText().toString());
140 | fragment.renameFile(file.getName(), renameEdit.getText().toString());
141 | dismiss();
142 | }
143 | });
144 | delete.setOnClickListener(new View.OnClickListener() {
145 | @Override
146 | public void onClick(View v) {
147 | down.setVisibility(View.GONE);
148 | open.setVisibility(View.GONE);
149 | rename.setVisibility(View.GONE);
150 | delete.setVisibility(View.GONE);
151 | renameOK.setVisibility(View.VISIBLE);
152 | renameCancel.setVisibility(View.VISIBLE);
153 | getDialog().setTitle(getString(R.string.delete_confirm) + " " + file.getName() + "?");
154 | renameOK.setOnClickListener(new View.OnClickListener() {
155 | @Override
156 | public void onClick(View v) {
157 | ArrayList files = new ArrayList();
158 | files.add(file.getName());
159 | fragment.deleteFiles(files);
160 | dismiss();
161 | }
162 | });
163 | renameOK.setText(R.string.yes);
164 | renameCancel.setText(R.string.no);
165 | }
166 | });
167 | renameCancel.setOnClickListener(new View.OnClickListener() {
168 | @Override
169 | public void onClick(View v) {
170 | dismiss();
171 | }
172 | });
173 | */
174 | return v;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPConnectionsList/ConnectionCursorAdapter.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPConnectionsList;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.util.Log;
6 | import android.view.View;
7 | import android.view.View.OnClickListener;
8 | import android.view.ViewGroup;
9 | import android.widget.CursorAdapter;
10 | import android.widget.ImageView;
11 | import android.widget.ListView;
12 | import android.widget.SimpleCursorAdapter;
13 | import android.widget.TextView;
14 |
15 | import com.peppe.ftpclient.androidftp.FTPClientMain.FTPConnection;
16 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
17 | import com.peppe.ftpclient.androidftp.R;
18 |
19 | /**
20 | * Created by Geri on 14/10/2015.
21 | */
22 | public class ConnectionCursorAdapter extends SimpleCursorAdapter {
23 | protected ListView listView;
24 | protected FTPConnectionsDBHelper dbHelper;
25 | protected MainActivity mActivity;
26 | public static final String TAG = "CONNECTION_ADAPTER";
27 |
28 | protected static class RowViewHolder {
29 | public TextView userTextView;
30 | public TextView nameTextView;
31 | public TextView hostTextView;
32 | public TextView atTextView;
33 | public ImageView edit;
34 | public ImageView delete;
35 |
36 | public RowViewHolder(View view){
37 | nameTextView = (TextView) view.findViewById(R.id.connectionNameTextView);
38 | userTextView = (TextView) view.findViewById(R.id.connectionUserTextView);
39 | hostTextView = (TextView) view.findViewById(R.id.connectionHostTextView);
40 | atTextView = (TextView) view.findViewById(R.id.connectionAtTextView);
41 | edit = (ImageView) view.findViewById(R.id.connectionEditImageButton);
42 | delete = (ImageView) view.findViewById(R.id.connectionDeleteImageButton);
43 | }
44 | }
45 | /**
46 | * Standard constructor.
47 | *
48 | * @param context The context where the ListView associated with this
49 | * SimpleListItemFactory is running
50 | * @param layout resource identifier of a layout file that defines the views
51 | * for this list item. The layout file should include at least
52 | * those named views defined in "to"
53 | * @param c The database cursor. Can be null if the cursor is not available yet.
54 | * @param from A list of column names representing the data to bind to the UI. Can be null
55 | * if the cursor is not available yet.
56 | * @param to The views that should display column in the "from" parameter.
57 | * These should all be TextViews. The first N views in this list
58 | * are given the values of the first N columns in the from
59 | * parameter. Can be null if the cursor is not available yet.
60 | * @param flags Flags used to determine the behavior of the adapter,
61 | * as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}.
62 | */
63 | public ConnectionCursorAdapter(FTPConnectionsDBHelper dbHelper, ListView listView,
64 | Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
65 | super(context, layout, c, from, to, flags);
66 | this.listView = listView;
67 | this.dbHelper = dbHelper;
68 | this.mActivity = (MainActivity)context;
69 | }
70 |
71 | @Override
72 | public void bindView(View view, Context context, Cursor cursor) {
73 | super.bindView(view, context, cursor);
74 | RowViewHolder holder = new RowViewHolder(view);
75 |
76 | if(cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_NAME)).equals("")){
77 | holder.nameTextView.setText(holder.hostTextView.getText());
78 | holder.atTextView.setVisibility(View.GONE);
79 | holder.hostTextView.setVisibility(View.GONE);
80 | }
81 | else{
82 | holder.atTextView.setVisibility(View.VISIBLE);
83 | holder.hostTextView.setVisibility(View.VISIBLE);
84 | }
85 |
86 | holder.edit.setOnClickListener(onEditButtonClickListener);
87 |
88 | holder.delete.setOnClickListener(onDeleteButtonClickListener);
89 |
90 | view.setTag(holder);
91 | }
92 |
93 | /**
94 | * Inflates view(s) from the specified XML file.
95 | *
96 | * @param context
97 | * @param cursor
98 | * @param parent
99 | * @see CursorAdapter#newView(Context,
100 | * Cursor, ViewGroup)
101 | */
102 | @Override
103 | public View newView(Context context, Cursor cursor, ViewGroup parent) {
104 | View view = View.inflate(context, R.layout.ftpconnection_item, null);
105 | return view;
106 | }
107 |
108 | private OnClickListener onEditButtonClickListener = new OnClickListener() {
109 | @Override
110 | public void onClick(View v) {
111 | final int position = listView.getPositionForView((View) v.getParent());
112 | Log.v(TAG, "edit button clicked, row "+position);
113 |
114 | Cursor cursor = getCursor();
115 | cursor.moveToPosition(position);
116 | int id = cursor.getInt(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_ROWID));
117 | String name = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_NAME));
118 | String host = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_HOST));
119 | String user = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_USER));
120 | String pass = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PASS));
121 | int port = cursor.getInt(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PORT));
122 | String protocol = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PROTOCOL));
123 |
124 | FTPConnection connection = new FTPConnection(id,name, host, user, pass, port, protocol);
125 |
126 | mActivity.startEditConnection(connection);
127 |
128 | /*ContentValues cv = new ContentValues();
129 | cv.put(FTPConnectionsDBHelper.KEY_NAME, "TEST_EDIT");
130 | dbHelper.updateFTPConnection(id, cv);
131 | changeCursor(dbHelper.fetchAllData());
132 | notifyDataSetChanged();*/
133 | }
134 | };
135 |
136 | private OnClickListener onDeleteButtonClickListener = new OnClickListener() {
137 | @Override
138 | public void onClick(View v) {
139 | final int position = listView.getPositionForView((View) v.getParent());
140 | Log.v(TAG, "delete button clicked, row " + position);
141 | Cursor cursor = getCursor();
142 | cursor.moveToPosition(position);
143 | int id = cursor.getInt(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_ROWID));
144 | /*
145 | String name = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_NAME));
146 | String host = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_HOST));
147 | String user = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_USER));
148 | String pass = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PASS));
149 | int port = cursor.getInt(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PORT));
150 | String protocol = cursor.getString(cursor.getColumnIndexOrThrow(FTPConnectionsDBHelper.KEY_PROTOCOL));
151 |
152 | FTPConnection connection = new FTPConnection(name, host, user, pass, port, protocol);
153 | */
154 |
155 | dbHelper.deleteFTPConnection(id);
156 | changeCursor(dbHelper.fetchAllData());
157 | notifyDataSetChanged();
158 | }
159 | };
160 | }
161 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
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 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPLocalExplorer/LocalFilesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPLocalExplorer;
2 |
3 | import android.support.v4.app.FragmentManager;
4 | import android.util.Log;
5 | import android.view.MenuItem;
6 | import android.view.View;
7 | import android.widget.PopupMenu;
8 |
9 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FilesAdapter;
10 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FilesFragment;
11 | import com.peppe.ftpclient.androidftp.R;
12 |
13 | import java.io.File;
14 | import java.text.SimpleDateFormat;
15 | import java.util.ArrayList;
16 | import java.util.Collections;
17 |
18 | /**
19 | * Created by Geri on 25/10/2015.
20 | */
21 | public class LocalFilesAdapter extends FilesAdapter {
22 |
23 | private static final String TAG = "LOCAL_FILES_ADAPTER";
24 |
25 | public LocalFilesAdapter(FilesFragment fragment) {
26 | super(fragment);
27 | }
28 |
29 |
30 | @Override
31 | public ArrayList getSelectedItems() {
32 | ArrayList items =
33 | new ArrayList<>(selectedItems.size());
34 | for (int i = 0; i < selectedItems.size(); i++) {
35 | items.add(dataset.get(selectedItems.keyAt(i)));
36 | }
37 | return items;
38 | }
39 |
40 | @Override
41 | public ArrayList getSelectedNames() {
42 | ArrayList names =
43 | new ArrayList<>(selectedItems.size());
44 | for (int i = 0; i < selectedItems.size(); i++) {
45 | names.add(dataset.get(selectedItems.keyAt(i)).getName());
46 | }
47 | return names;
48 | }
49 |
50 | @Override
51 | protected void sort(int mode) {
52 | ArrayList sorted = new ArrayList<>(dataset);
53 | Collections.sort(sorted, new LocalFileComparator(mode));
54 | animateTo(sorted);
55 | }
56 |
57 | private class LocalFileComparator extends FileComparator{
58 |
59 | public LocalFileComparator(int mode){
60 | super(mode);
61 | }
62 |
63 | @Override
64 | public int compare(File lhs, File rhs) {
65 | if(lhs.isDirectory() && rhs.isFile()){
66 | return -1;
67 | }
68 | else if (lhs.isFile() && rhs.isDirectory())
69 | return 1;
70 | else {
71 | int res = 0;
72 | switch (super.mode) {
73 | case BY_NAME:
74 | res = sortName(lhs, rhs);
75 | if(res != 0) return res;
76 | res = sortType(lhs, rhs);
77 | if(res != 0) return res;
78 | res = sortTime(lhs, rhs);
79 | if(res != 0) return res;
80 | return sortSize(lhs, rhs);
81 | case BY_SIZE:
82 | res = sortSize(lhs, rhs);
83 | if(res != 0) return res;
84 | res = sortName(lhs, rhs);
85 | if(res != 0) return res;
86 | res = sortType(lhs, rhs);
87 | if(res != 0) return res;
88 | return sortTime(lhs, rhs);
89 | case BY_TYPE:
90 | res = sortType(lhs, rhs);
91 | if(res != 0) return res;
92 | res = sortName(lhs, rhs);
93 | if(res != 0) return res;
94 | res = sortTime(lhs, rhs);
95 | if(res != 0) return res;
96 | return sortSize(lhs, rhs);
97 | case BY_TIME:
98 | res = sortTime(lhs, rhs);
99 | if(res != 0) return res;
100 | res = sortName(lhs, rhs);
101 | if(res != 0) return res;
102 | res = sortType(lhs, rhs);
103 | if(res != 0) return res;
104 | return sortSize(lhs, rhs);
105 | default:
106 | return 0;
107 | }
108 | }
109 | }
110 |
111 | private int sortName(File lhs, File rhs){
112 | String name1 = getName(lhs.getName());
113 | String name2 = getName(rhs.getName());
114 | return name1.compareTo(name2);
115 | }
116 |
117 | private int sortSize(File lhs, File rhs){
118 | long res = lhs.length() - rhs.length();
119 | if(res > 0) return 1;
120 | else if (res < 0) return -1;
121 | return 0;
122 | }
123 |
124 | private int sortTime(File lhs, File rhs){
125 | long res = lhs.lastModified() - rhs.lastModified();
126 | if(res > 0) return 1;
127 | else if (res < 0) return -1;
128 | return 0;
129 | }
130 |
131 | private int sortType(File lhs, File rhs){
132 | String type1 = getExt(lhs.getName());
133 | String type2 = getExt(rhs.getName());
134 | return type1.compareTo(type2);
135 | }
136 | }
137 |
138 | @Override
139 | public void onBindViewHolder(ViewHolder holder, int position) {
140 | holder.getNameTextView().setText(dataset.get(position).getName());
141 | String size = convertToStringRepresentation(dataset.get(position).length());
142 | SimpleDateFormat formatter = new SimpleDateFormat("MMM d, yyyy hh:mm a", java.util.Locale.getDefault());
143 | String time = formatter.format(dataset.get(position).lastModified());
144 | if (dataset.get(position).isDirectory())
145 | holder.getInfoTextView().setText(time);
146 | else
147 | holder.getInfoTextView().setText(size + " - " + time);
148 | fileOnClickListener listener = new fileOnClickListener(fragment, dataset.get(position));
149 | holder.itemView.setOnLongClickListener(listener);
150 | holder.itemView.setOnClickListener(listener);
151 | if(dataset.get(position).isFile()){
152 | holder.getImageView().setImageResource(android.R.drawable.ic_menu_delete);
153 | }
154 | else
155 | holder.getImageView().setImageResource(android.R.drawable.ic_menu_gallery);
156 | holder.itemView.setActivated(isSelected(position));
157 | }
158 |
159 | @Override
160 | public boolean isDirectory(File dir) {
161 | return dir.isDirectory();
162 | }
163 |
164 | protected class fileOnClickListener implements View.OnClickListener, View.OnLongClickListener {
165 | FilesFragment fragment;
166 | File file;
167 |
168 | public fileOnClickListener(FilesFragment fragment, File file) {
169 | this.file = file;
170 | this.fragment = fragment;
171 | }
172 |
173 | @Override
174 | public boolean onLongClick(View v) {
175 | Log.d(TAG, (file.isDirectory() ? "Directory ": "File ") + file.getName() + " long clicked.");
176 | if(isSelecting() && file.isDirectory()){
177 | final View view = v;
178 | PopupMenu menu = new PopupMenu(fragment.getActivity(), v);
179 | menu.getMenuInflater().inflate(R.menu.folder_popup_menu, menu.getMenu());
180 | menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
181 | @Override
182 | public boolean onMenuItemClick(MenuItem item) {
183 | switch(item.getItemId()){
184 | case R.id.folderPopupOpen:
185 | fragment.openDirecory(file.getName());
186 | return true;
187 | case R.id.folderPopupSelect:
188 | fragment.selectItem(view);
189 | return true;
190 | default:
191 | return false;
192 | }
193 | }
194 | });
195 | menu.show();
196 | }
197 | else {
198 | fragment.selectItem(v);
199 | }
200 | /*
201 | if (isDirectory(file)) {
202 | Log.d(TAG, "Directory " + file.getName() + " long clicked.");
203 | UploadDialog dialog = UploadDialog.newInstance(file);
204 | dialog.setTargetFragment(fragment, 1);
205 | FragmentManager fm = fragment.getActivity().getSupportFragmentManager();
206 | dialog.show(fm, "Upload");
207 | }
208 | else {
209 | Log.d(TAG, "File " + file.getName() + " long clicked.");
210 | }
211 | */
212 | return true;
213 | }
214 |
215 | @Override
216 | public void onClick(View v) {
217 | if(isSelecting())
218 | fragment.selectItem(v);
219 | else {
220 | if (isDirectory(file)) {
221 | Log.d(TAG, "Directory " + file.getName() + " clicked.");
222 | fragment.openDirecory(file.getName());
223 | } else {
224 | Log.d(TAG, "File " + file.getName() + " clicked.");
225 | UploadDialog dialog = UploadDialog.newInstance(file);
226 | dialog.setTargetFragment(fragment, 1);
227 | FragmentManager fm = fragment.getActivity().getSupportFragmentManager();
228 | dialog.show(fm, "Upload");
229 | }
230 | }
231 | }
232 | }
233 |
234 |
235 | }
236 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPViewPager.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.AnimationDrawable;
5 | import android.os.AsyncTask;
6 | import android.os.Bundle;
7 | import android.support.design.widget.FloatingActionButton;
8 | import android.support.v4.app.Fragment;
9 | import android.support.v4.app.FragmentManager;
10 | import android.support.v4.view.ViewPager;
11 | import android.util.Log;
12 | import android.view.LayoutInflater;
13 | import android.view.Menu;
14 | import android.view.MenuInflater;
15 | import android.view.MenuItem;
16 | import android.view.View;
17 | import android.view.ViewGroup;
18 | import android.view.animation.Animation;
19 | import android.view.animation.AnimationSet;
20 | import android.view.animation.AnimationUtils;
21 | import android.view.inputmethod.InputMethodManager;
22 | import android.widget.ProgressBar;
23 | import android.widget.Toast;
24 |
25 | import com.peppe.ftpclient.androidftp.FTPClientMain.FTPConnection;
26 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
27 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPLocalExplorer.LocalFilesFragment;
28 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPRemoteExplorer.RemoteFilesFragment;
29 | import com.peppe.ftpclient.androidftp.R;
30 |
31 | import org.apache.commons.net.ftp.FTP;
32 | import org.apache.commons.net.ftp.FTPClient;
33 | import org.apache.commons.net.ftp.FTPReply;
34 |
35 | import de.greenrobot.event.EventBus;
36 |
37 | public class FTPViewPager extends Fragment {
38 | private static final String CONNECT = "connect";
39 | private static final String TAG = "FTP_PAGER";
40 |
41 | private FTPConnection connection;
42 | private FTPPagerAdapter adapter;
43 | private FTPClient client;
44 | private View v;
45 |
46 | private EventBus bus = EventBus.getDefault();
47 |
48 | private Menu mMenu;
49 |
50 | public static FTPViewPager newInstance(FTPConnection connection) {
51 | FTPViewPager fragment = new FTPViewPager();
52 | Bundle args = new Bundle();
53 | args.putSerializable(CONNECT, connection);
54 | fragment.setArguments(args);
55 | return fragment;
56 | }
57 |
58 | @Override
59 | public void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setHasOptionsMenu(true);
62 |
63 | if (getArguments() != null) {
64 | this.connection = (FTPConnection)getArguments().getSerializable(CONNECT);
65 | //do something when on start
66 | if(connection == null){
67 |
68 | }
69 | else{
70 | if(client==null)
71 | client = new FTPClient();
72 | new FTPConnectTask().execute(connection);
73 | }
74 | }
75 |
76 | }
77 |
78 | @Override
79 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
80 | Bundle savedInstanceState) {
81 | // Inflate the layout for this fragment
82 | v = inflater.inflate(R.layout.fragment_ftpview_pager, container, false);
83 |
84 | return v;
85 | }
86 |
87 | @Override
88 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
89 | super.onCreateOptionsMenu(menu, inflater);
90 | }
91 |
92 | @Override
93 | public boolean onOptionsItemSelected(MenuItem item) {
94 | MainActivity activity =(MainActivity)getActivity();
95 | switch (item.getItemId()) {
96 | case android.R.id.home:
97 | FragmentManager fm = getActivity().getSupportFragmentManager();
98 | if (fm.getBackStackEntryCount() > 0) {
99 | fm.popBackStack();
100 | }
101 | return true;
102 | default:
103 | return super.onOptionsItemSelected(item);
104 | }
105 | }
106 |
107 | private class FTPConnectTask extends AsyncTask {
108 |
109 | private final String TAG = "CONNECT_TASK";
110 |
111 | @Override
112 | protected void onPostExecute(FTPClient c) {
113 | super.onPostExecute(c);
114 | if (c != null) {
115 | if(c.isConnected()) {
116 | ViewPager pager = (ViewPager) FTPViewPager.this.v.findViewById(R.id.ftpViewPager);
117 | pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
118 | final MainActivity activity = ((MainActivity) getActivity());
119 | FloatingActionButton fab = activity.fab;
120 | Animation show = AnimationUtils.loadAnimation(getContext(), R.anim.fab_show);
121 | Animation hide = AnimationUtils.loadAnimation(getContext(), R.anim.fab_hide);
122 | boolean shown = true;
123 |
124 | @Override
125 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
126 | //Log.d(TAG, "scroll position: " + position + ", offset: " + positionOffset);
127 | if(!shown && positionOffset == 0) {
128 | Log.d(TAG, "showing fab");
129 | shown = true;
130 | fab.startAnimation(show);
131 | fab.show();
132 | }
133 | else if (shown && positionOffset!= 0){
134 | shown = false;
135 | Log.d(TAG, "hiding fab");
136 | fab.startAnimation(hide);
137 | fab.hide();
138 | }
139 | }
140 |
141 | @Override
142 | public void onPageSelected(int position) {
143 | if (position == 0) {
144 | //activity.setTitle("Remote");
145 | Log.d(FTPViewPager.TAG, "remote alive 1");
146 | activity.isRemoteAlive = true;
147 | activity.isLocalAlive = false;
148 | } else {
149 | //activity.setTitle("Local");
150 | Log.d(FTPViewPager.TAG, "local alive 1");
151 | activity.isRemoteAlive = false;
152 | activity.isLocalAlive = true;
153 | if(activity.requestStoragePermission(getString(R.string.cant_show_files)))
154 | activity.getActiveFragment().refreshDir();
155 | }
156 | activity.getActiveFragment().ensurePathIsSowhn();
157 | //Log.d(TAG, "selected");
158 | fab.show();
159 | }
160 |
161 | @Override
162 | public void onPageScrollStateChanged(int state) {
163 | }
164 | });
165 | pager.setVisibility(View.VISIBLE);
166 | ProgressBar progress = (ProgressBar) FTPViewPager.this.v.findViewById(R.id.loadConnectionProgressBar);
167 | progress.setVisibility(View.GONE);
168 | adapter = new FTPPagerAdapter(c, connection, (MainActivity) getActivity(), getChildFragmentManager());
169 | pager.setAdapter(adapter);
170 | FloatingActionButton fab = ((MainActivity) getActivity()).fab;
171 | fab.setOnClickListener(((MainActivity)getActivity()));
172 | } else {
173 | Toast t = ((MainActivity) getActivity()).commonToast;
174 | t.setText("Authentication failed...");
175 | t.show();
176 | getActivity().onBackPressed();
177 | }
178 | } else if (c == null) {
179 | Toast t = ((MainActivity) getActivity()).commonToast;
180 | t.setText("Failed to connect...");
181 | t.show();
182 | getActivity().onBackPressed();
183 | }
184 | }
185 |
186 | @Override
187 | protected FTPClient doInBackground(FTPConnection... params) {
188 | FTPConnection connection = params[0];
189 | boolean suc = false;
190 | try {
191 | FTPClient client = new FTPClient();
192 | client.connect(connection.getHost(), connection.getPort());
193 |
194 | if (FTPReply.isPositiveCompletion(client.getReplyCode())) {
195 | Log.d(TAG, "connected!");
196 | boolean status = client.login(connection.getUser(), connection.getPass());
197 | client.setFileType(FTP.BINARY_FILE_TYPE);
198 | client.enterLocalPassiveMode();
199 | suc = status;
200 | }
201 | if (suc) {
202 | Log.d(TAG, "connected and authenticated!");
203 | return client;
204 | } else {
205 | Log.d(TAG, "failed to authenticate!");
206 | client.disconnect();
207 | return client;
208 | }
209 |
210 | } catch (Exception e) {
211 | Log.e(TAG, e.toString());
212 | Log.d(TAG, "Error: could not connect to host " + connection.getHost());
213 | }
214 |
215 | return null;
216 | }
217 |
218 | }
219 |
220 | }
221 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FTPRemoteExplorer/RemoteFilesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPRemoteExplorer;
2 |
3 | import android.support.v4.app.FragmentManager;
4 | import android.util.Log;
5 | import android.view.MenuItem;
6 | import android.view.View;
7 | import android.widget.PopupMenu;
8 |
9 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FilesAdapter;
10 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FilesFragment;
11 | import com.peppe.ftpclient.androidftp.R;
12 |
13 | import org.apache.commons.net.ftp.FTPFile;
14 |
15 | import java.text.SimpleDateFormat;
16 | import java.util.ArrayList;
17 | import java.util.Calendar;
18 | import java.util.Collections;
19 |
20 | /**
21 | * Created by Geri on 24/10/2015.
22 | */
23 | public class RemoteFilesAdapter extends FilesAdapter {
24 |
25 | private static final String TAG = "REMOTE_FILES_ADAPTER";
26 |
27 | public RemoteFilesAdapter(FilesFragment fragment) {
28 | super(fragment);
29 | }
30 |
31 | @Override
32 | protected void sort(int mode) {
33 | ArrayList sorted = new ArrayList<>(dataset);
34 | Collections.sort(sorted, new FTPFileComparator(mode));
35 | animateTo(sorted);
36 | }
37 |
38 | private class FTPFileComparator extends FileComparator{
39 |
40 | public FTPFileComparator(int mode){
41 | super(mode);
42 | }
43 |
44 | @Override
45 | public int compare(FTPFile lhs, FTPFile rhs) {
46 | if(lhs.isDirectory() && rhs.isFile()){
47 | return -1;
48 | }
49 | else if (lhs.isFile() && rhs.isDirectory())
50 | return 1;
51 | else {
52 | int res = 0;
53 | switch (super.mode) {
54 | case BY_NAME:
55 | res = sortName(lhs, rhs);
56 | if(res != 0) return res;
57 | res = sortType(lhs, rhs);
58 | if(res != 0) return res;
59 | res = sortTime(lhs, rhs);
60 | if(res != 0) return res;
61 | return sortSize(lhs, rhs);
62 | case BY_SIZE:
63 | res = sortSize(lhs, rhs);
64 | if(res != 0) return res;
65 | res = sortName(lhs, rhs);
66 | if(res != 0) return res;
67 | res = sortType(lhs, rhs);
68 | if(res != 0) return res;
69 | return sortTime(lhs, rhs);
70 | case BY_TYPE:
71 | res = sortType(lhs, rhs);
72 | if(res != 0) return res;
73 | res = sortName(lhs, rhs);
74 | if(res != 0) return res;
75 | res = sortTime(lhs, rhs);
76 | if(res != 0) return res;
77 | return sortSize(lhs, rhs);
78 | case BY_TIME:
79 | res = sortTime(lhs, rhs);
80 | if(res != 0) return res;
81 | res = sortName(lhs, rhs);
82 | if(res != 0) return res;
83 | res = sortType(lhs, rhs);
84 | if(res != 0) return res;
85 | return sortSize(lhs, rhs);
86 | default:
87 | return 0;
88 | }
89 | }
90 | }
91 |
92 | private int sortName(FTPFile lhs, FTPFile rhs){
93 | String name1 = getName(lhs.getName());
94 | String name2 = getName(rhs.getName());
95 | return name1.compareTo(name2);
96 | }
97 |
98 | private int sortSize(FTPFile lhs, FTPFile rhs){
99 | long res = lhs.getSize() - rhs.getSize();
100 | if(res > 0) return 1;
101 | else if (res < 0) return -1;
102 | return 0;
103 | }
104 |
105 | private int sortTime(FTPFile lhs, FTPFile rhs){
106 | long res = lhs.getTimestamp().getTimeInMillis() - rhs.getTimestamp().getTimeInMillis();
107 | if(res > 0) return 1;
108 | else if (res < 0) return -1;
109 | return 0;
110 | }
111 |
112 | private int sortType(FTPFile lhs, FTPFile rhs){
113 | String type1 = getExt(lhs.getName());
114 | String type2 = getExt(rhs.getName());
115 | return type1.compareTo(type2);
116 | }
117 | }
118 |
119 |
120 | @Override
121 | public ArrayList getSelectedIndices() {
122 | ArrayList items =
123 | new ArrayList(selectedItems.size());
124 | for (int i = 0; i < selectedItems.size(); i++) {
125 | items.add(selectedItems.keyAt(i));
126 | }
127 | return items;
128 | }
129 |
130 | @Override
131 | public ArrayList getSelectedItems() {
132 | ArrayList items =
133 | new ArrayList<>(selectedItems.size());
134 | for (int i = 0; i < selectedItems.size(); i++) {
135 | items.add(dataset.get(selectedItems.keyAt(i)));
136 | }
137 | return items;
138 | }
139 |
140 | @Override
141 | public ArrayList getSelectedNames() {
142 | ArrayList names =
143 | new ArrayList<>(selectedItems.size());
144 | for (int i = 0; i < selectedItems.size(); i++) {
145 | names.add(dataset.get(selectedItems.keyAt(i)).getName());
146 | }
147 | return names;
148 | }
149 |
150 | @Override
151 | public void onBindViewHolder(ViewHolder holder, int position) {
152 | FTPFile ftpFile = dataset.get(position);
153 | holder.getNameTextView().setText(ftpFile.getName());
154 | String size = convertToStringRepresentation(ftpFile.getSize());
155 | Calendar ctime = ftpFile.getTimestamp();
156 | SimpleDateFormat formatter = new SimpleDateFormat("MMM d, yyyy hh:mm a", java.util.Locale.getDefault());
157 | String time = formatter.format(ctime.getTime());
158 | if(ftpFile.isFile())
159 | holder.getInfoTextView().setText(size + " - " + time);
160 | else
161 | holder.getInfoTextView().setText(time);
162 | fileOnClickListener listener = new fileOnClickListener(fragment, position);
163 | holder.itemView.setOnClickListener(listener);
164 | holder.itemView.setOnLongClickListener(listener);
165 | if(ftpFile.isFile()){
166 | holder.getImageView().setImageResource(android.R.drawable.ic_menu_delete);
167 | }
168 | else
169 | holder.getImageView().setImageResource(android.R.drawable.ic_menu_gallery);
170 | boolean activate = (isSelected(position) || isCut(ftpFile.getName()));
171 | holder.itemView.setActivated(activate);
172 | }
173 |
174 | public boolean isDirectory(FTPFile dir){
175 | return dir.isDirectory();
176 | }
177 |
178 | protected class fileOnClickListener implements View.OnClickListener, View.OnLongClickListener {
179 | FilesFragment fragment;
180 | FTPFile file;
181 | int pos;
182 |
183 | public fileOnClickListener(FilesFragment fragment, int pos) {
184 | this.pos = pos;
185 | this.file = dataset.get(pos);
186 | this.fragment = fragment;
187 | }
188 |
189 | @Override
190 | public boolean onLongClick(View v) {
191 | Log.d(TAG, (file.isDirectory() ? "Directory ": "File ") + file.getName() + " long clicked.");
192 | if(!fragment.isPasteMode()) {
193 | if (isSelecting() && file.isDirectory()) {
194 | final View view = v;
195 | PopupMenu menu = new PopupMenu(fragment.getActivity(), v);
196 | menu.getMenuInflater().inflate(R.menu.folder_popup_menu, menu.getMenu());
197 | menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
198 | @Override
199 | public boolean onMenuItemClick(MenuItem item) {
200 | switch (item.getItemId()) {
201 | case R.id.folderPopupOpen:
202 | fragment.openDirecory(file.getName());
203 | return true;
204 | case R.id.folderPopupSelect:
205 | fragment.selectItem(view);
206 | return true;
207 | default:
208 | return false;
209 | }
210 | }
211 | });
212 | menu.show();
213 | } else {
214 | fragment.selectItem(v);
215 | }
216 | }
217 | /* old
218 | if (isDirectory(file)) {
219 | Log.d(TAG, "Directory " + file.getName() + " long clicked.");
220 | DownloadDialog dialog = DownloadDialog.newInstance(file);
221 | dialog.setTargetFragment(fragment, 1);
222 | FragmentManager fm = fragment.getActivity().getSupportFragmentManager();
223 | dialog.show(fm, "Download");
224 | }
225 | else {
226 | Log.d(TAG, "File " + file.getName() + " long clicked.");
227 | fragment.selectItem(v);
228 | }
229 | */
230 | return true;
231 | }
232 |
233 | @Override
234 | public void onClick(View v) {
235 | if(isSelecting() && !fragment.isPasteMode()) {
236 | fragment.selectItem(v);
237 | }
238 | else {
239 | if (isDirectory(file)) {
240 | if(!isCut(file.getName())) {
241 | Log.d(TAG, "Directory " + file.getName() + " clicked.");
242 | fragment.openDirecory(file.getName());
243 | }
244 | } else {
245 | if(!fragment.isPasteMode()) {
246 | Log.d(TAG, "File " + file.getName() + " clicked.");
247 | DownloadDialog dialog = DownloadDialog.newInstance(file);
248 | dialog.setTargetFragment(fragment, 1);
249 | FragmentManager fm = fragment.getActivity().getSupportFragmentManager();
250 | dialog.show(fm, "Download");
251 | }
252 | }
253 | }
254 | }
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPFilesExplorer/FilesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPFilesExplorer;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.support.v7.widget.SearchView;
5 | import android.util.Log;
6 | import android.util.SparseBooleanArray;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 |
13 | import com.peppe.ftpclient.androidftp.R;
14 |
15 | import java.util.ArrayList;
16 | import java.util.Arrays;
17 | import java.util.Comparator;
18 | import java.util.List;
19 |
20 | /**
21 | * Created by Geri on 19/10/2015.
22 | */
23 | public abstract class FilesAdapter extends RecyclerView.Adapter{
24 | private static final String TAG = "FILES_ADAPTER";
25 | protected FilesFragment fragment;
26 | public ArrayList dataset;
27 |
28 | //********************** ITEM SELECTION **********************//
29 |
30 | protected SparseBooleanArray selectedItems;
31 | protected ArrayList cutItems;
32 |
33 | public void cutSelection(){
34 | cutItems = getSelectedNames();
35 | selectedItems.clear();
36 | notifyDataSetChanged();
37 | }
38 |
39 | public boolean toggleSelection(int pos) {
40 | boolean ans = false;
41 | if (selectedItems.get(pos, false)) {
42 | selectedItems.delete(pos);
43 | }
44 | else {
45 | selectedItems.put(pos, true);
46 | ans = true;
47 | }
48 | notifyItemChanged(pos);
49 | return ans;
50 | }
51 |
52 | public boolean isSelected(int pos){
53 | return selectedItems.get(pos,false);
54 | }
55 |
56 | public boolean isCut(String name){
57 | return fragment.dir.equals(fragment.cutSource) && cutItems.contains(name);
58 | }
59 |
60 | public void clearSelections() {
61 | selectedItems.clear();
62 | notifyDataSetChanged();
63 | }
64 |
65 | public void clearCuts() {
66 | cutItems.clear();
67 | notifyDataSetChanged();
68 | }
69 |
70 |
71 | public int getSelectedItemCount() {
72 | return selectedItems.size();
73 | }
74 |
75 | public int getCutItemCount() {
76 | return cutItems.size();
77 | }
78 |
79 | public boolean isSelecting() { return getSelectedItemCount() != 0; }
80 |
81 | public ArrayList getSelectedIndices() {
82 | ArrayList items =
83 | new ArrayList(selectedItems.size());
84 | for (int i = 0; i < selectedItems.size(); i++) {
85 | items.add(selectedItems.keyAt(i));
86 | }
87 | return items;
88 | }
89 |
90 | public abstract ArrayList getSelectedItems();
91 |
92 | public ArrayList getCutNames(){
93 | return cutItems;
94 | }
95 |
96 | public abstract ArrayList getSelectedNames();
97 |
98 | //********************** END ITEM SELECTION **********************//
99 |
100 | public FilesAdapter(FilesFragment fragment) {
101 | this.fragment = fragment;
102 | this.selectedItems = new SparseBooleanArray();
103 | this.cutItems = new ArrayList<>();
104 | }
105 |
106 | protected abstract void sort(int mode);
107 |
108 | @Override
109 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
110 | View v = LayoutInflater.from(parent.getContext())
111 | .inflate(R.layout.files_recycler_item, parent, false);
112 |
113 | return new ViewHolder(v);
114 | }
115 |
116 | public String convertToStringRepresentation(long value) {
117 | final long K = 1024;
118 | final long M = K * K;
119 | final long G = M * K;
120 | final long T = G * K;
121 | final long[] dividers = new long[]{T, G, M, K, 1};
122 | final String[] units = new String[]{"TB", "GB", "MB", "KB", "B"};
123 | String result = "0 B";
124 | for (int i = 0; i < dividers.length; i++) {
125 | final long divider = dividers[i];
126 | if (value >= divider) {
127 | result = format(value, divider, units[i]);
128 | break;
129 | }
130 | }
131 | //Log.d(TAG, "value: "+value+", result: "+result);
132 | return result;
133 | }
134 |
135 | private String format(final long value,
136 | final long divider,
137 | final String unit) {
138 | final double result =
139 | divider > 1 ? (double) value / (double) divider : (double) value;
140 | return String.format("%.1f %s", result, unit);
141 | }
142 |
143 | @Override
144 | public abstract void onBindViewHolder(ViewHolder holder, int position);
145 |
146 | public void setDataset(E[] dataset) {
147 | if (dataset == null) {
148 | Log.d(TAG, "file dataset null");
149 | this.dataset = new ArrayList<>();
150 | }
151 | else {
152 | /*
153 | ArrayList dirs = new ArrayList<>();
154 | ArrayList files = new ArrayList<>();
155 | for (E dir : dataset) {
156 | if (isDirectory(dir))
157 | dirs.add(dir);
158 | else
159 | files.add(dir);
160 | }
161 | */
162 | if (this.dataset == null)
163 | this.dataset = new ArrayList<>();
164 | animateTo(Arrays.asList(dataset));
165 | sort(FileComparator.BY_NAME);
166 |
167 | /*
168 | int i = 0;
169 | for (i = 0; i < dirs.size(); i++)
170 | this.dataset.add(dirs.get(i));
171 | for (i = 0; i < files.size(); i++)
172 | this.dataset.add(files.get(i));
173 | */
174 | }
175 |
176 | }
177 |
178 | public abstract boolean isDirectory(E dir);
179 |
180 | @Override
181 | public int getItemCount() {
182 | if (dataset == null)
183 | return 0;
184 | return dataset.size();
185 | }
186 |
187 | public static class ViewHolder extends RecyclerView.ViewHolder {
188 | private final TextView nameTextView;
189 | private final TextView infoTextView;
190 | private final ImageView imageView;
191 | public final String TAG = "FILES_VH";
192 | private View v;
193 |
194 | public ViewHolder(View v) {
195 | super(v);
196 | this.v = v;
197 | // Define click listener for the ViewHolder's View.
198 | v.setOnClickListener(new View.OnClickListener() {
199 | @Override
200 | public void onClick(View v) {
201 | Log.d(TAG, "Element " + getPosition() + " clicked.");
202 | //here i try to open the dialog fragment.
203 |
204 | }
205 | });
206 | nameTextView = (TextView) v.findViewById(R.id.fileNameTextView);
207 | infoTextView = (TextView) v.findViewById(R.id.fileInfoTextView);
208 | imageView = (ImageView) v.findViewById(R.id.fileImageView);
209 | }
210 |
211 | public void setOnClickListener(View.OnClickListener listener) {
212 | v.setOnClickListener(listener);
213 | }
214 |
215 | public TextView getNameTextView() {
216 | return nameTextView;
217 | }
218 |
219 | public ImageView getImageView() {
220 | return imageView;
221 | }
222 |
223 | public TextView getInfoTextView() {
224 | return infoTextView;
225 | }
226 | }
227 |
228 | protected abstract class FileComparator implements Comparator{
229 | public static final int BY_NAME = 101;
230 | public static final int BY_SIZE = 102;
231 | public static final int BY_TYPE = 103;
232 | public static final int BY_TIME = 104;
233 |
234 | protected int mode;
235 |
236 | public FileComparator(int mode){
237 | this.mode = mode;
238 | }
239 |
240 | protected String getName(String fullName){
241 | if(fullName.indexOf('.')<0)
242 | return fullName;
243 | else
244 | return fullName.substring(0, fullName.indexOf('.'));
245 | }
246 |
247 | protected String getExt(String fullName){
248 | if(fullName.indexOf('.')<0)
249 | return "";
250 | else
251 | return fullName.substring(fullName.indexOf('.')+1);
252 | }
253 | }
254 |
255 | public E removeItem(int position) {
256 | final E file = dataset.remove(position);
257 | notifyItemRemoved(position);
258 | return file;
259 | }
260 |
261 | public void addItem(int position, E file) {
262 | dataset.add(position, file);
263 | notifyItemInserted(position);
264 | }
265 |
266 | public void moveItem(int fromPosition, int toPosition) {
267 | final E file = dataset.remove(fromPosition);
268 | dataset.add(toPosition, file);
269 | notifyItemMoved(fromPosition, toPosition);
270 | }
271 |
272 | private void applyAndAnimateRemovals(List newData) {
273 | for (int i = dataset.size() - 1; i >= 0; i--) {
274 | final E file = dataset.get(i);
275 | if (!newData.contains(file)) {
276 | removeItem(i);
277 | }
278 | }
279 | }
280 |
281 | private void applyAndAnimateAdditions(List newData) {
282 | for (int i = 0; i < newData.size(); i++) {
283 | final E file = newData.get(i);
284 | if (!dataset.contains(file)) {
285 | addItem(i, file);
286 | }
287 | }
288 | /*
289 | for (int i = newData.size() - 1; i >= 0; i--) {
290 | final E file = newData.get(i);
291 | if (!dataset.contains(file)) {
292 | addItem(i, file);
293 | }
294 | }
295 | */
296 | }
297 |
298 | private void applyAndAnimateMovedItems(List newData) {
299 | for (int toPosition = newData.size() - 1; toPosition >= 0; toPosition--) {
300 | final E file = newData.get(toPosition);
301 | final int fromPosition = dataset.indexOf(file);
302 | if (fromPosition >= 0 && fromPosition != toPosition) {
303 | moveItem(fromPosition, toPosition);
304 | }
305 | }
306 | }
307 |
308 | public void animateTo(List newData) {
309 | applyAndAnimateRemovals(newData);
310 | applyAndAnimateAdditions(newData);
311 | applyAndAnimateMovedItems(newData);
312 | }
313 |
314 |
315 | }
316 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPConnectionsList/EditConnectionFragment.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPConnectionsList;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.TextInputLayout;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentManager;
7 | import android.text.Editable;
8 | import android.text.TextWatcher;
9 | import android.view.LayoutInflater;
10 | import android.view.Menu;
11 | import android.view.MenuInflater;
12 | import android.view.MenuItem;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.CompoundButton;
16 | import android.widget.Spinner;
17 | import android.widget.Switch;
18 | import android.widget.Toast;
19 |
20 | import com.peppe.ftpclient.androidftp.FTPClientMain.FTPConnection;
21 | import com.peppe.ftpclient.androidftp.FTPClientMain.MainActivity;
22 | import com.peppe.ftpclient.androidftp.R;
23 |
24 | public class EditConnectionFragment extends Fragment {
25 | // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
26 | private static final String ARG_CONNECTION = "toEdit";
27 |
28 | public static final String TAG = "EDIT_CONNECTION_FRAG";
29 |
30 | private FTPConnection toEdit;
31 |
32 | private FormContainer form;
33 |
34 | private final class FormContainer {
35 | public TextInputLayout editName;
36 | public TextInputLayout editHost;
37 | public TextInputLayout editUser;
38 | public TextInputLayout editPass;
39 | public TextInputLayout editPort;
40 |
41 | public Spinner editProtocol;
42 |
43 | public Switch editAnonymous;
44 |
45 | public FormContainer(View view) {
46 | editName = (TextInputLayout) view.findViewById(R.id.nameInputLayout);
47 | editHost = (TextInputLayout) view.findViewById(R.id.hostInputLayout);
48 | editUser = (TextInputLayout) view.findViewById(R.id.userInputLayout);
49 | editPass = (TextInputLayout) view.findViewById(R.id.passInputLayout);
50 | editPort = (TextInputLayout) view.findViewById(R.id.portInputLayout);
51 |
52 | editProtocol = (Spinner) view.findViewById(R.id.editProtocolSpinner);
53 |
54 | editAnonymous = (Switch) view.findViewById(R.id.editAnonymousSwitch);
55 | }
56 | }
57 |
58 |
59 | public static EditConnectionFragment newInstance(FTPConnection param) {
60 | EditConnectionFragment fragment = new EditConnectionFragment();
61 | Bundle args = new Bundle();
62 | args.putSerializable(ARG_CONNECTION, param);
63 | fragment.setArguments(args);
64 | return fragment;
65 | }
66 |
67 | @Override
68 | public void onResume() {
69 | super.onResume();
70 | ((MainActivity)getActivity()).fab.hide();
71 | }
72 |
73 | public EditConnectionFragment() {
74 | // Required empty public constructor
75 | }
76 |
77 | @Override
78 | public void onCreate(Bundle savedInstanceState) {
79 | super.onCreate(savedInstanceState);
80 | setHasOptionsMenu(true);
81 | if (getArguments() != null) {
82 | toEdit = (FTPConnection) getArguments().getSerializable(ARG_CONNECTION);
83 | }
84 | }
85 |
86 | @Override
87 | public void onViewCreated(View view, Bundle savedInstanceState) {
88 | super.onViewCreated(view, savedInstanceState);
89 |
90 |
91 | form = new FormContainer(view);
92 |
93 | //edit connection
94 | if (toEdit != null) {
95 | if (!toEdit.getName().equals("")) {
96 | form.editName.getEditText().setText(toEdit.getName());
97 | }
98 | form.editHost.getEditText().setText(toEdit.getHost());
99 |
100 | if (toEdit.getUser().equals("anonymous")) {
101 | form.editAnonymous.setChecked(true);
102 | }
103 | form.editUser.getEditText().setText(toEdit.getUser());
104 | form.editPass.getEditText().setText(toEdit.getPass());
105 | form.editPort.getEditText().setText(Integer.toString(toEdit.getPort()));
106 |
107 | form.editProtocol.setSelection(toEdit.getIndexProtocol());
108 | }
109 |
110 | if (form.editAnonymous.isChecked()) {
111 | form.editUser.setVisibility(View.GONE);
112 | form.editPass.setVisibility(View.GONE);
113 | }
114 |
115 | form.editName.getEditText().addTextChangedListener(new FTPConnectionTextWatcher(form.editName));
116 | form.editHost.getEditText().addTextChangedListener(new FTPConnectionTextWatcher(form.editHost));
117 | form.editUser.getEditText().addTextChangedListener(new FTPConnectionTextWatcher(form.editUser));
118 | form.editPass.getEditText().addTextChangedListener(new FTPConnectionTextWatcher(form.editPass));
119 | form.editPort.getEditText().addTextChangedListener(new FTPConnectionTextWatcher(form.editPort));
120 |
121 | form.editAnonymous.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
122 | @Override
123 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
124 | if (isChecked) {
125 | form.editUser.setVisibility(View.GONE);
126 | form.editPass.setVisibility(View.GONE);
127 | form.editUser.getEditText().setText(R.string.anonymous_connection_user);
128 | form.editPass.getEditText().setText("");
129 | } else {
130 | form.editUser.setVisibility(View.VISIBLE);
131 | form.editPass.setVisibility(View.VISIBLE);
132 | }
133 | }
134 | });
135 | }
136 |
137 | @Override
138 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
139 | Bundle savedInstanceState) {
140 | return inflater.inflate(R.layout.fragment_edit_connection, container, false);
141 | }
142 |
143 | @Override
144 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
145 | super.onCreateOptionsMenu(menu, inflater);
146 | inflater.inflate(R.menu.menu_edit_connections, menu);
147 | //menu.findItem(R.menu.menu_main).setVisible(false);
148 | }
149 |
150 | @Override
151 | public boolean onOptionsItemSelected(MenuItem item) {
152 | switch (item.getItemId()) {
153 | case R.id.action_done_edit_connection:
154 | if (validateInput()) {
155 | String name = form.editName.getEditText().getText().toString();
156 | String host = form.editHost.getEditText().getText().toString();
157 | String user = form.editUser.getEditText().getText().toString();
158 | String pass = form.editPass.getEditText().getText().toString();
159 | if (form.editAnonymous.isChecked()) {
160 | user = "anonymous";
161 | pass = "";
162 | }
163 |
164 | int port = Integer.parseInt(form.editPort.getEditText().getText().toString());
165 | int protocol = form.editProtocol.getSelectedItemPosition();
166 | FTPConnection edited = new FTPConnection(name, host, user, pass, port, protocol);
167 | if (toEdit != null)
168 | edited.setId(edited.getId());
169 | ((MainActivity) getActivity()).finishEditConnection(toEdit, edited);
170 | } else {
171 | Toast.makeText(getActivity(), "Check input errors!", Toast.LENGTH_SHORT).show();
172 | }
173 | return true;
174 | case android.R.id.home:
175 | FragmentManager fm = getActivity().getSupportFragmentManager();
176 | if (fm.getBackStackEntryCount() > 0) {
177 | fm.popBackStack();
178 | }
179 | return true;
180 | default:
181 | return super.onOptionsItemSelected(item);
182 | }
183 | }
184 |
185 | private boolean validateInput() {
186 | validateHost();
187 | validatePort();
188 | validateUser();
189 | return !(form.editHost.isErrorEnabled() || form.editPort.isErrorEnabled() || form.editUser.isErrorEnabled());
190 | }
191 |
192 | public void validateHost() {
193 | TextInputLayout til = form.editHost;
194 | if (til.getEditText().getText().toString().isEmpty()) {
195 | til.setError(getString(R.string.cn_host_edit_error));
196 | til.requestFocus();
197 | } else {
198 | til.setErrorEnabled(false);
199 | }
200 | }
201 |
202 | public void validateUser() {
203 | TextInputLayout til = form.editUser;
204 | if (til.getEditText().getText().toString().isEmpty()) {
205 | til.setError(getString(R.string.cn_user_edit_error));
206 | til.requestFocus();
207 | } else {
208 | til.setErrorEnabled(false);
209 | }
210 | }
211 |
212 | public void validatePort() {
213 | TextInputLayout til = form.editPort;
214 | if (til.getEditText().getText().toString().isEmpty()) {
215 | til.setError(getString(R.string.cn_port_edit_error));
216 | til.requestFocus();
217 | } else {
218 | int port = Integer.parseInt(til.getEditText().getText().toString());
219 | if (port < 1 || port > 65535) {
220 | til.setError(getString(R.string.cn_port_edit_error));
221 | til.requestFocus();
222 | } else
223 | til.setErrorEnabled(false);
224 | }
225 | }
226 |
227 | private class FTPConnectionTextWatcher implements TextWatcher {
228 | private TextInputLayout til;
229 |
230 | public FTPConnectionTextWatcher(TextInputLayout til) {
231 | this.til = til;
232 | }
233 |
234 | @Override
235 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
236 |
237 | }
238 |
239 | @Override
240 | public void onTextChanged(CharSequence s, int start, int before, int count) {
241 |
242 | }
243 |
244 | @Override
245 | public void afterTextChanged(Editable s) {
246 | switch (til.getId()) {
247 | case R.id.hostInputLayout:
248 | validateHost();
249 | break;
250 | case R.id.userInputLayout:
251 | validateUser();
252 | break;
253 | case R.id.portInputLayout:
254 | validatePort();
255 | break;
256 | }
257 | }
258 | }
259 |
260 | }
261 |
--------------------------------------------------------------------------------
/app/src/main/java/com/peppe/ftpclient/androidftp/FTPClientMain/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.peppe.ftpclient.androidftp.FTPClientMain;
2 |
3 |
4 | import android.Manifest;
5 | import android.annotation.TargetApi;
6 | import android.content.Context;
7 | import android.content.pm.PackageManager;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.support.design.widget.FloatingActionButton;
11 | import android.support.v4.app.FragmentManager;
12 | import android.support.v4.app.FragmentTransaction;
13 | import android.support.v7.app.AppCompatActivity;
14 | import android.support.v7.widget.Toolbar;
15 | import android.util.Log;
16 | import android.view.ActionMode;
17 | import android.view.KeyEvent;
18 | import android.view.Menu;
19 | import android.view.MenuInflater;
20 | import android.view.MenuItem;
21 | import android.view.View;
22 | import android.view.inputmethod.InputMethodManager;
23 | import android.widget.Toast;
24 |
25 | import com.peppe.ftpclient.androidftp.FTPConnectionsList.ConnectionsFragment;
26 | import com.peppe.ftpclient.androidftp.FTPConnectionsList.EditConnectionFragment;
27 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPLocalExplorer.LocalFilesFragment;
28 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPRemoteExplorer.RemoteFilesFragment;
29 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FTPViewPager;
30 | import com.peppe.ftpclient.androidftp.FTPFilesExplorer.FilesFragment;
31 | import com.peppe.ftpclient.androidftp.R;
32 |
33 | import org.apache.commons.net.ftp.FTPClient;
34 |
35 | public class MainActivity extends AppCompatActivity implements View.OnClickListener{
36 |
37 | private final String TAG = "MAINACTIVITY";
38 |
39 | private final int MY_EXTERNAL_STORAGE = 401;
40 |
41 | public boolean isRemoteAlive = false;
42 | public boolean isLocalAlive = false;
43 | public RemoteFilesFragment remote;
44 | public LocalFilesFragment local;
45 |
46 | public Toast commonToast;
47 |
48 | private String savedTitle = null;
49 |
50 | public FloatingActionButton fab;
51 |
52 | private ConnectionsFragment cf;
53 | private String errorMessage;
54 |
55 | @Override
56 | protected void onCreate(Bundle savedInstanceState) {
57 | super.onCreate(savedInstanceState);
58 |
59 |
60 | setContentView(R.layout.activity_main);
61 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
62 | setSupportActionBar(toolbar);
63 |
64 | commonToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
65 |
66 | Log.d(TAG, "before replace");
67 | getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
68 | @Override
69 | public void onBackStackChanged() {
70 | int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
71 | if (stackHeight > 0) { // if we have something on the stack (doesn't include the current shown fragment)
72 | getSupportActionBar().setHomeButtonEnabled(true);
73 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
74 | } else {
75 | getSupportActionBar().setDisplayHomeAsUpEnabled(false);
76 | getSupportActionBar().setHomeButtonEnabled(false);
77 | }
78 | }
79 |
80 | });
81 |
82 |
83 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
84 | cf = new ConnectionsFragment();
85 | ft.replace(R.id.main_placeholder, cf, "CONNECTIONS_FRAGMENT");
86 | ft.commit();
87 | Log.d(TAG, "after replace");
88 | fab = (FloatingActionButton) findViewById(R.id.connections_fab);
89 |
90 | }
91 |
92 | @TargetApi(Build.VERSION_CODES.M)
93 | public boolean requestStoragePermission(String errorMessage) {
94 | int sdk = Build.VERSION.SDK_INT;
95 | if(sdk >= Build.VERSION_CODES.M) {
96 | if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
97 | PackageManager.PERMISSION_GRANTED) {
98 | requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
99 | Manifest.permission.READ_EXTERNAL_STORAGE}, MY_EXTERNAL_STORAGE);
100 | this.errorMessage = errorMessage;
101 | return false;
102 | }
103 | else
104 | return true;
105 | }
106 | return true;
107 | }
108 |
109 | @Override
110 | public boolean onCreateOptionsMenu(Menu menu) {
111 | getMenuInflater().inflate(R.menu.menu_main, menu);
112 | return true;
113 | }
114 |
115 | @Override
116 | public boolean onPrepareOptionsMenu(Menu menu) {
117 | MenuItem paste = menu.findItem(R.id.action_paste_file);
118 | if(getActiveFragment()!=null && paste != null ){
119 | Log.d(TAG, "paste menu item found");
120 | if(getActiveFragment().isPasteMode()) {
121 | Log.d(TAG, "in paste mode");
122 | savedTitle = getTitle().toString();
123 | String state = (getActiveFragment().isCopy() ? "Copy" : "Cut");
124 | setTitle(state + ": "+getActiveFragment().filesAdapter.getCutItemCount()+ " File(s).");
125 |
126 | }
127 | else if (savedTitle != null)
128 | setTitle(savedTitle);
129 | MenuItem home = menu.findItem(android.R.id.home);
130 | int icon = ((getActiveFragment() != null && getActiveFragment().isPasteMode()) ? R.drawable.ic_cancel : R.drawable.ic_back);
131 |
132 | getSupportActionBar().setHomeAsUpIndicator(icon);
133 | paste.setVisible(getActiveFragment().isPasteMode());
134 | return true;
135 | }
136 | return super.onPrepareOptionsMenu(menu);
137 | }
138 |
139 | public void setRemoteFragment(RemoteFilesFragment frag){
140 | this.remote = frag;
141 | }
142 |
143 | public void setLocalFragment(LocalFilesFragment frag){
144 | this.local = frag;
145 | }
146 |
147 | @Override
148 | public boolean onOptionsItemSelected(MenuItem item) {
149 | switch(item.getItemId()){
150 | case R.id.action_paste_file:
151 | getActiveFragment().pasteFiles();
152 | invalidateOptionsMenu();
153 | return true;
154 | case android.R.id.home:
155 | Log.d(TAG, "clicked home");
156 | if(getActiveFragment().isPasteMode()){
157 | getActiveFragment().pasteMode(false);
158 | return true;
159 | }
160 | default:
161 | return super.onOptionsItemSelected(item);
162 | }
163 | }
164 |
165 | @Override
166 | public void onBackPressed() {
167 | boolean back = false;
168 | if(remote != null && isRemoteAlive && !isLocalAlive){
169 | Log.d(TAG, "back pressed on remote");
170 | back = remote.pressBack();
171 | }
172 | else if(local != null && !isRemoteAlive && isLocalAlive){
173 | back = local.pressBack();
174 | }
175 | else{
176 | super.onBackPressed();
177 | /*Log.d(TAG, remote == null ? "remote is null in main" : "remote is not null in main");
178 | Log.d(TAG, isRemoteAlive ? "remote is alive in main" : "remote is not alive in main");
179 | Log.d(TAG, isLocalAlive ? "local is alive in main" : "local is not alive in main");*/
180 | }
181 | if (back) {
182 | super.onBackPressed();
183 | }
184 |
185 | }
186 |
187 |
188 | protected void onResume(){
189 | super.onResume();
190 | /*
191 | FTPConnection test = new FTPConnection();
192 | view= ((ListFragment)getFragmentManager().findFragmentById(R.id.fragment)).getListView();
193 | adapter = new ArrayAdapter(view.getContext(), android.R.layout.simple_list_item_activated_1);
194 | view.setAdapter(adapter);
195 | if(client == null)
196 | client = new FTPClient();
197 | new FTPConnectTask().execute(test);
198 | */
199 | }
200 |
201 | public void connectTo(FTPConnection connection){
202 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
203 | FTPViewPager pager = FTPViewPager.newInstance(connection);
204 | ft.replace(R.id.main_placeholder, pager);
205 | ft.addToBackStack("CONNECTION_PAGER");
206 | ft.commit();
207 | isRemoteAlive = true;
208 | isLocalAlive = false;
209 | }
210 |
211 | public void startEditConnection(FTPConnection connection){
212 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
213 | EditConnectionFragment editCF = EditConnectionFragment.newInstance(connection);
214 | ft.replace(R.id.main_placeholder, editCF);
215 | ft.addToBackStack("EDIT_CONNECTION");
216 | ft.commit();
217 |
218 | }
219 |
220 | public void finishEditConnection(FTPConnection old, FTPConnection edited){
221 | InputMethodManager inputManager = (InputMethodManager)
222 | getSystemService(Context.INPUT_METHOD_SERVICE);
223 | View v = getCurrentFocus();
224 | if(v != null)
225 | inputManager.hideSoftInputFromWindow(v.getWindowToken(),
226 | InputMethodManager.HIDE_NOT_ALWAYS);
227 |
228 |
229 | FragmentManager fm = getSupportFragmentManager();
230 | if (fm.getBackStackEntryCount() > 0) {
231 | fm.popBackStack();
232 | FragmentTransaction ft = fm.beginTransaction();
233 | ft.replace(R.id.main_placeholder, cf, "CONNECTIONS_FRAGMENT");
234 | ft.commit();
235 | cf.editDatabase(old, edited);
236 | }
237 | }
238 |
239 | public FilesFragment getActiveFragment(){
240 | if(remote!=null && isRemoteAlive && !isLocalAlive)
241 | return remote;
242 | else
243 | return local;
244 | }
245 |
246 | @Override
247 | public void onClick(View v) {
248 | if(isRemoteAlive && !isLocalAlive){
249 | Toast.makeText(this, "remote!", Toast.LENGTH_SHORT).show();
250 | }
251 | else if(isLocalAlive && !isRemoteAlive){
252 | Toast.makeText(this, "local!", Toast.LENGTH_SHORT).show();
253 | }
254 | }
255 |
256 | @Override
257 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
258 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
259 | switch (requestCode){
260 | case MY_EXTERNAL_STORAGE:
261 | if (grantResults.length > 0
262 | && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
263 | if(isRemoteAlive)
264 | Toast.makeText(this, getString(R.string.try_again), Toast.LENGTH_SHORT).show();
265 | if(local != null)
266 | local.refreshDir();
267 | }
268 | else
269 | Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show();
270 | }
271 | }
272 | }
273 |
--------------------------------------------------------------------------------