diff --git a/README.md b/README.md index d2fffc8..b4eec94 100644 --- a/README.md +++ b/README.md @@ -63,75 +63,21 @@ Using it in productivity, will make your server extremely vulnerable. ### Prerequisites -We're using ```docker``` and ```docker-compose``` to run the FTP server. -Go through the [official documentation](https://docs.docker.com/install/) in order to get both components installed. ### Build -Open ```map-file-download-center/docker-compose.yml``` and change the ```environment``` variables to your needs: -In this example, every file in `/opt/ohdm/` will be shown in the android application. Make sure, that there are actually `map-files` in the directory you specified under `volumes` in the `docker-compose.yml`. -``` -version: "3.3" -services: - vsftpd: - container_name: vsftpd - image: panubo/vsftpd - ports: - - "21:21" - - "4559-4564:4559-4564" - restart: always - environment: - FTP_USER: ohdm - FTP_PASSWORD: ohdm - FTP_USERS_ROOT: - network_mode: "host" - volumes: - - /opt/ohdm:/srv/ohdm - -``` - -Now you can start the container with - -``` -docker-compose up -``` - -If successful, you should see - -``` -... -vsftpd | Received SIGINT or SIGTERM. Shutting down vsftpd -vsftpd | Running vsftpd -``` -at the end of the output. -Great, now you can begin to adjust the source code to point the app to your ftp server ### Configure -Open the file ```app/src/main/java/de/htwBerlin/ois/Activities/MapDownloadActivity.java```: -and change the parameter with the values you just used in the ```docker-compose``` file: - -``` -... -private static final String FTP_SERVER_IP = ""; -private static final Integer FTP_PORT = 21; -private static final String FTP_USER = ""; -private static final String FTP_PASSWORD = ""; -... -``` ### Deploy -Just install the application again on your device with Android Studio. - -In order to host ```map```-files on the FTP server, just copy the files to ```/opt/ohdm/``` - -You then should see the listed files in the ```Maps``` tab. -You can start the container with ```docker-compose up -d``` in background. ## Contact Developed by: [FalcoSuessgott](https://github.com/FalcoSuessgott) +Developed by: [WilliBoelke](https://github.com/WilliBoelke) +Developed by: [NoteFox](https://github.com/NoteFox) Project Link: [Open Historical Data Map](https://github.com/OpenHistoricalDataMap) diff --git a/app/build.gradle b/app/build.gradle index 6ca3aea..d52f5ab 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,7 +24,7 @@ dependencies { implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.support:support-v4:28.0.0' implementation 'com.android.support:design:28.0.0' - compile group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.5.1' + compile group: 'org.apache.httpcomponents', name: 'httpclient-android', version: '4.3.5.1' implementation 'android.arch.lifecycle:extensions:1.1.1' testImplementation 'junit:junit:4.12' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2d90b3f..036abb9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,13 +12,13 @@ - + android:theme="@style/AppTheme" + android:usesCleartextTraffic="true"> + diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFileListViewAdapter.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFileListViewAdapter.java index 03a5819..554ee1e 100644 --- a/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFileListViewAdapter.java +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFileListViewAdapter.java @@ -12,8 +12,8 @@ import java.util.ArrayList; -import de.htwBerlin.ois.ServerCommunication.FtpTaskFileDownloading; import de.htwBerlin.ois.R; +import de.htwBerlin.ois.ServerCommunication.FtpTaskFileDownloading; /** * ListView adapter that holds ohdmFiles @@ -23,7 +23,7 @@ * @author morelly_t1 */ @Deprecated -public class OhdmFileListViewAdapter extends ArrayAdapter +public class OhdmFileListViewAdapter extends ArrayAdapter { private static final String TAG = "OhdmFileAdapter"; @@ -31,7 +31,7 @@ public class OhdmFileListViewAdapter extends ArrayAdapter private Context context; private int resource; - public OhdmFileListViewAdapter(Context context, int resource, ArrayList ohdmFiles) + public OhdmFileListViewAdapter(Context context, int resource, ArrayList ohdmFiles) { super(context, resource, ohdmFiles); this.context = context; @@ -45,7 +45,7 @@ public View getView(int position, View convertView, ViewGroup parent) String creationDate = getItem(position).getCreationDate(); Boolean isDownloaded = getItem(position).isDownloaded(); - final OhdmFile ohdmFile = new OhdmFile(fileName, fileSize, creationDate, isDownloaded); + final RemoteFile ohdmFile = new RemoteFile(fileName, fileSize, creationDate, isDownloaded); LayoutInflater inflater = LayoutInflater.from(context); convertView = inflater.inflate(resource, parent, false); @@ -63,7 +63,7 @@ public View getView(int position, View convertView, ViewGroup parent) @Override public void onClick(View v) { - FtpTaskFileDownloading ftpTaskFileDownloading = new FtpTaskFileDownloading(context); + FtpTaskFileDownloading ftpTaskFileDownloading = new FtpTaskFileDownloading(context, ""); Toast.makeText(getContext(), "Downloading " + fileName, Toast.LENGTH_SHORT).show(); ftpTaskFileDownloading.execute(ohdmFile); disableButton(buttonDownloadFile); diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFileRecyclerAdapter.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFileRecyclerAdapter.java deleted file mode 100644 index ed07315..0000000 --- a/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFileRecyclerAdapter.java +++ /dev/null @@ -1,109 +0,0 @@ -package de.htwBerlin.ois.FileStructure; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.ArrayList; - -import de.htwBerlin.ois.R; - -public class OhdmFileRecyclerAdapter extends RecyclerView.Adapter -{ - private ArrayList mapArrayList; - private Context context; - private int ressource; - private OnItemClickListener onItemClickListener; - - public OhdmFileRecyclerAdapter(Context context, ArrayList ohdmFiles, int ressource) - { - this.ressource = ressource; - this.mapArrayList = ohdmFiles; - this.context = context; - } - - @NonNull - @Override - public OhdmFileViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) - { - View view = LayoutInflater.from(parent.getContext()).inflate(ressource, parent, false); - return new OhdmFileRecyclerAdapter.OhdmFileViewHolder(view, this.onItemClickListener); - } - - @Override - public void onBindViewHolder(@NonNull OhdmFileRecyclerAdapter.OhdmFileViewHolder ohdmFileViewHolder, int position) - { - OhdmFile currentOhdmFile = this.mapArrayList.get(position); - String name = currentOhdmFile.getFilename(); - name = name.replace(".map", ""); - ohdmFileViewHolder.nameTextView.setText(name); - ohdmFileViewHolder.sizeTextView.setText((int) (double) (currentOhdmFile.getFileSize() / 1024) + " KB"); - ohdmFileViewHolder.dateTextView.setText(currentOhdmFile.getCreationDate()); - } - - @Override - public int getItemCount() - { - return mapArrayList.size(); - } - - public OhdmFile getFile(int position) - { - return this.mapArrayList.get(position); - } - - public void setOnItemClickListener(OhdmFileRecyclerAdapter.OnItemClickListener listener) - { - this.onItemClickListener = listener; - } - - - public interface OnItemClickListener - { - void onItemClick(int position); - } - - - protected static class OhdmFileViewHolder extends RecyclerView.ViewHolder - { - - public TextView nameTextView; - public TextView sizeTextView; - public TextView dateTextView; - - - public OhdmFileViewHolder(@NonNull View itemView, final OhdmFileRecyclerAdapter.OnItemClickListener listener) - { - super(itemView); - sizeTextView = itemView.findViewById(R.id.map_size_tv); - nameTextView = itemView.findViewById(R.id.map_name_tv); - dateTextView = itemView.findViewById(R.id.date_of_creation_tv); - - - itemView.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - if (listener != null) - { - int position = getAdapterPosition(); - if (position != RecyclerView.NO_POSITION) - { - listener.onItemClick(position); - } - } - } - }); - - } - } - - -} \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/OnRecyclerItemButtonClicklistenner.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/OnRecyclerItemButtonClicklistenner.java new file mode 100644 index 0000000..bd700a6 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/OnRecyclerItemButtonClicklistenner.java @@ -0,0 +1,6 @@ +package de.htwBerlin.ois.FileStructure; + +public interface OnRecyclerItemButtonClicklistenner +{ + void onButtonClick(int position); +} diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/LocalMapsRecyclerAdapter.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterLocalFiles.java similarity index 51% rename from app/src/main/java/de/htwBerlin/ois/FileStructure/LocalMapsRecyclerAdapter.java rename to app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterLocalFiles.java index 0830dcb..e0d9c7c 100644 --- a/app/src/main/java/de/htwBerlin/ois/FileStructure/LocalMapsRecyclerAdapter.java +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterLocalFiles.java @@ -7,6 +7,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Filter; +import android.widget.Filterable; import android.widget.ImageView; import android.widget.TextView; @@ -15,18 +17,88 @@ import de.htwBerlin.ois.R; - -public class LocalMapsRecyclerAdapter extends RecyclerView.Adapter +/** + * @author WilliBoelke + */ +public class RecyclerAdapterLocalFiles extends RecyclerView.Adapter implements Filterable { + + //------------Instance Variables------------ + + /** + * Log tag + */ private final String TAG = getClass().getSimpleName(); + /** + * The ArrayList to be displayed by the RecyclerView + *

+ * This list may be altered when the user searches for maps + */ private ArrayList mapArrayList; + /** + * This list serves as Backup for the mapArrayList in case + * it was altered through the Search/Filter + */ + private ArrayList mapArrayListBackup; + /** + * Context + */ private Context context; - private int ressource; - private LocalMapsRecyclerAdapter.OnItemClickListener onItemClickListener; + /** + * The resource id of the Recycleritem layout + */ + private int resource; + /** + * onClickListener + * use the {@link this#setOnItemClickListener(OnItemClickListener)} + * to implement this + */ + private RecyclerAdapterLocalFiles.OnItemClickListener onItemClickListener; + + + //------------Constructors------------ + private Filter nameFilter = new Filter() + { + @Override + protected FilterResults performFiltering(CharSequence constraint) + { + ArrayList filteredList = new ArrayList<>(); + if (constraint == null || constraint.length() == 0) + { + filteredList.addAll(mapArrayListBackup); + } + else + { + String filterPattern = constraint.toString().toLowerCase().trim(); + for (File map : mapArrayListBackup) + { + if (map.getName().toLowerCase().trim().contains(filterPattern)) + { + filteredList.add(map); + } + } + } + FilterResults results = new FilterResults(); + results.values = filteredList; + return results; + } - public LocalMapsRecyclerAdapter(Context context, ArrayList ohdmFiles, int ressource) + @Override + protected void publishResults(CharSequence constraint, FilterResults results) + { + mapArrayList.clear(); + mapArrayList.addAll((ArrayList) results.values); + notifyDataSetChanged(); + } + }; + + + //------------RecyclerViewAdapter Methods------------ + + public RecyclerAdapterLocalFiles(Context context, ArrayList ohdmFiles, int ressource) { - this.ressource = ressource; + this.mapArrayListBackup = new ArrayList<>(ohdmFiles); // need to be initialized like that + this.resource = ressource; this.mapArrayList = ohdmFiles; this.context = context; } @@ -35,7 +107,7 @@ public LocalMapsRecyclerAdapter(Context context, ArrayList ohdmFiles, int @Override public LocalMapsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) { - View view = LayoutInflater.from(parent.getContext()).inflate(ressource, parent, false); + View view = LayoutInflater.from(parent.getContext()).inflate(resource, parent, false); LocalMapsViewHolder localMapsViewHolder = new LocalMapsViewHolder(view, this.onItemClickListener); return localMapsViewHolder; } @@ -66,23 +138,49 @@ public void onBindViewHolder(@NonNull LocalMapsViewHolder localMapsViewHolder, i } } + + //------------OnItemClickListener------------ + @Override public int getItemCount() { return mapArrayList.size(); } - public void setOnItemClickListener(LocalMapsRecyclerAdapter.OnItemClickListener listener) + /** + * Setter for the implemented onItemClick method + * + * @param listener + */ + public void setOnItemClickListener(RecyclerAdapterLocalFiles.OnItemClickListener listener) { this.onItemClickListener = listener; } + + //------------Filter (Name)------------ + + @Override + public Filter getFilter() + { + return nameFilter; + } + + /** + * An interface to define the + * onItemClick method + *

