diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9a7ce1df..d02a2bf6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,7 @@ image: openjdk:8-jdk
variables:
ANDROID_TARGET_SDK: "25"
ANDROID_BUILD_TOOLS: "25.0.1"
- ANDROID_SDK_TOOLS: "25.2.4"
+ ANDROID_SDK_TOOLS: "25.2.5"
before_script:
- apt-get --quiet update --yes
diff --git a/VERSION b/VERSION
index 3eefcb9d..9084fa2f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0
+1.1.0
diff --git a/app/build.gradle b/app/build.gradle
index aab5c5d6..05e1d905 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,8 +9,8 @@ android {
applicationId "gr.thmmy.mthmmy"
minSdkVersion 19
targetSdkVersion 25
- versionCode 2
- versionName "1.0.1"
+ versionCode 3
+ versionName "1.1.0"
archivesBaseName = "mTHMMY-v$versionName"
}
@@ -37,7 +37,7 @@ dependencies {
compile 'com.squareup.okhttp3:okhttp:3.5.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
- compile 'org.jsoup:jsoup:1.10.1'
+ compile 'org.jsoup:jsoup:1.10.2'
compile 'com.github.franmontiel:PersistentCookieJar:v1.0.0'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.1'
compile('com.mikepenz:materialdrawer:5.8.1@aar') {
diff --git a/app/src/debug/java/mthmmy/utils/Report.java b/app/src/debug/java/mthmmy/utils/Report.java
index 68ab3c3b..6e6a906f 100644
--- a/app/src/debug/java/mthmmy/utils/Report.java
+++ b/app/src/debug/java/mthmmy/utils/Report.java
@@ -64,4 +64,18 @@ public class Report
{
Log.wtf(TAG,message + ": " + tr.getMessage(),tr);
}
+
+ /**
+ * Prints long messages in logcat (debug level).
+ */
+ public static void longMessage(String TAG, String message)
+ {
+ int maxLogSize = 1000;
+ for(int i = 0; i <= message.length() / maxLogSize; i++) {
+ int start = i * maxLogSize;
+ int end = (i+1) * maxLogSize;
+ end = end > message.length() ? message.length() : end;
+ Report.d(TAG, message.substring(start, end));
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f8bed348..1ad2d90b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,9 +6,9 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ android:screenOrientation="portrait"
+ android:theme="@style/AppTheme.NoActionBar"
+ android:windowSoftInputMode="adjustPan"/>
-
+ android:theme="@style/AppTheme.NoActionBar"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/assets/mit_libraries.html b/app/src/main/assets/mit_libraries.html
index f51bcca0..6d72c330 100644
--- a/app/src/main/assets/mit_libraries.html
+++ b/app/src/main/assets/mit_libraries.html
@@ -39,7 +39,7 @@
-
-
jsoup v1.10.1 (Copyright ©2009-2017, Jonathan Hedley <jonathan@hedley.net>)
+ jsoup v1.10.2 (Copyright ©2009-2017, Jonathan Hedley <jonathan@hedley.net>)
-
android-gif-drawable v1.2.3 (Copyright ©2016 Karol Wrótniak, Droids on Roids)
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
index 0b33c3e9..dd90a6df 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
@@ -16,7 +16,7 @@ import android.widget.TextView;
import gr.thmmy.mthmmy.BuildConfig;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
+import gr.thmmy.mthmmy.base.BaseActivity;
public class AboutActivity extends BaseActivity {
private static final int TIME_INTERVAL = 1000;
@@ -26,7 +26,7 @@ public class AboutActivity extends BaseActivity {
private AppBarLayout appBar;
private CoordinatorLayout coordinatorLayout;
- AlertDialog alertDialog;
+ private AlertDialog alertDialog;
private FrameLayout trollGif;
@Override
@@ -42,8 +42,10 @@ public class AboutActivity extends BaseActivity {
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(R.string.about);
setSupportActionBar(toolbar);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setDisplayShowHomeEnabled(true);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ }
createDrawer();
drawer.setSelection(ABOUT_ID);
@@ -84,11 +86,11 @@ public class AboutActivity extends BaseActivity {
}
public void displayApacheLibraries(View v) {
- LayoutInflater inflater =LayoutInflater.from(this);
+ LayoutInflater inflater = LayoutInflater.from(this);
WebView webView = (WebView) inflater.inflate(R.layout.dialog_licenses, coordinatorLayout, false);
webView.loadUrl("file:///android_asset/apache_libraries.html");
- int width = (int)(getResources().getDisplayMetrics().widthPixels*0.95);
- int height = (int)(getResources().getDisplayMetrics().heightPixels*0.95);
+ int width = (int) (getResources().getDisplayMetrics().widthPixels * 0.95);
+ int height = (int) (getResources().getDisplayMetrics().heightPixels * 0.95);
alertDialog = new AlertDialog.Builder(this, R.style.AppTheme_Dark_Dialog)
.setTitle(getString(R.string.apache_v2_0_libraries))
.setView(webView)
@@ -98,11 +100,11 @@ public class AboutActivity extends BaseActivity {
}
public void displayMITLibraries(View v) {
- LayoutInflater inflater =LayoutInflater.from(this);
+ LayoutInflater inflater = LayoutInflater.from(this);
WebView webView = (WebView) inflater.inflate(R.layout.dialog_licenses, coordinatorLayout, false);
webView.loadUrl("file:///android_asset/mit_libraries.html");
- int width = (int)(getResources().getDisplayMetrics().widthPixels*0.95);
- int height = (int)(getResources().getDisplayMetrics().heightPixels*0.95);
+ int width = (int) (getResources().getDisplayMetrics().widthPixels * 0.95);
+ int height = (int) (getResources().getDisplayMetrics().heightPixels * 0.95);
alertDialog = new AlertDialog.Builder(this, R.style.AppTheme_Dark_Dialog)
.setTitle(getString(R.string.the_mit_libraries))
.setView(webView)
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/BookmarkActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/BookmarkActivity.java
new file mode 100644
index 00000000..5d854eef
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/BookmarkActivity.java
@@ -0,0 +1,142 @@
+package gr.thmmy.mthmmy.activities;
+
+import android.content.Intent;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.widget.Toolbar;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.activities.board.BoardActivity;
+import gr.thmmy.mthmmy.activities.topic.TopicActivity;
+import gr.thmmy.mthmmy.base.BaseActivity;
+import gr.thmmy.mthmmy.model.Bookmark;
+
+import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
+import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
+import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE;
+import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
+
+public class BookmarkActivity extends BaseActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_bookmark);
+
+ //Initialize toolbar
+ toolbar = (Toolbar) findViewById(R.id.toolbar);
+ toolbar.setTitle("Bookmarks");
+ setSupportActionBar(toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ }
+
+ createDrawer();
+ drawer.setSelection(BOOKMARKS_ID);
+
+ LinearLayout bookmarksLinearView = (LinearLayout) findViewById(R.id.bookmarks_container);
+ LayoutInflater layoutInflater = getLayoutInflater();
+
+ TextView tmp = new TextView(this);
+ tmp.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT
+ , LinearLayout.LayoutParams.WRAP_CONTENT));
+ tmp.setText(getString(R.string.board_bookmarks_title));
+ tmp.setTypeface(tmp.getTypeface(), Typeface.BOLD);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ tmp.setTextColor(getColor(R.color.primary_text));
+ } else {
+ //noinspection deprecation
+ tmp.setTextColor(getResources().getColor(R.color.primary_text));
+ }
+ tmp.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
+ tmp.setTextSize(20f);
+ bookmarksLinearView.addView(tmp);
+
+ for (final Bookmark bookmarkedBoard : getBoardsBookmarked()) {
+ if (bookmarkedBoard != null && bookmarkedBoard.getTitle() != null) {
+ final LinearLayout row = (LinearLayout) layoutInflater.inflate(
+ R.layout.activity_bookmark_row, bookmarksLinearView, false);
+ row.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(BookmarkActivity.this, BoardActivity.class);
+ Bundle extras = new Bundle();
+ extras.putString(BUNDLE_BOARD_URL, "https://www.thmmy.gr/smf/index.php?board="
+ + bookmarkedBoard.getId() + ".0");
+ extras.putString(BUNDLE_BOARD_TITLE, bookmarkedBoard.getTitle());
+ intent.putExtras(extras);
+ startActivity(intent);
+ finish();
+ }
+ });
+ ((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedBoard.getTitle());
+ (row.findViewById(R.id.remove_bookmark)).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ removeBookmark(bookmarkedBoard);
+ row.setVisibility(View.GONE);
+ }
+ });
+ bookmarksLinearView.addView(row);
+ }
+ }
+
+ tmp = new TextView(this);
+ tmp.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT
+ , LinearLayout.LayoutParams.WRAP_CONTENT));
+ tmp.setText(getString(R.string.topic_bookmarks_title));
+ tmp.setTypeface(tmp.getTypeface(), Typeface.BOLD);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ tmp.setTextColor(getColor(R.color.primary_text));
+ } else {
+ //noinspection deprecation
+ tmp.setTextColor(getResources().getColor(R.color.primary_text));
+ }
+ tmp.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
+ tmp.setTextSize(20f);
+ bookmarksLinearView.addView(tmp);
+
+ for (final Bookmark bookmarkedTopic : getTopicsBookmarked()) {
+ if (bookmarkedTopic != null && bookmarkedTopic.getTitle() != null) {
+ final LinearLayout row = (LinearLayout) layoutInflater.inflate(
+ R.layout.activity_bookmark_row, bookmarksLinearView, false);
+ row.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(BookmarkActivity.this, TopicActivity.class);
+ Bundle extras = new Bundle();
+ extras.putString(BUNDLE_TOPIC_URL, "https://www.thmmy.gr/smf/index.php?topic="
+ + bookmarkedTopic.getId() + ".0");
+ extras.putString(BUNDLE_TOPIC_TITLE, bookmarkedTopic.getTitle());
+ intent.putExtras(extras);
+ startActivity(intent);
+ finish();
+ }
+ });
+ ((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedTopic.getTitle());
+ (row.findViewById(R.id.remove_bookmark)).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ removeBookmark(bookmarkedTopic);
+ row.setVisibility(View.GONE);
+ }
+ });
+ bookmarksLinearView.addView(row);
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ drawer.setSelection(BOOKMARKS_ID);
+ super.onResume();
+ }
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java
index 2035653a..7dacd734 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java
@@ -12,8 +12,8 @@ import android.widget.ScrollView;
import android.widget.Toast;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
import gr.thmmy.mthmmy.activities.main.MainActivity;
+import gr.thmmy.mthmmy.base.BaseActivity;
import mthmmy.utils.Report;
import static gr.thmmy.mthmmy.session.SessionManager.CONNECTION_ERROR;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/base/BaseActivity.java
deleted file mode 100644
index 4794cf9e..00000000
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/base/BaseActivity.java
+++ /dev/null
@@ -1,373 +0,0 @@
-package gr.thmmy.mthmmy.activities.base;
-
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.franmontiel.persistentcookiejar.PersistentCookieJar;
-import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
-import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
-import com.jakewharton.picasso.OkHttp3Downloader;
-import com.mikepenz.fontawesome_typeface_library.FontAwesome;
-import com.mikepenz.iconics.IconicsDrawable;
-import com.mikepenz.materialdrawer.AccountHeader;
-import com.mikepenz.materialdrawer.AccountHeaderBuilder;
-import com.mikepenz.materialdrawer.Drawer;
-import com.mikepenz.materialdrawer.DrawerBuilder;
-import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
-import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
-import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
-import com.mikepenz.materialdrawer.model.interfaces.IProfile;
-import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
-import com.mikepenz.materialdrawer.util.DrawerImageLoader;
-import com.squareup.picasso.Picasso;
-
-import java.util.concurrent.TimeUnit;
-
-import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.AboutActivity;
-import gr.thmmy.mthmmy.activities.LoginActivity;
-import gr.thmmy.mthmmy.activities.main.MainActivity;
-import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
-import gr.thmmy.mthmmy.session.SessionManager;
-import okhttp3.OkHttpClient;
-
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
-import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_THUMBNAIL_URL;
-import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_USERNAME;
-
-public abstract class BaseActivity extends AppCompatActivity
-{
- // Client & Cookies
- protected static OkHttpClient client;
- private static final long connectTimeout = 30; //TimeUnit.SECONDS for all three
- private static final long writeTimeout = 30;
- private static final long readTimeout = 30;
- protected static Picasso picasso;
- private static PersistentCookieJar cookieJar;
- private static SharedPrefsCookiePersistor sharedPrefsCookiePersistor;
-
- //Shared Preferences
- protected static final String SHARED_PREFS_NAME = "ThmmySharedPrefs";
- protected static SharedPreferences sharedPrefs;
-
- //SessionManager
- protected static SessionManager sessionManager;
-
- //Other variables
- private static boolean init = false; //To initialize stuff only once per app start
-
- //Common UI elements
- protected Toolbar toolbar;
- protected Drawer drawer;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (!init) {
- sharedPrefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE);
- sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(BaseActivity.this);
- cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor);
- client = new OkHttpClient.Builder()
- .cookieJar(cookieJar)
- .connectTimeout(connectTimeout, TimeUnit.SECONDS)
- .writeTimeout(writeTimeout, TimeUnit.SECONDS)
- .readTimeout(readTimeout, TimeUnit.SECONDS)
- .build();
- sessionManager = new SessionManager(client, cookieJar, sharedPrefsCookiePersistor, sharedPrefs);
- picasso = new Picasso.Builder(BaseActivity.this)
- .downloader(new OkHttp3Downloader(client))
- .build();
- Picasso.setSingletonInstance(picasso); // all following Picasso (with Picasso.with(Context context) requests will use this Picasso object
- //initialize and create the image loader logic TODO move this to a singleton BaseApplication obj
- DrawerImageLoader.init(new AbstractDrawerImageLoader() {
- @Override
- public void set(ImageView imageView, Uri uri, Drawable placeholder) {
- Picasso.with(imageView.getContext()).load(uri).placeholder(placeholder).into(imageView);
- }
- @Override
- public void cancel(ImageView imageView) {
- Picasso.with(imageView.getContext()).cancelRequest(imageView);
- }
-
- @Override
- public Drawable placeholder(Context ctx, String tag) {
- if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) {
- return new IconicsDrawable(ctx).icon(FontAwesome.Icon.faw_user)
- .paddingDp(10)
- .color(ContextCompat.getColor(ctx, R.color.primary_light))
- .backgroundColor(ContextCompat.getColor(ctx, R.color.primary));
- }
-
- return super.placeholder(ctx, tag);
- }
- });
- init = true;
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- updateDrawer();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if(drawer!=null) //close drawer animation after returning to activity
- drawer.closeDrawer();
- }
-
-
- public static OkHttpClient getClient()
- {
- return client;
- }
-
- public static SessionManager getSessionManager()
- {
- return sessionManager;
- }
-
- //TODO: move stuff below
- //------------------------------------------DRAWER STUFF----------------------------------------
- protected static final int HOME_ID=0;
- protected static final int LOG_ID =1;
- protected static final int ABOUT_ID=2;
-
- private AccountHeader accountHeader;
- private ProfileDrawerItem profileDrawerItem;
- private PrimaryDrawerItem homeItem, loginLogoutItem, aboutItem;
- private IconicsDrawable homeIcon, homeIconSelected, loginIcon, logoutIcon,
- aboutIcon, aboutIconSelected;
-
- /**
- * Call only after initializing Toolbar
- */
- protected void createDrawer()
- {
- final int primaryColor = ContextCompat.getColor(this, R.color.iron);
- final int selectedPrimaryColor = ContextCompat.getColor(this, R.color.primary_dark);
- final int selectedSecondaryColor = ContextCompat.getColor(this, R.color.accent);
-
- //Drawer Icons
- homeIcon =new IconicsDrawable(this)
- .icon(FontAwesome.Icon.faw_home)
- .color(primaryColor);
-
- homeIconSelected =new IconicsDrawable(this)
- .icon(FontAwesome.Icon.faw_home)
- .color(selectedSecondaryColor);
-
- loginIcon =new IconicsDrawable(this)
- .icon(FontAwesome.Icon.faw_sign_in)
- .color(primaryColor);
-
- logoutIcon =new IconicsDrawable(this)
- .icon(FontAwesome.Icon.faw_sign_out)
- .color(primaryColor);
-
- aboutIcon =new IconicsDrawable(this)
- .icon(FontAwesome.Icon.faw_info_circle)
- .color(primaryColor);
-
- aboutIconSelected =new IconicsDrawable(this)
- .icon(FontAwesome.Icon.faw_info_circle)
- .color(selectedSecondaryColor);
-
- //Drawer Items
- homeItem = new PrimaryDrawerItem()
- .withTextColor(primaryColor)
- .withSelectedColor(selectedPrimaryColor)
- .withSelectedTextColor(selectedSecondaryColor)
- .withIdentifier(HOME_ID)
- .withName(R.string.home)
- .withIcon(homeIcon)
- .withSelectedIcon(homeIconSelected);
-
- if (!sessionManager.isLoggedIn()) //When logged out
- loginLogoutItem = new PrimaryDrawerItem()
- .withTextColor(primaryColor)
- .withSelectedColor(selectedSecondaryColor)
- .withIdentifier(LOG_ID).withName(R.string.login)
- .withIcon(loginIcon)
- .withSelectable(false);
- else
- loginLogoutItem = new PrimaryDrawerItem()
- .withTextColor(primaryColor)
- .withSelectedColor(selectedSecondaryColor)
- .withIdentifier(LOG_ID)
- .withName(R.string.logout)
- .withIcon(logoutIcon)
- .withSelectable(false);
- aboutItem = new PrimaryDrawerItem()
- .withTextColor(primaryColor)
- .withSelectedColor(selectedPrimaryColor)
- .withSelectedTextColor(selectedSecondaryColor)
- .withIdentifier(ABOUT_ID)
- .withName(R.string.about)
- .withIcon(aboutIcon)
- .withSelectedIcon(aboutIconSelected);
-
- //Profile
- profileDrawerItem = new ProfileDrawerItem().withName(sessionManager.getUsername());
-
- //AccountHeader
- accountHeader = new AccountHeaderBuilder()
- .withActivity(this)
- .withCompactStyle(true)
- .withSelectionListEnabledForSingleProfile(false)
- .withHeaderBackground(R.color.primary)
- .addProfiles(profileDrawerItem)
- .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
- @Override
- public boolean onProfileChanged(View view, IProfile profile, boolean currentProfile) {
- if(sessionManager.isLoggedIn())
- {
- Intent intent = new Intent(BaseActivity.this, ProfileActivity.class);
- Bundle extras = new Bundle();
- extras.putString(BUNDLE_PROFILE_URL, "https://www.thmmy.gr/smf/index.php?action=profile");
- if(!sessionManager.hasAvatar())
- extras.putString(BUNDLE_THUMBNAIL_URL, "");
- else
- extras.putString(BUNDLE_THUMBNAIL_URL, sessionManager.getAvatarLink());
- extras.putString(BUNDLE_USERNAME, sessionManager.getUsername());
- intent.putExtras(extras);
- intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- return false;
- }
- return true;
-
- }
- })
- .build();
-
- //Drawer
- drawer = new DrawerBuilder()
- .withActivity(this)
- .withToolbar(toolbar)
- .withSliderBackgroundColor(ContextCompat.getColor(this, R.color.primary_light))
- .withAccountHeader(accountHeader)
- .addDrawerItems(homeItem,loginLogoutItem,aboutItem)
- .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
- @Override
- public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
- if(drawerItem.equals(HOME_ID))
- {
- if(!(BaseActivity.this instanceof MainActivity))
- {
- Intent i = new Intent(BaseActivity.this, MainActivity.class);
- startActivity(i);
- }
- }
- else if(drawerItem.equals(LOG_ID))
- {
- if (!sessionManager.isLoggedIn()) //When logged out or if user is guest
- {
- Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
- startActivity(intent);
- finish();
- overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out);
- }
- else
- new LogoutTask().execute();
- }
- else if(drawerItem.equals(ABOUT_ID))
- {
- if(!(BaseActivity.this instanceof AboutActivity))
- {
- Intent i = new Intent(BaseActivity.this, AboutActivity.class);
- startActivity(i);
- }
-
- }
-
- drawer.closeDrawer();
- return true;
- }
- })
- .build();
-
- drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(false);
- drawer.setOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
- @Override
- public boolean onNavigationClickListener(View clickedView) {
- onBackPressed();
- return true;
- }
- });
- }
-
- protected void updateDrawer()
- {
- if(drawer!=null)
- {
- if (!sessionManager.isLoggedIn()) //When logged out or if user is guest
- {
- loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login
- profileDrawerItem.withName(sessionManager.getUsername()).withIcon(new IconicsDrawable(this)
- .icon(FontAwesome.Icon.faw_user)
- .paddingDp(10)
- .color(ContextCompat.getColor(this, R.color.primary_light))
- .backgroundColor(ContextCompat.getColor(this, R.color.primary)));
- }
- else
- {
- loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout
- profileDrawerItem.withName(sessionManager.getUsername()).withIcon(sessionManager.getAvatarLink());
- }
- accountHeader.updateProfile(profileDrawerItem);
- drawer.updateItem(loginLogoutItem);
-
- }
- }
-
-
- //-------------------------------------------LOGOUT-------------------------------------------------
- /**
- * Result toast will always display a success, because when user chooses logout all data are
- * cleared regardless of the actual outcome
- */
- protected class LogoutTask extends AsyncTask { //Attempt logout
- ProgressDialog progressDialog;
-
- protected Integer doInBackground(Void... voids) {
- return sessionManager.logout();
- }
-
- protected void onPreExecute()
- { //Show a progress dialog until done
- progressDialog = new ProgressDialog(BaseActivity.this,
- R.style.AppTheme_Dark_Dialog);
- progressDialog.setCancelable(false);
- progressDialog.setIndeterminate(true);
- progressDialog.setMessage("Logging out...");
- progressDialog.show();
- }
-
- protected void onPostExecute(Integer result)
- {
- Toast.makeText(getBaseContext(), "Logged out successfully!", Toast.LENGTH_LONG).show();
- updateDrawer();
- progressDialog.dismiss();
- }
- }
-//-----------------------------------------LOGOUT END-----------------------------------------------
-
-
-}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java
index 9b7071f5..c3587b1b 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java
@@ -1,17 +1,15 @@
package gr.thmmy.mthmmy.activities.board;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
-import android.support.v7.app.AlertDialog;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
+import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.Toast;
@@ -26,10 +24,10 @@ import java.util.Objects;
import javax.net.ssl.SSLHandshakeException;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.LoginActivity;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
+import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.model.Board;
-import gr.thmmy.mthmmy.model.LinkTarget;
+import gr.thmmy.mthmmy.model.Bookmark;
+import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.model.Topic;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report;
@@ -76,8 +74,8 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
Bundle extras = getIntent().getExtras();
boardTitle = extras.getString(BUNDLE_BOARD_TITLE);
boardUrl = extras.getString(BUNDLE_BOARD_URL);
- LinkTarget.Target target = LinkTarget.resolveLinkTarget(Uri.parse(boardUrl));
- if (!target.is(LinkTarget.Target.BOARD)) {
+ ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(boardUrl));
+ if (!target.is(ThmmyPage.PageCategory.BOARD)) {
Report.e(TAG, "Bundle came with a non board url!\nUrl:\n" + boardUrl);
Toast.makeText(this, "An error has occurred\nAborting.", Toast.LENGTH_SHORT).show();
finish();
@@ -93,11 +91,16 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
+ thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl));
+ thisPageBookmarkButton = (ImageButton) findViewById(R.id.bookmark);
+ setBoardBookmark();
createDrawer();
+
progressBar = (MaterialProgressBar) findViewById(R.id.progressBar);
newTopicFAB = (FloatingActionButton) findViewById(R.id.board_fab);
newTopicFAB.setEnabled(false);
- if (!sessionManager.isLoggedIn()) newTopicFAB.hide();
+ newTopicFAB.hide();
+ /*if (!sessionManager.isLoggedIn()) newTopicFAB.hide();
else {
newTopicFAB.setOnClickListener(new View.OnClickListener() {
@Override
@@ -125,7 +128,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
}
}
});
- }
+ }*/
boardAdapter = new BoardAdapter(getApplicationContext(), parsedSubBoards, parsedTopics);
RecyclerView mainContent = (RecyclerView) findViewById(R.id.board_recycler_view);
@@ -178,7 +181,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
* BoardTask's {@link AsyncTask#execute execute} method needs a boards's url as String
* parameter!
*/
- public class BoardTask extends AsyncTask {
+ public class BoardTask extends AsyncTask {
//Class variables
/**
* Debug Tag for logging debug output to LogCat
@@ -186,34 +189,32 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
@SuppressWarnings("unused")
private static final String TAG = "BoardTask"; //Separate tag for AsyncTask
+ @Override
protected void onPreExecute() {
if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE);
if (newTopicFAB.getVisibility() != View.GONE) newTopicFAB.setEnabled(false);
}
@Override
- protected Boolean doInBackground(String... boardUrl) {
+ protected Void doInBackground(String... boardUrl) {
Request request = new Request.Builder()
.url(boardUrl[0])
.build();
try {
Response response = BaseActivity.getClient().newCall(request).execute();
- return parseBoard(Jsoup.parse(response.body().string()));
+ parseBoard(Jsoup.parse(response.body().string()));
} catch (SSLHandshakeException e) {
Report.w(TAG, "Certificate problem (please switch to unsafe connection).");
} catch (Exception e) {
Report.e("TAG", "ERROR", e);
}
- return false;
+ return null;
}
- protected void onPostExecute(Boolean result) {
- if (!result) { //Parse failed!
- Report.d(TAG, "Parse failed!");
- Toast.makeText(getApplicationContext()
- , "Fatal error!\n Aborting...", Toast.LENGTH_LONG).show();
- finish();
- }
+ @Override
+ protected void onPostExecute(Void voids) {
+ if (boardTitle == null || Objects.equals(boardTitle, "")) toolbar.setTitle(boardTitle);
+
//Parse was successful
++pagesLoaded;
if (newTopicFAB.getVisibility() != View.GONE) newTopicFAB.setEnabled(true);
@@ -222,7 +223,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
isLoadingMore = false;
}
- private boolean parseBoard(Document boardPage) {
+ private void parseBoard(Document boardPage) {
if (boardTitle == null || Objects.equals(boardTitle, ""))
boardTitle = boardPage.select("div.nav a.nav").last().text();
@@ -280,7 +281,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
} else {
pUrl = subBoardCol.select("a").first().attr("href");
pTitle = subBoardCol.select("a").first().text();
- pMods = subBoardCol.select("div.smalltext").first().text();
+ if (subBoardCol.select("div.smalltext").first() != null) {
+ pMods = subBoardCol.select("div.smalltext").first().text();
+ }
}
}
parsedSubBoards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl));
@@ -324,7 +327,6 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
}
}
}
- return true;
}
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
new file mode 100644
index 00000000..8d844e67
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
@@ -0,0 +1,279 @@
+package gr.thmmy.mthmmy.activities.downloads;
+
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v7.widget.DividerItemDecoration;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.Toast;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.base.BaseActivity;
+import gr.thmmy.mthmmy.model.Download;
+import gr.thmmy.mthmmy.model.ThmmyPage;
+import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
+import mthmmy.utils.Report;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.OnLoadMoreListener {
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
+ @SuppressWarnings("unused")
+ private static final String TAG = "DownloadsActivity";
+ /**
+ * The key to use when putting download's url String to {@link DownloadsActivity}'s Bundle.
+ */
+ public static final String BUNDLE_DOWNLOADS_URL = "DOWNLOADS_URL";
+ /**
+ * The key to use when putting download's title String to {@link DownloadsActivity}'s Bundle.
+ */
+ public static final String BUNDLE_DOWNLOADS_TITLE = "DOWNLOADS_TITLE";
+ private static final String downloadsIndexUrl = "https://www.thmmy.gr/smf/index.php?action=tpmod;dl;";
+ private String downloadsUrl;
+ private String downloadsTitle;
+ private final ArrayList parsedDownloads = new ArrayList<>();
+
+ private MaterialProgressBar progressBar;
+ private RecyclerView recyclerView;
+ private DownloadsAdapter downloadsAdapter;
+ private FloatingActionButton uploadFAB;
+
+ private ParseDownloadPageTask parseDownloadPageTask;
+ private int numberOfPages = -1;
+ private int pagesLoaded = 0;
+ private boolean isLoadingMore;
+ private static final int visibleThreshold = 5;
+ private int lastVisibleItem, totalItemCount;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_downloads);
+
+ Bundle extras = getIntent().getExtras();
+ downloadsTitle = extras.getString(BUNDLE_DOWNLOADS_TITLE);
+ downloadsUrl = extras.getString(BUNDLE_DOWNLOADS_URL);
+ if (downloadsUrl != null && !Objects.equals(downloadsUrl, "")) {
+ ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(downloadsUrl));
+ if (!target.is(ThmmyPage.PageCategory.DOWNLOADS)) {
+ Report.e(TAG, "Bundle came with a non board url!\nUrl:\n" + downloadsUrl);
+ Toast.makeText(this, "An error has occurred\nAborting.", Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ } else downloadsUrl = downloadsIndexUrl;
+
+ //Initialize toolbar
+ toolbar = (Toolbar) findViewById(R.id.toolbar);
+ if (downloadsTitle == null || Objects.equals(downloadsTitle, ""))
+ toolbar.setTitle("Downloads");
+ toolbar.setTitle(downloadsTitle);
+ setSupportActionBar(toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ }
+
+ createDrawer();
+ drawer.setSelection(DOWNLOADS_ID);
+
+ progressBar = (MaterialProgressBar) findViewById(R.id.progressBar);
+
+ recyclerView = (RecyclerView) findViewById(R.id.downloads_recycler_view);
+ recyclerView.setHasFixedSize(true);
+ final LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
+ recyclerView.setLayoutManager(layoutManager);
+ DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
+ layoutManager.getOrientation());
+ recyclerView.addItemDecoration(dividerItemDecoration);
+ downloadsAdapter = new DownloadsAdapter(getApplicationContext(), parsedDownloads);
+ recyclerView.setAdapter(downloadsAdapter);
+ recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ super.onScrolled(recyclerView, dx, dy);
+ totalItemCount = layoutManager.getItemCount();
+ lastVisibleItem = layoutManager.findLastVisibleItemPosition();
+
+ if (!isLoadingMore && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
+ isLoadingMore = true;
+ onLoadMore();
+ }
+ }
+ });
+
+ uploadFAB = (FloatingActionButton) findViewById(R.id.download_fab);
+ uploadFAB.setEnabled(false);
+ uploadFAB.hide();
+
+ parseDownloadPageTask = new ParseDownloadPageTask();
+ parseDownloadPageTask.execute(downloadsUrl);
+ }
+
+ @Override
+ public void onLoadMore() {
+ if (pagesLoaded < numberOfPages) {
+ parsedDownloads.add(null);
+ downloadsAdapter.notifyItemInserted(parsedDownloads.size());
+
+ //Load data
+ parseDownloadPageTask = new ParseDownloadPageTask();
+ if (downloadsUrl.contains("tpstart"))
+ parseDownloadPageTask.execute(downloadsUrl.substring(0
+ , downloadsUrl.lastIndexOf(";tpstart=")) + ";tpstart=" + pagesLoaded * 10);
+ else parseDownloadPageTask.execute(downloadsUrl + ";tpstart=" + pagesLoaded * 10);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (drawer.isDrawerOpen()) {
+ drawer.closeDrawer();
+ return;
+ }
+ super.onBackPressed();
+ }
+
+ @Override
+ protected void onResume() {
+ drawer.setSelection(DOWNLOADS_ID);
+ super.onResume();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ recyclerView.setAdapter(null);
+ if (parseDownloadPageTask != null && parseDownloadPageTask.getStatus() != AsyncTask.Status.RUNNING)
+ parseDownloadPageTask.cancel(true);
+ }
+
+ /**
+ * An {@link AsyncTask} that handles asynchronous fetching of a downloads page and parsing it's
+ * data. {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link RecyclerView#swapAdapter}
+ * to build graphics.
+ *
+ *
Calling TopicTask's {@link AsyncTask#execute execute} method needs to have profile's url
+ * as String parameter!
+ */
+ class ParseDownloadPageTask extends AsyncTask {
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
+ private static final String TAG = "ParseDownloadPageTask"; //Separate tag for AsyncTask
+ private String thisPageUrl;
+
+ @Override
+ protected void onPreExecute() {
+ if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE);
+ if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(false);
+ }
+
+ @Override
+ protected Void doInBackground(String... downloadsUrl) {
+ thisPageUrl = downloadsUrl[0];
+ Request request = new Request.Builder()
+ .url(downloadsUrl[0])
+ .build();
+ try {
+ Response response = BaseActivity.getClient().newCall(request).execute();
+ parseDownloads(Jsoup.parse(response.body().string()));
+ } catch (SSLHandshakeException e) {
+ Report.w(TAG, "Certificate problem (please switch to unsafe connection).");
+ } catch (Exception e) {
+ Report.e("TAG", "ERROR", e);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void voids) {
+ if (downloadsTitle != null && !Objects.equals(downloadsTitle, "") &&
+ toolbar.getTitle() != downloadsTitle)
+ toolbar.setTitle(downloadsTitle);
+
+ ++pagesLoaded;
+ if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(true);
+ progressBar.setVisibility(ProgressBar.INVISIBLE);
+ downloadsAdapter.notifyDataSetChanged();
+ isLoadingMore = false;
+ }
+
+ private void parseDownloads(Document downloadPage) {
+ if (downloadsTitle == null || Objects.equals(downloadsTitle, ""))
+ downloadsTitle = downloadPage.select("div.nav>b>a.nav").last().text();
+
+ //Removes loading item
+ if (isLoadingMore) {
+ if (parsedDownloads.size() > 0) parsedDownloads.remove(parsedDownloads.size() - 1);
+ }
+
+ Download.DownloadItemType type;
+ if (ThmmyPage.resolvePageCategory(Uri.parse(thisPageUrl)).is(ThmmyPage.
+ PageCategory.DOWNLOADS_CATEGORY))
+ type = Download.DownloadItemType.DOWNLOADS_CATEGORY;
+ else type = Download.DownloadItemType.DOWNLOADS_FILE;
+
+ Elements pages = downloadPage.select("a.navPages");
+ if (pages != null) {
+ for (Element page : pages) {
+ int pageNumber = Integer.parseInt(page.text());
+ if (pageNumber > numberOfPages) numberOfPages = pageNumber;
+ }
+ } else numberOfPages = 1;
+
+ Elements rows = downloadPage.select("table.tborder>tbody>tr");
+ if (type == Download.DownloadItemType.DOWNLOADS_CATEGORY) {
+ Elements navigationLinks = downloadPage.select("div.nav>b");
+ for (Element row : rows) {
+ if (row.select("td").size() == 1) continue;
+
+ String url = row.select("b>a").first().attr("href"),
+ title = row.select("b>a").first().text(),
+ subtitle = row.select("div.smalltext:not(:has(a))").text();
+ if (!row.select("td").last().hasClass("windowbg2")) {
+ if (navigationLinks.size() < 4) {
+
+ parsedDownloads.add(new Download(type, url, title, subtitle, null,
+ true, null));
+ } else {
+ String stats = row.text();
+ stats = stats.replace(title, "").replace(subtitle, "").trim();
+ parsedDownloads.add(new Download(type, url, title, subtitle, stats,
+ false, null));
+ }
+ } else {
+ String stats = row.text();
+ stats = stats.replace(title, "").replace(subtitle, "").trim();
+ parsedDownloads.add(new Download(type, url, title, subtitle, stats,
+ false, null));
+ }
+ }
+ } else {
+ parsedDownloads.add(new Download(type,
+ rows.select("b>a").first().attr("href"),
+ rows.select("b>a").first().text(),
+ rows.select("div.smalltext:not(:has(a))").text(),
+ rows.select("span:not(:has(a))").first().text(),
+ false,
+ rows.select("span:has(a)").first().text()));
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java
new file mode 100644
index 00000000..02c687df
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java
@@ -0,0 +1,187 @@
+package gr.thmmy.mthmmy.activities.downloads;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.model.Download;
+import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
+
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
+import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
+
+class DownloadsAdapter extends RecyclerView.Adapter {
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
+ @SuppressWarnings("unused")
+ private static final String TAG = "DownloadsAdapter";
+ private final int VIEW_TYPE_DOWNLOAD = 0;
+ private final int VIEW_TYPE_LOADING = 1;
+
+ private final Context context;
+ private ArrayList parsedDownloads = new ArrayList<>();
+ private final ArrayList downloadExpandableVisibility = new ArrayList<>();
+
+ DownloadsAdapter(Context context, ArrayList parsedDownloads) {
+ this.context = context;
+ this.parsedDownloads = parsedDownloads;
+ }
+
+ interface OnLoadMoreListener {
+ void onLoadMore();
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return (parsedDownloads.get(position) == null) ? VIEW_TYPE_LOADING : VIEW_TYPE_DOWNLOAD;
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == VIEW_TYPE_DOWNLOAD) {
+ View download = LayoutInflater.from(parent.getContext()).
+ inflate(R.layout.activity_downloads_row, parent, false);
+ return new DownloadViewHolder(download);
+ } else if (viewType == VIEW_TYPE_LOADING) {
+ View loading = LayoutInflater.from(parent.getContext()).
+ inflate(R.layout.recycler_loading_item, parent, false);
+ return new LoadingViewHolder(loading);
+ }
+ return null;
+ }
+
+ @Override
+ public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
+ if (holder instanceof DownloadViewHolder) {
+ final Download download = parsedDownloads.get(position);
+ final DownloadViewHolder downloadViewHolder = (DownloadViewHolder) holder;
+
+ if (downloadExpandableVisibility.size() != parsedDownloads.size()) {
+ for (int i = downloadExpandableVisibility.size(); i < parsedDownloads.size(); ++i)
+ downloadExpandableVisibility.add(false);
+ }
+
+ if (download.getType() == Download.DownloadItemType.DOWNLOADS_CATEGORY) {
+ downloadViewHolder.downloadRow.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(context, DownloadsActivity.class);
+ Bundle extras = new Bundle();
+ extras.putString(BUNDLE_DOWNLOADS_URL, download.getUrl());
+ extras.putString(BUNDLE_DOWNLOADS_TITLE, download.getTitle());
+ intent.putExtras(extras);
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+ }
+ });
+
+ if (downloadExpandableVisibility.get(downloadViewHolder.getAdapterPosition())) {
+ downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE);
+ downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up);
+ } else {
+ downloadViewHolder.informationExpandable.setVisibility(View.GONE);
+ downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down);
+ }
+ downloadViewHolder.informationExpandableBtn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ final boolean visible = downloadExpandableVisibility.get(downloadViewHolder.
+ getAdapterPosition());
+ if (visible) {
+ downloadViewHolder.informationExpandable.setVisibility(View.GONE);
+ downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down);
+ } else {
+ downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE);
+ downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up);
+ }
+ downloadExpandableVisibility.set(downloadViewHolder.getAdapterPosition(), !visible);
+ }
+ });
+ downloadViewHolder.title.setTypeface(Typeface.createFromAsset(context.getAssets()
+ , "fonts/fontawesome-webfont.ttf"));
+ if (download.hasSubCategory()) {
+ String tmp = context.getResources().getString(R.string.fa_folder) + " "
+ + download.getTitle();
+ downloadViewHolder.title.setText(tmp);
+ } else {
+ String tmp = context.getResources().getString(R.string.fa_file) + " "
+ + download.getTitle();
+ downloadViewHolder.title.setText(tmp);
+ }
+ } else {
+ //TODO implement download on click
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ downloadViewHolder.upperLinear.setBackgroundColor(context.getResources().getColor(R.color.background, null));
+ } else {
+ //noinspection deprecation
+ downloadViewHolder.upperLinear.setBackgroundColor(context.getResources().getColor(R.color.background));
+ }
+ downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE);
+ downloadViewHolder.informationExpandableBtn.setVisibility(View.GONE);
+ downloadViewHolder.informationExpandableBtn.setEnabled(false);
+ downloadViewHolder.title.setText(download.getTitle());
+ }
+
+ downloadViewHolder.subTitle.setText(download.getSubTitle());
+ String tmp = download.getExtraInfo();
+ if (tmp != null && !Objects.equals(tmp, ""))
+ downloadViewHolder.extraInfo.setText(tmp);
+ else downloadViewHolder.extraInfo.setVisibility(View.GONE);
+ tmp = download.getStatNumbers();
+ if (tmp != null && !Objects.equals(tmp, ""))
+ downloadViewHolder.uploaderDate.setText(tmp);
+ else downloadViewHolder.uploaderDate.setVisibility(View.GONE);
+ } else if (holder instanceof LoadingViewHolder) {
+ LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
+ loadingViewHolder.progressBar.setIndeterminate(true);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return parsedDownloads.size();
+ }
+
+ private static class DownloadViewHolder extends RecyclerView.ViewHolder {
+ final LinearLayout upperLinear, downloadRow, informationExpandable;
+ final TextView title, subTitle, extraInfo, uploaderDate;
+ final ImageButton informationExpandableBtn;
+
+ DownloadViewHolder(View download) {
+ super(download);
+ upperLinear = (LinearLayout) download.findViewById(R.id.upper_linear);
+ downloadRow = (LinearLayout) download.findViewById(R.id.download_row);
+ informationExpandable = (LinearLayout) download.findViewById(R.id.child_board_expandable);
+ title = (TextView) download.findViewById(R.id.download_title);
+ subTitle = (TextView) download.findViewById(R.id.download_sub_title);
+ extraInfo = (TextView) download.findViewById(R.id.download_extra_info);
+ uploaderDate = (TextView) download.findViewById(R.id.download_uploader_date);
+ informationExpandableBtn = (ImageButton) download.findViewById(R.id.download_information_button);
+ }
+ }
+
+ private static class LoadingViewHolder extends RecyclerView.ViewHolder {
+ final MaterialProgressBar progressBar;
+
+ LoadingViewHolder(View itemView) {
+ super(itemView);
+ progressBar = (MaterialProgressBar) itemView.findViewById(R.id.recycler_progress_bar);
+ }
+ }
+}
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 cb9981b1..65668324 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
@@ -1,6 +1,7 @@
package gr.thmmy.mthmmy.activities.main;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
@@ -8,20 +9,29 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
+import android.util.Log;
import android.widget.Toast;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.LoginActivity;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
import gr.thmmy.mthmmy.activities.board.BoardActivity;
+import gr.thmmy.mthmmy.activities.downloads.DownloadsActivity;
import gr.thmmy.mthmmy.activities.main.forum.ForumFragment;
import gr.thmmy.mthmmy.activities.main.recent.RecentFragment;
+import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
import gr.thmmy.mthmmy.activities.topic.TopicActivity;
+import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.model.Board;
+import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.model.TopicSummary;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
+import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
+import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
@@ -35,9 +45,13 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ final Intent intentFilter = getIntent();
+ redirectToActivityFromIntent(intentFilter);
setContentView(R.layout.activity_main);
- if (sessionManager.isLoginScreenDefault()) {
+ if (sessionManager.isLoginScreenDefault())
+
+ {
//Go to login
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
@@ -46,7 +60,10 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
}
//Initialize toolbar
- toolbar = (Toolbar) findViewById(R.id.toolbar);
+ toolbar = (Toolbar)
+
+ findViewById(R.id.toolbar);
+
setSupportActionBar(toolbar);
//Initialize drawer
@@ -63,6 +80,13 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
tabLayout.setupWithViewPager(mViewPager);
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ redirectToActivityFromIntent(intent);
+ setIntent(intent);
+ }
+
@Override
protected void onResume() {
drawer.setSelection(HOME_ID);
@@ -71,11 +95,10 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
@Override
public void onBackPressed() {
- if(drawer.isDrawerOpen()){
+ if (drawer.isDrawerOpen()) {
drawer.closeDrawer();
return;
- }
- else if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
+ } else if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
super.onBackPressed();
return;
} else {
@@ -117,10 +140,13 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
@Override
public Fragment getItem(int position) {
- switch(position) {
- case 0: return RecentFragment.newInstance(position +1);
- case 1: return ForumFragment.newInstance(position +1);
- default: return RecentFragment.newInstance(position +1); //temp (?)
+ switch (position) {
+ case 0:
+ return RecentFragment.newInstance(position + 1);
+ case 1:
+ return ForumFragment.newInstance(position + 1);
+ default:
+ return RecentFragment.newInstance(position + 1); //temp (?)
}
}
@@ -144,4 +170,41 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
}
//-------------------------------FragmentPagerAdapter END-------------------------------------------
+ private void redirectToActivityFromIntent(Intent intent) {
+ if (intent != null) {
+ Uri uri = intent.getData();
+ if (uri != null) {
+ Log.d(TAG, uri.toString());
+ ThmmyPage.PageCategory page = ThmmyPage.resolvePageCategory(uri);
+ if (!page.is(ThmmyPage.PageCategory.NOT_THMMY)) {
+ if (page.is(ThmmyPage.PageCategory.BOARD)) {
+ Intent redirectIntent = new Intent(MainActivity.this, BoardActivity.class);
+ redirectIntent.putExtra(BUNDLE_BOARD_URL, uri.toString());
+ redirectIntent.putExtra(BUNDLE_BOARD_TITLE, "");
+ startActivity(redirectIntent);
+ } else if (page.is(ThmmyPage.PageCategory.TOPIC)) {
+ Intent redirectIntent = new Intent(MainActivity.this, TopicActivity.class);
+ redirectIntent.putExtra(BUNDLE_TOPIC_URL, uri.toString());
+ redirectIntent.putExtra(BUNDLE_TOPIC_TITLE, "");
+ startActivity(redirectIntent);
+ } else if (page.is(ThmmyPage.PageCategory.PROFILE)) {
+ Intent redirectIntent = new Intent(MainActivity.this, ProfileActivity.class);
+ redirectIntent.putExtra(BUNDLE_PROFILE_URL, uri.toString());
+ redirectIntent.putExtra(BUNDLE_PROFILE_THUMBNAIL_URL, "");
+ redirectIntent.putExtra(BUNDLE_PROFILE_USERNAME, "");
+ startActivity(redirectIntent);
+ } else if (page.is(ThmmyPage.PageCategory.DOWNLOADS)) {
+ Intent redirectIntent = new Intent(MainActivity.this, DownloadsActivity.class);
+ redirectIntent.putExtra(BUNDLE_DOWNLOADS_URL, uri.toString());
+ redirectIntent.putExtra(BUNDLE_DOWNLOADS_TITLE, "");
+ startActivity(redirectIntent);
+ } else if (!page.is(ThmmyPage.PageCategory.INDEX)) {
+ Toast.makeText(this, "This thmmy sector is not yet supported.", Toast.LENGTH_LONG).show();
+ }
+ } else {
+ Toast.makeText(this, "This is not thmmy.", Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java
index 896078e8..40f14c93 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java
@@ -15,7 +15,7 @@ import com.bignerdranch.expandablerecyclerview.ParentViewHolder;
import java.util.List;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseFragment;
+import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.Board;
import gr.thmmy.mthmmy.model.Category;
import gr.thmmy.mthmmy.model.TopicSummary;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java
index 9b51c3af..d9777cf7 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java
@@ -24,8 +24,8 @@ import java.util.ArrayList;
import java.util.List;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
-import gr.thmmy.mthmmy.activities.base.BaseFragment;
+import gr.thmmy.mthmmy.base.BaseActivity;
+import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.Board;
import gr.thmmy.mthmmy.model.Category;
import gr.thmmy.mthmmy.session.SessionManager;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java
index beb22697..32e46af0 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java
@@ -11,7 +11,7 @@ import android.widget.TextView;
import java.util.List;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseFragment;
+import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.TopicSummary;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java
index 307f1b33..546b2db3 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java
@@ -23,7 +23,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseFragment;
+import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.TopicSummary;
import gr.thmmy.mthmmy.session.SessionManager;
import gr.thmmy.mthmmy.utils.CustomRecyclerView;
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 66e85146..5d604b00 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
@@ -1,6 +1,5 @@
package gr.thmmy.mthmmy.activities.profile;
-import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
@@ -12,8 +11,8 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.view.ViewPager;
-import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
+import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
@@ -33,14 +32,13 @@ import java.util.Objects;
import javax.net.ssl.SSLHandshakeException;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.LoginActivity;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
import gr.thmmy.mthmmy.activities.profile.latestPosts.LatestPostsFragment;
import gr.thmmy.mthmmy.activities.profile.stats.StatsFragment;
import gr.thmmy.mthmmy.activities.profile.summary.SummaryFragment;
import gr.thmmy.mthmmy.activities.topic.TopicActivity;
-import gr.thmmy.mthmmy.model.LinkTarget;
+import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.model.PostSummary;
+import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.utils.CircleTransform;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report;
@@ -53,8 +51,8 @@ import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
/**
* Activity for user profile. When creating an Intent of this activity you need to bundle a String
* containing this user's profile url using the key {@link #BUNDLE_PROFILE_URL}, a String containing
- * this user's avatar url using the key {@link #BUNDLE_THUMBNAIL_URL} and a String containing
- * the username using the key {@link #BUNDLE_USERNAME}.
+ * this user's avatar url using the key {@link #BUNDLE_PROFILE_THUMBNAIL_URL} and a String containing
+ * the username using the key {@link #BUNDLE_PROFILE_USERNAME}.
*/
public class ProfileActivity extends BaseActivity implements LatestPostsFragment.LatestPostsFragmentInteractionListener {
/**
@@ -70,15 +68,16 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
* The key to use when putting user's thumbnail url String to {@link ProfileActivity}'s Bundle.
* If user doesn't have a thumbnail put an empty string or leave it null.
*/
- public static final String BUNDLE_THUMBNAIL_URL = "THUMBNAIL_URL";
+ public static final String BUNDLE_PROFILE_THUMBNAIL_URL = "THUMBNAIL_URL";
/**
* The key to use when putting username String to {@link ProfileActivity}'s Bundle.
* If username is not available put an empty string or leave it null.
*/
- public static final String BUNDLE_USERNAME = "USERNAME";
+ public static final String BUNDLE_PROFILE_USERNAME = "USERNAME";
private static final int THUMBNAIL_SIZE = 200;
private TextView usernameView;
+ private ImageView thumbnailView;
private TextView personalTextView;
private MaterialProgressBar progressBar;
private FloatingActionButton pmFAB;
@@ -87,6 +86,7 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
private ProfileTask profileTask;
private String personalText;
private String profileUrl;
+ private String thumbnailUrl;
private String username;
private int tabSelect;
@@ -96,9 +96,10 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
setContentView(R.layout.activity_profile);
Bundle extras = getIntent().getExtras();
- String thumbnailUrl = extras.getString(BUNDLE_THUMBNAIL_URL);
+ thumbnailUrl = extras.getString(BUNDLE_PROFILE_THUMBNAIL_URL);
if (thumbnailUrl == null) thumbnailUrl = "";
- username = extras.getString(BUNDLE_USERNAME);
+ Log.d(TAG, "thumbnailUrl = " + thumbnailUrl);
+ username = extras.getString(BUNDLE_PROFILE_USERNAME);
profileUrl = extras.getString(BUNDLE_PROFILE_URL);
//Initializes graphic elements
@@ -114,7 +115,7 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
progressBar = (MaterialProgressBar) findViewById(R.id.progressBar);
- ImageView thumbnailView = (ImageView) findViewById(R.id.user_thumbnail);
+ thumbnailView = (ImageView) findViewById(R.id.user_thumbnail);
if (!Objects.equals(thumbnailUrl, ""))
//noinspection ConstantConditions
Picasso.with(this)
@@ -135,7 +136,8 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
pmFAB = (FloatingActionButton) findViewById(R.id.profile_fab);
pmFAB.setEnabled(false);
- if (!sessionManager.isLoggedIn()) pmFAB.hide();
+ pmFAB.hide();
+ /*if (!sessionManager.isLoggedIn()) pmFAB.hide();
else {
pmFAB.setOnClickListener(new View.OnClickListener() {
@Override
@@ -163,18 +165,18 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
}
}
});
- }
+ }*/
- LinkTarget.Target target = LinkTarget.resolveLinkTarget(Uri.parse(profileUrl));
- if (!target.is(LinkTarget.Target.PROFILE)) {
+ ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(profileUrl));
+ if (!target.is(ThmmyPage.PageCategory.PROFILE)) {
Report.e(TAG, "Bundle came with a non profile url!\nUrl:\n" + profileUrl);
Toast.makeText(this, "An error has occurred\n Aborting.", Toast.LENGTH_SHORT).show();
finish();
}
- if (target.is(LinkTarget.Target.PROFILE_STATS)) {
+ if (target.is(ThmmyPage.PageCategory.PROFILE_STATS)) {
profileUrl = profileUrl.substring(0, profileUrl.indexOf(";sa=statPanel"));
tabSelect = 2;
- } else if (target.is(LinkTarget.Target.PROFILE_LATEST_POSTS)) {
+ } else if (target.is(ThmmyPage.PageCategory.PROFILE_LATEST_POSTS)) {
profileUrl = profileUrl.substring(0, profileUrl.indexOf(";sa=showPosts"));
tabSelect = 1;
}
@@ -235,8 +237,18 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
if (username == null || Objects.equals(username, "")) {
username = profilePage.
select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) tr").
- first().text();
+ first().select("td").last().text();
+ }
+ Log.d(TAG, "thumbnailUrl = " + thumbnailUrl);
+ if (thumbnailUrl == null || Objects.equals(thumbnailUrl, "")) { //Maybe there is an avatar
+ Log.d(TAG, "thumbnailUrl = " + thumbnailUrl);
+ Element profileAvatar = profilePage
+ .select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) img.avatar")
+ .first();
+ if (profileAvatar != null) thumbnailUrl = profileAvatar.attr("abs:src");
}
+ Log.d(TAG, "thumbnailUrl = " + thumbnailUrl);
+ ;
{ //Finds personal text
Element tmpEl = profilePage.select("td.windowbg:nth-child(2)").first();
@@ -270,6 +282,18 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
progressBar.setVisibility(ProgressBar.INVISIBLE);
if (usernameView.getText() != username) usernameView.setText(username);
+ if (thumbnailUrl != null && !Objects.equals(thumbnailUrl, ""))
+ //noinspection ConstantConditions
+ Picasso.with(getApplicationContext())
+ .load(thumbnailUrl)
+ .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)
+ .centerCrop()
+ .error(ResourcesCompat.getDrawable(getResources()
+ , R.drawable.ic_default_user_thumbnail, null))
+ .placeholder(ResourcesCompat.getDrawable(getResources()
+ , R.drawable.ic_default_user_thumbnail, null))
+ .transform(new CircleTransform())
+ .into(thumbnailView);
if (personalText != null) personalTextView.setText(personalText);
setupViewPager(viewPager, profilePage);
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java
index 7976dd13..5f0f77d2 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java
@@ -11,7 +11,7 @@ import android.widget.TextView;
import java.util.ArrayList;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseFragment;
+import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.PostSummary;
import gr.thmmy.mthmmy.model.TopicSummary;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java
index 01786f3b..ccdb5593 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java
@@ -21,8 +21,8 @@ import java.util.ArrayList;
import javax.net.ssl.SSLHandshakeException;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
-import gr.thmmy.mthmmy.activities.base.BaseFragment;
+import gr.thmmy.mthmmy.base.BaseActivity;
+import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.PostSummary;
import gr.thmmy.mthmmy.utils.ParseHelpers;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
index c75d16bb..d99f7d65 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
@@ -38,7 +38,7 @@ import java.util.List;
import javax.net.ssl.SSLHandshakeException;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
+import gr.thmmy.mthmmy.base.BaseActivity;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report;
import okhttp3.Request;
@@ -248,11 +248,13 @@ public class StatsFragment extends Fragment {
postingActivityByTimeChartXAxis.setGranularity(1f);
LineDataSet postingActivityByTimeDataSet = new LineDataSet(postingActivityByTime, null);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient, null));
- } else
- //noinspection deprecation
- postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient));
+ if (isAdded()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient, null));
+ } else
+ //noinspection deprecation
+ postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient));
+ }
postingActivityByTimeDataSet.setDrawFilled(true);
postingActivityByTimeDataSet.setDrawCircles(false);
postingActivityByTimeDataSet.setDrawValues(false);
@@ -285,11 +287,13 @@ public class StatsFragment extends Fragment {
mostPopularBoardsByPostsChartYAxis.setGranularity(1f);
BarDataSet mostPopularBoardsByPostsDataSet = new BarDataSet(mostPopularBoardsByPosts, null);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent, null));
- } else
- //noinspection deprecation
- mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent));
+ if (isAdded()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent, null));
+ } else
+ //noinspection deprecation
+ mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent));
+ }
mostPopularBoardsByPostsDataSet.setDrawValues(false);
mostPopularBoardsByPostsDataSet.setValueTextColor(Color.WHITE);
@@ -324,11 +328,13 @@ public class StatsFragment extends Fragment {
mostPopularBoardsByActivityChartYAxis.setLabelCount(10, false);
BarDataSet mostPopularBoardsByActivityDataSet = new BarDataSet(mostPopularBoardsByActivity, null);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent, null));
- } else
- //noinspection deprecation
- mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent));
+ if (isAdded()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent, null));
+ } else
+ //noinspection deprecation
+ mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent));
+ }
mostPopularBoardsByActivityDataSet.setDrawValues(false);
mostPopularBoardsByActivityDataSet.setValueTextColor(Color.WHITE);
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java
index c621f295..1236b5a0 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java
@@ -82,7 +82,7 @@ public class SummaryFragment extends Fragment {
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_summary, container, false);
mainContent = (LinearLayout) rootView.findViewById(R.id.profile_activity_content);
- if (!parsedProfileSummaryData.isEmpty())
+ if (!parsedProfileSummaryData.isEmpty() && isAdded())
populateLayout();
return rootView;
}
@@ -126,7 +126,7 @@ public class SummaryFragment extends Fragment {
}
protected void onPostExecute(Void result) {
- populateLayout();
+ if (isAdded()) populateLayout();
}
/**
@@ -187,12 +187,12 @@ public class SummaryFragment extends Fragment {
}
TextView entry = new TextView(this.getContext());
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
entry.setTextColor(getResources().getColor(R.color.primary_text, null));
- } else {
+ else
//noinspection deprecation
entry.setTextColor(getResources().getColor(R.color.primary_text));
- }
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
entry.setText(Html.fromHtml(profileSummaryRow, Html.FROM_HTML_MODE_LEGACY));
} else {
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 3943bf0d..8bf4c7ac 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,13 +1,11 @@
package gr.thmmy.mthmmy.activities.topic;
-import android.content.DialogInterface;
-import android.content.Intent;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
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;
@@ -27,10 +25,10 @@ import java.util.ArrayList;
import java.util.Objects;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.LoginActivity;
-import gr.thmmy.mthmmy.activities.base.BaseActivity;
-import gr.thmmy.mthmmy.model.LinkTarget;
+import gr.thmmy.mthmmy.base.BaseActivity;
+import gr.thmmy.mthmmy.model.Bookmark;
import gr.thmmy.mthmmy.model.Post;
+import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.utils.ParseHelpers;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report;
@@ -69,7 +67,6 @@ public class TopicActivity extends BaseActivity {
public static final ArrayList toQuoteList = new ArrayList<>();
//Topic's pages
private int thisPage = 1;
- public static String base_url = "";
private int numberOfPages = 1;
private final SparseArray pagesUrls = new SparseArray<>();
//Page select
@@ -87,9 +84,10 @@ public class TopicActivity extends BaseActivity {
private ImageButton nextPage;
private ImageButton lastPage;
//Other variables
+ private FloatingActionButton replyFAB;
private MaterialProgressBar progressBar;
+ private static String base_url = "";
private String topicTitle;
- private FloatingActionButton replyFAB;
private String parsedTitle;
private RecyclerView recyclerView;
private String loadedPageUrl = "";
@@ -102,10 +100,11 @@ public class TopicActivity extends BaseActivity {
Bundle extras = getIntent().getExtras();
topicTitle = extras.getString(BUNDLE_TOPIC_TITLE);
- LinkTarget.Target target = LinkTarget.resolveLinkTarget(
- Uri.parse(extras.getString(BUNDLE_TOPIC_URL)));
- if (!target.is(LinkTarget.Target.TOPIC)) {
- Report.e(TAG, "Bundle came with a non topic url!\nUrl:\n" + extras.getString(BUNDLE_TOPIC_URL));
+ String topicPageUrl = extras.getString(BUNDLE_TOPIC_URL);
+ ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(
+ Uri.parse(topicPageUrl));
+ if (!target.is(ThmmyPage.PageCategory.TOPIC)) {
+ Report.e(TAG, "Bundle came with a non topic url!\nUrl:\n" + topicPageUrl);
Toast.makeText(this, "An error has occurred\n Aborting.", Toast.LENGTH_SHORT).show();
finish();
}
@@ -119,6 +118,9 @@ public class TopicActivity extends BaseActivity {
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
+ thisPageBookmark = new Bookmark(topicTitle, ThmmyPage.getTopicId(topicPageUrl));
+ thisPageBookmarkButton = (ImageButton) findViewById(R.id.bookmark);
+ setTopicBookmark();
createDrawer();
progressBar = (MaterialProgressBar) findViewById(R.id.progressBar);
@@ -129,13 +131,14 @@ public class TopicActivity extends BaseActivity {
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
- topicAdapter = new TopicAdapter(getApplicationContext(), progressBar, postsList,
+ topicAdapter = new TopicAdapter(this, postsList,
topicTask);
recyclerView.setAdapter(topicAdapter);
replyFAB = (FloatingActionButton) findViewById(R.id.topic_fab);
replyFAB.setEnabled(false);
- if (!sessionManager.isLoggedIn()) replyFAB.hide();
+ replyFAB.hide();
+ /*if (!sessionManager.isLoggedIn()) replyFAB.hide();
else {
replyFAB.setOnClickListener(new View.OnClickListener() {
@Override
@@ -163,7 +166,7 @@ public class TopicActivity extends BaseActivity {
}
}
});
- }
+ }*/
//Sets bottom navigation bar
firstPage = (ImageButton) findViewById(R.id.page_first_button);
@@ -176,11 +179,7 @@ public class TopicActivity extends BaseActivity {
initDecrementButton(previousPage, SMALL_STEP);
initIncrementButton(nextPage, SMALL_STEP);
initIncrementButton(lastPage, LARGE_STEP);
-
- firstPage.setEnabled(false);
- previousPage.setEnabled(false);
- nextPage.setEnabled(false);
- lastPage.setEnabled(false);
+ paginationEnabled(false);
//Gets posts
topicTask = new TopicTask();
@@ -210,19 +209,73 @@ public class TopicActivity extends BaseActivity {
topicTask.cancel(true);
}
- //--------------------------------------BOTTOM NAV BAR METHODS--------------------------------------
+ //--------------------------------------BOTTOM NAV BAR METHODS----------------------------------
+
+ /**
+ * 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;
+ }
+
+ public void run() {
+ long REPEAT_DELAY = 250;
+ if (autoIncrement) {
+ incrementPageRequestValue(step);
+ repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
+ } else if (autoDecrement) {
+ decrementPageRequestValue(step);
+ repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
+ }
+ }
+ }
+
+ private void paginationEnabled(boolean enabled) {
+ firstPage.setEnabled(enabled);
+ previousPage.setEnabled(enabled);
+ nextPage.setEnabled(enabled);
+ lastPage.setEnabled(enabled);
+ }
+
+ private void paginationEnabledExcept(boolean enabled, View exception) {
+ if (exception == firstPage) {
+ previousPage.setEnabled(enabled);
+ nextPage.setEnabled(enabled);
+ lastPage.setEnabled(enabled);
+ } else if (exception == previousPage) {
+ firstPage.setEnabled(enabled);
+ nextPage.setEnabled(enabled);
+ lastPage.setEnabled(enabled);
+ } else if (exception == nextPage) {
+ firstPage.setEnabled(enabled);
+ previousPage.setEnabled(enabled);
+ lastPage.setEnabled(enabled);
+ } else if (exception == lastPage) {
+ firstPage.setEnabled(enabled);
+ previousPage.setEnabled(enabled);
+ nextPage.setEnabled(enabled);
+ } else {
+ paginationEnabled(enabled);
+ }
+ }
+
private void initIncrementButton(ImageButton increment, final int step) {
// Increment once for a click
increment.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- if (!autoIncrement && step == LARGE_STEP) { //If just clicked go to last page
+ if (!autoIncrement && step == LARGE_STEP) {
changePage(numberOfPages - 1);
- return;
+ } else if (!autoIncrement) {
+ incrementPageRequestValue(step);
+ changePage(pageRequestValue - 1);
}
- //Clicked and holden
- autoIncrement = false; //Stop incrementing
- incrementPageRequestValue(step);
- changePage(pageRequestValue - 1);
}
});
@@ -230,6 +283,7 @@ public class TopicActivity extends BaseActivity {
increment.setOnLongClickListener(
new View.OnLongClickListener() {
public boolean onLongClick(View arg0) {
+ paginationEnabledExcept(false, arg0);
autoIncrement = true;
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), INITIAL_DELAY);
return false;
@@ -239,9 +293,21 @@ public class TopicActivity extends BaseActivity {
// When the button is released
increment.setOnTouchListener(new View.OnTouchListener() {
+ private Rect rect;
+
public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_UP && autoIncrement) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ } else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) {
+ autoIncrement = false;
+ paginationEnabled(true);
changePage(pageRequestValue - 1);
+ } else if (rect != null && event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
+ autoIncrement = false;
+ decrementPageRequestValue(pageRequestValue - thisPage);
+ paginationEnabled(true);
+ }
}
return false;
}
@@ -252,22 +318,20 @@ public class TopicActivity extends BaseActivity {
// Decrement once for a click
decrement.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- if (!autoDecrement && step == LARGE_STEP) { //If just clicked go to first page
+ if (!autoDecrement && step == LARGE_STEP) {
changePage(0);
- return;
+ } else if (!autoDecrement) {
+ decrementPageRequestValue(step);
+ changePage(pageRequestValue - 1);
}
- //Clicked and hold
- autoDecrement = false; //Stop decrementing
- decrementPageRequestValue(step);
- changePage(pageRequestValue - 1);
}
});
-
// Auto decrement for a long click
decrement.setOnLongClickListener(
new View.OnLongClickListener() {
public boolean onLongClick(View arg0) {
+ paginationEnabledExcept(false, arg0);
autoDecrement = true;
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), INITIAL_DELAY);
return false;
@@ -277,9 +341,21 @@ public class TopicActivity extends BaseActivity {
// When the button is released
decrement.setOnTouchListener(new View.OnTouchListener() {
+ private Rect rect;
+
public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ } else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) {
+ autoDecrement = false;
+ paginationEnabled(true);
changePage(pageRequestValue - 1);
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
+ autoIncrement = false;
+ incrementPageRequestValue(thisPage - pageRequestValue);
+ paginationEnabled(true);
+ }
}
return false;
}
@@ -333,15 +409,16 @@ public class TopicActivity extends BaseActivity {
private static final int OTHER_ERROR = 2;
private static final int SAME_PAGE = 3;
+ @Override
protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE);
- paginationEnable(false);
+ paginationEnabled(false);
if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(false);
}
protected Integer doInBackground(String... strings) {
Document document;
- base_url = strings[0].substring(0, strings[0].lastIndexOf(".")); //This topic's base url
+ base_url = strings[0].substring(0, strings[0].lastIndexOf(".")); //New topic's base url
String newPageUrl = strings[0];
//Finds the index of message focus if present
@@ -351,20 +428,30 @@ public class TopicActivity extends BaseActivity {
String tmp = newPageUrl.substring(newPageUrl.indexOf("msg") + 3);
if (tmp.contains(";"))
postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf(";")));
- else
+ else if (tmp.contains("#"))
postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf("#")));
}
}
//Checks if the page to be loaded is the one already shown
- if (!Objects.equals(loadedPageUrl, "") && !loadedPageUrl.contains(base_url)) {
+ if (!Objects.equals(loadedPageUrl, "") && loadedPageUrl.contains(base_url)) {
if (newPageUrl.contains("topicseen#new"))
- if (Integer.parseInt(loadedPageUrl.substring(base_url.length())) == numberOfPages)
+ if (thisPage == numberOfPages)
return SAME_PAGE;
- if (Objects.equals(loadedPageUrl.substring(base_url.length())
- , newPageUrl.substring(base_url.length())))
+ if (newPageUrl.contains("msg")) {
+ String tmpUrlSbstr = newPageUrl.substring(newPageUrl.indexOf("msg") + 3);
+ if (tmpUrlSbstr.contains("msg"))
+ tmpUrlSbstr = tmpUrlSbstr.substring(0, tmpUrlSbstr.indexOf("msg") - 1);
+ int testAgainst = Integer.parseInt(tmpUrlSbstr);
+ for (Post post : postsList) {
+ if (post.getPostIndex() == testAgainst) {
+ return SAME_PAGE;
+ }
+ }
+ }
+ if (Integer.parseInt(newPageUrl.substring(base_url.length() + 1)) / 15 + 1 == thisPage)
return SAME_PAGE;
- }
+ } else if (!Objects.equals(loadedPageUrl, "")) topicTitle = null;
loadedPageUrl = newPageUrl;
Request request = new Request.Builder()
@@ -395,6 +482,11 @@ public class TopicActivity extends BaseActivity {
switch (parseResult) {
case SUCCESS:
+ if (topicTitle == null || Objects.equals(topicTitle, "")) {
+ thisPageBookmark = new Bookmark(parsedTitle, ThmmyPage.getTopicId(loadedPageUrl));
+ setTopicBookmark();
+ }
+
progressBar.setVisibility(ProgressBar.INVISIBLE);
topicAdapter.customNotifyDataSetChanged(new TopicTask());
if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(true);
@@ -403,7 +495,7 @@ public class TopicActivity extends BaseActivity {
pageIndicator.setText(String.valueOf(thisPage) + "/" + String.valueOf(numberOfPages));
pageRequestValue = thisPage;
- paginationEnable(true);
+ paginationEnabled(true);
if (topicTitle == null || Objects.equals(topicTitle, ""))
toolbar.setTitle(parsedTitle);
@@ -412,6 +504,11 @@ public class TopicActivity extends BaseActivity {
Toast.makeText(getBaseContext(), "Network Error", Toast.LENGTH_SHORT).show();
break;
case SAME_PAGE:
+ progressBar.setVisibility(ProgressBar.INVISIBLE);
+ topicAdapter.customNotifyDataSetChanged(new TopicTask());
+ if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(true);
+ paginationEnabled(true);
+ Toast.makeText(TopicActivity.this, "That's the same page.", Toast.LENGTH_SHORT).show();
//TODO change focus
break;
default:
@@ -462,37 +559,4 @@ public class TopicActivity extends BaseActivity {
//postsList = TopicParser.parseTopic(topic, language);
}
}
-
- /**
- * 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;
- }
-
- public void run() {
- long REPEAT_DELAY = 250;
- if (autoIncrement) {
- incrementPageRequestValue(step);
- repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
- } else if (autoDecrement) {
- decrementPageRequestValue(step);
- repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
- }
- }
- }
-
- private void paginationEnable(boolean enabled) {
- firstPage.setEnabled(enabled);
- previousPage.setEnabled(enabled);
- nextPage.setEnabled(enabled);
- lastPage.setEnabled(enabled);
- }
}
\ 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 f44e3a65..b03b56e5 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,21 +7,17 @@ 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.PowerManager;
import android.support.annotation.NonNull;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
-import android.util.Log;
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,12 +27,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
-import android.widget.Toast;
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;
@@ -44,20 +37,19 @@ import java.util.Objects;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.board.BoardActivity;
import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
-import gr.thmmy.mthmmy.model.LinkTarget;
+import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.model.Post;
+import gr.thmmy.mthmmy.model.ThmmyFile;
+import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.utils.CircleTransform;
-import gr.thmmy.mthmmy.utils.FileManager.ThmmyFile;
-import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
-import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_THUMBNAIL_URL;
-import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_USERNAME;
-import static gr.thmmy.mthmmy.activities.topic.TopicActivity.base_url;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.toQuoteList;
/**
@@ -94,8 +86,6 @@ class TopicAdapter extends RecyclerView.Adapter {
* Index of state indicator in the boolean array. If true quote button for this post is checked.
*/
private static final int isQuoteButtonChecked = 2;
- private final MaterialProgressBar progressBar;
- private DownloadTask downloadTask;
private TopicActivity.TopicTask topicTask;
/**
@@ -158,7 +148,7 @@ class TopicAdapter extends RecyclerView.Adapter {
* @param context the context of the {@link RecyclerView}
* @param postsList List of {@link Post} objects to use
*/
- TopicAdapter(Context context, MaterialProgressBar progressBar, List postsList,
+ TopicAdapter(Context context, List postsList,
TopicActivity.TopicTask topicTask) {
this.context = context;
this.postsList = postsList;
@@ -168,8 +158,6 @@ class TopicAdapter extends RecyclerView.Adapter {
//Initializes properties, array's values will be false by default
viewProperties.add(new boolean[3]);
}
- this.progressBar = progressBar;
- downloadTask = new DownloadTask();
this.topicTask = topicTask;
}
@@ -231,6 +219,7 @@ class TopicAdapter extends RecyclerView.Adapter {
} else //noinspection deprecation
filesTextColor = context.getResources().getColor(R.color.accent);
+ holder.postFooter.removeAllViews();
for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) {
final TextView attached = new TextView(context);
attached.setTextSize(10f);
@@ -245,8 +234,7 @@ class TopicAdapter extends RecyclerView.Adapter {
attached.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- downloadTask = new DownloadTask();
- downloadTask.execute(attachedFile);
+ ((BaseActivity) context).launchDownloadService(attachedFile);
}
});
@@ -257,67 +245,85 @@ class TopicAdapter extends RecyclerView.Adapter {
holder.postFooter.removeAllViews();
}
+ String mSpecialRank, mRank, mGender, mNumberOfPosts, mPersonalText;
+ int mNumberOfStars, mUserColor;
+
if (!currentPost.isDeleted()) { //Sets user's extra info
- String mSpecialRank = currentPost.getSpecialRank(), mRank = currentPost.getRank(), mGender = currentPost.getGender(), mNumberOfPosts = currentPost.getNumberOfPosts(), mPersonalText = currentPost.getPersonalText();
- int mNumberOfStars = currentPost.getNumberOfStars(), mUserColor = currentPost.getUserColor();
-
- if (!Objects.equals(mSpecialRank, "") && mSpecialRank != null) {
- holder.specialRank.setText(mSpecialRank);
- holder.specialRank.setVisibility(View.VISIBLE);
- } else
- holder.specialRank.setVisibility(View.GONE);
- if (!Objects.equals(mRank, "") && mRank != null) {
- holder.rank.setText(mRank);
- holder.rank.setVisibility(View.VISIBLE);
- } else
- holder.rank.setVisibility(View.GONE);
- if (!Objects.equals(mGender, "") && mGender != null) {
- holder.gender.setText(mGender);
- holder.gender.setVisibility(View.VISIBLE);
- } else
- holder.gender.setVisibility(View.GONE);
- if (!Objects.equals(mNumberOfPosts, "") && mNumberOfPosts != null) {
- holder.numberOfPosts.setText(mNumberOfPosts);
- holder.numberOfPosts.setVisibility(View.VISIBLE);
- } else
- holder.numberOfPosts.setVisibility(View.GONE);
- if (!Objects.equals(mPersonalText, "") && mPersonalText != null) {
- holder.personalText.setText("\"" + mPersonalText + "\"");
- holder.personalText.setVisibility(View.VISIBLE);
- } else
- holder.personalText.setVisibility(View.GONE);
- if (mNumberOfStars > 0) {
- holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets()
- , "fonts/fontawesome-webfont.ttf"));
+ mSpecialRank = currentPost.getSpecialRank();
+ mRank = currentPost.getRank();
+ mGender = currentPost.getGender();
+ mNumberOfPosts = currentPost.getNumberOfPosts();
+ mPersonalText = currentPost.getPersonalText();
+ mNumberOfStars = currentPost.getNumberOfStars();
+ mUserColor = currentPost.getUserColor();
+ } else {
+ mSpecialRank = null;
+ mRank = null;
+ mGender = null;
+ mNumberOfPosts = null;
+ mPersonalText = null;
+ mNumberOfStars = 0;
+ mUserColor = 0;
+ }
- String aStar = context.getResources().getString(R.string.fa_icon_star);
- String usersStars = "";
- for (int i = 0; i < mNumberOfStars; ++i) {
- usersStars += aStar;
- }
- holder.stars.setText(usersStars);
- holder.stars.setTextColor(mUserColor);
- holder.stars.setVisibility(View.VISIBLE);
- } else
- holder.stars.setVisibility(View.GONE);
- //Special card for special member of the month!
- if (mUserColor == TopicParser.USER_COLOR_PINK) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- holder.cardChildLinear.setBackground(context.getResources().
- getDrawable(R.drawable.member_of_the_month_card, null));
- } else //noinspection deprecation
- holder.cardChildLinear.setBackground(context.getResources().
- getDrawable(R.drawable.member_of_the_month_card));
- } else holder.cardChildLinear.setBackground(null);
-
- //Avoid's view's visibility recycling
- if (viewProperties.get(position)[isUserExtraInfoVisibile]) {
- holder.userExtraInfo.setVisibility(View.VISIBLE);
- holder.userExtraInfo.setAlpha(1.0f);
- } else {
- holder.userExtraInfo.setVisibility(View.GONE);
- holder.userExtraInfo.setAlpha(0.0f);
+ if (!Objects.equals(mSpecialRank, "") && mSpecialRank != null) {
+ holder.specialRank.setText(mSpecialRank);
+ holder.specialRank.setVisibility(View.VISIBLE);
+ } else
+ holder.specialRank.setVisibility(View.GONE);
+ if (!Objects.equals(mRank, "") && mRank != null) {
+ holder.rank.setText(mRank);
+ holder.rank.setVisibility(View.VISIBLE);
+ } else
+ holder.rank.setVisibility(View.GONE);
+ if (!Objects.equals(mGender, "") && mGender != null) {
+ holder.gender.setText(mGender);
+ holder.gender.setVisibility(View.VISIBLE);
+ } else
+ holder.gender.setVisibility(View.GONE);
+ if (!Objects.equals(mNumberOfPosts, "") && mNumberOfPosts != null) {
+ holder.numberOfPosts.setText(mNumberOfPosts);
+ holder.numberOfPosts.setVisibility(View.VISIBLE);
+ } else
+ holder.numberOfPosts.setVisibility(View.GONE);
+ if (!Objects.equals(mPersonalText, "") && mPersonalText != null) {
+ holder.personalText.setText("\"" + mPersonalText + "\"");
+ holder.personalText.setVisibility(View.VISIBLE);
+ } else
+ holder.personalText.setVisibility(View.GONE);
+ if (mNumberOfStars > 0) {
+ holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets()
+ , "fonts/fontawesome-webfont.ttf"));
+
+ String aStar = context.getResources().getString(R.string.fa_icon_star);
+ String usersStars = "";
+ for (int i = 0; i < mNumberOfStars; ++i) {
+ usersStars += aStar;
}
+ holder.stars.setText(usersStars);
+ holder.stars.setTextColor(mUserColor);
+ holder.stars.setVisibility(View.VISIBLE);
+ } else
+ holder.stars.setVisibility(View.GONE);
+ //Special card for special member of the month!
+ if (mUserColor == TopicParser.USER_COLOR_PINK) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ holder.cardChildLinear.setBackground(context.getResources().
+ getDrawable(R.drawable.member_of_the_month_card, null));
+ } else //noinspection deprecation
+ holder.cardChildLinear.setBackground(context.getResources().
+ getDrawable(R.drawable.member_of_the_month_card));
+ } else holder.cardChildLinear.setBackground(null);
+
+ //Avoid's view's visibility recycling
+ if (!currentPost.isDeleted() && viewProperties.get(position)[isUserExtraInfoVisibile]) {
+ holder.userExtraInfo.setVisibility(View.VISIBLE);
+ holder.userExtraInfo.setAlpha(1.0f);
+ } else {
+ holder.userExtraInfo.setVisibility(View.GONE);
+ holder.userExtraInfo.setAlpha(0.0f);
+ }
+ if (!currentPost.isDeleted()) {
//Sets graphics behavior
holder.header.setOnClickListener(new View.OnClickListener() {
@Override
@@ -328,10 +334,10 @@ class TopicAdapter extends RecyclerView.Adapter {
Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, currentPost.getProfileURL());
if (currentPost.getThumbnailUrl() == null)
- extras.putString(BUNDLE_THUMBNAIL_URL, "");
+ extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
else
- extras.putString(BUNDLE_THUMBNAIL_URL, currentPost.getThumbnailUrl());
- extras.putString(BUNDLE_USERNAME, currentPost.getAuthor());
+ extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, currentPost.getThumbnailUrl());
+ extras.putString(BUNDLE_PROFILE_USERNAME, currentPost.getAuthor());
intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
@@ -354,7 +360,11 @@ class TopicAdapter extends RecyclerView.Adapter {
TopicAnimations.animateUserExtraInfoVisibility(v);
}
});
- }//End of deleted profiles
+ } else {
+ holder.header.setOnClickListener(null);
+ holder.userExtraInfo.setOnClickListener(null);
+ }
+
//Avoid's view's visibility recycling
if (viewProperties.get(position)[isPostDateAndNumberVisibile]) { //Expanded
holder.postDateAndNumberExp.setVisibility(View.VISIBLE);
@@ -526,11 +536,11 @@ class TopicAdapter extends RecyclerView.Adapter {
private boolean handleUri(final Uri uri) {
final String uriString = uri.toString();
- LinkTarget.Target target = LinkTarget.resolveLinkTarget(uri);
- if (target.is(LinkTarget.Target.TOPIC)) {
+ ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(uri);
+ if (target.is(ThmmyPage.PageCategory.TOPIC)) {
//This url points to a topic
//Checks if this is the current topic
- if (Objects.equals(uriString.substring(0, uriString.lastIndexOf(".")), base_url)) {
+ /*if (Objects.equals(uriString.substring(0, uriString.lastIndexOf(".")), base_url)) {
//Gets uri's targeted message's index number
String msgIndexReq = uriString.substring(uriString.indexOf("msg") + 3);
if (msgIndexReq.contains("#"))
@@ -545,10 +555,11 @@ class TopicAdapter extends RecyclerView.Adapter {
return true;
}
}
- }
+ }*/
+
topicTask.execute(uri.toString());
return true;
- } else if (target.is(LinkTarget.Target.BOARD)) {
+ } else if (target.is(ThmmyPage.PageCategory.BOARD)) {
Intent intent = new Intent(context, BoardActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_BOARD_URL, uriString);
@@ -557,12 +568,12 @@ class TopicAdapter extends RecyclerView.Adapter {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
return true;
- } else if (target.is(LinkTarget.Target.PROFILE)) {
+ } else if (target.is(ThmmyPage.PageCategory.PROFILE)) {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, uriString);
- extras.putString(BUNDLE_THUMBNAIL_URL, "");
- extras.putString(BUNDLE_USERNAME, "");
+ extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
+ extras.putString(BUNDLE_PROFILE_USERNAME, "");
intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
@@ -610,58 +621,4 @@ 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
- private PowerManager.WakeLock mWakeLock;
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- //Locks CPU to prevent going off
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- getClass().getName());
- mWakeLock.acquire();
- progressBar.setVisibility(View.VISIBLE);
- }
-
- @Override
- protected String doInBackground(ThmmyFile... files) {
- try {
- File tempFile = files[0].download(context);
- if (tempFile != null) {
- String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- files[0].getExtension());
-
- Intent intent = new Intent();
- intent.setAction(android.content.Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.fromFile(tempFile), 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 e.toString();
- } catch (OutOfMemoryError e) {
- Report.e(TAG, "Error while trying to download a file", e);
- return e.toString();
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(String result) {
- mWakeLock.release();
- if (result != null)
- Toast.makeText(context, result, Toast.LENGTH_SHORT).show();
- else
- Toast.makeText(context, "Download complete", Toast.LENGTH_SHORT).show();
- progressBar.setVisibility(View.INVISIBLE);
- }
- }
}
\ 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 538dec17..9cab0649 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
@@ -15,7 +15,7 @@ import java.util.List;
import java.util.Objects;
import gr.thmmy.mthmmy.model.Post;
-import gr.thmmy.mthmmy.utils.FileManager.ThmmyFile;
+import gr.thmmy.mthmmy.model.ThmmyFile;
import gr.thmmy.mthmmy.utils.ParseHelpers;
import mthmmy.utils.Report;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
new file mode 100644
index 00000000..501e2452
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
@@ -0,0 +1,565 @@
+package gr.thmmy.mthmmy.base;
+
+import android.Manifest;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.Toast;
+
+import com.mikepenz.fontawesome_typeface_library.FontAwesome;
+import com.mikepenz.iconics.IconicsDrawable;
+import com.mikepenz.materialdrawer.AccountHeader;
+import com.mikepenz.materialdrawer.AccountHeaderBuilder;
+import com.mikepenz.materialdrawer.Drawer;
+import com.mikepenz.materialdrawer.DrawerBuilder;
+import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
+import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
+import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
+import com.mikepenz.materialdrawer.model.interfaces.IProfile;
+
+import java.util.ArrayList;
+
+import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.activities.AboutActivity;
+import gr.thmmy.mthmmy.activities.BookmarkActivity;
+import gr.thmmy.mthmmy.activities.LoginActivity;
+import gr.thmmy.mthmmy.activities.downloads.DownloadsActivity;
+import gr.thmmy.mthmmy.activities.main.MainActivity;
+import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
+import gr.thmmy.mthmmy.model.Bookmark;
+import gr.thmmy.mthmmy.model.ThmmyFile;
+import gr.thmmy.mthmmy.services.DownloadService;
+import gr.thmmy.mthmmy.session.SessionManager;
+import okhttp3.OkHttpClient;
+
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
+import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
+import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
+
+public abstract class BaseActivity extends AppCompatActivity {
+ // Client & Cookies
+ protected static OkHttpClient client;
+
+ //SessionManager
+ protected static SessionManager sessionManager;
+
+ //Bookmarks
+ private static final String BOOKMARKS_SHARED_PREFS = "bookmarksSharedPrefs";
+ private static final String BOOKMARKED_TOPICS_KEY = "bookmarkedTopicsKey";
+ private static final String BOOKMARKED_BOARDS_KEY = "bookmarkedBoardsKey";
+ protected Bookmark thisPageBookmark;
+ protected ImageButton thisPageBookmarkButton;
+ private SharedPreferences bookmarksFile;
+ private ArrayList topicsBookmarked;
+ private ArrayList boardsBookmarked;
+ private static Drawable bookmarked;
+ private static Drawable notBookmarked;
+
+ //Common UI elements
+ protected Toolbar toolbar;
+ protected Drawer drawer;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (client == null)
+ client = BaseApplication.getInstance().getClient(); //must check every time - e.g.
+ // they become null when app restarts after crash
+ if (sessionManager == null)
+ sessionManager = BaseApplication.getInstance().getSessionManager();
+
+
+ if (sessionManager.isLoggedIn()) {
+ if (bookmarked == null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ bookmarked = getResources().getDrawable(R.drawable.ic_bookmark_true, null);
+ } else //noinspection deprecation
+ bookmarked = getResources().getDrawable(R.drawable.ic_bookmark_true);
+ }
+ if (notBookmarked == null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ notBookmarked = getResources().getDrawable(R.drawable.ic_bookmark_false, null);
+ } else //noinspection deprecation
+ notBookmarked = getResources().getDrawable(R.drawable.ic_bookmark_false);
+ }
+ if (topicsBookmarked == null || boardsBookmarked == null) {
+ bookmarksFile = getSharedPreferences(BOOKMARKS_SHARED_PREFS, Context.MODE_PRIVATE);
+ loadSavedBookmarks();
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateDrawer();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (drawer != null) //close drawer animation after returning to activity
+ drawer.closeDrawer();
+ }
+
+
+ public static OkHttpClient getClient() {
+ return client;
+ }
+
+ public static SessionManager getSessionManager() {
+ return sessionManager;
+ }
+
+ //TODO: move stuff below (?)
+ //------------------------------------------DRAWER STUFF----------------------------------------
+ protected static final int HOME_ID = 0;
+ protected static final int DOWNLOADS_ID = 1;
+ protected static final int BOOKMARKS_ID = 2;
+ protected static final int LOG_ID = 3;
+ protected static final int ABOUT_ID = 4;
+
+ private AccountHeader accountHeader;
+ private ProfileDrawerItem profileDrawerItem;
+ private PrimaryDrawerItem homeItem, downloadsItem, bookmarksItem, loginLogoutItem, aboutItem;
+ private IconicsDrawable homeIcon, homeIconSelected, downloadsIcon, downloadsIconSelected,
+ bookmarksIcon, bookmarksIconSelected, loginIcon, logoutIcon, aboutIcon,
+ aboutIconSelected;
+
+ /**
+ * Call only after initializing Toolbar
+ */
+ protected void createDrawer() {
+ final int primaryColor = ContextCompat.getColor(this, R.color.iron);
+ final int selectedPrimaryColor = ContextCompat.getColor(this, R.color.primary_dark);
+ final int selectedSecondaryColor = ContextCompat.getColor(this, R.color.accent);
+
+ //Drawer Icons
+ homeIcon = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_home)
+ .color(primaryColor);
+
+ homeIconSelected = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_home)
+ .color(selectedSecondaryColor);
+
+ downloadsIcon = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_download)
+ .color(primaryColor);
+
+ downloadsIconSelected = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_download)
+ .color(selectedSecondaryColor);
+
+ bookmarksIcon = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_bookmark)
+ .color(primaryColor);
+
+ bookmarksIconSelected = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_bookmark)
+ .color(selectedSecondaryColor);
+
+ loginIcon = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_sign_in)
+ .color(primaryColor);
+
+ logoutIcon = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_sign_out)
+ .color(primaryColor);
+
+ aboutIcon = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_info_circle)
+ .color(primaryColor);
+
+ aboutIconSelected = new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_info_circle)
+ .color(selectedSecondaryColor);
+
+ //Drawer Items
+ homeItem = new PrimaryDrawerItem()
+ .withTextColor(primaryColor)
+ .withSelectedColor(selectedPrimaryColor)
+ .withSelectedTextColor(selectedSecondaryColor)
+ .withIdentifier(HOME_ID)
+ .withName(R.string.home)
+ .withIcon(homeIcon)
+ .withSelectedIcon(homeIconSelected);
+
+
+ if (sessionManager.isLoggedIn()) //When logged in
+ {
+ loginLogoutItem = new PrimaryDrawerItem()
+ .withTextColor(primaryColor)
+ .withSelectedColor(selectedSecondaryColor)
+ .withIdentifier(LOG_ID)
+ .withName(R.string.logout)
+ .withIcon(logoutIcon)
+ .withSelectable(false);
+ downloadsItem = new PrimaryDrawerItem()
+ .withTextColor(primaryColor)
+ .withSelectedColor(selectedPrimaryColor)
+ .withSelectedTextColor(selectedSecondaryColor)
+ .withIdentifier(DOWNLOADS_ID)
+ .withName(R.string.downloads)
+ .withIcon(downloadsIcon)
+ .withSelectedIcon(downloadsIconSelected);
+ bookmarksItem = new PrimaryDrawerItem()
+ .withTextColor(primaryColor)
+ .withSelectedColor(selectedPrimaryColor)
+ .withSelectedTextColor(selectedSecondaryColor)
+ .withIdentifier(BOOKMARKS_ID)
+ .withName(R.string.bookmark)
+ .withIcon(bookmarksIcon)
+ .withSelectedIcon(bookmarksIconSelected);
+ } else
+ loginLogoutItem = new PrimaryDrawerItem()
+ .withTextColor(primaryColor)
+ .withSelectedColor(selectedSecondaryColor)
+ .withIdentifier(LOG_ID).withName(R.string.login)
+ .withIcon(loginIcon)
+ .withSelectable(false);
+
+ aboutItem = new PrimaryDrawerItem()
+ .withTextColor(primaryColor)
+ .withSelectedColor(selectedPrimaryColor)
+ .withSelectedTextColor(selectedSecondaryColor)
+ .withIdentifier(ABOUT_ID)
+ .withName(R.string.about)
+ .withIcon(aboutIcon)
+ .withSelectedIcon(aboutIconSelected);
+
+ //Profile
+ profileDrawerItem = new ProfileDrawerItem().withName(sessionManager.getUsername());
+
+ //AccountHeader
+ accountHeader = new AccountHeaderBuilder()
+ .withActivity(this)
+ .withCompactStyle(true)
+ .withSelectionListEnabledForSingleProfile(false)
+ .withHeaderBackground(R.color.primary)
+ .addProfiles(profileDrawerItem)
+ .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
+ @Override
+ public boolean onProfileChanged(View view, IProfile profile, boolean currentProfile) {
+ if (sessionManager.isLoggedIn()) {
+ Intent intent = new Intent(BaseActivity.this, ProfileActivity.class);
+ Bundle extras = new Bundle();
+ extras.putString(BUNDLE_PROFILE_URL, "https://www.thmmy.gr/smf/index.php?action=profile");
+ if (!sessionManager.hasAvatar())
+ extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
+ else
+ extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, sessionManager.getAvatarLink());
+ extras.putString(BUNDLE_PROFILE_USERNAME, sessionManager.getUsername());
+ intent.putExtras(extras);
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ return false;
+ }
+ return true;
+
+ }
+ })
+ .build();
+
+ //Drawer
+ DrawerBuilder drawerBuilder = new DrawerBuilder()
+ .withActivity(this)
+ .withToolbar(toolbar)
+ .withDrawerWidthDp((int) BaseApplication.getInstance().getDpWidth() / 2)
+ .withSliderBackgroundColor(ContextCompat.getColor(this, R.color.primary_light))
+ .withAccountHeader(accountHeader)
+ .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
+ @Override
+ public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
+ if (drawerItem.equals(HOME_ID)) {
+ if (!(BaseActivity.this instanceof MainActivity)) {
+ Intent i = new Intent(BaseActivity.this, MainActivity.class);
+ startActivity(i);
+ }
+ } else if (drawerItem.equals(DOWNLOADS_ID)) {
+ if (!(BaseActivity.this instanceof DownloadsActivity)) {
+ Intent i = new Intent(BaseActivity.this, DownloadsActivity.class);
+ Bundle extras = new Bundle();
+ extras.putString(BUNDLE_DOWNLOADS_URL, "");
+ extras.putString(BUNDLE_DOWNLOADS_TITLE, null);
+ i.putExtras(extras);
+ startActivity(i);
+ }
+ } else if (drawerItem.equals(BOOKMARKS_ID)) {
+ if (!(BaseActivity.this instanceof BookmarkActivity)) {
+ Intent i = new Intent(BaseActivity.this, BookmarkActivity.class);
+ startActivity(i);
+ }
+ } else if (drawerItem.equals(LOG_ID)) {
+ if (!sessionManager.isLoggedIn()) //When logged out or if user is guest
+ {
+ Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
+ startActivity(intent);
+ finish();
+ overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out);
+ } else
+ new LogoutTask().execute();
+ } else if (drawerItem.equals(ABOUT_ID)) {
+ if (!(BaseActivity.this instanceof AboutActivity)) {
+ Intent i = new Intent(BaseActivity.this, AboutActivity.class);
+ startActivity(i);
+ }
+
+ }
+
+ drawer.closeDrawer();
+ return true;
+ }
+ });
+
+ if (sessionManager.isLoggedIn())
+ drawerBuilder.addDrawerItems(homeItem, bookmarksItem, downloadsItem, loginLogoutItem, aboutItem);
+ else
+ drawerBuilder.addDrawerItems(homeItem, loginLogoutItem, aboutItem);
+
+ drawer = drawerBuilder.build();
+
+ drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(false);
+ drawer.setOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
+ @Override
+ public boolean onNavigationClickListener(View clickedView) {
+ onBackPressed();
+ return true;
+ }
+ });
+ }
+
+ protected void updateDrawer() {
+ if (drawer != null) {
+ if (!sessionManager.isLoggedIn()) //When logged out or if user is guest
+ {
+ drawer.removeItem(DOWNLOADS_ID);
+ drawer.removeItem(BOOKMARKS_ID);
+ loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login
+ profileDrawerItem.withName(sessionManager.getUsername()).withIcon(new IconicsDrawable(this)
+ .icon(FontAwesome.Icon.faw_user)
+ .paddingDp(10)
+ .color(ContextCompat.getColor(this, R.color.primary_light))
+ .backgroundColor(ContextCompat.getColor(this, R.color.primary)));
+ } else {
+ loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout
+ profileDrawerItem.withName(sessionManager.getUsername()).withIcon(sessionManager.getAvatarLink());
+ }
+ accountHeader.updateProfile(profileDrawerItem);
+ drawer.updateItem(loginLogoutItem);
+
+ }
+ }
+
+
+//-------------------------------------------LOGOUT-------------------------------------------------
+
+ /**
+ * Result toast will always display a success, because when user chooses logout all data are
+ * cleared regardless of the actual outcome
+ */
+ protected class LogoutTask extends AsyncTask { //Attempt logout
+ ProgressDialog progressDialog;
+
+ protected Integer doInBackground(Void... voids) {
+ return sessionManager.logout();
+ }
+
+ protected void onPreExecute() { //Show a progress dialog until done
+ progressDialog = new ProgressDialog(BaseActivity.this,
+ R.style.AppTheme_Dark_Dialog);
+ progressDialog.setCancelable(false);
+ progressDialog.setIndeterminate(true);
+ progressDialog.setMessage("Logging out...");
+ progressDialog.show();
+ }
+
+ protected void onPostExecute(Integer result) {
+ Toast.makeText(getBaseContext(), "Logged out successfully!", Toast.LENGTH_LONG).show();
+ updateDrawer();
+ progressDialog.dismiss();
+ }
+ }
+//-----------------------------------------LOGOUT END-----------------------------------------------
+
+//---------------------------------------------BOOKMARKS--------------------------------------------
+
+ protected ArrayList getBoardsBookmarked() {
+ return boardsBookmarked;
+ }
+
+ protected ArrayList getTopicsBookmarked() {
+ return topicsBookmarked;
+ }
+
+ protected void setTopicBookmark() {
+ if (thisPageBookmark.matchExists(topicsBookmarked)) {
+ thisPageBookmarkButton.setImageDrawable(bookmarked);
+ } else {
+ thisPageBookmarkButton.setImageDrawable(notBookmarked);
+ }
+ thisPageBookmarkButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (thisPageBookmark.matchExists(topicsBookmarked)) {
+ thisPageBookmarkButton.setImageDrawable(notBookmarked);
+ toggleTopicToBookmarks(thisPageBookmark);
+ Toast.makeText(BaseActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show();
+ } else {
+ thisPageBookmarkButton.setImageDrawable(bookmarked);
+ toggleTopicToBookmarks(thisPageBookmark);
+ Toast.makeText(BaseActivity.this, "Bookmark added", Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
+
+ protected void setBoardBookmark() {
+ if (thisPageBookmark.matchExists(boardsBookmarked)) {
+ thisPageBookmarkButton.setImageDrawable(bookmarked);
+ } else {
+ thisPageBookmarkButton.setImageDrawable(notBookmarked);
+ }
+ thisPageBookmarkButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (thisPageBookmark.matchExists(boardsBookmarked)) {
+ thisPageBookmarkButton.setImageDrawable(notBookmarked);
+ Toast.makeText(BaseActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show();
+ } else {
+ thisPageBookmarkButton.setImageDrawable(bookmarked);
+ Toast.makeText(BaseActivity.this, "Bookmark added", Toast.LENGTH_SHORT).show();
+ }
+ toggleBoardToBookmarks(thisPageBookmark);
+ }
+ });
+ }
+
+ private void loadSavedBookmarks() {
+ String tmpString = bookmarksFile.getString(BOOKMARKED_TOPICS_KEY, null);
+ if (tmpString != null)
+ topicsBookmarked = Bookmark.arrayFromString(tmpString);
+ else {
+ topicsBookmarked = new ArrayList<>();
+ }
+
+ tmpString = bookmarksFile.getString(BOOKMARKED_BOARDS_KEY, null);
+ if (tmpString != null)
+ boardsBookmarked = Bookmark.arrayFromString(tmpString);
+ else {
+ boardsBookmarked = new ArrayList<>();
+ }
+ }
+
+ private void toggleBoardToBookmarks(Bookmark bookmark) {
+ if (boardsBookmarked == null) return;
+ if (bookmark.matchExists(boardsBookmarked)) {
+ boardsBookmarked.remove(bookmark.findIndex(boardsBookmarked));
+ } else boardsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId()));
+ updateBoardBookmarks();
+ }
+
+ private void toggleTopicToBookmarks(Bookmark bookmark) {
+ if (topicsBookmarked == null) return;
+ if (bookmark.matchExists(topicsBookmarked)) {
+ topicsBookmarked.remove(bookmark.findIndex(topicsBookmarked));
+ } else {
+ topicsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId()));
+ }
+ updateTopicBookmarks();
+ }
+
+ private void updateBoardBookmarks() {
+ String tmpString;
+ tmpString = Bookmark.arrayToString(boardsBookmarked);
+ SharedPreferences.Editor editor = bookmarksFile.edit();
+ editor.putString(BOOKMARKED_BOARDS_KEY, tmpString).apply();
+ }
+
+ private void updateTopicBookmarks() {
+ String tmpString;
+ tmpString = Bookmark.arrayToString(topicsBookmarked);
+ SharedPreferences.Editor editor = bookmarksFile.edit();
+ editor.putString(BOOKMARKED_TOPICS_KEY, tmpString).apply();
+ }
+
+ protected void removeBookmark(Bookmark bookmark) {
+ if (bookmark.matchExists(boardsBookmarked)) toggleBoardToBookmarks(bookmark);
+ else if (bookmark.matchExists(topicsBookmarked)) toggleTopicToBookmarks(bookmark);
+ }
+//-------------------------------------------BOOKMARKS END------------------------------------------
+
+ //-------PERMS---------
+ private static final int PERMISSIONS_REQUEST_CODE = 69;
+
+ //True if permissions are OK
+ private boolean checkPerms() {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
+ String[] PERMISSIONS_STORAGE = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE};
+
+ return !(checkSelfPermission(PERMISSIONS_STORAGE[0]) == PackageManager.PERMISSION_DENIED ||
+ checkSelfPermission(PERMISSIONS_STORAGE[1]) == PackageManager.PERMISSION_DENIED);
+ }
+ return true;
+ }
+
+ //Display popup gor user to grant permission
+ public void requestPerms() { //Runtime permissions request for devices with API >= 23
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
+ String[] PERMISSIONS_STORAGE = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE};
+
+ requestPermissions(PERMISSIONS_STORAGE, PERMISSIONS_REQUEST_CODE);
+ }
+ }
+
+
+ @Override
+ public void onRequestPermissionsResult(int permsRequestCode, @NonNull String[] permissions
+ , @NonNull int[] grantResults) {
+ switch (permsRequestCode) {
+ case PERMISSIONS_REQUEST_CODE:
+ launchDownloadService();
+ break;
+ }
+ }
+
+
+ //----------------------------------DOWNLOAD----------------------
+ private ThmmyFile tempThmmyFile;
+
+ public void launchDownloadService(ThmmyFile thmmyFile) {
+ if (checkPerms())
+ DownloadService.startActionDownload(this, thmmyFile.getFileUrl().toString());
+ else {
+ tempThmmyFile = thmmyFile;
+ requestPerms();
+ }
+ }
+
+ //Uses temp file - called after permission grant
+ public void launchDownloadService() {
+ if (checkPerms())
+ DownloadService.startActionDownload(this, tempThmmyFile.getFileUrl().toString());
+
+ }
+
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
new file mode 100644
index 00000000..1e5ffdd6
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
@@ -0,0 +1,111 @@
+package gr.thmmy.mthmmy.base;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.support.v4.content.ContextCompat;
+import android.util.DisplayMetrics;
+import android.widget.ImageView;
+
+import com.franmontiel.persistentcookiejar.PersistentCookieJar;
+import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
+import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
+import com.jakewharton.picasso.OkHttp3Downloader;
+import com.mikepenz.fontawesome_typeface_library.FontAwesome;
+import com.mikepenz.iconics.IconicsDrawable;
+import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
+import com.mikepenz.materialdrawer.util.DrawerImageLoader;
+import com.squareup.picasso.Picasso;
+
+import java.util.concurrent.TimeUnit;
+
+import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.session.SessionManager;
+import okhttp3.OkHttpClient;
+
+public class BaseApplication extends Application {
+
+
+ private static BaseApplication baseApplication; //BaseApplication singleton
+
+ // Client & SessionManager
+ private OkHttpClient client;
+ private SessionManager sessionManager;
+
+ //Shared Preferences
+ private final String SHARED_PREFS_NAME = "ThmmySharedPrefs";
+
+ //Display Metrics
+ private static float dpHeight, dpWidth;
+
+ public static BaseApplication getInstance(){
+ return baseApplication;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ baseApplication = this; //init singleton
+
+ SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE);
+ SharedPrefsCookiePersistor sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(getApplicationContext());
+ PersistentCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor);
+ client = new OkHttpClient.Builder()
+ .cookieJar(cookieJar)
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .build();
+ sessionManager = new SessionManager(client, cookieJar, sharedPrefsCookiePersistor, sharedPrefs);
+ Picasso picasso = new Picasso.Builder(getApplicationContext())
+ .downloader(new OkHttp3Downloader(client))
+ .build();
+
+ Picasso.setSingletonInstance(picasso); //All following Picasso (with Picasso.with(Context context) requests will use this Picasso object
+
+ //Initialize and create the image loader logic
+ DrawerImageLoader.init(new AbstractDrawerImageLoader() {
+ @Override
+ public void set(ImageView imageView, Uri uri, Drawable placeholder) {
+ Picasso.with(imageView.getContext()).load(uri).placeholder(placeholder).into(imageView);
+ }
+ @Override
+ public void cancel(ImageView imageView) {
+ Picasso.with(imageView.getContext()).cancelRequest(imageView);
+ }
+
+ @Override
+ public Drawable placeholder(Context ctx, String tag) {
+ if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) {
+ return new IconicsDrawable(ctx).icon(FontAwesome.Icon.faw_user)
+ .paddingDp(10)
+ .color(ContextCompat.getColor(ctx, R.color.primary_light))
+ .backgroundColor(ContextCompat.getColor(ctx, R.color.primary));
+ }
+ return super.placeholder(ctx, tag);
+ }
+ });
+
+ DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
+ dpHeight = displayMetrics.heightPixels / displayMetrics.density;
+ dpWidth = displayMetrics.widthPixels / displayMetrics.density;
+ }
+
+ public OkHttpClient getClient() {
+ return client;
+ }
+
+ public SessionManager getSessionManager() {
+ return sessionManager;
+ }
+
+ public float getDpHeight() {
+ return dpHeight;
+ }
+
+ public float getDpWidth() {
+ return dpWidth;
+ }
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/base/BaseFragment.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java
similarity index 89%
rename from app/src/main/java/gr/thmmy/mthmmy/activities/base/BaseFragment.java
rename to app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java
index 6b0b93c9..c7b3d477 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/base/BaseFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java
@@ -1,4 +1,4 @@
-package gr.thmmy.mthmmy.activities.base;
+package gr.thmmy.mthmmy.base;
import android.content.Context;
import android.os.Bundle;
@@ -16,14 +16,16 @@ public abstract class BaseFragment extends Fragment {
private String TAG;
protected int sectionNumber;
- protected OkHttpClient client;
+ protected static OkHttpClient client;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TAG = getArguments().getString(ARG_TAG);
sectionNumber = getArguments().getInt(ARG_SECTION_NUMBER);
- client = BaseActivity.getClient();
+ if(client==null)
+ client = BaseApplication.getInstance().getClient(); //must check every time - e.g.
+ // becomes null when app restarts after crash
Report.d(TAG, "onCreate");
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java b/app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java
new file mode 100644
index 00000000..e9753046
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java
@@ -0,0 +1,73 @@
+package gr.thmmy.mthmmy.model;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+public class Bookmark implements java.io.Serializable {
+ private final String title, id;
+
+ public Bookmark(String title, String id) {
+ this.title = title;
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public boolean matchExists(ArrayList array) {
+ if (array != null && !array.isEmpty()) {
+ for (Bookmark bookmark : array) {
+ if (bookmark != null) {
+ if (Objects.equals(bookmark.getId(), this.id)
+ && Objects.equals(bookmark.getTitle(), this.title))
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public int findIndex(ArrayList array) {
+ if (array != null && !array.isEmpty()) {
+ for (int i = 0; i < array.size(); ++i) {
+ if (array.get(i) != null && Objects.equals(array.get(i).getId(), this.id)
+ && Objects.equals(array.get(i).getTitle(), this.title))
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Nullable
+ public static String arrayToString(@NonNull ArrayList arrayList) {
+ String returnString = "";
+ for (Bookmark bookmark : arrayList) {
+ if (bookmark != null) {
+ returnString += (bookmark.getId() + "\t");
+ returnString += (bookmark.getTitle() + "\n");
+ }
+ }
+ if (!Objects.equals(returnString, "")) return returnString;
+ else return null;
+ }
+
+ public static ArrayList arrayFromString(@NonNull String string) {
+ ArrayList returnArray = new ArrayList<>();
+ String[] lines = string.split("\n");
+ for (String line : lines) {
+ if (line == null || line.isEmpty() || Objects.equals(line, "")) break;
+ String[] parameters = line.split("\t");
+ if (parameters.length != 2) break;
+ returnArray.add(new Bookmark(parameters[1], parameters[0]));
+ }
+ return returnArray;
+ }
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Download.java b/app/src/main/java/gr/thmmy/mthmmy/model/Download.java
new file mode 100644
index 00000000..5216fea4
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/model/Download.java
@@ -0,0 +1,58 @@
+package gr.thmmy.mthmmy.model;
+
+public class Download {
+ public enum DownloadItemType {DOWNLOADS_CATEGORY, DOWNLOADS_FILE}
+
+ private final String url, title, subTitle, statNumbers, extraInfo;
+ private final boolean hasSubCategory;
+ private final DownloadItemType type;
+
+ public Download() {
+ type = null;
+ url = null;
+ title = null;
+ subTitle = null;
+ statNumbers = null;
+ hasSubCategory = false;
+ extraInfo = null;
+ }
+
+ public Download(DownloadItemType type, String url, String title, String subTitle,
+ String statNumbers, boolean hasSubCategory, String extraInfo) {
+ this.type = type;
+ this.url = url;
+ this.title = title;
+ this.subTitle = subTitle;
+ this.statNumbers = statNumbers;
+ this.hasSubCategory = hasSubCategory;
+ this.extraInfo = extraInfo;
+ }
+
+ public DownloadItemType getType() {
+ return type;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getSubTitle() {
+ return subTitle;
+ }
+
+ public String getStatNumbers() {
+ return statNumbers;
+ }
+
+ public String getExtraInfo() {
+ return extraInfo;
+ }
+
+ public boolean hasSubCategory() {
+ return hasSubCategory;
+ }
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Post.java b/app/src/main/java/gr/thmmy/mthmmy/model/Post.java
index 96c5a04e..15b6afe6 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/model/Post.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/model/Post.java
@@ -5,8 +5,6 @@ import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.Objects;
-import gr.thmmy.mthmmy.utils.FileManager.ThmmyFile;
-
/**
* Class that defines a topic's post. All member variables are declared final (thus no setters are
* supplied). Class has two constructors and getter methods for all variables.
diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java
new file mode 100644
index 00000000..e071a6a2
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java
@@ -0,0 +1,37 @@
+package gr.thmmy.mthmmy.model;
+
+import java.net.URL;
+
+public class ThmmyFile {
+ /**
+ * Debug Tag for logging debug output to LogCat
+ */
+ private static final String TAG = "ThmmyFile";
+ private final URL fileUrl;
+ private final String filename, fileInfo;
+
+ /**
+ * This constructor only creates a ThmmyFile object and does not download the file.
+ *
+ * @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;
+ }
+
+ public URL getFileUrl() {
+ return fileUrl;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public String getFileInfo() {
+ return fileInfo;
+ }
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/LinkTarget.java b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java
similarity index 56%
rename from app/src/main/java/gr/thmmy/mthmmy/model/LinkTarget.java
rename to app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java
index aaf14773..c4bc5272 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/model/LinkTarget.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java
@@ -1,7 +1,6 @@
package gr.thmmy.mthmmy.model;
import android.net.Uri;
-import android.support.annotation.NonNull;
import java.util.Objects;
@@ -12,7 +11,7 @@ import mthmmy.utils.Report;
* classes). It can be used to resolve link targets as to whether they are pointing to the forum and
* where in the forum they may point.
*/
-public class LinkTarget {
+public class ThmmyPage {
/**
* Debug Tag for logging debug output to LogCat
*/
@@ -23,6 +22,7 @@ public class LinkTarget {
* An enum describing a link's target by defining the types:
* - {@link #NOT_THMMY}
* - {@link #THMMY}
+ * - {@link #INDEX}
* - {@link #UNKNOWN_THMMY}
* - {@link #TOPIC}
* - {@link #BOARD}
@@ -33,7 +33,7 @@ public class LinkTarget {
* - {@link #PROFILE}
*
*/
- public enum Target {
+ public enum PageCategory {
/**
* Link doesn't point to thmmy.
*/
@@ -42,6 +42,10 @@ public class LinkTarget {
* Link points to thmmy.
*/
THMMY,
+ /**
+ * Link points to thmmy index page/
+ */
+ INDEX,
/**
* Link points to a thmmy page that's not (yet) supported by the app.
*/
@@ -73,28 +77,44 @@ public class LinkTarget {
/**
* Link points to a profile.
*/
- PROFILE;
+ PROFILE,
+ /**
+ * Link points to a download.
+ */
+ DOWNLOADS_CATEGORY,
+ /**
+ * Link points to a download category.
+ */
+ DOWNLOADS_FILE,
+ /**
+ * Link points to downloads.
+ */
+ DOWNLOADS;
/**
- * This method defines a custom equality check for {@link Target} enums. It does not check
+ * This method defines a custom equality check for {@link PageCategory} enums. It does not check
* whether a url is equal to another.
* Method returns true if parameter's Target is the same as the object and in the specific
* cases described below, false otherwise.
* - (Everything but {@link #NOT_THMMY}).is({@link #THMMY}) returns true
* - {@link #PROFILE_SUMMARY}.is({@link #PROFILE}) returns true
- * - {@link #PROFILE_LATEST_POSTS}.is({@link #PROFILE}) returns true
- * - {@link #PROFILE_STATS}.is({@link #PROFILE}) returns true
* - {@link #PROFILE}.is({@link #PROFILE_SUMMARY}) returns false
+ * - {@link #PROFILE_LATEST_POSTS}.is({@link #PROFILE}) returns true
* - {@link #PROFILE}.is({@link #PROFILE_LATEST_POSTS}) returns false
- * - {@link #PROFILE}.is({@link #PROFILE_STATS}) returns false
+ * - {@link #PROFILE_STATS}.is({@link #PROFILE}) returns true
+ * - {@link #PROFILE}.is({@link #PROFILE_STATS}) returns false
+ * - {@link #DOWNLOADS_CATEGORY}.is({@link #DOWNLOADS}) returns true
+ * - {@link #DOWNLOADS}.is({@link #DOWNLOADS_CATEGORY}) returns false
+ * - {@link #DOWNLOADS_FILE}.is({@link #DOWNLOADS}) returns true
+ * - {@link #DOWNLOADS}.is({@link #DOWNLOADS_FILE}) returns false
*
* @param other another Target
* @return true if enums are equal, false otherwise
*/
- public boolean is(Target other) {
- return (this == PROFILE_LATEST_POSTS ||
- this == PROFILE_STATS ||
- this == PROFILE_SUMMARY) && other == PROFILE
+ public boolean is(PageCategory other) {
+ return ((this == PROFILE_LATEST_POSTS || this == PROFILE_STATS || this == PROFILE_SUMMARY)
+ && other == PROFILE)
+ || ((this == DOWNLOADS_FILE || this == DOWNLOADS_CATEGORY) && other == DOWNLOADS)
|| (this != NOT_THMMY && other == THMMY)
|| this == other;
}
@@ -107,7 +127,7 @@ public class LinkTarget {
* @return true if url is pointing to thmmy, false otherwise
*/
public static boolean isThmmy(Uri uri) {
- return resolveLinkTarget(uri) != Target.NOT_THMMY;
+ return resolvePageCategory(uri) != PageCategory.NOT_THMMY;
}
/**
@@ -116,24 +136,49 @@ public class LinkTarget {
* @param uri url to resolve
* @return resolved target
*/
- public static Target resolveLinkTarget(Uri uri) {
+ public static PageCategory resolvePageCategory(Uri uri) {
final String host = uri.getHost();
final String uriString = uri.toString();
+ if (Objects.equals(uriString, "thmmy.gr")) return PageCategory.INDEX;
if (Objects.equals(host, "www.thmmy.gr")) {
- if (uriString.contains("topic=")) return Target.TOPIC;
- else if (uriString.contains("board=")) return Target.BOARD;
+ if (uriString.contains("topic=")) return PageCategory.TOPIC;
+ else if (uriString.contains("board=")) return PageCategory.BOARD;
else if (uriString.contains("action=profile")) {
if (uriString.contains(";sa=showPosts"))
- return Target.PROFILE_LATEST_POSTS;
+ return PageCategory.PROFILE_LATEST_POSTS;
else if (uriString.contains(";sa=statPanel"))
- return Target.PROFILE_STATS;
- else return Target.PROFILE_SUMMARY;
+ return PageCategory.PROFILE_STATS;
+ else return PageCategory.PROFILE_SUMMARY;
} else if (uriString.contains("action=unread"))
- return Target.UNREAD_POSTS;
+ return PageCategory.UNREAD_POSTS;
+ else if (uriString.contains("action=tpmod;dl=item"))
+ return PageCategory.DOWNLOADS_FILE;
+ else if (uriString.contains("action=tpmod;dl"))
+ return PageCategory.DOWNLOADS_CATEGORY;
+ else if (uriString.contains("action=forum") || Objects.equals(uriString, "www.thmmy.gr")
+ || Objects.equals(uriString, "http://www.thmmy.gr")
+ || Objects.equals(uriString, "https://www.thmmy.gr")
+ || Objects.equals(uriString, "https://www.thmmy.gr/smf/index.php"))
+ return PageCategory.INDEX;
Report.v(TAG, "Unknown thmmy link found, link: " + uriString);
- return Target.UNKNOWN_THMMY;
+ return PageCategory.UNKNOWN_THMMY;
+ }
+ return PageCategory.NOT_THMMY;
+ }
+
+ public static String getBoardId(String boardUrl) {
+ if (resolvePageCategory(Uri.parse(boardUrl)) == PageCategory.BOARD) {
+ return boardUrl.substring(boardUrl.indexOf("board=") + 6, boardUrl.lastIndexOf("."));
+ }
+ return null;
+ }
+
+ public static String getTopicId(String topicUrl) {
+ if (resolvePageCategory(Uri.parse(topicUrl)) == PageCategory.TOPIC) {
+ String tmp = topicUrl.substring(topicUrl.indexOf("topic=") + 6);
+ return tmp.substring(0, tmp.indexOf("."));
}
- return Target.NOT_THMMY;
+ return null;
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/receiver/Receiver.java b/app/src/main/java/gr/thmmy/mthmmy/receiver/Receiver.java
new file mode 100644
index 00000000..3f76766e
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/receiver/Receiver.java
@@ -0,0 +1,84 @@
+package gr.thmmy.mthmmy.receiver;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v7.app.NotificationCompat;
+import android.webkit.MimeTypeMap;
+
+import java.io.File;
+
+import gr.thmmy.mthmmy.R;
+import mthmmy.utils.Report;
+
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static gr.thmmy.mthmmy.services.DownloadService.ACTION_DOWNLOAD;
+import static gr.thmmy.mthmmy.services.DownloadService.COMPLETED;
+import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_DOWNLOAD_ID;
+import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_DOWNLOAD_STATE;
+import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_FILE_EXTENSION;
+import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_FILE_NAME;
+import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_NOTIFICATION_TEXT;
+import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_NOTIFICATION_TICKER;
+import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_NOTIFICATION_TITLE;
+import static gr.thmmy.mthmmy.services.DownloadService.SAVE_DIR;
+import static gr.thmmy.mthmmy.services.DownloadService.STARTED;
+
+public class Receiver extends BroadcastReceiver {
+ private static final String TAG = "BroadcastReceiver";
+
+ public Receiver() {
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ if (intent.getAction().equals(ACTION_DOWNLOAD)) {
+ Bundle extras = intent.getExtras();
+ int id = extras.getInt(EXTRA_DOWNLOAD_ID);
+ String state = extras.getString(EXTRA_DOWNLOAD_STATE, "NONE");
+ String title = extras.getString(EXTRA_NOTIFICATION_TITLE);
+ String text = extras.getString(EXTRA_NOTIFICATION_TEXT);
+ String ticker = extras.getString(EXTRA_NOTIFICATION_TICKER);
+
+ builder.setContentTitle(title)
+ .setContentText(text)
+ .setTicker(ticker)
+ .setAutoCancel(true) //???
+ .setSmallIcon(R.mipmap.ic_launcher);
+
+ if (state.equals(STARTED))
+ builder.setOngoing(true);
+ else if (state.equals(COMPLETED)) {
+ String fileName = extras.getString(EXTRA_FILE_NAME, "NONE");
+ String extension = extras.getString(EXTRA_FILE_EXTENSION, "extension");
+
+ File file = new File(SAVE_DIR, fileName);
+ if (file.exists()) {
+ String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+ MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath()));
+
+ Intent chooser = new Intent();
+ chooser.setAction(android.content.Intent.ACTION_VIEW);
+ chooser.setDataAndType(Uri.fromFile(file), type);
+ chooser.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, chooser, PendingIntent.FLAG_CANCEL_CURRENT);
+ builder.setContentIntent(pendingIntent);
+ } else
+ Report.w(TAG, "File doesn't exist.");
+ }
+ Notification notification = builder.build();
+ notificationManager.notify(id, notification);
+ }
+ }
+
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/DownloadService.java b/app/src/main/java/gr/thmmy/mthmmy/services/DownloadService.java
new file mode 100644
index 00000000..5eca8376
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/services/DownloadService.java
@@ -0,0 +1,221 @@
+package gr.thmmy.mthmmy.services;
+
+import android.app.IntentService;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Environment;
+import android.support.annotation.NonNull;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import gr.thmmy.mthmmy.base.BaseApplication;
+import gr.thmmy.mthmmy.receiver.Receiver;
+import mthmmy.utils.Report;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.Okio;
+
+/**
+ * An {@link IntentService} subclass for handling asynchronous task requests in
+ * a service on a separate handler thread.
+ */
+public class DownloadService extends IntentService {
+ private static final String TAG = "DownloadService";
+ private static int sDownloadId =0;
+
+ private Receiver receiver;
+
+ public static final String SAVE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "mthmmy";
+
+ public static final String ACTION_DOWNLOAD = "gr.thmmy.mthmmy.services.action.DOWNLOAD";
+ public static final String EXTRA_DOWNLOAD_URL = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_URL";
+
+ public static final String EXTRA_DOWNLOAD_ID = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_ID";
+ public static final String EXTRA_DOWNLOAD_STATE = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_STATE";
+ public static final String EXTRA_FILE_NAME = "gr.thmmy.mthmmy.services.extra.FILE_NAME";
+ public static final String EXTRA_FILE_EXTENSION = "gr.thmmy.mthmmy.services.extra.FILE_EXTENSION";
+ public static final String EXTRA_NOTIFICATION_TITLE = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TITLE";
+ public static final String EXTRA_NOTIFICATION_TEXT = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TEXT";
+ public static final String EXTRA_NOTIFICATION_TICKER = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TICKER";
+
+ public static final String STARTED = "Started";
+ public static final String COMPLETED = "Completed";
+ public static final String FAILED = "Failed";
+
+
+
+ public DownloadService() {
+ super("DownloadService");
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ final IntentFilter filter = new IntentFilter(DownloadService.ACTION_DOWNLOAD);
+ receiver = new Receiver();
+ registerReceiver(receiver, filter);
+
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ this.unregisterReceiver(receiver);
+ }
+
+ /**
+ * Starts this service to perform action Download with the given parameters. If
+ * the service is already performing a task this action will be queued.
+ *
+ * @see IntentService
+ */
+ public static void startActionDownload(Context context, String downloadUrl) {
+ Intent intent = new Intent(context, DownloadService.class);
+ intent.setAction(ACTION_DOWNLOAD);
+ intent.putExtra(EXTRA_DOWNLOAD_URL, downloadUrl);
+ context.startService(intent);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ if (intent != null) {
+ final String action = intent.getAction();
+ if (ACTION_DOWNLOAD.equals(action)) {
+ final String downloadLink = intent.getStringExtra(EXTRA_DOWNLOAD_URL);
+ handleActionDownload(downloadLink);
+ }
+ }
+ }
+
+ /**
+ * Handle action Foo in the provided background thread with the provided
+ * parameters.
+ */
+ private void handleActionDownload(String downloadLink) {
+ OkHttpClient client = BaseApplication.getInstance().getClient();
+ BufferedSink sink = null;
+ String fileName = "file";
+ String extension = "extension";
+ int downloadId = sDownloadId;
+ sDownloadId++;
+
+ try {
+ Request request = new Request.Builder().url(downloadLink).build();
+ Response response = client.newCall(request).execute();
+
+ String contentType = response.headers("Content-Type").toString(); //check if link provides a binary file
+ if(contentType.equals("[application/octet-stream]"))
+ {
+ fileName = response.headers("Content-Disposition").toString().split("\"")[1];
+
+ File dirPath = new File(SAVE_DIR);
+ if(!dirPath.isDirectory())
+ {
+ if(dirPath.mkdirs())
+ Report.i(TAG, "mTHMMY's directory created successfully!");
+ else
+ Report.e(TAG, "Couldn't create mTHMMY's directory...");
+ }
+
+
+ String nameFormat;
+ String[] tokens = fileName.split("\\.(?=[^\\.]+$)");
+
+ if(tokens.length!=2)
+ {
+ Report.w(TAG, "Couldn't get file extension...");
+ nameFormat = fileName + "(%d)";
+ }
+ else
+ {
+ nameFormat = tokens[0] + "(%d)." + tokens[1];
+ extension = tokens[1];
+ }
+
+
+
+ File file = new File(dirPath, fileName);
+
+ for (int i = 1;;i++) {
+ if (!file.exists()) {
+ break;
+ }
+
+ file = new File(dirPath, String.format(nameFormat, i));
+ }
+
+ fileName = file.getName();
+
+ Report.v(TAG, "Started saving file " + fileName);
+ sendNotification(downloadId, STARTED, fileName, extension);
+
+ sink = Okio.buffer(Okio.sink(file));
+ sink.writeAll(response.body().source());
+ sink.flush();
+ Report.i(TAG, "Download OK!");
+ sendNotification(downloadId, COMPLETED, fileName, extension);
+ }
+ else
+ Report.e(TAG, "Response not a binary file!");
+ }
+ catch (FileNotFoundException e){
+ Report.e(TAG, "FileNotFound", e);
+ Report.i(TAG, "Download failed...");
+ sendNotification(downloadId, FAILED, fileName, extension);
+ }
+ catch (IOException e){
+ Report.e(TAG, "IOException", e);
+ Report.i(TAG, "Download failed...");
+ sendNotification(downloadId, FAILED, fileName, extension);
+ } finally {
+ if (sink!= null) {
+ try {
+ sink.close();
+ } catch (IOException e) {
+ // Ignore - Significant errors should already have been reported
+ }
+ }
+ }
+ }
+
+ private void sendNotification(int downloadId, String type, @NonNull String fileName, String fileExtension)
+ {
+ Intent intent = new Intent(ACTION_DOWNLOAD);
+ switch (type) {
+ case STARTED: {
+ intent.putExtra(EXTRA_NOTIFICATION_TITLE, "Download Started");
+ intent.putExtra(EXTRA_NOTIFICATION_TEXT, "\"" + fileName + "\" downloading...");
+ intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Downloading...");
+ break;
+ }
+ case COMPLETED: {
+ intent.putExtra(EXTRA_NOTIFICATION_TITLE, "Download Completed");
+ intent.putExtra(EXTRA_NOTIFICATION_TEXT, "\"" + fileName + "\" finished downloading.");
+ intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Download Completed");
+ break;
+ }
+ case FAILED: {
+ intent.putExtra(EXTRA_NOTIFICATION_TITLE, "Download Failed");
+ intent.putExtra(EXTRA_NOTIFICATION_TEXT, "\"" + fileName + "\" failed.");
+ intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Download Failed");
+ break;
+ }
+ default:{
+ Report.wtf(TAG, "Invalid notification case!");
+ return;
+ }
+ }
+ intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId);
+ intent.putExtra(EXTRA_DOWNLOAD_STATE, type);
+ intent.putExtra(EXTRA_FILE_NAME, fileName);
+ intent.putExtra(EXTRA_FILE_EXTENSION, fileExtension);
+ sendBroadcast(intent);
+
+ }
+
+}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
index 16ee1d0f..d47e4969 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
@@ -1,6 +1,7 @@
package gr.thmmy.mthmmy.session;
import android.content.SharedPreferences;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
@@ -8,7 +9,6 @@ import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersisto
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
@@ -27,17 +27,16 @@ import okhttp3.RequestBody;
import okhttp3.Response;
/**
- This class handles all session related operations (e.g. login, logout)
- and stores data to SharedPreferences (session information and cookies).
-*/
-public class SessionManager
-{
+ * This class handles all session related operations (e.g. login, logout)
+ * and stores data to SharedPreferences (session information and cookies).
+ */
+public class SessionManager {
//Class TAG
private static final String TAG = "SessionManager";
//Generic constants
- public static final HttpUrl indexUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php");
- public static final HttpUrl forumUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=forum");
+ public static final HttpUrl indexUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?theme=4");
+ public static final HttpUrl forumUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=forum;theme=4");
private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2");
private static final String guestName = "Guest";
@@ -66,27 +65,25 @@ public class SessionManager
//Constructor
public SessionManager(OkHttpClient client, PersistentCookieJar cookieJar,
- SharedPrefsCookiePersistor cookiePersistor, SharedPreferences sharedPrefs)
- {
+ SharedPrefsCookiePersistor cookiePersistor, SharedPreferences sharedPrefs) {
this.client = client;
- this.cookiePersistor=cookiePersistor;
+ this.cookiePersistor = cookiePersistor;
this.cookieJar = cookieJar;
this.sharedPrefs = sharedPrefs;
}
//------------------------------------AUTH BEGINS----------------------------------------------
+
/**
- * Login function with two options: (username, password) or nothing (using saved cookies).
- * Always call it in a separate thread.
+ * Login function with two options: (username, password) or nothing (using saved cookies).
+ * Always call it in a separate thread.
*/
- public int login(String... strings)
- {
+ public int login(String... strings) {
Report.i(TAG, "Logging in...");
//Build the login request for each case
Request request;
- if (strings.length == 2)
- {
+ if (strings.length == 2) {
clearSessionData();
String loginName = strings[0];
@@ -101,9 +98,7 @@ public class SessionManager
.url(loginUrl)
.post(formBody)
.build();
- }
- else
- {
+ } else {
request = new Request.Builder()
.url(loginUrl)
.build();
@@ -114,8 +109,9 @@ public class SessionManager
Response response = client.newCall(request).execute();
Document document = Jsoup.parse(response.body().string());
- Element logoutButton = document.getElementById("logoutbtn"); //Attempt to find logout button
- if (logoutButton != null) //If logout button exists, login was successful
+ Elements unreadRepliesLinks = document.select("a[href=https://www.thmmy.gr/smf/index.php?action=unreadreplies]");
+
+ if (unreadRepliesLinks.size()>=2) //Normally it's just == 2, but who knows what can be posted by users
{
Report.i(TAG, "Login successful!");
setPersistentCookieSession(); //Store cookies
@@ -125,20 +121,17 @@ public class SessionManager
sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, false).apply();
sharedPrefs.edit().putString(USERNAME, extractUserName(document)).apply();
String avatar = extractAvatarLink(document);
- if (avatar!=null)
- {
- sharedPrefs.edit().putBoolean(HAS_AVATAR,true).apply();
+ if (avatar != null) {
+ sharedPrefs.edit().putBoolean(HAS_AVATAR, true).apply();
sharedPrefs.edit().putString(AVATAR_LINK, extractAvatarLink(document)).apply();
- }
- else
- sharedPrefs.edit().putBoolean(HAS_AVATAR,false).apply();
+ } else
+ sharedPrefs.edit().putBoolean(HAS_AVATAR, false).apply();
+
- sharedPrefs.edit().putString(LOGOUT_LINK, HttpUrl.parse(logoutButton.attr("href")).toString()).apply();
+ sharedPrefs.edit().putString(LOGOUT_LINK, extractLogoutLink(document)).apply();
return SUCCESS;
- }
- else
- {
+ } else {
Report.i(TAG, "Login failed.");
//Investigate login failure
@@ -159,41 +152,35 @@ public class SessionManager
return FAILURE;
}
//Handle exception
- }
- catch (InterruptedIOException e){
+ } catch (InterruptedIOException e) {
Report.i(TAG, "Login InterruptedIOException"); //users cancels LoginTask
return CANCELLED;
- }
- catch (IOException e) {
+ } catch (IOException e) {
Report.w(TAG, "Login IOException", e);
return CONNECTION_ERROR;
- }
- catch (Exception e) {
+ } catch (Exception e) {
Report.w(TAG, "Login Exception (other)", e);
return EXCEPTION;
}
}
/**
- * A function that checks the validity of the current saved session (if it exists).
- * If isLoggedIn() is true, it will call login() with cookies. On failure, this can only return
- * the code FAILURE. CANCELLED, CONNECTION_ERROR and EXCEPTION are simply considered a SUCCESS
- * (e.g. no internet connection), at least until a more thorough handling of different
- * exceptions is implemented (if considered mandatory).
- * Always call it in a separate thread in a way that won't hinder performance (e.g. after
- * fragments' data are retrieved).
+ * A function that checks the validity of the current saved session (if it exists).
+ * If isLoggedIn() is true, it will call login() with cookies. On failure, this can only return
+ * the code FAILURE. CANCELLED, CONNECTION_ERROR and EXCEPTION are simply considered a SUCCESS
+ * (e.g. no internet connection), at least until a more thorough handling of different
+ * exceptions is implemented (if considered mandatory).
+ * Always call it in a separate thread in a way that won't hinder performance (e.g. after
+ * fragments' data are retrieved).
*/
- public void validateSession()
- {
+ public void validateSession() {
Report.i(TAG, "Validating session...");
- if(isLoggedIn())
- {
+ if (isLoggedIn()) {
int loginResult = login();
- if(loginResult != FAILURE)
+ if (loginResult != FAILURE)
return;
- }
- else if(isLoginScreenDefault())
+ } else if (isLoginScreenDefault())
return;
sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, true).apply();
@@ -201,10 +188,9 @@ public class SessionManager
}
/**
- * Call this function when user explicitly chooses to continue as a guest (UI thread).
+ * Call this function when user explicitly chooses to continue as a guest (UI thread).
*/
- public void guestLogin()
- {
+ public void guestLogin() {
Report.i("TAG", "Continuing as a guest, as chosen by the user.");
clearSessionData();
sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, false).apply();
@@ -212,14 +198,13 @@ public class SessionManager
/**
- * Logout function. Always call it in a separate thread.
+ * Logout function. Always call it in a separate thread.
*/
- public int logout()
- {
+ public int logout() {
Report.i(TAG, "Logging out...");
Request request = new Request.Builder()
- .url(sharedPrefs.getString(LOGOUT_LINK,"LogoutLink"))
+ .url(sharedPrefs.getString(LOGOUT_LINK, "LogoutLink"))
.build();
try {
@@ -271,15 +256,17 @@ public class SessionManager
return sharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true);
}
+ public String getCookieHeader() {
+ return cookiePersistor.loadAll().get(0).toString();
+ }
+
//--------------------------------------GETTERS END---------------------------------------------
//------------------------------------OTHER FUNCTIONS-------------------------------------------
- private void setPersistentCookieSession()
- {
+ private void setPersistentCookieSession() {
List cookieList = cookieJar.loadForRequest(indexUrl);
- if (cookieList.size() == 2)
- {
+ if (cookieList.size() == 2) {
if ((cookieList.get(0).name().equals("THMMYgrC00ki3"))
&& (cookieList.get(1).name().equals("PHPSESSID"))) {
Cookie.Builder builder = new Cookie.Builder();
@@ -295,45 +282,66 @@ public class SessionManager
}
}
- private void clearSessionData()
- {
+ private void clearSessionData() {
cookieJar.clear();
sharedPrefs.edit().clear().apply(); //Clear session data
sharedPrefs.edit().putString(USERNAME, guestName).apply();
sharedPrefs.edit().putBoolean(LOGGED_IN, false).apply(); //User logs out
- Report.i(TAG,"Session data cleared.");
+ Report.i(TAG, "Session data cleared.");
}
@Nullable
- private String extractUserName(Document doc)
- {
- if (doc != null) {
- Elements user = doc.select("div[id=myuser] > h3");
-
- if (user.size() == 1) {
- String txt = user.first().ownText();
-
- Pattern pattern = Pattern.compile(", (.*?),");
- Matcher matcher = pattern.matcher(txt);
- if (matcher.find())
- return matcher.group(1);
+ private String extractUserName(@NonNull Document doc) {
+ //Scribbles2 Theme
+ Elements user = doc.select("div[id=myuser] > h3");
+
+ if (user.size() == 1) {
+ String txt = user.first().ownText();
+
+ Pattern pattern = Pattern.compile(", (.*?),");
+ Matcher matcher = pattern.matcher(txt);
+ if (matcher.find())
+ return matcher.group(1);
+ }
+ else
+ {
+ //Helios_Multi and SMF_oneBlue
+ user = doc.select("td.smalltext[width=100%] b");
+ if (user.size() == 1)
+ return user.first().ownText();
+ else
+ {
+ //SMF Default Theme
+ user = doc.select("td.titlebg2[height=32] b");
+ if (user.size() == 1)
+ return user.first().ownText();
}
}
- Report.w(TAG,"Extracting username failed!");
+
+
+ Report.e(TAG, "Extracting username failed!");
return null;
}
+
@Nullable
- private String extractAvatarLink(Document doc)
- {
- if (doc != null) {
- Elements avatar = doc.select("#ava img");
+ private String extractAvatarLink(@NonNull Document doc) {
+ Elements avatar = doc.getElementsByClass("avatar");
+ if (!avatar.isEmpty())
+ return avatar.first().attr("src");
- if (avatar.size() == 1) {
- return avatar.attr("src");
- }
- }
- Report.w(TAG,"Extracting avatar's link failed!");
+ Report.e(TAG, "Extracting avatar's link failed!");
+ return null;
+ }
+
+ @Nullable
+ private String extractLogoutLink(@NonNull Document doc) {
+ Elements logoutLink = doc.select("a[href^=https://www.thmmy.gr/smf/index.php?action=logout;sesc=]");
+
+ if (!logoutLink.isEmpty())
+ return logoutLink.first().attr("href");
+
+ Report.e(TAG, "Extracting logout link failed!");
return null;
}
//----------------------------------OTHER FUNCTIONS END-----------------------------------------
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
deleted file mode 100644
index c1eb7cfb..00000000
--- a/app/src/main/java/gr/thmmy/mthmmy/utils/FileManager/ThmmyFile.java
+++ /dev/null
@@ -1,194 +0,0 @@
-package gr.thmmy.mthmmy.utils.FileManager;
-
-import android.content.Context;
-import android.os.Environment;
-import android.os.StatFs;
-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)}.
- */
-public class ThmmyFile {
- /**
- * Debug Tag for logging debug output to LogCat
- */
- private static final String TAG = "ThmmyFile";
- private final URL fileUrl;
- private final String filename, fileInfo;
- private String extension, filePath;
- private File file;
-
- /**
- * This constructor only creates a empty ThmmyFile object and does not download the file. To download
- * the file use {@link #download(Context)} after setting file's url!
- */
- public ThmmyFile() {
- this.fileUrl = null;
- this.filename = null;
- this.fileInfo = null;
- this.extension = null;
- this.filePath = null;
- this.file = null;
- }
-
- /**
- * This constructor only creates a ThmmyFile object and does not download the file. To download
- * the file use {@link #download(Context)}!
- *
- * @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(Context)} 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(Context)} 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(Context)} 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/packageName
- *
- * @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(Context context) throws IOException, SecurityException, OutOfMemoryError {
- if (fileUrl == null) {
- return null;
- }
- 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(context, filename, fileInfo);
- 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 File getOutputMediaFile(Context context, String fileName, String fileInfo) throws OutOfMemoryError, IOException {
- File mediaStorageDir;
- String extState = Environment.getExternalStorageState();
- if (Environment.isExternalStorageRemovable() &&
- Objects.equals(extState, Environment.MEDIA_MOUNTED)) {
- mediaStorageDir = new File(Environment.getExternalStorageDirectory()
- + "/Android/data/gr.thmmy.mthmmy/"
- + "Downloads/");
- } else {
- mediaStorageDir = new File(context.getFilesDir(), "Downloads");
- }
-
- //Creates the storage directory if it does not exist
- if (!mediaStorageDir.exists()) {
- if (!mediaStorageDir.mkdirs()) {
- Report.d(TAG, "problem!");
- throw new IOException("Error.\nCouldn't create the path!");
- }
- }
-
-
- if (fileInfo != null) {
- if (fileInfo.contains("KB")) {
- float fileSize = Float.parseFloat(fileInfo
- .substring(fileInfo.indexOf("(") + 1, fileInfo.indexOf("KB") - 1));
-
- StatFs stat = new StatFs(mediaStorageDir.getPath());
- long bytesAvailable = stat.getBlockSizeLong() * stat.getAvailableBlocksLong();
- if ((bytesAvailable / 1024.f) < fileSize)
- throw new OutOfMemoryError("There is not enough memory!");
- }
- }
-
- //Creates a media file name
- File mediaFile;
- mediaFile = new File(mediaStorageDir.getPath() + File.separator + fileName);
- return mediaFile;
- }
-}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java
index 6e791204..0f3564c6 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java
@@ -6,7 +6,6 @@ import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.ViewPropertyAnimator;
diff --git a/app/src/main/res/drawable-hdpi/ic_bookmark_false.png b/app/src/main/res/drawable-hdpi/ic_bookmark_false.png
new file mode 100644
index 00000000..afb6271f
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_bookmark_false.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_bookmark_true.png b/app/src/main/res/drawable-hdpi/ic_bookmark_true.png
new file mode 100644
index 00000000..ce6dd7a9
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_bookmark_true.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_pin.png b/app/src/main/res/drawable-hdpi/ic_pin.png
deleted file mode 100644
index 9b2e2981..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_pin.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_remove_circle.png b/app/src/main/res/drawable-hdpi/ic_remove_circle.png
new file mode 100644
index 00000000..e4cc8579
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_remove_circle.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_bookmark_false.png b/app/src/main/res/drawable-mdpi/ic_bookmark_false.png
new file mode 100644
index 00000000..79157474
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_bookmark_false.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_bookmark_true.png b/app/src/main/res/drawable-mdpi/ic_bookmark_true.png
new file mode 100644
index 00000000..06eba446
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_bookmark_true.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_pin.png b/app/src/main/res/drawable-mdpi/ic_pin.png
deleted file mode 100644
index efbfd6bd..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_pin.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_remove_circle.png b/app/src/main/res/drawable-mdpi/ic_remove_circle.png
new file mode 100644
index 00000000..a8470e61
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_remove_circle.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_bookmark_false.png b/app/src/main/res/drawable-xhdpi/ic_bookmark_false.png
new file mode 100644
index 00000000..cded6d60
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_bookmark_false.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_bookmark_true.png b/app/src/main/res/drawable-xhdpi/ic_bookmark_true.png
new file mode 100644
index 00000000..368c9ead
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_bookmark_true.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_pin.png b/app/src/main/res/drawable-xhdpi/ic_pin.png
deleted file mode 100644
index 43cc8ca0..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_pin.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_remove_circle.png b/app/src/main/res/drawable-xhdpi/ic_remove_circle.png
new file mode 100644
index 00000000..c8ef34d2
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_remove_circle.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_bookmark_false.png b/app/src/main/res/drawable-xxhdpi/ic_bookmark_false.png
new file mode 100644
index 00000000..a837b04d
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_bookmark_false.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_bookmark_true.png b/app/src/main/res/drawable-xxhdpi/ic_bookmark_true.png
new file mode 100644
index 00000000..0253be02
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_bookmark_true.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_pin.png b/app/src/main/res/drawable-xxhdpi/ic_pin.png
deleted file mode 100644
index f1b6eb44..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_pin.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_remove_circle.png b/app/src/main/res/drawable-xxhdpi/ic_remove_circle.png
new file mode 100644
index 00000000..505d8b3a
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_remove_circle.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_bookmark_false.png b/app/src/main/res/drawable-xxxhdpi/ic_bookmark_false.png
new file mode 100644
index 00000000..d65bb47d
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_bookmark_false.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_bookmark_true.png b/app/src/main/res/drawable-xxxhdpi/ic_bookmark_true.png
new file mode 100644
index 00000000..59c96d06
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_bookmark_true.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_pin.png b/app/src/main/res/drawable-xxxhdpi/ic_pin.png
deleted file mode 100644
index 4d6bdf41..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_pin.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_remove_circle.png b/app/src/main/res/drawable-xxxhdpi/ic_remove_circle.png
new file mode 100644
index 00000000..5bfad8b3
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_remove_circle.png differ
diff --git a/app/src/main/res/drawable/ic_file_upload.xml b/app/src/main/res/drawable/ic_file_upload.xml
new file mode 100644
index 00000000..74f3b4ca
--- /dev/null
+++ b/app/src/main/res/drawable/ic_file_upload.xml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_board.xml b/app/src/main/res/layout/activity_board.xml
index 4c0684f7..5d3d7a3d 100644
--- a/app/src/main/res/layout/activity_board.xml
+++ b/app/src/main/res/layout/activity_board.xml
@@ -22,6 +22,16 @@
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ToolbarTheme">
+
+
diff --git a/app/src/main/res/layout/activity_board_sub_board.xml b/app/src/main/res/layout/activity_board_sub_board.xml
index b78a9c07..3b202022 100644
--- a/app/src/main/res/layout/activity_board_sub_board.xml
+++ b/app/src/main/res/layout/activity_board_sub_board.xml
@@ -1,79 +1,88 @@
+ android:orientation="vertical">
+ android:background="?attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp">
-
+ android:layout_marginBottom="5dp"
+ android:layout_marginTop="5dp"
+ android:orientation="horizontal">
-
-
+
-
+
+
-
+ android:layout_marginBottom="5dp"
+ android:orientation="vertical"
+ android:visibility="gone">
-
+
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_board_topic.xml b/app/src/main/res/layout/activity_board_topic.xml
index a036f151..d041cc46 100644
--- a/app/src/main/res/layout/activity_board_topic.xml
+++ b/app/src/main/res/layout/activity_board_topic.xml
@@ -4,7 +4,9 @@
android:id="@+id/topic_row_linear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
android:clickable="true"
+ android:focusable="true"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp">
@@ -20,8 +22,9 @@
android:id="@+id/topic_subject"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:layout_weight="1"
- android:gravity="center_vertical"
+ android:paddingBottom="2dp"
android:text="@string/topic_subject"
android:textColor="@color/primary_text"
android:textSize="18sp"/>
@@ -30,7 +33,7 @@
android:id="@+id/topic_expand_collapse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@color/background"
+ android:background="@null"
android:contentDescription="@string/child_board_button"
android:src="@drawable/ic_arrow_drop_down"/>
diff --git a/app/src/main/res/layout/activity_bookmark.xml b/app/src/main/res/layout/activity_bookmark.xml
new file mode 100644
index 00000000..b2fa6e33
--- /dev/null
+++ b/app/src/main/res/layout/activity_bookmark.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_bookmark_row.xml b/app/src/main/res/layout/activity_bookmark_row.xml
new file mode 100644
index 00000000..a5245a79
--- /dev/null
+++ b/app/src/main/res/layout/activity_bookmark_row.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_downloads.xml b/app/src/main/res/layout/activity_downloads.xml
new file mode 100644
index 00000000..3547d5ea
--- /dev/null
+++ b/app/src/main/res/layout/activity_downloads.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_downloads_row.xml b/app/src/main/res/layout/activity_downloads_row.xml
new file mode 100644
index 00000000..d6c664c9
--- /dev/null
+++ b/app/src/main/res/layout/activity_downloads_row.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index b79c2503..52bdc281 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -1,7 +1,6 @@
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:isScrollContainer="false">
+ android:layout_height="0dp"
+ android:layout_weight="0.4"/>
+ android:layout_height="0dp"
+ android:layout_weight="0.45"/>
+ android:layout_height="wrap_content">
+
+
+
+
-
+ android:layout_height="0dp"
+ android:layout_weight="0.2"/>
+
diff --git a/app/src/main/res/layout/activity_topic.xml b/app/src/main/res/layout/activity_topic.xml
index 8d2993ef..23b12737 100644
--- a/app/src/main/res/layout/activity_topic.xml
+++ b/app/src/main/res/layout/activity_topic.xml
@@ -22,6 +22,16 @@
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ToolbarTheme">
+
+
@@ -50,6 +60,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
+ android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_first"
app:srcCompat="@drawable/page_first"/>
@@ -58,6 +69,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
+ android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_previous"
app:srcCompat="@drawable/page_previous"/>
@@ -78,6 +90,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
+ android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_next"
app:srcCompat="@drawable/page_next"/>
@@ -86,6 +99,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
+ android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_last"
app:srcCompat="@drawable/page_last"/>
diff --git a/app/src/main/res/layout/fragment_latest_posts_row.xml b/app/src/main/res/layout/fragment_latest_posts_row.xml
index 82d5b60d..cad4d1cb 100644
--- a/app/src/main/res/layout/fragment_latest_posts_row.xml
+++ b/app/src/main/res/layout/fragment_latest_posts_row.xml
@@ -1,55 +1,61 @@
-
+ android:background="@color/card_background">
-
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
+ android:paddingBottom="6dp"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:paddingTop="6dp">
-
+
+
-
-
+
-
-
-
\ No newline at end of file
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/spacer_divider">
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 88e15276..1640a038 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,14 +5,16 @@
Login
Authenticating…
Logout
+ Downloads
+ About
Home
+ Bookmarks
thmmy.gr
Username
Password
LOGIN
- - OR -
Don\'t have an account? Continue as guest!
@@ -52,10 +54,14 @@
Most Popular Boards By Activity
- About
v%1$s
Logo
- You should watch a funny pic!
+ You should see a funny pic!
+
+
+ Remove
+ Your bookmarked boards:
+ Your bookmarked topics:
Libraries
@@ -78,4 +84,5 @@
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 98df4222..3f32d79c 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -42,6 +42,4 @@
- @color/primary_text
- @color/dialog_bg_semi_transparent
-
-
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
new file mode 100644
index 00000000..a0b81b43
--- /dev/null
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/release/java/mthmmy.utils/Report.java b/app/src/release/java/mthmmy.utils/Report.java
index 25df4841..ce2ea89d 100644
--- a/app/src/release/java/mthmmy.utils/Report.java
+++ b/app/src/release/java/mthmmy.utils/Report.java
@@ -77,5 +77,10 @@ public class Report
FirebaseCrash.report(tr);
}
+ /**
+ * Does nothing in release.
+ */
+ public static void longMessage(String TAG, String level, String message) {return;}
+
}
diff --git a/doc/forum_post.txt b/doc/forum_post.txt
new file mode 100644
index 00000000..f51905fa
--- /dev/null
+++ b/doc/forum_post.txt
@@ -0,0 +1,34 @@
+[center][size=25pt][b]Introduction[/b][/size][/center]
+
+Áðü ôç óõæÞôçóç [url=https://www.thmmy.gr/smf/index.php?topic=67629.0]åäþ[/url], îåêßíçóå Ýíá project ìå óôü÷ï ôç äçìéïõñãßá åöáñìïãÞò ãéá Android êéíçôÜ ðïõ èá óõãêåíôñþíåé êáé èá êÜíåé ðéï åýêïëç ôç ðñüóâáóç óå ìåñéêÝò áðü ôéò âáóéêÝò óåëßäåò êáé õðçñåóßåò ðïõ áöïñïýí ôç ó÷ïëÞ êáé ÷ñçóéìïðïéïýìå êáèçìåñéíÜ.
+
+ÌåôÜ áðü 2+ ìÞíåò äïõëåéÜò êáé ðÜíù áðü 9000 ãñáììÝò êþäéêá [size=9pt](.java, .xml êáé Üëëá)[/size], óÞìåñá áíåâÜóáìå ãéá ðñþôç öïñÜ ôçí åöáñìïãÞ (óå closed alpha phase) óôï Google Play Store!
+
+Ðñïò ôï ðáñüí ç åöáñìïãÞ õðïóôçñßæåé êÜðïéåò áðü ôéò âáóéêÝò ëåéôïõñãßåò ôïõ forum. ÓôáäéáêÜ èá åíóùìáôþíïíôáé üëï êáé ðåñéóóüôåñåò ëåéôïõñãßåò, ãéá ðáñÜäåéãìá åíüò óõóôÞìáôïò åéäïðïéÞóåùí ãéá íÝåò áíáêïéíþóåéò ôïõ ethmmy êáé ôçò óåëßäáò ôçò ãñáììáôåßáò, instant chat ê.Ü., áíÜëïãá ðÜíôá ìå ôéò éäÝåò, ôç äéÜèåóç êáé ôçí åíÝñãåéá üóùí èá óõììåôÝ÷ïõí.
+
+ÁõôÞ ôç óôéãìÞ ìå ôï project áó÷ïëïýìáóôå åãþ êáé ï L, åíþ Ý÷ïõí âïçèÞóåé ï iason1907 êáé ï [url=https://www.thmmy.gr/smf/index.php?topic=67565.msg1163192#msg1163192]nohponex[/url].
+
+[hr]
+[center][size=25pt][b]ÊÜëåóìá ãéá contributors[/b][/size]
+
+[img height=400]https://tctechcrunch2011.files.wordpress.com/2015/04/uncle-sam-we-want-you1-kopie_1.png[/img][/center]
+
+Áí åíäéáöÝñåóáé êé ÅÓÕ íá áó÷ïëçèåßò ìå ôï project ìðïñåßò íá ôï êÜíåéò ìå ðïëëïýò ôñüðïõò:
+[list]
+[li]Áí îÝñåéò ðñïãñáììáôéóìü ìðïñåßò áñ÷éêÜ íá æçôÞóåéò ðñüóâáóç óôï repository. ×ñåéÜæïíôáé [i]Üìåóá[/i] íÝïé developers ãéá õëïðïéÞóç êáéíïýñãéùí ÷áñáêôçñéóôéêþí, äéüñèùóç åíôüìùí, óýíôáîç ôùí javadocs êáé ôïõ documentation ãåíéêüôåñá, white-box testing, õëïðïßçóç ôïõ backend óôï server ðïõ óôÞèçêå ðñüóöáôá êáé ðïëëþí Üëëùí. Áõôü, áñ÷éêÜ, èá ãßíåôáé ìå forks êáé merge requests - êáé ðÜíôá óôï ñõèìü ðïõ ìðïñåßò íá óõíåéóöÝñåéò.
+[/li]
+[li]
+Íá áíáöÝñåéò bugs, íá ðñïôåßíåéò âåëôéþóåéò êáé íá óõììåôÝ÷åéò óå óõæçôÞóåéò, åßôå óôïí [url=https://discord.gg/PVRVjth]Discord server[/url], åßôå áðïêôþíôáò ðñüóâáóç óôïí Issue Tracker ìáò.
+[/li]
+[li]
+Íá êáôåâÜóåéò êáé íá äïêéìÜóåéò ôçí alpha Ýêäïóç ôçò åöáñìïãÞò áðü [url=https://play.google.com/apps/testing/gr.thmmy.mthmmy]åäþ[/url] áöïý ðñþôá ìáò äþóåéò Ýíá gmail ãéá íá áðïêôÞóåéò ðñüóâáóç.
+[/li]
+[li]
+Íá Ýñèåéò óå Üìåóç åðéêïéíùíßá ìå ôçí ïìÜäá ìÝóù ôïõ Discord Þ óôÝëíïíôáò email óôï thmmynolife@gmail.com.
+[/li][/list]
+[hr]
+[center][size=25pt][b]Ç åöáñìïãÞ[/b][/size][/center]
+
+[center][url=https://s6.postimg.org/4mupem3jl/image.png][img width=200]https://s6.postimg.org/4mupem3jl/image.png[/img][/url] [url=https://s6.postimg.org/ovdhmldgx/image.png][img width=200]https://s6.postimg.org/ovdhmldgx/image.png[/img][/url] [url=https://s6.postimg.org/a9mgycgoh/image.png][img width=200]https://s6.postimg.org/a9mgycgoh/image.png[/img][/url] [url=https://s6.postimg.org/5jwj9qpo1/image.png][img width=200]https://s6.postimg.org/5jwj9qpo1/image.png[/img][/url] [url=https://s6.postimg.org/fjrfpn0xd/image.png][img width=200]https://s6.postimg.org/fjrfpn0xd/image.png[/img][/url] [url=https://s6.postimg.org/z0c5c5w1d/image.png][img width=200]https://s6.postimg.org/z0c5c5w1d/image.png[/img][/url][/center]
+
+ÁõôÞ ôç óôéãìÞ óôçí åöáñìïãÞ ìðïñåßò íá êÜíåéò login êáé logout, íá äåéò ôá "Ðñüóöáôá", íá ðåñéçãçèåßò óôá boards, topics êáé user profiles êáé íá êáôåâÜóåéò áñ÷åßá óõíçììÝíá óå post.
\ No newline at end of file