Browse Source

Version 1.1.2

master v1.1.2
Ezerous 8 years ago
parent
commit
887271cddd
  1. 35
      CONTRIBUTING.md
  2. 2
      VERSION
  3. 4
      app/build.gradle
  4. 3
      app/src/main/AndroidManifest.xml
  5. 1
      app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
  6. 30
      app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java
  7. 52
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
  8. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java
  9. 7
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  10. 5
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  11. 3
      app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java
  12. 16
      app/src/main/java/gr/thmmy/mthmmy/receiver/Receiver.java
  13. 22
      app/src/main/java/gr/thmmy/mthmmy/services/DownloadService.java
  14. 47
      app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
  15. 20
      app/src/main/java/gr/thmmy/mthmmy/utils/CenterVerticalSpan.java
  16. 13
      app/src/main/java/gr/thmmy/mthmmy/utils/exceptions/ParseException.java
  17. 14
      app/src/main/java/gr/thmmy/mthmmy/utils/exceptions/UnknownException.java
  18. 1
      app/src/main/res/layout-v21/activity_profile.xml
  19. 1
      app/src/main/res/layout/activity_profile.xml
  20. 1
      app/src/main/res/values/strings.xml
  21. 10
      app/src/release/java/mthmmy.utils/Report.java

35
CONTRIBUTING.md

@ -13,49 +13,36 @@ vulnerabilities, please report them in private to
There are many ways of contributing to mTHMMY: There are many ways of contributing to mTHMMY:
- Simply using the latest release version - Simply using the latest release version (anonymous reports are sent automatically)
- Becoming an alpha or beta tester
- Joining our [Discord server][discord-server] - Joining our [Discord server][discord-server]
- Creating issues & joining discussions on our [Issue Tracker][issue-tracker] - Submiting bugs and ideas on our [Trello board][trello-board]
- Getting code access to fork mTHMMY and submit [merge requests](#merge-requests) - Getting code access to fork mTHMMY and submit [merge requests](#merge-requests)
- Joining our core team - Joining our core team
- Contacting us by email at `thmmynolife@gmail.com` - Contacting us by email at `thmmynolife@gmail.com`
## Issue tracker ## Issue tracker
The [mTHMMY issue tracker on GitLab.com][issue-tracker] is for [bugs](#bugs) concerning the latest mTHMMY release and [improvements](#improvements). The [mTHMMY Board on trello.com][trello-board] is used as an Issue Tracker, for bugs and improvements concerning the available mTHMMY releases.
Before creating a card to submit an issue please **[search the board][trello-board]** for similar entries.
Before submitting an issue please **[search the issue tracker][issue-tracker]** for similar entries and if you don't find any create your own conforming to the simple issue submission guidelines listed below.
### Bugs
Please submit bugs using the ['Bug' issue template](.gitlab/issue_templates/Bug.md) provided on the issue tracker and the [`Bug`](https://gitlab.com/thmmy.gr/mTHMMY/issues?label_name=Bug) label.
### Improvements
Please submit improvements/ feature proposals using the ['Improvement' issue template](.gitlab/issue_templates/Improvement.md) provided on the issue tracker and the [`Improvement`](https://gitlab.com/thmmy.gr/mTHMMY/issues?label_name=Improvement) label.
### Issue weight
Issue weight represents the amount of work required for an issue, as an abstract measurement of its complexity. You are encouraged to discuss and set the weight of any issue to what makes most sense.
For example, something that has a weight of 1 (or no weight) is really small and simple.
Something that is 9 is a very complex issue requiring to (re)write big parts of code.
## Merge requests ## Merge requests
Merge requests with fixes and improvements to mTHMMY are most welcome. The simple workflow to make a merge request is as follows: Merge requests with fixes and improvements to mTHMMY are most welcome. Any developer that wants to work independently from the core team can simply
follow the workflow below to make a merge request:
1. Request and get access to the repository
1. Fork the project into your personal space on GitLab.com 1. Fork the project into your personal space on GitLab.com
1. Create a feature branch, branch away from `master` 1. Create a feature branch, branch away from `develop`
1. Push the commit(s) to your fork 1. Push the commit(s) to your fork
1. Create a merge request (MR) targeting `master` [at mTHMMY](https://gitlab.com/thmmy.gr/mTHMMY/tree/master) 1. Create a merge request (MR) targeting `develop` [at mTHMMY](https://gitlab.com/ThmmyNoLife/mTHMMY/tree/develop)
1. Fill the MR title describing the change you want to make 1. Fill the MR title describing the change you want to make
1. Fill the MR description with a brief motive for your change and the method you used to achieve it. 1. Fill the MR description with a brief motive for your change and the method you used to achieve it.
1. Submit the MR. 1. Submit the MR.
*This guide was inspired by [Gitlab CE's Contributing Guide][gitlab-contributing-guide].*
[issue-tracker]: https://gitlab.com/thmmy.gr/mTHMMY/issues [trello-board]: https://trello.com/invite/b/4MVlkrkg/44a931707bd0b84a5e0bdfc42b9ae4f1/mthmmy
[discord-server]: https://discord.gg/CVt3yrn [discord-server]: https://discord.gg/CVt3yrn
[gitlab-contributing-guide]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md [gitlab-contributing-guide]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md

2
VERSION

@ -1 +1 @@
1.1.0 1.1.2

4
app/build.gradle

@ -9,8 +9,8 @@ android {
applicationId "gr.thmmy.mthmmy" applicationId "gr.thmmy.mthmmy"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 25 targetSdkVersion 25
versionCode 4 versionCode 5
versionName "1.1.1" versionName "1.1.2"
archivesBaseName = "mTHMMY-v$versionName" archivesBaseName = "mTHMMY-v$versionName"
} }

3
app/src/main/AndroidManifest.xml

@ -46,6 +46,9 @@
<data <data
android:host="thmmy.gr" android:host="thmmy.gr"
android:scheme="https"/> android:scheme="https"/>
<data
android:host="thmmy.gr"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity

1
app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java

@ -174,7 +174,6 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
if (intent != null) { if (intent != null) {
Uri uri = intent.getData(); Uri uri = intent.getData();
if (uri != null) { if (uri != null) {
Log.d(TAG, uri.toString());
ThmmyPage.PageCategory page = ThmmyPage.resolvePageCategory(uri); ThmmyPage.PageCategory page = ThmmyPage.resolvePageCategory(uri);
if (!page.is(ThmmyPage.PageCategory.NOT_THMMY)) { if (!page.is(ThmmyPage.PageCategory.NOT_THMMY)) {
if (page.is(ThmmyPage.PageCategory.BOARD)) { if (page.is(ThmmyPage.PageCategory.BOARD)) {

30
app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java

@ -27,6 +27,7 @@ import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.model.TopicSummary;
import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.session.SessionManager;
import gr.thmmy.mthmmy.utils.CustomRecyclerView; import gr.thmmy.mthmmy.utils.CustomRecyclerView;
import gr.thmmy.mthmmy.utils.exceptions.ParseException;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report; import mthmmy.utils.Report;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
@ -159,12 +160,15 @@ public class RecentFragment extends BaseFragment {
document = Jsoup.parse(response.body().string()); document = Jsoup.parse(response.body().string());
parse(document); parse(document);
return 0; return 0;
} catch (IOException e) { } catch (ParseException e) {
Report.d(TAG, "Network Error", e); Report.e(TAG, "ParseException", e);
return 1; return 1;
} catch (Exception e) { } catch (IOException e) {
Report.d(TAG, "Exception", e); Report.i(TAG, "Network Error", e);
return 2; return 2;
} catch (Exception e) {
Report.e(TAG, "Exception", e);
return 3;
} }
} }
@ -174,14 +178,14 @@ public class RecentFragment extends BaseFragment {
if (result == 0) if (result == 0)
recentAdapter.notifyDataSetChanged(); recentAdapter.notifyDataSetChanged();
else if (result == 1) else if (result == 2)
Toast.makeText(getActivity(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), "Network error", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
private void parse(Document document) { private void parse(Document document) throws ParseException {
Elements recent = document.select("#block8 :first-child div"); Elements recent = document.select("#block8 :first-child div");
if (!recent.isEmpty()) { if (!recent.isEmpty()) {
topicSummaries.clear(); topicSummaries.clear();
@ -195,27 +199,23 @@ public class RecentFragment extends BaseFragment {
Matcher matcher = pattern.matcher(lastUser); Matcher matcher = pattern.matcher(lastUser);
if (matcher.find()) if (matcher.find())
lastUser = matcher.group(1); lastUser = matcher.group(1);
else { else
Report.e(TAG, "Parsing failed (lastUser)!"); throw new ParseException("Parsing failed (lastUser)");
return;
}
String dateTime = recent.get(i + 2).text(); String dateTime = recent.get(i + 2).text();
pattern = Pattern.compile("\\[(.*)\\]"); pattern = Pattern.compile("\\[(.*)\\]");
matcher = pattern.matcher(dateTime); matcher = pattern.matcher(dateTime);
if (matcher.find()) if (matcher.find())
dateTime = matcher.group(1); dateTime = matcher.group(1);
else { else
Report.e(TAG, "Parsing failed (dateTime)!"); throw new ParseException("Parsing failed (dateTime)");
return;
}
topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime)); topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime));
} }
return; return;
} }
Report.e(TAG, "Parsing failed!"); throw new ParseException("Parsing failed");
} }
} }

52
app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java

@ -1,6 +1,8 @@
package gr.thmmy.mthmmy.activities.profile; package gr.thmmy.mthmmy.activities.profile;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
@ -12,7 +14,11 @@ import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.res.ResourcesCompat; import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
@ -24,6 +30,7 @@ import com.squareup.picasso.Picasso;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -39,6 +46,7 @@ import gr.thmmy.mthmmy.activities.topic.TopicActivity;
import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.model.PostSummary;
import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.utils.CenterVerticalSpan;
import gr.thmmy.mthmmy.utils.CircleTransform; import gr.thmmy.mthmmy.utils.CircleTransform;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report; import mthmmy.utils.Report;
@ -98,7 +106,6 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
thumbnailUrl = extras.getString(BUNDLE_PROFILE_THUMBNAIL_URL); thumbnailUrl = extras.getString(BUNDLE_PROFILE_THUMBNAIL_URL);
if (thumbnailUrl == null) thumbnailUrl = ""; if (thumbnailUrl == null) thumbnailUrl = "";
Log.d(TAG, "thumbnailUrl = " + thumbnailUrl);
username = extras.getString(BUNDLE_PROFILE_USERNAME); username = extras.getString(BUNDLE_PROFILE_USERNAME);
profileUrl = extras.getString(BUNDLE_PROFILE_URL); profileUrl = extras.getString(BUNDLE_PROFILE_URL);
@ -129,6 +136,8 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
.transform(new CircleTransform()) .transform(new CircleTransform())
.into(thumbnailView); .into(thumbnailView);
usernameView = (TextView) findViewById(R.id.profile_activity_username); usernameView = (TextView) findViewById(R.id.profile_activity_username);
usernameView.setTypeface(Typeface.createFromAsset(this.getAssets()
, "fonts/fontawesome-webfont.ttf"));
if (username != null && !Objects.equals(username, "")) usernameView.setText(username); if (username != null && !Objects.equals(username, "")) usernameView.setText(username);
personalTextView = (TextView) findViewById(R.id.profile_activity_personal_text); personalTextView = (TextView) findViewById(R.id.profile_activity_personal_text);
@ -218,6 +227,7 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String TAG = "ProfileTask"; //Separate tag for AsyncTask private static final String TAG = "ProfileTask"; //Separate tag for AsyncTask
Document profilePage; Document profilePage;
Spannable usernameSpan;
protected void onPreExecute() { protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
@ -233,23 +243,16 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
try { try {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
profilePage = Jsoup.parse(response.body().string()); profilePage = Jsoup.parse(response.body().string());
Elements contentsTable = profilePage.select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2)");
//Finds username if missing //Finds username if missing
if (username == null || Objects.equals(username, "")) { if (username == null || Objects.equals(username, "")) {
username = profilePage. username = contentsTable.select("tr").first().select("td").last().text();
select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) tr").
first().select("td").last().text();
} }
Log.d(TAG, "thumbnailUrl = " + thumbnailUrl);
if (thumbnailUrl == null || Objects.equals(thumbnailUrl, "")) { //Maybe there is an avatar if (thumbnailUrl == null || Objects.equals(thumbnailUrl, "")) { //Maybe there is an avatar
Log.d(TAG, "thumbnailUrl = " + thumbnailUrl); Element profileAvatar = contentsTable.select("img.avatar").first();
Element profileAvatar = profilePage
.select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) img.avatar")
.first();
if (profileAvatar != null) thumbnailUrl = profileAvatar.attr("abs:src"); if (profileAvatar != null) thumbnailUrl = profileAvatar.attr("abs:src");
} }
Log.d(TAG, "thumbnailUrl = " + thumbnailUrl);
;
{ //Finds personal text { //Finds personal text
Element tmpEl = profilePage.select("td.windowbg:nth-child(2)").first(); Element tmpEl = profilePage.select("td.windowbg:nth-child(2)").first();
if (tmpEl != null) { if (tmpEl != null) {
@ -261,6 +264,21 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
personalText = null; personalText = null;
} }
} }
{ //Finds status
usernameSpan = new SpannableString(getResources()
.getString(R.string.fa_circle) + " " + username);
usernameSpan.setSpan(new CenterVerticalSpan(), 0, 2,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
usernameSpan.setSpan(new RelativeSizeSpan(0.45f)
, 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (contentsTable.toString().contains("Online")
|| contentsTable.toString().contains("Συνδεδεμένος")) {
usernameSpan.setSpan(new ForegroundColorSpan(Color.parseColor("#4CAF50"))
, 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} else
usernameSpan.setSpan(new ForegroundColorSpan(Color.GRAY)
, 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return true; return true;
} catch (SSLHandshakeException e) { } catch (SSLHandshakeException e) {
Report.w(TAG, "Certificate problem (please switch to unsafe connection)."); Report.w(TAG, "Certificate problem (please switch to unsafe connection).");
@ -281,7 +299,8 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(true); if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(true);
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
if (usernameView.getText() != username) usernameView.setText(username); if (usernameSpan != null) usernameView.setText(usernameSpan);
else if (usernameView.getText() != username) usernameView.setText(username);
if (thumbnailUrl != null && !Objects.equals(thumbnailUrl, "")) if (thumbnailUrl != null && !Objects.equals(thumbnailUrl, ""))
//noinspection ConstantConditions //noinspection ConstantConditions
Picasso.with(getApplicationContext()) Picasso.with(getApplicationContext())
@ -294,7 +313,10 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
, R.drawable.ic_default_user_thumbnail, null)) , R.drawable.ic_default_user_thumbnail, null))
.transform(new CircleTransform()) .transform(new CircleTransform())
.into(thumbnailView); .into(thumbnailView);
if (personalText != null) personalTextView.setText(personalText); if (personalText != null) {
personalTextView.setText(personalText);
personalTextView.setVisibility(View.VISIBLE);
}
setupViewPager(viewPager, profilePage); setupViewPager(viewPager, profilePage);
TabLayout tabLayout = (TabLayout) findViewById(R.id.profile_tabs); TabLayout tabLayout = (TabLayout) findViewById(R.id.profile_tabs);

2
app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java

@ -148,6 +148,8 @@ public class SummaryFragment extends Fragment {
if (summaryRow.select("td").size() == 1) //Horizontal rule rows if (summaryRow.select("td").size() == 1) //Horizontal rule rows
pHtml = ""; pHtml = "";
else if (summaryRow.text().contains("Current Status")
|| summaryRow.text().contains("Κατάσταση")) continue;
else if (rowText.contains("Signature") || rowText.contains("Υπογραφή")) { else if (rowText.contains("Signature") || rowText.contains("Υπογραφή")) {
//This needs special handling since it may have css //This needs special handling since it may have css
pHtml = ParseHelpers.youtubeEmbeddedFix(summaryRow); pHtml = ParseHelpers.youtubeEmbeddedFix(summaryRow);

7
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java

@ -9,6 +9,7 @@ import android.support.design.widget.FloatingActionButton;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
@ -432,10 +433,9 @@ public class TopicActivity extends BaseActivity {
postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf("#"))); postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf("#")));
} }
} }
//Checks if the page to be loaded is the one already shown //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 (newPageUrl.contains("topicseen#new") || newPageUrl.contains("#new"))
if (thisPage == numberOfPages) if (thisPage == numberOfPages)
return SAME_PAGE; return SAME_PAGE;
if (newPageUrl.contains("msg")) { if (newPageUrl.contains("msg")) {
@ -448,8 +448,7 @@ public class TopicActivity extends BaseActivity {
return SAME_PAGE; return SAME_PAGE;
} }
} }
} } else if (Integer.parseInt(newPageUrl.substring(base_url.length() + 1)) / 15 + 1 == thisPage)
if (Integer.parseInt(newPageUrl.substring(base_url.length() + 1)) / 15 + 1 == thisPage)
return SAME_PAGE; return SAME_PAGE;
} else if (!Objects.equals(loadedPageUrl, "")) topicTitle = null; } else if (!Objects.equals(loadedPageUrl, "")) topicTitle = null;