+ * can be implemented and set as on itemClickListener through the + * {@link this#setOnItemClickListener} method + */ public interface OnItemClickListener { void onItemClick(int position); } + //------------View Holder------------ + protected static class LocalMapsViewHolder extends RecyclerView.ViewHolder { @@ -91,7 +189,7 @@ protected static class LocalMapsViewHolder extends RecyclerView.ViewHolder public TextView dateTextView; public ImageView currentMapIcon; - public LocalMapsViewHolder(@NonNull View itemView, final LocalMapsRecyclerAdapter.OnItemClickListener listener) + public LocalMapsViewHolder(@NonNull View itemView, final RecyclerAdapterLocalFiles.OnItemClickListener listener) { super(itemView); sizeTextView = itemView.findViewById(R.id.map_size_tv); diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterRemoteDirectories.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterRemoteDirectories.java new file mode 100644 index 0000000..95781c2 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterRemoteDirectories.java @@ -0,0 +1,226 @@ +package de.htwBerlin.ois.FileStructure; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; + +import de.htwBerlin.ois.Fragments.FragmentDownloadCenterCategories; +import de.htwBerlin.ois.R; +import de.htwBerlin.ois.ServerCommunication.AsyncResponse; +import de.htwBerlin.ois.ServerCommunication.FtpTaskFileDownloading; +import de.htwBerlin.ois.ServerCommunication.FtpTaskFileListing; + + +/** + * A RecyclerView Adapter to display complete FTP directories. + *

+ * Each element of the Recycler stands for a single directory + * Each element has a name (TextView) which displays the name of the remote directory + * Each element contains another RecyclerView -linting the files (maps) within the directory {@link RecyclerAdapterRemoteFiles} + *

+ * used in : + * + * @author WilliBoelke + * @see FragmentDownloadCenterCategories + */ +public class RecyclerAdapterRemoteDirectories extends RecyclerView.Adapter +{ + + //------------Instance Variables------------ + + /** + * log tag + */ + private final String TAG = getClass().getSimpleName(); + /** + * This list will be altered when the user searches for maps + */ + private ArrayList directoryList; + /** + * Resource id for the RecyclerItem layout + */ + private int ressource; + /** + * Context + */ + private Context context; + + + //------------Constructors------------ + + /** + * Public constructor + * + * @param context + * @param directoryList + * @param ressource + */ + public RecyclerAdapterRemoteDirectories(Context context, ArrayList directoryList, int ressource) + { + this.context = context; + this.ressource = ressource; + this.directoryList = directoryList; + } + + + //------------RecyclerViewAdapter Methods------------ + + @NonNull + @Override + public DirectoriesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) + { + View view = LayoutInflater.from(parent.getContext()).inflate(ressource, parent, false); + return new RecyclerAdapterRemoteDirectories.DirectoriesViewHolder(view); + } + + @Override + public int getItemCount() + { + return directoryList.size(); + } + + + //------------View Holder------------ + + protected static class DirectoriesViewHolder extends RecyclerView.ViewHolder + { + + public TextView nameTextView; + public ArrayList directoryContent; + public ArrayList directoryContentBackup; + public RecyclerView dirContentRecycler; + + public DirectoriesViewHolder(@NonNull View itemView) + { + super(itemView); + directoryContent = new ArrayList<>(); + directoryContentBackup = new ArrayList<>(); // the backup list is needed for the Search/Filter implementation in the RecyclerAdapterRemoteFiles + nameTextView = itemView.findViewById(R.id.dir_name_tv); + dirContentRecycler = itemView.findViewById(R.id.dir_content_recycler); + } + } + + @Override + public void onBindViewHolder(@NonNull final RecyclerAdapterRemoteDirectories.DirectoriesViewHolder directoriesViewHolder, final int position) + { + final RemoteDirectory currentDirectory = this.directoryList.get(position); + + + directoriesViewHolder.nameTextView.setText(currentDirectory.getFilename()); + + LinearLayoutManager recyclerLayoutManager = new LinearLayoutManager(context);//layout manager vor vertical scrolling recycler + recyclerLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + + //The recycler adapter + RecyclerAdapterRemoteFiles latestRecyclerAdapter = new RecyclerAdapterRemoteFiles(context, directoriesViewHolder.directoryContent, directoriesViewHolder.directoryContentBackup, R.layout.recycler_item_horizonal); + + //on button click listener + latestRecyclerAdapter.setOnItemButtonClickListener(new OnRecyclerItemButtonClicklistenner() + { + @Override + public void onButtonClick(int position) + { + Toast.makeText(context, "Download started", Toast.LENGTH_SHORT).show(); + FtpTaskFileDownloading ftpTaskFileDownloading = new FtpTaskFileDownloading(context.getApplicationContext(), currentDirectory.getPath()); + ftpTaskFileDownloading.execute(directoriesViewHolder.directoryContent.get(position)); + } + }); + + + //Putting everything together + directoriesViewHolder.dirContentRecycler.setLayoutManager(recyclerLayoutManager); + directoriesViewHolder.dirContentRecycler.setAdapter(latestRecyclerAdapter); + + restoreFiles(currentDirectory.getPath(), directoriesViewHolder.directoryContent, directoriesViewHolder.directoryContentBackup, latestRecyclerAdapter); + } + + + //------------FTP------------ + + /** + * This method retrieves the content/files for a single Directory from the FTPServer + * + * @param path path of directory + * @param list the list to be filled through the async response + * @param backup the backup list to be filled through the async response + * @param adapter the adapter -to notify when the data changes + */ + private void ftpGetDirectoryContent(final String path, final ArrayList list, final ArrayList backup, final RecyclerAdapterRemoteFiles adapter) + { + FtpTaskFileListing ftpTaskFileListing = new FtpTaskFileListing(context, path, false, new AsyncResponse() + { + @Override + public void getOhdmFiles(ArrayList remoteFiles) + { + if (remoteFiles.size() > 0) + { + Log.i(TAG, "received " + remoteFiles.size() + " files."); + RemoteListsSingleton.getInstance().getDirectoryContents().put(path, remoteFiles); + list.addAll(remoteFiles); + backup.addAll(remoteFiles); + adapter.notifyDataSetChanged(); + } + else // Server directory was empty or server hasn't responded + { + + } + } + + @Override + public void getRemoteDirectories(ArrayList dirs) + { + //No need to be implemented here + } + }); + ftpTaskFileListing.execute(); + } + + + //------------Save/Restore Instance State------------ + + /** + * Checks if the list is persisted in the {@link RemoteListsSingleton} + * if so adds it to the items list and notifies the adapter + *

+ * else it will start the FTP task to download the list from the server + * + * @param path + * @param list + * @param backup + * @param adapter + */ + private void restoreFiles(final String path, final ArrayList list, final ArrayList backup, final RecyclerAdapterRemoteFiles adapter) + { + try + { + if (RemoteListsSingleton.getInstance().getDirectoryContents().get(path).size() != 0) + { + list.clear(); + list.addAll(RemoteListsSingleton.getInstance().getDirectoryContents().get(path)); + backup.clear(); + backup.addAll(list); + adapter.notifyDataSetChanged(); + } + else + { + ftpGetDirectoryContent(path, list, backup, adapter); + } + } + catch (NullPointerException e) + { + ftpGetDirectoryContent(path, list, backup, adapter); + } + + + } + +} \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterRemoteFiles.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterRemoteFiles.java new file mode 100644 index 0000000..4c26770 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterRemoteFiles.java @@ -0,0 +1,225 @@ +package de.htwBerlin.ois.FileStructure; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.TextView; + +import java.util.ArrayList; + +import de.htwBerlin.ois.R; + +import static android.support.constraint.Constraints.TAG; + +/** + * The RecyclerViewAdapter for ohdmFiles (->means files from the FTP server) + * + * @author WilliBölke + */ +public class RecyclerAdapterRemoteFiles extends RecyclerView.Adapter implements Filterable +{ + + //------------Instance Variables------------ + + /** + * This list will be altered when the user searches for maps + */ + private ArrayList ohdmFiles; + /** + * This list will always contain all maps + * Its here as a backup for the mapArrayList + */ + private ArrayList ohdmFilesBackup; + /** + * Resource id for the RecyclerItem layout + */ + private int ressource; + /** + * Context + */ + private Context context; + /** + * The on itemClickListener + */ + private OnItemClickListener onItemClickListener; + + private OnRecyclerItemButtonClicklistenner onButtonClickListener; + + + //------------Constructors------------ + + + /** + * Public constructor + * + * @param context + * @param ohdmFiles + * @param mapArrayListBackup + * @param ressource + */ + public RecyclerAdapterRemoteFiles(Context context, ArrayList ohdmFiles, ArrayList mapArrayListBackup, int ressource) + { + this.context = context; + this.ressource = ressource; + this.ohdmFiles = ohdmFiles; + this.ohdmFilesBackup = mapArrayListBackup; + } + + + //------------RecyclerViewAdapter Methods------------ + + + @Override + public int getItemCount() + { + return ohdmFiles.size(); + } + + + //------------OnClickListener------------ + + + /** + * Setter for the implemented onItemClick method + * + * @param listener + */ + public void setOnItemClickListener(RecyclerAdapterRemoteFiles.OnItemClickListener listener) + { + this.onItemClickListener = listener; + } + + public void setOnItemButtonClickListener(OnRecyclerItemButtonClicklistenner listener) + { + this.onButtonClickListener = listener; + } + + /** + * An interface to define the + * onItemClick method + *

+ * can be implemented and set as on itemClickListener through the + * {@link this#setOnItemClickListener} method + */ + public interface OnItemClickListener + { + void onItemClick(int position); + } + + + //------------Filter (Name)------------ + + @Override + public Filter getFilter() + { + return nameFilter; + } + + private Filter nameFilter = new Filter() + { + @Override + protected FilterResults performFiltering(CharSequence constraint) + { + ArrayList filteredList = new ArrayList<>(); + Log.e(TAG, "Size--" + ohdmFilesBackup.size()); + if (constraint == null || constraint.length() == 0) + { + filteredList.addAll(ohdmFilesBackup); + } + else + { + String filterPattern = constraint.toString().toLowerCase().trim(); + for (RemoteFile map : ohdmFilesBackup) + { + if (map.getFilename().toLowerCase().trim().contains(filterPattern)) + { + filteredList.add(map); + } + } + } + FilterResults results = new FilterResults(); + results.values = filteredList; + return results; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) + { + ohdmFiles.clear(); + ohdmFiles.addAll((ArrayList) results.values); + notifyDataSetChanged(); + } + }; + + + //------------View Holder------------ + + @NonNull + @Override + public OhdmFileViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) + { + View view = LayoutInflater.from(parent.getContext()).inflate(ressource, parent, false); + return new RecyclerAdapterRemoteFiles.OhdmFileViewHolder(view, this.onItemClickListener); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerAdapterRemoteFiles.OhdmFileViewHolder ohdmFileViewHolder, final int position) + { + RemoteFile currentOhdmFile = this.ohdmFiles.get(position); + String name = currentOhdmFile.getFilename(); + name = name.replace(".map", ""); + ohdmFileViewHolder.nameTextView.setText(name); + ohdmFileViewHolder.sizeTextView.setText((int) (double) (currentOhdmFile.getFileSize() / 1024) + " KB"); + ohdmFileViewHolder.dateTextView.setText(currentOhdmFile.getCreationDate()); + ohdmFileViewHolder.downloadbutton.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + onButtonClickListener.onButtonClick(position); + } + }); + } + + protected static class OhdmFileViewHolder extends RecyclerView.ViewHolder + { + + public TextView nameTextView; + public TextView sizeTextView; + public TextView dateTextView; + public Button downloadbutton; + + public OhdmFileViewHolder(@NonNull View itemView, final RecyclerAdapterRemoteFiles.OnItemClickListener listener) + { + super(itemView); + sizeTextView = itemView.findViewById(R.id.map_size_tv); + nameTextView = itemView.findViewById(R.id.map_name_tv); + dateTextView = itemView.findViewById(R.id.date_of_creation_tv); + downloadbutton = itemView.findViewById(R.id.download_button); + downloadbutton.setVisibility(View.VISIBLE); + + itemView.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + if (listener != null) + { + int position = getAdapterPosition(); + if (position != RecyclerView.NO_POSITION) + { + listener.onItemClick(position); + } + } + } + }); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerViewItemSwipeGestures.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterSwipeGestures.java similarity index 66% rename from app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerViewItemSwipeGestures.java rename to app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterSwipeGestures.java index c7accb6..4d3dc0b 100644 --- a/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerViewItemSwipeGestures.java +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/RecyclerAdapterSwipeGestures.java @@ -9,46 +9,74 @@ import android.view.View; -public class RecyclerViewItemSwipeGestures extends ItemTouchHelper.SimpleCallback +public class RecyclerAdapterSwipeGestures extends ItemTouchHelper.SimpleCallback { + + //------------Instance Variables------------ + private final ColorDrawable redBackground; private final ColorDrawable greenBackground; - private LeftSwipeCallback leftSwipeCallback; - private RightSwipeCallback rightSwipeCallback; - private OhdmFileRecyclerAdapter mAdapter; + private SwipeCallbackLeft swipeCallbackLeft; + private SwipeCallbackRight swipeCallbackRight; + private RecyclerView.Adapter mAdapter; private ColorDrawable actualIColor; - public RecyclerViewItemSwipeGestures(OhdmFileRecyclerAdapter adapter, LeftSwipeCallback onLeftSwipe) + + //------------Constructors------------ + + /** + * Public Constructor to just implement the LeftSwipe + * + * @param adapter + * @param onLeftSwipe + */ + public RecyclerAdapterSwipeGestures(RecyclerView.Adapter adapter, SwipeCallbackLeft onLeftSwipe) { super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); mAdapter = adapter; actualIColor = new ColorDrawable(Color.GREEN); redBackground = new ColorDrawable(Color.RED); greenBackground = new ColorDrawable(Color.GREEN); - this.leftSwipeCallback = onLeftSwipe; + this.swipeCallbackLeft = onLeftSwipe; } - public RecyclerViewItemSwipeGestures(OhdmFileRecyclerAdapter adapter, RightSwipeCallback onRightSwipe) + /** + * Public Constructor to just implement the RightSwipe + * + * @param adapter + * @param onRightSwipe + */ + public RecyclerAdapterSwipeGestures(RecyclerView.Adapter adapter, SwipeCallbackRight onRightSwipe) { super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); mAdapter = adapter; actualIColor = new ColorDrawable(Color.GREEN); redBackground = new ColorDrawable(Color.RED); greenBackground = new ColorDrawable(Color.GREEN); - this.rightSwipeCallback = onRightSwipe; + this.swipeCallbackRight = onRightSwipe; } - public RecyclerViewItemSwipeGestures(OhdmFileRecyclerAdapter adapter, RightSwipeCallback onRightSwipe, LeftSwipeCallback onLeftSwipe) + + /** + * Public Constructor to implement both swipe directions + * + * @param adapter + * @param onLeftSwipe + */ + public RecyclerAdapterSwipeGestures(RecyclerView.Adapter adapter, SwipeCallbackRight onRightSwipe, SwipeCallbackLeft onLeftSwipe) { super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); mAdapter = adapter; actualIColor = new ColorDrawable(Color.GREEN); redBackground = new ColorDrawable(Color.RED); greenBackground = new ColorDrawable(Color.GREEN); - this.rightSwipeCallback = onRightSwipe; - this.leftSwipeCallback = onLeftSwipe; + this.swipeCallbackRight = onRightSwipe; + this.swipeCallbackLeft = onLeftSwipe; } + + //------------ItemTouchHelper Methods------------ + @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) { @@ -60,18 +88,18 @@ public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { int position = viewHolder.getAdapterPosition(); - if (leftSwipeCallback != null) + if (swipeCallbackLeft != null) { if (direction == ItemTouchHelper.LEFT) { - this.leftSwipeCallback.onLeftSwipe(position); + this.swipeCallbackLeft.onLeftSwipe(position); } } - if (rightSwipeCallback != null) + if (swipeCallbackRight != null) { if (direction == ItemTouchHelper.RIGHT) { - this.rightSwipeCallback.onRightSwipe(position); + this.swipeCallbackRight.onRightSwipe(position); } } @@ -109,5 +137,4 @@ else if (dX < 0) super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } - -} \ No newline at end of file +} diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteDirectory.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteDirectory.java new file mode 100644 index 0000000..ddb24f0 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteDirectory.java @@ -0,0 +1,71 @@ +package de.htwBerlin.ois.FileStructure; + +import java.io.Serializable; + +/** + * Class do describe a directory from the FTP Server + * + * @author WilliBoelke + */ +public class RemoteDirectory implements Serializable +{ + + //------------Instance Variables------------ + + private String filename; + private String path; + private String creationDate; + + + //------------Constructors------------ + + public RemoteDirectory(String path, String creationDate) + { + this.filename = path.replace("_", " "); + this.path = path; + this.creationDate = creationDate; + } + + + //------------Setter------------ + + public String getFilename() + { + return filename; + } + + public void setFilename(String filename) + { + this.filename = filename; + } + + public String getPath() + { + return path; + } + + + //------------Getter------------ + + public void setPath(String path) + { + this.path = path; + } + + public String getCreationDate() + { + return creationDate; + } + + public void setCreationDate(String creationDate) + { + this.creationDate = creationDate; + } + + + @Override + public String toString() + { + return "RemoteDirectory{" + "filename='" + filename + '\'' + ", creationDate='" + creationDate + '\'' + ", path=" + path + '}'; + } +} \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFile.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteFile.java similarity index 87% rename from app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFile.java rename to app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteFile.java index 777ef1f..3f5f18b 100644 --- a/app/src/main/java/de/htwBerlin/ois/FileStructure/OhdmFile.java +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteFile.java @@ -1,6 +1,8 @@ package de.htwBerlin.ois.FileStructure; -public class OhdmFile +import java.io.Serializable; + +public class RemoteFile implements Serializable { private String filename; @@ -8,7 +10,7 @@ public class OhdmFile private String creationDate; private boolean isDownloaded; - public OhdmFile(String filename, Long fileSize, String creationDate, boolean isDownloaded) + public RemoteFile(String filename, Long fileSize, String creationDate, boolean isDownloaded) { this.filename = filename; this.fileSize = fileSize; diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteListsSingleton.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteListsSingleton.java new file mode 100644 index 0000000..f5ce620 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/RemoteListsSingleton.java @@ -0,0 +1,83 @@ +package de.htwBerlin.ois.FileStructure; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * this singleton is used to store the lists + * from the {@link de.htwBerlin.ois.Fragments.FragmentDownloadCenterAll} + * and {@link de.htwBerlin.ois.Fragments.FragmentDownloadCenterCategories} + * at runtime. + * to minimize server requests + */ +public class RemoteListsSingleton +{ + + private static ArrayList allMaps; + private static ArrayList latestMaps; + private static ArrayList directories; + private static HashMap> directoryContents; + private static RemoteListsSingleton instance = null; + + private RemoteListsSingleton() + { + + } + + public static RemoteListsSingleton getInstance() + { + if (instance == null) + { + instance = new RemoteListsSingleton(); + latestMaps = new ArrayList<>(); + allMaps = new ArrayList<>(); + directories = new ArrayList<>(); + directoryContents = new HashMap<>(); + } + return instance; + } + + public ArrayList getAllMaps() + { + return allMaps; + } + + public void setAllMaps(ArrayList allMaps) + { + RemoteListsSingleton.allMaps.clear(); + RemoteListsSingleton.allMaps = allMaps; + } + + public ArrayList getLatestMaps() + { + return latestMaps; + } + + public void setLatestMaps(ArrayList latestMaps) + { + RemoteListsSingleton.latestMaps.clear(); + RemoteListsSingleton.latestMaps = latestMaps; + } + + public ArrayList getDirectories() + { + return directories; + } + + public void setDirectories(ArrayList directories) + { + RemoteListsSingleton.directories.clear(); + RemoteListsSingleton.directories = directories; + } + + public HashMap> getDirectoryContents() + { + return directoryContents; + } + + public void setDirectoryContents(HashMap> directoryContents) + { + RemoteListsSingleton.directoryContents.clear(); + RemoteListsSingleton.directoryContents = directoryContents; + } +} diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/RightSwipeCallback.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/RightSwipeCallback.java deleted file mode 100644 index 52597d5..0000000 --- a/app/src/main/java/de/htwBerlin/ois/FileStructure/RightSwipeCallback.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.htwBerlin.ois.FileStructure; - -public interface RightSwipeCallback -{ - void onRightSwipe(int position); - -} diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/LeftSwipeCallback.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/SwipeCallbackLeft.java similarity index 69% rename from app/src/main/java/de/htwBerlin/ois/FileStructure/LeftSwipeCallback.java rename to app/src/main/java/de/htwBerlin/ois/FileStructure/SwipeCallbackLeft.java index 7beed13..38b4a16 100644 --- a/app/src/main/java/de/htwBerlin/ois/FileStructure/LeftSwipeCallback.java +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/SwipeCallbackLeft.java @@ -1,6 +1,6 @@ package de.htwBerlin.ois.FileStructure; -public interface LeftSwipeCallback +public interface SwipeCallbackLeft { void onLeftSwipe(int position); } diff --git a/app/src/main/java/de/htwBerlin/ois/FileStructure/SwipeCallbackRight.java b/app/src/main/java/de/htwBerlin/ois/FileStructure/SwipeCallbackRight.java new file mode 100644 index 0000000..7475a55 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/FileStructure/SwipeCallbackRight.java @@ -0,0 +1,7 @@ +package de.htwBerlin.ois.FileStructure; + +public interface SwipeCallbackRight +{ + void onRightSwipe(int position); + +} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/AboutFragment.java b/app/src/main/java/de/htwBerlin/ois/Fragments/AboutFragment.java deleted file mode 100644 index 5d0a360..0000000 --- a/app/src/main/java/de/htwBerlin/ois/Fragments/AboutFragment.java +++ /dev/null @@ -1,44 +0,0 @@ -package de.htwBerlin.ois.Fragments; - -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import de.htwBerlin.ois.R; - -/** - * Fragment showing about OHDM information - * Can be reached by the user via the Toolbars 3-dod menu - */ -public class AboutFragment extends Fragment -{ - /** - * Fragment ID used to identify the fragment - * (for example by putting the ID into the Intent extra ) - */ - public static String ID = "About"; - - /** - * Log tag - */ - private final String TAG = this.getClass().getSimpleName(); - /** - * Fragments view - */ - private View view; - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) - { - //inflating the view - view = inflater.inflate(R.layout.fragment_about, container, false); - return view; - } - - -} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentDownloadCenterAll.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentDownloadCenterAll.java new file mode 100644 index 0000000..34918a6 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentDownloadCenterAll.java @@ -0,0 +1,537 @@ +package de.htwBerlin.ois.Fragments; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.SearchView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; + +import de.htwBerlin.ois.FileStructure.OnRecyclerItemButtonClicklistenner; +import de.htwBerlin.ois.FileStructure.RecyclerAdapterRemoteFiles; +import de.htwBerlin.ois.FileStructure.RemoteDirectory; +import de.htwBerlin.ois.FileStructure.RemoteFile; +import de.htwBerlin.ois.FileStructure.RemoteListsSingleton; +import de.htwBerlin.ois.R; +import de.htwBerlin.ois.ServerCommunication.AsyncResponse; +import de.htwBerlin.ois.ServerCommunication.FtpTaskFileDownloading; +import de.htwBerlin.ois.ServerCommunication.FtpTaskFileListing; + +import static de.htwBerlin.ois.ServerCommunication.Variables.MOST_RECENT_PATH; + +/** + * This Activity represents a small map file download center + * + * @author WilliBoelke + */ +public class FragmentDownloadCenterAll extends FragmentWithServerConnection +{ + + //------------Instance Variables------------ + + /** + * Fragment ID used to identify the fragment + * (for example by putting the ID into the Intent extra ) + */ + public static String ID = "MapDownload"; + /** + * Log tag + */ + private final String TAG = this.getClass().getSimpleName(); + /** + * ArrayList of OHDMFiles, to be displayed in the RecyclerView + * This list will be altered when the user uses the search function + */ + private ArrayList allOhdmFiles; + /** + * ArrayList of RemoteFiles (.map), + * This list will serve as backup when the + * ohdmFiles list was altered + */ + private ArrayList allOhdmFilesBackup; + private ArrayList latestOhdmFiles; + private ArrayList latestOhdmFilesBackup; + private RecyclerAdapterRemoteFiles allRecyclerAdapter; + private RecyclerAdapterRemoteFiles latestRecyclerAdapter; + /** + * The recyclerView + */ + private RecyclerView allMapsRecyclerView; + private RecyclerView latestMapsRecyclerView; + + + //------------Static Variables------------ + /** + * The view + */ + private View view; + + + //------------Activity/Fragment Lifecycle------------ + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) + { + // inflating the view + view = inflater.inflate(R.layout.fragment_map_download_all, container, false); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) + { + super.onActivityCreated(savedInstanceState); + allOhdmFiles = new ArrayList<>(); + allOhdmFilesBackup = new ArrayList<>(); + latestOhdmFiles = new ArrayList<>(); + latestOhdmFilesBackup = new ArrayList<>(); + setHasOptionsMenu(true); + this.setupAllMapsRecyclerView(); + this.setupLatestMapsRecyclerView(); + this.setupLatestSearchView(); + this.setupAllSearchView(); + this.changeVisibilities(STATE_CONNECTING); + this.setupFAB(); + this.setupSwipeToRefresh(); + this.setupButtonToCategories(); + this.restoreFiles(); + } + + @Override + public void onStart() + { + super.onStart(); + } + + @Override + public void onResume() + { + super.onResume(); + } + + @Override + public void onStop() + { + super.onStop(); + storeFiles(); + } + + @Override + public void onDestroy() + { + super.onDestroy(); + } + + + //------------Setup Views------------ + + /** + * Setup the FloatingActionButton to replace this fragment with the + * {@link FragmentrequestNewMap} + */ + private void setupFAB() + { + FloatingActionButton requestNewMapFab = view.findViewById(R.id.request_new_map_fab); + requestNewMapFab.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentrequestNewMap()).addToBackStack(null).commit(); + } + }); + } + + /** + * Setup the AllMaps RecyclerView : + *

+ * Setup Swipe gestures + * Setup onItemClickListener + */ + private void setupAllMapsRecyclerView() + { + allMapsRecyclerView = view.findViewById(R.id.available_maps_recycler); + + allMapsRecyclerView.setVisibility(View.INVISIBLE); // is invisible till the server responds + + RecyclerView.LayoutManager recyclerLayoutManager = new LinearLayoutManager(this.getContext());//layout manager vor vertical scrolling recycler + + //The recycler adapter + allRecyclerAdapter = new RecyclerAdapterRemoteFiles(getActivity().getApplicationContext(), allOhdmFiles, allOhdmFilesBackup, R.layout.recycler_item_vertical); + + //OnClickListener for the button inside the RecyclerView item layout + allRecyclerAdapter.setOnItemButtonClickListener(new OnRecyclerItemButtonClicklistenner() + { + @Override + public void onButtonClick(int position) + { + Toast.makeText(getContext(), "Download started", Toast.LENGTH_SHORT).show(); + FtpTaskFileDownloading ftpTaskFileDownloading = new FtpTaskFileDownloading(getActivity().getApplicationContext(), ""); + ftpTaskFileDownloading.execute(allOhdmFiles.get(position)); + allRecyclerAdapter.notifyDataSetChanged(); + } + }); + allMapsRecyclerView.setLayoutManager(recyclerLayoutManager); + allMapsRecyclerView.setAdapter(allRecyclerAdapter); + } + + /** + * Setup the Latest RecyclerView : + *

+ * Setup Swipe gestures + * Setup onItemClickListener + */ + private void setupLatestMapsRecyclerView() + { + latestMapsRecyclerView = view.findViewById(R.id.latest_maps_recycler); + + latestMapsRecyclerView.setVisibility(View.INVISIBLE); // is invisible till the server responds + + LinearLayoutManager recyclerLayoutManager = new LinearLayoutManager(this.getContext());//layout manager vor vertical scrolling recycler + recyclerLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + + //The recycler adapter + latestRecyclerAdapter = new RecyclerAdapterRemoteFiles(getActivity().getApplicationContext(), latestOhdmFiles, latestOhdmFilesBackup, R.layout.recycler_item_horizonal); + + latestRecyclerAdapter.setOnItemButtonClickListener(new OnRecyclerItemButtonClicklistenner() + { + @Override + public void onButtonClick(int position) + { + Toast.makeText(getContext(), "Download started", Toast.LENGTH_SHORT).show(); + FtpTaskFileDownloading ftpTaskFileDownloading = new FtpTaskFileDownloading(getActivity().getApplicationContext(), MOST_RECENT_PATH); + ftpTaskFileDownloading.execute(latestOhdmFiles.get(position)); + allRecyclerAdapter.notifyDataSetChanged(); + } + }); + + //Putting everything together + latestMapsRecyclerView.setLayoutManager(recyclerLayoutManager); + latestMapsRecyclerView.setAdapter(latestRecyclerAdapter); + } + + private void setupButtonToCategories() + { + Button button = view.findViewById(R.id.button_categories); + button.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentDownloadCenterCategories()).addToBackStack(null).commit(); + } + }); + } + + /** + * Setup the search view to use the nameFilter + * implemented in {@link RecyclerAdapterRemoteFiles} + */ + private void setupGeneralSearchView(SearchView searchView) + { + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() + { + @Override + public boolean onQueryTextSubmit(String query) + { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) + { + allRecyclerAdapter.getFilter().filter(newText); + latestRecyclerAdapter.getFilter().filter(newText); + return false; + } + }); + } + + /** + * Setup the search view to use the nameFilter + * only in the LatestMapsRecycler + * implemented in {@link RecyclerAdapterRemoteFiles} + */ + private void setupAllSearchView() + { + SearchView searchView = view.findViewById(R.id.all_sv); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() + { + @Override + public boolean onQueryTextSubmit(String query) + { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) + { + allRecyclerAdapter.getFilter().filter(newText); + return false; + } + }); + } + + /** + * Setup the search view to use the nameFilter + * only in the LatestMapsRecycler + * implemented in {@link RecyclerAdapterRemoteFiles} + */ + private void setupLatestSearchView() + { + SearchView searchView = view.findViewById(R.id.latest_sv); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() + { + @Override + public boolean onQueryTextSubmit(String query) + { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) + { + latestRecyclerAdapter.getFilter().filter(newText); + return false; + } + }); + } + + + //------------FTP Listing------------ + + + /** + * Initializes an FTP Request to list all files -> {@link FtpTaskFileListing} + *

+ * Implements the {@link AsyncResponse} interface to add the retrieved + * files to both the ohdmFiles and the ohdmFilesBackup list + */ + private void FTPListAllFiles() + { + FtpTaskFileListing ftpTaskFileListing = new FtpTaskFileListing(getActivity(), "", true, new AsyncResponse() + { + @Override + public void getOhdmFiles(ArrayList remoteFiles) + { + if (remoteFiles.size() > 0) + { + Log.i(TAG, "received " + remoteFiles.size() + " files."); + + allOhdmFiles.clear(); + allOhdmFilesBackup.clear(); + allOhdmFiles.addAll(remoteFiles); + allOhdmFilesBackup.addAll(remoteFiles); + allRecyclerAdapter.notifyDataSetChanged(); + latestRecyclerAdapter.notifyDataSetChanged(); + changeVisibilities(STATE_CONNECTED); + } + else // Server directory was empty or server hasn't responded + { + view.findViewById(R.id.connecting_pb).setVisibility(View.INVISIBLE); + TextView tv = view.findViewById(R.id.connecting_tv); + tv.setText("Connection failed, try again later"); + } + } + + @Override + public void getRemoteDirectories(ArrayList dirs) + { + + } + }); + ftpTaskFileListing.execute(); + } + + /** + * Initializes an FTP Request to list all files -> {@link FtpTaskFileListing} + *

+ * Implements the {@link AsyncResponse} interface to add the retrieved + * files to both the ohdmFiles and the ohdmFilesBackup list + */ + private void FTPListLatestFiles() + { + FtpTaskFileListing ftpTaskFileListing = new FtpTaskFileListing(getActivity(), MOST_RECENT_PATH, false, new AsyncResponse() + { + @Override + public void getOhdmFiles(ArrayList remoteFiles) + { + if (remoteFiles.size() > 0) + { + Log.i(TAG, "received " + remoteFiles.size() + " files."); + + latestOhdmFilesBackup.clear(); + latestOhdmFiles.clear(); + latestOhdmFiles.addAll(remoteFiles); + latestOhdmFilesBackup.addAll(remoteFiles); + latestRecyclerAdapter.notifyDataSetChanged(); + changeVisibilities(STATE_CONNECTED); + } + else // Server directory was empty or server hasn't responded + { + changeVisibilities(STATE_NO_CONNECTION); + } + } + + @Override + public void getRemoteDirectories(ArrayList dirs) + { + + } + }); + ftpTaskFileListing.execute(); + } + + + //------------Toolbar Menu------------ + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.actionbar_menu, menu); + MenuItem searchItem = menu.findItem(R.id.ab_menu_search).setVisible(true); + setupGeneralSearchView((SearchView) searchItem.getActionView()); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.ab_menu_about: + //no implemented here, + return false; + case R.id.ab_menu_faq: + //no implemented here, + return false; + case R.id.ab_menu_settings: + //no implemented here + return false; + case R.id.ab_menu_search: + + } + return super.onOptionsItemSelected(item); + } + + + //------------Swipe To Refresh------------ + + private void setupSwipeToRefresh() + { + final SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_to_refresh); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() + { + @Override + public void onRefresh() + { + swipeRefreshLayout.setRefreshing(true); + changeVisibilities(STATE_CONNECTING); + FTPListAllFiles(); + FTPListLatestFiles(); + swipeRefreshLayout.setRefreshing(false); + } + }); + } + + + //------------Save/Restore Instance State------------ + + private void storeFiles() + { + RemoteListsSingleton.getInstance().setAllMaps(this.allOhdmFilesBackup); + RemoteListsSingleton.getInstance().setLatestMaps(this.latestOhdmFilesBackup); + } + + private void restoreFiles() + { + if (RemoteListsSingleton.getInstance().getAllMaps().size() != 0) + { + allOhdmFiles.clear(); + allOhdmFilesBackup.clear(); + this.allOhdmFiles.addAll(RemoteListsSingleton.getInstance().getAllMaps()); + this.allOhdmFilesBackup.addAll(allOhdmFiles); + changeVisibilities(STATE_CONNECTED); + allRecyclerAdapter.notifyDataSetChanged(); + } + else + { + FTPListAllFiles(); + } + if (RemoteListsSingleton.getInstance().getLatestMaps().size() != 0) + { + latestOhdmFilesBackup.clear(); + latestOhdmFiles.clear(); + this.latestOhdmFiles.addAll(RemoteListsSingleton.getInstance().getLatestMaps()); + this.latestOhdmFilesBackup.addAll(latestOhdmFiles); + changeVisibilities(STATE_CONNECTED); + latestRecyclerAdapter.notifyDataSetChanged(); + } + else + { + FTPListLatestFiles(); + } + } + + + //------------FragmentWithServerConnection Methods------------ + + @Override + protected void onNoConnection() + { + view.findViewById(R.id.connecting_tv).setVisibility(View.VISIBLE); + ((TextView) view.findViewById(R.id.connecting_tv)).setText("Coudnt make connection"); + + view.findViewById(R.id.connecting_pb).setVisibility(View.INVISIBLE); + view.findViewById(R.id.all_tv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.all_sv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.latest_sv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.lates_tv).setVisibility(View.INVISIBLE); + allMapsRecyclerView.setVisibility(View.INVISIBLE); + latestMapsRecyclerView.setVisibility(View.INVISIBLE); + } + + @Override + protected void onConnecting() + { + view.findViewById(R.id.connecting_tv).setVisibility(View.VISIBLE); + view.findViewById(R.id.connecting_pb).setVisibility(View.VISIBLE); + + view.findViewById(R.id.all_sv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.all_tv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.latest_sv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.lates_tv).setVisibility(View.INVISIBLE); + allMapsRecyclerView.setVisibility(View.INVISIBLE); + latestMapsRecyclerView.setVisibility(View.INVISIBLE); + } + + @Override + protected void onConnected() + { + view.findViewById(R.id.connecting_tv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.connecting_pb).setVisibility(View.INVISIBLE); + + view.findViewById(R.id.all_sv).setVisibility(View.VISIBLE); + view.findViewById(R.id.all_tv).setVisibility(View.VISIBLE); + view.findViewById(R.id.latest_sv).setVisibility(View.VISIBLE); + view.findViewById(R.id.lates_tv).setVisibility(View.VISIBLE); + allMapsRecyclerView.setVisibility(View.VISIBLE); + latestMapsRecyclerView.setVisibility(View.VISIBLE); + } + +} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentDownloadCenterCategories.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentDownloadCenterCategories.java new file mode 100644 index 0000000..2db5486 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentDownloadCenterCategories.java @@ -0,0 +1,241 @@ +package de.htwBerlin.ois.Fragments; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import java.util.ArrayList; + +import de.htwBerlin.ois.FileStructure.RecyclerAdapterRemoteDirectories; +import de.htwBerlin.ois.FileStructure.RemoteDirectory; +import de.htwBerlin.ois.FileStructure.RemoteFile; +import de.htwBerlin.ois.FileStructure.RemoteListsSingleton; +import de.htwBerlin.ois.R; +import de.htwBerlin.ois.ServerCommunication.AsyncResponse; +import de.htwBerlin.ois.ServerCommunication.FtpTaskDirListing; + + +public class FragmentDownloadCenterCategories extends FragmentWithServerConnection +{ + + //------------Instance Variables------------ + + /** + * Log tag + */ + private final String TAG = getClass().getSimpleName(); + /** + * The View + */ + private View view; + /** + * The list of directories from the FTP server + */ + private ArrayList directoryList; + /** + * The RecyclerAdapter + */ + private RecyclerAdapterRemoteDirectories recyclerViewAdapter; + + + //------------Activity/Fragment Lifecycle------------ + /** + * Code to be executed after the FtpTaskDirListing finished + */ + private AsyncResponse asyncResponseDirListing = new AsyncResponse() + { + @Override + public void getOhdmFiles(ArrayList remoteFiles) + { + + } + + @Override + public void getRemoteDirectories(ArrayList dirs) + { + if (dirs.size() != 0) + { + directoryList.clear(); + directoryList.addAll(dirs); + recyclerViewAdapter.notifyDataSetChanged(); + changeVisibilities(STATE_CONNECTED); + } + else + { + changeVisibilities(STATE_NO_CONNECTION); + } + + } + }; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) + { + // inflating the view + view = inflater.inflate(R.layout.fragment_map_download_categories, container, false); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) + { + super.onActivityCreated(savedInstanceState); + directoryList = new ArrayList<>(); + setHasOptionsMenu(true); + this.setupDirRecycler(); + this.changeVisibilities(STATE_CONNECTING); + this.setupToAllMapsButton(); + this.setupFAB(); + this.restoreFiles(); + this.setupSwipeToRefresh(); + } + + //------------Setup Views------------ + + @Override + public void onPause() + { + super.onPause(); + this.storeFiles(); + } + + /** + * Setup for the directory recycler. + *

+ * Each RecyclerItem represents a directory from the server, + * Each RecyclerItem contains another recycler displaying the content of + * he displayed Directory + */ + private void setupDirRecycler() + { + RecyclerView dirRecycler = view.findViewById(R.id.directory_recycler); + + LinearLayoutManager recyclerLayoutManager = new LinearLayoutManager(this.getContext()); + + //The recycler adapter + recyclerViewAdapter = new RecyclerAdapterRemoteDirectories(getActivity().getApplicationContext(), directoryList, R.layout.recycler_item_directory); + + + //Putting everything together + dirRecycler.setLayoutManager(recyclerLayoutManager); + dirRecycler.setAdapter(recyclerViewAdapter); + } + + private void setupToAllMapsButton() + { + Button button = view.findViewById(R.id.button_all_maps); + button.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentDownloadCenterAll()).addToBackStack(null).commit(); + } + }); + } + + private void setupSwipeToRefresh() + { + final SwipeRefreshLayout swipeToRefreshLayout = view.findViewById(R.id.swipe_to_refresh); + swipeToRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() + { + @Override + public void onRefresh() + { + swipeToRefreshLayout.setRefreshing(true); + changeVisibilities(STATE_CONNECTING); + FTPGetDirectories(); + setupDirRecycler(); + swipeToRefreshLayout.setRefreshing(false); + } + }); + } + + /** + * Setup the FloatingActionButton to replace this fragment with the + * {@link FragmentrequestNewMap} + */ + private void setupFAB() + { + FloatingActionButton requestNewMapFab = view.findViewById(R.id.request_new_map_fab); + requestNewMapFab.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentrequestNewMap()).addToBackStack(null).commit(); + } + }); + } + + private void FTPGetDirectories() + { + FtpTaskDirListing dirListing = new FtpTaskDirListing(getActivity(), "", asyncResponseDirListing); + dirListing.execute(); + } + + //------------Save/Restore Instance State------------ + + private void storeFiles() + { + RemoteListsSingleton.getInstance().setDirectories(this.directoryList); + } + + private void restoreFiles() + { + if (RemoteListsSingleton.getInstance().getDirectories().size() != 0) + { + this.directoryList.clear(); + this.directoryList.addAll(RemoteListsSingleton.getInstance().getDirectories()); + this.changeVisibilities(STATE_CONNECTED); + } + else + { + FTPGetDirectories(); + recyclerViewAdapter.notifyDataSetChanged(); + } + + } + + + //------------Fragment With Server Connection Methods------------ + + @Override + protected void onNoConnection() + { + view.findViewById(R.id.connecting_tv).setVisibility(View.VISIBLE); + ((TextView) view.findViewById(R.id.connecting_tv)).setText("Coudnt make connection"); + + view.findViewById(R.id.connecting_pb).setVisibility(View.INVISIBLE); + view.findViewById(R.id.directory_recycler).setVisibility(View.INVISIBLE); + } + + @Override + protected void onConnecting() + { + view.findViewById(R.id.connecting_tv).setVisibility(View.VISIBLE); + view.findViewById(R.id.connecting_pb).setVisibility(View.VISIBLE); + + view.findViewById(R.id.directory_recycler).setVisibility(View.INVISIBLE); + } + + @Override + protected void onConnected() + { + view.findViewById(R.id.connecting_tv).setVisibility(View.INVISIBLE); + view.findViewById(R.id.connecting_pb).setVisibility(View.INVISIBLE); + + view.findViewById(R.id.directory_recycler).setVisibility(View.VISIBLE); + + } +} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/FAQFragment.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentFAQ.java similarity index 51% rename from app/src/main/java/de/htwBerlin/ois/Fragments/FAQFragment.java rename to app/src/main/java/de/htwBerlin/ois/Fragments/FragmentFAQ.java index c36e78c..f5fadc9 100644 --- a/app/src/main/java/de/htwBerlin/ois/Fragments/FAQFragment.java +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentFAQ.java @@ -7,6 +7,9 @@ import android.support.annotation.RequiresApi; import android.support.v4.app.Fragment; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -15,16 +18,25 @@ /** * @author WilliBoelke */ -public class FAQFragment extends Fragment +public class FragmentFAQ extends Fragment { + + //------------Instance Variables------------ + /** * Fragment ID used to identify the fragment * (for example by putting the ID into the Intent extra ) */ public static String ID = "FAQ"; private final String TAG = this.getClass().getSimpleName(); + + + //------------Static Variables------------ private View view; + + //------------Activity/Fragment Lifecycle------------ + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) @@ -39,6 +51,37 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(true); + } + + + //------------Toolbar Menu------------ + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.actionbar_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.ab_menu_about: + //no implemented here, + return false; + case R.id.ab_menu_faq: + //no implemented here, + return false; + case R.id.ab_menu_settings: + //no implemented here + return false; + case R.id.ab_menu_search: + + } + return super.onOptionsItemSelected(item); } + } \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentHome.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentHome.java new file mode 100644 index 0000000..76fc6b5 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentHome.java @@ -0,0 +1,256 @@ +package de.htwBerlin.ois.Fragments; + +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; +import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.SearchView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import java.io.File; +import java.util.ArrayList; + +import de.htwBerlin.ois.FileStructure.MapFileSingleton; +import de.htwBerlin.ois.FileStructure.RecyclerAdapterLocalFiles; +import de.htwBerlin.ois.FileStructure.RecyclerAdapterSwipeGestures; +import de.htwBerlin.ois.FileStructure.SwipeCallbackLeft; +import de.htwBerlin.ois.FileStructure.SwipeCallbackRight; +import de.htwBerlin.ois.MainActivity.MainActivity; +import de.htwBerlin.ois.R; + +/** + * Represents the HOME Tab and thus, the starting point for the OHDM Offline Viewer application + * + * @author morelly_t1 + * @author WilliBoelke + */ +public class FragmentHome extends Fragment +{ + + //------------Instance Variables------------ + + /** + * Fragment ID used to identify the fragment + * (for example by putting the ID into the Intent extra ) + */ + public static String ID = "Home"; + /** + * Log tag + */ + private final String TAG = this.getClass().getSimpleName(); + /** + * Set of the .map files ind the OHDM directory + * Filled in {@link #findMapFiles()} + */ + private ArrayList mapFiles; + /** + * The view + */ + private View view; + /** + * The RecyclerAdapter + */ + private RecyclerAdapterLocalFiles recyclerAdapter; + + + //------------Static Variables------------ + /** + * The RecyclerView + */ + private RecyclerView localMapsRecyclerView; + + + //------------Activity/Fragment Lifecycle------------ + private SwipeCallbackLeft swipeCallbackLeft = new SwipeCallbackLeft() + { + @Override + public void onLeftSwipe(int position) + { + Log.i(TAG, "using " + mapFiles.get(position).getName() + " as mapfile"); + MapFileSingleton mapFile = MapFileSingleton.getInstance(); + mapFile.setFile(mapFiles.get(position)); + recyclerAdapter.notifyDataSetChanged(); + } + }; + private SwipeCallbackRight swipeCallbackRight = new SwipeCallbackRight() + { + @Override + public void onRightSwipe(int position) + { + mapFiles.get(position).delete(); + mapFiles.remove(position); + recyclerAdapter.notifyDataSetChanged(); + } + }; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) + { + //inflating the view + view = inflater.inflate(R.layout.fragment_home, container, false); + return view; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) + { + super.onActivityCreated(savedInstanceState); + mapFiles = findMapFiles(); + setHasOptionsMenu(true); + setupRecycler(); + } + + + //------------Setup Views------------ + + @Override + public void onStart() + { + super.onStart(); + } + + @Override + public void onResume() + { + super.onResume(); + } + + + //------------Others------------ + + /** + * Scans OHDM Directory for .map Files + * + * @return a set of .map files + */ + private ArrayList findMapFiles() + { + ArrayList maps = new ArrayList<>(); + try + { + for (File mapFile : new File(MainActivity.MAP_FILE_PATH).listFiles()) + { + if (mapFile.getName().endsWith(".map")) + { + Log.i(TAG, "osmfile: " + mapFile.getName()); + maps.add(mapFile); + } + } + } + catch (NullPointerException e) + { + Log.i(TAG, "No map files located."); + } + return maps; + } + + + //------------Toolbar Menu------------ + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.actionbar_menu, menu); + MenuItem searchItem = menu.findItem(R.id.ab_menu_search).setVisible(true); + setupSearchView((SearchView) searchItem.getActionView()); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.ab_menu_about: + //no implemented here, + return false; + case R.id.ab_menu_faq: + //no implemented here, + return false; + case R.id.ab_menu_settings: + //no implemented here + return false; + case R.id.ab_menu_search: + } + return super.onOptionsItemSelected(item); + } + + + //------------Swipe Gestures------------ + + /** + * Setup for the SearchView + */ + private void setupSearchView(SearchView searchView) + { + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() + { + @Override + public boolean onQueryTextSubmit(String query) + { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) + { + try + { + recyclerAdapter.getFilter().filter(newText); + } + catch (NullPointerException e) + { + e.printStackTrace(); + } + return false; + } + }); + + } + + /** + * Setup method for the RecyclerView + */ + private void setupRecycler() + { + localMapsRecyclerView = view.findViewById(R.id.local_maps_recycler); + + if (!mapFiles.isEmpty()) + { + //In case there are files in the local OHDM directory these two will be behind the recycler + view.findViewById(R.id.content_card_home_info).setVisibility(View.INVISIBLE); + view.findViewById(R.id.ohdm_logo_iv).setVisibility(View.INVISIBLE); + + localMapsRecyclerView.setVisibility(View.VISIBLE); + + RecyclerView.LayoutManager recyclerLayoutManager = new LinearLayoutManager(this.getContext()); + recyclerAdapter = new RecyclerAdapterLocalFiles(this.getContext(), mapFiles, R.layout.recycler_item_vertical); + + //The itemTouchhelper for the swipe gestures on the recycler Items + ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new RecyclerAdapterSwipeGestures(recyclerAdapter, this.swipeCallbackRight, this.swipeCallbackLeft)); + + + //Putting everything together + itemTouchHelper.attachToRecyclerView(localMapsRecyclerView); + + + //Putting everything together + localMapsRecyclerView.setLayoutManager(recyclerLayoutManager); + localMapsRecyclerView.setAdapter(recyclerAdapter); + recyclerAdapter.notifyDataSetChanged(); + } + } +} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/NavigationFragment.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentNavigation.java similarity index 78% rename from app/src/main/java/de/htwBerlin/ois/Fragments/NavigationFragment.java rename to app/src/main/java/de/htwBerlin/ois/Fragments/FragmentNavigation.java index 43846bb..c40ab84 100644 --- a/app/src/main/java/de/htwBerlin/ois/Fragments/NavigationFragment.java +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentNavigation.java @@ -5,11 +5,15 @@ import android.location.Location; import android.location.LocationManager; import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; @@ -34,39 +38,39 @@ import static android.content.Context.LOCATION_SERVICE; /** - * Map Activity, which displays the actual Map File + * Fragment to display a the map file + * from {@link MapFileSingleton} + * * @author WilliBoelke */ -public class NavigationFragment extends Fragment +public class FragmentNavigation extends Fragment { + + //------------Instance Variables------------ + /** - * Log tag + * Fragment ID used to identify the fragment + * (for example by putting the ID into the Intent extra ) */ - private final String TAG = this.getClass().getSimpleName(); + public static String ID = "Navigation"; /** - * The MapView (MapsForge) + * Log tag */ - private MapView mapView = null; + private final String TAG = this.getClass().getSimpleName(); /** * The view */ private View view; + + + //------------Static Variables------------ /** - * Fragment ID used to identify the fragment - * (for example by putting the ID into the Intent extra ) - */ - public static String ID = "Navigation"; - /** - * - */ - private FloatingActionButton locateFab; - /** - * Empty Constructor + * The MapView */ - public NavigationFragment() - { - // Required empty public constructor - } + private MapView mapView; + + + //------------Activity/Fragment Lifecycle------------ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) @@ -74,16 +78,25 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa super.onCreate(savedInstanceState); view = inflater.inflate(R.layout.fragment_navigation, container, false); AndroidGraphicFactory.createInstance(getActivity().getApplication()); - setUpLocateFab(); - setUpMap(); + setupLocateFab(); + setupMap(); return view; } + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) + { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(true); + } + + + //------------Setup Views------------ /** * Initializes the mapView */ - private void setUpMap() + private void setupMap() { Log.i(TAG, "setting up map"); mapView = view.findViewById(R.id.map); @@ -117,9 +130,9 @@ private void setUpMap() * On Click for the LocateFAb * Sets the map center to the last know position of the device */ - private void setUpLocateFab() + private void setupLocateFab() { - locateFab = view.findViewById(R.id.locate_fab); + FloatingActionButton locateFab = view.findViewById(R.id.locate_fab); locateFab.setOnClickListener(new View.OnClickListener() { @Override @@ -151,8 +164,12 @@ public void onClick(View v) } + + //------------Others------------ + /** * Gets the last know position of the device from the android LocationManager + * * @return Location of the device */ private Location getLastKnownLocation() @@ -180,4 +197,35 @@ private Location getLastKnownLocation() } return bestLocation; } + + + //------------Toolbar Menu------------ + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.actionbar_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.ab_menu_about: + //no implemented here, + return false; + case R.id.ab_menu_faq: + //no implemented here, + return false; + case R.id.ab_menu_settings: + //no implemented here + return false; + case R.id.ab_menu_search: + + } + return super.onOptionsItemSelected(item); + } + } diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/OptionsFragment.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentOptions.java similarity index 77% rename from app/src/main/java/de/htwBerlin/ois/Fragments/OptionsFragment.java rename to app/src/main/java/de/htwBerlin/ois/Fragments/FragmentOptions.java index f604f77..aae95e3 100644 --- a/app/src/main/java/de/htwBerlin/ois/Fragments/OptionsFragment.java +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentOptions.java @@ -10,6 +10,9 @@ import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.CompoundButton; @@ -27,8 +30,11 @@ * * @author WilliBoelke */ -public class OptionsFragment extends Fragment +public class FragmentOptions extends Fragment { + + //------------Instance Variables------------ + /** * Key to get the DarkMode boolean from the SharedPreferences */ @@ -37,18 +43,21 @@ public class OptionsFragment extends Fragment * SharedPreferences name */ public static final String SETTINGS_SHARED_PREFERENCES = "OHDMViewerSettings"; - private static final int ACCESS_LOCATION_PERMISSION = 34; - private static final int WRITE_STORAGE_PERMISSION = 56; + private static final int REQUEST_CODE_ACCESS_LOCATION_PERMISSION = 34; + + + //------------Static Variables------------ + private static final int REQUEST_CODE_WRITE_STORAGE_PERMISSION = 56; private static final int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124; - /** - * Log tag - */ - private final String TAG = getClass().getSimpleName(); /** * Fragment ID used to identify the fragment * (for example by putting the ID into the Intent extra ) */ public static String ID = "Options"; + /** + * Log tag + */ + private final String TAG = getClass().getSimpleName(); /** * the view */ @@ -57,20 +66,9 @@ public class OptionsFragment extends Fragment * SharedPreferences to quickly store and access user settings */ private SharedPreferences prefs; - /** - * Dark mode toggle - */ - private Switch darkModeToggle; - private Switch allowLocationToggle; - private Switch allowWriteLocalStorageToggle; - /** - * Empty Constructor - */ - public OptionsFragment() - { - // Required empty public constructor - } + + //------------Activity/Fragment Lifecycle------------ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) @@ -84,18 +82,21 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); prefs = getActivity().getApplicationContext().getSharedPreferences(SETTINGS_SHARED_PREFERENCES, 0); - + setHasOptionsMenu(true); this.setUpDarkModeToggle(); this.setupAllowAccessLocationToggle(); this.setupAllowWriteLocalStorageToggle(); } + + //------------Setup Views------------ + /** * Setup the allowWriteLocalStorage Switch */ private void setupAllowWriteLocalStorageToggle() { - allowWriteLocalStorageToggle = view.findViewById(R.id.allow_write_storage_switch); + Switch allowWriteLocalStorageToggle = view.findViewById(R.id.allow_write_storage_switch); if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { allowWriteLocalStorageToggle.setChecked(true); @@ -111,7 +112,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) List permissions = new ArrayList<>(); permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); String[] params = permissions.toArray(new String[permissions.size()]); - requestPermissions(params, WRITE_STORAGE_PERMISSION); + requestPermissions(params, REQUEST_CODE_WRITE_STORAGE_PERMISSION); } else { @@ -126,7 +127,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) */ private void setupAllowAccessLocationToggle() { - allowLocationToggle = view.findViewById(R.id.allow_access_location_switch); + Switch allowLocationToggle = view.findViewById(R.id.allow_access_location_switch); if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { allowLocationToggle.setChecked(true); @@ -142,7 +143,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) List permissions = new ArrayList<>(); permissions.add(Manifest.permission.ACCESS_FINE_LOCATION); String[] params = permissions.toArray(new String[permissions.size()]); - requestPermissions(params, ACCESS_LOCATION_PERMISSION); + requestPermissions(params, REQUEST_CODE_ACCESS_LOCATION_PERMISSION); } else { @@ -160,7 +161,7 @@ private void setUpDarkModeToggle() { Log.v(TAG, "Setup DarkMode toggle"); - darkModeToggle = view.findViewById(R.id.dark_mode_switch); + Switch darkModeToggle = view.findViewById(R.id.dark_mode_switch); //Set the switch to "checked" in chase the darkmode is enabled if (prefs.getBoolean(DARK_MODE, false) == true) @@ -192,28 +193,20 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) }); } - /** - * reloads the MainActivity in order to enable/disable the darkmode - */ - private void reset() - { - Log.v(TAG, "Reset Activity "); - Intent intent = new Intent(getActivity().getApplicationContext(), MainActivity.class); - intent.putExtra("Fragment", ID); - startActivity(intent); - } + + //------------Request------------ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { - case ACCESS_LOCATION_PERMISSION: + case REQUEST_CODE_ACCESS_LOCATION_PERMISSION: { Toast.makeText(getActivity().getApplicationContext(), "Location access granted", Toast.LENGTH_SHORT).show(); } break; - case WRITE_STORAGE_PERMISSION: + case REQUEST_CODE_WRITE_STORAGE_PERMISSION: { Toast.makeText(getActivity().getApplicationContext(), "Allowed to access local storage", Toast.LENGTH_SHORT).show(); } @@ -223,4 +216,46 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in } + //------------Others------------ + + /** + * reloads the MainActivity in order to enable/disable the darkmode + */ + private void reset() + { + Log.v(TAG, "Reset Activity "); + Intent intent = new Intent(getActivity().getApplicationContext(), MainActivity.class); + intent.putExtra("Fragment", ID); + startActivity(intent); + } + + + //------------Toolbar Menu------------ + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.actionbar_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.ab_menu_about: + //no implemented here, + return false; + case R.id.ab_menu_faq: + //no implemented here, + return false; + case R.id.ab_menu_settings: + //no implemented here + return false; + case R.id.ab_menu_search: + + } + return super.onOptionsItemSelected(item); + } } diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentWithServerConnection.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentWithServerConnection.java new file mode 100644 index 0000000..c8a957a --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentWithServerConnection.java @@ -0,0 +1,47 @@ +package de.htwBerlin.ois.Fragments; + +import android.support.v4.app.Fragment; + +public abstract class FragmentWithServerConnection extends Fragment +{ + /** + * used in {@link this#changeVisibilities} + * to define which views are visible/invisible + * while trying to connect with the server + */ + final byte STATE_CONNECTING = 1; + /** + * used in {@link this#changeVisibilities} + * to define which views are visible/invisible + * when the server hast responded + */ + final byte STATE_NO_CONNECTION = 2; + /** + * used in {@link this#changeVisibilities} + * to define which views are visible/invisible + * when connected with the server / file listing was successful + */ + final byte STATE_CONNECTED = 3; + + public void changeVisibilities(int State) + { + switch (State) + { + case STATE_CONNECTED: + this.onConnected(); + break; + case STATE_CONNECTING: + this.onConnecting(); + break; + case STATE_NO_CONNECTION: + this.onNoConnection(); + break; + } + } + + protected abstract void onNoConnection(); + + protected abstract void onConnecting(); + + protected abstract void onConnected(); +} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentrequestNewMap.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentrequestNewMap.java new file mode 100644 index 0000000..8af55c5 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FragmentrequestNewMap.java @@ -0,0 +1,274 @@ +package de.htwBerlin.ois.Fragments; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.Toast; + +import de.htwBerlin.ois.R; +import de.htwBerlin.ois.ServerCommunication.HTTPRequestNewMap; + +/** + * Fragment to allow the user to request a new map + * + * @author WilliBoelke + */ +public class FragmentrequestNewMap extends Fragment +{ + //------------Instance Variables------------ + + /** + * Fragment ID used to identify the fragment + * (for example by putting the ID into the Intent extra ) + */ + public static String ID = "RequestMap"; + /** + * Log Tag + */ + private final String TAG = this.getClass().getSimpleName(); + /** + * The View + */ + private View view; + /** + * Date picker to let the user pick the date of the map + */ + private DatePicker datePicker; + private Button requestButton; + + private EditText longitudeTop; + private EditText longitudeBottom; + private EditText latitudeRight; + private EditText latitudeLeft; + + public static final int MIN_LATITUDE = -180; + public static final int MAX_LATITUDE = 180; + public static final int MAX_LONGITUDE = 90; + public static final int MIN_LONGITUDE = -90; + + //------------Static Variables------------ + private EditText name; + + + //------------Activity/Fragment Lifecycle------------ + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + view = inflater.inflate(R.layout.fragment_request_map, container, false); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) + { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(true); + datePicker = view.findViewById(R.id.simpleDatePicker); + //no calender view + datePicker.setCalendarViewShown(false); + name = view.findViewById(R.id.name_et); + requestButton = view.findViewById(R.id.request_button); + longitudeTop = view.findViewById(R.id.long_top_et); + longitudeBottom = view.findViewById(R.id.long_bottom_et); + latitudeRight = view.findViewById(R.id.lat_right_et); + latitudeLeft = view.findViewById(R.id.lat_left_et); + + + requestButton.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + if (checkForNullName() == true && checkForNullCoordinates() == true) + { + HTTPRequestNewMap httpRequestNewMap = new HTTPRequestNewMap(getDatePickerValuesAsString(), getCoordinatesAsString(), name.getText().toString()); + httpRequestNewMap.execute(); + } + } + }); + + } + + + //------------User Input------------ + + + /** + * Building a formatted string (jjjj-mm-dd), as its needed by the server + * + * @return Date as string + */ + private String getDatePickerValuesAsString() + { + StringBuilder stringBuilder = new StringBuilder(); + + //Building a string in format JJJJJ-MM-TT + stringBuilder.append(datePicker.getYear()); + stringBuilder.append("-"); + stringBuilder.append(datePicker.getMonth()); + stringBuilder.append("-"); + stringBuilder.append(datePicker.getDayOfMonth()); + + return stringBuilder.toString(); + } + + /** + * Building a String out of the coordinates + * Format: Top,Left_Top,Right_Bottom, Right_Bottom,Left_Top,Left + * + * @return + */ + private String getCoordinatesAsString() + { + String longTop = longitudeTop.getText().toString(); + String longBottom = longitudeBottom.getText().toString(); + String latLeft = latitudeLeft.getText().toString(); + String latRight = latitudeRight.getText().toString(); + + Log.i(TAG, "getCoordinatesAsString: creating coordinates string ..."); + StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.append(longTop); + stringBuilder.append(", "); + stringBuilder.append(latLeft); + stringBuilder.append("_"); + + stringBuilder.append(longTop); + stringBuilder.append(", "); + stringBuilder.append(latRight); + stringBuilder.append("_"); + + stringBuilder.append(longBottom); + stringBuilder.append(", "); + stringBuilder.append(latRight); + stringBuilder.append("_"); + + stringBuilder.append(longBottom); + stringBuilder.append(", "); + stringBuilder.append(latLeft); + stringBuilder.append("_"); + + stringBuilder.append(longTop); + stringBuilder.append(", "); + stringBuilder.append(latLeft); + Log.i(TAG, "getCoordinatesAsString: String created"); + Log.i(TAG, "getCoordinatesAsString: result: " + stringBuilder.toString()); + return stringBuilder.toString(); + } + + + //------------Check User Input------------ + + /** + * Check if a name was entered by the user + * + * @return + */ + private boolean checkForNullName() + { + if (name.getText().toString().length() == 0) + { + Toast.makeText(getActivity().getApplicationContext(), "Please enter a name ", Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + /** + * Check if the user entered all necessary coordinates + * + * @return + */ + private boolean checkForNullCoordinates() + { + if (longitudeTop.getText().toString().length() == 0) + { + Toast.makeText(getActivity(), "Please insert a top latitude ", Toast.LENGTH_SHORT).show(); + return false; + } + if (longitudeBottom.getText().toString().length() == 0) + { + Toast.makeText(getActivity(), "Please insert the bottom latitude ", Toast.LENGTH_SHORT).show(); + return false; + } + if (latitudeRight.getText().toString().length() == 0) + { + Toast.makeText(getActivity(), "Please insert the right longitude ", Toast.LENGTH_SHORT).show(); + return false; + } + if (latitudeLeft.getText().toString().length() == 0) + { + Toast.makeText(getActivity(), "Please insert the left longitude", Toast.LENGTH_SHORT).show(); + return false; + } + + double longTop = Double.parseDouble(longitudeTop.getText().toString()); + double longBottom = Double.parseDouble(longitudeBottom.getText().toString()); + double latLeft = Double.parseDouble(latitudeLeft.getText().toString()); + double latRight = Double.parseDouble(latitudeRight.getText().toString()); + + if (longTop< MIN_LONGITUDE || longTop > MAX_LONGITUDE) + { + Toast.makeText(getActivity(), "You inserted a invalid top latitude ", Toast.LENGTH_SHORT).show(); + return false; + } + if (longBottom< MIN_LONGITUDE || longBottom > MAX_LONGITUDE) + { + Toast.makeText(getActivity(), "You inserted a invalid bottom latitude ", Toast.LENGTH_SHORT).show(); + return false; + } + if (latRight< MIN_LATITUDE || latRight > MAX_LATITUDE) + { + Toast.makeText(getActivity(), "You inserted a invalid right longitude ", Toast.LENGTH_SHORT).show(); + return false; + } + if (latLeft < MIN_LATITUDE || latLeft > MAX_LATITUDE) + { + Toast.makeText(getActivity(), "You inserted a invalid left longitude ", Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + + //------------Toolbar Menu------------ + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.actionbar_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.ab_menu_about: + //no implemented here, + return false; + case R.id.ab_menu_faq: + //no implemented here, + return false; + case R.id.ab_menu_settings: + //no implemented here + return false; + case R.id.ab_menu_search: + + } + return super.onOptionsItemSelected(item); + } + +} \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/FramentAbout.java b/app/src/main/java/de/htwBerlin/ois/Fragments/FramentAbout.java new file mode 100644 index 0000000..fa633bb --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/Fragments/FramentAbout.java @@ -0,0 +1,90 @@ +package de.htwBerlin.ois.Fragments; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import de.htwBerlin.ois.R; + +/** + * Fragment showing about OHDM information + * Can be reached by the user via the Toolbars 3-dod menu + */ +public class FramentAbout extends Fragment +{ + + //------------Instance Variables------------ + + /** + * Fragment ID used to identify the fragment + * (for example by putting the ID into the Intent extra ) + */ + public static String ID = "About"; + /** + * Log tag + */ + private final String TAG = this.getClass().getSimpleName(); + + + //------------Static Variables------------ + /** + * Fragments view + */ + private View view; + + + //------------Activity/Fragment Lifecycle------------ + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) + { + //inflating the view + view = inflater.inflate(R.layout.fragment_about, container, false); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) + { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(true); + } + + //------------Toolbar Menu------------ + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.actionbar_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.ab_menu_about: + //no implemented here, + return false; + case R.id.ab_menu_faq: + //no implemented here, + return false; + case R.id.ab_menu_settings: + //no implemented here + return false; + case R.id.ab_menu_search: + + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/HomeFragment.java b/app/src/main/java/de/htwBerlin/ois/Fragments/HomeFragment.java deleted file mode 100644 index 45efbe1..0000000 --- a/app/src/main/java/de/htwBerlin/ois/Fragments/HomeFragment.java +++ /dev/null @@ -1,158 +0,0 @@ -package de.htwBerlin.ois.Fragments; - -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.support.v4.app.Fragment; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.Spinner; - -import java.io.File; -import java.util.ArrayList; - -import de.htwBerlin.ois.FileStructure.LocalMapsRecyclerAdapter; -import de.htwBerlin.ois.FileStructure.MapFileSingleton; -import de.htwBerlin.ois.MainActivity.MainActivity; -import de.htwBerlin.ois.R; - -/** - * Represents the HOME Tab and thus, the starting point for the OHDM Offline Viewer application - * - * @author morelly_t1 - */ -public class HomeFragment extends Fragment -{ - /** - * Fragment ID used to identify the fragment - * (for example by putting the ID into the Intent extra ) - */ - public static String ID = "Home"; - /** - * Log tag - */ - private final String TAG = this.getClass().getSimpleName(); - /** - * Set of the .map files ind the OHDM directory - * Filled in {@link #findMapFiles()} - */ - private ArrayList mapFiles; - /** - * Spinner to choose a .map file from - */ - private Spinner spinnerMapFile; - /** - * Button to save the chosen .map file - */ - private Button buttonSave; - /** - * The view - */ - private View view; - /** - * The RecyclerViews LayoutManager - */ - private RecyclerView.LayoutManager recyclerLayoutManager; - /** - * The RecyclerAdapter - */ - private LocalMapsRecyclerAdapter recyclerAdapter; - - private RecyclerView localMapsRecyclerView; - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) - { - //inflating the view - view = inflater.inflate(R.layout.fragment_home, container, false); - return view; - } - - @RequiresApi(api = Build.VERSION_CODES.N) - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) - { - super.onActivityCreated(savedInstanceState); - - mapFiles = findMapFiles(); - setupRecycler(); - } - - private void setupRecycler() - { - localMapsRecyclerView = view.findViewById(R.id.local_maps_recycler); - if (!mapFiles.isEmpty()) - { - view.findViewById(R.id.content_card_home_info).setVisibility(View.INVISIBLE); - view.findViewById(R.id.ohdm_logo_iv).setVisibility(View.INVISIBLE); - localMapsRecyclerView.setVisibility(View.VISIBLE); - recyclerLayoutManager = new LinearLayoutManager(this.getContext()); - recyclerAdapter = new LocalMapsRecyclerAdapter(this.getContext(), mapFiles, R.layout.download_recycler_item); - recyclerAdapter.setOnItemClickListener(new LocalMapsRecyclerAdapter.OnItemClickListener() - { - @Override - public void onItemClick(int position) - { - Log.i(TAG, "using " + mapFiles.get(position).getName() + " as mapfile"); - MapFileSingleton mapFile = MapFileSingleton.getInstance(); - mapFile.setFile(mapFiles.get(position)); - recyclerAdapter.notifyDataSetChanged(); - } - }); - localMapsRecyclerView.setLayoutManager(recyclerLayoutManager); - localMapsRecyclerView.setAdapter(recyclerAdapter); - recyclerAdapter.notifyDataSetChanged(); - - - } - } - - /** - * Scans OHDM Directory for .map Files - * - * @return a set of .map files - */ - protected ArrayList findMapFiles() - { - ArrayList maps = new ArrayList<>(); - try - { - for (File mapFile : new File(MainActivity.MAP_FILE_PATH).listFiles()) - { - if (mapFile.getName().endsWith(".map")) - { - Log.i(TAG, "osmfile: " + mapFile.getName()); - maps.add(mapFile); - } - } - } - catch (NullPointerException e) - { - Log.i(TAG, "No map files located."); - } - return maps; - } - - - @Override - public void onStart() - { - super.onStart(); - } - - - @Override - public void onResume() - { - super.onResume(); - } - -} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/MapDownloadFragment.java b/app/src/main/java/de/htwBerlin/ois/Fragments/MapDownloadFragment.java deleted file mode 100644 index 7f77361..0000000 --- a/app/src/main/java/de/htwBerlin/ois/Fragments/MapDownloadFragment.java +++ /dev/null @@ -1,181 +0,0 @@ -package de.htwBerlin.ois.Fragments; - -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.app.Fragment; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import java.util.ArrayList; - -import de.htwBerlin.ois.FileStructure.LeftSwipeCallback; -import de.htwBerlin.ois.FileStructure.OhdmFile; -import de.htwBerlin.ois.FileStructure.OhdmFileRecyclerAdapter; -import de.htwBerlin.ois.FileStructure.RecyclerViewItemSwipeGestures; -import de.htwBerlin.ois.R; -import de.htwBerlin.ois.ServerCommunication.AsyncResponse; -import de.htwBerlin.ois.ServerCommunication.FtpTaskFileDownloading; -import de.htwBerlin.ois.ServerCommunication.FtpTaskFileListing; - -/** - * This Activity represents a small map file download center - */ -public class MapDownloadFragment extends Fragment -{ - /** - * Fragment ID used to identify the fragment - * (for example by putting the ID into the Intent extra ) - */ - public static String ID = "MapDownload"; - /** - * Log tag - */ - private final String TAG = this.getClass().getSimpleName(); - /** - * RecyclerView to display the downloadable maps - */ - private RecyclerView recyclerView; - /** - * The RecyclerViews LayoutManager - */ - private RecyclerView.LayoutManager recyclerLayoutManager; - /** - * The RecyclerAdapter - */ - private OhdmFileRecyclerAdapter recyclerAdapter; - /** - * ArrayList of OHDMFiles, to be displayed in the RecyclerView - */ - private ArrayList ohdmFiles; - private ItemTouchHelper itemTouchHelper; - private FloatingActionButton requestNewMapFab; - /** - * The view - */ - private View view; - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) - { - // inflating the view - view = inflater.inflate(R.layout.fragment_map_download, container, false); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) - { - super.onActivityCreated(savedInstanceState); - this.setupRecyclerView(); - this.listFTPFiles(); - } - - /** - * Setup the RecyclerView : - *

- * Filling it with OHDMFiles - * Setup Swipe gestures - * Setup onItemClickListener - */ - private void setupRecyclerView() - { - - recyclerView = view.findViewById(R.id.available_maps_recycler); - recyclerView.setVisibility(View.INVISIBLE); - ohdmFiles = new ArrayList<>(); - recyclerLayoutManager = new LinearLayoutManager(this.getContext()); - itemTouchHelper = new ItemTouchHelper(new RecyclerViewItemSwipeGestures(recyclerAdapter, new LeftSwipeCallback() - { - @Override - public void onLeftSwipe(int position) - { - FtpTaskFileDownloading ftpTaskFileDownloading = new FtpTaskFileDownloading(getActivity().getApplicationContext()); - ftpTaskFileDownloading.execute(ohdmFiles.get(position)); - recyclerAdapter.notifyDataSetChanged(); - } - })); - itemTouchHelper.attachToRecyclerView(recyclerView); - recyclerView.setLayoutManager(recyclerLayoutManager); - recyclerAdapter = new OhdmFileRecyclerAdapter(getActivity().getApplicationContext(), ohdmFiles, R.layout.download_recycler_item); - recyclerView.setAdapter(recyclerAdapter); - FtpTaskFileListing ftpTaskFileListing = new FtpTaskFileListing( new AsyncResponse() - { - @Override - public void getOhdmFiles(ArrayList files) - { - if(files.size() > 0) - { - ohdmFiles.addAll(files); - Log.i(TAG, "received " + files.size() + " files."); - recyclerView.setVisibility(View.VISIBLE); - view.findViewById(R.id.connecting_tv).setVisibility(View.INVISIBLE); - view.findViewById(R.id.connecting_pb).setVisibility(View.INVISIBLE); - recyclerAdapter.notifyDataSetChanged(); - } - else - { - TextView tv = view.findViewById(R.id.connecting_tv); - tv.setText("Connection failed, try again later"); - } - } - }, getActivity()); - ftpTaskFileListing.execute(); - - - //FloatingActionButton - - requestNewMapFab = view.findViewById(R.id.request_new_map_fab); - requestNewMapFab.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new RequestMapFragment()).addToBackStack(null).commit(); - } - }); - } - - /** - * executes list files async task - */ - private void listFTPFiles() - { - //ftpTaskFileListing.execute(); - } - - - @Override - public void onStart() - { - super.onStart(); - } - - - @Override - public void onResume() - { - super.onResume(); - } - - @Override - public void onStop() - { - super.onStop(); - } - - @Override - public void onDestroy() - { - super.onDestroy(); - } - -} diff --git a/app/src/main/java/de/htwBerlin/ois/Fragments/RequestMapFragment.java b/app/src/main/java/de/htwBerlin/ois/Fragments/RequestMapFragment.java deleted file mode 100644 index 6673ce3..0000000 --- a/app/src/main/java/de/htwBerlin/ois/Fragments/RequestMapFragment.java +++ /dev/null @@ -1,223 +0,0 @@ -package de.htwBerlin.ois.Fragments; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.DatePicker; -import android.widget.EditText; -import android.widget.Toast; - -import de.htwBerlin.ois.ServerCommunication.HTTPRequestNewMap; -import de.htwBerlin.ois.R; - -/** - * @author WilliBoelke - */ -public class RequestMapFragment extends Fragment -{ - private final String TAG = this.getClass().getSimpleName(); - /** - * Fragment ID used to identify the fragment - * (for example by putting the ID into the Intent extra ) - */ - public static String ID = "RequestMap"; - - /** - * The View - */ - private View view; - /** - * Date picker to let the user pick the date of the map - */ - private DatePicker datePicker; - private Button requestButton; - - /** - * Coordinate pair 1 / upper left corner - */ - private EditText coordx1; - private EditText coordy1; - - /** - * Coordinate pair 2 / upper right corner - */ - private EditText coordx2; - private EditText coordy2; - - /** - * Coordinate pair 3 / bottom right corner - */ - private EditText coordx3; - private EditText coordy3; - - /** - * Coordinate pair 4 / bottom left corner - */ - private EditText coordx4; - private EditText coordy4; - - private EditText name; - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) - { - view = inflater.inflate(R.layout.fragment_request_map, container, false); - return view; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) - { - super.onActivityCreated(savedInstanceState); - - datePicker = view.findViewById(R.id.simpleDatePicker); - //no calender view - datePicker.setCalendarViewShown(false); - name = view.findViewById(R.id.name_et); - requestButton = view.findViewById(R.id.request_button); - coordx1 = view.findViewById(R.id.coord_x1_et); - coordy1 = view.findViewById(R.id.coord_y1_et); - coordx2 = view.findViewById(R.id.coord_x2_et); - coordy2 = view.findViewById(R.id.coord_y2_et); - coordx3 = view.findViewById(R.id.coord_x3_et); - coordy3 = view.findViewById(R.id.coord_y3_et); - coordx4 = view.findViewById(R.id.coord_x4_et); - coordy4 = view.findViewById(R.id.coord_y4_et); - - - requestButton.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - if (checkForNullName() == true && checkForNullCoordinates() == true) - { - HTTPRequestNewMap httpRequestNewMap = new HTTPRequestNewMap(getDatePickerValuesAsString(), getCoordinatesAsString(), name.getText().toString()); - httpRequestNewMap.execute(); - } - } - }); - - } - - - /** - * Building a formatted string (jjjj-mm-dd), as its needed by the server - * - * @return Date as string - */ - private String getDatePickerValuesAsString() - { - StringBuilder stringBuilder = new StringBuilder(); - - //Building a string in format JJJJJ-MM-TT - stringBuilder.append(datePicker.getYear()); - stringBuilder.append("-"); - stringBuilder.append(datePicker.getMonth()); - stringBuilder.append("-"); - stringBuilder.append(datePicker.getDayOfMonth()); - - return stringBuilder.toString(); - } - - private String getCoordinatesAsString() - { - Log.i(TAG, "getCoordinatesAsString: creating coordinates string ..."); - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(coordx1.getText().toString().trim()); - stringBuilder.append(","); - stringBuilder.append(coordy1.getText().toString().trim()); - stringBuilder.append("_"); - stringBuilder.append(coordx2.getText().toString().trim()); - stringBuilder.append(","); - stringBuilder.append(coordy2.getText().toString().trim()); - stringBuilder.append("_"); - stringBuilder.append(coordx3.getText().toString().trim()); - stringBuilder.append(","); - stringBuilder.append(coordy3.getText().toString().trim()); - stringBuilder.append("_"); - stringBuilder.append(coordx4.getText().toString().trim()); - stringBuilder.append(","); - stringBuilder.append(coordy4.getText().toString().trim()); - stringBuilder.append("_"); - stringBuilder.append(coordx2.getText().toString().trim()); - stringBuilder.append(","); - stringBuilder.append(coordy2.getText().toString().trim()); - stringBuilder.append("_"); - Log.i(TAG, "getCoordinatesAsString: String created"); - Log.i(TAG, "getCoordinatesAsString: result: " + stringBuilder.toString()); - return stringBuilder.toString(); - } - - - /** - * Check if a name was entered by the user - * - * @return - */ - private boolean checkForNullName() - { - if (name.getText().toString().length() == 0) - { - Toast.makeText(getActivity().getApplicationContext(), "Please enter a name ", Toast.LENGTH_SHORT).show(); - return false; - } - return true; - } - - - /** - * Check if the user entered all necessary coordinates - * @return - */ - private boolean checkForNullCoordinates() - { - if (coordx1.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate X1 ", Toast.LENGTH_SHORT).show(); - return false; - } - if (coordy1.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate Y1 ", Toast.LENGTH_SHORT).show(); - return false; - } - if (coordx2.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate X2 ", Toast.LENGTH_SHORT).show(); - return false; - } - if (coordy2.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate Y2", Toast.LENGTH_SHORT).show(); - return false; - } - if (coordx3.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate X3 ", Toast.LENGTH_SHORT).show(); - return false; - } - if (coordy3.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate Y3 ", Toast.LENGTH_SHORT).show(); - return false; - } - if (coordx4.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate X4 ", Toast.LENGTH_SHORT).show(); - return false; - } - if (coordy4.getText().toString().length() == 0) - { - Toast.makeText(getActivity(), "Please insert the Coordinate Y4 ", Toast.LENGTH_SHORT).show(); - return false; - } - return true; - } -} \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/MainActivity/MainActivity.java b/app/src/main/java/de/htwBerlin/ois/MainActivity/MainActivity.java index 417eca5..ec2b472 100644 --- a/app/src/main/java/de/htwBerlin/ois/MainActivity/MainActivity.java +++ b/app/src/main/java/de/htwBerlin/ois/MainActivity/MainActivity.java @@ -13,7 +13,6 @@ import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; -import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; @@ -24,39 +23,106 @@ import java.util.Map; import de.htwBerlin.ois.FileStructure.MapFileSingleton; -import de.htwBerlin.ois.Fragments.AboutFragment; -import de.htwBerlin.ois.Fragments.FAQFragment; -import de.htwBerlin.ois.Fragments.HomeFragment; -import de.htwBerlin.ois.Fragments.MapDownloadFragment; -import de.htwBerlin.ois.Fragments.NavigationFragment; -import de.htwBerlin.ois.Fragments.OptionsFragment; +import de.htwBerlin.ois.Fragments.FragmentDownloadCenterAll; +import de.htwBerlin.ois.Fragments.FragmentFAQ; +import de.htwBerlin.ois.Fragments.FragmentHome; +import de.htwBerlin.ois.Fragments.FragmentNavigation; +import de.htwBerlin.ois.Fragments.FragmentOptions; +import de.htwBerlin.ois.Fragments.FramentAbout; import de.htwBerlin.ois.R; +/** + * @author WilliBoelke + */ public class MainActivity extends AppCompatActivity { + //------------Instance Variables------------ + public static final String MAP_FILE_PATH = Environment.getExternalStorageDirectory().toString() + "/OHDM"; private static final int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124; + + + //------------Instance Variables------------ + private String TAG = getClass().getSimpleName(); - private Fragment defaultFragment = new HomeFragment(); + private Fragment defaultFragment = new FragmentHome(); + + + //------------Activity/Fragment Lifecycle------------ + + /** + * Bottom Nav Listener + */ + private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() + { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) + { + Fragment selectedFragment = null; + String id = null; + // switch ... case to select the right Fragment to start + switch (item.getItemId()) + { + case R.id.nav_home: + selectedFragment = new FragmentHome(); + id = FragmentHome.ID; + break; + case R.id.nav_download: + selectedFragment = new FragmentDownloadCenterAll(); + id = FragmentHome.ID; + break; + case R.id.nav_navigation: + if (MapFileSingleton.getInstance().getFile() != null) + { + selectedFragment = new FragmentNavigation(); + id = FragmentNavigation.ID; + } + else + { + Toast.makeText(getApplicationContext(), "You need to choose a map", Toast.LENGTH_LONG).show(); + } + break; + default: + return false; + } + + // giving the FragmentManager the container and the fragment which should be loaded into view + // ... also commit + try + { + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).addToBackStack(id).commit(); + } + catch (NullPointerException e) + { + Log.e(TAG, "onNavigationItemSelected: Fragment was null ", e); + } + // return true to tell that everything did go right + return true; + } + }; @Override protected void onCreate(Bundle savedInstanceState) { + Log.d(TAG, "onCreate : setting app theme..."); super.onCreate(savedInstanceState); //Get settings from SharedPrefs - if (getApplicationContext().getSharedPreferences(OptionsFragment.SETTINGS_SHARED_PREFERENCES, 0).getBoolean(OptionsFragment.DARK_MODE, false) == true) + if (getApplicationContext().getSharedPreferences(FragmentOptions.SETTINGS_SHARED_PREFERENCES, 0).getBoolean(FragmentOptions.DARK_MODE, false) == true) { setTheme(R.style.DarkTheme); + Log.d(TAG, "onCreate : app theme DARK"); } else { setTheme(R.style.LightTheme); + Log.d(TAG, "onCreate : app theme LIGHT"); } setContentView(R.layout.activity_main); + // setting up the BottomNavigationView with Listener BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation_view); bottomNav.setOnNavigationItemSelectedListener(navListener); @@ -65,23 +131,21 @@ protected void onCreate(Bundle savedInstanceState) Intent intent = getIntent(); if (intent.getStringExtra("Fragment") != null) { - if (intent.getStringExtra("Fragment").equals(OptionsFragment.ID)) + if (intent.getStringExtra("Fragment").equals(FragmentOptions.ID)) { //if we came her from the reset method in the options fragment, we want the options fragment to appear again - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new OptionsFragment()).addToBackStack(OptionsFragment.ID).commit(); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentOptions()).commit(); + intent.putExtra("Fragment", ""); } - } else { - // giving first defaultFragment to the FragmentManager - if (savedInstanceState == null) + if(savedInstanceState == null) { getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, defaultFragment).addToBackStack(null).commit(); } } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkPermissions(); @@ -89,11 +153,15 @@ protected void onCreate(Bundle savedInstanceState) createOhdmDirectory(); } + + //------------Toolbar Menu------------ + /** * Creates OHDM Folder if not exists */ private void createOhdmDirectory() { + Log.d(TAG, "createOhdmDirectory : Creating OHDM directory..."); File dir = new File(MAP_FILE_PATH); boolean status; if (!dir.exists()) @@ -102,67 +170,11 @@ private void createOhdmDirectory() if (status) Toast.makeText(this, "Created OHDM Directory.", Toast.LENGTH_SHORT).show(); else Toast.makeText(this, "Couldn't create OHDM Directory.", Toast.LENGTH_SHORT).show(); } + Log.d(TAG, "createOhdmDirectory : OHDM directory created"); } - /** - * Bottom Nav Listener - */ - private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() - { - @Override - public boolean onNavigationItemSelected(@NonNull MenuItem item) - { - Fragment selectedFragment = null; - String id = null; - // switch ... case to select the right Fragment to start - switch (item.getItemId()) - { - case R.id.nav_home: - selectedFragment = new HomeFragment(); - id = HomeFragment.ID; - break; - case R.id.nav_download: - selectedFragment = new MapDownloadFragment(); - id = HomeFragment.ID; - break; - case R.id.nav_navigation: - if (MapFileSingleton.getInstance().getFile() != null) - { - selectedFragment = new NavigationFragment(); - id = NavigationFragment.ID; - } - else - { - Toast.makeText(getApplicationContext(), "You need to choose a map", Toast.LENGTH_LONG).show(); - } - break; - - default: - return false; - } - - // giving the FragmentManager the container and the fragment which should be loaded into view - // ... also commit - try - { - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).addToBackStack(id).commit(); - } - catch (NullPointerException e) - { - Log.e(TAG, "onNavigationItemSelected: Fragment was null ", e); - } - // return true to tell that everything did go right - return true; - } - }; - - @Override - public boolean onCreateOptionsMenu(Menu menu) - { - getMenuInflater().inflate(R.menu.actionbar_menu, menu); - return true; - } + //------------Permissions------------ @Override public boolean onOptionsItemSelected(MenuItem item) @@ -170,20 +182,25 @@ public boolean onOptionsItemSelected(MenuItem item) switch (item.getItemId()) { case R.id.ab_menu_about: - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AboutFragment()).addToBackStack(AboutFragment.ID).commit(); + Log.d(TAG, "Options Menu : replacing current fragment with FragmentAbout"); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FramentAbout()).addToBackStack(FramentAbout.ID).commit(); break; case R.id.ab_menu_faq: - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FAQFragment()).addToBackStack(FAQFragment.ID).commit(); + Log.d(TAG, "Options Menu : replacing current fragment with FragmentFAQ"); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentFAQ()).addToBackStack(FragmentFAQ.ID).commit(); break; case R.id.ab_menu_settings: - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new OptionsFragment()).addToBackStack(OptionsFragment.ID).commit(); + Log.d(TAG, "Options Menu : replacing current fragment with FragmentOptions"); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentOptions()).commit(); break; + case R.id.ab_menu_search: + //no implemented here, to e implemented in fragments + return false; } return super.onOptionsItemSelected(item); } - /** * Checks necessary permissions * Source https://programtalk.com/vs/osmdroid/osmdroid-forge-app/src/main/java/org/osmdroid/forge/app/MainActivity.java/ @@ -212,6 +229,8 @@ private void checkPermissions() } + //------------Bottom Navigation------------ + @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { diff --git a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/AsyncResponse.java b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/AsyncResponse.java index 5d8bcab..a8bbd84 100644 --- a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/AsyncResponse.java +++ b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/AsyncResponse.java @@ -2,9 +2,12 @@ import java.util.ArrayList; -import de.htwBerlin.ois.FileStructure.OhdmFile; +import de.htwBerlin.ois.FileStructure.RemoteDirectory; +import de.htwBerlin.ois.FileStructure.RemoteFile; public interface AsyncResponse { - void getOhdmFiles(ArrayList ohdmFiles); + void getOhdmFiles(ArrayList remoteFiles); + + void getRemoteDirectories(ArrayList remoteDirectories); } diff --git a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpClient.java b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpClient.java index 47e7348..3175724 100644 --- a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpClient.java +++ b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpClient.java @@ -13,57 +13,61 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.PrintStream; import java.net.SocketException; +import java.util.ArrayList; import static de.htwBerlin.ois.MainActivity.MainActivity.MAP_FILE_PATH; +import static de.htwBerlin.ois.ServerCommunication.Variables.FTP_Port; +import static de.htwBerlin.ois.ServerCommunication.Variables.SERVER_IP; +import static de.htwBerlin.ois.ServerCommunication.Variables.USER_NAME; +import static de.htwBerlin.ois.ServerCommunication.Variables.USER_PASSWORD; /** * Wraps the apache FTPClient - * @author NoteFox - * @author WilliBoelke + * + * @author NoteFox + * @author WilliBoelke */ public class FtpClient { + //------------Instance Variables------------ + private final String TAG = getClass().getSimpleName(); private FTPClient client; - private PrintStream logStream; - private boolean LOGGING_OVER_FILE = true; - public FtpClient(OutputStream os) - { - logStream = new PrintStream(os); - } - public FtpClient() + //------------Constructors----------- + + protected FtpClient() { - LOGGING_OVER_FILE = false; + Log.d(TAG, "Constructor : new FtpClient "); } + + //------------Connection----------- + /** * if called, connects to a server * - * @param server server ip/hostname - * @param port FTPServer port - * @param user user to log in with - * @param pass passwort used to log in * @return 0 = successful connection, * 1 = FTP server refused connection, * 2 = Could not login to FTP Server (probably wrong password), * 3 = Socket exception thrown, Server not found, * 4 = IO Exception */ - public int connect(String server, int port, String user, String pass) + int connect() { + Log.d(TAG, "connect : connecting to ftp client..."); if (client == null) { - Log.i(TAG, "Getting passive FTP client"); + Log.d(TAG, "connect : getting passive FTP client"); client = new FTPClient(); try { - client.connect(server, port); + Log.d(TAG, "connect : connecting to " + SERVER_IP + " : " + FTP_Port); + client.connect(SERVER_IP, FTP_Port); // After connection attempt, you should check the reply code to verify // success. int reply = client.getReplyCode(); @@ -71,67 +75,187 @@ public int connect(String server, int port, String user, String pass) if (!FTPReply.isPositiveCompletion(reply)) { client.disconnect(); - Log.e(TAG, " FTP server refused connection."); + Log.e(TAG, "connect : FTP server refused connection."); return 1; } + else + { + Log.d(TAG, "connect : connected successfully"); + } //after connecting to the server set the local passive mode client.enterLocalPassiveMode(); //send username and password to login to the server - if (!client.login(user, pass)) + Log.d(TAG, "connect : trying to log in ..."); + if (!client.login(USER_NAME, USER_PASSWORD)) { - Log.e(TAG, "Could not login to FTP Server"); + Log.e(TAG, "connect : Could not login to FTP Server"); return 2; } + else + { + Log.d(TAG, "connect : log in successful"); + } client.setFileType(FTP.BINARY_FILE_TYPE); } catch (SocketException e) { - String message = "Socket exception thrown, Server not found"; - Log.e(TAG, "ERROR :" + message + "\n" + e); + Log.e(TAG, "connect : socket exception thrown, Server not found" + "\n" + e); return 3; } catch (IOException e) { - String message = "IO Exception"; - Log.e(TAG, "ERROR :" + message + "\n" + e); + Log.e(TAG, "IO Exception" + "\n" + e); return 4; } } + else + { + Log.d(TAG, "was already connected "); + } + Log.d(TAG, "connect : successfully connected"); return 0; } /** * checking if connected * - * @return + * @return true if connected, else false */ - public boolean isConnected() + boolean isConnected() { return client.isConnected(); } + /** + * closes connection + * pls always use at the end !!!! + */ + protected void closeConnection() + { + Log.d(TAG, "closeConnection : trying to close connection with " + SERVER_IP + " : " + FTP_Port); + if (client == null) + { + Log.d(TAG, "closeConnection : nothing to close, the FTPClient wasn't initialized"); + return; + } + //be polite and logout & close the connection before the application finishes + try + { + client.logout(); + client.disconnect(); + } + catch (IOException e) + { + Log.e(TAG, "closeConnection : Could not logout"); + } + Log.d(TAG, "closeConnection : log out successful"); + } + + + //------------Listing----------- /** - * gives back the File list, given in current working dir + * Returns a list of all directories in path + * + * @param path the path + * @return all directories + * @throws IOException + */ + protected FTPFile[] getDirList(String path) throws IOException + { + if (client == null) + { + Log.e(TAG, "getDirList : wasnt connected to server, call connect() first"); + return null; + } + Log.d(TAG, " getDirList : getting file list for " + path + " ..."); + FTPFile[] files = client.listFiles(path); + ArrayList dirList = new ArrayList<>(); + for (FTPFile f : files) + { + if (f.isDirectory()) dirList.add(f); + } + Log.d(TAG, " getDirList : got " + dirList.size() + "dirs from " + path); + return dirList.toArray(new FTPFile[dirList.size()]); + } + + /** + * gives back the File list, given in path dir + * ignores sub dirs completely * * @return FTPFiles in current dir * @throws IOException couldn't read from current dir */ - public FTPFile[] getFileList() throws IOException + protected FTPFile[] getFileList(String path) throws IOException { if (client == null) { - Log.i(TAG, "First initialize the FTPClient by calling 'initFTPPassiveClient()"); + Log.e(TAG, "getFileList : wasnt connected to server, call connect() first"); return null; } - Log.i(TAG, "Getting file listing for current director"); - FTPFile[] files = client.listFiles(""); + Log.d(TAG, " getFileList : getting file list for " + path + " ..."); + FTPFile[] filesAndDirs = client.listFiles(path); + ArrayList files = new ArrayList<>(); - return files; + for (FTPFile f : filesAndDirs) + { + if (!f.isDirectory()) + { + files.add(f); + } + } + Log.d(TAG, " getFileList : got " + files.size() + "files from " + path); + return files.toArray(new FTPFile[files.size()]); } + /** + * gives back the File list, given in path dir + * including files from sub dirs + * + * @return FTPFiles in current dir + * @throws IOException couldn't read from current dir + */ + protected FTPFile[] getAllFileList(String path) throws IOException + { + if (client == null) + { + Log.e(TAG, "getAllFileList : wasnt connected to server, call connect() first"); + return null; + } + Log.d(TAG, " getAllFileList : getting file list for " + path + " ..."); + FTPFile[] filesAndDirs = client.listFiles(path); + ArrayList files = new ArrayList<>(); + ArrayList dirs = new ArrayList<>(); + + for (FTPFile f : filesAndDirs) + { + if (!f.isDirectory()) + { + files.add(f); + } + else + { + dirs.add(f); + } + } + + for (FTPFile d : dirs) + { + String subPath = path + "/" + d.getName(); + FTPFile[] subFiles = getAllFileList(subPath); + + for (FTPFile f : subFiles) + { + files.add(f); + } + } + Log.d(TAG, " getAllFileList : got " + files.size() + "files from " + path); + return files.toArray(new FTPFile[files.size()]); + } + + //------------Downloading----------- /** * call to download a File from current dir @@ -140,10 +264,15 @@ public FTPFile[] getFileList() throws IOException * @param downloadPath Path to write to * @throws IOException couldn't download from current dir */ - public void downloadFile(String remoteFileName, String downloadPath) throws IOException + protected boolean downloadFile(String remoteFileName, String downloadPath) throws IOException { - + if (client == null) + { + Log.e(TAG, "downloadFile : wasnt connected to server, call connect() first"); + return false; + } File downloadFile = new File(MAP_FILE_PATH, remoteFileName); + client.changeWorkingDirectory(downloadPath); OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(downloadFile)); InputStream inputStream = client.retrieveFileStream(remoteFileName); byte[] bytesArray = new byte[4096]; @@ -165,29 +294,8 @@ public void downloadFile(String remoteFileName, String downloadPath) throws IOEx outputStream.close(); inputStream.close(); - + return true; } - /** - * closes connection - * pls always use at the end !!!! - */ - public void closeConnection() - { - if (client == null) - { - Log.i(TAG, "Nothing to close, the FTPClient wasn't initialized"); - return; - } - //be polite and logout & close the connection before the application finishes - try - { - client.logout(); - client.disconnect(); - } - catch (IOException e) - { - Log.e(TAG, "Could not logout"); - } - } + } diff --git a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskDirListing.java b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskDirListing.java new file mode 100644 index 0000000..cee91f0 --- /dev/null +++ b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskDirListing.java @@ -0,0 +1,118 @@ +package de.htwBerlin.ois.ServerCommunication; + +import android.content.Context; +import android.os.AsyncTask; +import android.util.Log; + +import org.apache.commons.net.ftp.FTPFile; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; + +import de.htwBerlin.ois.FileStructure.RemoteDirectory; + +/** + * Async task that lists directories hosted on FTP Remote Server + * + * @author WilliBoelke + */ +public class FtpTaskDirListing extends AsyncTask +{ + + + //------------Instance Variables------------ + + private static final SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yy"); + /** + * Log Tag + */ + private final String TAG = getClass().getSimpleName(); + /** + * The list to be filled with remote directories + */ + private ArrayList directoryList; + /** + * Implementation of the {@link AsyncResponse} interface + * (To be implemented when initializing this class) + */ + private AsyncResponse delegate; + /** + * Context + */ + private WeakReference context; + /** + * The path to the directory + */ + private String path; + + + //------------Constructors------------ + + /** + * Public Constructor + * + * @param context + * @param path + * @param asyncResponse + */ + public FtpTaskDirListing(Context context, String path, AsyncResponse asyncResponse) + { + Log.d(TAG, "Constructor : new FtpTaskDirListing with : path = " + path); + this.delegate = asyncResponse; + this.path = path; + this.context = new WeakReference(context); + } + + + //------------AsyncTask Implementation------------ + + @Override + protected String doInBackground(Void... params) + { + directoryList = new ArrayList<>(); + Log.d(TAG, "doingInBackground : initializing new FtpClient "); + FtpClient ftpClient = new FtpClient(); + ftpClient.connect(); + Log.d(TAG, "doingInBackground : connected to FtpClient"); + + FTPFile[] files = new FTPFile[0]; + try + { + Log.d(TAG, "doingInBackground : trying to get directories"); + files = ftpClient.getDirList(path); + } + catch (IOException e) + { + Log.e(TAG, "doingInBackground : something went wrong while while retrieving the directories"); + e.printStackTrace(); + } + + for (FTPFile ftpFile : files) + { + Date date = ftpFile.getTimestamp().getTime(); + RemoteDirectory dir = new RemoteDirectory(ftpFile.getName(), sdf.format(date.getTime())); + directoryList.add(dir); + Log.d(TAG, "doingInBackground : got dir " + dir.toString()); + } + Log.d(TAG, "doingInBackground : closing server connection"); + ftpClient.closeConnection(); + return null; + } + + @Override + protected void onPostExecute(String result) + { + if (directoryList.size() == 0) + { + Log.e(TAG, "Server not available or empty"); + } + else + { + Log.i(TAG, "Found " + directoryList.size() + " directories"); + delegate.getRemoteDirectories(this.directoryList); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileDownloading.java b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileDownloading.java index 3c6a5a5..d6dcb4a 100644 --- a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileDownloading.java +++ b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileDownloading.java @@ -2,19 +2,13 @@ import android.content.Context; import android.os.AsyncTask; -import android.os.Environment; import android.util.Log; import android.widget.Toast; import java.io.IOException; import java.lang.ref.WeakReference; -import de.htwBerlin.ois.FileStructure.OhdmFile; - -import static de.htwBerlin.ois.ServerCommunication.Variables.FTP_Port; -import static de.htwBerlin.ois.ServerCommunication.Variables.SERVER_IP; -import static de.htwBerlin.ois.ServerCommunication.Variables.USER_NAME; -import static de.htwBerlin.ois.ServerCommunication.Variables.USER_PASSWORD; +import de.htwBerlin.ois.FileStructure.RemoteFile; /** * Asynctask that downloads files from FTP Remote server @@ -22,40 +16,49 @@ * @author morelly_t1 * @author WilliBoelke */ -public class FtpTaskFileDownloading extends AsyncTask +public class FtpTaskFileDownloading extends AsyncTask { - private final String TAG = getClass().getSimpleName(); - private static final String MAP_FILE_PATH = Environment.getExternalStorageDirectory().toString() + "/OHDM"; + //------------Instance Variables------------ + private final String TAG = getClass().getSimpleName(); + private final String path; private WeakReference context; private FtpClient ftpClient; - public FtpTaskFileDownloading(Context context) + + //------------Constructors------------ + + public FtpTaskFileDownloading(Context context, String path) { + Log.d(TAG, "Constructor : new FtpTaskFileDownloading with : path = " + path); + this.path = path; this.context = new WeakReference(context); } - @Override - protected void onPreExecute() - { - super.onPreExecute(); - } + + //------------AsyncTask Implementation------------ @Override - protected Long doInBackground(OhdmFile... ohdmFile) + protected Long doInBackground(RemoteFile... ohdmFile) { - + Log.d(TAG, "doingInBackground : initializing new FtpClient "); ftpClient = new FtpClient(); - ftpClient.connect(SERVER_IP, FTP_Port, USER_NAME, USER_PASSWORD); + ftpClient.connect(); + Log.d(TAG, "doingInBackground : connected to FtpClient"); try { - ftpClient.downloadFile(ohdmFile[0].getFilename(), ohdmFile[0].getFilename()); + Log.d(TAG, "doingInBackground : starting file download..."); + ftpClient.downloadFile(ohdmFile[0].getFilename(), this.path); + Log.d(TAG, "doingInBackground : download finished successfully"); } catch (IOException e) { + Log.d(TAG, "doingInBackground : something went wrong while downloading the file"); e.printStackTrace(); } + Log.d(TAG, "doingInBackground : closing server connection"); + ftpClient.closeConnection(); return null; } @@ -63,6 +66,6 @@ protected Long doInBackground(OhdmFile... ohdmFile) protected void onPostExecute(Long params) { Context context = this.context.get(); - Toast.makeText(context, "Download Finished!", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Download Finished", Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileListing.java b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileListing.java index ccfe208..310aa6c 100644 --- a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileListing.java +++ b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/FtpTaskFileListing.java @@ -3,7 +3,6 @@ import android.content.Context; import android.os.AsyncTask; import android.util.Log; -import android.widget.Toast; import org.apache.commons.net.ftp.FTPFile; @@ -13,79 +12,120 @@ import java.util.ArrayList; import java.util.Date; -import de.htwBerlin.ois.FileStructure.OhdmFile; - -import static de.htwBerlin.ois.ServerCommunication.Variables.FTP_Port; -import static de.htwBerlin.ois.ServerCommunication.Variables.SERVER_IP; -import static de.htwBerlin.ois.ServerCommunication.Variables.USER_NAME; -import static de.htwBerlin.ois.ServerCommunication.Variables.USER_PASSWORD; +import de.htwBerlin.ois.FileStructure.RemoteFile; /** * Async task that lists files hosted on FTP Remote Server * * @author morelly_t1 + * @author WilliBoelke */ public class FtpTaskFileListing extends AsyncTask { - private static final SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yy HH:mm"); - private static final String TAG = "FtpTaskFileListing"; - private ArrayList ohdmFiles; + //------------Instance Variables------------ + + private static final SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yy"); + /** + * Log Tag + */ + private final String TAG = getClass().getSimpleName(); + /** + * The list to be filled with remote ohdmFiles + */ + private ArrayList remoteFiles; + /** + * Implementation of the {@link AsyncResponse} interface + * (To be implemented when initializing this class) + */ private AsyncResponse delegate; + /** + * Context + */ private WeakReference context; - private FtpClient ftpClient; + private boolean includeSubDirs; + /** + * The path to the directory + */ + private String path; + + + - public FtpTaskFileListing( AsyncResponse asyncResponse, Context context) + //------------Constructors------------ + + /** + * Public Constructor + * + * @param context + * @param path + * @param asyncResponse + */ + public FtpTaskFileListing(Context context, String path, boolean includeSubDirs, AsyncResponse asyncResponse) { + Log.d(TAG, "Constructor : new FtpTaskFileListing with : path = " + path + " includeSubDirs = " + includeSubDirs); + this.includeSubDirs = includeSubDirs; this.delegate = asyncResponse; + this.path = path; this.context = new WeakReference(context); } - @Override - protected void onPreExecute() - { - Log.i(TAG, "onPreExecute: "); - super.onPreExecute(); - } + + //------------AsyncTask Implementation------------ + @Override protected String doInBackground(Void... params) { - ohdmFiles = new ArrayList<>(); - ftpClient = new FtpClient(); - ftpClient.connect(SERVER_IP, FTP_Port, USER_NAME, USER_PASSWORD); + remoteFiles = new ArrayList<>(); + Log.d(TAG, "doingInBackground : initializing new FtpClient "); + FtpClient ftpClient = new FtpClient(); + ftpClient.connect(); + Log.d(TAG, "doingInBackground : connected to FtpClient"); + FTPFile[] files = new FTPFile[0]; try { - files = ftpClient.getFileList(); + if (includeSubDirs == true) + { + Log.d(TAG, "doingInBackground : getting all files including sub dirs..."); + files = ftpClient.getAllFileList(path); + } + else + { + Log.d(TAG, "doingInBackground : getting all files..."); + files = ftpClient.getFileList(path); + } } catch (IOException e) { + Log.e(TAG, "something went wrong while retrieving files from the FTP Server"); e.printStackTrace(); } - for (FTPFile ftpFile : files) - { - Date date = ftpFile.getTimestamp().getTime(); - OhdmFile ohdm = new OhdmFile(ftpFile.getName(), (ftpFile.getSize() / 1024), sdf.format(date.getTime()), Boolean.FALSE); - ohdmFiles.add(ohdm); - Log.i(TAG, ohdm.toString()); - } - + { + Date date = ftpFile.getTimestamp().getTime(); + RemoteFile ohdm = new RemoteFile(ftpFile.getName(), (ftpFile.getSize() / 1024), sdf.format(date.getTime()), Boolean.FALSE); + remoteFiles.add(ohdm); + Log.d(TAG, "doingInBackground : got file : " + ohdm.toString()); + } + Log.d(TAG, "doingInBackground : finished - closing connection : "); + ftpClient.closeConnection(); return null; } @Override protected void onPostExecute(String result) { - Context context = this.context.get(); - if (ohdmFiles.size() == 0) - Toast.makeText(context, "Download Service not available", Toast.LENGTH_SHORT).show(); + if (remoteFiles.size() == 0) + { + Log.e(TAG, "Server not available or empty"); + } else - Toast.makeText(context, "Found " + ohdmFiles.size() + " maps!", Toast.LENGTH_SHORT).show(); - delegate.getOhdmFiles(this.ohdmFiles); + { + Log.d(TAG, "Found " + remoteFiles.size() + " files from server"); + delegate.getOhdmFiles(this.remoteFiles); + } } - - } diff --git a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/HTTPRequestNewMap.java b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/HTTPRequestNewMap.java index 313d255..cdacf35 100644 --- a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/HTTPRequestNewMap.java +++ b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/HTTPRequestNewMap.java @@ -5,14 +5,15 @@ import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.ProtocolException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; import javax.net.ssl.HttpsURLConnection; @@ -31,83 +32,93 @@ public class HTTPRequestNewMap extends AsyncTask { + + //------------Instance Variables------------ + + /** + * Log tag + */ private final String TAG = this.getClass().getSimpleName(); + /** + * A date as String + */ private String date; + /** + * 8 Coordinates (Lat/Long) as String + */ private String coordinates; + /** + * map name + */ private String name; + /** + * Remote server url + */ private URL url; + + //------------Constructors------------ + /** * Public constructor - * @param date - * @param coordinates - * @param name + * + * @param date the date of the requested map + * @param coordinates the coordinates of the requested map + * @param name the name of the requested map */ public HTTPRequestNewMap(String date, String coordinates, String name) { + Log.d(TAG, "Constructor: new HttpRequestNewMap with : date = " + date + " coords = " + coordinates + " name = " + name); this.date = date; this.name = name; this.coordinates = coordinates; } + + //------------AsyncTask Implementation------------ + @Override protected void onPreExecute() { - Log.i(TAG, "onPreExecute: "); + Log.d(TAG, "onPreExecute: building url ...."); try { url = new URL("http://" + SERVER_IP + ":" + HTTP_PORT + "/request"); + Log.d(TAG, "onPreExecute: Url = " + url); } catch (MalformedURLException e) { + Log.e(TAG, "Something went wrong while building the URL"); e.printStackTrace(); } - super.onPreExecute(); } - /** - * Builds a string as accepted by the server - * example: - * name=mapname&coords=13.005,15.123_13.005,15.123_13.005,15.123_13.005,15.123_13.005,15.123&date=2117-12-11 - * @return the String - */ - private String buildParamsString() - { - StringBuilder sb = new StringBuilder(); - sb.append("name="); - sb.append(this.name); - sb.append("&coords="); - sb.append(this.coordinates); - sb.append("&date="); - sb.append(this.date); - - return sb.toString(); - } - @Override protected String doInBackground(Void... params) { - String response = null; try { + Log.d(TAG, "doingInBackground : connecting with server " + url); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(15000); conn.setConnectTimeout(15000); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); + Log.d(TAG, "doingInBackground : connected successfully"); - + Log.d(TAG, "doingInBackground : writing to server, request = " + this.buildParamsString()); OutputStream os = conn.getOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8)); writer.write(this.buildParamsString()); writer.flush(); writer.close(); os.close(); + Log.d(TAG, "doingInBackground : transmission to server finished "); + Log.d(TAG, "doingInBackground : getting server response code..."); int responseCode = conn.getResponseCode(); - if (responseCode == HttpsURLConnection.HTTP_OK) { String line; @@ -116,19 +127,44 @@ protected String doInBackground(Void... params) { response += line; } + Log.d(TAG, "doingInBackground: server response : " + response); } - else - { - response = ""; - - } } - catch (Exception e) + catch (ProtocolException e) + { + Log.e(TAG, "doingInBackground : couldnt connect with the server " + url); + e.printStackTrace(); + } + catch (IOException e) { + Log.e(TAG, "doingInBackground : couldnt write to the server "); e.printStackTrace(); } - Log.i(TAG, "Server response : " + response); return null; } + + //------------Others------------ + + /** + * Builds a string as accepted by the server + * example: + * name=mapname&coords=13.005,15.123_13.005,15.123_13.005,15.123_13.005,15.123_13.005,15.123&date=2117-12-11 + * + * @return the String + */ + private String buildParamsString() + { + Log.e(TAG, "buildParamsString : building params string..."); + StringBuilder sb = new StringBuilder(); + sb.append("name="); + sb.append(this.name); + sb.append("&coords="); + sb.append(this.coordinates); + sb.append("&date="); + sb.append(this.date); + Log.e(TAG, "buildParamsString : builded params string"); + return sb.toString(); + } + } diff --git a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/Variables.java b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/Variables.java index 47f68ee..1fc71cf 100644 --- a/app/src/main/java/de/htwBerlin/ois/ServerCommunication/Variables.java +++ b/app/src/main/java/de/htwBerlin/ois/ServerCommunication/Variables.java @@ -5,15 +5,18 @@ */ public class Variables { + + public static final String MOST_RECENT_PATH = "/most_recent"; + public static final String LAST_REQUEST_PATH = "/last_request"; /** * The remote server ip * (For localhost in android emulator set to "10.0.2.2") */ - protected static final String SERVER_IP = "192.168.178.27"; + protected static final String SERVER_IP = "141.45.146.200"; /** * The remote server port for HTTP requests */ - protected static final int HTTP_PORT = 8080; + protected static final int HTTP_PORT = 5001; /** * the remote server port for ftp requests */ @@ -26,4 +29,9 @@ public class Variables * The remote server user password */ protected static final String USER_PASSWORD = "H!3r0glyph Sat3llite Era$er"; + + private Variables() + { + //ot to be initialized + } } diff --git a/app/src/main/res/drawable/bottom_nav_icon_download_black.xml b/app/src/main/res/drawable/bottom_nav_icon_download_black.xml index a127690..3999ef0 100644 --- a/app/src/main/res/drawable/bottom_nav_icon_download_black.xml +++ b/app/src/main/res/drawable/bottom_nav_icon_download_black.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/bottom_nav_icon_download_white.xml b/app/src/main/res/drawable/bottom_nav_icon_download_white.xml index 066a6df..e82f1fd 100644 --- a/app/src/main/res/drawable/bottom_nav_icon_download_white.xml +++ b/app/src/main/res/drawable/bottom_nav_icon_download_white.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/bottom_nav_icon_home_black.xml b/app/src/main/res/drawable/bottom_nav_icon_home_black.xml index 9a700ce..c0e1c7f 100644 --- a/app/src/main/res/drawable/bottom_nav_icon_home_black.xml +++ b/app/src/main/res/drawable/bottom_nav_icon_home_black.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/bottom_nav_icon_home_white.xml b/app/src/main/res/drawable/bottom_nav_icon_home_white.xml index 8f17191..8519a4c 100644 --- a/app/src/main/res/drawable/bottom_nav_icon_home_white.xml +++ b/app/src/main/res/drawable/bottom_nav_icon_home_white.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/bottom_nav_icon_navigation_black.xml b/app/src/main/res/drawable/bottom_nav_icon_navigation_black.xml index e6705e1..0c22224 100644 --- a/app/src/main/res/drawable/bottom_nav_icon_navigation_black.xml +++ b/app/src/main/res/drawable/bottom_nav_icon_navigation_black.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/bottom_nav_icon_navigation_white.xml b/app/src/main/res/drawable/bottom_nav_icon_navigation_white.xml index e515c3c..a882b74 100644 --- a/app/src/main/res/drawable/bottom_nav_icon_navigation_white.xml +++ b/app/src/main/res/drawable/bottom_nav_icon_navigation_white.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 1e528a3..6811c7d 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,74 +1,170 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:viewportHeight="108"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_search_white.xml b/app/src/main/res/drawable/ic_search_white.xml new file mode 100644 index 0000000..be5ad99 --- /dev/null +++ b/app/src/main/res/drawable/ic_search_white.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/icon_add.xml b/app/src/main/res/drawable/icon_add.xml index e3979cd..bbda803 100644 --- a/app/src/main/res/drawable/icon_add.xml +++ b/app/src/main/res/drawable/icon_add.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/icon_current_map.xml b/app/src/main/res/drawable/icon_current_map.xml index ec284fa..2fb4a17 100644 --- a/app/src/main/res/drawable/icon_current_map.xml +++ b/app/src/main/res/drawable/icon_current_map.xml @@ -5,7 +5,6 @@ android:viewportHeight="18"> - + android:pathData="M9 0a9 9 0 1 0 0 18A9 9 0 1 0 9 0z" /> + \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_search_black.xml b/app/src/main/res/drawable/icon_search_black.xml new file mode 100644 index 0000000..affc7ba --- /dev/null +++ b/app/src/main/res/drawable/icon_search_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/primary_button.xml b/app/src/main/res/drawable/primary_button.xml index 6b5521d..05555a8 100644 --- a/app/src/main/res/drawable/primary_button.xml +++ b/app/src/main/res/drawable/primary_button.xml @@ -1,14 +1,10 @@ - - + + - + diff --git a/app/src/main/res/drawable/primary_button_blocked.xml b/app/src/main/res/drawable/primary_button_blocked.xml index 9a4933c..f05c8ee 100644 --- a/app/src/main/res/drawable/primary_button_blocked.xml +++ b/app/src/main/res/drawable/primary_button_blocked.xml @@ -5,7 +5,7 @@ android:viewportHeight="42"> + android:strokeColor="#000" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/primary_button_default.xml b/app/src/main/res/drawable/primary_button_default.xml index e1fff64..e78e094 100644 --- a/app/src/main/res/drawable/primary_button_default.xml +++ b/app/src/main/res/drawable/primary_button_default.xml @@ -1,11 +1,11 @@ - - - + android:width="185dp" + android:height="50dp" + android:viewportWidth="185" + android:viewportHeight="50"> + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/primary_button_pressed.xml b/app/src/main/res/drawable/primary_button_pressed.xml index 4e9e56f..c022a4e 100644 --- a/app/src/main/res/drawable/primary_button_pressed.xml +++ b/app/src/main/res/drawable/primary_button_pressed.xml @@ -5,5 +5,5 @@ android:viewportHeight="42"> + android:pathData="M0 4c0-2.21 1.79-4 4-4h169c2.21 0 4 1.79 4 4v34c0 2.21-1.79 4-4 4h-169c-2.21 0-4-1.79-4-4z" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/recycler_item_gradient.xml b/app/src/main/res/drawable/recycler_item_gradient.xml index e31d637..941e4a5 100644 --- a/app/src/main/res/drawable/recycler_item_gradient.xml +++ b/app/src/main/res/drawable/recycler_item_gradient.xml @@ -4,21 +4,20 @@ android:height="74dp" android:viewportWidth="368" android:viewportHeight="74"> - + + android:type="linear"> + android:offset="0" /> + android:offset="1" /> diff --git a/app/src/main/res/drawable/recycler_item_latest_gradient.xml b/app/src/main/res/drawable/recycler_item_latest_gradient.xml new file mode 100644 index 0000000..54cebc0 --- /dev/null +++ b/app/src/main/res/drawable/recycler_item_latest_gradient.xml @@ -0,0 +1,24 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/toolbar_menu_item_info_black.xml b/app/src/main/res/drawable/toolbar_menu_item_info_black.xml index 4efbbbc..87f21f7 100644 --- a/app/src/main/res/drawable/toolbar_menu_item_info_black.xml +++ b/app/src/main/res/drawable/toolbar_menu_item_info_black.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/toolbar_menu_item_settings_black.xml b/app/src/main/res/drawable/toolbar_menu_item_settings_black.xml index 24a5623..a671514 100644 --- a/app/src/main/res/drawable/toolbar_menu_item_settings_black.xml +++ b/app/src/main/res/drawable/toolbar_menu_item_settings_black.xml @@ -1,9 +1,9 @@ + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z" /> diff --git a/app/src/main/res/layout-land/download_recycler_item.xml b/app/src/main/res/layout-land/download_recycler_item.xml deleted file mode 100644 index f00ecde..0000000 --- a/app/src/main/res/layout-land/download_recycler_item.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_about.xml b/app/src/main/res/layout-land/fragment_about.xml index c9d4521..139f01e 100644 --- a/app/src/main/res/layout-land/fragment_about.xml +++ b/app/src/main/res/layout-land/fragment_about.xml @@ -6,7 +6,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="?attr/backgroundColor" - tools:context=".Fragments.AboutFragment"> + tools:context=".Fragments.FramentAbout"> + tools:context=".Fragments.FragmentHome"> + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="@+id/allow_access_location_tv" /> diff --git a/app/src/main/res/layout-land/fragment_request_map.xml b/app/src/main/res/layout-land/fragment_request_map.xml index fb617ae..cb72494 100644 --- a/app/src/main/res/layout-land/fragment_request_map.xml +++ b/app/src/main/res/layout-land/fragment_request_map.xml @@ -12,204 +12,134 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - + android:background="?attr/foreground"> - + - + - + - + - - - - - - - - + android:typeface="normal" + app:layout_constraintBottom_toTopOf="@+id/long_bottom_et" + app:layout_constraintEnd_toStartOf="@+id/lat_right_et" + app:layout_constraintStart_toEndOf="@+id/lat_left_et" + app:layout_constraintTop_toBottomOf="@+id/long_top_et" + app:layout_constraintVertical_bias="0.666" /> + + diff --git a/app/src/main/res/layout-land/recycler_item_horizonal.xml b/app/src/main/res/layout-land/recycler_item_horizonal.xml new file mode 100644 index 0000000..bfaedbf --- /dev/null +++ b/app/src/main/res/layout-land/recycler_item_horizonal.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + +