From be5e8cc868915df9f1381ced9c06d45da35e839c Mon Sep 17 00:00:00 2001
From: Apostolof
Date: Mon, 26 Dec 2016 22:34:21 +0200
Subject: [PATCH] More code cleanup and (javadoc style) commenting, FileManager
begin
---
.../mthmmy/activities/main/MainActivity.java | 6 +-
.../activities/profile/ProfileActivity.java | 26 +-
.../activities/topic/TopicActivity.java | 293 +++++++-----------
.../mthmmy/activities/topic/TopicAdapter.java | 48 ++-
.../mthmmy/activities/topic/TopicParser.java | 43 ++-
.../main/java/gr/thmmy/mthmmy/data/Post.java | 10 +-
.../mthmmy/utils/FileManager/ThmmyFile.java | 183 +++++++++++
7 files changed, 382 insertions(+), 227 deletions(-)
create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/FileManager/ThmmyFile.java
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
index 9362f14a..24f4278a 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
@@ -18,6 +18,8 @@ import gr.thmmy.mthmmy.activities.main.recent.RecentFragment;
import gr.thmmy.mthmmy.activities.topic.TopicActivity;
import gr.thmmy.mthmmy.data.TopicSummary;
+import static gr.thmmy.mthmmy.activities.topic.TopicActivity.EXTRAS_TOPIC_TITLE;
+import static gr.thmmy.mthmmy.activities.topic.TopicActivity.EXTRAS_TOPIC_URL;
import static gr.thmmy.mthmmy.session.SessionManager.LOGGED_OUT;
public class MainActivity extends BaseActivity implements RecentFragment.RecentFragmentInteractionListener, ForumFragment.ForumFragmentInteractionListener {
@@ -83,8 +85,8 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
@Override
public void onFragmentInteraction(TopicSummary topicSummary) {
Intent i = new Intent(MainActivity.this, TopicActivity.class);
- i.putExtra("TOPIC_URL", topicSummary.getTopicUrl());
- i.putExtra("TOPIC_TITLE", topicSummary.getTitle());
+ i.putExtra(EXTRAS_TOPIC_URL, topicSummary.getTopicUrl());
+ i.putExtra(EXTRAS_TOPIC_TITLE, topicSummary.getTitle());
startActivity(i);
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
index 00db479d..94f2e13d 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
@@ -72,6 +72,7 @@ public class ProfileActivity extends BaseActivity {
* {@link ArrayList} of Strings used to hold profile's information. Data are added in {@link ProfileTask}.
*/
private ArrayList parsedProfileData;
+ private ProfileTask profileTask;
private static final int THUMBNAIL_SIZE = 200;
@Override
@@ -82,7 +83,7 @@ public class ProfileActivity extends BaseActivity {
PACKAGE_NAME = getApplicationContext().getPackageName();
Bundle extras = getIntent().getExtras();
- //Initialize graphic elements
+ //Initializes graphic elements
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(null);
setSupportActionBar(toolbar);
@@ -90,7 +91,9 @@ public class ProfileActivity extends BaseActivity {
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
+
createDrawer();
+
progressBar = (ProgressBar) findViewById(R.id.progressBar);
userThumbnail = (ImageView) findViewById(R.id.user_thumbnail);
@@ -100,24 +103,19 @@ public class ProfileActivity extends BaseActivity {
replyFAB = (FloatingActionButton) findViewById(R.id.profile_fab);
replyFAB.setEnabled(false);
-
replyFAB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE);
int tmp_curr_status = sharedPrefs.getInt(LOGIN_STATUS, -1);
if (tmp_curr_status == -1) {
+ Report.e(TAG, "Error while getting LOGIN_STATUS");
new AlertDialog.Builder(ProfileActivity.this)
.setTitle("ERROR!")
- .setMessage("An error occurred while trying to find your LOGIN_STATUS.\n" +
- "Please sent below info to developers:\n"
- + getLocalClassName() + "." + "l"
- + Thread.currentThread().getStackTrace()[1].getLineNumber())
+ .setMessage("An error occurred while trying to find your LOGIN_STATUS.")
.setNeutralButton("Dismiss", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
- //Todo
- //Maybe sent info back to developers?
}
})
.show();
@@ -146,7 +144,17 @@ public class ProfileActivity extends BaseActivity {
}
});
- new ProfileTask().execute(extras.getString(EXTRAS_PROFILE_URL)); //Attempt data parsing
+ //Gets info
+ parsedProfileData = new ArrayList<>();
+ profileTask = new ProfileTask();
+ profileTask.execute(extras.getString(EXTRAS_PROFILE_URL)); //Attempt data parsing
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (profileTask != null && profileTask.getStatus() != AsyncTask.Status.RUNNING)
+ profileTask.cancel(true);
}
/**
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
index a3148293..9d7f8544 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
@@ -1,25 +1,19 @@
package gr.thmmy.mthmmy.activities.topic;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
-import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
-import android.util.Log;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
-import android.webkit.MimeTypeMap;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -28,8 +22,6 @@ import android.widget.Toast;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -40,34 +32,47 @@ import gr.thmmy.mthmmy.activities.LoginActivity;
import gr.thmmy.mthmmy.activities.base.BaseActivity;
import gr.thmmy.mthmmy.data.Post;
import mthmmy.utils.Report;
-import okhttp3.Call;
-import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.session.SessionManager.LOGGED_IN;
import static gr.thmmy.mthmmy.session.SessionManager.LOGIN_STATUS;
+/**
+ * Activity for topics. When creating an Intent of this activity you need to bundle a String
+ * containing this topics's url using the key {@link #EXTRAS_TOPIC_URL} and a String containing
+ * this topic's title using the key {@link #EXTRAS_TOPIC_TITLE}.
+ */
@SuppressWarnings("unchecked")
public class TopicActivity extends BaseActivity {
-
- //-----------------------------------------CLASS VARIABLES------------------------------------------
+ //Class variables
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
+ @SuppressWarnings("unused")
+ private static final String TAG = "TopicActivity";
+ /**
+ * The key to use when putting topic's url String to {@link TopicActivity}'s Bundle.
+ */
+ public static final String EXTRAS_TOPIC_URL = "TOPIC_URL";
+ /**
+ * The key to use when putting topic's title String to {@link TopicActivity}'s Bundle.
+ */
+ public static final String EXTRAS_TOPIC_TITLE = "TOPIC_TITLE";
+ static String PACKAGE_NAME;
private TopicTask topicTask;
-
- /* --Posts-- */
+ //About posts
private List postsList;
static final int NO_POST_FOCUS = -1;
static int postFocus = NO_POST_FOCUS;
- //Quote
+ //Quotes
public static final ArrayList toQuoteList = new ArrayList<>();
- /* --Topic's pages-- */
+ //Topic's pages
private int thisPage = 1;
public static String base_url = "";
private int numberOfPages = 1;
private final SparseArray pagesUrls = new SparseArray<>();
//Page select
- private TextView pageIndicator;
private final Handler repeatUpdateHandler = new Handler();
private final long INITIAL_DELAY = 500;
private boolean autoIncrement = false;
@@ -75,22 +80,20 @@ public class TopicActivity extends BaseActivity {
private static final int SMALL_STEP = 1;
private static final int LARGE_STEP = 10;
private Integer pageRequestValue;
-
+ //Bottom navigation graphics
private ImageButton firstPage;
private ImageButton previousPage;
+ private TextView pageIndicator;
private ImageButton nextPage;
private ImageButton lastPage;
-
//Other variables
private ProgressBar progressBar;
- @SuppressWarnings("unused")
- private static final String TAG = "TopicActivity";
private String topicTitle;
private FloatingActionButton replyFAB;
private String parsedTitle;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
- static String PACKAGE_NAME;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -98,11 +101,10 @@ public class TopicActivity extends BaseActivity {
setContentView(R.layout.activity_topic);
PACKAGE_NAME = getApplicationContext().getPackageName();
-
Bundle extras = getIntent().getExtras();
- topicTitle = getIntent().getExtras().getString("TOPIC_TITLE");
+ topicTitle = extras.getString("TOPIC_TITLE");
- //Initialize toolbar, drawer and ProgressBar
+ //Initializes graphics
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(topicTitle);
setSupportActionBar(toolbar);
@@ -115,44 +117,29 @@ public class TopicActivity extends BaseActivity {
progressBar = (ProgressBar) findViewById(R.id.progressBar);
- postsList = new ArrayList<>();
+ postsList = new ArrayList<>();
- firstPage = (ImageButton) findViewById(R.id.page_first_button);
- previousPage = (ImageButton) findViewById(R.id.page_previous_button);
- pageIndicator = (TextView) findViewById(R.id.page_indicator);
- nextPage = (ImageButton) findViewById(R.id.page_next_button);
- lastPage = (ImageButton) findViewById(R.id.page_last_button);
-
- initDecrementButton(firstPage, LARGE_STEP);
- initDecrementButton(previousPage, SMALL_STEP);
- initIncrementButton(nextPage, SMALL_STEP);
- initIncrementButton(lastPage, LARGE_STEP);
-
- firstPage.setEnabled(false);
- previousPage.setEnabled(false);
- nextPage.setEnabled(false);
- lastPage.setEnabled(false);
+ recyclerView = (RecyclerView) findViewById(R.id.topic_recycler_view);
+ recyclerView.setHasFixedSize(true);
+ layoutManager = new LinearLayoutManager(getApplicationContext());
+ recyclerView.setLayoutManager(layoutManager);
+ recyclerView.setAdapter(new TopicAdapter(getApplicationContext(), postsList));
replyFAB = (FloatingActionButton) findViewById(R.id.topic_fab);
replyFAB.setEnabled(false);
-
replyFAB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE);
int tmp_curr_status = sharedPrefs.getInt(LOGIN_STATUS, -1);
if (tmp_curr_status == -1) {
+ Report.e(TAG, "Error while getting LOGIN_STATUS");
new AlertDialog.Builder(TopicActivity.this)
.setTitle("ERROR!")
- .setMessage("An error occurred while trying to find your LOGIN_STATUS.\n" +
- "Please sent below info to developers:\n"
- + getLocalClassName() + "." + "l"
- + Thread.currentThread().getStackTrace()[1].getLineNumber())
+ .setMessage("An error occurred while trying to find your LOGIN_STATUS.")
.setNeutralButton("Dismiss", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
- //Todo
- //Maybe sent info back to developers?
}
})
.show();
@@ -181,14 +168,26 @@ public class TopicActivity extends BaseActivity {
}
});
- recyclerView = (RecyclerView) findViewById(R.id.topic_recycler_view);
- recyclerView.setHasFixedSize(true);
- layoutManager = new LinearLayoutManager(getApplicationContext());
- recyclerView.setLayoutManager(layoutManager);
- recyclerView.setAdapter(new TopicAdapter(getApplicationContext(), postsList));
+ //Sets bottom navigation bar
+ firstPage = (ImageButton) findViewById(R.id.page_first_button);
+ previousPage = (ImageButton) findViewById(R.id.page_previous_button);
+ pageIndicator = (TextView) findViewById(R.id.page_indicator);
+ nextPage = (ImageButton) findViewById(R.id.page_next_button);
+ lastPage = (ImageButton) findViewById(R.id.page_last_button);
+
+ initDecrementButton(firstPage, LARGE_STEP);
+ initDecrementButton(previousPage, SMALL_STEP);
+ initIncrementButton(nextPage, SMALL_STEP);
+ initIncrementButton(lastPage, LARGE_STEP);
+
+ firstPage.setEnabled(false);
+ previousPage.setEnabled(false);
+ nextPage.setEnabled(false);
+ lastPage.setEnabled(false);
+ //Gets posts
topicTask = new TopicTask();
- topicTask.execute(extras.getString("TOPIC_URL")); //Attempt data parsing
+ topicTask.execute(extras.getString(EXTRAS_TOPIC_URL)); //Attempt data parsing
}
@Override
@@ -260,8 +259,8 @@ public class TopicActivity extends BaseActivity {
changePage(0);
return;
}
- //Clicked and holden
- autoDecrement = false; //Stop incrementing
+ //Clicked and hold
+ autoDecrement = false; //Stop decrementing
decrementPageRequestValue(step);
changePage(pageRequestValue - 1);
}
@@ -296,10 +295,6 @@ public class TopicActivity extends BaseActivity {
} else
pageRequestValue = numberOfPages;
pageIndicator.setText(pageRequestValue + "/" + String.valueOf(numberOfPages));
- if (pageRequestValue >= 1000)
- pageIndicator.setTextSize(16);
- else
- pageIndicator.setTextSize(20);
}
private void decrementPageRequestValue(int step) {
@@ -308,10 +303,6 @@ public class TopicActivity extends BaseActivity {
else
pageRequestValue = 1;
pageIndicator.setText(pageRequestValue + "/" + String.valueOf(numberOfPages));
- if (numberOfPages >= 1000)
- pageIndicator.setTextSize(16);
- else
- pageIndicator.setTextSize(20);
}
private void changePage(int pageRequested) {
@@ -326,15 +317,24 @@ public class TopicActivity extends BaseActivity {
}
//------------------------------------BOTTOM NAV BAR METHODS END------------------------------------
- //---------------------------------------TOPIC ASYNC TASK-------------------------------------------
+ /**
+ * An {@link AsyncTask} that handles asynchronous fetching of a topic page and parsing it's
+ * data. {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link RecyclerView#swapAdapter}
+ * to build graphics.
+ *
+ *
Calling ProfileTask's {@link AsyncTask#execute execute} method needs to have profile's url
+ * as String parameter!
+ */
public class TopicTask extends AsyncTask {
//Class variables
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
private static final String TAG = "TopicTask"; //Separate tag for AsyncTask
private static final int SUCCESS = 0;
private static final int NETWORK_ERROR = 1;
private static final int OTHER_ERROR = 2;
- //Show a progress bar until done
protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE);
replyFAB.setEnabled(false);
@@ -343,9 +343,9 @@ public class TopicActivity extends BaseActivity {
protected Integer doInBackground(String... strings) {
Document document;
base_url = strings[0].substring(0, strings[0].lastIndexOf(".")); //This topic's base url
- String pageUrl = strings[0]; //This page's url
+ String pageUrl = strings[0];
- //Find message focus if present
+ //Finds message focus if present
{
postFocus = NO_POST_FOCUS;
if (pageUrl.contains("msg")) {
@@ -363,7 +363,7 @@ public class TopicActivity extends BaseActivity {
try {
Response response = client.newCall(request).execute();
document = Jsoup.parse(response.body().string());
- parse(document); //Parse data
+ parse(document);
return SUCCESS;
} catch (IOException e) {
Report.i(TAG, "IO Exception", e);
@@ -374,18 +374,26 @@ public class TopicActivity extends BaseActivity {
}
}
- protected void onPostExecute(Integer result) {
- switch (result) {
+ protected void onPostExecute(Integer parseResult) {
+ switch (parseResult) {
case SUCCESS:
- //Parse was successful
- progressBar.setVisibility(ProgressBar.INVISIBLE); //Hide progress bar
- populateLayout(); //Show parsed data
+ progressBar.setVisibility(ProgressBar.INVISIBLE);
+
+ recyclerView.swapAdapter(new TopicAdapter(getApplicationContext(), postsList), false);
+ //Set post focus
+ if (postFocus != NO_POST_FOCUS) {
+ for (int i = postsList.size() - 1; i >= 0; --i) {
+ int currentPostIndex = postsList.get(i).getPostIndex();
+ if (currentPostIndex == postFocus) {
+ layoutManager.scrollToPosition(i);
+ }
+ }
+ }
+ replyFAB.setEnabled(true);
//Set current page
pageIndicator.setText(String.valueOf(thisPage) + "/" + String.valueOf(numberOfPages));
pageRequestValue = thisPage;
- if (numberOfPages >= 1000)
- pageIndicator.setTextSize(16);
firstPage.setEnabled(true);
previousPage.setEnabled(true);
@@ -406,13 +414,18 @@ public class TopicActivity extends BaseActivity {
}
}
- /* Parse method */
- private void parse(Document document) {
- String language = TopicParser.defineLanguage(document);
+ /**
+ * All the parsing a topic needs.
+ *
+ * @param topic {@link Document} object containing this topic's source code
+ * @see org.jsoup.Jsoup Jsoup
+ */
+ private void parse(Document topic) {
+ String language = TopicParser.defineLanguage(topic);
- //Find topic title if missing
+ //Finds topic title if missing
if (topicTitle == null || Objects.equals(topicTitle, "")) {
- parsedTitle = document.select("td[id=top_subject]").first().text();
+ parsedTitle = topic.select("td[id=top_subject]").first().text();
if (parsedTitle.contains("Topic:")) {
parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Topic:") + 7
, parsedTitle.indexOf("(Read") - 2);
@@ -423,11 +436,11 @@ public class TopicActivity extends BaseActivity {
}
}
- { //Find current page's index
- thisPage = TopicParser.parseCurrentPageIndex(document, language);
+ { //Finds current page's index
+ thisPage = TopicParser.parseCurrentPageIndex(topic, language);
}
- { //Find number of pages
- numberOfPages = TopicParser.parseTopicNumberOfPages(document, thisPage, language);
+ { //Finds number of pages
+ numberOfPages = TopicParser.parseTopicNumberOfPages(topic, thisPage, language);
for (int i = 0; i < numberOfPages; i++) {
//Generate each page's url from topic's base url +".15*numberOfPage"
@@ -435,44 +448,20 @@ public class TopicActivity extends BaseActivity {
}
}
- postsList = TopicParser.parseTopic(document, language);
- }
- /* Parse method end */
- }
-//-------------------------------------TOPIC ASYNC TASK END-----------------------------------------
-
-//----------------------------------------POPULATE UI METHOD----------------------------------------
-
- /**
- * This method runs on the main thread. It reads from the postsList and dynamically
- * adds a card for each post to the ScrollView.
- */
- private void populateLayout() {
- recyclerView.swapAdapter(new TopicAdapter(getApplicationContext(), postsList), false);
-
- //Set post focus
- if (postFocus != NO_POST_FOCUS) {
- for (int i = postsList.size() - 1; i >= 0; --i) {
- int currentPostIndex = postsList.get(i).getPostIndex();
- if (currentPostIndex == postFocus) {
- layoutManager.scrollToPosition(i);
- }
- }
+ postsList = TopicParser.parseTopic(topic, language);
}
- replyFAB.setEnabled(true);
}
-//--------------------------------------POPULATE UI METHOD END--------------------------------------
-
-//----------------------------------------REPETITIVE UPDATER----------------------------------------
-
/**
- * This class is used to implement the repetitive incrementPageRequestValue/decrementPageRequestValue of page value
- * when long pressing one of the page navigation buttons.
+ * This class is used to implement the repetitive incrementPageRequestValue/decrementPageRequestValue
+ * of page value when long pressing one of the page navigation buttons.
*/
class RepetitiveUpdater implements Runnable {
private final int step;
+ /**
+ * @param step number of pages to add/subtract on each repetition
+ */
RepetitiveUpdater(int step) {
this.step = step;
}
@@ -488,76 +477,4 @@ public class TopicActivity extends BaseActivity {
}
}
}
-//--------------------------------------REPETITIVE UPDATER END--------------------------------------
-
-//------------------------------METHODS FOR DOWNLOADING ATTACHED FILES------------------------------
-
- /**
- * Create a File
- */
- static void downloadFileAsync(final String downloadUrl, final String fileName, final Context context) {
- Request request = new Request.Builder().url(downloadUrl).build();
-
- getClient().newCall(request).enqueue(new Callback() {
- public void onFailure(Call call, IOException e) {
- e.printStackTrace();
- }
-
- public void onResponse(Call call, Response response) throws IOException {
- if (!response.isSuccessful()) {
- throw new IOException("Failed to download file: " + response);
- }
- File tmpFile = getOutputMediaFile(PACKAGE_NAME, fileName);
- if (tmpFile == null) {
- Report.d(TAG
- , "Error creating media file, check storage permissions!");
- } else {
- FileOutputStream fos = new FileOutputStream(tmpFile);
- fos.write(response.body().bytes());
- fos.close();
-
- String filePath = tmpFile.getAbsolutePath();
- String extension = MimeTypeMap.getFileExtensionFromUrl(
- filePath.substring(filePath.lastIndexOf("/")));
- String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
-
- Intent intent = new Intent();
- intent.setAction(android.content.Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.fromFile(tmpFile), mime);
- intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
- }
- }
- });
- }
-
- /**
- * Create a File
- */
- @Nullable
- private static File getOutputMediaFile(String packageName, String fileName) {
- // To be safe, you should check that the SDCard is mounted
- // using Environment.getExternalStorageState() before doing this.
- File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
- + "/Android/data/"
- + packageName
- + "/Downloads");
-
- // This location works best if you want the created files to be shared
- // between applications and persist after your app has been uninstalled.
-
- // Create the storage directory if it does not exist
- if (!mediaStorageDir.exists()) {
- if (!mediaStorageDir.mkdirs()) {
- Log.d(TAG, "problem!");
- return null;
- }
- }
- // Create a media file name
- File mediaFile;
- mediaFile = new File(mediaStorageDir.getPath() + File.separator + fileName);
- return mediaFile;
- }
-
-//----------------------------METHODS FOR DOWNLOADING ATTACHED FILES END----------------------------
}
\ No newline at end of file
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
index 111788bb..5bd8c5fc 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
@@ -7,6 +7,7 @@ import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -19,6 +20,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.webkit.MimeTypeMap;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -31,6 +33,8 @@ import android.widget.TextView;
import com.squareup.picasso.Picasso;
+import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -39,13 +43,14 @@ import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
import gr.thmmy.mthmmy.data.Post;
import gr.thmmy.mthmmy.utils.CircleTransform;
+import gr.thmmy.mthmmy.utils.FileManager.ThmmyFile;
import mthmmy.utils.Report;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.EXTRAS_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.NO_POST_FOCUS;
+import static gr.thmmy.mthmmy.activities.topic.TopicActivity.PACKAGE_NAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.base_url;
-import static gr.thmmy.mthmmy.activities.topic.TopicActivity.downloadFileAsync;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.postFocus;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.toQuoteList;
@@ -197,30 +202,28 @@ class TopicAdapter extends RecyclerView.Adapter {
if (currentPost.getAttachedFiles().size() != 0) {
holder.bodyFooterDivider.setVisibility(View.VISIBLE);
- int filesTextColor = 0;
+ int filesTextColor;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
filesTextColor = context.getResources().getColor(R.color.accent, null);
} else //noinspection deprecation
filesTextColor = context.getResources().getColor(R.color.accent);
- for (final String[] attachedFile : currentPost.getAttachedFiles()) {
+ for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) {
final TextView attached = new TextView(context);
attached.setTextSize(10f);
attached.setClickable(true);
attached.setTypeface(Typeface.createFromAsset(context.getAssets()
, "fonts/fontawesome-webfont.ttf"));
- attached.setText(faIconFromExtension(attachedFile[1]) + " " + attachedFile[1] + attachedFile[2]);
+ attached.setText(faIconFromExtension(attachedFile.getFilename()) + " "
+ + attachedFile.getFilename() + attachedFile.getFileInfo());
attached.setTextColor(filesTextColor);
attached.setPadding(0, 3, 0, 3);
attached.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- try {
- downloadFileAsync(attachedFile[0], attachedFile[1], context);
- } catch (Exception e) {
- e.printStackTrace();
- }
+ DownloadTask downloadTask = new DownloadTask();
+ downloadTask.execute(attachedFile);
}
});
@@ -578,4 +581,31 @@ class TopicAdapter extends RecyclerView.Adapter {
return context.getResources().getString(R.string.fa_file);
}
+
+ private class DownloadTask extends AsyncTask {
+ //Class variables
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
+ private static final String TAG = "DownloadTask"; //Separate tag for AsyncTask
+
+ protected Void doInBackground(ThmmyFile... files) {
+ try {
+ File tmpFile = files[0].download(PACKAGE_NAME);
+ if (tmpFile != null) {
+ String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+ files[0].getExtension());
+
+ Intent intent = new Intent();
+ intent.setAction(android.content.Intent.ACTION_VIEW);
+ intent.setDataAndType(Uri.fromFile(tmpFile), mime);
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+ }
+ } catch (IOException e) {
+ Report.e(TAG, "Error while trying to download a file", e);
+ }
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
index 0bae59a5..095a02b1 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
@@ -7,12 +7,16 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import gr.thmmy.mthmmy.data.Post;
+import gr.thmmy.mthmmy.utils.FileManager.ThmmyFile;
+import mthmmy.utils.Report;
/**
* Singleton used for parsing a topic.
@@ -20,8 +24,7 @@ import gr.thmmy.mthmmy.data.Post;
* {@link #parseCurrentPageIndex(Document, String)}
* {@link #parseTopicNumberOfPages(Document, int, String)}
* {@link #parseTopic(Document, String)}
- * {@link #defineLanguage(Document)}
- * (private) {@link #colorPicker(String)}
+ * {@link #defineLanguage(Document)}
*/
class TopicParser {
//Languages supported
@@ -165,7 +168,7 @@ class TopicParser {
p_specialRank, p_gender, p_personalText, p_numberOfPosts;
int p_postNum, p_postIndex, p_numberOfStars, p_userColor;
boolean p_isDeleted = false;
- ArrayList p_attachedFiles;
+ ArrayList p_attachedFiles;
//Initialize variables
p_profileURL = null;
@@ -274,21 +277,26 @@ class TopicParser {
String postAttachmentsText = postAttachments.text();
for (int i = 0; i < attachedFiles.size(); ++i) {
- String[] attachedArray = new String[3];
+ URL attachedUrl;
//Gets file's url and filename
Element tmpAttachedFileUrlAndName = attachedFiles.get(i);
- attachedArray[0] = tmpAttachedFileUrlAndName.attr("href");
- attachedArray[1] = tmpAttachedFileUrlAndName.text().substring(1);
+ try {
+ attachedUrl = new URL(tmpAttachedFileUrlAndName.attr("href"));
+ } catch (MalformedURLException e) {
+ Report.e(TAG,"Attached file malformed url", e);
+ break;
+ }
+ String attachedFileName = tmpAttachedFileUrlAndName.text().substring(1);
//Gets file's info (size and download count)
String postAttachmentsTextSbstr = postAttachmentsText.substring(
- postAttachmentsText.indexOf(attachedArray[1]));
+ postAttachmentsText.indexOf(attachedFileName));
- attachedArray[2] = postAttachmentsTextSbstr.substring(attachedArray[1]
+ String attachedFileInfo = postAttachmentsTextSbstr.substring(attachedFileName
.length(), postAttachmentsTextSbstr.indexOf("φορές.")) + "φορές.)";
- p_attachedFiles.add(attachedArray);
+ p_attachedFiles.add(new ThmmyFile(attachedUrl,attachedFileName,attachedFileInfo));
}
}
} else {
@@ -329,21 +337,26 @@ class TopicParser {
String postAttachmentsText = postAttachments.text();
for (int i = 0; i < attachedFiles.size(); ++i) {
- String[] attachedArray = new String[3];
+ URL attachedUrl;
//Gets file's url and filename
Element tmpAttachedFileUrlAndName = attachedFiles.get(i);
- attachedArray[0] = tmpAttachedFileUrlAndName.attr("href");
- attachedArray[1] = tmpAttachedFileUrlAndName.text().substring(1);
+ try {
+ attachedUrl = new URL(tmpAttachedFileUrlAndName.attr("href"));
+ } catch (MalformedURLException e) {
+ Report.e(TAG,"Attached file malformed url", e);
+ break;
+ }
+ String attachedFileName = tmpAttachedFileUrlAndName.text().substring(1);
//Gets file's info (size and download count)
String postAttachmentsTextSbstr = postAttachmentsText.substring(
- postAttachmentsText.indexOf(attachedArray[1]));
+ postAttachmentsText.indexOf(attachedFileName));
- attachedArray[2] = postAttachmentsTextSbstr.substring(attachedArray[1]
+ String attachedFileInfo = postAttachmentsTextSbstr.substring(attachedFileName
.length(), postAttachmentsTextSbstr.indexOf("times.")) + "times.)";
- p_attachedFiles.add(attachedArray);
+ p_attachedFiles.add(new ThmmyFile(attachedUrl,attachedFileName,attachedFileInfo));
}
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/data/Post.java b/app/src/main/java/gr/thmmy/mthmmy/data/Post.java
index d8241e9b..9ce37162 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/data/Post.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/data/Post.java
@@ -2,6 +2,8 @@ package gr.thmmy.mthmmy.data;
import java.util.ArrayList;
+import gr.thmmy.mthmmy.utils.FileManager.ThmmyFile;
+
public class Post {
//Standard info (exists in every post)
private final String thumbnailUrl;
@@ -22,13 +24,13 @@ public class Post {
private final String personalText;
private final int numberOfStars;
private final int userColor;
- private final ArrayList attachedFiles;
+ private final ArrayList attachedFiles;
public Post(String thumbnailUrl, String author, String subject, String content
, int postIndex, int postNumber, String postDate, String profileURl, String rank
, String special_rank, String gender, String numberOfPosts
, String personalText, int numberOfStars, int userColor
- , ArrayList attachedFiles) {
+ , ArrayList attachedFiles) {
this.thumbnailUrl = thumbnailUrl;
this.author = author;
this.subject = subject;
@@ -50,7 +52,7 @@ public class Post {
public Post(String thumbnailUrl, String author, String subject, String content
, int postIndex, int postNumber, String postDate, int userColor
- , ArrayList attachedFiles) {
+ , ArrayList attachedFiles) {
this.thumbnailUrl = thumbnailUrl;
this.author = author;
this.subject = subject;
@@ -135,7 +137,7 @@ public class Post {
return userColor;
}
- public ArrayList getAttachedFiles() {
+ public ArrayList getAttachedFiles() {
return attachedFiles;
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/FileManager/ThmmyFile.java b/app/src/main/java/gr/thmmy/mthmmy/utils/FileManager/ThmmyFile.java
new file mode 100644
index 00000000..906afd9c
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/utils/FileManager/ThmmyFile.java
@@ -0,0 +1,183 @@
+package gr.thmmy.mthmmy.utils.FileManager;
+
+import android.os.Environment;
+import android.support.annotation.Nullable;
+import android.webkit.MimeTypeMap;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Objects;
+
+import mthmmy.utils.Report;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import static gr.thmmy.mthmmy.activities.base.BaseActivity.getClient;
+
+/**
+ * Used for downloading and storing a file from the forum using {@link okhttp3}.
+ * Class has one constructor:
- {@link #ThmmyFile(URL, String, String)}
+ * and the methods:- getters
+ * - {@link #download()}
+ * - {@link #download(String)}
+ */
+public class ThmmyFile {
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
+ private static final String TAG = "ThmmyFile";
+ /**
+ * Folder name used when downloading files without a package name.
+ */
+ private static final String NO_PACKAGE_FOLDER_NAME = "Other";
+ private final URL fileUrl;
+ private final String filename, fileInfo;
+ private String extension, filePath;
+ private File file;
+
+ /**
+ * This constructor only creates a ThmmyFile object and does not download the file. To download
+ * the file use {@link #download(String)} or {@link #download()}!
+ *
+ * @param fileUrl {@link URL} object with file's url
+ * @param filename {@link String} with desired file name
+ * @param fileInfo {@link String} with any extra information (like number of downloads)
+ */
+ public ThmmyFile(URL fileUrl, String filename, String fileInfo) {
+ this.fileUrl = fileUrl;
+ this.filename = filename;
+ this.fileInfo = fileInfo;
+ this.extension = null;
+ this.filePath = null;
+ this.file = null;
+ }
+
+ public URL getFileUrl() {
+ return fileUrl;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public String getFileInfo() {
+ return fileInfo;
+ }
+
+ /**
+ * This is null until {@link #download(String)} or {@link #download()} is called and has succeeded.
+ *
+ * @return String with file's extension or null
+ */
+ @Nullable
+ public String getExtension() {
+ return extension;
+ }
+
+ /**
+ * This is null until {@link #download(String)} or {@link #download()} is called and has succeeded.
+ *
+ * @return String with file's path or null
+ */
+ @Nullable
+ public String getFilePath() {
+ return filePath;
+ }
+
+ /**
+ * This is null until {@link #download(String)} or {@link #download()} is called and has succeeded.
+ *
+ * @return {@link File} or null
+ */
+ @Nullable
+ public File getFile() {
+ return file;
+ }
+
+ private void setExtension(String extension) {
+ this.extension = extension;
+ }
+
+ private void setFilePath(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Used to download the file. If download is successful file's extension and path will be assigned
+ * to object's fields and can be accessed using getter methods.
+ * File is stored in sdcard1/Android/data/Downloads/{@link #NO_PACKAGE_FOLDER_NAME}
+ *
+ * @return the {@link File} if successful, null otherwise
+ * @throws IOException
+ * @throws SecurityException
+ */
+ @Nullable
+ public File download() throws IOException, SecurityException {
+ return download(NO_PACKAGE_FOLDER_NAME);
+ }
+
+ /**
+ * Used to download the file. If download is successful file's extension and path will be assigned
+ * to object's fields and can be accessed using getter methods.
+ * File is stored in sdcard1/Android/data/Downloads/packageName
+ *
+ * @param packageName package's name to use as folder name for file's path
+ * @return the {@link File} if successful, null otherwise
+ * @throws IOException if the request could not be executed due to cancellation, a connectivity
+ * problem or timeout. Because networks can fail during an exchange, it is possible that the
+ * remote server accepted the request before the failure.
+ * @throws SecurityException if the requested file is not hosted by the forum.
+ */
+ @Nullable
+ public File download(final String packageName) throws IOException, SecurityException {
+ if (!Objects.equals(fileUrl.getHost(), "www.thmmy.gr"))
+ throw new SecurityException("Downloading files from other sources is not supported");
+
+ Request request = new Request.Builder().url(fileUrl).build();
+
+ Response response = getClient().newCall(request).execute();
+ if (!response.isSuccessful()) {
+ throw new IOException("Failed to download file: " + response);
+ }
+ file = getOutputMediaFile(packageName, filename);
+ if (file == null) {
+ Report.d(TAG, "Error creating media file, check storage permissions!");
+ } else {
+ FileOutputStream fos = new FileOutputStream(file);
+ fos.write(response.body().bytes());
+ fos.close();
+
+ filePath = file.getAbsolutePath();
+ extension = MimeTypeMap.getFileExtensionFromUrl(
+ filePath.substring(filePath.lastIndexOf("/")));
+ }
+ return file;
+ }
+
+ @Nullable
+ private static File getOutputMediaFile(String packageName, String fileName) {
+ // To be safe, you should check that the SDCard is mounted
+ // using Environment.getExternalStorageState() before doing this.
+ File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ + "/Android/data/gr.thmmy.mthmmy/"
+ + "Downloads/"
+ + packageName);
+
+ // This location works best if you want the created files to be shared
+ // between applications and persist after your app has been uninstalled.
+
+ // Create the storage directory if it does not exist
+ if (!mediaStorageDir.exists()) {
+ if (!mediaStorageDir.mkdirs()) {
+ Report.d(TAG, "problem!");
+ return null;
+ }
+ }
+ // Create a media file name
+ File mediaFile;
+ mediaFile = new File(mediaStorageDir.getPath() + File.separator + fileName);
+ return mediaFile;
+ }
+}