5
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java

@ -389,6 +389,10 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
holder.subject.setMaxLines(1); holder.subject.setMaxLines(1);
holder.subject.setEllipsize(TextUtils.TruncateAt.END); holder.subject.setEllipsize(TextUtils.TruncateAt.END);
} }
//noinspection PointlessBooleanExpression,ConstantConditions
if (!BaseActivity.getSessionManager().isLoggedIn() || true) //Hide it until reply is implemented
holder.quoteToggle.setVisibility(View.GONE);
else {
if (viewProperties.get(position)[isQuoteButtonChecked]) if (viewProperties.get(position)[isQuoteButtonChecked])
holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked); holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked);
else else
@ -413,6 +417,7 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
viewProperties.set(holder.getAdapterPosition(), tmp); viewProperties.set(holder.getAdapterPosition(), tmp);
} }
}); });
}
//Card expand/collapse when card is touched //Card expand/collapse when card is touched
holder.cardView.setOnClickListener(new View.OnClickListener() { holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override @Override

3
app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java

@ -140,7 +140,8 @@ public class ThmmyPage {
final String host = uri.getHost(); final String host = uri.getHost();
final String uriString = uri.toString(); final String uriString = uri.toString();
if (Objects.equals(uriString, "thmmy.gr")) return PageCategory.INDEX; if (Objects.equals(uriString, "http://thmmy.gr")
|| Objects.equals(uriString, "https://thmmy.gr")) return PageCategory.INDEX;
if (Objects.equals(host, "www.thmmy.gr")) { if (Objects.equals(host, "www.thmmy.gr")) {
if (uriString.contains("topic=")) return PageCategory.TOPIC; if (uriString.contains("topic=")) return PageCategory.TOPIC;
else if (uriString.contains("board=")) return PageCategory.BOARD; else if (uriString.contains("board=")) return PageCategory.BOARD;

16
app/src/main/java/gr/thmmy/mthmmy/receiver/Receiver.java

@ -16,12 +16,10 @@ import java.io.File;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
import mthmmy.utils.Report; 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.ACTION_DOWNLOAD;
import static gr.thmmy.mthmmy.services.DownloadService.COMPLETED; 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_ID;
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_DOWNLOAD_STATE; 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_FILE_NAME;
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_NOTIFICATION_TEXT; 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_TICKER;
@ -51,28 +49,28 @@ public class Receiver extends BroadcastReceiver {
builder.setContentTitle(title) builder.setContentTitle(title)
.setContentText(text) .setContentText(text)
.setTicker(ticker) .setTicker(ticker)
.setAutoCancel(true) //??? .setAutoCancel(true)
.setSmallIcon(R.mipmap.ic_launcher); .setSmallIcon(R.mipmap.ic_launcher);
if (state.equals(STARTED)) if (state.equals(STARTED))
builder.setOngoing(true); builder.setOngoing(true);
else if (state.equals(COMPLETED)) { else if (state.equals(COMPLETED)) {
String fileName = extras.getString(EXTRA_FILE_NAME, "NONE"); String fileName = extras.getString(EXTRA_FILE_NAME, "NONE");
String extension = extras.getString(EXTRA_FILE_EXTENSION, "extension");
File file = new File(SAVE_DIR, fileName); File file = new File(SAVE_DIR, fileName);
if (file.exists()) { if (file.exists()) {
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension( String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath())); MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath()));
Intent chooser = new Intent();
chooser.setAction(android.content.Intent.ACTION_VIEW); Intent chooserIntent = new Intent(Intent.ACTION_VIEW);
chooser.setDataAndType(Uri.fromFile(file), type); chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
chooser.setFlags(FLAG_ACTIVITY_NEW_TASK); chooserIntent.setDataAndType(Uri.fromFile(file), type);
chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Intent chooser = Intent.createChooser(chooserIntent, "Open With...");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, chooser, PendingIntent.FLAG_CANCEL_CURRENT); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, chooser, PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(pendingIntent); builder.setContentIntent(pendingIntent);
} else } else
Report.w(TAG, "File doesn't exist."); Report.w(TAG, "File doesn't exist.");
} }

22
app/src/main/java/gr/thmmy/mthmmy/services/DownloadService.java

@ -38,7 +38,6 @@ public class DownloadService extends IntentService {
public static final String EXTRA_DOWNLOAD_ID = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_ID"; 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_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_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_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_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 EXTRA_NOTIFICATION_TICKER = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TICKER";
@ -100,7 +99,7 @@ public class DownloadService extends IntentService {
OkHttpClient client = BaseApplication.getInstance().getClient(); OkHttpClient client = BaseApplication.getInstance().getClient();
BufferedSink sink = null; BufferedSink sink = null;
String fileName = "file"; String fileName = "file";
String extension = "extension";
int downloadId = sDownloadId; int downloadId = sDownloadId;
sDownloadId++; sDownloadId++;
@ -132,10 +131,8 @@ public class DownloadService extends IntentService {
nameFormat = fileName + "(%d)"; nameFormat = fileName + "(%d)";
} }
else else
{
nameFormat = tokens[0] + "(%d)." + tokens[1]; nameFormat = tokens[0] + "(%d)." + tokens[1];
extension = tokens[1];
}
@ -152,26 +149,26 @@ public class DownloadService extends IntentService {
fileName = file.getName(); fileName = file.getName();
Report.v(TAG, "Started saving file " + fileName); Report.v(TAG, "Started saving file " + fileName);
sendNotification(downloadId, STARTED, fileName, extension); sendNotification(downloadId, STARTED, fileName);
sink = Okio.buffer(Okio.sink(file)); sink = Okio.buffer(Okio.sink(file));
sink.writeAll(response.body().source()); sink.writeAll(response.body().source());
sink.flush(); sink.flush();
Report.i(TAG, "Download OK!"); Report.i(TAG, "Download OK!");
sendNotification(downloadId, COMPLETED, fileName, extension); sendNotification(downloadId, COMPLETED, fileName);
} }
else else
Report.e(TAG, "Response not a binary file!"); Report.e(TAG, "Response not a binary file!");
} }
catch (FileNotFoundException e){ catch (FileNotFoundException e){
Report.e(TAG, "FileNotFound", e);
Report.i(TAG, "Download failed..."); Report.i(TAG, "Download failed...");
sendNotification(downloadId, FAILED, fileName, extension); Report.e(TAG, "FileNotFound", e);
sendNotification(downloadId, FAILED, fileName);
} }
catch (IOException e){ catch (IOException e){
Report.e(TAG, "IOException", e);
Report.i(TAG, "Download failed..."); Report.i(TAG, "Download failed...");
sendNotification(downloadId, FAILED, fileName, extension); Report.e(TAG, "IOException", e);
sendNotification(downloadId, FAILED, fileName);
} finally { } finally {
if (sink!= null) { if (sink!= null) {
try { try {
@ -183,7 +180,7 @@ public class DownloadService extends IntentService {
} }
} }
private void sendNotification(int downloadId, String type, @NonNull String fileName, String fileExtension) private void sendNotification(int downloadId, String type, @NonNull String fileName)
{ {
Intent intent = new Intent(ACTION_DOWNLOAD); Intent intent = new Intent(ACTION_DOWNLOAD);
switch (type) { switch (type) {
@ -213,7 +210,6 @@ public class DownloadService extends IntentService {
intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId); intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId);
intent.putExtra(EXTRA_DOWNLOAD_STATE, type); intent.putExtra(EXTRA_DOWNLOAD_STATE, type);
intent.putExtra(EXTRA_FILE_NAME, fileName); intent.putExtra(EXTRA_FILE_NAME, fileName);
intent.putExtra(EXTRA_FILE_EXTENSION, fileExtension);
sendBroadcast(intent); sendBroadcast(intent);
} }

47
app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java

@ -17,6 +17,7 @@ import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import gr.thmmy.mthmmy.utils.exceptions.ParseException;
import mthmmy.utils.Report; import mthmmy.utils.Report;
import okhttp3.Cookie; import okhttp3.Cookie;
import okhttp3.FormBody; import okhttp3.FormBody;
@ -56,12 +57,12 @@ public class SessionManager {
//Shared Preferences & its keys //Shared Preferences & its keys
private SharedPreferences sharedPrefs; private SharedPreferences sharedPrefs;
public static final String USERNAME = "Username"; private static final String USERNAME = "Username";
public static final String AVATAR_LINK = "AvatarLink"; private static final String AVATAR_LINK = "AvatarLink";
public static final String HAS_AVATAR = "HasAvatar"; private static final String HAS_AVATAR = "HasAvatar";
public static final String LOGOUT_LINK = "LogoutLink"; private static final String LOGOUT_LINK = "LogoutLink";
public static final String LOGGED_IN = "LoggedIn"; private static final String LOGGED_IN = "LoggedIn";
public static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault"; private static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault";
//Constructor //Constructor
public SessionManager(OkHttpClient client, PersistentCookieJar cookieJar, public SessionManager(OkHttpClient client, PersistentCookieJar cookieJar,
@ -290,10 +291,11 @@ public class SessionManager {
Report.i(TAG, "Session data cleared."); Report.i(TAG, "Session data cleared.");
} }
@Nullable @NonNull
private String extractUserName(@NonNull Document doc){ private String extractUserName(@NonNull Document doc){
//Scribbles2 Theme //Scribbles2 Theme
Elements user = doc.select("div[id=myuser] > h3"); Elements user = doc.select("div[id=myuser] > h3");
String userName = null;
if (user.size() == 1) { if (user.size() == 1) {
String txt = user.first().ownText(); String txt = user.first().ownText();
@ -301,26 +303,26 @@ public class SessionManager {
Pattern pattern = Pattern.compile(", (.*?),"); Pattern pattern = Pattern.compile(", (.*?),");
Matcher matcher = pattern.matcher(txt); Matcher matcher = pattern.matcher(txt);
if (matcher.find()) if (matcher.find())
return matcher.group(1); userName = matcher.group(1);
} }
else else {
{
//Helios_Multi and SMF_oneBlue //Helios_Multi and SMF_oneBlue
user = doc.select("td.smalltext[width=100%] b"); user = doc.select("td.smalltext[width=100%] b");
if (user.size() == 1) if (user.size() == 1)
return user.first().ownText(); userName = user.first().ownText();
else else {
{
//SMF Default Theme //SMF Default Theme
user = doc.select("td.titlebg2[height=32] b"); user = doc.select("td.titlebg2[height=32] b");
if (user.size() == 1) if (user.size() == 1)
return user.first().ownText(); userName = user.first().ownText();
} }
} }
if(userName != null && !userName.isEmpty())
return userName;
Report.e(TAG, "Extracting username failed!"); Report.e(TAG, "ParseException", new ParseException("Parsing failed(username extraction)"));
return null; return "User"; //return a default username
} }
@ -334,15 +336,18 @@ public class SessionManager {
return null; return null;
} }
@Nullable @NonNull
private String extractLogoutLink(@NonNull Document doc) { private String extractLogoutLink(@NonNull Document doc) {
Elements logoutLink = doc.select("a[href^=https://www.thmmy.gr/smf/index.php?action=logout;sesc=]"); Elements logoutLink = doc.select("a[href^=https://www.thmmy.gr/smf/index.php?action=logout;sesc=]");
if (!logoutLink.isEmpty()) if (!logoutLink.isEmpty())
return logoutLink.first().attr("href"); {
String link = logoutLink.first().attr("href");
Report.e(TAG, "Extracting logout link failed!"); if(link != null && !link.isEmpty())
return null; return link;
}
Report.e(TAG, "ParseException", new ParseException("Parsing failed(logoutLink extraction)"));
return "https://www.thmmy.gr/smf/index.php?action=logout"; //return a default link
} }
//----------------------------------OTHER FUNCTIONS END----------------------------------------- //----------------------------------OTHER FUNCTIONS END-----------------------------------------

20
app/src/main/java/gr/thmmy/mthmmy/utils/CenterVerticalSpan.java

@ -0,0 +1,20 @@
package gr.thmmy.mthmmy.utils;
import android.text.TextPaint;
import android.text.style.SuperscriptSpan;
import android.util.Log;
public class CenterVerticalSpan extends SuperscriptSpan {
public CenterVerticalSpan() {
}
@Override
public void updateDrawState(TextPaint textPaint) {
textPaint.baselineShift -= 7f;
}
@Override
public void updateMeasureState(TextPaint tp) {
updateDrawState(tp);
}
}

13
app/src/main/java/gr/thmmy/mthmmy/utils/exceptions/ParseException.java

@ -0,0 +1,13 @@
package gr.thmmy.mthmmy.utils.exceptions;
/**
* ParseException is to be used for errors while parsing.
*/
public class ParseException extends Exception {
public ParseException() {}
public ParseException(String message)
{
super(message);
}
}

14
app/src/main/java/gr/thmmy/mthmmy/utils/exceptions/UnknownException.java

@ -0,0 +1,14 @@
package gr.thmmy.mthmmy.utils.exceptions;
/**
* UnknownException is thrown upon an error (see Report.java in release), when no other specific
* exception is set, to report to FireBase.
*/
public class UnknownException extends Exception {
public UnknownException() {}
public UnknownException(String message)
{
super(message);
}
}

1
app/src/main/res/layout-v21/activity_profile.xml

@ -68,6 +68,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:paddingBottom="2dp"
android:text="@string/username" android:text="@string/username"
android:textColor="@color/accent" android:textColor="@color/accent"
android:textSize="25sp"/> android:textSize="25sp"/>

1
app/src/main/res/layout/activity_profile.xml

@ -67,6 +67,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:paddingBottom="2dp"
android:text="@string/username" android:text="@string/username"
android:textColor="@color/accent" android:textColor="@color/accent"
android:textSize="25sp"/> android:textSize="25sp"/>

1
app/src/main/res/values/strings.xml

@ -85,4 +85,5 @@
<string name="fa_lock">&#xf023;</string> <string name="fa_lock">&#xf023;</string>
<string name="fa_sticky">&#xf249;</string> <string name="fa_sticky">&#xf249;</string>
<string name="fa_folder">&#xf07b;</string> <string name="fa_folder">&#xf07b;</string>
<string name="fa_circle">&#xf111;</string>
</resources> </resources>

10
app/src/release/java/mthmmy.utils/Report.java

@ -2,6 +2,8 @@ package mthmmy.utils;
import com.google.firebase.crash.FirebaseCrash; import com.google.firebase.crash.FirebaseCrash;
import gr.thmmy.mthmmy.utils.exceptions.UnknownException;
public class Report public class Report
{ {
@ -66,16 +68,24 @@ public class Report
} }
private static void log(String level, String TAG, String message) private static void log(String level, String TAG, String message)
{
if(!level.equals("V")&&!level.equals("D")) //don't log V and D levels
{ {
FirebaseCrash.log(level + "/" + TAG + ": " + message); FirebaseCrash.log(level + "/" + TAG + ": " + message);
if(level.equals("E")||level.equals("WTF")) //report only serious exceptions
FirebaseCrash.report(new UnknownException("UnknownException"));
}
} }
private static void exception(String level, String TAG, String message, Throwable tr) private static void exception(String level, String TAG, String message, Throwable tr)
{
if(!level.equals("V")&&!level.equals("D")) //don't log V and D levels
{ {
FirebaseCrash.log(level + "/" + TAG + ": " + message + ": " + tr.getMessage()); FirebaseCrash.log(level + "/" + TAG + ": " + message + ": " + tr.getMessage());
if(level.equals("E")||level.equals("WTF")) //report only serious exceptions if(level.equals("E")||level.equals("WTF")) //report only serious exceptions
FirebaseCrash.report(tr); FirebaseCrash.report(tr);
} }
}
/** /**
* Does nothing in release. * Does nothing in release.

Loading…
Cancel
Save