From 7433d9b2de7595e0a680c89731dffc2f184cbb40 Mon Sep 17 00:00:00 2001 From: Apostolof Date: Sat, 7 Jul 2018 12:04:23 +0300 Subject: [PATCH 001/180] Add settings, Minor drawer bug fix --- app/build.gradle | 2 + app/src/main/AndroidManifest.xml | 9 ++ .../mthmmy/activities/LoginActivity.java | 3 + .../bookmarks/BookmarkActivity.java | 39 +++++---- .../mthmmy/activities/main/MainActivity.java | 3 + .../activities/settings/SettingsActivity.java | 44 ++++++++++ .../activities/settings/SettingsFragment.java | 82 +++++++++++++++++++ .../activities/topic/TopicActivity.java | 39 ++++++--- .../gr/thmmy/mthmmy/base/BaseActivity.java | 71 +++++++++++----- .../mthmmy/services/NotificationService.java | 62 +++++++++----- app/src/main/res/layout/activity_bookmark.xml | 4 +- app/src/main/res/layout/activity_settings.xml | 33 ++++++++ app/src/main/res/values-v21/styles.xml | 1 + app/src/main/res/values/strings.xml | 21 ++++- app/src/main/res/values/styles.xml | 1 + app/src/main/res/xml/app_preferences.xml | 35 ++++++++ 16 files changed, 372 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java create mode 100644 app/src/main/res/layout/activity_settings.xml create mode 100644 app/src/main/res/xml/app_preferences.xml diff --git a/app/build.gradle b/app/build.gradle index aafe1fe9..a4de63b5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,6 +31,8 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:design:27.1.1' + implementation 'com.android.support:preference-v7:27.1.1' + implementation 'com.android.support:preference-v14:27.1.1' implementation 'com.android.support:support-v4:27.1.1' implementation 'com.android.support:cardview-v7:27.1.1' implementation 'com.android.support:recyclerview-v7:27.1.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7417185a..b9789d97 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -105,6 +105,15 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activities.main.MainActivity" /> + + + 0 && postsList.get(postsList.size()-1)==null) - { + } else if (postsList != null && postsList.size() > 0 && postsList.get(postsList.size() - 1) == null) { postsList.remove(postsList.size() - 1); topicAdapter.notifyItemRemoved(postsList.size()); topicAdapter.setBackButtonHidden(); @@ -356,6 +365,11 @@ public class TopicActivity extends BaseActivity { super.onResume(); refreshTopicBookmark(); drawer.setSelection(-1); + + if (sessionManager.isLoggedIn()) { + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + includeAppSignaturePreference = sharedPrefs.getBoolean(SettingsActivity.APP_SIGNATURE_ENABLE_KEY, true); + } } @Override @@ -548,7 +562,8 @@ public class TopicActivity extends BaseActivity { } } -//------------------------------------BOTTOM NAV BAR METHODS END------------------------------------ + + //------------------------------------BOTTOM NAV BAR METHODS END------------------------------------ private enum ResultCode { SUCCESS, NETWORK_ERROR, PARSING_ERROR, OTHER_ERROR, SAME_PAGE, UNAUTHORIZED } @@ -632,7 +647,7 @@ public class TopicActivity extends BaseActivity { Timber.i(e, "IO Exception"); return ResultCode.NETWORK_ERROR; } catch (ParseException e) { - if(isUnauthorized(document)) + if (isUnauthorized(document)) return ResultCode.UNAUTHORIZED; Timber.e(e, "Parsing Error"); return ResultCode.PARSING_ERROR; @@ -673,9 +688,9 @@ public class TopicActivity extends BaseActivity { pageIndicator.setText(String.valueOf(thisPage) + "/" + String.valueOf(numberOfPages)); pageRequestValue = thisPage; - if(thisPage==numberOfPages){ + if (thisPage == numberOfPages) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - if(notificationManager!=null) + if (notificationManager != null) notificationManager.cancel(NEW_POST_TAG, loadedPageTopicId); } @@ -702,7 +717,7 @@ public class TopicActivity extends BaseActivity { } } - private void stopLoading(){ + private void stopLoading() { progressBar.setVisibility(ProgressBar.INVISIBLE); if (replyPageUrl == null) { replyFAB.hide(); @@ -718,7 +733,7 @@ public class TopicActivity extends BaseActivity { * @param topic {@link Document} object containing this topic's source code * @see org.jsoup.Jsoup Jsoup */ - private ArrayList parse(Document topic) throws ParseException{ + private ArrayList parse(Document topic) throws ParseException { try { ParseHelpers.Language language = ParseHelpers.Language.getLanguage(topic); @@ -898,7 +913,9 @@ public class TopicActivity extends BaseActivity { @Override protected Boolean doInBackground(String... args) { - final String sentFrommTHMMY = "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url] [/i][/size][/right]"; + final String sentFrommTHMMY = includeAppSignaturePreference + ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY [/url][/i][/size][/right]" + : ""; RequestBody postBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("message", args[1] + sentFrommTHMMY) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 9150065d..64096b56 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -47,6 +47,7 @@ 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.activities.settings.SettingsActivity; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.services.DownloadHelper; @@ -147,10 +148,11 @@ public abstract class BaseActivity extends AppCompatActivity { protected static final int BOOKMARKS_ID = 2; protected static final int LOG_ID = 3; protected static final int ABOUT_ID = 4; + protected static final int SETTINGS_ID = 5; private AccountHeader accountHeader; private ProfileDrawerItem profileDrawerItem; - private PrimaryDrawerItem downloadsItem, loginLogoutItem; + private PrimaryDrawerItem downloadsItem, settingsItem, loginLogoutItem; private IconicsDrawable loginIcon, logoutIcon; /** @@ -162,9 +164,8 @@ public abstract class BaseActivity extends AppCompatActivity { final int selectedSecondaryColor = ContextCompat.getColor(this, R.color.accent); PrimaryDrawerItem homeItem, bookmarksItem, aboutItem; - IconicsDrawable homeIcon, homeIconSelected, downloadsIcon, downloadsIconSelected, - bookmarksIcon, bookmarksIconSelected, aboutIcon, - aboutIconSelected; + IconicsDrawable homeIcon, homeIconSelected, downloadsIcon, downloadsIconSelected, settingsIcon, + settingsIconSelected, bookmarksIcon, bookmarksIconSelected, aboutIcon, aboutIconSelected; //Drawer Icons homeIcon = new IconicsDrawable(this) @@ -188,6 +189,14 @@ public abstract class BaseActivity extends AppCompatActivity { .color(primaryColor); downloadsIconSelected = new IconicsDrawable(this) + .icon(GoogleMaterial.Icon.gmd_settings) + .color(selectedSecondaryColor); + + settingsIcon = new IconicsDrawable(this) + .icon(GoogleMaterial.Icon.gmd_settings) + .color(primaryColor); + + settingsIconSelected = new IconicsDrawable(this) .icon(GoogleMaterial.Icon.gmd_file_download) .color(selectedSecondaryColor); @@ -243,6 +252,15 @@ public abstract class BaseActivity extends AppCompatActivity { .withIcon(loginIcon) .withSelectable(false); + settingsItem = new PrimaryDrawerItem() + .withTextColor(primaryColor) + .withSelectedColor(selectedPrimaryColor) + .withSelectedTextColor(selectedSecondaryColor) + .withIdentifier(SETTINGS_ID) + .withName(R.string.settings) + .withIcon(settingsIcon) + .withSelectedIcon(settingsIconSelected); + bookmarksItem = new PrimaryDrawerItem() .withTextColor(primaryColor) .withSelectedColor(selectedPrimaryColor) @@ -337,7 +355,11 @@ public abstract class BaseActivity extends AppCompatActivity { Intent i = new Intent(BaseActivity.this, AboutActivity.class); startActivity(i); } - + } else if (drawerItem.equals(SETTINGS_ID)) { + if (!(BaseActivity.this instanceof SettingsActivity)) { + Intent intent = new Intent(BaseActivity.this, SettingsActivity.class); + startActivity(intent); + } } drawer.closeDrawer(); @@ -346,7 +368,7 @@ public abstract class BaseActivity extends AppCompatActivity { }); if (sessionManager.isLoggedIn()) - drawerBuilder.addDrawerItems(homeItem, bookmarksItem, downloadsItem, loginLogoutItem, aboutItem); + drawerBuilder.addDrawerItems(homeItem, bookmarksItem, downloadsItem, settingsItem, loginLogoutItem, aboutItem); else drawerBuilder.addDrawerItems(homeItem, bookmarksItem, loginLogoutItem, aboutItem); @@ -369,13 +391,20 @@ public abstract class BaseActivity extends AppCompatActivity { if (!sessionManager.isLoggedIn()) //When logged out or if user is guest { drawer.removeItem(DOWNLOADS_ID); + drawer.removeItem(SETTINGS_ID); loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login profileDrawerItem.withName(sessionManager.getUsername()); setDefaultAvatar(); } else { + if (!drawer.getDrawerItems().contains(downloadsItem)){ + drawer.addItemAtPosition(settingsItem, 2); + } + if (!drawer.getDrawerItems().contains(settingsItem)){ + drawer.addItemAtPosition(settingsItem, 3); + } loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout profileDrawerItem.withName(sessionManager.getUsername()); - if(sessionManager.hasAvatar()) + if (sessionManager.hasAvatar()) profileDrawerItem.withIcon(sessionManager.getAvatarLink()); else setDefaultAvatar(); @@ -422,9 +451,9 @@ public abstract class BaseActivity extends AppCompatActivity { mainActivity.updateTabs(); progressDialog.dismiss(); //if (BaseActivity.this instanceof TopicActivity){ - Intent intent = new Intent(BaseActivity.this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); + Intent intent = new Intent(BaseActivity.this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); //} } } @@ -560,12 +589,12 @@ public abstract class BaseActivity extends AppCompatActivity { else if (bookmark.matchExists(topicsBookmarked)) toggleTopicToBookmarks(bookmark); } - protected boolean toggleNotification(Bookmark bookmark){ - if (bookmark.matchExists(topicsBookmarked)){ + protected boolean toggleNotification(Bookmark bookmark) { + if (bookmark.matchExists(topicsBookmarked)) { topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).toggleNotificationsEnabled(); updateTopicBookmarks(); - if (topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).isNotificationsEnabled()){ + if (topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).isNotificationsEnabled()) { FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId()); } else { FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); @@ -634,9 +663,9 @@ public abstract class BaseActivity extends AppCompatActivity { prepareDownload(tempThmmyFile); } - private void prepareDownload(ThmmyFile thmmyFile){ + private void prepareDownload(ThmmyFile thmmyFile) { String fileName = thmmyFile.getFilename(); - if(FileUtils.fileNameExists(fileName)) + if (FileUtils.fileNameExists(fileName)) openDownloadPrompt(thmmyFile); else DownloadHelper.enqueueDownload(thmmyFile); @@ -647,7 +676,7 @@ public abstract class BaseActivity extends AppCompatActivity { final BottomSheetDialog dialog = new BottomSheetDialog(this); dialog.setContentView(view); TextView downloadPromptTextView = view.findViewById(R.id.downloadPromptTextView); - downloadPromptTextView.setText(getString(R.string.downloadPromptText,thmmyFile.getFilename())); + downloadPromptTextView.setText(getString(R.string.downloadPromptText, thmmyFile.getFilename())); Button cancelButton = view.findViewById(R.id.cancel); Button openButton = view.findViewById(R.id.open); Button downloadButton = view.findViewById(R.id.download); @@ -661,15 +690,15 @@ public abstract class BaseActivity extends AppCompatActivity { @Override public void onClick(View v) { dialog.dismiss(); - try{ + try { String fileName = thmmyFile.getFilename(); Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_GRANT_READ_URI_PERMISSION); - Uri fileUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", new File(SAVE_DIR, fileName)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); + Uri fileUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", new File(SAVE_DIR, fileName)); intent.setDataAndType(fileUri, getMimeType(fileName)); BaseActivity.this.startActivity(intent); - }catch (Exception e){ - Timber.e(e,"Couldn't open downloaded file..."); + } catch (Exception e) { + Timber.e(e, "Couldn't open downloaded file..."); Toast.makeText(getBaseContext(), "Couldn't open file...", Toast.LENGTH_SHORT).show(); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java index 2ebe4a37..f6db39ad 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java +++ b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java @@ -6,11 +6,14 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.support.annotation.RequiresApi; import android.support.v4.app.NotificationCompat; +import android.support.v7.preference.PreferenceManager; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; @@ -25,6 +28,9 @@ import gr.thmmy.mthmmy.model.PostNotification; import timber.log.Timber; import static android.support.v4.app.NotificationCompat.PRIORITY_MAX; +import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.NOTIFICATION_VIBRATION_KEY; +import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SELECTED_RINGTONE; +import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SETTINGS_SHARED_PREFS; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; @@ -40,15 +46,13 @@ public class NotificationService extends FirebaseMessagingService { try { int userId = BaseApplication.getInstance().getSessionManager().getUserId(); //Don't notify me if the sender is me! - if(Integer.parseInt(json.getString("posterId"))!= userId) - { + if (Integer.parseInt(json.getString("posterId")) != userId) { int topicId = Integer.parseInt(json.getString("topicId")); int postId = Integer.parseInt(json.getString("postId")); String topicTitle = json.getString("topicTitle"); String poster = json.getString("poster"); sendNotification(new PostNotification(postId, topicId, topicTitle, poster)); - } - else + } else Timber.v("Notification suppressed (own userID)."); } catch (JSONException e) { Timber.e(e, "JSON Exception"); @@ -70,6 +74,20 @@ public class NotificationService extends FirebaseMessagingService { */ private void sendNotification(PostNotification postNotification) { Timber.i("Creating a notification..."); + + SharedPreferences settingsFile = getSharedPreferences(SETTINGS_SHARED_PREFS, Context.MODE_PRIVATE); + Uri notificationSoundUri = Uri.parse(settingsFile.getString(SELECTED_RINGTONE, null)); + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + boolean notificationsVibrateEnabled = sharedPrefs.getBoolean(NOTIFICATION_VIBRATION_KEY, true); + + int notificationDefaultValues = Notification.DEFAULT_LIGHTS; + if (notificationsVibrateEnabled) { + notificationDefaultValues |= Notification.DEFAULT_VIBRATE; + } + if (notificationSoundUri == null) { + notificationDefaultValues |= Notification.DEFAULT_SOUND; + } + String topicUrl = "https://www.thmmy.gr/smf/index.php?topic=" + postNotification.getTopicId() + "." + postNotification.getPostId(); Intent intent = new Intent(this, TopicActivity.class); Bundle extras = new Bundle(); @@ -84,10 +102,9 @@ public class NotificationService extends FirebaseMessagingService { String contentText = "New post by " + postNotification.getPoster(); int newPostsCount = 1; - if (buildVersion >= Build.VERSION_CODES.M){ + if (buildVersion >= Build.VERSION_CODES.M) { Notification existingNotification = getActiveNotification(topicId); - if(existingNotification!=null) - { + if (existingNotification != null) { newPostsCount = existingNotification.extras.getInt(NEW_POSTS_COUNT) + 1; contentText = newPostsCount + " new posts"; } @@ -103,21 +120,27 @@ public class NotificationService extends FirebaseMessagingService { .setContentText(contentText) .setAutoCancel(true) .setContentIntent(pendingIntent) - .setDefaults(Notification.DEFAULT_ALL) + .setDefaults(notificationDefaultValues) .setGroup(GROUP_KEY) .addExtras(notificationExtras); + //Checks for values other than defaults and applies them + if (notificationSoundUri != null) { + notificationBuilder.setSound(notificationSoundUri); + } + if (!notificationsVibrateEnabled) { + notificationBuilder.setVibrate(new long[]{0L}); + } if (buildVersion < Build.VERSION_CODES.O) notificationBuilder.setPriority(PRIORITY_MAX); boolean createSummaryNotification = false; - if(buildVersion >= Build.VERSION_CODES.M) + if (buildVersion >= Build.VERSION_CODES.M) createSummaryNotification = otherNotificationsExist(topicId); NotificationCompat.Builder summaryNotificationBuilder = null; - if(createSummaryNotification) - { + if (createSummaryNotification) { summaryNotificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) @@ -130,8 +153,6 @@ public class NotificationService extends FirebaseMessagingService { } - - NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // Since Android Oreo notification channel is needed. @@ -140,17 +161,16 @@ public class NotificationService extends FirebaseMessagingService { notificationManager.notify(NEW_POST_TAG, topicId, notificationBuilder.build()); - if(createSummaryNotification) - notificationManager.notify(SUMMARY_TAG,0, summaryNotificationBuilder.build()); + if (createSummaryNotification) + notificationManager.notify(SUMMARY_TAG, 0, summaryNotificationBuilder.build()); } @RequiresApi(api = Build.VERSION_CODES.M) private Notification getActiveNotification(int notificationId) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - if(notificationManager!=null) - { + if (notificationManager != null) { StatusBarNotification[] barNotifications = notificationManager.getActiveNotifications(); - for(StatusBarNotification notification: barNotifications) { + for (StatusBarNotification notification : barNotifications) { if (notification.getId() == notificationId) return notification.getNotification(); } @@ -160,13 +180,13 @@ public class NotificationService extends FirebaseMessagingService { } @RequiresApi(api = Build.VERSION_CODES.M) - private boolean otherNotificationsExist(int notificationId){ + private boolean otherNotificationsExist(int notificationId) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - if(notificationManager!=null) { + if (notificationManager != null) { StatusBarNotification[] barNotifications = notificationManager.getActiveNotifications(); for (StatusBarNotification notification : barNotifications) { String tag = notification.getTag(); - if (tag!=null && tag.equals(NEW_POST_TAG) && notification.getId() != notificationId) + if (tag != null && tag.equals(NEW_POST_TAG) && notification.getId() != notificationId) return true; } } diff --git a/app/src/main/res/layout/activity_bookmark.xml b/app/src/main/res/layout/activity_bookmark.xml index 939fb01a..d35191dd 100644 --- a/app/src/main/res/layout/activity_bookmark.xml +++ b/app/src/main/res/layout/activity_bookmark.xml @@ -54,6 +54,4 @@ app:layout_anchorGravity="bottom|center" app:mpb_indeterminateTint="@color/accent" app:mpb_progressStyle="horizontal"/> - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml new file mode 100644 index 00000000..a6a0513b --- /dev/null +++ b/app/src/main/res/layout/activity_settings.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index 72e2ac82..628b2a36 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -24,5 +24,6 @@ true true @android:color/transparent + @style/PreferenceThemeOverlay.v14.Material diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index df0d3cd4..2517070c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ Authenticating… Logout Downloads + Settings About Home Bookmarks @@ -74,6 +75,7 @@ Remove You have no bookmarked boards You have no bookmarked topics + Toggle Notification @@ -91,13 +93,26 @@ - - Toggle Notification - File \"%1$s\" already exists. Download again?" Download Symbol Cancel Open Download + + + Settings + Settings + + Notifications + + Vibration + Summary + Notifications sound + Select your preferred notification sound + + Posting + App signature + If enabled, a \"Posted from mThmmy\" message will be inserted at the end of your posts diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 3f32d79c..543cc9b2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -23,6 +23,7 @@ + + - + + + + + + + + + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 4ffe55a1..8e9f47f2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -25,6 +25,7 @@ false true @style/PreferenceThemeOverlay.v14.Material + @color/accent + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8e9f47f2..bab8b574 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -24,6 +24,9 @@ + + From f54974ed7ff99330669d865c7da42154ef76106b Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 2 Sep 2018 12:18:08 +0300 Subject: [PATCH 096/180] remove floating label on EditorView --- .../java/gr/thmmy/mthmmy/editorview/EditorView.java | 2 +- app/src/main/res/layout/editor_view.xml | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index fdec350c..a4ccc119 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -59,7 +59,7 @@ public class EditorView extends LinearLayout { TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EditorView, 0, 0); try { - edittextWrapper.setHint(a.getString(R.styleable.EditorView_hint)); + editText.setHint(a.getString(R.styleable.EditorView_hint)); } finally { a.recycle(); } diff --git a/app/src/main/res/layout/editor_view.xml b/app/src/main/res/layout/editor_view.xml index d249f889..4f691fbf 100644 --- a/app/src/main/res/layout/editor_view.xml +++ b/app/src/main/res/layout/editor_view.xml @@ -134,14 +134,17 @@ + android:orientation="horizontal" + android:layout_marginTop="4dp"> + android:layout_gravity="center" + android:orientation="vertical" + app:hintEnabled="false"> @@ -163,7 +166,7 @@ android:id="@+id/submit_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="bottom" + android:layout_gravity="center" android:contentDescription="@string/submit" android:padding="4dp" app:srcCompat="@drawable/ic_send_accent_24dp" From c09931f4b34264c6fbac7a06a696a46546769024 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 2 Sep 2018 12:32:32 +0300 Subject: [PATCH 097/180] change text color icon underline color --- app/src/main/res/drawable/ic_format_color_text.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/drawable/ic_format_color_text.xml b/app/src/main/res/drawable/ic_format_color_text.xml index 350065ff..9e8b6a46 100644 --- a/app/src/main/res/drawable/ic_format_color_text.xml +++ b/app/src/main/res/drawable/ic_format_color_text.xml @@ -1,6 +1,6 @@ - + From 28a58530730fdb0bd17dff9beb356cbe45774df7 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 2 Sep 2018 13:20:41 +0300 Subject: [PATCH 098/180] fixes --- app/src/main/AndroidManifest.xml | 3 +++ app/src/main/res/layout/editor_view.xml | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6432f0c6..cd4582c4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,9 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> + @@ -157,7 +156,7 @@ android:id="@+id/emoji_keyboard_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" + android:layout_gravity="bottom" android:padding="4dp" app:srcCompat="@drawable/ic_tag_faces_24dp" android:background="?android:selectableItemBackground"/> @@ -166,7 +165,7 @@ android:id="@+id/submit_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" + android:layout_gravity="bottom" android:contentDescription="@string/submit" android:padding="4dp" app:srcCompat="@drawable/ic_send_accent_24dp" From 5489102ef4751820a44960781847dab4056c772e Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sun, 2 Sep 2018 14:52:57 +0300 Subject: [PATCH 099/180] Added drawer intro, tiny changes --- CONTRIBUTING.md | 12 ++++++------ .../thmmy/mthmmy/activities/main/MainActivity.java | 9 +++++++-- .../thmmy/mthmmy/activities/topic/TopicActivity.java | 2 +- .../thmmy/mthmmy/activities/topic/TopicAdapter.java | 4 ++-- .../mthmmy/activities/topic/tasks/ReplyTask.java | 2 +- .../java/gr/thmmy/mthmmy/base/BaseApplication.java | 2 +- .../thmmy/mthmmy/editorview/AutoFitGridLayout.java | 1 + 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 556dfb11..0badb7f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ to contribute to mTHMMY in a way that is efficient for everyone. **Important!** Instead of creating publicly viewable issues for suspected security vulnerabilities, please report them in private to -`thmmynolife@gmail.com`. +[thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). ## I want to contribute! @@ -18,7 +18,7 @@ There are many ways of contributing to mTHMMY: - Submitting bugs and ideas to our [issue tracker][github-issues] - Forking mTHMMY and submitting [pull requests](#pull-requests) - Joining our core team -- Contacting us by email at `thmmynolife@gmail.com` +- Contacting us by email at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com) ## Issue tracker @@ -27,17 +27,17 @@ Before creating a new issue make sure to **search the tracker** for similar ones ## Compiling -Due to the app's integration with Firebase, a `google-services.json` is required inside the `app` directory. To get one, either [set up your own Firebase project][firebase-console] (with or without a self hosted [backend][sisyphus]), or ask us to provide you the one we use for development. +Due to the app's integration with Firebase, a *google-services.json* file is required inside the *app* directory. To get one, either [set up your own Firebase project][firebase-console] (with or without a self hosted [backend][sisyphus]), or ask us to provide you the one we use for development. ## Pull requests Pull 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 pull request: +follow the workflow below to make a pull request (PR): 1. Fork the project into your personal space on Github -1. Create a feature branch, away from `develop` +1. Create a feature branch, away from [develop](https://github.com/ThmmyNoLife/mTHMMY/tree/develop) 1. Push the commit(s) to your fork -1. Create a pull request (PR) targeting `develop` [at mTHMMY](https://github.com/ThmmyNoLife/mTHMMY/tree/develop) +1. Create a PR targeting [develop at mTHMMY](https://github.com/ThmmyNoLife/mTHMMY/tree/develop) 1. Fill the PR title describing the change you want to make 1. Fill the PR description with a brief motive for your change and the method you used to achieve it 1. Submit the PR. 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 59d686a6..4ffc3dff 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 @@ -45,6 +45,8 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF //-----------------------------------------CLASS VARIABLES------------------------------------------ private static final int TIME_INTERVAL = 2000; + private SharedPreferences sharedPrefs; + private static final String DRAWER_INTRO = "DRAWER_INTRO"; private long mBackPressed; private SectionsPagerAdapter sectionsPagerAdapter; private ViewPager viewPager; @@ -83,13 +85,12 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF TabLayout tabLayout = findViewById(R.id.tabs); tabLayout.setupWithViewPager(viewPager); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); int preferredTab = Integer.parseInt(sharedPrefs.getString(DEFAULT_HOME_TAB, "0")); if (preferredTab != 3 || sessionManager.isLoggedIn()) { tabLayout.getTabAt(preferredTab).select(); } - setMainActivity(this); } @@ -103,6 +104,10 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF @Override protected void onResume() { drawer.setSelection(HOME_ID); + if(!sharedPrefs.getBoolean(DRAWER_INTRO, false)){ + drawer.openDrawer(); + sharedPrefs.edit().putBoolean(DRAWER_INTRO, true).apply(); + } updateTabs(); super.onResume(); } 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 8ba2bae3..f9a9f8c5 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 @@ -41,11 +41,11 @@ import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; -import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; 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 1359e9fa..4c853526 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 @@ -42,12 +42,12 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.board.BoardActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.editorview.EditorView; +import gr.thmmy.mthmmy.editorview.EmojiKeyboard; 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.editorview.EditorView; -import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import timber.log.Timber; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java index 0b527421..63c2955b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java @@ -31,7 +31,7 @@ public class ReplyTask extends AsyncTask { @Override protected Boolean doInBackground(String... args) { final String sentFrommTHMMY = includeAppSignature - ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY [/url][/i][/size][/right]" + ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i] [/size][/right]" : ""; RequestBody postBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index 6caa91d4..dbd760a7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -42,7 +42,7 @@ import timber.log.Timber; public class BaseApplication extends Application { private static BaseApplication baseApplication; //BaseApplication singleton - //FirebaseAnalytics + //Firebase Analytics private FirebaseAnalytics firebaseAnalytics; //Client & SessionManager diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java index 8e3055e5..2b3eff99 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.GridLayout; + import gr.thmmy.mthmmy.R; public class AutoFitGridLayout extends GridLayout { From 4452c8b35505414eb6ce480932b89f3029ddbca2 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 2 Sep 2018 16:33:33 +0300 Subject: [PATCH 100/180] hopefully katarameno fix --- .../activities/board/BoardActivity.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) 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 75d0bea8..0aaa1525 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 @@ -156,7 +156,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo @Override public void onLoadMore() { - if (pagesLoaded < numberOfPages) { + if (pagesLoaded < numberOfPages && parsedTopics.get(parsedTopics.size() - 1) != null) { parsedTopics.add(null); boardAdapter.notifyItemInserted(parsedSubBoards.size() + parsedTopics.size()); @@ -185,6 +185,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo * parameter!

*/ private class BoardTask extends ParseTask { + ArrayList tempSubboards = new ArrayList<>(); + ArrayList tempTopics = new ArrayList<>(); + @Override protected void onPreExecute() { if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE); @@ -195,10 +198,6 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo public void parse(Document boardPage) throws ParseException { parsedTitle = boardPage.select("div.nav a.nav").last().text(); - //Removes loading item - if (isLoadingMore) { - if (parsedTopics.size() > 0) parsedTopics.remove(parsedTopics.size() - 1); - } //Finds number of pages if (numberOfPages == -1) { numberOfPages = 1; @@ -254,7 +253,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo } } } - parsedSubBoards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl)); + tempSubboards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl)); } } } @@ -293,7 +292,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo Timber.wtf("Board parsing about to fail. pLastPost came with: %s", pLastPost); } pLastPostUrl = topicColumns.last().select("a:has(img)").first().attr("href"); - parsedTopics.add(new Topic(pTopicUrl, pSubject, pStartedBy, pLastPost, pLastPostUrl, + tempTopics.add(new Topic(pTopicUrl, pSubject, pStartedBy, pLastPost, pLastPostUrl, pStats, pLocked, pSticky, pUnread)); } } @@ -304,18 +303,31 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo @Override protected void postExecution(ResultCode result) { //TODO if (result == ResultCode.SUCCESS)... - if (boardTitle == null || Objects.equals(boardTitle, "") - || !Objects.equals(boardTitle, parsedTitle)) { - boardTitle = parsedTitle; - toolbar.setTitle(boardTitle); - thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), false); + if (result == ResultCode.SUCCESS) { + if (boardTitle == null || Objects.equals(boardTitle, "") + || !Objects.equals(boardTitle, parsedTitle)) { + boardTitle = parsedTitle; + toolbar.setTitle(boardTitle); + thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), false); + } + + //Removes loading item + if (isLoadingMore) { + if (parsedTopics.size() > 0) parsedTopics.remove(parsedTopics.size() - 1); + } + + parsedTopics.clear(); + parsedSubBoards.clear(); + parsedTopics.addAll(tempTopics); + parsedSubBoards.addAll(tempSubboards); + boardAdapter.notifyDataSetChanged(); + + //Parse was successful + ++pagesLoaded; + if (newTopicFAB.getVisibility() != View.GONE) newTopicFAB.setEnabled(true); } - //Parse was successful - ++pagesLoaded; - if (newTopicFAB.getVisibility() != View.GONE) newTopicFAB.setEnabled(true); progressBar.setVisibility(ProgressBar.INVISIBLE); - boardAdapter.notifyDataSetChanged(); isLoadingMore = false; } } From 8484af46986cff09ed4394a6bc548850caf77f32 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 2 Sep 2018 18:21:59 +0300 Subject: [PATCH 101/180] disable scrolling on new topics --- .../java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 8ba2bae3..0c87db43 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 @@ -172,6 +172,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo //LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager( getApplicationContext(), topicPageUrl); + recyclerView.setLayoutManager(layoutManager); topicAdapter = new TopicAdapter(this, postsList); recyclerView.setAdapter(topicAdapter); @@ -632,10 +633,10 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo postsList.addAll(postList); topicAdapter.notifyDataSetChanged(); }); - viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> { + /*viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> { if (focusedPostIndex == null) return; recyclerView.scrollToPosition(focusedPostIndex); - }); + });*/ viewModel.getTopicTaskResultCode().observe(this, resultCode -> { if (resultCode == null) return; progressBar.setVisibility(ProgressBar.GONE); From 97ba6219c718feeae144183cf258b40bfb8e56c1 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 4 Sep 2018 11:25:55 +0300 Subject: [PATCH 102/180] create content activity layout init --- app/src/main/AndroidManifest.xml | 3 + .../activities/CreateContentActivity.java | 56 +++++++++++++++++++ .../activities/board/BoardActivity.java | 50 ++++++++--------- .../res/layout/activity_create_content.xml | 33 +++++++++++ 4 files changed, 114 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java create mode 100644 app/src/main/res/layout/activity_create_content.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cd4582c4..decb9b42 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + + \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java new file mode 100644 index 00000000..bcc0a334 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java @@ -0,0 +1,56 @@ +package gr.thmmy.mthmmy.activities; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.inputmethod.InputConnection; + +import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.editorview.EditorView; +import gr.thmmy.mthmmy.editorview.EmojiKeyboard; + +public class CreateContentActivity extends AppCompatActivity implements EmojiKeyboard.EmojiKeyboardOwner { + + EditorView contentEditor; + EmojiKeyboard emojiKeyboard; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create_content); + + emojiKeyboard = findViewById(R.id.emoji_keyboard); + + contentEditor = findViewById(R.id.main_content_editorview); + setEmojiKeyboardInputConnection(contentEditor.getInputConnection()); + contentEditor.setEmojiKeyboardOwner(this); + contentEditor.setOnSubmitListener(v -> { + + }); + } + + @Override + public void setEmojiKeyboardVisible(boolean visible) { + emojiKeyboard.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + @Override + public boolean isEmojiKeyboardVisible() { + return emojiKeyboard.getVisibility() == View.VISIBLE; + } + + @Override + public void setEmojiKeyboardInputConnection(InputConnection ic) { + emojiKeyboard.setInputConnection(ic); + } + + @Override + public void onBackPressed() { + if (emojiKeyboard.getVisibility() == View.VISIBLE) { + emojiKeyboard.setVisibility(View.GONE); + contentEditor.updateEmojiKeyboardVisibility(); + } else { + super.onBackPressed(); + } + } +} 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 75d0bea8..04a03503 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,9 +1,11 @@ package gr.thmmy.mthmmy.activities.board; +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; @@ -20,6 +22,8 @@ import java.util.ArrayList; import java.util.Objects; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.activities.CreateContentActivity; +import gr.thmmy.mthmmy.activities.LoginActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.Board; import gr.thmmy.mthmmy.model.Bookmark; @@ -95,37 +99,27 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo progressBar = findViewById(R.id.progressBar); newTopicFAB = findViewById(R.id.board_fab); - newTopicFAB.setEnabled(false); - newTopicFAB.hide(); - /*if (!sessionManager.isLoggedIn()) newTopicFAB.hide(); + if (!sessionManager.isLoggedIn()) newTopicFAB.hide(); else { - newTopicFAB.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (sessionManager.isLoggedIn()) { - //TODO create topic - } else { - new AlertDialog.Builder(BoardActivity.this) - .setMessage("You need to be logged in to create a new topic!") - .setPositiveButton("Login", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Intent intent = new Intent(BoardActivity.this, LoginActivity.class); - startActivity(intent); - finish(); - overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out); - } - }) - .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - } - }) - .show(); - } + newTopicFAB.setOnClickListener(view -> { + if (sessionManager.isLoggedIn()) { + //TODO create topic + startActivity(new Intent(this, CreateContentActivity.class)); + } else { + new AlertDialog.Builder(BoardActivity.this) + .setMessage("You need to be logged in to create a new topic!") + .setPositiveButton("Login", (dialogInterface, i) -> { + Intent intent = new Intent(BoardActivity.this, LoginActivity.class); + startActivity(intent); + finish(); + overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out); + }) + .setNegativeButton("Cancel", (dialogInterface, i) -> { + }) + .show(); } }); - }*/ + } boardAdapter = new BoardAdapter(getApplicationContext(), parsedSubBoards, parsedTopics); RecyclerView mainContent = findViewById(R.id.board_recycler_view); diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml new file mode 100644 index 00000000..35bb9143 --- /dev/null +++ b/app/src/main/res/layout/activity_create_content.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file From 3ae5ca276bf014e569fed3e84253c24897aeeaf9 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 4 Sep 2018 12:21:09 +0300 Subject: [PATCH 103/180] complete new topic task --- .../activities/CreateContentActivity.java | 53 ++++++++++- .../thmmy/mthmmy/activities/NewTopicTask.java | 95 +++++++++++++++++++ .../activities/board/BoardActivity.java | 14 ++- .../res/layout/activity_create_content.xml | 87 ++++++++++++----- app/src/main/res/values/strings.xml | 3 + 5 files changed, 224 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java index bcc0a334..48610cb7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java @@ -1,31 +1,57 @@ package gr.thmmy.mthmmy.activities; +import android.content.Intent; import android.os.Bundle; +import android.support.design.widget.TextInputLayout; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.inputmethod.InputConnection; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.Toolbar; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.editorview.EditorView; import gr.thmmy.mthmmy.editorview.EmojiKeyboard; +import me.zhanghai.android.materialprogressbar.MaterialProgressBar; +import timber.log.Timber; -public class CreateContentActivity extends AppCompatActivity implements EmojiKeyboard.EmojiKeyboardOwner { +public class CreateContentActivity extends AppCompatActivity implements EmojiKeyboard.EmojiKeyboardOwner, + NewTopicTask.NewTopicTaskCallbacks { - EditorView contentEditor; - EmojiKeyboard emojiKeyboard; + public final static String EXTRA_NEW_TOPIC_URL = "new-topic-extra"; + + private EditorView contentEditor; + private EmojiKeyboard emojiKeyboard; + private TextInputLayout subjectInput; + private MaterialProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_create_content); + TextView toolbarTitle = findViewById(R.id.toolbar_title); + toolbarTitle.setText(R.string.new_topic_toolbar); + + progressBar = findViewById(R.id.progressBar); + + Intent callingIntent = getIntent(); + String newTopicUrl = callingIntent.getStringExtra(EXTRA_NEW_TOPIC_URL); + emojiKeyboard = findViewById(R.id.emoji_keyboard); + subjectInput = findViewById(R.id.subject_input); + contentEditor = findViewById(R.id.main_content_editorview); setEmojiKeyboardInputConnection(contentEditor.getInputConnection()); contentEditor.setEmojiKeyboardOwner(this); contentEditor.setOnSubmitListener(v -> { - + if (newTopicUrl != null) { + new NewTopicTask(this).execute(newTopicUrl, subjectInput.getEditText().getText().toString(), + contentEditor.getText().toString()); + } }); } @@ -53,4 +79,23 @@ public class CreateContentActivity extends AppCompatActivity implements EmojiKey super.onBackPressed(); } } + + @Override + public void onNewTopicTaskStarted() { + Timber.i("New topic creation started"); + progressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onNewTopicTaskFinished(boolean success) { + progressBar.setVisibility(View.INVISIBLE); + if (success) { + Timber.i("New topic created successfully"); + finish(); + } else { + Timber.w("New topic creation failed"); + Toast.makeText(getBaseContext(), "Failed to create new topic!", Toast.LENGTH_LONG).show(); + finish(); + } + } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java new file mode 100644 index 00000000..322cac43 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java @@ -0,0 +1,95 @@ +package gr.thmmy.mthmmy.activities; + +import android.os.AsyncTask; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import java.io.IOException; + +import gr.thmmy.mthmmy.base.BaseApplication; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import timber.log.Timber; + +import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; + +public class NewTopicTask extends AsyncTask { + + private NewTopicTaskCallbacks listener; + + public NewTopicTask(NewTopicTaskCallbacks listener){ + this.listener = listener; + } + + @Override + protected void onPreExecute() { + listener.onNewTopicTaskStarted(); + } + + @Override + protected Boolean doInBackground(String... strings) { + Request request = new Request.Builder() + .url(strings[0] + ";wap2") + .build(); + + OkHttpClient client = BaseApplication.getInstance().getClient(); + + Document document; + String seqnum, sc, topic, createTopicUrl; + try { + Response response = client.newCall(request).execute(); + document = Jsoup.parse(response.body().string()); + + seqnum = document.select("input[name=seqnum]").first().attr("value"); + sc = document.select("input[name=sc]").first().attr("value"); + topic = document.select("input[name=topic]").first().attr("value"); + createTopicUrl = document.select("form").first().attr("action"); + + RequestBody postBody = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("message", strings[2]) + .addFormDataPart("seqnum", seqnum) + .addFormDataPart("sc", sc) + .addFormDataPart("subject", strings[1]) + .addFormDataPart("topic", topic) + .build(); + + Request post = new Request.Builder() + .url(createTopicUrl) + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") + .post(postBody) + .build(); + + try { + client.newCall(post).execute(); + Response response2 = client.newCall(post).execute(); + switch (replyStatus(response2)) { + case SUCCESSFUL: + BaseApplication.getInstance().logFirebaseAnalyticsEvent("new_topic_creation", null); + return true; + default: + Timber.e("Malformed post. Request string: %s", post.toString()); + return false; + } + } catch (IOException e) { + return false; + } + } catch (IOException e) { + return false; + } + } + + @Override + protected void onPostExecute(Boolean success) { + listener.onNewTopicTaskFinished(success); + } + + public interface NewTopicTaskCallbacks { + void onNewTopicTaskStarted(); + void onNewTopicTaskFinished(boolean success); + } +} 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 04a03503..9b905fb1 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 @@ -55,6 +55,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo private String boardUrl; private String boardTitle; private String parsedTitle; + private String newTopicUrl; private int numberOfPages = -1; private int pagesLoaded = 0; @@ -104,7 +105,11 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo newTopicFAB.setOnClickListener(view -> { if (sessionManager.isLoggedIn()) { //TODO create topic - startActivity(new Intent(this, CreateContentActivity.class)); + if (newTopicUrl != null) { + Intent intent = new Intent(this, CreateContentActivity.class); + intent.putExtra(CreateContentActivity.EXTRA_NEW_TOPIC_URL, newTopicUrl); + startActivity(intent); + } } else { new AlertDialog.Builder(BoardActivity.this) .setMessage("You need to be logged in to create a new topic!") @@ -209,6 +214,13 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo //It just means this board has only one page of topics. } } + + //Finds the url needed to create a new topic + Element newTopicButton = boardPage.select("a:has(img[alt=Start new topic])").first(); + if (newTopicButton == null) + newTopicButton = boardPage.select("a:has(img[alt=Νέο θέμα])").first(); + if (newTopicButton != null) newTopicUrl = newTopicButton.attr("href"); + { //Finds sub boards Elements subBoardRows = boardPage.select("div.tborder>table>tbody>tr"); if (subBoardRows != null && !subBoardRows.isEmpty()) { diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index 35bb9143..220de6e4 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -1,33 +1,74 @@ - - - - - + android:layout_width="match_parent"> - + android:layout_height="match_parent"> + + + + + + + + + + + + + + + + + + - + android:layout_height="@dimen/progress_bar_height" + android:indeterminate="true" + android:visibility="invisible" + app:layout_anchor="@id/appbar" + app:layout_anchorGravity="bottom|center" + app:mpb_indeterminateTint="@color/accent" + app:mpb_progressStyle="horizontal" /> - \ No newline at end of file + \ 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 4b8013a4..a5308050 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -180,4 +180,7 @@ Link URL Link text Required + + + New topic From 5011fbf4ded8ac740f927969ddf28bc5b5560f1f Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 4 Sep 2018 12:35:50 +0300 Subject: [PATCH 104/180] appbar fixes --- app/src/main/AndroidManifest.xml | 6 +++++- app/src/main/res/layout/activity_create_content.xml | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index decb9b42..b9c48bf4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -149,7 +149,11 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index 220de6e4..4e596664 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -5,7 +5,8 @@ xmlns:tools="http://schemas.android.com/tools" tools:context=".activities.CreateContentActivity" android:layout_height="match_parent" - android:layout_width="match_parent"> + android:layout_width="match_parent" + android:fitsSystemWindows="true"> Date: Tue, 4 Sep 2018 12:57:17 +0300 Subject: [PATCH 105/180] more appbar fixes --- .../mthmmy/activities/CreateContentActivity.java | 14 ++++++++++---- .../main/res/layout/activity_create_content.xml | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java index 48610cb7..9b1bcede 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java @@ -4,14 +4,13 @@ import android.content.Intent; import android.os.Bundle; import android.support.design.widget.TextInputLayout; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; import android.view.View; import android.view.inputmethod.InputConnection; import android.widget.TextView; import android.widget.Toast; -import android.widget.Toolbar; import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.editorview.EditorView; import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; @@ -32,8 +31,15 @@ public class CreateContentActivity extends AppCompatActivity implements EmojiKey super.onCreate(savedInstanceState); setContentView(R.layout.activity_create_content); - TextView toolbarTitle = findViewById(R.id.toolbar_title); - toolbarTitle.setText(R.string.new_topic_toolbar); + //Initialize toolbar + Toolbar toolbar = findViewById(R.id.toolbar); + toolbar.setTitle("Create topic"); + setSupportActionBar(toolbar); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + } + ((TextView) findViewById(R.id.toolbar_title)).setText("Create topic"); progressBar = findViewById(R.id.progressBar); diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index 4e596664..9602df66 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -51,7 +51,8 @@ android:id="@+id/main_content_editorview" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_below="@id/subject_input" /> + android:layout_below="@id/subject_input" + app:hint="topic message"/> Date: Wed, 5 Sep 2018 12:11:37 +0300 Subject: [PATCH 106/180] include app signature in new topic --- .../mthmmy/activities/CreateContentActivity.java | 14 +++++++++++++- .../gr/thmmy/mthmmy/activities/NewTopicTask.java | 9 +++++++-- .../mthmmy/activities/topic/tasks/ReplyTask.java | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java index 9b1bcede..b46d401a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java @@ -1,7 +1,9 @@ package gr.thmmy.mthmmy.activities; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.design.widget.TextInputLayout; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; @@ -11,8 +13,11 @@ import android.widget.TextView; import android.widget.Toast; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.activities.settings.SettingsActivity; +import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.editorview.EditorView; import gr.thmmy.mthmmy.editorview.EmojiKeyboard; +import gr.thmmy.mthmmy.session.SessionManager; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; @@ -55,7 +60,14 @@ public class CreateContentActivity extends AppCompatActivity implements EmojiKey contentEditor.setEmojiKeyboardOwner(this); contentEditor.setOnSubmitListener(v -> { if (newTopicUrl != null) { - new NewTopicTask(this).execute(newTopicUrl, subjectInput.getEditText().getText().toString(), + boolean includeAppSignature = true; + SessionManager sessionManager = BaseActivity.getSessionManager(); + if (sessionManager.isLoggedIn()) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + includeAppSignature = prefs.getBoolean(SettingsActivity.POSTING_APP_SIGNATURE_ENABLE_KEY, true); + } + + new NewTopicTask(this, includeAppSignature).execute(newTopicUrl, subjectInput.getEditText().getText().toString(), contentEditor.getText().toString()); } }); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java index 322cac43..c8dc34d5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java @@ -20,9 +20,11 @@ import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; public class NewTopicTask extends AsyncTask { private NewTopicTaskCallbacks listener; + private boolean includeAppSignature; - public NewTopicTask(NewTopicTaskCallbacks listener){ + public NewTopicTask(NewTopicTaskCallbacks listener, boolean includeAppSignature){ this.listener = listener; + this.includeAppSignature = includeAppSignature; } @Override @@ -49,9 +51,12 @@ public class NewTopicTask extends AsyncTask { topic = document.select("input[name=topic]").first().attr("value"); createTopicUrl = document.select("form").first().attr("action"); + final String appSignature = "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/" + + "details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i][/size][/right]"; + RequestBody postBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) - .addFormDataPart("message", strings[2]) + .addFormDataPart("message", strings[2] + (includeAppSignature ? appSignature : "")) .addFormDataPart("seqnum", seqnum) .addFormDataPart("sc", sc) .addFormDataPart("subject", strings[1]) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java index 63c2955b..033316d2 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java @@ -31,7 +31,7 @@ public class ReplyTask extends AsyncTask { @Override protected Boolean doInBackground(String... args) { final String sentFrommTHMMY = includeAppSignature - ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i] [/size][/right]" + ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i][/size][/right]" : ""; RequestBody postBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) From c344016546142e965051a4c2d3aaa582dac92a83 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 6 Sep 2018 11:47:29 +0300 Subject: [PATCH 107/180] Settings strings minor changes --- app/src/main/res/layout/activity_topic.xml | 2 +- app/src/main/res/values/strings.xml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/activity_topic.xml b/app/src/main/res/layout/activity_topic.xml index f331ceb9..242fb44e 100644 --- a/app/src/main/res/layout/activity_topic.xml +++ b/app/src/main/res/layout/activity_topic.xml @@ -6,6 +6,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" + android:background="@color/background" tools:context=".activities.topic.TopicActivity"> App Default home tab - Select your preferred, home screen, default tab + Sets a home screen tab as default Default home tab Notifications @@ -149,17 +149,17 @@ Toggle notifications state--> Vibration Notifications led - Enables/disables notifications led, if your device has one + Enables/disables the notifications led (if the device has one) Notifications sound - Select your preferred notification sound + Sets your preferred notification sound Posting App signature - If enabled, a \"sent from mTHMMY\" message will be inserted at the end of your posts + Appends a \"sent from mTHMMY\" message to your posts Uploading App signature - If enabled, an \"uploaded from mTHMMY\" message will be inserted at the end of your uploads descriptions + Appends an \"uploaded from mTHMMY\" message to the descriptions of your uploads Black From 98e62f07ee8b201ab79efd12de49adbefbbe630c Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Thu, 6 Sep 2018 13:30:54 +0300 Subject: [PATCH 108/180] minor UI adjustment --- app/src/main/res/layout/activity_create_content.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index 9602df66..f3b77e09 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -40,6 +40,7 @@ android:layout_width="240dp" android:layout_height="wrap_content" android:layout_below="@id/appbar" + android:layout_margin="16dp" android:hint="@string/subject"> Date: Thu, 6 Sep 2018 16:09:52 +0300 Subject: [PATCH 109/180] colored letters and dot in color picker --- .../thmmy/mthmmy/editorview/EditorView.java | 7 +++- .../res/layout/editor_view_color_picker.xml | 42 ++++++++++++------- app/src/main/res/values/colors.xml | 21 ++++++++++ 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index a4ccc119..4e01856d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -1,5 +1,6 @@ package gr.thmmy.mthmmy.editorview; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -20,6 +21,7 @@ import android.view.inputmethod.InputMethodManager; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.ScrollView; +import android.widget.TextView; import java.util.Objects; @@ -50,6 +52,7 @@ public class EditorView extends LinearLayout { init(context, attrs); } + @SuppressLint("SetTextI18n") private void init(Context context, AttributeSet attrs) { LayoutInflater.from(context).inflate(R.layout.editor_view, this, true); setOrientation(VERTICAL); @@ -142,7 +145,9 @@ public class EditorView extends LinearLayout { LinearLayout colorPicker = (LinearLayout) colorPickerScrollview.getChildAt(0); popupWindow.setContentView(colorPickerScrollview); for (int i = 0; i < colorPicker.getChildCount(); i++) { - colorPicker.getChildAt(i).setOnClickListener(v -> { + TextView child = (TextView) colorPicker.getChildAt(i); + child.setText("\u2B24 " + child.getText()); + child.setOnClickListener(v -> { boolean hadTextSelection = editText.hasSelection(); getText().insert(editText.getSelectionStart(), "[color=" + colors.get(v.getId()) + "]"); getText().insert(editText.getSelectionEnd(), "[/color]"); diff --git a/app/src/main/res/layout/editor_view_color_picker.xml b/app/src/main/res/layout/editor_view_color_picker.xml index 0ac2d71b..b71214e1 100644 --- a/app/src/main/res/layout/editor_view_color_picker.xml +++ b/app/src/main/res/layout/editor_view_color_picker.xml @@ -13,71 +13,85 @@ + android:text="@string/black" + android:textColor="@color/black"/> + android:text="@string/red" + android:textColor="@color/red"/> + android:text="@string/yellow" + android:textColor="@color/yellow"/> + android:text="@string/pink" + android:textColor="@color/pink"/> + android:text="@string/green" + android:textColor="@color/green"/> + android:text="@string/orange" + android:textColor="@color/orange"/> + android:text="@string/purple" + android:textColor="@color/purple"/> + android:text="@string/blue" + android:textColor="@color/blue"/> + android:text="@string/beige" + android:textColor="@color/beige"/> + android:text="@string/brown" + android:textColor="@color/brown"/> + android:text="@string/teal" + android:textColor="@color/teal"/> + android:text="@string/navy" + android:textColor="@color/navy"/> + android:text="@string/maroon" + android:textColor="@color/maroon"/> + android:text="@string/lime_green" + android:textColor="@color/lime_green"/>
\ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index c3bdac7a..f2209027 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -26,4 +26,25 @@ #D92B2B2B #E91E63 @color/primary_text + + #FF0000 + #800000 + #A52A2A + #FFA500 + #FFFF00 + #808000 + #008000 + #800080 + #FF00FF + #FFC0CB + #F5F5DC + #00FF00 + #32CD32 + #008080 + #00FFFF + #0000FF + #000080 + #000000 + #808080 + #C0C0C0 From 9333b5d2b9bf306a458ff3251bd5c17afee4713d Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Thu, 6 Sep 2018 18:44:34 +0300 Subject: [PATCH 110/180] no dots --- app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index 4e01856d..44b649a9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -146,7 +146,6 @@ public class EditorView extends LinearLayout { popupWindow.setContentView(colorPickerScrollview); for (int i = 0; i < colorPicker.getChildCount(); i++) { TextView child = (TextView) colorPicker.getChildAt(i); - child.setText("\u2B24 " + child.getText()); child.setOnClickListener(v -> { boolean hadTextSelection = editText.hasSelection(); getText().insert(editText.getSelectionStart(), "[color=" + colors.get(v.getId()) + "]"); From c4df3f38e7c561196a785336003bcf2a2cabb12e Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Fri, 7 Sep 2018 14:11:35 +0300 Subject: [PATCH 111/180] project structure --- app/src/main/AndroidManifest.xml | 2 +- .../java/gr/thmmy/mthmmy/activities/board/BoardActivity.java | 2 +- .../activities/{ => create_content}/CreateContentActivity.java | 3 ++- .../mthmmy/activities/{ => create_content}/NewTopicTask.java | 2 +- app/src/main/res/layout/activity_create_content.xml | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) rename app/src/main/java/gr/thmmy/mthmmy/activities/{ => create_content}/CreateContentActivity.java (97%) rename app/src/main/java/gr/thmmy/mthmmy/activities/{ => create_content}/NewTopicTask.java (98%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b9c48bf4..3b37c299 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -150,7 +150,7 @@ 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 9b905fb1..556f23df 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 @@ -22,7 +22,7 @@ import java.util.ArrayList; import java.util.Objects; import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.activities.CreateContentActivity; +import gr.thmmy.mthmmy.activities.create_content.CreateContentActivity; import gr.thmmy.mthmmy.activities.LoginActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.Board; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java similarity index 97% rename from app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java rename to app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index b46d401a..44e025ed 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.activities; +package gr.thmmy.mthmmy.activities.create_content; import android.content.Intent; import android.content.SharedPreferences; @@ -13,6 +13,7 @@ import android.widget.TextView; import android.widget.Toast; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.activities.create_content.NewTopicTask; import gr.thmmy.mthmmy.activities.settings.SettingsActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.editorview.EditorView; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java rename to app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java index c8dc34d5..253280eb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/NewTopicTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.activities; +package gr.thmmy.mthmmy.activities.create_content; import android.os.AsyncTask; diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index f3b77e09..9578bd2d 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - tools:context=".activities.CreateContentActivity" + tools:context=".activities.create_content.CreateContentActivity" android:layout_height="match_parent" android:layout_width="match_parent" android:fitsSystemWindows="true"> From f3bb24fd1f54a50997cc1b036e482656b40d1f4c Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Fri, 7 Sep 2018 14:14:46 +0300 Subject: [PATCH 112/180] minor stuff --- .../activities/create_content/CreateContentActivity.java | 3 +-- app/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index 44e025ed..524d022c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -13,7 +13,6 @@ import android.widget.TextView; import android.widget.Toast; import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.activities.create_content.NewTopicTask; import gr.thmmy.mthmmy.activities.settings.SettingsActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.editorview.EditorView; @@ -45,7 +44,7 @@ public class CreateContentActivity extends AppCompatActivity implements EmojiKey getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); } - ((TextView) findViewById(R.id.toolbar_title)).setText("Create topic"); + ((TextView) findViewById(R.id.toolbar_title)).setText(R.string.create_topic); progressBar = findViewById(R.id.progressBar); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a5308050..53cbb9b2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -183,4 +183,5 @@ New topic + Create topic From 5ad072e417dca84934e3f73481baf4ab6842ebae Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Fri, 7 Sep 2018 14:29:20 +0300 Subject: [PATCH 113/180] toolbar fix --- .../activities/create_content/CreateContentActivity.java | 8 ++------ app/src/main/res/layout/activity_create_content.xml | 8 +------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index 524d022c..781bb9f3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -5,11 +5,8 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.design.widget.TextInputLayout; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; import android.view.View; import android.view.inputmethod.InputConnection; -import android.widget.TextView; import android.widget.Toast; import gr.thmmy.mthmmy.R; @@ -21,7 +18,7 @@ import gr.thmmy.mthmmy.session.SessionManager; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; -public class CreateContentActivity extends AppCompatActivity implements EmojiKeyboard.EmojiKeyboardOwner, +public class CreateContentActivity extends BaseActivity implements EmojiKeyboard.EmojiKeyboardOwner, NewTopicTask.NewTopicTaskCallbacks { public final static String EXTRA_NEW_TOPIC_URL = "new-topic-extra"; @@ -37,14 +34,13 @@ public class CreateContentActivity extends AppCompatActivity implements EmojiKey setContentView(R.layout.activity_create_content); //Initialize toolbar - Toolbar toolbar = findViewById(R.id.toolbar); + toolbar = findViewById(R.id.toolbar); toolbar.setTitle("Create topic"); setSupportActionBar(toolbar); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); } - ((TextView) findViewById(R.id.toolbar_title)).setText(R.string.create_topic); progressBar = findViewById(R.id.progressBar); diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index 9578bd2d..04af0ea4 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -24,14 +24,8 @@ android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" - app:contentInsetStartWithNavigation="0dp" + android:gravity="center" app:popupTheme="@style/ToolbarTheme"> - - From d80d8a4d42d260ce7fe89f622244ebb3a498bfc5 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 10 Sep 2018 15:58:36 +0300 Subject: [PATCH 114/180] Ensure correct google-services.json is supplied when building release APKs --- app/build.gradle | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 00e58bbd..5baea52e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,8 @@ +import groovy.json.JsonSlurper + apply plugin: 'com.android.application' apply plugin: 'io.fabric' - android { compileSdkVersion 27 @@ -34,6 +35,17 @@ android { } } +tasks.whenTaskAdded { task -> + if (task.name.contains("assembleRelease")) { + task.getDependsOn().add({ + def inputFile = new File("app/google-services.json") + def json = new JsonSlurper().parseText(inputFile.text) + if(json.project_info.project_id != "mthmmy-release-3aef0") + throw new GradleException('Please supply the correct google-services.json for release or manually change the id above!') + }) + } +} + dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' @@ -44,7 +56,7 @@ dependencies { implementation 'com.android.support:cardview-v7:27.1.1' implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'com.google.firebase:firebase-core:16.0.3' - implementation 'com.google.firebase:firebase-messaging:17.3.0' + implementation 'com.google.firebase:firebase-messaging:17.3.1' implementation 'com.crashlytics.sdk.android:crashlytics:2.9.5' implementation 'com.squareup.okhttp3:okhttp:3.10.0' implementation 'com.squareup.picasso:picasso:2.5.2' From b31ad5db0644f08454f7ad1f1cc992a948796d9e Mon Sep 17 00:00:00 2001 From: Apostolof Date: Mon, 10 Sep 2018 20:36:21 +0300 Subject: [PATCH 115/180] UI fixes for topics activity --- .../activities/topic/TopicActivity.java | 26 ++++++++++++-- app/src/main/res/layout/activity_topic.xml | 36 ++++++++++--------- app/src/main/res/values/strings.xml | 2 +- 3 files changed, 45 insertions(+), 19 deletions(-) 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 84f35817..953f7ad8 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 @@ -12,12 +12,17 @@ import android.os.Bundle; import android.os.Handler; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; +import android.support.v4.content.ContextCompat; +import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatDelegate; import android.support.v7.widget.RecyclerView; +import android.text.Spannable; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -62,7 +67,7 @@ import static gr.thmmy.mthmmy.services.NotificationService.NEW_POST_TAG; */ @SuppressWarnings("unchecked") public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFocusChangeListener, - EmojiKeyboard.EmojiKeyboardOwner{ + EmojiKeyboard.EmojiKeyboardOwner { //Activity's variables /** * The key to use when putting topic's url String to {@link TopicActivity}'s Bundle. @@ -651,7 +656,15 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo // no page has been loaded yet. Give user the ability to refresh recyclerView.setVisibility(View.GONE); TextView errorTextview = findViewById(R.id.error_textview); - errorTextview.setText(getString(R.string.network_error_retry_prompt)); + + Spannable errorText = new SpannableString(getString(R.string.network_error_retry_prompt)); + errorText.setSpan( + new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.accent, null)), + errorText.toString().indexOf("Tap to retry"), + errorText.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + errorTextview.setText(errorText); errorTextview.setVisibility(View.VISIBLE); errorTextview.setOnClickListener(view -> { viewModel.reloadPage(); @@ -671,6 +684,15 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo Timber.w("Requested topic was unauthorized"); recyclerView.setVisibility(View.GONE); TextView errorTextview = findViewById(R.id.error_textview); + + Spannable errorText = new SpannableString(getString(R.string.unauthorized_topic_error)); + errorText.setSpan( + //TODO: maybe change the color to a red in order to indicate the error nature of the message + new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.accent, null)), + 0, + errorText.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + errorTextview.setText(getString(R.string.unauthorized_topic_error)); errorTextview.setVisibility(View.VISIBLE); break; diff --git a/app/src/main/res/layout/activity_topic.xml b/app/src/main/res/layout/activity_topic.xml index 242fb44e..1ef0d0e7 100644 --- a/app/src/main/res/layout/activity_topic.xml +++ b/app/src/main/res/layout/activity_topic.xml @@ -5,13 +5,13 @@ android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent" - android:fitsSystemWindows="true" android:background="@color/background" + android:fitsSystemWindows="true" tools:context=".activities.topic.TopicActivity"> + android:layout_height="match_parent"> @@ -39,10 +40,11 @@ - + android:visibility="gone" /> - + + Subject… Submit Message… - Could not connect to thmmy.gr \n\n Tap to retry + Could not connect to thmmy.gr\n\nTap to retry Network error retry This topic is either missing or off limits to you From 0ff971c84061302fc2de700deae71c17f27874b6 Mon Sep 17 00:00:00 2001 From: Apostolof Date: Mon, 10 Sep 2018 20:57:38 +0300 Subject: [PATCH 116/180] Fix greek parsing for mentions --- .../main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java | 2 +- app/src/main/res/layout/activity_topic.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) 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 e6970a80..b0132a14 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 @@ -32,7 +32,7 @@ import timber.log.Timber; */ public class TopicParser { private static Pattern mentionsPattern = Pattern. - compile("
\\n\\s+?Quote from: " + compile("
\\n\\s+?(Quote from|Παράθεση από): " + BaseActivity.getSessionManager().getUsername()); //User colors diff --git a/app/src/main/res/layout/activity_topic.xml b/app/src/main/res/layout/activity_topic.xml index 1ef0d0e7..ac653015 100644 --- a/app/src/main/res/layout/activity_topic.xml +++ b/app/src/main/res/layout/activity_topic.xml @@ -44,7 +44,6 @@ android:layout_above="@id/emoji_keyboard" android:layout_below="@id/appbar" android:layout_gravity="top|start" - android:background="@color/background" android:clipToPadding="false" android:paddingBottom="4dp" android:paddingTop="4dp" From 6a619ef878696d7d4e5b9b3fb287b2774d8ae7b3 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 10 Sep 2018 22:28:59 +0300 Subject: [PATCH 117/180] Unread bug fix --- .../main/unread/UnreadFragment.java | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 1709db82..b18874d5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -102,15 +102,12 @@ public class UnreadFragment extends BaseFragment { if (rootView instanceof RelativeLayout) { progressBar = rootView.findViewById(R.id.progressBar); unreadAdapter = new UnreadAdapter(topicSummaries, - fragmentInteractionListener, new UnreadAdapter.MarkReadInteractionListener() { - @Override - public void onMarkReadInteraction(String markReadLinkUrl) { - if (markReadTask != null && markReadTask.getStatus() != AsyncTask.Status.RUNNING) { - markReadTask = new MarkReadTask(); - markReadTask.execute(markReadLinkUrl); - } - } - }); + fragmentInteractionListener, markReadLinkUrl -> { + if (markReadTask != null && markReadTask.getStatus() != AsyncTask.Status.RUNNING) { + markReadTask = new MarkReadTask(); + markReadTask.execute(markReadLinkUrl); + } + }); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext()); @@ -124,19 +121,15 @@ public class UnreadFragment extends BaseFragment { swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.primary); swipeRefreshLayout.setColorSchemeResources(R.color.accent); swipeRefreshLayout.setOnRefreshListener( - new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - if (unreadTask != null && unreadTask.getStatus() != AsyncTask.Status.RUNNING) { - topicSummaries.clear(); - numberOfPages = 0; - loadedPages = 0; - unreadTask = new UnreadTask(); - assert SessionManager.unreadUrl != null; - unreadTask.execute(SessionManager.unreadUrl.toString()); - } + () -> { + if (unreadTask != null && unreadTask.getStatus() != AsyncTask.Status.RUNNING) { + topicSummaries.clear(); + numberOfPages = 0; + loadedPages = 0; + unreadTask = new UnreadTask(); + assert SessionManager.unreadUrl != null; + unreadTask.execute(SessionManager.unreadUrl.toString()); } - } ); } @@ -237,7 +230,12 @@ public class UnreadFragment extends BaseFragment { assert SessionManager.unreadUrl != null; unreadTask.execute(SessionManager.unreadUrl.toString() + ";start=" + loadedPages * 20); } - + else { + progressBar.setVisibility(ProgressBar.INVISIBLE); + swipeRefreshLayout.setRefreshing(false); + } + } + else{ progressBar.setVisibility(ProgressBar.INVISIBLE); swipeRefreshLayout.setRefreshing(false); } From 4f8e2e079dde0c8364d046af8b2997a40dcdb50d Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Mon, 10 Sep 2018 23:16:46 +0300 Subject: [PATCH 118/180] new parse task --- .../mthmmy/utils/parsing/NewParseTask.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java new file mode 100644 index 00000000..5af4a172 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -0,0 +1,66 @@ +package gr.thmmy.mthmmy.utils.parsing; + +import android.os.AsyncTask; + +public abstract class NewParseTask extends AsyncTask { + + private OnParseTaskStartedListener onParseTaskStartedListener; + private OnParseTaskCancelledListener onParseTaskCancelledListener; + private OnParseTaskFinishedListener onParseTaskFinishedListener; + + @Override + protected void onPreExecute() { + if (onParseTaskStartedListener != null) + onParseTaskStartedListener.onParseStart(); + else + super.onPreExecute(); + } + + @Override + protected void onCancelled() { + if (onParseTaskCancelledListener != null) + onParseTaskCancelledListener.onParseCancel(); + else + super.onCancelled(); + } + + @Override + protected void onCancelled(V v) { + if (onParseTaskCancelledListener != null) + onParseTaskCancelledListener.onParseCancel(); + else + super.onCancelled(); + } + + @Override + protected void onPostExecute(V v) { + if (onParseTaskFinishedListener != null) + onParseTaskFinishedListener.onParseFinish(); + else + super.onPostExecute(v); + } + + public void setOnParseTaskStartedListener(OnParseTaskStartedListener onParseTaskStartedListener) { + this.onParseTaskStartedListener = onParseTaskStartedListener; + } + + public void setOnParseTaskCancelledListener(OnParseTaskCancelledListener onParseTaskCancelledListener) { + this.onParseTaskCancelledListener = onParseTaskCancelledListener; + } + + public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public interface OnParseTaskStartedListener { + void onParseStart(); + } + + public interface OnParseTaskCancelledListener { + void onParseCancel(); + } + + public interface OnParseTaskFinishedListener { + void onParseFinish(); + } +} From d7bd211de618dbbca9b864a2a014f2f2bf73c374 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Mon, 10 Sep 2018 23:20:14 +0300 Subject: [PATCH 119/180] constructors instead of setters --- .../thmmy/mthmmy/utils/parsing/NewParseTask.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index 5af4a172..ec1da28e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -40,6 +40,20 @@ public abstract class NewParseTask extends AsyncTask { super.onPostExecute(v); } + public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, + OnParseTaskFinishedListener onParseTaskFinishedListener) { + this.onParseTaskStartedListener = onParseTaskStartedListener; + this.onParseTaskCancelledListener = onParseTaskCancelledListener; + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { + this.onParseTaskStartedListener = onParseTaskStartedListener; + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public NewParseTask() { } + public void setOnParseTaskStartedListener(OnParseTaskStartedListener onParseTaskStartedListener) { this.onParseTaskStartedListener = onParseTaskStartedListener; } From bb7537f65ac15289c9a1e709d20a88324d6d01fe Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Mon, 10 Sep 2018 23:32:27 +0300 Subject: [PATCH 120/180] fixes --- .../mthmmy/utils/parsing/NewParseTask.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index ec1da28e..ab6047e8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -6,7 +6,7 @@ public abstract class NewParseTask extends AsyncTask { private OnParseTaskStartedListener onParseTaskStartedListener; private OnParseTaskCancelledListener onParseTaskCancelledListener; - private OnParseTaskFinishedListener onParseTaskFinishedListener; + private OnParseTaskFinishedListener onParseTaskFinishedListener; @Override protected void onPreExecute() { @@ -35,37 +35,25 @@ public abstract class NewParseTask extends AsyncTask { @Override protected void onPostExecute(V v) { if (onParseTaskFinishedListener != null) - onParseTaskFinishedListener.onParseFinish(); + onParseTaskFinishedListener.onParseFinish(v); else super.onPostExecute(v); } public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { + OnParseTaskFinishedListener onParseTaskFinishedListener) { this.onParseTaskStartedListener = onParseTaskStartedListener; this.onParseTaskCancelledListener = onParseTaskCancelledListener; this.onParseTaskFinishedListener = onParseTaskFinishedListener; } - public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { + public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { this.onParseTaskStartedListener = onParseTaskStartedListener; this.onParseTaskFinishedListener = onParseTaskFinishedListener; } public NewParseTask() { } - public void setOnParseTaskStartedListener(OnParseTaskStartedListener onParseTaskStartedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; - } - - public void setOnParseTaskCancelledListener(OnParseTaskCancelledListener onParseTaskCancelledListener) { - this.onParseTaskCancelledListener = onParseTaskCancelledListener; - } - - public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskFinishedListener = onParseTaskFinishedListener; - } - public interface OnParseTaskStartedListener { void onParseStart(); } @@ -74,7 +62,7 @@ public abstract class NewParseTask extends AsyncTask { void onParseCancel(); } - public interface OnParseTaskFinishedListener { - void onParseFinish(); + public interface OnParseTaskFinishedListener { + void onParseFinish(V result); } } From db75338039d6347a95d70b74551e39df59aec23a Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 11 Sep 2018 18:04:46 +0300 Subject: [PATCH 121/180] improvements --- .../utils/parsing/ExternalAsyncTask.java | 80 +++++++++++++++++++ .../mthmmy/utils/parsing/NetworkTask.java | 65 +++++++++++++++ .../mthmmy/utils/parsing/NewParseTask.java | 71 ++++------------ .../gr/thmmy/mthmmy/utils/parsing/Parcel.java | 51 ++++++++++++ 4 files changed, 211 insertions(+), 56 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java new file mode 100644 index 00000000..6f5814e0 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java @@ -0,0 +1,80 @@ +package gr.thmmy.mthmmy.utils.parsing; + +import android.os.AsyncTask; + +public abstract class ExternalAsyncTask extends AsyncTask { + + private OnParseTaskStartedListener onParseTaskStartedListener; + private OnParseTaskCancelledListener onParseTaskCancelledListener; + private OnParseTaskFinishedListener onParseTaskFinishedListener; + + @Override + protected void onPreExecute() { + if (onParseTaskStartedListener != null) + onParseTaskStartedListener.onParseStart(); + else + super.onPreExecute(); + } + + @Override + protected void onCancelled() { + if (onParseTaskCancelledListener != null) + onParseTaskCancelledListener.onParseCancel(); + else + super.onCancelled(); + } + + @Override + protected void onCancelled(V v) { + if (onParseTaskCancelledListener != null) + onParseTaskCancelledListener.onParseCancel(); + else + super.onCancelled(); + } + + @Override + protected void onPostExecute(V v) { + if (onParseTaskFinishedListener != null) + onParseTaskFinishedListener.onParseFinish(v); + else + super.onPostExecute(v); + } + + public ExternalAsyncTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, + OnParseTaskFinishedListener onParseTaskFinishedListener) { + this.onParseTaskStartedListener = onParseTaskStartedListener; + this.onParseTaskCancelledListener = onParseTaskCancelledListener; + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public ExternalAsyncTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { + this.onParseTaskStartedListener = onParseTaskStartedListener; + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public ExternalAsyncTask() { } + + public void setOnParseTaskStartedListener(OnParseTaskStartedListener onParseTaskStartedListener) { + this.onParseTaskStartedListener = onParseTaskStartedListener; + } + + public void setOnParseTaskCancelledListener(OnParseTaskCancelledListener onParseTaskCancelledListener) { + this.onParseTaskCancelledListener = onParseTaskCancelledListener; + } + + public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public interface OnParseTaskStartedListener { + void onParseStart(); + } + + public interface OnParseTaskCancelledListener { + void onParseCancel(); + } + + public interface OnParseTaskFinishedListener { + void onParseFinish(V result); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java new file mode 100644 index 00000000..d2bd3d57 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java @@ -0,0 +1,65 @@ +package gr.thmmy.mthmmy.utils.parsing; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import java.io.IOException; + +import gr.thmmy.mthmmy.base.BaseApplication; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import timber.log.Timber; + +public abstract class NetworkTask extends ExternalAsyncTask> { + + private OnParseTaskFinishedListener onParseTaskFinishedListener; + + @Override + protected final Parcel doInBackground(String... input) { + Request request = createRequest(input); + Response response = getResponse(request, BaseApplication.getInstance().getClient()); + String responseBodyString; + try { + responseBodyString = response.body().string(); + } catch (IOException e) { + Timber.e(e); + return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); + } + try { + T data = performTask(Jsoup.parse(responseBodyString)); + int resultCode = getResultCode(response, data); + return new Parcel<>(resultCode, data); + } catch (ParseException pe) { + Timber.e(pe); + return new Parcel<>(Parcel.ResultCode.PARSE_ERROR, null); + } catch (Exception e) { + Timber.e(e); + return new Parcel<>(Parcel.ResultCode.PERFORM_TASK_ERROR, null); + } + } + + @Override + protected void onPostExecute(Parcel tParcel) { + if (onParseTaskFinishedListener != null) + onParseTaskFinishedListener.onParseFinish(tParcel.getResultCode(), tParcel.getData()); + else + super.onPostExecute(tParcel); + } + + abstract Request createRequest(String... input); + + abstract Response getResponse(Request request, OkHttpClient client); + + abstract T performTask(Document document) throws ParseException; + + abstract int getResultCode(Response response, T data); + + public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public interface OnParseTaskFinishedListener { + void onParseFinish(int resultCOde, T data); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index ab6047e8..4c23c241 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -1,68 +1,27 @@ package gr.thmmy.mthmmy.utils.parsing; -import android.os.AsyncTask; +import org.jsoup.nodes.Document; -public abstract class NewParseTask extends AsyncTask { +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; - private OnParseTaskStartedListener onParseTaskStartedListener; - private OnParseTaskCancelledListener onParseTaskCancelledListener; - private OnParseTaskFinishedListener onParseTaskFinishedListener; +public abstract class NewParseTask extends NetworkTask { @Override - protected void onPreExecute() { - if (onParseTaskStartedListener != null) - onParseTaskStartedListener.onParseStart(); - else - super.onPreExecute(); + final T performTask(Document document) throws ParseException { + try { + return parse(document); + } catch (Exception e) { + throw new ParseException("Parse failed."); + } } - @Override - protected void onCancelled() { - if (onParseTaskCancelledListener != null) - onParseTaskCancelledListener.onParseCancel(); - else - super.onCancelled(); - } - - @Override - protected void onCancelled(V v) { - if (onParseTaskCancelledListener != null) - onParseTaskCancelledListener.onParseCancel(); - else - super.onCancelled(); - } - - @Override - protected void onPostExecute(V v) { - if (onParseTaskFinishedListener != null) - onParseTaskFinishedListener.onParseFinish(v); - else - super.onPostExecute(v); - } + abstract Request createRequest(String... input); - public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; - this.onParseTaskCancelledListener = onParseTaskCancelledListener; - this.onParseTaskFinishedListener = onParseTaskFinishedListener; - } - - public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; - this.onParseTaskFinishedListener = onParseTaskFinishedListener; - } - - public NewParseTask() { } + abstract Response getResponse(Request request, OkHttpClient client); - public interface OnParseTaskStartedListener { - void onParseStart(); - } - - public interface OnParseTaskCancelledListener { - void onParseCancel(); - } + abstract T parse (Document document); - public interface OnParseTaskFinishedListener { - void onParseFinish(V result); - } + abstract int getResultCode(Response response, T data); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java new file mode 100644 index 00000000..6e1e0f7f --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java @@ -0,0 +1,51 @@ +package gr.thmmy.mthmmy.utils.parsing; + +public class Parcel { + + private int resultCode; + private T data; + + public Parcel(int resultCode, T data) { + this.resultCode = resultCode; + this.data = data; + } + + public int getResultCode() { + return resultCode; + } + + public T getData() { + return data; + } + + public class ResultCode { + /** + * The request was successful + */ + public static final int SUCCESSFUL = 0; + /** + * Error 404, page was not found + */ + public static final int NOT_FOUND = 1; + /** + * User session ended while posting the reply + */ + public static final int SESSION_ENDED = 2; + /** + * Exception occured while parsing + */ + public static final int PARSE_ERROR = 3; + /** + * Other undefined of unidentified error + */ + public static final int OTHER_ERROR = 4; + /** + * Failed to connect to thmmy.gr + */ + public static final int NETWORK_ERROR = 5; + /** + * Error while excecuting NetworkTask's performTask() + */ + public static final int PERFORM_TASK_ERROR = 6; + } +} From fff52d1ec6061e936136b604bbe9164480640e81 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 11 Sep 2018 18:13:49 +0300 Subject: [PATCH 122/180] add parse exception constructor --- .../main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java | 2 +- .../java/gr/thmmy/mthmmy/utils/parsing/ParseException.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index 4c23c241..0d19c098 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -13,7 +13,7 @@ public abstract class NewParseTask extends NetworkTask { try { return parse(document); } catch (Exception e) { - throw new ParseException("Parse failed."); + throw new ParseException("Parse failed.", e); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java index fea7be6b..abda1f38 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java @@ -10,4 +10,8 @@ public class ParseException extends Exception { { super(message); } + + public ParseException(String message, Throwable cause) { + super(message, cause); + } } From e31227f62e3262031a2c16276c02e0af78c6a572 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 11 Sep 2018 18:36:08 +0300 Subject: [PATCH 123/180] override constructors --- .../mthmmy/utils/parsing/NetworkTask.java | 13 ++++++++++++ .../mthmmy/utils/parsing/NewParseTask.java | 21 ++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java index d2bd3d57..cfceb904 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java @@ -15,6 +15,19 @@ public abstract class NetworkTask extends ExternalAsyncTask private OnParseTaskFinishedListener onParseTaskFinishedListener; + public NetworkTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, + OnParseTaskFinishedListener onParseTaskFinishedListener) { + super(onParseTaskStartedListener, onParseTaskCancelledListener, null); + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public NetworkTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { + super(onParseTaskStartedListener, null); + this.onParseTaskFinishedListener = onParseTaskFinishedListener; + } + + public NetworkTask() {} + @Override protected final Parcel doInBackground(String... input) { Request request = createRequest(input); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index 0d19c098..0a0591de 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -2,12 +2,19 @@ package gr.thmmy.mthmmy.utils.parsing; import org.jsoup.nodes.Document; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - public abstract class NewParseTask extends NetworkTask { + public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, + OnParseTaskFinishedListener onParseTaskFinishedListener) { + super(onParseTaskStartedListener, onParseTaskCancelledListener, onParseTaskFinishedListener); + } + + public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { + super(onParseTaskStartedListener, onParseTaskFinishedListener); + } + + public NewParseTask() {} + @Override final T performTask(Document document) throws ParseException { try { @@ -17,11 +24,5 @@ public abstract class NewParseTask extends NetworkTask { } } - abstract Request createRequest(String... input); - - abstract Response getResponse(Request request, OkHttpClient client); - abstract T parse (Document document); - - abstract int getResultCode(Response response, T data); } From 4b79360ad1f3207cd2dfe3bc97b0c6d94bddc3b5 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 11 Sep 2018 19:33:01 +0300 Subject: [PATCH 124/180] fix variable and method scopes --- .../thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java | 6 +++--- .../gr/thmmy/mthmmy/utils/parsing/NetworkTask.java | 10 +++++----- .../gr/thmmy/mthmmy/utils/parsing/NewParseTask.java | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java index 6f5814e0..93bc4224 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java @@ -4,9 +4,9 @@ import android.os.AsyncTask; public abstract class ExternalAsyncTask extends AsyncTask { - private OnParseTaskStartedListener onParseTaskStartedListener; - private OnParseTaskCancelledListener onParseTaskCancelledListener; - private OnParseTaskFinishedListener onParseTaskFinishedListener; + protected OnParseTaskStartedListener onParseTaskStartedListener; + protected OnParseTaskCancelledListener onParseTaskCancelledListener; + protected OnParseTaskFinishedListener onParseTaskFinishedListener; @Override protected void onPreExecute() { diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java index cfceb904..a137ebdb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java @@ -13,7 +13,7 @@ import timber.log.Timber; public abstract class NetworkTask extends ExternalAsyncTask> { - private OnParseTaskFinishedListener onParseTaskFinishedListener; + protected OnParseTaskFinishedListener onParseTaskFinishedListener; public NetworkTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { @@ -60,13 +60,13 @@ public abstract class NetworkTask extends ExternalAsyncTask super.onPostExecute(tParcel); } - abstract Request createRequest(String... input); + protected abstract Request createRequest(String... input); - abstract Response getResponse(Request request, OkHttpClient client); + protected abstract Response getResponse(Request request, OkHttpClient client); - abstract T performTask(Document document) throws ParseException; + protected abstract T performTask(Document document) throws ParseException; - abstract int getResultCode(Response response, T data); + protected abstract int getResultCode(Response response, T data); public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { this.onParseTaskFinishedListener = onParseTaskFinishedListener; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index 0a0591de..98449b64 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -16,7 +16,7 @@ public abstract class NewParseTask extends NetworkTask { public NewParseTask() {} @Override - final T performTask(Document document) throws ParseException { + protected final T performTask(Document document) throws ParseException { try { return parse(document); } catch (Exception e) { @@ -24,5 +24,5 @@ public abstract class NewParseTask extends NetworkTask { } } - abstract T parse (Document document); + protected abstract T parse (Document document); } From f400960548cb266f92b68ec20d0e1bba4882c01c Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 11 Sep 2018 21:18:22 +0300 Subject: [PATCH 125/180] merge createRequest and getResponse --- .../gr/thmmy/mthmmy/utils/parsing/NetworkTask.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java index a137ebdb..a63f954e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java @@ -30,11 +30,13 @@ public abstract class NetworkTask extends ExternalAsyncTask @Override protected final Parcel doInBackground(String... input) { - Request request = createRequest(input); - Response response = getResponse(request, BaseApplication.getInstance().getClient()); + Response response = sendRequest(BaseApplication.getInstance().getClient(), input); String responseBodyString; try { responseBodyString = response.body().string(); + } catch (NullPointerException npe) { + Timber.e(npe, "Invalid response. Detatails: https://square.github.io/okhttp/3.x/okhttp/okhttp3/Response.html#body--"); + return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); } catch (IOException e) { Timber.e(e); return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); @@ -60,9 +62,7 @@ public abstract class NetworkTask extends ExternalAsyncTask super.onPostExecute(tParcel); } - protected abstract Request createRequest(String... input); - - protected abstract Response getResponse(Request request, OkHttpClient client); + protected abstract Response sendRequest(OkHttpClient client, String... input); protected abstract T performTask(Document document) throws ParseException; From 4938597f2ed778d4a0929c4fd830dc2618983f44 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 11 Sep 2018 23:06:22 +0300 Subject: [PATCH 126/180] improvements and implement parse task in delete post --- .../activities/topic/TopicActivity.java | 29 ++++------ .../activities/topic/tasks/DeleteTask.java | 53 ++++++------------- .../mthmmy/utils/parsing/NetworkTask.java | 19 ++++--- .../mthmmy/utils/parsing/NewParseTask.java | 4 +- .../mthmmy/utils/parsing/ParseException.java | 2 +- .../mthmmy/viewmodel/TopicViewModel.java | 16 ++++-- 6 files changed, 51 insertions(+), 72 deletions(-) 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 953f7ad8..7f8b248a 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 @@ -12,7 +12,6 @@ import android.os.Bundle; import android.os.Handler; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; -import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatDelegate; @@ -39,7 +38,6 @@ import android.widget.Toast; import java.util.ArrayList; import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.activities.topic.tasks.DeleteTask; import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; @@ -52,6 +50,7 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; import gr.thmmy.mthmmy.utils.HTMLUtils; +import gr.thmmy.mthmmy.utils.parsing.Parcel; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; @@ -498,23 +497,15 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo progressBar.setVisibility(ProgressBar.GONE); } }); - viewModel.setDeleteTaskCallbacks(new DeleteTask.DeleteTaskCallbacks() { - @Override - public void onDeleteTaskStarted() { - progressBar.setVisibility(ProgressBar.VISIBLE); - } - - @Override - public void onDeleteTaskFinished(boolean result) { - progressBar.setVisibility(ProgressBar.GONE); - - if (result) { - Timber.i("Post deleted successfully"); - viewModel.reloadPage(); - } else { - Timber.w("Failed to delete post"); - Toast.makeText(getBaseContext(), "Delete failed!", Toast.LENGTH_SHORT).show(); - } + viewModel.setDeleteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); + viewModel.setDeleteTaskFinishedListener((resultCode, data) -> { + progressBar.setVisibility(ProgressBar.GONE); + if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + Timber.i("Post deleted successfully"); + viewModel.reloadPage(); + } else { + Timber.w("Failed to delete post"); + Toast.makeText(getBaseContext(), "Delete failed!", Toast.LENGTH_SHORT).show(); } }); viewModel.setReplyFinishListener(new ReplyTask.ReplyTaskCallbacks() { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java index 0a9486b1..40a2df5b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java @@ -1,62 +1,39 @@ package gr.thmmy.mthmmy.activities.topic.tasks; -import android.os.AsyncTask; +import org.jsoup.nodes.Document; import java.io.IOException; -import gr.thmmy.mthmmy.activities.topic.Posting; -import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.utils.parsing.NetworkTask; +import gr.thmmy.mthmmy.utils.parsing.Parcel; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import timber.log.Timber; -public class DeleteTask extends AsyncTask { - private DeleteTaskCallbacks listener; +public class DeleteTask extends NetworkTask { - public DeleteTask(DeleteTaskCallbacks listener) { - this.listener = listener; + public DeleteTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { + super(onParseTaskStartedListener, onParseTaskFinishedListener); } @Override - protected void onPreExecute() { - listener.onDeleteTaskStarted(); - } - - @Override - protected Boolean doInBackground(String... args) { + protected Response sendRequest(OkHttpClient client, String... input) throws IOException { Request delete = new Request.Builder() - .url(args[0]) + .url(input[0]) .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") .build(); - - try { - OkHttpClient client = BaseApplication.getInstance().getClient(); - client.newCall(delete).execute(); - Response response = client.newCall(delete).execute(); - //Response response = client.newCall(delete).execute(); - switch (Posting.replyStatus(response)) { - case SUCCESSFUL: - BaseApplication.getInstance().logFirebaseAnalyticsEvent("post_deletion", null); - return true; - default: - Timber.e("Something went wrong. Request string: %s", delete.toString()); - return false; - } - } catch (IOException e) { - Timber.e(e, "Delete failed."); - return false; - } + client.newCall(delete).execute(); + return client.newCall(delete).execute(); } @Override - protected void onPostExecute(Boolean result) { - listener.onDeleteTaskFinished(result); + protected Void performTask(Document document) { + return null; } - public interface DeleteTaskCallbacks { - void onDeleteTaskStarted(); - void onDeleteTaskFinished(boolean result); + @Override + protected int getResultCode(Response response, Void data) { + return Parcel.ResultCode.SUCCESSFUL; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java index a63f954e..3507d130 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java @@ -7,7 +7,6 @@ import java.io.IOException; import gr.thmmy.mthmmy.base.BaseApplication; import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; @@ -30,15 +29,21 @@ public abstract class NetworkTask extends ExternalAsyncTask @Override protected final Parcel doInBackground(String... input) { - Response response = sendRequest(BaseApplication.getInstance().getClient(), input); + Response response; + try { + response = sendRequest(BaseApplication.getInstance().getClient(), input); + } catch (IOException e) { + Timber.e(e, "Error connecting to thmmy.gr"); + return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); + } String responseBodyString; try { responseBodyString = response.body().string(); } catch (NullPointerException npe) { - Timber.e(npe, "Invalid response. Detatails: https://square.github.io/okhttp/3.x/okhttp/okhttp3/Response.html#body--"); + Timber.wtf(npe, "Invalid response. Detatails: https://square.github.io/okhttp/3.x/okhttp/okhttp3/Response.html#body--"); return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); } catch (IOException e) { - Timber.e(e); + Timber.e(e, "Error getting response body string"); return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); } try { @@ -62,9 +67,9 @@ public abstract class NetworkTask extends ExternalAsyncTask super.onPostExecute(tParcel); } - protected abstract Response sendRequest(OkHttpClient client, String... input); + protected abstract Response sendRequest(OkHttpClient client, String... input) throws IOException; - protected abstract T performTask(Document document) throws ParseException; + protected abstract T performTask(Document document); protected abstract int getResultCode(Response response, T data); @@ -73,6 +78,6 @@ public abstract class NetworkTask extends ExternalAsyncTask } public interface OnParseTaskFinishedListener { - void onParseFinish(int resultCOde, T data); + void onParseFinish(int resultCode, T data); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index 98449b64..c9f6ea2e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -16,7 +16,7 @@ public abstract class NewParseTask extends NetworkTask { public NewParseTask() {} @Override - protected final T performTask(Document document) throws ParseException { + protected final T performTask(Document document) { try { return parse(document); } catch (Exception e) { @@ -24,5 +24,5 @@ public abstract class NewParseTask extends NetworkTask { } } - protected abstract T parse (Document document); + protected abstract T parse (Document document) throws ParseException; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java index abda1f38..942e789b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java @@ -3,7 +3,7 @@ package gr.thmmy.mthmmy.utils.parsing; /** * ParseException is to be used for errors while parsing. */ -public class ParseException extends Exception { +public class ParseException extends RuntimeException { public ParseException() {} public ParseException(String message) diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 96cecf4a..78284b11 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -9,8 +9,8 @@ import android.preference.PreferenceManager; import java.util.ArrayList; import gr.thmmy.mthmmy.activities.settings.SettingsActivity; -import gr.thmmy.mthmmy.activities.topic.tasks.DeleteTask; import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; +import gr.thmmy.mthmmy.activities.topic.tasks.DeleteTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditResult; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; @@ -50,7 +50,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa //callbacks for topic activity private TopicTask.TopicTaskObserver topicTaskObserver; - private DeleteTask.DeleteTaskCallbacks deleteTaskCallbacks; + private DeleteTask.OnParseTaskStartedListener deleteTaskStartedListener; + private DeleteTask.OnParseTaskFinishedListener deleteTaskFinishedListener; private ReplyTask.ReplyTaskCallbacks replyFinishListener; private PrepareForEditTask.PrepareForEditCallbacks prepareForEditCallbacks; private EditTask.EditTaskCallbacks editTaskCallbacks; @@ -133,7 +134,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa public void deletePost(String postDeleteUrl) { Timber.i("Deleting post"); - new DeleteTask(deleteTaskCallbacks).execute(postDeleteUrl); + new DeleteTask(deleteTaskStartedListener, deleteTaskFinishedListener).execute(postDeleteUrl); } public void prepareForEdit(int position, String postEditURL) { @@ -313,8 +314,13 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa this.topicTaskObserver = topicTaskObserver; } - public void setDeleteTaskCallbacks(DeleteTask.DeleteTaskCallbacks deleteTaskCallbacks) { - this.deleteTaskCallbacks = deleteTaskCallbacks; + + public void setDeleteTaskStartedListener(DeleteTask.OnParseTaskStartedListener deleteTaskStartedListener) { + this.deleteTaskStartedListener = deleteTaskStartedListener; + } + + public void setDeleteTaskFinishedListener(DeleteTask.OnParseTaskFinishedListener deleteTaskFinishedListener) { + this.deleteTaskFinishedListener = deleteTaskFinishedListener; } public void setReplyFinishListener(ReplyTask.ReplyTaskCallbacks replyFinishListener) { From 5129c06cd4cf2f3d65df3d1881d82e6404ef6e21 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 12 Sep 2018 13:29:16 +0300 Subject: [PATCH 127/180] add default request in NetworkTask, refactor main activity --- .../activities/main/forum/ForumFragment.java | 89 ++++++++++--------- .../main/recent/RecentFragment.java | 70 ++++++++------- .../main/unread/UnreadFragment.java | 71 +++++++++------ .../mthmmy/utils/parsing/NetworkTask.java | 9 +- 4 files changed, 142 insertions(+), 97 deletions(-) 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 3b6366b4..f98dcd60 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 @@ -10,6 +10,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.RelativeLayout; +import android.widget.Toast; import com.bignerdranch.expandablerecyclerview.ExpandableRecyclerAdapter; @@ -17,21 +18,26 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.Board; import gr.thmmy.mthmmy.model.Category; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import gr.thmmy.mthmmy.utils.parsing.NewParseTask; +import gr.thmmy.mthmmy.utils.parsing.Parcel; import gr.thmmy.mthmmy.utils.parsing.ParseException; -import gr.thmmy.mthmmy.utils.parsing.ParseTask; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; import okhttp3.Request; +import okhttp3.Response; import timber.log.Timber; /** @@ -83,7 +89,7 @@ public class ForumFragment extends BaseFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (categories.isEmpty()) { - forumTask = new ForumTask(); + forumTask = new ForumTask(this::onForumTaskStarted, this::onForumTaskFinished); forumTask.execute(); } @@ -106,7 +112,7 @@ public class ForumFragment extends BaseFragment { if (BaseActivity.getSessionManager().isLoggedIn()) { if (forumTask.getStatus() == AsyncTask.Status.RUNNING) forumTask.cancel(true); - forumTask = new ForumTask(); + forumTask = new ForumTask(ForumFragment.this::onForumTaskStarted, ForumFragment.this::onForumTaskFinished); forumTask.setUrl(categories.get(parentPosition).getCategoryURL()); forumTask.execute(); } @@ -117,7 +123,7 @@ public class ForumFragment extends BaseFragment { if (BaseActivity.getSessionManager().isLoggedIn()) { if (forumTask.getStatus() == AsyncTask.Status.RUNNING) forumTask.cancel(true); - forumTask = new ForumTask(); + forumTask = new ForumTask(ForumFragment.this::onForumTaskStarted, ForumFragment.this::onForumTaskFinished); forumTask.setUrl(categories.get(parentPosition).getCategoryURL()); forumTask.execute(); } @@ -135,16 +141,12 @@ public class ForumFragment extends BaseFragment { swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh); swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.primary); swipeRefreshLayout.setColorSchemeResources(R.color.accent); - swipeRefreshLayout.setOnRefreshListener( - new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - if (forumTask != null && forumTask.getStatus() != AsyncTask.Status.RUNNING) { - forumTask = new ForumTask(); - forumTask.execute(SessionManager.indexUrl.toString()); - } + swipeRefreshLayout.setOnRefreshListener(() -> { + if (forumTask != null && forumTask.getStatus() != AsyncTask.Status.RUNNING) { + forumTask = new ForumTask(ForumFragment.this::onForumTaskStarted, ForumFragment.this::onForumTaskFinished); + //forumTask.execute(SessionManager.indexUrl.toString()); + forumTask.execute(); } - } ); @@ -163,33 +165,38 @@ public class ForumFragment extends BaseFragment { void onForumFragmentInteraction(Board board); } - //---------------------------------------ASYNC TASK----------------------------------- + public void onForumTaskStarted() { + progressBar.setVisibility(ProgressBar.VISIBLE); + } - private class ForumTask extends ParseTask { - private HttpUrl forumUrl = SessionManager.forumUrl; //may change upon collapse/expand + public void onForumTaskFinished(int resultCode, ArrayList fetchedCategories) { + if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + categories.clear(); + categories.addAll(fetchedCategories); + forumAdapter.notifyParentDataSetChanged(false); + } else if (resultCode == Parcel.ResultCode.NETWORK_ERROR) { + Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); + } - private final List fetchedCategories; + progressBar.setVisibility(ProgressBar.INVISIBLE); + swipeRefreshLayout.setRefreshing(false); + } - ForumTask() { - fetchedCategories = new ArrayList<>(); - } + //---------------------------------------ASYNC TASK----------------------------------- - protected void onPreExecute() { - progressBar.setVisibility(ProgressBar.VISIBLE); - } + private class ForumTask extends NewParseTask> { + private HttpUrl forumUrl = SessionManager.forumUrl; //may change upon collapse/expand - @Override - protected Request prepareRequest(String... params) { - return new Request.Builder() - .url(forumUrl) - .build(); + public ForumTask(OnParseTaskStartedListener onParseTaskStartedListener, + OnParseTaskFinishedListener> onParseTaskFinishedListener) { + super(onParseTaskStartedListener, onParseTaskFinishedListener); } - @Override - public void parse(Document document) throws ParseException { + protected ArrayList parse(Document document) throws ParseException { Elements categoryBlocks = document.select(".tborder:not([style])>table[cellpadding=5]"); if (categoryBlocks.size() != 0) { + ArrayList fetchedCategories = new ArrayList<>(); for (Element categoryBlock : categoryBlocks) { Element categoryElement = categoryBlock.select("td[colspan=2]>[name]").first(); String categoryUrl = categoryElement.attr("href"); @@ -207,24 +214,26 @@ public class ForumFragment extends BaseFragment { fetchedCategories.add(category); } - categories.clear(); - categories.addAll(fetchedCategories); - fetchedCategories.clear(); + return fetchedCategories; } else throw new ParseException("Parsing failed"); } @Override - protected void postExecution(ParseTask.ResultCode result) { - if (result == ResultCode.SUCCESS) - forumAdapter.notifyParentDataSetChanged(false); + protected Response sendRequest(OkHttpClient client, String... input) throws IOException { + Request request = new Request.Builder() + .url(forumUrl) + .build(); + return client.newCall(request).execute(); + } - progressBar.setVisibility(ProgressBar.INVISIBLE); - swipeRefreshLayout.setRefreshing(false); + @Override + protected int getResultCode(Response response, ArrayList data) { + return Parcel.ResultCode.SUCCESSFUL; } - public void setUrl(String string) //TODO delete and simplify e.g. in prepareRequest possible? - { + //TODO delete and simplify e.g. in prepareRequest possible? + public void setUrl(String string) { forumUrl = HttpUrl.parse(string); } } 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 aee35e37..31b3421d 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 @@ -10,23 +10,30 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.RelativeLayout; +import android.widget.Toast; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import gr.thmmy.mthmmy.utils.parsing.NewParseTask; +import gr.thmmy.mthmmy.utils.parsing.Parcel; import gr.thmmy.mthmmy.utils.parsing.ParseException; -import gr.thmmy.mthmmy.utils.parsing.ParseTask; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import timber.log.Timber; @@ -79,7 +86,7 @@ public class RecentFragment extends BaseFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (topicSummaries.isEmpty()) { - recentTask = new RecentTask(); + recentTask = new RecentTask(this::onRecentTaskStarted, this::onRecentTaskFinished); recentTask.execute(SessionManager.indexUrl.toString()); } @@ -109,16 +116,11 @@ public class RecentFragment extends BaseFragment { swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh); swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.primary); swipeRefreshLayout.setColorSchemeResources(R.color.accent); - swipeRefreshLayout.setOnRefreshListener( - new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - if (recentTask != null && recentTask.getStatus() != AsyncTask.Status.RUNNING) { - recentTask = new RecentTask(); - recentTask.execute(SessionManager.indexUrl.toString()); - } + swipeRefreshLayout.setOnRefreshListener(() -> { + if (recentTask != null && recentTask.getStatus() != AsyncTask.Status.RUNNING) { + recentTask = new RecentTask(this::onRecentTaskStarted, this::onRecentTaskFinished); + recentTask.execute(SessionManager.indexUrl.toString()); } - } ); } @@ -138,18 +140,34 @@ public class RecentFragment extends BaseFragment { void onRecentFragmentInteraction(TopicSummary topicSummary); } + private void onRecentTaskStarted() { + progressBar.setVisibility(ProgressBar.VISIBLE); + } + + private void onRecentTaskFinished(int resultCode, ArrayList fetchedRecent) { + if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + topicSummaries.clear(); + topicSummaries.addAll(fetchedRecent); + recentAdapter.notifyDataSetChanged(); + } else if (resultCode == Parcel.ResultCode.NETWORK_ERROR) { + Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); + } + + progressBar.setVisibility(ProgressBar.INVISIBLE); + swipeRefreshLayout.setRefreshing(false); + } + //---------------------------------------ASYNC TASK----------------------------------- - private class RecentTask extends ParseTask { - private List fetchedRecent; + private class RecentTask extends NewParseTask> { - @Override - protected void onPreExecute() { - progressBar.setVisibility(ProgressBar.VISIBLE); - fetchedRecent = new ArrayList<>(); + public RecentTask(OnParseTaskStartedListener onParseTaskStartedListener, + OnParseTaskFinishedListener> onParseTaskFinishedListener) { + super(onParseTaskStartedListener, onParseTaskFinishedListener); } @Override - public void parse(Document document) throws ParseException { + protected ArrayList parse(Document document) throws ParseException { + ArrayList fetchedRecent = new ArrayList<>(); Elements recent = document.select("#block8 :first-child div"); if (!recent.isEmpty()) { for (int i = 0; i < recent.size(); i += 3) { @@ -174,7 +192,7 @@ public class RecentFragment extends BaseFragment { dateTime.contains(" πμ") || dateTime.contains(" μμ")) { dateTime = dateTime.replaceAll(":[0-5][0-9] ", " "); } else { - dateTime=dateTime.substring(0,dateTime.lastIndexOf(":")); + dateTime = dateTime.substring(0, dateTime.lastIndexOf(":")); } if (!dateTime.contains(",")) { dateTime = dateTime.replaceAll(".+? ([0-9])", "$1"); @@ -184,22 +202,14 @@ public class RecentFragment extends BaseFragment { fetchedRecent.add(new TopicSummary(link, title, lastUser, dateTime)); } - return; + return fetchedRecent; } throw new ParseException("Parsing failed"); } @Override - protected void postExecution(ParseTask.ResultCode result) { - if (result == ResultCode.SUCCESS) - { - topicSummaries.clear(); - topicSummaries.addAll(fetchedRecent); - recentAdapter.notifyDataSetChanged(); - } - - progressBar.setVisibility(ProgressBar.INVISIBLE); - swipeRefreshLayout.setRefreshing(false); + protected int getResultCode(Response response, ArrayList data) { + return Parcel.ResultCode.SUCCESSFUL; } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index b18874d5..0c4f5417 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -22,13 +22,19 @@ import java.util.ArrayList; import java.util.List; import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import gr.thmmy.mthmmy.utils.parsing.NewParseTask; +import gr.thmmy.mthmmy.utils.parsing.Parcel; +import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.parsing.ParseTask; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; +import okhttp3.OkHttpClient; import okhttp3.Request; +import okhttp3.Response; import timber.log.Timber; /** @@ -83,7 +89,7 @@ public class UnreadFragment extends BaseFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (topicSummaries.isEmpty()) { - unreadTask = new UnreadTask(); + unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); assert SessionManager.unreadUrl != null; unreadTask.execute(SessionManager.unreadUrl.toString()); } @@ -126,7 +132,7 @@ public class UnreadFragment extends BaseFragment { topicSummaries.clear(); numberOfPages = 0; loadedPages = 0; - unreadTask = new UnreadTask(); + unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); assert SessionManager.unreadUrl != null; unreadTask.execute(SessionManager.unreadUrl.toString()); } @@ -151,13 +157,42 @@ public class UnreadFragment extends BaseFragment { } //---------------------------------------ASYNC TASK----------------------------------- - private class UnreadTask extends ParseTask { - protected void onPreExecute() { - progressBar.setVisibility(ProgressBar.VISIBLE); + + private void onUnreadTaskStarted() { + progressBar.setVisibility(ProgressBar.VISIBLE); + } + + private void onUnreadTaskFinished(int resultCode, Void data) { + if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + unreadAdapter.notifyDataSetChanged(); + + ++loadedPages; + if (loadedPages < numberOfPages) { + unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); + assert SessionManager.unreadUrl != null; + unreadTask.execute(SessionManager.unreadUrl.toString() + ";start=" + loadedPages * 20); + } + else { + progressBar.setVisibility(ProgressBar.INVISIBLE); + swipeRefreshLayout.setRefreshing(false); + } + } + else{ + progressBar.setVisibility(ProgressBar.INVISIBLE); + swipeRefreshLayout.setRefreshing(false); + if (resultCode == Parcel.ResultCode.NETWORK_ERROR) + Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); + } + } + + private class UnreadTask extends NewParseTask { + + UnreadTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { + super(onParseTaskStartedListener, onParseTaskFinishedListener); } @Override - public void parse(Document document) { + protected Void parse(Document document) throws ParseException { Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); if (!unread.isEmpty()) { //topicSummaries.clear(); @@ -217,28 +252,12 @@ public class UnreadFragment extends BaseFragment { } topicSummaries.add(new TopicSummary(null, null, null, message)); } + return null; } @Override - protected void postExecution(ParseTask.ResultCode result) { - if (result == ResultCode.SUCCESS) { - unreadAdapter.notifyDataSetChanged(); - - ++loadedPages; - if (loadedPages < numberOfPages) { - unreadTask = new UnreadTask(); - assert SessionManager.unreadUrl != null; - unreadTask.execute(SessionManager.unreadUrl.toString() + ";start=" + loadedPages * 20); - } - else { - progressBar.setVisibility(ProgressBar.INVISIBLE); - swipeRefreshLayout.setRefreshing(false); - } - } - else{ - progressBar.setVisibility(ProgressBar.INVISIBLE); - swipeRefreshLayout.setRefreshing(false); - } + protected int getResultCode(Response response, Void data) { + return Parcel.ResultCode.SUCCESSFUL; } } @@ -282,7 +301,7 @@ public class UnreadFragment extends BaseFragment { , "Fatal error!\n Task aborted...", Toast.LENGTH_LONG).show(); } else { if (unreadTask != null && unreadTask.getStatus() != AsyncTask.Status.RUNNING) { - unreadTask = new UnreadTask(); + unreadTask = new UnreadTask(UnreadFragment.this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskFinished); assert SessionManager.unreadUrl != null; unreadTask.execute(SessionManager.unreadUrl.toString()); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java index 3507d130..c638f284 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java @@ -7,6 +7,7 @@ import java.io.IOException; import gr.thmmy.mthmmy.base.BaseApplication; import okhttp3.OkHttpClient; +import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; @@ -67,7 +68,13 @@ public abstract class NetworkTask extends ExternalAsyncTask super.onPostExecute(tParcel); } - protected abstract Response sendRequest(OkHttpClient client, String... input) throws IOException; + protected Response sendRequest(OkHttpClient client, String... input) throws IOException { + String url = input[0]; + Request request = new Request.Builder() + .url(url) + .build(); + return client.newCall(request).execute(); + } protected abstract T performTask(Document document); From 0107f36d59e8fd0e67836648fe73a32b01610fe0 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 12 Sep 2018 13:36:26 +0300 Subject: [PATCH 128/180] externalize result codes, change project structure --- .../activities/main/forum/ForumFragment.java | 8 +-- .../main/recent/RecentFragment.java | 11 ++-- .../main/unread/UnreadFragment.java | 10 ++-- .../activities/topic/TopicActivity.java | 4 +- .../activities/topic/tasks/DeleteTask.java | 6 +-- .../{parsing => }/ExternalAsyncTask.java | 2 +- .../mthmmy/utils/NetworkResultCodes.java | 32 ++++++++++++ .../utils/{parsing => }/NetworkTask.java | 13 ++--- .../java/gr/thmmy/mthmmy/utils/Parcel.java | 20 ++++++++ .../mthmmy/utils/parsing/NewParseTask.java | 2 + .../gr/thmmy/mthmmy/utils/parsing/Parcel.java | 51 ------------------- 11 files changed, 79 insertions(+), 80 deletions(-) rename app/src/main/java/gr/thmmy/mthmmy/utils/{parsing => }/ExternalAsyncTask.java (98%) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/NetworkResultCodes.java rename app/src/main/java/gr/thmmy/mthmmy/utils/{parsing => }/NetworkTask.java (87%) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java delete mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java 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 f98dcd60..ceb41e13 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 @@ -30,8 +30,8 @@ import gr.thmmy.mthmmy.model.Board; import gr.thmmy.mthmmy.model.Category; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; -import gr.thmmy.mthmmy.utils.parsing.Parcel; import gr.thmmy.mthmmy.utils.parsing.ParseException; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.HttpUrl; @@ -170,11 +170,11 @@ public class ForumFragment extends BaseFragment { } public void onForumTaskFinished(int resultCode, ArrayList fetchedCategories) { - if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + if (resultCode == NetworkResultCodes.SUCCESSFUL) { categories.clear(); categories.addAll(fetchedCategories); forumAdapter.notifyParentDataSetChanged(false); - } else if (resultCode == Parcel.ResultCode.NETWORK_ERROR) { + } else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); } @@ -229,7 +229,7 @@ public class ForumFragment extends BaseFragment { @Override protected int getResultCode(Response response, ArrayList data) { - return Parcel.ResultCode.SUCCESSFUL; + return NetworkResultCodes.SUCCESSFUL; } //TODO delete and simplify e.g. in prepareRequest possible? 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 31b3421d..98ad7f69 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 @@ -15,7 +15,6 @@ import android.widget.Toast; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -27,12 +26,10 @@ import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; -import gr.thmmy.mthmmy.utils.parsing.Parcel; import gr.thmmy.mthmmy.utils.parsing.ParseException; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; -import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; @@ -145,11 +142,11 @@ public class RecentFragment extends BaseFragment { } private void onRecentTaskFinished(int resultCode, ArrayList fetchedRecent) { - if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + if (resultCode == NetworkResultCodes.SUCCESSFUL) { topicSummaries.clear(); topicSummaries.addAll(fetchedRecent); recentAdapter.notifyDataSetChanged(); - } else if (resultCode == Parcel.ResultCode.NETWORK_ERROR) { + } else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); } @@ -209,7 +206,7 @@ public class RecentFragment extends BaseFragment { @Override protected int getResultCode(Response response, ArrayList data) { - return Parcel.ResultCode.SUCCESSFUL; + return NetworkResultCodes.SUCCESSFUL; } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 0c4f5417..0681c4af 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -27,12 +27,10 @@ import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; -import gr.thmmy.mthmmy.utils.parsing.Parcel; import gr.thmmy.mthmmy.utils.parsing.ParseException; -import gr.thmmy.mthmmy.utils.parsing.ParseTask; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; -import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; @@ -163,7 +161,7 @@ public class UnreadFragment extends BaseFragment { } private void onUnreadTaskFinished(int resultCode, Void data) { - if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + if (resultCode == NetworkResultCodes.SUCCESSFUL) { unreadAdapter.notifyDataSetChanged(); ++loadedPages; @@ -180,7 +178,7 @@ public class UnreadFragment extends BaseFragment { else{ progressBar.setVisibility(ProgressBar.INVISIBLE); swipeRefreshLayout.setRefreshing(false); - if (resultCode == Parcel.ResultCode.NETWORK_ERROR) + if (resultCode == NetworkResultCodes.NETWORK_ERROR) Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); } } @@ -257,7 +255,7 @@ public class UnreadFragment extends BaseFragment { @Override protected int getResultCode(Response response, Void data) { - return Parcel.ResultCode.SUCCESSFUL; + return NetworkResultCodes.SUCCESSFUL; } } 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 7f8b248a..00e16471 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 @@ -50,7 +50,7 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; import gr.thmmy.mthmmy.utils.HTMLUtils; -import gr.thmmy.mthmmy.utils.parsing.Parcel; +import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; @@ -500,7 +500,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo viewModel.setDeleteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); viewModel.setDeleteTaskFinishedListener((resultCode, data) -> { progressBar.setVisibility(ProgressBar.GONE); - if (resultCode == Parcel.ResultCode.SUCCESSFUL) { + if (resultCode == NetworkResultCodes.SUCCESSFUL) { Timber.i("Post deleted successfully"); viewModel.reloadPage(); } else { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java index 40a2df5b..41563ae5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java @@ -4,8 +4,8 @@ import org.jsoup.nodes.Document; import java.io.IOException; -import gr.thmmy.mthmmy.utils.parsing.NetworkTask; -import gr.thmmy.mthmmy.utils.parsing.Parcel; +import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -34,6 +34,6 @@ public class DeleteTask extends NetworkTask { @Override protected int getResultCode(Response response, Void data) { - return Parcel.ResultCode.SUCCESSFUL; + return NetworkResultCodes.SUCCESSFUL; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java similarity index 98% rename from app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java index 93bc4224..82b535b6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ExternalAsyncTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils.parsing; +package gr.thmmy.mthmmy.utils; import android.os.AsyncTask; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkResultCodes.java b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkResultCodes.java new file mode 100644 index 00000000..90cd8771 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkResultCodes.java @@ -0,0 +1,32 @@ +package gr.thmmy.mthmmy.utils; + +public class NetworkResultCodes { + /** + * The request was successful + */ + public static final int SUCCESSFUL = 0; + /** + * Error 404, page was not found + */ + public static final int NOT_FOUND = 1; + /** + * User session ended while posting the reply + */ + public static final int SESSION_ENDED = 2; + /** + * Exception occured while parsing + */ + public static final int PARSE_ERROR = 3; + /** + * Other undefined of unidentified error + */ + public static final int OTHER_ERROR = 4; + /** + * Failed to connect to thmmy.gr + */ + public static final int NETWORK_ERROR = 5; + /** + * Error while excecuting NetworkTask's performTask() + */ + public static final int PERFORM_TASK_ERROR = 6; +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java similarity index 87% rename from app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java index c638f284..6793120a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils.parsing; +package gr.thmmy.mthmmy.utils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -6,6 +6,7 @@ import org.jsoup.nodes.Document; import java.io.IOException; import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.utils.parsing.ParseException; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -35,17 +36,17 @@ public abstract class NetworkTask extends ExternalAsyncTask response = sendRequest(BaseApplication.getInstance().getClient(), input); } catch (IOException e) { Timber.e(e, "Error connecting to thmmy.gr"); - return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); + return new Parcel<>(NetworkResultCodes.NETWORK_ERROR, null); } String responseBodyString; try { responseBodyString = response.body().string(); } catch (NullPointerException npe) { Timber.wtf(npe, "Invalid response. Detatails: https://square.github.io/okhttp/3.x/okhttp/okhttp3/Response.html#body--"); - return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); + return new Parcel<>(NetworkResultCodes.NETWORK_ERROR, null); } catch (IOException e) { Timber.e(e, "Error getting response body string"); - return new Parcel<>(Parcel.ResultCode.NETWORK_ERROR, null); + return new Parcel<>(NetworkResultCodes.NETWORK_ERROR, null); } try { T data = performTask(Jsoup.parse(responseBodyString)); @@ -53,10 +54,10 @@ public abstract class NetworkTask extends ExternalAsyncTask return new Parcel<>(resultCode, data); } catch (ParseException pe) { Timber.e(pe); - return new Parcel<>(Parcel.ResultCode.PARSE_ERROR, null); + return new Parcel<>(NetworkResultCodes.PARSE_ERROR, null); } catch (Exception e) { Timber.e(e); - return new Parcel<>(Parcel.ResultCode.PERFORM_TASK_ERROR, null); + return new Parcel<>(NetworkResultCodes.PERFORM_TASK_ERROR, null); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java b/app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java new file mode 100644 index 00000000..83e65285 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java @@ -0,0 +1,20 @@ +package gr.thmmy.mthmmy.utils; + +public class Parcel { + + private int resultCode; + private T data; + + public Parcel(int resultCode, T data) { + this.resultCode = resultCode; + this.data = data; + } + + public int getResultCode() { + return resultCode; + } + + public T getData() { + return data; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index c9f6ea2e..51749f2a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -2,6 +2,8 @@ package gr.thmmy.mthmmy.utils.parsing; import org.jsoup.nodes.Document; +import gr.thmmy.mthmmy.utils.NetworkTask; + public abstract class NewParseTask extends NetworkTask { public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java deleted file mode 100644 index 6e1e0f7f..00000000 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/Parcel.java +++ /dev/null @@ -1,51 +0,0 @@ -package gr.thmmy.mthmmy.utils.parsing; - -public class Parcel { - - private int resultCode; - private T data; - - public Parcel(int resultCode, T data) { - this.resultCode = resultCode; - this.data = data; - } - - public int getResultCode() { - return resultCode; - } - - public T getData() { - return data; - } - - public class ResultCode { - /** - * The request was successful - */ - public static final int SUCCESSFUL = 0; - /** - * Error 404, page was not found - */ - public static final int NOT_FOUND = 1; - /** - * User session ended while posting the reply - */ - public static final int SESSION_ENDED = 2; - /** - * Exception occured while parsing - */ - public static final int PARSE_ERROR = 3; - /** - * Other undefined of unidentified error - */ - public static final int OTHER_ERROR = 4; - /** - * Failed to connect to thmmy.gr - */ - public static final int NETWORK_ERROR = 5; - /** - * Error while excecuting NetworkTask's performTask() - */ - public static final int PERFORM_TASK_ERROR = 6; - } -} From b51cea6404d68eb4e8cb4c2521562a464cdcdc8a Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 12 Sep 2018 16:27:00 +0300 Subject: [PATCH 129/180] fix dialog theme, make subject one line --- .../main/java/gr/thmmy/mthmmy/editorview/EditorView.java | 2 +- app/src/main/res/layout/activity_create_content.xml | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index a4ccc119..9eaac429 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -201,7 +201,7 @@ public class EditorView extends LinearLayout { linkText.getEditText().setText( editText.getText().toString().substring(editText.getSelectionStart(), editText.getSelectionEnd())); } - new AlertDialog.Builder(context, R.style.AppCompatAlertDialogStyleAccent) + new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) .setTitle(R.string.dialog_create_link_title) .setView(dialogBody) .setPositiveButton(R.string.ok, (dialog, which) -> { diff --git a/app/src/main/res/layout/activity_create_content.xml b/app/src/main/res/layout/activity_create_content.xml index 04af0ea4..60028c0c 100644 --- a/app/src/main/res/layout/activity_create_content.xml +++ b/app/src/main/res/layout/activity_create_content.xml @@ -39,7 +39,11 @@ + android:layout_height="wrap_content" + android:lines="1" + android:maxLines="1" + android:ellipsize="end" + android:inputType="text"/> Date: Thu, 13 Sep 2018 15:46:44 +0300 Subject: [PATCH 130/180] do not allow line break character on subject edittexts --- .../activities/create_content/CreateContentActivity.java | 4 ++++ .../java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index 781bb9f3..b0b6a11b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -5,7 +5,9 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.design.widget.TextInputLayout; +import android.text.InputType; import android.view.View; +import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.widget.Toast; @@ -50,6 +52,8 @@ public class CreateContentActivity extends BaseActivity implements EmojiKeyboard emojiKeyboard = findViewById(R.id.emoji_keyboard); subjectInput = findViewById(R.id.subject_input); + subjectInput.getEditText().setRawInputType(InputType.TYPE_CLASS_TEXT); + subjectInput.getEditText().setImeOptions(EditorInfo.IME_ACTION_DONE); contentEditor = findViewById(R.id.main_content_editorview); setEmojiKeyboardInputConnection(contentEditor.getInputConnection()); 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 4c853526..bf9f3b52 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 @@ -16,10 +16,12 @@ import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.AlertDialog; import android.support.v7.content.res.AppCompatResources; import android.support.v7.widget.RecyclerView; +import android.text.InputType; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.webkit.WebResourceRequest; @@ -456,6 +458,8 @@ class TopicAdapter extends RecyclerView.Adapter { .into(holder.thumbnail); holder.username.setText(getSessionManager().getUsername()); holder.quickReplySubject.setText("Re: " + viewModel.getTopicTitle().getValue()); + holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); + holder.quickReplySubject.setImeOptions(EditorInfo.IME_ACTION_DONE); holder.replyEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); InputConnection ic = holder.replyEditor.getInputConnection(); @@ -505,6 +509,8 @@ class TopicAdapter extends RecyclerView.Adapter { .into(holder.thumbnail); holder.username.setText(getSessionManager().getUsername()); holder.editSubject.setText(postsList.get(position).getSubject()); + holder.editSubject.setRawInputType(InputType.TYPE_CLASS_TEXT); + holder.editSubject.setImeOptions(EditorInfo.IME_ACTION_DONE); holder.editEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); InputConnection ic = holder.editEditor.getInputConnection(); From ee8d0383489a76fac7fafac0c2bfca56af9f7e25 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 16 Sep 2018 12:56:35 +0300 Subject: [PATCH 131/180] create poll in model --- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 85 +++++++++++++++++++ .../main/java/gr/thmmy/mthmmy/model/Post.java | 2 +- .../java/gr/thmmy/mthmmy/model/TopicItem.java | 4 + 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/model/Poll.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java new file mode 100644 index 00000000..49fbba8b --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -0,0 +1,85 @@ +package gr.thmmy.mthmmy.model; + +import java.text.DecimalFormat; + +public class Poll { + private final String question; + private Entry[] entries; + private int availableVoteCount; + private String pollFormUrl, sc; + + public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc) { + this.question = question; + this.entries = entries; + this.availableVoteCount = availableVoteCount; + this.pollFormUrl = pollFormUrl; + this.sc = sc; + } + + public String getQuestion() { + return question; + } + + public Entry[] getEntries() { + return entries; + } + + public int getAvailableVoteCount() { + return availableVoteCount; + } + + public String getPollFormUrl() { + return pollFormUrl; + } + + public String getSc() { + return sc; + } + + public int totalVotes() { + int sum = 0; + for (Entry entry : entries) { + sum += entry.votes; + } + return sum; + } + + public String getVotePercentage(int index) { + DecimalFormat format = new DecimalFormat(".#"); + double percentage = 100 * ((double) entries[index].votes / (double) totalVotes()); + return format.format(percentage); + } + + static class Entry { + private final String entryName; + private int votes; + + public Entry(String entryName, int votes) { + this.entryName = entryName; + this.votes = votes; + } + + /** + * Constructor for entry with unknown number of votes + * + * @param entryName + * The name of the entry + */ + public Entry(String entryName) { + this.entryName = entryName; + votes = -1; + } + + public String getEntryName() { + return entryName; + } + + public int getVotes() { + return votes; + } + + public void setVotes(int votes) { + this.votes = votes; + } + } +} 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 078386dc..1113ffbc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Post.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Post.java @@ -15,7 +15,7 @@ import java.util.Objects; * gender, number of posts, personal text and number of start to be described in addition to * previous fields.

*/ -public class Post { +public class Post extends TopicItem { public static final int TYPE_POST = 0; public static final int TYPE_QUICK_REPLY = 1; public static final int TYPE_EDIT = 2; diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java new file mode 100644 index 00000000..9d38a85e --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java @@ -0,0 +1,4 @@ +package gr.thmmy.mthmmy.model; + +public class TopicItem { +} From 290daf8eab592a6a1b68ca18dbfa9545b47b27f2 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 16 Sep 2018 13:02:45 +0300 Subject: [PATCH 132/180] add remove vote url --- app/src/main/java/gr/thmmy/mthmmy/model/Poll.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 49fbba8b..1b8e07a7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -6,14 +6,16 @@ public class Poll { private final String question; private Entry[] entries; private int availableVoteCount; - private String pollFormUrl, sc; + private String pollFormUrl, sc, removeVoteUrl; - public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc) { + public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc, + String removeVoteUrl) { this.question = question; this.entries = entries; this.availableVoteCount = availableVoteCount; this.pollFormUrl = pollFormUrl; this.sc = sc; + this.removeVoteUrl = removeVoteUrl; } public String getQuestion() { @@ -36,6 +38,10 @@ public class Poll { return sc; } + public String getRemoveVoteUrl() { + return removeVoteUrl; + } + public int totalVotes() { int sum = 0; for (Entry entry : entries) { From 7db9c43fd855d83b24a325c261581e77dac1edc8 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 18 Sep 2018 22:41:35 +0300 Subject: [PATCH 133/180] generify posts list to topic items --- .../activities/topic/TopicActivity.java | 38 +- .../mthmmy/activities/topic/TopicAdapter.java | 779 +++++++++--------- .../mthmmy/activities/topic/TopicParser.java | 5 +- .../activities/topic/tasks/TopicTask.java | 5 +- .../topic/tasks/TopicTaskResult.java | 7 +- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 4 +- .../java/gr/thmmy/mthmmy/model/TopicItem.java | 3 +- .../mthmmy/viewmodel/TopicViewModel.java | 13 +- 8 files changed, 434 insertions(+), 420 deletions(-) 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 953f7ad8..92154320 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 @@ -12,7 +12,6 @@ import android.os.Bundle; import android.os.Handler; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; -import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatDelegate; @@ -50,6 +49,7 @@ import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; @@ -85,7 +85,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo /** * Holds a list of this topic's posts */ - private ArrayList postsList; + private ArrayList topicItems; //Reply related private FloatingActionButton replyFAB; //Topic's pages related @@ -170,7 +170,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo progressBar = findViewById(R.id.progressBar); emojiKeyboard = findViewById(R.id.emoji_keyboard); - postsList = new ArrayList<>(); + topicItems = new ArrayList<>(); recyclerView = findViewById(R.id.topic_recycler_view); recyclerView.setHasFixedSize(true); @@ -179,7 +179,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo getApplicationContext(), topicPageUrl); recyclerView.setLayoutManager(layoutManager); - topicAdapter = new TopicAdapter(this, postsList); + topicAdapter = new TopicAdapter(this, topicItems); recyclerView.setAdapter(topicAdapter); replyFAB = findViewById(R.id.topic_fab); @@ -280,15 +280,15 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } return; } else if (viewModel.isWritingReply()) { - postsList.remove(postsList.size() - 1); - topicAdapter.notifyItemRemoved(postsList.size()); + topicItems.remove(topicItems.size() - 1); + topicAdapter.notifyItemRemoved(topicItems.size()); topicAdapter.setBackButtonHidden(); viewModel.setWritingReply(false); replyFAB.show(); bottomNavBar.setVisibility(View.VISIBLE); return; } else if (viewModel.isEditingPost()) { - postsList.get(viewModel.getPostBeingEditedPosition()).setPostType(Post.TYPE_POST); + ((Post) topicItems.get(viewModel.getPostBeingEditedPosition())).setPostType(Post.TYPE_POST); topicAdapter.notifyItemChanged(viewModel.getPostBeingEditedPosition()); topicAdapter.setBackButtonHidden(); viewModel.setEditingPost(false); @@ -538,7 +538,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo replyFAB.show(); bottomNavBar.setVisibility(View.VISIBLE); viewModel.setWritingReply(false); - if ((postsList.get(postsList.size() - 1).getPostNumber() + 1) % 15 == 0) { + if ((((Post) topicItems.get(topicItems.size() - 1)).getPostNumber() + 1) % 15 == 0) { Timber.i("Reply was posted in new page. Switching to last page."); viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + "." + 2147483647); } else { @@ -547,8 +547,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } else { Timber.w("Post reply unsuccessful"); Toast.makeText(getBaseContext(), "Post failed!", Toast.LENGTH_SHORT).show(); - recyclerView.getChildAt(postsList.size() - 1).setAlpha(1); - recyclerView.getChildAt(postsList.size() - 1).setEnabled(true); + recyclerView.getChildAt(topicItems.size() - 1).setAlpha(1); + recyclerView.getChildAt(topicItems.size() - 1).setEnabled(true); } } }); @@ -581,7 +581,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo if (result) { Timber.i("Post edit successful"); - postsList.get(position).setPostType(Post.TYPE_POST); + ((Post) topicItems.get(position)).setPostType(Post.TYPE_POST); topicAdapter.notifyItemChanged(position); replyFAB.show(); bottomNavBar.setVisibility(View.VISIBLE); @@ -631,11 +631,11 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo else replyFAB.show(); }); - viewModel.getPostsList().observe(this, postList -> { + viewModel.getTopicItems().observe(this, postList -> { if (postList == null) progressBar.setVisibility(ProgressBar.VISIBLE); recyclerView.getRecycledViewPool().clear(); //Avoid inconsistency detected bug - postsList.clear(); - postsList.addAll(postList); + topicItems.clear(); + topicItems.addAll(postList); topicAdapter.notifyDataSetChanged(); }); /*viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> { @@ -652,7 +652,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo break; case NETWORK_ERROR: Timber.w("Network error on loaded page"); - if (viewModel.getPostsList().getValue() == null) { + if (viewModel.getTopicItems().getValue() == null) { // no page has been loaded yet. Give user the ability to refresh recyclerView.setVisibility(View.GONE); TextView errorTextview = findViewById(R.id.error_textview); @@ -710,9 +710,9 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo Timber.i("Prepare for reply successful"); //prepare for a reply viewModel.setWritingReply(true); - postsList.add(Post.newQuickReply()); - topicAdapter.notifyItemInserted(postsList.size()); - recyclerView.scrollToPosition(postsList.size() - 1); + topicItems.add(Post.newQuickReply()); + topicAdapter.notifyItemInserted(topicItems.size()); + recyclerView.scrollToPosition(topicItems.size() - 1); replyFAB.hide(); bottomNavBar.setVisibility(View.GONE); } else { @@ -725,7 +725,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo if (result != null && result.isSuccessful()) { Timber.i("Prepare for edit successful"); viewModel.setEditingPost(true); - postsList.get(result.getPosition()).setPostType(Post.TYPE_EDIT); + ((Post) topicItems.get(result.getPosition())).setPostType(Post.TYPE_EDIT); topicAdapter.notifyItemChanged(result.getPosition()); recyclerView.scrollToPosition(result.getPosition()); replyFAB.hide(); 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 bf9f3b52..509c13c1 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 @@ -46,9 +46,11 @@ import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.editorview.EditorView; import gr.thmmy.mthmmy.editorview.EmojiKeyboard; +import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyPage; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CircleTransform; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; @@ -76,16 +78,16 @@ class TopicAdapter extends RecyclerView.Adapter { private final Context context; private final OnPostFocusChangeListener postFocusListener; private final EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner; - private final List postsList; + private final List topicItems; private TopicViewModel viewModel; /** * @param context the context of the {@link RecyclerView} - * @param postsList List of {@link Post} objects to use + * @param topicItems List of {@link Post} objects to use */ - TopicAdapter(TopicActivity context, List postsList) { + TopicAdapter(TopicActivity context, List topicItems) { this.context = context; - this.postsList = postsList; + this.topicItems = topicItems; this.postFocusListener = context; this.emojiKeyboardOwner = context; @@ -96,7 +98,8 @@ class TopicAdapter extends RecyclerView.Adapter { @Override public int getItemViewType(int position) { - return postsList.get(position).getPostType(); + if (topicItems.get(position) instanceof Poll) return Poll.TYPE_POLL; + return ((Post) topicItems.get(position)).getPostType(); } @NonNull @@ -141,414 +144,418 @@ class TopicAdapter extends RecyclerView.Adapter { @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder currentHolder, final int position) { - if (currentHolder instanceof PostViewHolder) { - final Post currentPost = postsList.get(position); - final PostViewHolder holder = (PostViewHolder) currentHolder; - - //Post's WebView parameters - holder.post.setClickable(true); - holder.post.setWebViewClient(new LinkLauncher()); - - //Avoids errors about layout having 0 width/height - holder.thumbnail.setMinimumWidth(1); - holder.thumbnail.setMinimumHeight(1); - //Sets thumbnail size - holder.thumbnail.setMaxWidth(THUMBNAIL_SIZE); - holder.thumbnail.setMaxHeight(THUMBNAIL_SIZE); - - //noinspection ConstantConditions - Picasso.with(context) - .load(currentPost.getThumbnailURL()) - .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) - .centerCrop() - .error(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .placeholder(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .transform(new CircleTransform()) - .into(holder.thumbnail); - - //Sets username,submit date, index number, subject, post's and attached files texts - holder.username.setText(currentPost.getAuthor()); - holder.postDate.setText(currentPost.getPostDate()); - if (currentPost.getPostNumber() != 0) - holder.postNum.setText(context.getString( - R.string.user_number_of_posts, currentPost.getPostNumber())); - else - holder.postNum.setText(""); - holder.subject.setText(currentPost.getSubject()); - holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null); - if ((currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) - || (currentPost.getLastEdit() != null)) { - holder.bodyFooterDivider.setVisibility(View.VISIBLE); - holder.postFooter.removeAllViews(); - - if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { - int filesTextColor; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - filesTextColor = context.getResources().getColor(R.color.accent, null); - } else //noinspection deprecation - filesTextColor = context.getResources().getColor(R.color.accent); - - for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) { - final TextView attached = new TextView(context); - attached.setTextSize(10f); - attached.setClickable(true); - attached.setTypeface(Typeface.createFromAsset(context.getAssets() - , "fonts/fontawesome-webfont.ttf")); - attached.setText(faIconFromFilename(attachedFile.getFilename()) + " " - + attachedFile.getFilename() + attachedFile.getFileInfo()); - attached.setTextColor(filesTextColor); - attached.setPadding(0, 3, 0, 3); - - attached.setOnClickListener(view -> ((BaseActivity) context).downloadFile(attachedFile)); - - holder.postFooter.addView(attached); + if (currentHolder.getItemViewType() == Poll.TYPE_POLL) { + + } else { + Post currentPost = (Post) topicItems.get(position); + if (currentHolder instanceof PostViewHolder) { + final PostViewHolder holder = (PostViewHolder) currentHolder; + + //Post's WebView parameters + holder.post.setClickable(true); + holder.post.setWebViewClient(new LinkLauncher()); + + //Avoids errors about layout having 0 width/height + holder.thumbnail.setMinimumWidth(1); + holder.thumbnail.setMinimumHeight(1); + //Sets thumbnail size + holder.thumbnail.setMaxWidth(THUMBNAIL_SIZE); + holder.thumbnail.setMaxHeight(THUMBNAIL_SIZE); + + //noinspection ConstantConditions + Picasso.with(context) + .load(currentPost.getThumbnailURL()) + .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) + .centerCrop() + .error(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .placeholder(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .transform(new CircleTransform()) + .into(holder.thumbnail); + + //Sets username,submit date, index number, subject, post's and attached files texts + holder.username.setText(currentPost.getAuthor()); + holder.postDate.setText(currentPost.getPostDate()); + if (currentPost.getPostNumber() != 0) + holder.postNum.setText(context.getString( + R.string.user_number_of_posts, currentPost.getPostNumber())); + else + holder.postNum.setText(""); + holder.subject.setText(currentPost.getSubject()); + holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null); + if ((currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) + || (currentPost.getLastEdit() != null)) { + holder.bodyFooterDivider.setVisibility(View.VISIBLE); + holder.postFooter.removeAllViews(); + + if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { + int filesTextColor; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + filesTextColor = context.getResources().getColor(R.color.accent, null); + } else //noinspection deprecation + filesTextColor = context.getResources().getColor(R.color.accent); + + for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) { + final TextView attached = new TextView(context); + attached.setTextSize(10f); + attached.setClickable(true); + attached.setTypeface(Typeface.createFromAsset(context.getAssets() + , "fonts/fontawesome-webfont.ttf")); + attached.setText(faIconFromFilename(attachedFile.getFilename()) + " " + + attachedFile.getFilename() + attachedFile.getFileInfo()); + attached.setTextColor(filesTextColor); + attached.setPadding(0, 3, 0, 3); + + attached.setOnClickListener(view -> ((BaseActivity) context).downloadFile(attachedFile)); + + holder.postFooter.addView(attached); + } } + if (currentPost.getLastEdit() != null && currentPost.getLastEdit().length() > 0) { + int lastEditTextColor; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + lastEditTextColor = context.getResources().getColor(R.color.white, null); + } else //noinspection deprecation + lastEditTextColor = context.getResources().getColor(R.color.white); + + final TextView lastEdit = new TextView(context); + lastEdit.setTextSize(12f); + lastEdit.setText(currentPost.getLastEdit()); + lastEdit.setTextColor(lastEditTextColor); + lastEdit.setPadding(0, 3, 0, 3); + holder.postFooter.addView(lastEdit); + } + } else { + holder.bodyFooterDivider.setVisibility(View.GONE); + holder.postFooter.removeAllViews(); } - if (currentPost.getLastEdit() != null && currentPost.getLastEdit().length() > 0) { - int lastEditTextColor; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - lastEditTextColor = context.getResources().getColor(R.color.white, null); - } else //noinspection deprecation - lastEditTextColor = context.getResources().getColor(R.color.white); - - final TextView lastEdit = new TextView(context); - lastEdit.setTextSize(12f); - lastEdit.setText(currentPost.getLastEdit()); - lastEdit.setTextColor(lastEditTextColor); - lastEdit.setPadding(0, 3, 0, 3); - holder.postFooter.addView(lastEdit); - } - } else { - holder.bodyFooterDivider.setVisibility(View.GONE); - holder.postFooter.removeAllViews(); - } - String mSpecialRank, mRank, mGender, mNumberOfPosts, mPersonalText; - int mNumberOfStars, mUserColor; - - if (!currentPost.isDeleted()) { //Sets user's extra info - mSpecialRank = currentPost.getSpecialRank(); - mRank = currentPost.getRank(); - mGender = currentPost.getGender(); - mNumberOfPosts = currentPost.getNumberOfPosts(); - mPersonalText = currentPost.getPersonalText(); - mNumberOfStars = currentPost.getNumberOfStars(); - } else { - mSpecialRank = null; - mRank = null; - mGender = null; - mNumberOfPosts = null; - mPersonalText = null; - mNumberOfStars = 0; - } - 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 (mUserColor != USER_COLOR_YELLOW) { - holder.username.setTextColor(mUserColor); - } else { - holder.username.setTextColor(USER_COLOR_WHITE); - } - if (mNumberOfStars > 0) { - holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets() - , "fonts/fontawesome-webfont.ttf")); - - String aStar = context.getResources().getString(R.string.fa_icon_star); - StringBuilder usersStars = new StringBuilder(); - for (int i = 0; i < mNumberOfStars; ++i) { - usersStars.append(aStar); - } - holder.stars.setText(usersStars.toString()); - holder.stars.setTextColor(mUserColor); - holder.stars.setVisibility(View.VISIBLE); - } else - holder.stars.setVisibility(View.GONE); - - if (currentPost.isUserMentionedInPost()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - holder.cardChildLinear.setBackground(context.getResources(). - getDrawable(R.drawable.mention_card, null)); - } else //noinspection deprecation - holder.cardChildLinear.setBackground(context.getResources(). - getDrawable(R.drawable.mention_card)); - } else if (mUserColor == TopicParser.USER_COLOR_PINK) { - //Special card for special member of the month! - 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() && viewModel.isUserExtraInfoVisible(holder.getAdapterPosition())) { - holder.userExtraInfo.setVisibility(View.VISIBLE); - holder.userExtraInfo.setAlpha(1.0f); - - holder.username.setMaxLines(Integer.MAX_VALUE); - holder.username.setEllipsize(null); - - holder.subject.setTextColor(Color.parseColor("#FFFFFF")); - holder.subject.setMaxLines(Integer.MAX_VALUE); - holder.subject.setEllipsize(null); - } else { - holder.userExtraInfo.setVisibility(View.GONE); - holder.userExtraInfo.setAlpha(0.0f); - - holder.username.setMaxLines(1); - holder.username.setEllipsize(TextUtils.TruncateAt.END); - - holder.subject.setTextColor(Color.parseColor("#757575")); - holder.subject.setMaxLines(1); - holder.subject.setEllipsize(TextUtils.TruncateAt.END); - } - if (!currentPost.isDeleted()) { - //Sets graphics behavior - holder.thumbnail.setOnClickListener(view -> { - //Clicking the thumbnail opens user's profile - Intent intent = new Intent(context, ProfileActivity.class); - Bundle extras = new Bundle(); - extras.putString(BUNDLE_PROFILE_URL, currentPost.getProfileURL()); - if (currentPost.getThumbnailURL() == null) - extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); - else - 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); - }); - holder.header.setOnClickListener(v -> { - //Clicking the header makes it expand/collapse - viewModel.toggleUserInfo(holder.getAdapterPosition()); - TopicAnimations.animateUserExtraInfoVisibility(holder.username, - holder.subject, Color.parseColor("#FFFFFF"), - Color.parseColor("#757575"), holder.userExtraInfo); - }); - //Clicking the expanded part of a header (the extra info) makes it collapse - holder.userExtraInfo.setOnClickListener(v -> { - viewModel.hideUserInfo(holder.getAdapterPosition()); - TopicAnimations.animateUserExtraInfoVisibility(holder.username, - holder.subject, Color.parseColor("#FFFFFF"), - Color.parseColor("#757575"), (LinearLayout) v); - }); - } else { - holder.header.setOnClickListener(null); - holder.userExtraInfo.setOnClickListener(null); - } + String mSpecialRank, mRank, mGender, mNumberOfPosts, mPersonalText; + int mNumberOfStars, mUserColor; - holder.overflowButton.setOnClickListener(view -> { - //Inflates the popup menu content - LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - if (layoutInflater == null) { - return; + if (!currentPost.isDeleted()) { //Sets user's extra info + mSpecialRank = currentPost.getSpecialRank(); + mRank = currentPost.getRank(); + mGender = currentPost.getGender(); + mNumberOfPosts = currentPost.getNumberOfPosts(); + mPersonalText = currentPost.getPersonalText(); + mNumberOfStars = currentPost.getNumberOfStars(); + } else { + mSpecialRank = null; + mRank = null; + mGender = null; + mNumberOfPosts = null; + mPersonalText = null; + mNumberOfStars = 0; } - View popUpContent = layoutInflater.inflate(R.layout.activity_topic_overflow_menu, null); - - //Creates the PopupWindow - final PopupWindow popUp = new PopupWindow(holder.overflowButton.getContext()); - popUp.setContentView(popUpContent); - popUp.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT); - popUp.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT); - popUp.setFocusable(true); - - TextView shareButton = popUpContent.findViewById(R.id.post_share_button); - Drawable shareStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_share_white_24dp); - shareButton.setCompoundDrawablesRelativeWithIntrinsicBounds(shareStartDrawable, null, null, null); - shareButton.setOnClickListener(v -> { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.setType("text/plain"); - sendIntent.putExtra(Intent.EXTRA_TEXT, currentPost.getPostURL()); - context.startActivity(Intent.createChooser(sendIntent, "Share via")); - popUp.dismiss(); - }); + 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 (mUserColor != USER_COLOR_YELLOW) { + holder.username.setTextColor(mUserColor); + } else { + holder.username.setTextColor(USER_COLOR_WHITE); + } + if (mNumberOfStars > 0) { + holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets() + , "fonts/fontawesome-webfont.ttf")); + + String aStar = context.getResources().getString(R.string.fa_icon_star); + StringBuilder usersStars = new StringBuilder(); + for (int i = 0; i < mNumberOfStars; ++i) { + usersStars.append(aStar); + } + holder.stars.setText(usersStars.toString()); + holder.stars.setTextColor(mUserColor); + holder.stars.setVisibility(View.VISIBLE); + } else + holder.stars.setVisibility(View.GONE); + + if (currentPost.isUserMentionedInPost()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + holder.cardChildLinear.setBackground(context.getResources(). + getDrawable(R.drawable.mention_card, null)); + } else //noinspection deprecation + holder.cardChildLinear.setBackground(context.getResources(). + getDrawable(R.drawable.mention_card)); + } else if (mUserColor == TopicParser.USER_COLOR_PINK) { + //Special card for special member of the month! + 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); - final TextView editPostButton = popUpContent.findViewById(R.id.edit_post); - Drawable editStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_edit_white_24dp); - editPostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(editStartDrawable, null, null, null); + //Avoid's view's visibility recycling + if (!currentPost.isDeleted() && viewModel.isUserExtraInfoVisible(holder.getAdapterPosition())) { + holder.userExtraInfo.setVisibility(View.VISIBLE); + holder.userExtraInfo.setAlpha(1.0f); - if (viewModel.isEditingPost() || currentPost.getPostEditURL() == null || currentPost.getPostEditURL().equals("")) { - editPostButton.setVisibility(View.GONE); + holder.username.setMaxLines(Integer.MAX_VALUE); + holder.username.setEllipsize(null); + + holder.subject.setTextColor(Color.parseColor("#FFFFFF")); + holder.subject.setMaxLines(Integer.MAX_VALUE); + holder.subject.setEllipsize(null); } else { - editPostButton.setOnClickListener(v -> { - viewModel.prepareForEdit(position, postsList.get(position).getPostEditURL()); - popUp.dismiss(); - }); - } + holder.userExtraInfo.setVisibility(View.GONE); + holder.userExtraInfo.setAlpha(0.0f); - TextView deletePostButton = popUpContent.findViewById(R.id.delete_post); + holder.username.setMaxLines(1); + holder.username.setEllipsize(TextUtils.TruncateAt.END); - if (currentPost.getPostDeleteURL() == null || currentPost.getPostDeleteURL().equals("")) { - deletePostButton.setVisibility(View.GONE); + holder.subject.setTextColor(Color.parseColor("#757575")); + holder.subject.setMaxLines(1); + holder.subject.setEllipsize(TextUtils.TruncateAt.END); + } + if (!currentPost.isDeleted()) { + //Sets graphics behavior + holder.thumbnail.setOnClickListener(view -> { + //Clicking the thumbnail opens user's profile + Intent intent = new Intent(context, ProfileActivity.class); + Bundle extras = new Bundle(); + extras.putString(BUNDLE_PROFILE_URL, currentPost.getProfileURL()); + if (currentPost.getThumbnailURL() == null) + extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); + else + 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); + }); + holder.header.setOnClickListener(v -> { + //Clicking the header makes it expand/collapse + viewModel.toggleUserInfo(holder.getAdapterPosition()); + TopicAnimations.animateUserExtraInfoVisibility(holder.username, + holder.subject, Color.parseColor("#FFFFFF"), + Color.parseColor("#757575"), holder.userExtraInfo); + }); + //Clicking the expanded part of a header (the extra info) makes it collapse + holder.userExtraInfo.setOnClickListener(v -> { + viewModel.hideUserInfo(holder.getAdapterPosition()); + TopicAnimations.animateUserExtraInfoVisibility(holder.username, + holder.subject, Color.parseColor("#FFFFFF"), + Color.parseColor("#757575"), (LinearLayout) v); + }); } else { - Drawable deleteStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_delete_white_24dp); - deletePostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(deleteStartDrawable, null, null, null); - popUpContent.findViewById(R.id.delete_post).setOnClickListener(v -> { - new AlertDialog.Builder(holder.overflowButton.getContext()) - .setTitle("Delete post") - .setMessage("Do you really want to delete this post?") - .setIcon(android.R.drawable.ic_dialog_alert) - .setPositiveButton(android.R.string.yes, (dialog, whichButton) -> viewModel.deletePost(currentPost.getPostDeleteURL())) - .setNegativeButton(android.R.string.no, null).show(); + holder.header.setOnClickListener(null); + holder.userExtraInfo.setOnClickListener(null); + } + + holder.overflowButton.setOnClickListener(view -> { + //Inflates the popup menu content + LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + if (layoutInflater == null) { + return; + } + View popUpContent = layoutInflater.inflate(R.layout.activity_topic_overflow_menu, null); + + //Creates the PopupWindow + final PopupWindow popUp = new PopupWindow(holder.overflowButton.getContext()); + popUp.setContentView(popUpContent); + popUp.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT); + popUp.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT); + popUp.setFocusable(true); + + TextView shareButton = popUpContent.findViewById(R.id.post_share_button); + Drawable shareStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_share_white_24dp); + shareButton.setCompoundDrawablesRelativeWithIntrinsicBounds(shareStartDrawable, null, null, null); + shareButton.setOnClickListener(v -> { + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.setType("text/plain"); + sendIntent.putExtra(Intent.EXTRA_TEXT, currentPost.getPostURL()); + context.startActivity(Intent.createChooser(sendIntent, "Share via")); popUp.dismiss(); }); - } - //Displays the popup - popUp.showAsDropDown(holder.overflowButton); - }); + final TextView editPostButton = popUpContent.findViewById(R.id.edit_post); + Drawable editStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_edit_white_24dp); + editPostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(editStartDrawable, null, null, null); + + if (viewModel.isEditingPost() || currentPost.getPostEditURL() == null || currentPost.getPostEditURL().equals("")) { + editPostButton.setVisibility(View.GONE); + } else { + editPostButton.setOnClickListener(v -> { + viewModel.prepareForEdit(position, currentPost.getPostEditURL()); + popUp.dismiss(); + }); + } - //noinspection PointlessBooleanExpression,ConstantConditions - if (!BaseActivity.getSessionManager().isLoggedIn() || !viewModel.canReply()) { - holder.quoteToggle.setVisibility(View.GONE); - } else { - if (viewModel.getToQuoteList().contains(currentPost.getPostIndex())) - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked_accent_24dp); - else - holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp); - //Sets graphics behavior - holder.quoteToggle.setOnClickListener(view -> { - viewModel.postIndexToggle(currentPost.getPostIndex()); + TextView deletePostButton = popUpContent.findViewById(R.id.delete_post); + + if (currentPost.getPostDeleteURL() == null || currentPost.getPostDeleteURL().equals("")) { + deletePostButton.setVisibility(View.GONE); + } else { + Drawable deleteStartDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_delete_white_24dp); + deletePostButton.setCompoundDrawablesRelativeWithIntrinsicBounds(deleteStartDrawable, null, null, null); + popUpContent.findViewById(R.id.delete_post).setOnClickListener(v -> { + new AlertDialog.Builder(holder.overflowButton.getContext()) + .setTitle("Delete post") + .setMessage("Do you really want to delete this post?") + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(android.R.string.yes, (dialog, whichButton) -> viewModel.deletePost(currentPost.getPostDeleteURL())) + .setNegativeButton(android.R.string.no, null).show(); + popUp.dismiss(); + }); + } + + //Displays the popup + popUp.showAsDropDown(holder.overflowButton); + }); + + //noinspection PointlessBooleanExpression,ConstantConditions + if (!BaseActivity.getSessionManager().isLoggedIn() || !viewModel.canReply()) { + holder.quoteToggle.setVisibility(View.GONE); + } else { if (viewModel.getToQuoteList().contains(currentPost.getPostIndex())) holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked_accent_24dp); else holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp); - }); - } - } else if (currentHolder instanceof QuickReplyViewHolder) { - final QuickReplyViewHolder holder = (QuickReplyViewHolder) currentHolder; - - //noinspection ConstantConditions - Picasso.with(context) - .load(getSessionManager().getAvatarLink()) - .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) - .centerCrop() - .error(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .placeholder(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .transform(new CircleTransform()) - .into(holder.thumbnail); - holder.username.setText(getSessionManager().getUsername()); - holder.quickReplySubject.setText("Re: " + viewModel.getTopicTitle().getValue()); - holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); - holder.quickReplySubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - - holder.replyEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.replyEditor.updateEmojiKeyboardVisibility(); - holder.replyEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - InputConnection ic12 = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic12); - holder.replyEditor.updateEmojiKeyboardVisibility(); - }); - - holder.replyEditor.setText(viewModel.getBuildedQuotes()); - holder.replyEditor.setOnSubmitListener(view -> { - if (holder.quickReplySubject.getText().toString().isEmpty()) return; - if (holder.replyEditor.getText().toString().isEmpty()) { - holder.replyEditor.setError("Required"); - return; - } - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - holder.itemView.setAlpha(0.5f); - holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); - - viewModel.postReply(context, holder.quickReplySubject.getText().toString(), - holder.replyEditor.getText().toString()); - }); - holder.replyEditor.setOnClickListener(view -> holder.replyEditor.setError(null)); - - if (backPressHidden) { - holder.replyEditor.requestFocus(); - backPressHidden = false; - } - } else if (currentHolder instanceof EditMessageViewHolder) { - final EditMessageViewHolder holder = (EditMessageViewHolder) currentHolder; - - //noinspection ConstantConditions - Picasso.with(context) - .load(getSessionManager().getAvatarLink()) - .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) - .centerCrop() - .error(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .placeholder(ResourcesCompat.getDrawable(context.getResources() - , R.drawable.ic_default_user_thumbnail_white_24dp, null)) - .transform(new CircleTransform()) - .into(holder.thumbnail); - holder.username.setText(getSessionManager().getUsername()); - holder.editSubject.setText(postsList.get(position).getSubject()); - holder.editSubject.setRawInputType(InputType.TYPE_CLASS_TEXT); - holder.editSubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - - holder.editEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.editEditor.updateEmojiKeyboardVisibility(); - holder.editEditor.setText(viewModel.getPostBeingEditedText()); - holder.editEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - if (hasFocus) { - InputConnection ic1 = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic1); - holder.editEditor.updateEmojiKeyboardVisibility(); + //Sets graphics behavior + holder.quoteToggle.setOnClickListener(view -> { + viewModel.postIndexToggle(currentPost.getPostIndex()); + if (viewModel.getToQuoteList().contains(currentPost.getPostIndex())) + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_checked_accent_24dp); + else + holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp); + }); } - }); - holder.editEditor.setOnSubmitListener(view -> { - if (holder.editSubject.getText().toString().isEmpty()) return; - if (holder.editEditor.getText().toString().isEmpty()) { - holder.editEditor.setError("Required"); - return; + } else if (currentHolder instanceof QuickReplyViewHolder) { + final QuickReplyViewHolder holder = (QuickReplyViewHolder) currentHolder; + + //noinspection ConstantConditions + Picasso.with(context) + .load(getSessionManager().getAvatarLink()) + .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) + .centerCrop() + .error(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .placeholder(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .transform(new CircleTransform()) + .into(holder.thumbnail); + holder.username.setText(getSessionManager().getUsername()); + holder.quickReplySubject.setText("Re: " + viewModel.getTopicTitle().getValue()); + holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); + holder.quickReplySubject.setImeOptions(EditorInfo.IME_ACTION_DONE); + + holder.replyEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); + InputConnection ic = holder.replyEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); + holder.replyEditor.updateEmojiKeyboardVisibility(); + holder.replyEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { + InputConnection ic12 = holder.replyEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic12); + holder.replyEditor.updateEmojiKeyboardVisibility(); + }); + + holder.replyEditor.setText(viewModel.getBuildedQuotes()); + holder.replyEditor.setOnSubmitListener(view -> { + if (holder.quickReplySubject.getText().toString().isEmpty()) return; + if (holder.replyEditor.getText().toString().isEmpty()) { + holder.replyEditor.setError("Required"); + return; + } + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + holder.itemView.setAlpha(0.5f); + holder.itemView.setEnabled(false); + emojiKeyboardOwner.setEmojiKeyboardVisible(false); + + viewModel.postReply(context, holder.quickReplySubject.getText().toString(), + holder.replyEditor.getText().toString()); + }); + holder.replyEditor.setOnClickListener(view -> holder.replyEditor.setError(null)); + + if (backPressHidden) { + holder.replyEditor.requestFocus(); + backPressHidden = false; } - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - holder.itemView.setAlpha(0.5f); - holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); + } else if (currentHolder instanceof EditMessageViewHolder) { + final EditMessageViewHolder holder = (EditMessageViewHolder) currentHolder; + + //noinspection ConstantConditions + Picasso.with(context) + .load(getSessionManager().getAvatarLink()) + .resize(THUMBNAIL_SIZE, THUMBNAIL_SIZE) + .centerCrop() + .error(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .placeholder(ResourcesCompat.getDrawable(context.getResources() + , R.drawable.ic_default_user_thumbnail_white_24dp, null)) + .transform(new CircleTransform()) + .into(holder.thumbnail); + holder.username.setText(getSessionManager().getUsername()); + holder.editSubject.setText(currentPost.getSubject()); + holder.editSubject.setRawInputType(InputType.TYPE_CLASS_TEXT); + holder.editSubject.setImeOptions(EditorInfo.IME_ACTION_DONE); + + holder.editEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); + InputConnection ic = holder.editEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); + holder.editEditor.updateEmojiKeyboardVisibility(); + holder.editEditor.setText(viewModel.getPostBeingEditedText()); + holder.editEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { + if (hasFocus) { + InputConnection ic1 = holder.editEditor.getInputConnection(); + emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic1); + holder.editEditor.updateEmojiKeyboardVisibility(); + } + }); + holder.editEditor.setOnSubmitListener(view -> { + if (holder.editSubject.getText().toString().isEmpty()) return; + if (holder.editEditor.getText().toString().isEmpty()) { + holder.editEditor.setError("Required"); + return; + } + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + holder.itemView.setAlpha(0.5f); + holder.itemView.setEnabled(false); + emojiKeyboardOwner.setEmojiKeyboardVisible(false); - viewModel.editPost(position, holder.editSubject.getText().toString(), holder.editEditor.getText().toString()); - }); + viewModel.editPost(position, holder.editSubject.getText().toString(), holder.editEditor.getText().toString()); + }); - if (backPressHidden) { - holder.editEditor.requestFocus(); - backPressHidden = false; + if (backPressHidden) { + holder.editEditor.requestFocus(); + backPressHidden = false; + } } } } @Override public int getItemCount() { - return postsList.size(); + return topicItems.size(); } /** @@ -680,8 +687,8 @@ class TopicAdapter extends RecyclerView.Adapter { if (tmpUrlSbstr.contains("msg")) tmpUrlSbstr = tmpUrlSbstr.substring(0, tmpUrlSbstr.indexOf("msg") - 1); int testAgainst = Integer.parseInt(tmpUrlSbstr); - for (int i = 0; i < postsList.size(); i++) { - if (postsList.get(i).getPostIndex() == testAgainst) { + for (int i = 0; i < topicItems.size(); i++) { + if (topicItems.get(i) instanceof Post && ((Post) topicItems.get(i)).getPostIndex() == testAgainst) { //same page Timber.e(Integer.toString(i)); postFocusListener.onPostFocusChange(i); 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 b0132a14..30878617 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 @@ -18,6 +18,7 @@ import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -146,10 +147,10 @@ public class TopicParser { * @return {@link ArrayList} of {@link Post}s * @see org.jsoup.Jsoup Jsoup */ - public static ArrayList parseTopic(Document topic, ParseHelpers.Language language) { + public static ArrayList parseTopic(Document topic, ParseHelpers.Language language) { //Method's variables final int NO_INDEX = -1; - ArrayList parsedPostsList = new ArrayList<>(); + ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; //Each row is a post diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java index 7c5e5d1f..fa4f9d2d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java @@ -13,6 +13,7 @@ import gr.thmmy.mthmmy.activities.topic.TopicParser; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import okhttp3.Request; import okhttp3.Response; @@ -92,14 +93,14 @@ public class TopicTask extends AsyncTask { //Finds number of pages int pageCount = TopicParser.parseTopicNumberOfPages(topic, currentPageIndex, language); - ArrayList newPostsList = TopicParser.parseTopic(topic, language); + ArrayList newPostsList = TopicParser.parseTopic(topic, language); int loadedPageTopicId = Integer.parseInt(ThmmyPage.getTopicId(newPageUrl)); //Finds the position of the focused message if present int focusedPostIndex = 0; for (int i = 0; i < newPostsList.size(); ++i) { - if (newPostsList.get(i).getPostIndex() == postFocus) { + if (newPostsList.get(i) instanceof Post && ((Post) newPostsList.get(i)).getPostIndex() == postFocus) { focusedPostIndex = i; break; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java index c713da1f..3a4080fb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTaskResult.java @@ -3,6 +3,7 @@ package gr.thmmy.mthmmy.activities.topic.tasks; import java.util.ArrayList; import gr.thmmy.mthmmy.model.Post; +import gr.thmmy.mthmmy.model.TopicItem; public class TopicTaskResult { private final TopicTask.ResultCode resultCode; @@ -16,7 +17,7 @@ public class TopicTaskResult { * This topic's reply url */ private final String replyPageUrl; - private final ArrayList newPostsList; + private final ArrayList newPostsList; /** * The topicId of the loaded page */ @@ -38,7 +39,7 @@ public class TopicTaskResult { private final String topicViewers; public TopicTaskResult(TopicTask.ResultCode resultCode, String topicTitle, - String replyPageUrl, ArrayList newPostsList, int loadedPageTopicId, + String replyPageUrl, ArrayList newPostsList, int loadedPageTopicId, int currentPageIndex, int pageCount, int focusedPostIndex, String topicTreeAndMods, String topicViewers) { this.resultCode = resultCode; @@ -65,7 +66,7 @@ public class TopicTaskResult { return replyPageUrl; } - public ArrayList getNewPostsList() { + public ArrayList getNewPostsList() { return newPostsList; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 1b8e07a7..85fa4c49 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -2,7 +2,9 @@ package gr.thmmy.mthmmy.model; import java.text.DecimalFormat; -public class Poll { +public class Poll extends TopicItem { + public static int TYPE_POLL = 3; + private final String question; private Entry[] entries; private int availableVoteCount; diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java index 9d38a85e..17a8c6ef 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/TopicItem.java @@ -1,4 +1,5 @@ package gr.thmmy.mthmmy.model; -public class TopicItem { +public abstract class TopicItem { + } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 96cecf4a..66a80407 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -20,6 +20,7 @@ import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTaskResult; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.Post; +import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -65,7 +66,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa private MutableLiveData replyPageUrl = new MutableLiveData<>(); private MutableLiveData pageTopicId = new MutableLiveData<>(); private MutableLiveData topicTitle = new MutableLiveData<>(); - private MutableLiveData> postsList = new MutableLiveData<>(); + private MutableLiveData> topicItems = new MutableLiveData<>(); private MutableLiveData focusedPostIndex = new MutableLiveData<>(); private MutableLiveData topicTaskResultCode = new MutableLiveData<>(); private MutableLiveData topicTreeAndMods = new MutableLiveData<>(); @@ -193,7 +194,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa replyPageUrl.setValue(result.getReplyPageUrl()); topicTitle.setValue(result.getTopicTitle()); pageIndicatorIndex.setValue(result.getCurrentPageIndex()); - postsList.setValue(result.getNewPostsList()); + topicItems.setValue(result.getNewPostsList()); focusedPostIndex.setValue(result.getFocusedPostIndex()); isUserExtraInfoVisibile.clear(); for (int i = 0; i < result.getNewPostsList().size(); i++) { @@ -262,8 +263,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa return focusedPostIndex; } - public MutableLiveData> getPostsList() { - return postsList; + public MutableLiveData> getTopicItems() { + return topicItems; } public MutableLiveData getReplyPageUrl() { @@ -388,8 +389,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } public int postCount() { - if (postsList.getValue() == null) + if (topicItems.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); - return postsList.getValue().size(); + return topicItems.getValue().size(); } } From 8ec74335a67fdf5f38bef367d5130791d5b11685 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 19 Sep 2018 00:18:42 +0300 Subject: [PATCH 134/180] cover multiple selection poll --- .../mthmmy/activities/topic/TopicAdapter.java | 38 ++++++++++++++- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 37 ++++++++------- .../mthmmy/viewmodel/TopicViewModel.java | 12 +++++ .../main/res/layout/activity_topic_poll.xml | 46 +++++++++++++++++++ app/src/main/res/values/strings.xml | 3 ++ 5 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/layout/activity_topic_poll.xml 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 509c13c1..32ef244b 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 @@ -15,6 +15,7 @@ import android.support.annotation.NonNull; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.AlertDialog; import android.support.v7.content.res.AppCompatResources; +import android.support.v7.widget.AppCompatButton; import android.support.v7.widget.RecyclerView; import android.text.InputType; import android.text.TextUtils; @@ -27,6 +28,8 @@ import android.view.inputmethod.InputMethodManager; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; @@ -38,6 +41,7 @@ import android.widget.TextView; import com.squareup.picasso.Picasso; import java.util.List; +import java.util.Map; import java.util.Objects; import gr.thmmy.mthmmy.R; @@ -135,6 +139,10 @@ class TopicAdapter extends RecyclerView.Adapter { editPostEdittext.requestFocus(); return new EditMessageViewHolder(view); + } else if (viewType == Poll.TYPE_POLL) { + View view = LayoutInflater.from(parent.getContext()). + inflate(R.layout.activity_topic_edit_row, parent, false); + return new PollViewHolder(view); } else { throw new IllegalArgumentException("Unknown view type"); } @@ -145,7 +153,18 @@ class TopicAdapter extends RecyclerView.Adapter { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder currentHolder, final int position) { if (currentHolder.getItemViewType() == Poll.TYPE_POLL) { - + Poll poll = (Poll) topicItems.get(position); + Poll.Entry[] entries = poll.getEntries(); + PollViewHolder holder = (PollViewHolder) currentHolder; + holder.question.setText(poll.getQuestion()); + if (poll.getAvailableVoteCount() > 1) { + for (int i = 0; i < entries.length; i++) { + CheckBox checkBox = new CheckBox(context); + checkBox.setText(entries[i].getEntryName()); + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> + viewModel.onVoteCheckboxClicked(holder.optionsLayout.indexOfChild(buttonView), isChecked)); + } + } } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { @@ -644,6 +663,23 @@ class TopicAdapter extends RecyclerView.Adapter { } } + static class PollViewHolder extends RecyclerView.ViewHolder { + final TextView question, errorTooManySelected; + final LinearLayout optionsLayout; + final AppCompatButton submitButton; + final AppCompatButton removeVotesButton; + + public PollViewHolder(View itemView) { + super(itemView); + + question = itemView.findViewById(R.id.question_textview); + optionsLayout = itemView.findViewById(R.id.options_layout); + submitButton = itemView.findViewById(R.id.submit_button); + removeVotesButton = itemView.findViewById(R.id.remove_vote_button); + errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); + } + } + /** * This class is used to handle link clicks in WebViews. When link url is one that the app can * handle internally, it does. Otherwise user is prompt to open the link in a browser. diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 85fa4c49..1d1b54bc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -3,21 +3,36 @@ package gr.thmmy.mthmmy.model; import java.text.DecimalFormat; public class Poll extends TopicItem { - public static int TYPE_POLL = 3; + public static final int TYPE_POLL = 3; private final String question; private Entry[] entries; private int availableVoteCount; - private String pollFormUrl, sc, removeVoteUrl; + private String pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl; public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc, - String removeVoteUrl) { + String removeVoteUrl, String showVoteResultsUrl) { this.question = question; this.entries = entries; this.availableVoteCount = availableVoteCount; this.pollFormUrl = pollFormUrl; this.sc = sc; this.removeVoteUrl = removeVoteUrl; + this.showVoteResultsUrl = showVoteResultsUrl; + } + + public int totalVotes() { + int sum = 0; + for (Entry entry : entries) { + sum += entry.votes; + } + return sum; + } + + public String getVotePercentage(int index) { + DecimalFormat format = new DecimalFormat(".#"); + double percentage = 100 * ((double) entries[index].votes / (double) totalVotes()); + return format.format(percentage); } public String getQuestion() { @@ -44,21 +59,11 @@ public class Poll extends TopicItem { return removeVoteUrl; } - public int totalVotes() { - int sum = 0; - for (Entry entry : entries) { - sum += entry.votes; - } - return sum; - } - - public String getVotePercentage(int index) { - DecimalFormat format = new DecimalFormat(".#"); - double percentage = 100 * ((double) entries[index].votes / (double) totalVotes()); - return format.format(percentage); + public String getShowVoteResultsUrl() { + return showVoteResultsUrl; } - static class Entry { + public static class Entry { private final String entryName; private int votes; diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 66a80407..1a4c5adc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -5,6 +5,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; +import android.view.View; +import android.widget.CheckBox; import java.util.ArrayList; @@ -44,6 +46,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa * holds the adapter position of the post being edited */ private int postBeingEditedPosition; + private ArrayList selectedVoteIndices; private TopicTask currentTopicTask; private PrepareForEditTask currentPrepareForEditTask; @@ -245,6 +248,15 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) performPageChange(); } + public void onVoteCheckboxClicked(int index, boolean checked) { + if (checked) { + selectedVoteIndices.add(index); + } else { + selectedVoteIndices.remove(index); + } + + } + // <-------------Just getters, setters and helper methods below here----------------> public MutableLiveData getTopicViewers() { diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml new file mode 100644 index 00000000..3c68a7db --- /dev/null +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + \ 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 c52cf546..d502d343 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,6 +59,9 @@ Network error retry This topic is either missing or off limits to you + Remove vote + Show results + You may only select %d options Username From a381bc8e3965117c6ebfad79d6cb942eb107edab Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 19 Sep 2018 10:06:11 +0300 Subject: [PATCH 135/180] cover single choice poll --- .../mthmmy/activities/topic/TopicAdapter.java | 27 +++++++++++++++---- .../mthmmy/viewmodel/TopicViewModel.java | 15 +++++------ .../main/res/layout/activity_topic_poll.xml | 7 +---- 3 files changed, 30 insertions(+), 19 deletions(-) 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 32ef244b..45df3c58 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 @@ -35,6 +35,8 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; +import android.widget.RadioButton; +import android.widget.RadioGroup; import android.widget.RelativeLayout; import android.widget.TextView; @@ -158,12 +160,27 @@ class TopicAdapter extends RecyclerView.Adapter { PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); if (poll.getAvailableVoteCount() > 1) { - for (int i = 0; i < entries.length; i++) { + LinearLayout optionsLayout = new LinearLayout(context); + optionsLayout.setOrientation(LinearLayout.HORIZONTAL); + for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); - checkBox.setText(entries[i].getEntryName()); + checkBox.setText(entry.getEntryName()); checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> - viewModel.onVoteCheckboxClicked(holder.optionsLayout.indexOfChild(buttonView), isChecked)); + viewModel.onVoteCheckboxClicked(optionsLayout.indexOfChild(buttonView), isChecked)); + optionsLayout.addView(checkBox); + } + holder.rootLayout.addView(optionsLayout, 1); + } else if (poll.getAvailableVoteCount() == 1) { + RadioGroup radioGroup = new RadioGroup(context); + for (int i = 0; i < entries.length; i++) { + RadioButton radioButton = new RadioButton(context); + radioButton.setText(entries[i].getEntryName()); + radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); + radioGroup.addView(radioButton); } + holder.rootLayout.addView(radioGroup, 1); + } else { + //Showing results } } else { Post currentPost = (Post) topicItems.get(position); @@ -665,7 +682,7 @@ class TopicAdapter extends RecyclerView.Adapter { static class PollViewHolder extends RecyclerView.ViewHolder { final TextView question, errorTooManySelected; - final LinearLayout optionsLayout; + final LinearLayout rootLayout; final AppCompatButton submitButton; final AppCompatButton removeVotesButton; @@ -673,7 +690,7 @@ class TopicAdapter extends RecyclerView.Adapter { super(itemView); question = itemView.findViewById(R.id.question_textview); - optionsLayout = itemView.findViewById(R.id.options_layout); + rootLayout = (LinearLayout) itemView; submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 1a4c5adc..18ae0ab5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -5,8 +5,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; -import android.view.View; -import android.widget.CheckBox; import java.util.ArrayList; @@ -46,7 +44,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa * holds the adapter position of the post being edited */ private int postBeingEditedPosition; - private ArrayList selectedVoteIndices; + private ArrayList selectedVoteIndices = new ArrayList<>(); private TopicTask currentTopicTask; private PrepareForEditTask currentPrepareForEditTask; @@ -249,12 +247,13 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } public void onVoteCheckboxClicked(int index, boolean checked) { - if (checked) { - selectedVoteIndices.add(index); - } else { - selectedVoteIndices.remove(index); - } + if (checked) selectedVoteIndices.add(index); + else selectedVoteIndices.remove(index); + } + public void onRadioButtonCLicked(int index) { + selectedVoteIndices.clear(); + selectedVoteIndices.add(index); } // <-------------Just getters, setters and helper methods below here----------------> diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 3c68a7db..96c55c96 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -1,5 +1,6 @@ - - Date: Wed, 19 Sep 2018 12:58:36 +0300 Subject: [PATCH 136/180] finish vote chart viewing --- .../mthmmy/activities/topic/TopicAdapter.java | 28 ++++++++++++++++--- .../main/res/layout/activity_topic_poll.xml | 5 ++++ 2 files changed, 29 insertions(+), 4 deletions(-) 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 45df3c58..9c0f73ea 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 @@ -29,7 +29,6 @@ import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.CheckBox; -import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; @@ -40,10 +39,18 @@ import android.widget.RadioGroup; import android.widget.RelativeLayout; import android.widget.TextView; +import com.github.mikephil.charting.charts.HorizontalBarChart; +import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.formatter.IAxisValueFormatter; +import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import com.squareup.picasso.Picasso; +import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Objects; import gr.thmmy.mthmmy.R; @@ -172,15 +179,26 @@ class TopicAdapter extends RecyclerView.Adapter { holder.rootLayout.addView(optionsLayout, 1); } else if (poll.getAvailableVoteCount() == 1) { RadioGroup radioGroup = new RadioGroup(context); - for (int i = 0; i < entries.length; i++) { + for (Poll.Entry entry : entries) { RadioButton radioButton = new RadioButton(context); - radioButton.setText(entries[i].getEntryName()); + radioButton.setText(entry.getEntryName()); radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); radioGroup.addView(radioButton); } holder.rootLayout.addView(radioGroup, 1); } else { //Showing results + ArrayList valuesToCompare = new ArrayList<>(); + for (int i = 0; i < entries.length; i++) { + valuesToCompare.add(new BarEntry(entries[i].getVotes(), i)); + } + BarDataSet data = new BarDataSet(valuesToCompare, "Vote Results"); + + YAxis yAxisLeft = holder.voteChart.getAxisLeft(); + yAxisLeft.setValueFormatter((value, axis) -> entries[(int) value].getEntryName()); + + BarData barData = new BarData(data); + holder.voteChart.setData(barData); } } else { Post currentPost = (Post) topicItems.get(position); @@ -685,6 +703,7 @@ class TopicAdapter extends RecyclerView.Adapter { final LinearLayout rootLayout; final AppCompatButton submitButton; final AppCompatButton removeVotesButton; + final HorizontalBarChart voteChart; public PollViewHolder(View itemView) { super(itemView); @@ -694,6 +713,7 @@ class TopicAdapter extends RecyclerView.Adapter { submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); + voteChart = itemView.findViewById(R.id.vote_chart); } } diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 96c55c96..2803d653 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -11,6 +11,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" /> + + Date: Wed, 19 Sep 2018 13:16:01 +0300 Subject: [PATCH 137/180] poll parsing init --- .../mthmmy/activities/topic/TopicParser.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 30878617..336e4613 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 @@ -16,6 +16,7 @@ import java.util.Objects; import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.TopicItem; @@ -150,6 +151,9 @@ public class TopicParser { public static ArrayList parseTopic(Document topic, ParseHelpers.Language language) { //Method's variables final int NO_INDEX = -1; + + Poll poll = findPoll(topic, language); + ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; @@ -469,6 +473,20 @@ public class TopicParser { return parsedPostsList; } + private static Poll findPoll(Document topic, ParseHelpers.Language language) { + Elements tables = topic.select("table"); + for (int i = 0; i < tables.size(); i++) { + try { + Element image = tables.get(i).child(0).child(0).child(0); + if (image.html().contains("Poll")) { + return new Poll(); + } else if (image.html().contains("Ψηφοφορία")) { + return new Poll(); + } + } catch (Exception ignored) { } + } + } + /** * Returns the color of a user according to user's rank on forum. * From 4f7d8ba017826548141b6199614ac2d90d1e7567 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Thu, 20 Sep 2018 13:29:57 +0300 Subject: [PATCH 138/180] finish poll parsing --- .../mthmmy/activities/topic/TopicParser.java | 73 +++++++++++++++++-- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 9 ++- 2 files changed, 73 insertions(+), 9 deletions(-) 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 336e4613..a23825c3 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 @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.regex.Matcher; import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; @@ -152,7 +153,7 @@ public class TopicParser { //Method's variables final int NO_INDEX = -1; - Poll poll = findPoll(topic, language); + Poll poll = findPoll(topic); ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; @@ -473,18 +474,76 @@ public class TopicParser { return parsedPostsList; } - private static Poll findPoll(Document topic, ParseHelpers.Language language) { + private static Poll findPoll(Document topic) { + Pattern integerPattern = Pattern.compile("[0-9]+"); Elements tables = topic.select("table"); for (int i = 0; i < tables.size(); i++) { try { Element image = tables.get(i).child(0).child(0).child(0); - if (image.html().contains("Poll")) { - return new Poll(); - } else if (image.html().contains("Ψηφοφορία")) { - return new Poll(); + if (image.html().contains("Poll") || image.html().contains("Ψηφοφορία")) { + // has poll in english + String question; + ArrayList entries = new ArrayList<>(); + int availableVoteCount = 0; + String pollFormUrl = null, sc = null, removeVoteUrl = null, showVoteResultsUrl = null, + showOptionsUrl = null; + + Element secondRow = tables.get(i).select("tr[class=windowbg]").first(); + Element secondColumn = secondRow.child(1); + String columnString = secondColumn.outerHtml(); + question = columnString.substring(columnString.indexOf('>'), columnString.indexOf('<', 2)).trim(); + + Element form = secondColumn.select("form").first(); + if (form != null) { + // english poll in vote mode + pollFormUrl = form.attr("action"); + + Elements formInputs = form.select("input"); + for (int j = 0; j < formInputs.size(); j++) { + if (formInputs.get(i).attr("name").equals("options[]")) { + entries.add(new Poll.Entry(formInputs.get(i).text())); + } else if (formInputs.get(i).attr("name").equals("sc")) { + sc = formInputs.get(i).attr("value"); + } + } + + Element promptColumn = form.child(0).child(0).child(0); + String prompt = promptColumn.text(); + Matcher integerMatcher = integerPattern.matcher(prompt); + availableVoteCount = Integer.parseInt(prompt.substring(integerMatcher.start(), integerMatcher.end())); + + Elements links = form.select("a"); + if (links != null && links.size() > 0) { + showVoteResultsUrl = links.first().attr("href"); + } + } else { + // english poll in results mode + Elements optionRows = secondColumn.child(0).select("table").first().children(); + for (int j = 0; j < optionRows.size(); j++) { + String optionName = optionRows.get(i).child(0).text(); + String voteCountDescription = optionRows.get(i).child(1).text(); + Matcher integerMatcher = integerPattern.matcher(voteCountDescription); + int voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), + integerMatcher.end())); + entries.add(new Poll.Entry(optionName, voteCount)); + } + + Elements links = secondColumn.select("a"); + if (links != null && links.size() > 0) { + if (links.first().text().equals("Remove Vote") || links.first().text().equals("Αφαίρεση ψήφου")) + removeVoteUrl = links.first().attr("href"); + else if (links.first().text().equals("Voting options") || links.first().text().equals("Επιλογές ψηφοφορίας")) + showOptionsUrl = links.first().attr("href"); + } + } + return new Poll(question, entries.toArray(new Poll.Entry[0]), availableVoteCount, + pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl, showOptionsUrl); } - } catch (Exception ignored) { } + } catch (Exception e) { + Timber.v(e, "Could not parse a poll"); + } } + return null; } /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 1d1b54bc..66c28a57 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -8,10 +8,10 @@ public class Poll extends TopicItem { private final String question; private Entry[] entries; private int availableVoteCount; - private String pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl; + private String pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl, showOptionsUrl; public Poll(String question, Entry[] entries, int availableVoteCount, String pollFormUrl, String sc, - String removeVoteUrl, String showVoteResultsUrl) { + String removeVoteUrl, String showVoteResultsUrl, String showOptionsUrl) { this.question = question; this.entries = entries; this.availableVoteCount = availableVoteCount; @@ -19,6 +19,7 @@ public class Poll extends TopicItem { this.sc = sc; this.removeVoteUrl = removeVoteUrl; this.showVoteResultsUrl = showVoteResultsUrl; + this.showOptionsUrl = showOptionsUrl; } public int totalVotes() { @@ -63,6 +64,10 @@ public class Poll extends TopicItem { return showVoteResultsUrl; } + public String getShowOptionsUrl() { + return showOptionsUrl; + } + public static class Entry { private final String entryName; private int votes; From cd6d4e07c8dcd2bfaefae365c9c40d5e4a0931bd Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Thu, 20 Sep 2018 13:57:57 +0300 Subject: [PATCH 139/180] fix parse mistakes in results mode --- .../mthmmy/activities/topic/TopicAdapter.java | 2 +- .../thmmy/mthmmy/activities/topic/TopicParser.java | 14 +++++++++----- app/src/main/res/layout/activity_topic_poll.xml | 6 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) 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 9c0f73ea..ad8ecb28 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 @@ -150,7 +150,7 @@ class TopicAdapter extends RecyclerView.Adapter { return new EditMessageViewHolder(view); } else if (viewType == Poll.TYPE_POLL) { View view = LayoutInflater.from(parent.getContext()). - inflate(R.layout.activity_topic_edit_row, parent, false); + inflate(R.layout.activity_topic_poll, parent, false); return new PollViewHolder(view); } else { throw new IllegalArgumentException("Unknown view type"); 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 a23825c3..ecef6034 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 @@ -153,9 +153,12 @@ public class TopicParser { //Method's variables final int NO_INDEX = -1; + ArrayList parsedPostsList = new ArrayList<>(); + Poll poll = findPoll(topic); + if (poll != null) + parsedPostsList.add(poll); - ArrayList parsedPostsList = new ArrayList<>(); Elements postRows; //Each row is a post @@ -491,7 +494,7 @@ public class TopicParser { Element secondRow = tables.get(i).select("tr[class=windowbg]").first(); Element secondColumn = secondRow.child(1); String columnString = secondColumn.outerHtml(); - question = columnString.substring(columnString.indexOf('>'), columnString.indexOf('<', 2)).trim(); + question = columnString.substring(columnString.indexOf('>') + 1, columnString.indexOf('<', 2)).trim(); Element form = secondColumn.select("form").first(); if (form != null) { @@ -518,11 +521,12 @@ public class TopicParser { } } else { // english poll in results mode - Elements optionRows = secondColumn.child(0).select("table").first().children(); + Elements optionRows = secondColumn.child(0).child(0).select("table").first().child(0).children(); for (int j = 0; j < optionRows.size(); j++) { - String optionName = optionRows.get(i).child(0).text(); - String voteCountDescription = optionRows.get(i).child(1).text(); + String optionName = optionRows.get(j).child(0).text(); + String voteCountDescription = optionRows.get(j).child(1).text(); Matcher integerMatcher = integerPattern.matcher(voteCountDescription); + integerMatcher.find(); int voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), integerMatcher.end())); entries.add(new Poll.Entry(optionName, voteCount)); diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 2803d653..9953846f 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -4,7 +4,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content"> + android:layout_width="match_parent" + android:layout_height="250dp" /> Date: Fri, 21 Sep 2018 14:19:29 +0300 Subject: [PATCH 140/180] configure bar chart --- .../mthmmy/activities/topic/TopicAdapter.java | 32 +++++++-- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 5 ++ .../main/res/layout/activity_topic_poll.xml | 70 ++++++++++++------- 3 files changed, 75 insertions(+), 32 deletions(-) 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 ad8ecb28..ff766e62 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 @@ -40,13 +40,11 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.github.mikephil.charting.charts.HorizontalBarChart; -import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; -import com.github.mikephil.charting.formatter.IAxisValueFormatter; -import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import com.squareup.picasso.Picasso; import java.util.ArrayList; @@ -188,18 +186,36 @@ class TopicAdapter extends RecyclerView.Adapter { holder.rootLayout.addView(radioGroup, 1); } else { //Showing results - ArrayList valuesToCompare = new ArrayList<>(); + List valuesToCompare = new ArrayList<>(); for (int i = 0; i < entries.length; i++) { - valuesToCompare.add(new BarEntry(entries[i].getVotes(), i)); + valuesToCompare.add(new BarEntry(i, entries[i].getVotes())); } BarDataSet data = new BarDataSet(valuesToCompare, "Vote Results"); YAxis yAxisLeft = holder.voteChart.getAxisLeft(); - yAxisLeft.setValueFormatter((value, axis) -> entries[(int) value].getEntryName()); + yAxisLeft.setGranularity(1f); + YAxis yAxisRight = holder.voteChart.getAxisRight(); + yAxisRight.setEnabled(false); + + XAxis xAxis = holder.voteChart.getXAxis(); + xAxis.setValueFormatter((value, axis) -> entries[(int) value].getEntryName()); + xAxis.setTextColor(context.getResources().getColor(R.color.primary_text)); + xAxis.setGranularity(1f); + xAxis.setDrawGridLines(false); + xAxis.setDrawAxisLine(false); + xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); BarData barData = new BarData(data); + barData.setValueTextColor(context.getResources().getColor(R.color.accent)); holder.voteChart.setData(barData); + holder.voteChart.getLegend().setEnabled(false); + holder.voteChart.getDescription().setEnabled(false); + holder.voteChart.invalidate(); } + if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); + if (poll.getShowVoteResultsUrl() != null) holder.showPollResultsButton.setVisibility(View.VISIBLE); + if (poll.getShowOptionsUrl() != null) holder.showPollOptionsButton.setVisibility(View.VISIBLE); + if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { @@ -702,7 +718,7 @@ class TopicAdapter extends RecyclerView.Adapter { final TextView question, errorTooManySelected; final LinearLayout rootLayout; final AppCompatButton submitButton; - final AppCompatButton removeVotesButton; + final AppCompatButton removeVotesButton, showPollResultsButton, showPollOptionsButton; final HorizontalBarChart voteChart; public PollViewHolder(View itemView) { @@ -712,6 +728,8 @@ class TopicAdapter extends RecyclerView.Adapter { rootLayout = (LinearLayout) itemView; submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); + showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); + showPollOptionsButton = itemView.findViewById(R.id.show_poll_options_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); voteChart = itemView.findViewById(R.id.vote_chart); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 66c28a57..071557e9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -99,5 +99,10 @@ public class Poll extends TopicItem { public void setVotes(int votes) { this.votes = votes; } + + @Override + public String toString() { + return "Vote label:" + entryName + ", num votes:" + votes; + } } } diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 9953846f..5a63eb03 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -1,20 +1,21 @@ - + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:orientation="vertical"> + android:layout_height="wrap_content" + android:textColor="@color/primary_text" /> + android:layout_height="200dp" /> + android:visibility="gone" /> - + + - - - + + + + + + + + + + \ No newline at end of file From 3189cc93650064fa48ee305fdb8d8dbfbd7419a2 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sat, 22 Sep 2018 18:15:06 +0300 Subject: [PATCH 141/180] fix vote mode parsing in polls --- .../mthmmy/activities/topic/TopicAdapter.java | 5 +++- .../mthmmy/activities/topic/TopicParser.java | 26 +++++++++++++------ .../main/res/layout/activity_topic_poll.xml | 10 +++++-- 3 files changed, 30 insertions(+), 11 deletions(-) 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 ff766e62..43f019da 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 @@ -48,6 +48,7 @@ import com.github.mikephil.charting.data.BarEntry; import com.squareup.picasso.Picasso; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -166,10 +167,11 @@ class TopicAdapter extends RecyclerView.Adapter { holder.question.setText(poll.getQuestion()); if (poll.getAvailableVoteCount() > 1) { LinearLayout optionsLayout = new LinearLayout(context); - optionsLayout.setOrientation(LinearLayout.HORIZONTAL); + optionsLayout.setOrientation(LinearLayout.VERTICAL); for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); checkBox.setText(entry.getEntryName()); + checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> viewModel.onVoteCheckboxClicked(optionsLayout.indexOfChild(buttonView), isChecked)); optionsLayout.addView(checkBox); @@ -211,6 +213,7 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.getLegend().setEnabled(false); holder.voteChart.getDescription().setEnabled(false); holder.voteChart.invalidate(); + holder.voteChart.setVisibility(View.VISIBLE); } if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); if (poll.getShowVoteResultsUrl() != null) holder.showPollResultsButton.setVisibility(View.VISIBLE); 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 ecef6034..9c987964 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 @@ -1,6 +1,7 @@ package gr.thmmy.mthmmy.activities.topic; import android.graphics.Color; +import android.util.Log; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -500,20 +501,29 @@ public class TopicParser { if (form != null) { // english poll in vote mode pollFormUrl = form.attr("action"); - - Elements formInputs = form.select("input"); - for (int j = 0; j < formInputs.size(); j++) { - if (formInputs.get(i).attr("name").equals("options[]")) { - entries.add(new Poll.Entry(formInputs.get(i).text())); - } else if (formInputs.get(i).attr("name").equals("sc")) { - sc = formInputs.get(i).attr("value"); + sc = form.select("input[name=sc]").first().attr("value"); + + int rowIndex = -1; + Elements possibleEntriesRows = form.child(0).child(0).children(); + for (int j = 0; j < possibleEntriesRows.size(); j++) { + if (possibleEntriesRows.get(j).select("input").size() > 0) { + rowIndex = j; + break; } } + String entriesRaw = form.child(0).child(0).child(rowIndex).child(0).html(); + Matcher entryMatcher = Pattern.compile(">[^<]+ 0) { diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 5a63eb03..5c779274 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -15,7 +15,8 @@ + android:layout_height="200dp" + android:visibility="gone"/> + android:visibility="gone" + android:layout_marginEnd="16dp"/> @@ -53,6 +56,7 @@ android:id="@+id/show_poll_options_button" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="16dp" android:text="@string/show_vote_results_button" android:visibility="gone" /> @@ -60,7 +64,9 @@ android:id="@+id/submit_button" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="16dp" android:text="@string/submit" + android:textColor="@color/accent" android:visibility="gone"/> \ No newline at end of file From 4f8af3d539fd9035effcd25406eea916806338c5 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sat, 22 Sep 2018 22:15:02 +0300 Subject: [PATCH 142/180] style vote bar chart a lil bit --- .../gr/thmmy/mthmmy/activities/topic/TopicAdapter.java | 7 +++++++ app/src/main/res/layout/activity_topic_poll.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) 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 43f019da..987528cf 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 @@ -5,6 +5,7 @@ import android.annotation.TargetApi; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -19,6 +20,7 @@ import android.support.v7.widget.AppCompatButton; import android.support.v7.widget.RecyclerView; import android.text.InputType; import android.text.TextUtils; +import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -193,9 +195,11 @@ class TopicAdapter extends RecyclerView.Adapter { valuesToCompare.add(new BarEntry(i, entries[i].getVotes())); } BarDataSet data = new BarDataSet(valuesToCompare, "Vote Results"); + data.setColor(context.getResources().getColor(R.color.accent)); YAxis yAxisLeft = holder.voteChart.getAxisLeft(); yAxisLeft.setGranularity(1f); + yAxisLeft.setTextColor(context.getResources().getColor(R.color.primary_text)); YAxis yAxisRight = holder.voteChart.getAxisRight(); yAxisRight.setEnabled(false); @@ -212,6 +216,9 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.setData(barData); holder.voteChart.getLegend().setEnabled(false); holder.voteChart.getDescription().setEnabled(false); + int chartHeightdp = 10 + 30 * entries.length; + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + holder.voteChart.setMinimumHeight((int) (chartHeightdp * (metrics.densityDpi / 160f))); holder.voteChart.invalidate(); holder.voteChart.setVisibility(View.VISIBLE); } diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 5c779274..e23b57cf 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -15,7 +15,7 @@ Date: Sat, 22 Sep 2018 23:19:34 +0300 Subject: [PATCH 143/180] add functionality to show/ hide results --- .../mthmmy/activities/topic/TopicAdapter.java | 30 +++++++++++++++---- .../java/gr/thmmy/mthmmy/model/ThmmyPage.java | 10 ++++--- .../mthmmy/utils/parsing/ParseHelpers.java | 12 ++++---- .../mthmmy/viewmodel/TopicViewModel.java | 12 ++++++++ .../main/res/layout/activity_topic_poll.xml | 2 +- app/src/main/res/values/strings.xml | 3 +- 6 files changed, 51 insertions(+), 18 deletions(-) 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 987528cf..c6c7ae53 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 @@ -5,7 +5,6 @@ import android.annotation.TargetApi; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -50,7 +49,6 @@ import com.github.mikephil.charting.data.BarEntry; import com.squareup.picasso.Picasso; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -223,9 +221,29 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.setVisibility(View.VISIBLE); } if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); - if (poll.getShowVoteResultsUrl() != null) holder.showPollResultsButton.setVisibility(View.VISIBLE); - if (poll.getShowOptionsUrl() != null) holder.showPollOptionsButton.setVisibility(View.VISIBLE); + else holder.removeVotesButton.setVisibility(View.GONE); + if (poll.getShowVoteResultsUrl() != null) { + holder.showPollResultsButton.setOnClickListener(v -> { + if (holder.voteChart.getData() != null) { + // Chart has been already created, just make it visible + holder.voteChart.setVisibility(View.VISIBLE); + holder.showPollResultsButton.setVisibility(View.GONE); + holder.hidePollResultsButton.setVisibility(View.VISIBLE); + } else viewModel.viewVoteResults(); + }); + holder.showPollResultsButton.setVisibility(View.VISIBLE); + } else holder.showPollResultsButton.setVisibility(View.GONE); + + if (poll.getShowOptionsUrl() != null) { + holder.hidePollResultsButton.setOnClickListener(v -> { + holder.voteChart.setVisibility(View.GONE); + holder.hidePollResultsButton.setVisibility(View.GONE); + holder.showPollResultsButton.setVisibility(View.VISIBLE); + }); + holder.hidePollResultsButton.setVisibility(View.VISIBLE); + } else holder.hidePollResultsButton.setVisibility(View.GONE); if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); + else holder.submitButton.setVisibility(View.GONE); } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { @@ -728,7 +746,7 @@ class TopicAdapter extends RecyclerView.Adapter { final TextView question, errorTooManySelected; final LinearLayout rootLayout; final AppCompatButton submitButton; - final AppCompatButton removeVotesButton, showPollResultsButton, showPollOptionsButton; + final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton; final HorizontalBarChart voteChart; public PollViewHolder(View itemView) { @@ -739,7 +757,7 @@ class TopicAdapter extends RecyclerView.Adapter { submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); - showPollOptionsButton = itemView.findViewById(R.id.show_poll_options_button); + hidePollResultsButton = itemView.findViewById(R.id.show_poll_options_button); errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); voteChart = itemView.findViewById(R.id.vote_chart); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java index bc451fd1..c500c50a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java @@ -3,6 +3,8 @@ package gr.thmmy.mthmmy.model; import android.net.Uri; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import timber.log.Timber; @@ -180,10 +182,10 @@ public class ThmmyPage { public static String getTopicId(String topicUrl) { if (resolvePageCategory(Uri.parse(topicUrl)) == PageCategory.TOPIC) { - String returnString = topicUrl.substring(topicUrl.indexOf("topic=") + 6); - if (returnString.contains(".")) - returnString = returnString.substring(0, returnString.indexOf(".")); - return returnString; + Matcher topicIdMatcher = Pattern.compile("topic=[0-9]+").matcher(topicUrl); + if (topicIdMatcher.find()) { + return topicUrl.substring(topicIdMatcher.start() + 6, topicIdMatcher.end()); + } else return null; } return null; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java index 0034ffc4..804c9e85 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java @@ -5,6 +5,8 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import timber.log.Timber; @@ -179,11 +181,9 @@ public class ParseHelpers { * @return the base URL of the given topic */ public static String getBaseURL(String topicURL) { - if (topicURL.substring(0, topicURL.lastIndexOf(".")).contains("topic=")) - return topicURL.substring(0, topicURL.lastIndexOf(".")); - else { - Timber.wtf(new ParseException("Could not parse base URL of topic")); - return ""; - } + Matcher baseUrlMatcher = Pattern.compile(".+topic=[0-9]+").matcher(topicURL); + if (baseUrlMatcher.find()) + return topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end()); + else return ""; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index a625f311..5bc1f894 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -106,6 +106,18 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } } + public void viewVoteResults() { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Viewing poll results"); + loadUrl(ParseHelpers.getBaseURL(topicUrl) + ";viewResults"); + } + + public void loadBaseUrl() { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Viewing poll results"); + loadUrl(ParseHelpers.getBaseURL(topicUrl)); + } + public void prepareForReply() { if (replyPageUrl.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index e23b57cf..fd4f1f5f 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -57,7 +57,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" - android:text="@string/show_vote_results_button" + android:text="@string/show_vote_options_button" android:visibility="gone" /> retry This topic is either missing or off limits to you Remove vote - Show results + show results You may only select %d options + hide results Username From 87e4e54f3c45499784cdb76e5297207d29df4994 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 23 Sep 2018 00:58:51 +0300 Subject: [PATCH 144/180] fix behaviour of show/hide results --- .../mthmmy/activities/topic/TopicAdapter.java | 34 +++++++------------ .../main/res/layout/activity_topic_poll.xml | 10 ++++-- 2 files changed, 20 insertions(+), 24 deletions(-) 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 c6c7ae53..d0682f1e 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 @@ -166,17 +166,14 @@ class TopicAdapter extends RecyclerView.Adapter { PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); if (poll.getAvailableVoteCount() > 1) { - LinearLayout optionsLayout = new LinearLayout(context); - optionsLayout.setOrientation(LinearLayout.VERTICAL); for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); checkBox.setText(entry.getEntryName()); checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); - checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> - viewModel.onVoteCheckboxClicked(optionsLayout.indexOfChild(buttonView), isChecked)); - optionsLayout.addView(checkBox); + holder.optionsLayout.addView(checkBox); } - holder.rootLayout.addView(optionsLayout, 1); + holder.voteChart.setVisibility(View.GONE); + holder.optionsLayout.setVisibility(View.VISIBLE); } else if (poll.getAvailableVoteCount() == 1) { RadioGroup radioGroup = new RadioGroup(context); for (Poll.Entry entry : entries) { @@ -185,9 +182,13 @@ class TopicAdapter extends RecyclerView.Adapter { radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); radioGroup.addView(radioButton); } - holder.rootLayout.addView(radioGroup, 1); + holder.optionsLayout.addView(radioGroup); + holder.voteChart.setVisibility(View.GONE); + holder.optionsLayout.setVisibility(View.VISIBLE); } else { //Showing results + holder.optionsLayout.removeAllViews(); + holder.optionsLayout.setVisibility(View.GONE); List valuesToCompare = new ArrayList<>(); for (int i = 0; i < entries.length; i++) { valuesToCompare.add(new BarEntry(i, entries[i].getVotes())); @@ -223,23 +224,12 @@ class TopicAdapter extends RecyclerView.Adapter { if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); else holder.removeVotesButton.setVisibility(View.GONE); if (poll.getShowVoteResultsUrl() != null) { - holder.showPollResultsButton.setOnClickListener(v -> { - if (holder.voteChart.getData() != null) { - // Chart has been already created, just make it visible - holder.voteChart.setVisibility(View.VISIBLE); - holder.showPollResultsButton.setVisibility(View.GONE); - holder.hidePollResultsButton.setVisibility(View.VISIBLE); - } else viewModel.viewVoteResults(); - }); + holder.showPollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowVoteResultsUrl())); holder.showPollResultsButton.setVisibility(View.VISIBLE); } else holder.showPollResultsButton.setVisibility(View.GONE); if (poll.getShowOptionsUrl() != null) { - holder.hidePollResultsButton.setOnClickListener(v -> { - holder.voteChart.setVisibility(View.GONE); - holder.hidePollResultsButton.setVisibility(View.GONE); - holder.showPollResultsButton.setVisibility(View.VISIBLE); - }); + holder.hidePollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowOptionsUrl())); holder.hidePollResultsButton.setVisibility(View.VISIBLE); } else holder.hidePollResultsButton.setVisibility(View.GONE); if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); @@ -744,7 +734,7 @@ class TopicAdapter extends RecyclerView.Adapter { static class PollViewHolder extends RecyclerView.ViewHolder { final TextView question, errorTooManySelected; - final LinearLayout rootLayout; + final LinearLayout optionsLayout; final AppCompatButton submitButton; final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton; final HorizontalBarChart voteChart; @@ -753,7 +743,7 @@ class TopicAdapter extends RecyclerView.Adapter { super(itemView); question = itemView.findViewById(R.id.question_textview); - rootLayout = (LinearLayout) itemView; + optionsLayout = itemView.findViewById(R.id.options_layout); submitButton = itemView.findViewById(R.id.submit_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button); showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index fd4f1f5f..84a7e275 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -1,6 +1,6 @@ - + + Date: Sun, 23 Sep 2018 14:45:09 +0300 Subject: [PATCH 145/180] finish submit/remove vote functionality --- .../activities/main/forum/ForumFragment.java | 8 +-- .../main/recent/RecentFragment.java | 8 +-- .../main/unread/UnreadFragment.java | 6 +- .../activities/topic/TopicActivity.java | 11 ++++ .../mthmmy/activities/topic/TopicAdapter.java | 24 ++++--- .../activities/topic/tasks/DeleteTask.java | 6 +- .../topic/tasks/SubmitVoteTask.java | 52 +++++++++++++++ .../thmmy/mthmmy/utils/ExternalAsyncTask.java | 62 +++++++++--------- .../gr/thmmy/mthmmy/utils/NetworkTask.java | 32 +++++----- .../mthmmy/utils/parsing/NewParseTask.java | 17 ++--- .../mthmmy/utils/parsing/ParseHelpers.java | 5 +- .../mthmmy/viewmodel/TopicViewModel.java | 63 ++++++++++++------- 12 files changed, 192 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java 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 ceb41e13..a85eca23 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 @@ -187,13 +187,13 @@ public class ForumFragment extends BaseFragment { private class ForumTask extends NewParseTask> { private HttpUrl forumUrl = SessionManager.forumUrl; //may change upon collapse/expand - public ForumTask(OnParseTaskStartedListener onParseTaskStartedListener, - OnParseTaskFinishedListener> onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public ForumTask(OnTaskStartedListener onTaskStartedListener, + OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected ArrayList parse(Document document) throws ParseException { + protected ArrayList parse(Document document, Response response) throws ParseException { Elements categoryBlocks = document.select(".tborder:not([style])>table[cellpadding=5]"); if (categoryBlocks.size() != 0) { ArrayList fetchedCategories = new ArrayList<>(); 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 98ad7f69..65b0d315 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 @@ -157,13 +157,13 @@ public class RecentFragment extends BaseFragment { //---------------------------------------ASYNC TASK----------------------------------- private class RecentTask extends NewParseTask> { - public RecentTask(OnParseTaskStartedListener onParseTaskStartedListener, - OnParseTaskFinishedListener> onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public RecentTask(OnTaskStartedListener onTaskStartedListener, + OnNetworkTaskFinishedListener> onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected ArrayList parse(Document document) throws ParseException { + protected ArrayList parse(Document document, Response response) throws ParseException { ArrayList fetchedRecent = new ArrayList<>(); Elements recent = document.select("#block8 :first-child div"); if (!recent.isEmpty()) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 0681c4af..0747b4bf 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -185,12 +185,12 @@ public class UnreadFragment extends BaseFragment { private class UnreadTask extends NewParseTask { - UnreadTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + UnreadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected Void parse(Document document) throws ParseException { + protected Void parse(Document document, Response response) throws ParseException { Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); if (!unread.isEmpty()) { //topicSummaries.clear(); 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 b6201e9c..4a997e49 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 @@ -50,8 +50,10 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; +import gr.thmmy.mthmmy.utils.ExternalAsyncTask; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; @@ -598,6 +600,15 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo progressBar.setVisibility(ProgressBar.GONE); } }); + viewModel.setVoteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); + viewModel.setVoteTaskFinishedListener((resultCode, data) -> { + if (resultCode == NetworkResultCodes.SUCCESSFUL) + Toast.makeText(this, "success", Toast.LENGTH_LONG).show(); + else + Toast.makeText(this, "fail", Toast.LENGTH_LONG).show(); + progressBar.setVisibility(View.GONE); + viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); + }); // observe the chages in data viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> { if (pageIndicatorIndex == null) return; 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 d0682f1e..b7e1ccef 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 @@ -165,6 +165,7 @@ class TopicAdapter extends RecyclerView.Adapter { Poll.Entry[] entries = poll.getEntries(); PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); + holder.optionsLayout.removeAllViews(); if (poll.getAvailableVoteCount() > 1) { for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); @@ -176,10 +177,11 @@ class TopicAdapter extends RecyclerView.Adapter { holder.optionsLayout.setVisibility(View.VISIBLE); } else if (poll.getAvailableVoteCount() == 1) { RadioGroup radioGroup = new RadioGroup(context); - for (Poll.Entry entry : entries) { + for (int i = 0; i < entries.length; i++) { RadioButton radioButton = new RadioButton(context); - radioButton.setText(entry.getEntryName()); - radioButton.setOnClickListener(v -> viewModel.onRadioButtonCLicked(radioGroup.indexOfChild(v))); + radioButton.setId(i); + radioButton.setText(entries[i].getEntryName()); + radioButton.setTextColor(context.getResources().getColor(R.color.primary_text)); radioGroup.addView(radioButton); } holder.optionsLayout.addView(radioGroup); @@ -187,7 +189,6 @@ class TopicAdapter extends RecyclerView.Adapter { holder.optionsLayout.setVisibility(View.VISIBLE); } else { //Showing results - holder.optionsLayout.removeAllViews(); holder.optionsLayout.setVisibility(View.GONE); List valuesToCompare = new ArrayList<>(); for (int i = 0; i < entries.length; i++) { @@ -221,8 +222,13 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.invalidate(); holder.voteChart.setVisibility(View.VISIBLE); } - if (poll.getRemoveVoteUrl() != null) holder.removeVotesButton.setVisibility(View.VISIBLE); - else holder.removeVotesButton.setVisibility(View.GONE); + if (poll.getRemoveVoteUrl() != null) { + holder.removeVotesButton.setOnClickListener(v -> { + viewModel.loadUrl(poll.getRemoveVoteUrl()); + viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); + }); + holder.removeVotesButton.setVisibility(View.VISIBLE); + } else holder.removeVotesButton.setVisibility(View.GONE); if (poll.getShowVoteResultsUrl() != null) { holder.showPollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowVoteResultsUrl())); holder.showPollResultsButton.setVisibility(View.VISIBLE); @@ -232,8 +238,10 @@ class TopicAdapter extends RecyclerView.Adapter { holder.hidePollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowOptionsUrl())); holder.hidePollResultsButton.setVisibility(View.VISIBLE); } else holder.hidePollResultsButton.setVisibility(View.GONE); - if (poll.getPollFormUrl() != null) holder.submitButton.setVisibility(View.VISIBLE); - else holder.submitButton.setVisibility(View.GONE); + if (poll.getPollFormUrl() != null) { + holder.submitButton.setOnClickListener(v -> viewModel.submitVote(holder.optionsLayout)); + holder.submitButton.setVisibility(View.VISIBLE); + } else holder.submitButton.setVisibility(View.GONE); } else { Post currentPost = (Post) topicItems.get(position); if (currentHolder instanceof PostViewHolder) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java index 41563ae5..b277d2bd 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java @@ -12,8 +12,8 @@ import okhttp3.Response; public class DeleteTask extends NetworkTask { - public DeleteTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public DeleteTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } @Override @@ -28,7 +28,7 @@ public class DeleteTask extends NetworkTask { } @Override - protected Void performTask(Document document) { + protected Void performTask(Document document, Response response) { return null; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java new file mode 100644 index 00000000..886264d6 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java @@ -0,0 +1,52 @@ +package gr.thmmy.mthmmy.activities.topic.tasks; + +import org.jsoup.nodes.Document; + +import java.io.IOException; +import java.util.Arrays; + +import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import timber.log.Timber; + +public class SubmitVoteTask extends NetworkTask { + + private int[] votes; + + public SubmitVoteTask(int... votes) { + this.votes = votes; + } + + @Override + protected Response sendRequest(OkHttpClient client, String... input) throws IOException { + MultipartBody.Builder postBodyBuilder = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("sc", input[1]); + for (int vote : votes) { + postBodyBuilder.addFormDataPart("options[]", Integer.toString(vote)); + } + Timber.d("response" + Arrays.toString(votes)); + + Request voteRequest = new Request.Builder() + .url(input[0]) + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") + .post(postBodyBuilder.build()) + .build(); + return client.newCall(voteRequest).execute(); + } + + @Override + protected Void performTask(Document document, Response response) { + return null; + } + + @Override + protected int getResultCode(Response response, Void data) { + Timber.d("response" + response); + return NetworkResultCodes.SUCCESSFUL; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java index 82b535b6..d20d29dc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java @@ -4,77 +4,77 @@ import android.os.AsyncTask; public abstract class ExternalAsyncTask extends AsyncTask { - protected OnParseTaskStartedListener onParseTaskStartedListener; - protected OnParseTaskCancelledListener onParseTaskCancelledListener; - protected OnParseTaskFinishedListener onParseTaskFinishedListener; + protected OnTaskStartedListener onTaskStartedListener; + protected OnTaskCancelledListener onTaskCancelledListener; + protected OnTaskFinishedListener onTaskFinishedListener; @Override protected void onPreExecute() { - if (onParseTaskStartedListener != null) - onParseTaskStartedListener.onParseStart(); + if (onTaskStartedListener != null) + onTaskStartedListener.onTaskStarted(); else super.onPreExecute(); } @Override protected void onCancelled() { - if (onParseTaskCancelledListener != null) - onParseTaskCancelledListener.onParseCancel(); + if (onTaskCancelledListener != null) + onTaskCancelledListener.onTaskCanceled(); else super.onCancelled(); } @Override protected void onCancelled(V v) { - if (onParseTaskCancelledListener != null) - onParseTaskCancelledListener.onParseCancel(); + if (onTaskCancelledListener != null) + onTaskCancelledListener.onTaskCanceled(); else super.onCancelled(); } @Override protected void onPostExecute(V v) { - if (onParseTaskFinishedListener != null) - onParseTaskFinishedListener.onParseFinish(v); + if (onTaskFinishedListener != null) + onTaskFinishedListener.onTaskFinished(v); else super.onPostExecute(v); } - public ExternalAsyncTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; - this.onParseTaskCancelledListener = onParseTaskCancelledListener; - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public ExternalAsyncTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, + OnTaskFinishedListener onTaskFinishedListener) { + this.onTaskStartedListener = onTaskStartedListener; + this.onTaskCancelledListener = onTaskCancelledListener; + this.onTaskFinishedListener = onTaskFinishedListener; } - public ExternalAsyncTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public ExternalAsyncTask(OnTaskStartedListener onTaskStartedListener, OnTaskFinishedListener onTaskFinishedListener) { + this.onTaskStartedListener = onTaskStartedListener; + this.onTaskFinishedListener = onTaskFinishedListener; } public ExternalAsyncTask() { } - public void setOnParseTaskStartedListener(OnParseTaskStartedListener onParseTaskStartedListener) { - this.onParseTaskStartedListener = onParseTaskStartedListener; + public void setOnTaskStartedListener(OnTaskStartedListener onTaskStartedListener) { + this.onTaskStartedListener = onTaskStartedListener; } - public void setOnParseTaskCancelledListener(OnParseTaskCancelledListener onParseTaskCancelledListener) { - this.onParseTaskCancelledListener = onParseTaskCancelledListener; + public void setOnTaskCancelledListener(OnTaskCancelledListener onTaskCancelledListener) { + this.onTaskCancelledListener = onTaskCancelledListener; } - public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public void setOnTaskFinishedListener(OnTaskFinishedListener onTaskFinishedListener) { + this.onTaskFinishedListener = onTaskFinishedListener; } - public interface OnParseTaskStartedListener { - void onParseStart(); + public interface OnTaskStartedListener { + void onTaskStarted(); } - public interface OnParseTaskCancelledListener { - void onParseCancel(); + public interface OnTaskCancelledListener { + void onTaskCanceled(); } - public interface OnParseTaskFinishedListener { - void onParseFinish(V result); + public interface OnTaskFinishedListener { + void onTaskFinished(V result); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java index 6793120a..cb613f26 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java @@ -14,17 +14,17 @@ import timber.log.Timber; public abstract class NetworkTask extends ExternalAsyncTask> { - protected OnParseTaskFinishedListener onParseTaskFinishedListener; + protected OnNetworkTaskFinishedListener onNetworkTaskFinishedListener; - public NetworkTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskCancelledListener, null); - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public NetworkTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, + OnNetworkTaskFinishedListener onNetworkTaskFinishedListener) { + super(onTaskStartedListener, onTaskCancelledListener, null); + this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener; } - public NetworkTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, null); - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public NetworkTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onNetworkTaskFinishedListener) { + super(onTaskStartedListener, null); + this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener; } public NetworkTask() {} @@ -49,7 +49,7 @@ public abstract class NetworkTask extends ExternalAsyncTask return new Parcel<>(NetworkResultCodes.NETWORK_ERROR, null); } try { - T data = performTask(Jsoup.parse(responseBodyString)); + T data = performTask(Jsoup.parse(responseBodyString), response); int resultCode = getResultCode(response, data); return new Parcel<>(resultCode, data); } catch (ParseException pe) { @@ -63,8 +63,8 @@ public abstract class NetworkTask extends ExternalAsyncTask @Override protected void onPostExecute(Parcel tParcel) { - if (onParseTaskFinishedListener != null) - onParseTaskFinishedListener.onParseFinish(tParcel.getResultCode(), tParcel.getData()); + if (onNetworkTaskFinishedListener != null) + onNetworkTaskFinishedListener.onNetworkTaskFinished(tParcel.getResultCode(), tParcel.getData()); else super.onPostExecute(tParcel); } @@ -77,15 +77,15 @@ public abstract class NetworkTask extends ExternalAsyncTask return client.newCall(request).execute(); } - protected abstract T performTask(Document document); + protected abstract T performTask(Document document, Response response); protected abstract int getResultCode(Response response, T data); - public void setOnParseTaskFinishedListener(OnParseTaskFinishedListener onParseTaskFinishedListener) { - this.onParseTaskFinishedListener = onParseTaskFinishedListener; + public void setOnNetworkTaskFinishedListener(OnNetworkTaskFinishedListener onNetworkTaskFinishedListener) { + this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener; } - public interface OnParseTaskFinishedListener { - void onParseFinish(int resultCode, T data); + public interface OnNetworkTaskFinishedListener { + void onNetworkTaskFinished(int resultCode, T data); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index 51749f2a..def14c2f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -3,28 +3,29 @@ package gr.thmmy.mthmmy.utils.parsing; import org.jsoup.nodes.Document; import gr.thmmy.mthmmy.utils.NetworkTask; +import okhttp3.Response; public abstract class NewParseTask extends NetworkTask { - public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskCancelledListener onParseTaskCancelledListener, - OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskCancelledListener, onParseTaskFinishedListener); + public NewParseTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, + OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onTaskCancelledListener, onParseTaskFinishedListener); } - public NewParseTask(OnParseTaskStartedListener onParseTaskStartedListener, OnParseTaskFinishedListener onParseTaskFinishedListener) { - super(onParseTaskStartedListener, onParseTaskFinishedListener); + public NewParseTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); } public NewParseTask() {} @Override - protected final T performTask(Document document) { + protected final T performTask(Document document, Response response) { try { - return parse(document); + return parse(document, response); } catch (Exception e) { throw new ParseException("Parse failed.", e); } } - protected abstract T parse (Document document) throws ParseException; + protected abstract T parse (Document document, Response response) throws ParseException; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java index 804c9e85..52669582 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java @@ -181,9 +181,10 @@ public class ParseHelpers { * @return the base URL of the given topic */ public static String getBaseURL(String topicURL) { - Matcher baseUrlMatcher = Pattern.compile(".+topic=[0-9]+").matcher(topicURL); + String forumUrl = "https://www.thmmy.gr/smf/index.php?"; + Matcher baseUrlMatcher = Pattern.compile("topic=[0-9]+").matcher(topicURL); if (baseUrlMatcher.find()) - return topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end()); + return forumUrl + topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end()); else return ""; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 5bc1f894..540d4917 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -5,6 +5,9 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.RadioGroup; import java.util.ArrayList; @@ -16,12 +19,17 @@ import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReplyResult; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; +import gr.thmmy.mthmmy.activities.topic.tasks.SubmitVoteTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTaskResult; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.session.SessionManager; +import gr.thmmy.mthmmy.utils.ExternalAsyncTask; +import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -44,7 +52,6 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa * holds the adapter position of the post being edited */ private int postBeingEditedPosition; - private ArrayList selectedVoteIndices = new ArrayList<>(); private TopicTask currentTopicTask; private PrepareForEditTask currentPrepareForEditTask; @@ -52,12 +59,14 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa //callbacks for topic activity private TopicTask.TopicTaskObserver topicTaskObserver; - private DeleteTask.OnParseTaskStartedListener deleteTaskStartedListener; - private DeleteTask.OnParseTaskFinishedListener deleteTaskFinishedListener; + private ExternalAsyncTask.OnTaskStartedListener deleteTaskStartedListener; + private NetworkTask.OnNetworkTaskFinishedListener deleteTaskFinishedListener; private ReplyTask.ReplyTaskCallbacks replyFinishListener; private PrepareForEditTask.PrepareForEditCallbacks prepareForEditCallbacks; private EditTask.EditTaskCallbacks editTaskCallbacks; private PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks; + private ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener; + private NetworkTask.OnNetworkTaskFinishedListener voteTaskFinishedListener; /** * Holds the value (index) of the page to be requested when a user interaction with bottom @@ -106,16 +115,25 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } } - public void viewVoteResults() { - if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); - Timber.i("Viewing poll results"); - loadUrl(ParseHelpers.getBaseURL(topicUrl) + ";viewResults"); - } - - public void loadBaseUrl() { - if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); - Timber.i("Viewing poll results"); - loadUrl(ParseHelpers.getBaseURL(topicUrl)); + public void submitVote(LinearLayout optionsLayout) { + if (topicItems.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); + ArrayList votes = new ArrayList<>(); + if (optionsLayout.getChildAt(0) instanceof RadioGroup) { + RadioGroup optionsRadioGroup = (RadioGroup) optionsLayout.getChildAt(0); + votes.add(optionsRadioGroup.getCheckedRadioButtonId()); + } else if (optionsLayout.getChildAt(0) instanceof CheckBox) { + for (int i = 0; i < optionsLayout.getChildCount(); i++) { + if (((CheckBox) optionsLayout.getChildAt(i)).isChecked()) + votes.add(i); + } + } + int[] votesArray = new int[votes.size()]; + for (int i = 0; i < votes.size(); i++) votesArray[i] = votes.get(i); + Poll poll = (Poll) topicItems.getValue().get(0); + SubmitVoteTask submitVoteTask = new SubmitVoteTask(votesArray); + submitVoteTask.setOnTaskStartedListener(voteTaskStartedListener); + submitVoteTask.setOnNetworkTaskFinishedListener(voteTaskFinishedListener); + submitVoteTask.execute(poll.getPollFormUrl(), poll.getSc()); } public void prepareForReply() { @@ -259,17 +277,16 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) performPageChange(); } - public void onVoteCheckboxClicked(int index, boolean checked) { - if (checked) selectedVoteIndices.add(index); - else selectedVoteIndices.remove(index); - } + // <-------------Just getters, setters and helper methods below here----------------> + - public void onRadioButtonCLicked(int index) { - selectedVoteIndices.clear(); - selectedVoteIndices.add(index); + public void setVoteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener) { + this.voteTaskStartedListener = voteTaskStartedListener; } - // <-------------Just getters, setters and helper methods below here----------------> + public void setVoteTaskFinishedListener(NetworkTask.OnNetworkTaskFinishedListener voteTaskFinishedListener) { + this.voteTaskFinishedListener = voteTaskFinishedListener; + } public MutableLiveData getTopicViewers() { return topicViewers; @@ -339,11 +356,11 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } - public void setDeleteTaskStartedListener(DeleteTask.OnParseTaskStartedListener deleteTaskStartedListener) { + public void setDeleteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener deleteTaskStartedListener) { this.deleteTaskStartedListener = deleteTaskStartedListener; } - public void setDeleteTaskFinishedListener(DeleteTask.OnParseTaskFinishedListener deleteTaskFinishedListener) { + public void setDeleteTaskFinishedListener(NetworkTask.OnNetworkTaskFinishedListener deleteTaskFinishedListener) { this.deleteTaskFinishedListener = deleteTaskFinishedListener; } From 687e4a42f05da2ab90f272227b4a35faa5c08635 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Mon, 24 Sep 2018 13:12:57 +0300 Subject: [PATCH 146/180] polish poll tasks, set chart start at 0 --- .../activities/topic/TopicActivity.java | 30 +++++++++++---- .../mthmmy/activities/topic/TopicAdapter.java | 6 +-- .../topic/tasks/RemoveVoteTask.java | 20 ++++++++++ .../topic/tasks/SubmitVoteTask.java | 4 -- .../mthmmy/viewmodel/TopicViewModel.java | 38 ++++++++++++++++--- 5 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java 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 4a997e49..c21a5b05 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 @@ -50,7 +50,6 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; -import gr.thmmy.mthmmy.utils.ExternalAsyncTask; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.NetworkTask; @@ -423,7 +422,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) { autoIncrement = false; paginationEnabled(true); - viewModel.performPageChange(); + viewModel.loadPageIndicated(); } else if (rect != null && event.getAction() == MotionEvent.ACTION_MOVE) { if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { autoIncrement = false; @@ -467,7 +466,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) { autoDecrement = false; paginationEnabled(true); - viewModel.performPageChange(); + viewModel.loadPageIndicated(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (rect != null && !rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { @@ -602,12 +601,27 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo }); viewModel.setVoteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); viewModel.setVoteTaskFinishedListener((resultCode, data) -> { - if (resultCode == NetworkResultCodes.SUCCESSFUL) - Toast.makeText(this, "success", Toast.LENGTH_LONG).show(); - else - Toast.makeText(this, "fail", Toast.LENGTH_LONG).show(); progressBar.setVisibility(View.GONE); - viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); + if (resultCode == NetworkResultCodes.SUCCESSFUL) { + Timber.i("Vote sent"); + viewModel.resetPage(); + } + else { + Timber.w("Failed to send vote"); + Toast.makeText(this, "Failed to send vote", Toast.LENGTH_LONG).show(); + } + }); + viewModel.setRemoveVoteTaskStartedListener(() -> progressBar.setVisibility(ProgressBar.VISIBLE)); + viewModel.setRemoveVoteTaskFinishedListener((resultCode, data) -> { + progressBar.setVisibility(View.GONE); + if (resultCode == NetworkResultCodes.SUCCESSFUL) { + Timber.i("Vote removed"); + viewModel.resetPage(); + } + else { + Timber.w("Failed to remove vote"); + Toast.makeText(this, "Failed to remove vote", Toast.LENGTH_LONG).show(); + } }); // observe the chages in data viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> { 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 b7e1ccef..01759f34 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 @@ -200,6 +200,7 @@ class TopicAdapter extends RecyclerView.Adapter { YAxis yAxisLeft = holder.voteChart.getAxisLeft(); yAxisLeft.setGranularity(1f); yAxisLeft.setTextColor(context.getResources().getColor(R.color.primary_text)); + yAxisLeft.setAxisMinimum(0); YAxis yAxisRight = holder.voteChart.getAxisRight(); yAxisRight.setEnabled(false); @@ -223,10 +224,7 @@ class TopicAdapter extends RecyclerView.Adapter { holder.voteChart.setVisibility(View.VISIBLE); } if (poll.getRemoveVoteUrl() != null) { - holder.removeVotesButton.setOnClickListener(v -> { - viewModel.loadUrl(poll.getRemoveVoteUrl()); - viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + ".0"); - }); + holder.removeVotesButton.setOnClickListener(v -> viewModel.removeVote()); holder.removeVotesButton.setVisibility(View.VISIBLE); } else holder.removeVotesButton.setVisibility(View.GONE); if (poll.getShowVoteResultsUrl() != null) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java new file mode 100644 index 00000000..f94ae027 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java @@ -0,0 +1,20 @@ +package gr.thmmy.mthmmy.activities.topic.tasks; + +import org.jsoup.nodes.Document; + +import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.NetworkTask; +import okhttp3.Response; + +public class RemoveVoteTask extends NetworkTask { + + @Override + protected Void performTask(Document document, Response response) { + return null; + } + + @Override + protected int getResultCode(Response response, Void data) { + return NetworkResultCodes.SUCCESSFUL; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java index 886264d6..ec3773f7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java @@ -3,7 +3,6 @@ package gr.thmmy.mthmmy.activities.topic.tasks; import org.jsoup.nodes.Document; import java.io.IOException; -import java.util.Arrays; import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.NetworkTask; @@ -11,7 +10,6 @@ import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import timber.log.Timber; public class SubmitVoteTask extends NetworkTask { @@ -29,7 +27,6 @@ public class SubmitVoteTask extends NetworkTask { for (int vote : votes) { postBodyBuilder.addFormDataPart("options[]", Integer.toString(vote)); } - Timber.d("response" + Arrays.toString(votes)); Request voteRequest = new Request.Builder() .url(input[0]) @@ -46,7 +43,6 @@ public class SubmitVoteTask extends NetworkTask { @Override protected int getResultCode(Response response, Void data) { - Timber.d("response" + response); return NetworkResultCodes.SUCCESSFUL; } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 540d4917..1175980a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -18,6 +18,7 @@ import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditResult; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReplyResult; +import gr.thmmy.mthmmy.activities.topic.tasks.RemoveVoteTask; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; import gr.thmmy.mthmmy.activities.topic.tasks.SubmitVoteTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; @@ -28,7 +29,6 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.ExternalAsyncTask; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; @@ -67,6 +67,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa private PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks; private ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener; private NetworkTask.OnNetworkTaskFinishedListener voteTaskFinishedListener; + private ExternalAsyncTask.OnTaskStartedListener removeVoteTaskStartedListener; + private NetworkTask.OnNetworkTaskFinishedListener removeVoteTaskFinishedListener; /** * Holds the value (index) of the page to be requested when a user interaction with bottom @@ -102,7 +104,17 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa loadUrl(topicUrl); } - public void performPageChange() { + /** + * In contrasto to {@link TopicViewModel#reloadPage()} this method gets rid of any arguements + * in the url before refreshing + */ + public void resetPage() { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Reseting page"); + loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + String.valueOf(currentPageIndex * 15)); + } + + public void loadPageIndicated() { if (pageIndicatorIndex.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); int pageRequested = pageIndicatorIndex.getValue() - 1; @@ -136,6 +148,14 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa submitVoteTask.execute(poll.getPollFormUrl(), poll.getSc()); } + public void removeVote() { + if (topicItems.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); + RemoveVoteTask removeVoteTask = new RemoveVoteTask(); + removeVoteTask.setOnTaskStartedListener(removeVoteTaskStartedListener); + removeVoteTask.setOnNetworkTaskFinishedListener(removeVoteTaskFinishedListener); + removeVoteTask.execute(((Poll) topicItems.getValue().get(0)).getRemoveVoteUrl()); + } + public void prepareForReply() { if (replyPageUrl.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); @@ -255,7 +275,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() + step); } else pageIndicatorIndex.setValue(pageCount); - if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) performPageChange(); + if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) loadPageIndicated(); } public void decrementPageRequestValue(int step, boolean changePage) { @@ -266,7 +286,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() - step); } else pageIndicatorIndex.setValue(1); - if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) performPageChange(); + if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) loadPageIndicated(); } public void setPageIndicatorIndex(int pageIndicatorIndex, boolean changePage) { @@ -274,12 +294,20 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa throw new NullPointerException("No page has been loaded yet!"); int oldIndicatorIndex = this.pageIndicatorIndex.getValue(); this.pageIndicatorIndex.setValue(pageIndicatorIndex); - if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) performPageChange(); + if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) loadPageIndicated(); } // <-------------Just getters, setters and helper methods below here----------------> + public void setRemoveVoteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener removeVoteTaskStartedListener) { + this.removeVoteTaskStartedListener = removeVoteTaskStartedListener; + } + + public void setRemoveVoteTaskFinishedListener(NetworkTask.OnNetworkTaskFinishedListener removeVoteTaskFinishedListener) { + this.removeVoteTaskFinishedListener = removeVoteTaskFinishedListener; + } + public void setVoteTaskStartedListener(ExternalAsyncTask.OnTaskStartedListener voteTaskStartedListener) { this.voteTaskStartedListener = voteTaskStartedListener; } From 7dcda065a9018464d226a6b18a26c2b8bb5e8fe0 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 25 Sep 2018 22:41:41 +0300 Subject: [PATCH 147/180] fixes: reverse poll results, error when too many votes, remove   when poll has expired, background of emoji keyboard --- .../activities/topic/TopicActivity.java | 66 ++++++++++++++----- .../mthmmy/activities/topic/TopicAdapter.java | 9 ++- .../mthmmy/activities/topic/TopicParser.java | 9 +-- .../activities/topic/tasks/ReplyTask.java | 23 ++----- .../mthmmy/editorview/EmojiKeyboard.java | 1 + .../mthmmy/viewmodel/TopicViewModel.java | 15 ++++- .../main/res/layout/activity_topic_poll.xml | 1 - app/src/main/res/values/strings.xml | 5 +- 8 files changed, 87 insertions(+), 42 deletions(-) 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 c21a5b05..51c7f594 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 @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.app.NotificationManager; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Rect; import android.net.Uri; @@ -36,6 +37,7 @@ import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; +import java.util.function.Consumer; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; @@ -44,6 +46,7 @@ import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.base.BaseActivity; +import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.editorview.EmojiKeyboard; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Post; @@ -52,12 +55,12 @@ import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.NetworkResultCodes; -import gr.thmmy.mthmmy.utils.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; +import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; import static gr.thmmy.mthmmy.services.NotificationService.NEW_POST_TAG; /** @@ -517,7 +520,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } @Override - public void onReplyTaskFinished(boolean success) { + public void onReplyTaskFinished(Posting.REPLY_STATUS replyStatus) { View view = getCurrentFocus(); if (view != null) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); @@ -526,22 +529,49 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo progressBar.setVisibility(ProgressBar.GONE); - if (success) { - Timber.i("Post reply successful"); - replyFAB.show(); - bottomNavBar.setVisibility(View.VISIBLE); - viewModel.setWritingReply(false); - if ((((Post) topicItems.get(topicItems.size() - 1)).getPostNumber() + 1) % 15 == 0) { - Timber.i("Reply was posted in new page. Switching to last page."); - viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + "." + 2147483647); - } else { - viewModel.reloadPage(); - } - } else { - Timber.w("Post reply unsuccessful"); - Toast.makeText(getBaseContext(), "Post failed!", Toast.LENGTH_SHORT).show(); - recyclerView.getChildAt(topicItems.size() - 1).setAlpha(1); - recyclerView.getChildAt(topicItems.size() - 1).setEnabled(true); + switch (replyStatus) { + case SUCCESSFUL: + BaseApplication.getInstance().logFirebaseAnalyticsEvent("post_creation", null); + Timber.i("Post reply successful"); + replyFAB.show(); + bottomNavBar.setVisibility(View.VISIBLE); + viewModel.setWritingReply(false); + if ((((Post) topicItems.get(topicItems.size() - 1)).getPostNumber() + 1) % 15 == 0) { + Timber.i("Reply was posted in new page. Switching to last page."); + viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + "." + 2147483647); + } else { + viewModel.reloadPage(); + } + case NEW_REPLY_WHILE_POSTING: + Timber.i("New reply while writing a reply"); + TopicAdapter.QuickReplyViewHolder replyHolder = (TopicAdapter.QuickReplyViewHolder) + recyclerView.findViewHolderForAdapterPosition(topicItems.size() - 1); + String subject = replyHolder.quickReplySubject.getText().toString(); + String message = replyHolder.replyEditor.getText().toString(); + Runnable addReply = () -> { + viewModel.setWritingReply(true); + topicItems.add(Post.newQuickReply()); + topicAdapter.notifyItemInserted(topicItems.size()); + recyclerView.scrollToPosition(topicItems.size() - 1); + replyFAB.hide(); + bottomNavBar.setVisibility(View.GONE); + TopicAdapter.QuickReplyViewHolder newReplyHolder = (TopicAdapter.QuickReplyViewHolder) + recyclerView.findViewHolderForAdapterPosition(topicItems.size() - 1); + newReplyHolder.quickReplySubject.setText(subject); + newReplyHolder.replyEditor.setText(message); + AlertDialog.Builder builder = new AlertDialog.Builder(TopicActivity.this, + R.style.AppCompatAlertDialogStyleAccent); + builder.setMessage("A new reply was posted before you completed your new post." + + " Please review it and send your reply again") + .setNeutralButton(getString(R.string.ok), (dialog, which) -> dialog.dismiss()) + .show(); + }; + viewModel.reloadPageThen(addReply); + default: + Timber.w("Post reply unsuccessful"); + Toast.makeText(getBaseContext(), "Post failed!", Toast.LENGTH_SHORT).show(); + recyclerView.getChildAt(topicItems.size() - 1).setAlpha(1); + recyclerView.getChildAt(topicItems.size() - 1).setEnabled(true); } } }); 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 01759f34..13d50f9d 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 @@ -166,6 +166,7 @@ class TopicAdapter extends RecyclerView.Adapter { PollViewHolder holder = (PollViewHolder) currentHolder; holder.question.setText(poll.getQuestion()); holder.optionsLayout.removeAllViews(); + holder.errorTooManySelected.setVisibility(View.GONE); if (poll.getAvailableVoteCount() > 1) { for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); @@ -237,7 +238,13 @@ class TopicAdapter extends RecyclerView.Adapter { holder.hidePollResultsButton.setVisibility(View.VISIBLE); } else holder.hidePollResultsButton.setVisibility(View.GONE); if (poll.getPollFormUrl() != null) { - holder.submitButton.setOnClickListener(v -> viewModel.submitVote(holder.optionsLayout)); + holder.submitButton.setOnClickListener(v -> { + if (!viewModel.submitVote(holder.optionsLayout)) { + holder.errorTooManySelected.setText(context.getResources() + .getQuantityText(R.plurals.error_too_many_checked, poll.getAvailableVoteCount())); + holder.errorTooManySelected.setVisibility(View.VISIBLE); + } + }); holder.submitButton.setVisibility(View.VISIBLE); } else holder.submitButton.setVisibility(View.GONE); } else { 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 9c987964..b835472c 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 @@ -495,11 +495,12 @@ public class TopicParser { Element secondRow = tables.get(i).select("tr[class=windowbg]").first(); Element secondColumn = secondRow.child(1); String columnString = secondColumn.outerHtml(); - question = columnString.substring(columnString.indexOf('>') + 1, columnString.indexOf('<', 2)).trim(); + question = columnString.substring(columnString.indexOf('>') + 1, columnString.indexOf('<', 2)) + .replace(" ", " ").trim(); Element form = secondColumn.select("form").first(); if (form != null) { - // english poll in vote mode + // poll in vote mode pollFormUrl = form.attr("action"); sc = form.select("input[name=sc]").first().attr("value"); @@ -530,7 +531,7 @@ public class TopicParser { showVoteResultsUrl = links.first().attr("href"); } } else { - // english poll in results mode + // poll in results mode Elements optionRows = secondColumn.child(0).child(0).select("table").first().child(0).children(); for (int j = 0; j < optionRows.size(); j++) { String optionName = optionRows.get(j).child(0).text(); @@ -539,7 +540,7 @@ public class TopicParser { integerMatcher.find(); int voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), integerMatcher.end())); - entries.add(new Poll.Entry(optionName, voteCount)); + entries.add(0, new Poll.Entry(optionName, voteCount)); } Elements links = secondColumn.select("a"); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java index 033316d2..dfbdbb7f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java @@ -4,6 +4,7 @@ import android.os.AsyncTask; import java.io.IOException; +import gr.thmmy.mthmmy.activities.topic.Posting; import gr.thmmy.mthmmy.base.BaseApplication; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; @@ -14,7 +15,7 @@ import timber.log.Timber; import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; -public class ReplyTask extends AsyncTask { +public class ReplyTask extends AsyncTask { private ReplyTaskCallbacks listener; private boolean includeAppSignature; @@ -29,7 +30,7 @@ public class ReplyTask extends AsyncTask { } @Override - protected Boolean doInBackground(String... args) { + protected Posting.REPLY_STATUS doInBackground(String... args) { final String sentFrommTHMMY = includeAppSignature ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i][/size][/right]" : ""; @@ -52,30 +53,20 @@ public class ReplyTask extends AsyncTask { OkHttpClient client = BaseApplication.getInstance().getClient(); client.newCall(post).execute(); Response response = client.newCall(post).execute(); - switch (replyStatus(response)) { - case SUCCESSFUL: - BaseApplication.getInstance().logFirebaseAnalyticsEvent("post_creation", null); - return true; - case NEW_REPLY_WHILE_POSTING: - //TODO this... - return true; - default: - Timber.e("Malformed post. Request string: %s", post.toString()); - return true; - } + return replyStatus(response); } catch (IOException e) { Timber.e(e, "Post failed."); - return false; + return Posting.REPLY_STATUS.OTHER_ERROR; } } @Override - protected void onPostExecute(Boolean result) { + protected void onPostExecute(Posting.REPLY_STATUS result) { listener.onReplyTaskFinished(result); } public interface ReplyTaskCallbacks { void onReplyTaskStarted(); - void onReplyTaskFinished(boolean result); + void onReplyTaskFinished(Posting.REPLY_STATUS result); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java index 95acec1b..14a63438 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java @@ -152,6 +152,7 @@ public class EmojiKeyboard extends LinearLayout { public void init(Context context, AttributeSet attrs) { LayoutInflater.from(context).inflate(R.layout.emoji_keyboard, this, true); setOrientation(VERTICAL); + setBackgroundColor(getResources().getColor(R.color.primary)); RecyclerView emojiRecyclerview = findViewById(R.id.emoji_recyclerview); emojiRecyclerview.setHasFixedSize(true); diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 1175980a..0e5997e0 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -104,6 +104,17 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa loadUrl(topicUrl); } + public void reloadPageThen(Runnable runnable) { + if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); + Timber.i("Reloading page"); + stopLoading(); + currentTopicTask = new TopicTask(topicTaskObserver, result -> { + TopicViewModel.this.onTopicTaskCompleted(result); + runnable.run(); + }); + currentTopicTask.execute(topicUrl); + } + /** * In contrasto to {@link TopicViewModel#reloadPage()} this method gets rid of any arguements * in the url before refreshing @@ -127,7 +138,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa } } - public void submitVote(LinearLayout optionsLayout) { + public boolean submitVote(LinearLayout optionsLayout) { if (topicItems.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); ArrayList votes = new ArrayList<>(); if (optionsLayout.getChildAt(0) instanceof RadioGroup) { @@ -142,10 +153,12 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa int[] votesArray = new int[votes.size()]; for (int i = 0; i < votes.size(); i++) votesArray[i] = votes.get(i); Poll poll = (Poll) topicItems.getValue().get(0); + if (poll.getAvailableVoteCount() < votesArray.length) return false; SubmitVoteTask submitVoteTask = new SubmitVoteTask(votesArray); submitVoteTask.setOnTaskStartedListener(voteTaskStartedListener); submitVoteTask.setOnNetworkTaskFinishedListener(voteTaskFinishedListener); submitVoteTask.execute(poll.getPollFormUrl(), poll.getSc()); + return true; } public void removeVote() { diff --git a/app/src/main/res/layout/activity_topic_poll.xml b/app/src/main/res/layout/activity_topic_poll.xml index 84a7e275..60b7c96d 100644 --- a/app/src/main/res/layout/activity_topic_poll.xml +++ b/app/src/main/res/layout/activity_topic_poll.xml @@ -28,7 +28,6 @@ android:id="@+id/error_too_many_checked" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/error_too_many_checked" android:textColor="@color/red" android:visibility="gone" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 071bb9dc..310c407f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,7 +61,10 @@ This topic is either missing or off limits to you Remove vote show results - You may only select %d options + + You may only select %d option + You may only select %d options + hide results From c06ade5569bfec1513344a9a167f91a52386a645 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 26 Sep 2018 01:07:12 +0300 Subject: [PATCH 148/180] breaks dammit --- .../java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java | 2 ++ 1 file changed, 2 insertions(+) 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 51c7f594..8b581a05 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 @@ -542,6 +542,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } else { viewModel.reloadPage(); } + break; case NEW_REPLY_WHILE_POSTING: Timber.i("New reply while writing a reply"); TopicAdapter.QuickReplyViewHolder replyHolder = (TopicAdapter.QuickReplyViewHolder) @@ -567,6 +568,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo .show(); }; viewModel.reloadPageThen(addReply); + break; default: Timber.w("Post reply unsuccessful"); Toast.makeText(getBaseContext(), "Post failed!", Toast.LENGTH_SHORT).show(); From b487f5aa350d8d87fca324e13b452e83f824fea0 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Fri, 28 Sep 2018 14:38:27 +0300 Subject: [PATCH 149/180] fix issue #56, update gradle plugin --- .../mthmmy/editorview/AutoFitGridLayout.java | 56 ---- .../thmmy/mthmmy/editorview/EditorView.java | 317 ++++++++++-------- .../editorview/FormatButtonsAdapter.java | 56 ++++ app/src/main/res/layout/editor_view.xml | 128 +------ .../res/layout/format_button_grid_cell.xml | 8 + app/src/main/res/values/attrs.xml | 4 - app/src/main/res/values/dimens.xml | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 9 files changed, 244 insertions(+), 333 deletions(-) delete mode 100644 app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/editorview/FormatButtonsAdapter.java create mode 100644 app/src/main/res/layout/format_button_grid_cell.xml diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java deleted file mode 100644 index 2b3eff99..00000000 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/AutoFitGridLayout.java +++ /dev/null @@ -1,56 +0,0 @@ -package gr.thmmy.mthmmy.editorview; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.widget.GridLayout; - -import gr.thmmy.mthmmy.R; - -public class AutoFitGridLayout extends GridLayout { - private int columnWidth; - private int defaultColumnCount; - - public AutoFitGridLayout(Context context) { - super(context); - init(context, null, 0); - } - - public AutoFitGridLayout(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs, 0); - } - - public AutoFitGridLayout(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs, defStyleAttr); - } - - public void init(Context context, AttributeSet attrs, int defStyleAttr) { - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoFitGridLayout, 0, defStyleAttr); - try { - columnWidth = a.getDimensionPixelSize(R.styleable.AutoFitGridLayout_columnWidth, 0); - - int[] set = {android.R.attr.columnCount}; - a = context.obtainStyledAttributes(attrs, set, 0, defStyleAttr); - defaultColumnCount = a.getInt(0, 6); - } finally { - a.recycle(); - } - setColumnCount(1); - } - - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - super.onMeasure(widthSpec, heightSpec); - - int width = MeasureSpec.getSize(widthSpec); - if (columnWidth > 0 && width > 0) { - int totalSpace = width - getPaddingRight() - getPaddingLeft(); - int columnCount = Math.max(1, totalSpace / columnWidth); - setColumnCount(columnCount); - } else { - setColumnCount(defaultColumnCount); - } - } -} diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index 37fea85b..0cb17141 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -10,9 +10,12 @@ import android.support.annotation.Nullable; import android.support.design.widget.TextInputEditText; import android.support.design.widget.TextInputLayout; import android.support.v7.widget.AppCompatImageButton; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; import android.text.Editable; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.inputmethod.EditorInfo; @@ -80,47 +83,6 @@ public class EditorView extends LinearLayout { return false; }); - emojiButton.setOnClickListener(view -> { - InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); - assert imm != null; - if (emojiKeyboardOwner.isEmojiKeyboardVisible()) { - editText.requestFocus(); - imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); - emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); - } else { - imm.hideSoftInputFromWindow(getWindowToken(), 0); - view.clearFocus(); - emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); - } - emojiKeyboardOwner.setEmojiKeyboardVisible(!emojiKeyboardOwner.isEmojiKeyboardVisible()); - }); - - submitButton = findViewById(R.id.submit_button); - findViewById(R.id.bold_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[b]"); - getText().insert(editText.getSelectionEnd(), "[/b]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); - }); - findViewById(R.id.italic_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[i]"); - getText().insert(editText.getSelectionEnd(), "[/i]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); - }); - findViewById(R.id.underline_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[u]"); - getText().insert(editText.getSelectionEnd(), "[/u]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); - }); - findViewById(R.id.strikethrough_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[s]"); - getText().insert(editText.getSelectionEnd(), "[/s]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); - }); - colors.append(R.id.black, "black"); colors.append(R.id.red, "red"); colors.append(R.id.yellow, "yellow"); @@ -136,114 +98,181 @@ public class EditorView extends LinearLayout { colors.append(R.id.maroon, "maroon"); colors.append(R.id.lime_green, "limegreen"); - findViewById(R.id.text_color_button).setOnClickListener(view -> { - PopupWindow popupWindow = new PopupWindow(view.getContext()); - popupWindow.setHeight(LayoutParams.WRAP_CONTENT); - popupWindow.setWidth(LayoutParams.WRAP_CONTENT); - popupWindow.setFocusable(true); - ScrollView colorPickerScrollview = (ScrollView) LayoutInflater.from(context).inflate(R.layout.editor_view_color_picker, null); - LinearLayout colorPicker = (LinearLayout) colorPickerScrollview.getChildAt(0); - popupWindow.setContentView(colorPickerScrollview); - for (int i = 0; i < colorPicker.getChildCount(); i++) { - TextView child = (TextView) colorPicker.getChildAt(i); - child.setOnClickListener(v -> { + RecyclerView formatButtonsRecyclerview = findViewById(R.id.buttons_recyclerview); + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + float itemWidth = getResources().getDimension(R.dimen.editor_format_button_size) + + getResources().getDimension(R.dimen.editor_format_button_margin_between); + int columns = (int) Math.floor(displayMetrics.widthPixels / itemWidth); + formatButtonsRecyclerview.setLayoutManager(new GridLayoutManager(context, columns)); + formatButtonsRecyclerview.setAdapter(new FormatButtonsAdapter((view, drawableId) -> { + switch (drawableId) { + case R.drawable.ic_format_bold: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[b]"); + getText().insert(editText.getSelectionEnd(), "[/b]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); + break; + } + case R.drawable.ic_format_italic: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[i]"); + getText().insert(editText.getSelectionEnd(), "[/i]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); + break; + } + case R.drawable.ic_format_underlined: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[u]"); + getText().insert(editText.getSelectionEnd(), "[/u]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); + break; + } + case R.drawable.ic_strikethrough_s: { boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[color=" + colors.get(v.getId()) + "]"); - getText().insert(editText.getSelectionEnd(), "[/color]"); + getText().insert(editText.getSelectionStart(), "[s]"); + getText().insert(editText.getSelectionEnd(), "[/s]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); + break; + } + case R.drawable.ic_format_color_text: { + PopupWindow popupWindow = new PopupWindow(view.getContext()); + popupWindow.setHeight(LayoutParams.WRAP_CONTENT); + popupWindow.setWidth(LayoutParams.WRAP_CONTENT); + popupWindow.setFocusable(true); + ScrollView colorPickerScrollview = (ScrollView) LayoutInflater.from(context).inflate(R.layout.editor_view_color_picker, null); + LinearLayout colorPicker = (LinearLayout) colorPickerScrollview.getChildAt(0); + popupWindow.setContentView(colorPickerScrollview); + for (int i = 0; i < colorPicker.getChildCount(); i++) { + TextView child = (TextView) colorPicker.getChildAt(i); + child.setOnClickListener(v -> { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[color=" + colors.get(v.getId()) + "]"); + getText().insert(editText.getSelectionEnd(), "[/color]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); + popupWindow.dismiss(); + }); + } + popupWindow.showAsDropDown(view); + break; + } + case R.drawable.ic_format_size: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[size=10pt]"); + getText().insert(editText.getSelectionEnd(), "[/size]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); + break; + } + case R.drawable.ic_text_format: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[font=Verdana]"); + getText().insert(editText.getSelectionEnd(), "[/font]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); + break; + } + case R.drawable.ic_format_list_bulleted: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[list]\n[li]"); + getText().insert(editText.getSelectionEnd(), "[/li]\n[li][/li]\n[/list]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() - 13 : editText.getSelectionStart() - 23); + break; + } + case R.drawable.ic_format_align_left: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[left]"); + getText().insert(editText.getSelectionEnd(), "[/left]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); + break; + } + case R.drawable.ic_format_align_center: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[center]"); + getText().insert(editText.getSelectionEnd(), "[/center]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 9); + break; + } + case R.drawable.ic_format_align_right: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[right]"); + getText().insert(editText.getSelectionEnd(), "[/right]"); editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); - popupWindow.dismiss(); - }); - } - popupWindow.showAsDropDown(view); - }); - findViewById(R.id.text_size_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[size=10pt]"); - getText().insert(editText.getSelectionEnd(), "[/size]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); - }); - findViewById(R.id.font_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[font=Verdana]"); - getText().insert(editText.getSelectionEnd(), "[/font]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); - }); - findViewById(R.id.unordered_list_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[list]\n[li]"); - getText().insert(editText.getSelectionEnd(), "[/li]\n[li][/li]\n[/list]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() - 13 : editText.getSelectionStart() - 23); - }); - findViewById(R.id.align_left_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[left]"); - getText().insert(editText.getSelectionEnd(), "[/left]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); - }); - findViewById(R.id.align_center_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[center]"); - getText().insert(editText.getSelectionEnd(), "[/center]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 9); - }); - findViewById(R.id.align_right_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[right]"); - getText().insert(editText.getSelectionEnd(), "[/right]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); - }); - findViewById(R.id.link_button).setOnClickListener(view -> { - LinearLayout dialogBody = (LinearLayout) LayoutInflater.from(context) - .inflate(R.layout.dialog_create_link, null); - TextInputLayout linkUrl = dialogBody.findViewById(R.id.link_url_input); - linkUrl.setOnClickListener(view1 -> linkUrl.setError(null)); - TextInputLayout linkText = dialogBody.findViewById(R.id.link_text_input); - linkText.setOnClickListener(view2 -> linkText.setError(null)); - boolean hadTextSelection = editText.hasSelection(); - int start = editText.getSelectionStart(), end = editText.getSelectionEnd(); - if (editText.hasSelection()) { - linkText.getEditText().setText( - editText.getText().toString().substring(editText.getSelectionStart(), editText.getSelectionEnd())); + break; + } + case R.drawable.ic_insert_link: { + LinearLayout dialogBody = (LinearLayout) LayoutInflater.from(context) + .inflate(R.layout.dialog_create_link, null); + TextInputLayout linkUrl = dialogBody.findViewById(R.id.link_url_input); + linkUrl.setOnClickListener(view1 -> linkUrl.setError(null)); + TextInputLayout linkText = dialogBody.findViewById(R.id.link_text_input); + linkText.setOnClickListener(view2 -> linkText.setError(null)); + boolean hadTextSelection = editText.hasSelection(); + int start = editText.getSelectionStart(), end = editText.getSelectionEnd(); + if (editText.hasSelection()) { + linkText.getEditText().setText( + editText.getText().toString().substring(editText.getSelectionStart(), editText.getSelectionEnd())); + } + new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) + .setTitle(R.string.dialog_create_link_title) + .setView(dialogBody) + .setPositiveButton(R.string.ok, (dialog, which) -> { + if (TextUtils.isEmpty(Objects.requireNonNull(linkUrl.getEditText()).getText().toString())) { + linkUrl.setError(context.getString(R.string.input_field_required)); + return; + } + if (TextUtils.isEmpty(Objects.requireNonNull(linkText.getEditText()).getText().toString())) { + linkUrl.setError(context.getString(R.string.input_field_required)); + return; + } + + if (hadTextSelection) editText.getText().delete(start, end); + getText().insert(editText.getSelectionStart(), "[url=" + + Objects.requireNonNull(linkUrl.getEditText()).getText().toString() + "]" + + Objects.requireNonNull(linkText.getEditText()).getText().toString() + "[/url]"); + }) + .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) + .show(); + break; + } + case R.drawable.ic_format_quote: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[quote]"); + getText().insert(editText.getSelectionEnd(), "[/quote]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); + break; + } + case R.drawable.ic_code: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[code]"); + getText().insert(editText.getSelectionEnd(), "[/code]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); + break; + } + case R.drawable.ic_functions: { + boolean hadTextSelection = editText.hasSelection(); + getText().insert(editText.getSelectionStart(), "[tex]"); + getText().insert(editText.getSelectionEnd(), "[/tex]"); + editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 6); + break; + } + default: throw new IllegalArgumentException("Unknown format button click"); } - new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) - .setTitle(R.string.dialog_create_link_title) - .setView(dialogBody) - .setPositiveButton(R.string.ok, (dialog, which) -> { - if (TextUtils.isEmpty(Objects.requireNonNull(linkUrl.getEditText()).getText().toString())) { - linkUrl.setError(context.getString(R.string.input_field_required)); - return; - } - if (TextUtils.isEmpty(Objects.requireNonNull(linkText.getEditText()).getText().toString())) { - linkUrl.setError(context.getString(R.string.input_field_required)); - return; - } + })); - if (hadTextSelection) editText.getText().delete(start, end); - getText().insert(editText.getSelectionStart(), "[url=" + - Objects.requireNonNull(linkUrl.getEditText()).getText().toString() + "]" + - Objects.requireNonNull(linkText.getEditText()).getText().toString() + "[/url]"); - }) - .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) - .show(); - }); - findViewById(R.id.quote_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[quote]"); - getText().insert(editText.getSelectionEnd(), "[/quote]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); - }); - findViewById(R.id.code_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[code]"); - getText().insert(editText.getSelectionEnd(), "[/code]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); - }); - findViewById(R.id.math_button).setOnClickListener(view -> { - boolean hadTextSelection = editText.hasSelection(); - getText().insert(editText.getSelectionStart(), "[tex]"); - getText().insert(editText.getSelectionEnd(), "[/tex]"); - editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 6); + emojiButton.setOnClickListener(view -> { + InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); + assert imm != null; + if (emojiKeyboardOwner.isEmojiKeyboardVisible()) { + editText.requestFocus(); + imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); + emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); + } else { + imm.hideSoftInputFromWindow(getWindowToken(), 0); + view.clearFocus(); + emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); + } + emojiKeyboardOwner.setEmojiKeyboardVisible(!emojiKeyboardOwner.isEmojiKeyboardVisible()); }); + + submitButton = findViewById(R.id.submit_button); } public TextInputEditText getEditText() { diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/FormatButtonsAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/FormatButtonsAdapter.java new file mode 100644 index 00000000..469cf2f6 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/FormatButtonsAdapter.java @@ -0,0 +1,56 @@ +package gr.thmmy.mthmmy.editorview; + +import android.support.annotation.NonNull; +import android.support.v7.widget.AppCompatImageButton; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import gr.thmmy.mthmmy.R; + +public class FormatButtonsAdapter extends RecyclerView.Adapter { + private OnFormatButtonClickListener listener; + + public static final int[] FORMAT_BUTTON_IDS = {R.drawable.ic_format_bold, R.drawable.ic_format_italic, + R.drawable.ic_format_underlined, R.drawable.ic_strikethrough_s, R.drawable.ic_format_color_text, + R.drawable.ic_format_size, R.drawable.ic_text_format, R.drawable.ic_format_list_bulleted, + R.drawable.ic_format_align_left, R.drawable.ic_format_align_center, R.drawable.ic_format_align_right, + R.drawable.ic_insert_link, R.drawable.ic_format_quote, R.drawable.ic_code, R.drawable.ic_functions}; + + public FormatButtonsAdapter(OnFormatButtonClickListener listener) { + this.listener = listener; + } + + @NonNull + @Override + public FormatButtonViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + AppCompatImageButton formatButton = (AppCompatImageButton) LayoutInflater.from(parent.getContext()) + .inflate(R.layout.format_button_grid_cell, parent, false); + return new FormatButtonViewHolder(formatButton); + } + + @Override + public void onBindViewHolder(@NonNull FormatButtonViewHolder holder, int position) { + holder.formatButton.setImageResource(FORMAT_BUTTON_IDS[position]); + holder.formatButton.setOnClickListener(v -> + listener.onFormatButtonClick(v, FORMAT_BUTTON_IDS[holder.getAdapterPosition()])); + } + + @Override + public int getItemCount() { + return FORMAT_BUTTON_IDS.length; + } + + static class FormatButtonViewHolder extends RecyclerView.ViewHolder { + AppCompatImageButton formatButton; + FormatButtonViewHolder(AppCompatImageButton formatButton) { + super(formatButton); + this.formatButton = formatButton; + } + } + + public interface OnFormatButtonClickListener { + void onFormatButtonClick(View view, int drawableId); + } +} diff --git a/app/src/main/res/layout/editor_view.xml b/app/src/main/res/layout/editor_view.xml index ad649e6a..b95ecc61 100644 --- a/app/src/main/res/layout/editor_view.xml +++ b/app/src/main/res/layout/editor_view.xml @@ -4,132 +4,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="wrap_content"/> + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 293db5cd..a086e88b 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -1,9 +1,5 @@ - - - - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index c022ce31..ea69690c 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -10,5 +10,5 @@ 16sp 24sp 24dp - 4dp + 6dp diff --git a/build.gradle b/build.gradle index ee3a2f36..65178d9a 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.android.tools.build:gradle:3.2.0' classpath 'com.google.gms:google-services:4.0.1' classpath 'io.fabric.tools:gradle:1.25.4' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3cae3bf9..07d9d5c1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Apr 07 11:11:36 EEST 2018 +#Fri Sep 28 13:21:54 EEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip From a2303c902f5eaa252055ffafc03a92ed814426d3 Mon Sep 17 00:00:00 2001 From: Apostolof Date: Sat, 6 Oct 2018 20:20:38 +0300 Subject: [PATCH 150/180] Poll parsing fixes --- .../profile/summary/SummaryFragment.java | 2 - .../mthmmy/activities/topic/TopicAdapter.java | 26 +++- .../mthmmy/activities/topic/TopicParser.java | 138 +++++++++--------- .../main/java/gr/thmmy/mthmmy/model/Poll.java | 2 +- 4 files changed, 89 insertions(+), 79 deletions(-) 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 8993fcf0..76380576 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 @@ -180,8 +180,6 @@ public class SummaryFragment extends Fragment { if (profileSummaryRow.contains("@") && (profileSummaryRow.contains("Email") || profileSummaryRow.contains("E-mail"))) { - Timber.d("mpika"); - Timber.d(profileSummaryRow); String email = profileSummaryRow.substring(profileSummaryRow.indexOf(": ") + 6); profileSummaryRow = profileSummaryRow.replace(email, "
" + email + ""); 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 13d50f9d..bbd8f85d 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 @@ -17,8 +17,10 @@ import android.support.v7.app.AlertDialog; import android.support.v7.content.res.AppCompatResources; import android.support.v7.widget.AppCompatButton; import android.support.v7.widget.RecyclerView; +import android.text.Html; import android.text.InputType; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; @@ -41,11 +43,13 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.github.mikephil.charting.charts.HorizontalBarChart; +import com.github.mikephil.charting.components.AxisBase; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.formatter.IAxisValueFormatter; import com.squareup.picasso.Picasso; import java.util.ArrayList; @@ -94,7 +98,7 @@ class TopicAdapter extends RecyclerView.Adapter { private TopicViewModel viewModel; /** - * @param context the context of the {@link RecyclerView} + * @param context the context of the {@link RecyclerView} * @param topicItems List of {@link Post} objects to use */ TopicAdapter(TopicActivity context, List topicItems) { @@ -170,7 +174,13 @@ class TopicAdapter extends RecyclerView.Adapter { if (poll.getAvailableVoteCount() > 1) { for (Poll.Entry entry : entries) { CheckBox checkBox = new CheckBox(context); - checkBox.setText(entry.getEntryName()); + checkBox.setMovementMethod(LinkMovementMethod.getInstance()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + checkBox.setText(Html.fromHtml(entry.getEntryName(), Html.FROM_HTML_MODE_LEGACY)); + } else { + //noinspection deprecation + checkBox.setText(Html.fromHtml(entry.getEntryName())); + } checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); holder.optionsLayout.addView(checkBox); } @@ -181,7 +191,13 @@ class TopicAdapter extends RecyclerView.Adapter { for (int i = 0; i < entries.length; i++) { RadioButton radioButton = new RadioButton(context); radioButton.setId(i); - radioButton.setText(entries[i].getEntryName()); + radioButton.setMovementMethod(LinkMovementMethod.getInstance()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + radioButton.setText(Html.fromHtml(entries[i].getEntryName(), Html.FROM_HTML_MODE_LEGACY)); + } else { + //noinspection deprecation + radioButton.setText(Html.fromHtml(entries[i].getEntryName())); + } radioButton.setTextColor(context.getResources().getColor(R.color.primary_text)); radioGroup.addView(radioButton); } @@ -206,7 +222,7 @@ class TopicAdapter extends RecyclerView.Adapter { yAxisRight.setEnabled(false); XAxis xAxis = holder.voteChart.getXAxis(); - xAxis.setValueFormatter((value, axis) -> entries[(int) value].getEntryName()); + xAxis.setValueFormatter((value, axis) -> Html.fromHtml(entries[(int) value].getEntryName()).toString()); xAxis.setTextColor(context.getResources().getColor(R.color.primary_text)); xAxis.setGranularity(1f); xAxis.setDrawGridLines(false); @@ -752,7 +768,7 @@ class TopicAdapter extends RecyclerView.Adapter { final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton; final HorizontalBarChart voteChart; - public PollViewHolder(View itemView) { + PollViewHolder(View itemView) { super(itemView); question = itemView.findViewById(R.id.question_textview); 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 b835472c..4ebbba5a 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 @@ -1,11 +1,11 @@ package gr.thmmy.mthmmy.activities.topic; import android.graphics.Color; -import android.util.Log; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; import org.jsoup.select.Elements; import java.net.MalformedURLException; @@ -480,84 +480,80 @@ public class TopicParser { private static Poll findPoll(Document topic) { Pattern integerPattern = Pattern.compile("[0-9]+"); - Elements tables = topic.select("table"); - for (int i = 0; i < tables.size(); i++) { - try { - Element image = tables.get(i).child(0).child(0).child(0); - if (image.html().contains("Poll") || image.html().contains("Ψηφοφορία")) { - // has poll in english - String question; - ArrayList entries = new ArrayList<>(); - int availableVoteCount = 0; - String pollFormUrl = null, sc = null, removeVoteUrl = null, showVoteResultsUrl = null, + Element table = topic.select("table.tborder").first(); + try { + String question; + ArrayList entries = new ArrayList<>(); + int availableVoteCount = 0; + String pollFormUrl = null, sc = null, removeVoteUrl = null, showVoteResultsUrl = null, showOptionsUrl = null; - Element secondRow = tables.get(i).select("tr[class=windowbg]").first(); - Element secondColumn = secondRow.child(1); - String columnString = secondColumn.outerHtml(); - question = columnString.substring(columnString.indexOf('>') + 1, columnString.indexOf('<', 2)) - .replace(" ", " ").trim(); - - Element form = secondColumn.select("form").first(); - if (form != null) { - // poll in vote mode - pollFormUrl = form.attr("action"); - sc = form.select("input[name=sc]").first().attr("value"); - - int rowIndex = -1; - Elements possibleEntriesRows = form.child(0).child(0).children(); - for (int j = 0; j < possibleEntriesRows.size(); j++) { - if (possibleEntriesRows.get(j).select("input").size() > 0) { - rowIndex = j; - break; - } - } - String entriesRaw = form.child(0).child(0).child(rowIndex).child(0).html(); - Matcher entryMatcher = Pattern.compile(">[^<]+ 0) { - showVoteResultsUrl = links.first().attr("href"); - } - } else { - // poll in results mode - Elements optionRows = secondColumn.child(0).child(0).select("table").first().child(0).children(); - for (int j = 0; j < optionRows.size(); j++) { - String optionName = optionRows.get(j).child(0).text(); - String voteCountDescription = optionRows.get(j).child(1).text(); - Matcher integerMatcher = integerPattern.matcher(voteCountDescription); - integerMatcher.find(); - int voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), - integerMatcher.end())); - entries.add(0, new Poll.Entry(optionName, voteCount)); - } + if (form != null) { + // poll in vote mode + pollFormUrl = form.attr("action"); + sc = form.select("input[name=sc]").first().attr("value"); - Elements links = secondColumn.select("a"); - if (links != null && links.size() > 0) { - if (links.first().text().equals("Remove Vote") || links.first().text().equals("Αφαίρεση ψήφου")) - removeVoteUrl = links.first().attr("href"); - else if (links.first().text().equals("Voting options") || links.first().text().equals("Επιλογές ψηφοφορίας")) - showOptionsUrl = links.first().attr("href"); - } + List possibleEntriesRows = form.select("td:has(input[id^=options])").first().childNodes(); + for (Node possibleEntry : possibleEntriesRows) { + String possibleEntryHtml = possibleEntry.outerHtml(); + if (!possibleEntryHtml.equals(" ") && !possibleEntryHtml.equals("
") && !possibleEntryHtml.startsWith("tr"); + Elements links; + + if (formTableRows.size() == 3) { + String prompt = formTableRows.first().child(0).text().trim(); + Matcher integerMatcher = integerPattern.matcher(prompt); + if (integerMatcher.find()) { + availableVoteCount = Integer.parseInt(prompt.substring(integerMatcher.start(), integerMatcher.end())); + } + links = formTableRows.get(1).child(1).select("a"); + } else { + availableVoteCount = 1; + links = formTableRows.first().child(1).select("a"); + } + + if (links != null && links.size() > 0) { + showVoteResultsUrl = links.first().attr("href"); + } + } else { + // poll in results mode + Elements entryRows = pollColumn.select("table[cellspacing] tr"); + for (Element entryRow : entryRows) { + Elements entryColumns = entryRow.select("td"); + String optionName = entryColumns.first().html(); + String voteCountDescription = entryColumns.last().text(); + Matcher integerMatcher = integerPattern.matcher(voteCountDescription); + int voteCount = 0; + if (integerMatcher.find()) { + voteCount = Integer.parseInt(voteCountDescription.substring(integerMatcher.start(), + integerMatcher.end())); + } + + entries.add(0, new Poll.Entry(optionName, voteCount)); + } + + Elements links = pollColumn.child(0).child(0).child(0).child(1).select("a"); + if (links != null && links.size() > 0) { + if (links.first().text().equals("Remove Vote") || links.first().text().equals("Αφαίρεση ψήφου")) + removeVoteUrl = links.first().attr("href"); + else if (links.first().text().equals("Voting options") || links.first().text().equals("Επιλογές ψηφοφορίας")) + showOptionsUrl = links.first().attr("href"); + } } + return new Poll(question, entries.toArray(new Poll.Entry[0]), availableVoteCount, + pollFormUrl, sc, removeVoteUrl, showVoteResultsUrl, showOptionsUrl); + } catch (Exception e) { + Timber.v(e, "Could not parse a poll"); } + return null; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java index 071557e9..e0d544f6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Poll.java @@ -22,7 +22,7 @@ public class Poll extends TopicItem { this.showOptionsUrl = showOptionsUrl; } - public int totalVotes() { + private int totalVotes() { int sum = 0; for (Entry entry : entries) { sum += entry.votes; From f62bb59a3e3a2d0bc3bf12068c09022624d774a1 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 7 Oct 2018 13:20:57 +0300 Subject: [PATCH 151/180] poll fixes --- .../mthmmy/activities/topic/TopicAdapter.java | 16 +++++++++++----- .../thmmy/mthmmy/viewmodel/TopicViewModel.java | 3 ++- 2 files changed, 13 insertions(+), 6 deletions(-) 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 bbd8f85d..07b2d111 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 @@ -173,16 +173,21 @@ class TopicAdapter extends RecyclerView.Adapter { holder.errorTooManySelected.setVisibility(View.GONE); if (poll.getAvailableVoteCount() > 1) { for (Poll.Entry entry : entries) { + LinearLayout container = new LinearLayout(context); + container.setOrientation(LinearLayout.HORIZONTAL); CheckBox checkBox = new CheckBox(context); - checkBox.setMovementMethod(LinkMovementMethod.getInstance()); + TextView label = new TextView(context); + label.setMovementMethod(LinkMovementMethod.getInstance()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - checkBox.setText(Html.fromHtml(entry.getEntryName(), Html.FROM_HTML_MODE_LEGACY)); + label.setText(Html.fromHtml(entry.getEntryName(), Html.FROM_HTML_MODE_LEGACY)); } else { //noinspection deprecation - checkBox.setText(Html.fromHtml(entry.getEntryName())); + label.setText(Html.fromHtml(entry.getEntryName())); } checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); - holder.optionsLayout.addView(checkBox); + container.addView(checkBox); + container.addView(label); + holder.optionsLayout.addView(container); } holder.voteChart.setVisibility(View.GONE); holder.optionsLayout.setVisibility(View.VISIBLE); @@ -215,7 +220,7 @@ class TopicAdapter extends RecyclerView.Adapter { data.setColor(context.getResources().getColor(R.color.accent)); YAxis yAxisLeft = holder.voteChart.getAxisLeft(); - yAxisLeft.setGranularity(1f); + yAxisLeft.setGranularity(1); yAxisLeft.setTextColor(context.getResources().getColor(R.color.primary_text)); yAxisLeft.setAxisMinimum(0); YAxis yAxisRight = holder.voteChart.getAxisRight(); @@ -225,6 +230,7 @@ class TopicAdapter extends RecyclerView.Adapter { xAxis.setValueFormatter((value, axis) -> Html.fromHtml(entries[(int) value].getEntryName()).toString()); xAxis.setTextColor(context.getResources().getColor(R.color.primary_text)); xAxis.setGranularity(1f); + xAxis.setLabelCount(entries.length, true); xAxis.setDrawGridLines(false); xAxis.setDrawAxisLine(false); xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 0e5997e0..34aa4972 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -146,7 +146,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa votes.add(optionsRadioGroup.getCheckedRadioButtonId()); } else if (optionsLayout.getChildAt(0) instanceof CheckBox) { for (int i = 0; i < optionsLayout.getChildCount(); i++) { - if (((CheckBox) optionsLayout.getChildAt(i)).isChecked()) + LinearLayout container = (LinearLayout) optionsLayout.getChildAt(i); + if (((CheckBox) container.getChildAt(0)).isChecked()) votes.add(i); } } From 19cd76a5c310244c665b33b7f6fac095a048c5af Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sun, 7 Oct 2018 17:28:17 +0300 Subject: [PATCH 152/180] Privacy Policy Init --- PRIVACY.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 PRIVACY.md diff --git a/PRIVACY.md b/PRIVACY.md new file mode 100644 index 00000000..7b560b40 --- /dev/null +++ b/PRIVACY.md @@ -0,0 +1,76 @@ +# Privacy Policy + +*Effective date: 7/10/2018* + +Thmmy No Life ("us", "we", or "our") developed the mTHMMY mobile app (the "App") as an open source application. It is provided by us at no cost and is intended for use as is. + +As a user of the App, your privacy is protected and we feel a strong commitment to protect your privacy. The purpose of this Privacy Policy is to inform you about the collection, use and disclosure of your data, and the choices you have associated with them. + +## Data processing + +To be able to offer you all functions and services of the App in the most convenient way possible and to continuously improve it, we use a number of different cloud services. This means we will transfer your data to a third party – the cloud services provider. + +Google Ireland Limited ("Google"), with offices at Gordon House, Barrow Street, Dublin 4, Ireland and, more specifically, Firebase, a Google subsidiary with its registered office in San Francisco, CA, U.S.A., is a third party – the cloud services provider – that stores and processes your data on our behalf (the "processor", as defined in Article 4, GDPR). + +### Location of processing + +The majority of Firebase services run on global Google infrastructure. They could process data at any of the Google Cloud Platform locations or Google data center locations, within or outside the European Union (EU). + +The Commission Decision (EU) 2016/1250 of 12.07.2016 allows the transfer of data from an EU controller or processor of orders to organizations in the US that have committed themselves to adhere to the framework principles of the EU-US Privacy Shield (https://www.privacyshield.gov), including the additional principles, by way of self-certification with the US Department of Commerce. Google is subject to these principles through self-certification with the U.S. Department of Commerce. + +### General Information + +* The Firebase services that we use collect and further process anonymized information, data with no personally identifiable information which can be used to trace its source so that the people whom it describes can remain anonymous. These data are not subject to the same treatment as are personal data, particularly with regards to any desire you might have for accessing it, rectifying it or erasing it (Article 11, GDPR). +* Firebase uses the Instance ID of your mobile device to identify individual installations of this mobile app. Since each Instance ID is unique to a particular application and device, they give Firebase a way to refer to specific instances of the App. +* Your IP address transmitted by the App in the context of Firebase will not be merged with other collected data. +* Legal basis for the use of Firebase is Article 6 Par. 1 S. 1 letter (a) or (f), GDPR. + +The use of each Firebase service is explained below: + +### Firebase Cloud Messaging + +* **Purpose**: This service is essential for the funcionality of the App. It uses anonymous push notification tokens in order to determine which devices to deliver the appropriate messages to. +* **Data collected**: Instance IDs. +* **Consent**: You will be prompted to agree to the use of this service when you open the App for the first time. +* **Retention**: Firebase retains Instance IDs until we make an API call for deletion. After the call, data are removed from live and backup systems within 180 days. + +### Firebase Crashlytics + +* **Purpose**: This service automatically collects and delivers analyses of errors and system crashes in real time and displays them in the Firebase Console. This helps us maintain the App and improve its stability. +* **Data collected**: Instance IDs and crash reports with information about register codes and your device, e.g. type of device and version of operating system. For more information: https://try.crashlytics.com/security/ +* **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable it from the Settings inside the App. +* **Retention**: Crash traces and their associated identifiers are kept for 90 days. + +### Google Analytics for Firebase + +* **Purpose**: This service provides analytics and attribution information for statistical purposes. The precise information collected can vary by the device and environment. +* **Data collected**: Instance IDs, Android IDs, Analytics App Instance IDs and custom events created by us. For more information: https://support.google.com/firebase/answer/6318039 +* **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable (and clear all collected data) from the Settings inside the App. +* **Retention**: ID-associated data are retained for 60 days. Aggregate reporting and campaign data are retained without automatic expiration. + +You can find further information on the data use by Google through Firebase following the links below: +https://firebase.google.com/terms/ +https://firebase.google.com/terms/data-processing-terms +https://firebase.google.com/support/privacy/ +https://firebase.google.com/support/privacy/manage-iids + +## Other data + +* When downloading the mobile app, the necessary information is transferred to the App Store (Google Play), i.e. in particular the name, e-mail address and customer number of your customer account, time of download, payment information and the individual device identification number. We have no influence on this data collection and shall not be responsible for it. We only process the data if it is necessary for downloading the mobile app to your mobile device. +* The App provides functionality to login to thmmy.gr through an encrypted connection. This process generates session cookies that are stored on your device. Those cookies contain the same information as those that would be generated if you logged in using a web browser and we have no influence on them. Any other personal information that the App collects from you from thmmy.gr is only stored locally and never transmitted. You can delete all the data related to thmmy.gr anytime you wish, by logging out or clearing the App's data from your device's Settings. + +## About thmmy.gr + +We have neither influence, nor responsibility on anything you read, write, download or upload by interacting with thmmy.gr through the App. For more information you can also read the Terms of Service of thmmy.gr at https://www.thmmy.gr/smf/index.php?topic=52522. + +## Third-Party Links + +mTHMMY may contain links to third-party websites. Any access to and use of such linked websites is not governed by this Policy, but instead is governed by the privacy policies of those third party websites. We are not responsible for the information practices of such third party websites. + +## Policy Updates + +We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at https://github.com/ThmmyNoLife/mTHMMY/blob/develop/PRIVACY.md. + +## Contact Us + +If you have any question about our Privacy Policy, please contact us at thmmynolife@gmail.com. From 0ff66afda738991571265788adcb62536b94613b Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 7 Oct 2018 17:47:16 +0300 Subject: [PATCH 153/180] fix error when selecting too many vote options --- .../java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java | 3 ++- .../main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) 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 07b2d111..18cab71c 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 @@ -263,7 +263,8 @@ class TopicAdapter extends RecyclerView.Adapter { holder.submitButton.setOnClickListener(v -> { if (!viewModel.submitVote(holder.optionsLayout)) { holder.errorTooManySelected.setText(context.getResources() - .getQuantityText(R.plurals.error_too_many_checked, poll.getAvailableVoteCount())); + .getQuantityString(R.plurals.error_too_many_checked, poll.getAvailableVoteCount(), + poll.getAvailableVoteCount())); holder.errorTooManySelected.setVisibility(View.VISIBLE); } }); diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 34aa4972..ec875274 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -10,6 +10,8 @@ import android.widget.LinearLayout; import android.widget.RadioGroup; import java.util.ArrayList; +import java.util.Arrays; +import java.util.TimerTask; import gr.thmmy.mthmmy.activities.settings.SettingsActivity; import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; @@ -144,7 +146,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa if (optionsLayout.getChildAt(0) instanceof RadioGroup) { RadioGroup optionsRadioGroup = (RadioGroup) optionsLayout.getChildAt(0); votes.add(optionsRadioGroup.getCheckedRadioButtonId()); - } else if (optionsLayout.getChildAt(0) instanceof CheckBox) { + } else if (optionsLayout.getChildAt(0) instanceof LinearLayout) { for (int i = 0; i < optionsLayout.getChildCount(); i++) { LinearLayout container = (LinearLayout) optionsLayout.getChildAt(i); if (((CheckBox) container.getChildAt(0)).isChecked()) From 5c6466ad2e1a53237e72295b0d44a7f23a0a9abb Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 8 Oct 2018 17:03:19 +0300 Subject: [PATCH 154/180] Added privacy-related settings --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 7 +- .../activities/board/BoardActivity.java | 2 +- .../activities/settings/SettingsActivity.java | 2 +- .../activities/settings/SettingsFragment.java | 57 ++++++++++++--- .../activities/topic/TopicActivity.java | 3 - .../mthmmy/activities/topic/TopicAdapter.java | 2 - .../topic/tasks/TopicTaskResult.java | 1 - .../gr/thmmy/mthmmy/base/BaseActivity.java | 70 +++++++++---------- .../gr/thmmy/mthmmy/base/BaseApplication.java | 50 ++++++++----- .../mthmmy/services/NotificationService.java | 9 +++ .../mthmmy/utils/parsing/ParseHelpers.java | 2 - .../mthmmy/viewmodel/TopicViewModel.java | 4 +- app/src/main/res/values/strings.xml | 10 ++- app/src/main/res/xml/app_preferences.xml | 49 +++++++------ 15 files changed, 163 insertions(+), 109 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5baea52e..81b88eb7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,13 +4,13 @@ apply plugin: 'com.android.application' apply plugin: 'io.fabric' android { - compileSdkVersion 27 + compileSdkVersion 28 defaultConfig { vectorDrawables.useSupportLibrary = true applicationId "gr.thmmy.mthmmy" minSdkVersion 19 - targetSdkVersion 27 + targetSdkVersion 28 versionCode 13 versionName "1.4.1" archivesBaseName = "mTHMMY-v$versionName" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3b37c299..72b99fbc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,9 +17,10 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - + + + + { + 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; + } else + startLoginActivity(); + return true; - } }) .build(); @@ -360,12 +358,8 @@ public abstract class BaseActivity extends AppCompatActivity { } } 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 + startLoginActivity(); + else new LogoutTask().execute(); } else if (drawerItem.equals(ABOUT_ID)) { if (!(BaseActivity.this instanceof AboutActivity)) { @@ -533,18 +527,15 @@ public abstract class BaseActivity extends AppCompatActivity { } else { thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp); } - thisPageBookmarkImageButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (thisPageBookmark.matchExists(boardsBookmarked)) { - thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp); - Toast.makeText(getBaseContext(), "Bookmark removed", Toast.LENGTH_SHORT).show(); - } else { - thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp); - Toast.makeText(getBaseContext(), "Bookmark added", Toast.LENGTH_SHORT).show(); - } - toggleBoardToBookmarks(thisPageBookmark); + thisPageBookmarkImageButton.setOnClickListener(view -> { + if (thisPageBookmark.matchExists(boardsBookmarked)) { + thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp); + Toast.makeText(getBaseContext(), "Bookmark removed", Toast.LENGTH_SHORT).show(); + } else { + thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp); + Toast.makeText(getBaseContext(), "Bookmark added", Toast.LENGTH_SHORT).show(); } + toggleBoardToBookmarks(thisPageBookmark); }); } @@ -743,4 +734,11 @@ public abstract class BaseActivity extends AppCompatActivity { protected void setMainActivity(MainActivity mainActivity) { this.mainActivity = mainActivity; } + + private void startLoginActivity(){ + Intent intent = new Intent(BaseActivity.this, LoginActivity.class); + startActivity(intent); + finish(); + overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out); + } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index dbd760a7..0f74807d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -39,6 +39,8 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import timber.log.Timber; +import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SETTINGS_SHARED_PREFS; + public class BaseApplication extends Application { private static BaseApplication baseApplication; //BaseApplication singleton @@ -49,11 +51,10 @@ public class BaseApplication extends Application { private OkHttpClient client; private SessionManager sessionManager; - //Shared Preferences - private final String SHARED_PREFS_NAME = "ThmmySharedPrefs"; + private final String SHARED_PREFS = "ThmmySharedPrefs"; //Display Metrics - private static float dpHeight, dpWidth; + private static float dpWidth; public static BaseApplication getInstance() { return baseApplication; @@ -64,22 +65,35 @@ public class BaseApplication extends Application { super.onCreate(); baseApplication = this; //init singleton - // Set up Crashlytics, disabled for debug builds - Crashlytics crashlyticsKit = new Crashlytics.Builder() - .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) - .build(); - // Initialize Fabric with the debug-disabled crashlytics. - Fabric.with(this, crashlyticsKit); - // Initialize timber + // Initialize Timber if (BuildConfig.DEBUG) Timber.plant(new Timber.DebugTree()); else Timber.plant(new CrashReportingTree()); - // Analytics init + //Shared Preferences + SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE); + SharedPreferences settingsSharedPrefs = getSharedPreferences(SETTINGS_SHARED_PREFS, Context.MODE_PRIVATE); + + // Set up Crashlytics, disabled for debug builds + if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)) { + Crashlytics crashlyticsKit = new Crashlytics.Builder() + .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) + .build(); + // Initialize Fabric with the debug-disabled Crashlytics. + Fabric.with(this, crashlyticsKit); + Timber.i("Starting app with Crashlytics enabled."); + } else + Timber.i("Starting app with Crashlytics disabled."); + firebaseAnalytics = FirebaseAnalytics.getInstance(this); + boolean enableAnalytics = settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_analytics_enable_key), false); + firebaseAnalytics.setAnalyticsCollectionEnabled(enableAnalytics); + if(enableAnalytics) + Timber.i("Starting app with Analytics enabled."); + else + Timber.i("Starting app with Analytics disabled."); - SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE); SharedPrefsCookiePersistor sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(getApplicationContext()); PersistentCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor); client = new OkHttpClient.Builder() @@ -137,7 +151,6 @@ public class BaseApplication extends Application { }); DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics(); - dpHeight = displayMetrics.heightPixels / displayMetrics.density; dpWidth = displayMetrics.widthPixels / displayMetrics.density; } @@ -145,8 +158,13 @@ public class BaseApplication extends Application { firebaseAnalytics.logEvent(event, params); } - //Getters + public void firebaseAnalyticsCollection(boolean enabled) { + firebaseAnalytics.setAnalyticsCollectionEnabled(enabled); + if(!enabled) + firebaseAnalytics.resetAnalyticsData(); + } + //Getters public OkHttpClient getClient() { return client; } @@ -155,10 +173,6 @@ public class BaseApplication extends Application { return sessionManager; } - public float getDpHeight() { - return dpHeight; - } - public float getDpWidth() { return dpWidth; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java index 8f27c963..a383e282 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java +++ b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java @@ -226,4 +226,13 @@ public class NotificationService extends FirebaseMessagingService { } + /** + * Called if InstanceID token is updated. Note that this is called when the InstanceID token + * is initially generated so this is where you would retrieve the token. + */ + @Override + public void onNewToken(String s) { + super.onNewToken(s); + Timber.i("InstanceID token updated (onNewToken)"); + } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java index 52669582..2208ff04 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java @@ -8,8 +8,6 @@ import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; -import timber.log.Timber; - /** * This class consists exclusively of static classes (enums) and methods (excluding methods of inner * classes). It can be used to resolve a page's language and state or fix embedded videos html code. diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index ec875274..530cdc9d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -10,12 +10,10 @@ import android.widget.LinearLayout; import android.widget.RadioGroup; import java.util.ArrayList; -import java.util.Arrays; -import java.util.TimerTask; import gr.thmmy.mthmmy.activities.settings.SettingsActivity; -import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; import gr.thmmy.mthmmy.activities.topic.tasks.DeleteTask; +import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditResult; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 310c407f..3c133b80 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -152,8 +152,6 @@ Default home tab Notifications - Vibration Notifications led Enables/disables the notifications led (if the device has one) @@ -168,6 +166,14 @@ App signature Appends an \"uploaded from mTHMMY\" message to the descriptions of your uploads + Privacy + pref_privacy_crashlytics_enable_key + Crash data reports + Automatically send us anonymized reports of errors and crashes + pref_privacy_analytics_enable_key + Analytics data reports + Automatically send us anonymized data for analytical purposes + Black Red diff --git a/app/src/main/res/xml/app_preferences.xml b/app/src/main/res/xml/app_preferences.xml index 806ba3a8..82127641 100644 --- a/app/src/main/res/xml/app_preferences.xml +++ b/app/src/main/res/xml/app_preferences.xml @@ -2,66 +2,65 @@ - - + android:title="@string/pref_title_app_main_default_tab" + android:summary="@string/pref_summary_app_main_default_tab" /> - - - - - + android:title="@string/pref_title_notification_led_enable" + android:summary="@string/pref_summary_notification_led_enable" /> - + android:title="@string/pref_title_notifications_sound" + android:summary="@string/pref_summary_notifications_sound" /> - - + android:title="@string/pref_title_posting_app_signature_enable" + android:summary="@string/pref_summary_posting_app_signature_enable" /> - + android:title="@string/pref_title_uploading_app_signature_enable" + android:summary="@string/pref_summary_uploading_app_signature_enable" /> + + + + \ No newline at end of file From 85ffbeb96b4c80e876aa60b63fc765cc5935be83 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 9 Oct 2018 14:45:02 +0300 Subject: [PATCH 155/180] poll fixes: labels --- .../java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 18cab71c..820c7770 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 @@ -43,13 +43,11 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.github.mikephil.charting.charts.HorizontalBarChart; -import com.github.mikephil.charting.components.AxisBase; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; -import com.github.mikephil.charting.formatter.IAxisValueFormatter; import com.squareup.picasso.Picasso; import java.util.ArrayList; @@ -177,6 +175,7 @@ class TopicAdapter extends RecyclerView.Adapter { container.setOrientation(LinearLayout.HORIZONTAL); CheckBox checkBox = new CheckBox(context); TextView label = new TextView(context); + label.setTextColor(context.getResources().getColor(R.color.primary_text)); label.setMovementMethod(LinkMovementMethod.getInstance()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { label.setText(Html.fromHtml(entry.getEntryName(), Html.FROM_HTML_MODE_LEGACY)); @@ -230,7 +229,7 @@ class TopicAdapter extends RecyclerView.Adapter { xAxis.setValueFormatter((value, axis) -> Html.fromHtml(entries[(int) value].getEntryName()).toString()); xAxis.setTextColor(context.getResources().getColor(R.color.primary_text)); xAxis.setGranularity(1f); - xAxis.setLabelCount(entries.length, true); + xAxis.setLabelCount(entries.length); xAxis.setDrawGridLines(false); xAxis.setDrawAxisLine(false); xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); From b6ad92120b2b03b3ad8eeb32a4c706b432a8ff4a Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Tue, 9 Oct 2018 15:23:06 +0300 Subject: [PATCH 156/180] fix board load more function --- .../mthmmy/activities/board/BoardActivity.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) 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 5d751b4b..7e96d6ce 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 @@ -104,7 +104,6 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo else { newTopicFAB.setOnClickListener(view -> { if (sessionManager.isLoggedIn()) { - //TODO create topic if (newTopicUrl != null) { Intent intent = new Intent(this, CreateContentActivity.class); intent.putExtra(CreateContentActivity.EXTRA_NEW_TOPIC_URL, newTopicUrl); @@ -195,6 +194,12 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo @Override //TODO should throw ParseException public void parse(Document boardPage) throws ParseException { + tempSubboards.addAll(parsedSubBoards); + tempTopics.addAll(parsedTopics); + //Removes loading item + if (isLoadingMore) { + if (tempTopics.size() > 0) tempTopics.remove(tempTopics.size() - 1); + } parsedTitle = boardPage.select("div.nav a.nav").last().text(); //Finds number of pages @@ -308,7 +313,6 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo @Override protected void postExecution(ResultCode result) { - //TODO if (result == ResultCode.SUCCESS)... if (result == ResultCode.SUCCESS) { if (boardTitle == null || Objects.equals(boardTitle, "") || !Objects.equals(boardTitle, parsedTitle)) { @@ -317,10 +321,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), false); } - //Removes loading item - if (isLoadingMore) { - if (parsedTopics.size() > 0) parsedTopics.remove(parsedTopics.size() - 1); - } + Timber.d("topix " + tempTopics); parsedTopics.clear(); parsedSubBoards.clear(); From c5442218f0f4deb283874c59e6a69cb43c3d9891 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 11 Oct 2018 19:28:03 +0300 Subject: [PATCH 157/180] Navigation fixes --- app/src/main/AndroidManifest.xml | 4 +- .../mthmmy/activities/LoginActivity.java | 28 ++-- .../activities/settings/SettingsFragment.java | 2 - .../gr/thmmy/mthmmy/base/BaseActivity.java | 145 ++++++++---------- 4 files changed, 81 insertions(+), 98 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 72b99fbc..245e6ada 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -113,11 +113,12 @@ android:theme="@style/AppTheme.NoActionBar"> + android:value=".activities.upload.UploadActivity" /> { + //Session data update + sessionManager.guestLogin(); + + //Go to main + Intent intent = new Intent(LoginActivity.this, MainActivity.class); + startActivity(intent); + finish(); + overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); }); } @Override public void onBackPressed() { - // Disable going back to the MainActivity - moveTaskToBack(true); + super.onBackPressed(); if (loginTask != null && loginTask.getStatus() == AsyncTask.Status.RUNNING) { loginTask.cancel(true); } + if(!isTaskRoot()) + overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); } private void onLoginFailed() { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java index 101dce1b..7309090a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java @@ -32,8 +32,6 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared private static final String SELECTED_NOTIFICATIONS_SOUND = "pref_notifications_select_sound_key"; private static final String POSTING_CATEGORY = "pref_category_posting_key"; private static final String UPLOADING_CATEGORY = "pref_category_uploading_key"; - public static final String PRIVACY_CRASHLYTICS_ENABLE_KEY = "pref_privacy_crashlytics_enable_key"; - public static final String PRIVACY_ANALYTICS_ENABLE_KEY = "pref_privacy_analytics_enable_key"; //SharedPreferences keys private static final int REQUEST_CODE_ALERT_RINGTONE = 2; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 6aa08cba..d182adf7 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -35,8 +35,6 @@ 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.io.File; import java.util.ArrayList; @@ -329,53 +327,53 @@ public abstract class BaseActivity extends AppCompatActivity { .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 intent = new Intent(BaseActivity.this, MainActivity.class); - startActivity(intent); - } - } else if (drawerItem.equals(DOWNLOADS_ID)) { - if (!(BaseActivity.this instanceof DownloadsActivity)) { - Intent intent = new Intent(BaseActivity.this, DownloadsActivity.class); - Bundle extras = new Bundle(); - extras.putString(BUNDLE_DOWNLOADS_URL, ""); - extras.putString(BUNDLE_DOWNLOADS_TITLE, null); - intent.putExtras(extras); - startActivity(intent); - } - } else if (drawerItem.equals(UPLOAD_ID)) { - if (!(BaseActivity.this instanceof UploadActivity)) { - Intent intent = new Intent(BaseActivity.this, UploadActivity.class); - startActivity(intent); - } - } else if (drawerItem.equals(BOOKMARKS_ID)) { - if (!(BaseActivity.this instanceof BookmarkActivity)) { - Intent intent = new Intent(BaseActivity.this, BookmarkActivity.class); - startActivity(intent); - } - } else if (drawerItem.equals(LOG_ID)) { - if (!sessionManager.isLoggedIn()) //When logged out or if user is guest - startLoginActivity(); - else - new LogoutTask().execute(); - } else if (drawerItem.equals(ABOUT_ID)) { - if (!(BaseActivity.this instanceof AboutActivity)) { - Intent intent = new Intent(BaseActivity.this, AboutActivity.class); - startActivity(intent); - } - } else if (drawerItem.equals(SETTINGS_ID)) { - if (!(BaseActivity.this instanceof SettingsActivity)) { - Intent intent = new Intent(BaseActivity.this, SettingsActivity.class); - startActivity(intent); - } + .withOnDrawerItemClickListener((view, position, drawerItem) -> { + if (drawerItem.equals(HOME_ID)) { + if (!(BaseActivity.this instanceof MainActivity)) { + Intent intent = new Intent(BaseActivity.this, MainActivity.class); + startActivity(intent); + } + } else if (drawerItem.equals(DOWNLOADS_ID)) { + if (!(BaseActivity.this instanceof DownloadsActivity)) { + Intent intent = new Intent(BaseActivity.this, DownloadsActivity.class); + Bundle extras = new Bundle(); + extras.putString(BUNDLE_DOWNLOADS_URL, ""); + extras.putString(BUNDLE_DOWNLOADS_TITLE, null); + intent.putExtras(extras); + startActivity(intent); + } + } else if (drawerItem.equals(UPLOAD_ID)) { + if (!(BaseActivity.this instanceof UploadActivity)) { + Intent intent = new Intent(BaseActivity.this, UploadActivity.class); + startActivity(intent); + } + } else if (drawerItem.equals(BOOKMARKS_ID)) { + if (!(BaseActivity.this instanceof BookmarkActivity)) { + Intent intent = new Intent(BaseActivity.this, BookmarkActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivity(intent); + } + } else if (drawerItem.equals(LOG_ID)) { + if (!sessionManager.isLoggedIn()) //When logged out or if user is guest + startLoginActivity(); + else + new LogoutTask().execute(); + } else if (drawerItem.equals(ABOUT_ID)) { + if (!(BaseActivity.this instanceof AboutActivity)) { + Intent intent = new Intent(BaseActivity.this, AboutActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivity(intent); + } + } else if (drawerItem.equals(SETTINGS_ID)) { + if (!(BaseActivity.this instanceof SettingsActivity)) { + Intent intent = new Intent(BaseActivity.this, SettingsActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivity(intent); } - - drawer.closeDrawer(); - return true; } + + drawer.closeDrawer(); + return true; }); if (sessionManager.isLoggedIn()) @@ -388,12 +386,9 @@ public abstract class BaseActivity extends AppCompatActivity { if (!(BaseActivity.this instanceof MainActivity)) drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(false); - drawer.setOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() { - @Override - public boolean onNavigationClickListener(View clickedView) { - onBackPressed(); - return true; - } + drawer.setOnDrawerNavigationListener(clickedView -> { + onBackPressed(); + return true; }); } @@ -696,36 +691,25 @@ public abstract class BaseActivity extends AppCompatActivity { Button cancelButton = view.findViewById(R.id.cancel); Button openButton = view.findViewById(R.id.open); Button downloadButton = view.findViewById(R.id.download); - cancelButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dialog.dismiss(); + cancelButton.setOnClickListener(v -> dialog.dismiss()); + openButton.setOnClickListener(v -> { + dialog.dismiss(); + try { + String fileName = thmmyFile.getFilename(); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); + Uri fileUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", new File(SAVE_DIR, fileName)); + intent.setDataAndType(fileUri, getMimeType(fileName)); + BaseActivity.this.startActivity(intent); + } catch (Exception e) { + Timber.e(e, "Couldn't open downloaded file..."); + Toast.makeText(getBaseContext(), "Couldn't open file...", Toast.LENGTH_SHORT).show(); } - }); - openButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dialog.dismiss(); - try { - String fileName = thmmyFile.getFilename(); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); - Uri fileUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", new File(SAVE_DIR, fileName)); - intent.setDataAndType(fileUri, getMimeType(fileName)); - BaseActivity.this.startActivity(intent); - } catch (Exception e) { - Timber.e(e, "Couldn't open downloaded file..."); - Toast.makeText(getBaseContext(), "Couldn't open file...", Toast.LENGTH_SHORT).show(); - } - } }); - downloadButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dialog.dismiss(); - DownloadHelper.enqueueDownload(thmmyFile); - } + downloadButton.setOnClickListener(v -> { + dialog.dismiss(); + DownloadHelper.enqueueDownload(thmmyFile); }); dialog.show(); } @@ -738,7 +722,6 @@ public abstract class BaseActivity extends AppCompatActivity { private void startLoginActivity(){ Intent intent = new Intent(BaseActivity.this, LoginActivity.class); startActivity(intent); - finish(); overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out); } } From fe364c20f40041f5d3f2a4d5e99a7a6af2a16519 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 14:11:19 +0300 Subject: [PATCH 158/180] Added initial consent dialog --- PRIVACY.md | 22 +++--- README.md | 7 +- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 1 + app/src/main/assets/PRIVACY.md | 76 +++++++++++++++++++ app/src/main/assets/apache_libraries.html | 3 + .../mthmmy/activities/LoginActivity.java | 31 ++++---- .../gr/thmmy/mthmmy/base/BaseActivity.java | 75 +++++++++++++++++- .../gr/thmmy/mthmmy/base/BaseApplication.java | 4 + .../gr/thmmy/mthmmy/utils/LaunchType.java | 40 ++++++++++ app/src/main/res/values-v21/styles.xml | 27 +------ app/src/main/res/values/strings.xml | 2 + app/src/main/res/values/styles.xml | 26 +++++-- 13 files changed, 252 insertions(+), 63 deletions(-) create mode 100644 app/src/main/assets/PRIVACY.md create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java diff --git a/PRIVACY.md b/PRIVACY.md index 7b560b40..8e69038c 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -1,6 +1,6 @@ # Privacy Policy -*Effective date: 7/10/2018* +*Effective date: 13/10/2018* Thmmy No Life ("us", "we", or "our") developed the mTHMMY mobile app (the "App") as an open source application. It is provided by us at no cost and is intended for use as is. @@ -16,7 +16,7 @@ Google Ireland Limited ("Google"), with offices at Gordon House, Barrow Street, The majority of Firebase services run on global Google infrastructure. They could process data at any of the Google Cloud Platform locations or Google data center locations, within or outside the European Union (EU). -The Commission Decision (EU) 2016/1250 of 12.07.2016 allows the transfer of data from an EU controller or processor of orders to organizations in the US that have committed themselves to adhere to the framework principles of the EU-US Privacy Shield (https://www.privacyshield.gov), including the additional principles, by way of self-certification with the US Department of Commerce. Google is subject to these principles through self-certification with the U.S. Department of Commerce. +The Commission Decision (EU) 2016/1250 of 12.07.2016 allows the transfer of data from an EU controller or processor of orders to organizations in the US that have committed themselves to adhere to the framework principles of the EU-US Privacy Shield (), including the additional principles, by way of self-certification with the US Department of Commerce. Google is subject to these principles through self-certification with the U.S. Department of Commerce. ### General Information @@ -37,22 +37,22 @@ The use of each Firebase service is explained below: ### Firebase Crashlytics * **Purpose**: This service automatically collects and delivers analyses of errors and system crashes in real time and displays them in the Firebase Console. This helps us maintain the App and improve its stability. -* **Data collected**: Instance IDs and crash reports with information about register codes and your device, e.g. type of device and version of operating system. For more information: https://try.crashlytics.com/security/ +* **Data collected**: Instance IDs and crash reports with information about register codes and your device, e.g. type of device and version of operating system. For more information: * **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable it from the Settings inside the App. * **Retention**: Crash traces and their associated identifiers are kept for 90 days. ### Google Analytics for Firebase * **Purpose**: This service provides analytics and attribution information for statistical purposes. The precise information collected can vary by the device and environment. -* **Data collected**: Instance IDs, Android IDs, Analytics App Instance IDs and custom events created by us. For more information: https://support.google.com/firebase/answer/6318039 +* **Data collected**: Instance IDs, Android IDs, Analytics App Instance IDs and custom events created by us. For more information: * **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable (and clear all collected data) from the Settings inside the App. * **Retention**: ID-associated data are retained for 60 days. Aggregate reporting and campaign data are retained without automatic expiration. You can find further information on the data use by Google through Firebase following the links below: -https://firebase.google.com/terms/ -https://firebase.google.com/terms/data-processing-terms -https://firebase.google.com/support/privacy/ -https://firebase.google.com/support/privacy/manage-iids + + + + ## Other data @@ -61,7 +61,7 @@ https://firebase.google.com/support/privacy/manage-iids ## About thmmy.gr -We have neither influence, nor responsibility on anything you read, write, download or upload by interacting with thmmy.gr through the App. For more information you can also read the Terms of Service of thmmy.gr at https://www.thmmy.gr/smf/index.php?topic=52522. +We have neither influence, nor responsibility on anything you read, write, download or upload by interacting with thmmy.gr through the App. For more information you can also read the Terms of Service of thmmy.gr at . ## Third-Party Links @@ -69,8 +69,8 @@ mTHMMY may contain links to third-party websites. Any access to and use of such ## Policy Updates -We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at https://github.com/ThmmyNoLife/mTHMMY/blob/develop/PRIVACY.md. +We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at . ## Contact Us -If you have any question about our Privacy Policy, please contact us at thmmynolife@gmail.com. +If you have any questions about our Privacy Policy, please contact us at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). diff --git a/README.md b/README.md index 4118864b..529f01a5 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ [![API](https://img.shields.io/badge/API-19%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=19) [![Discord Channel](https://img.shields.io/badge/discord-public@mTHMMY-738bd7.svg?style=flat)][discord-server] +![alt text](app\src\main\res\mipmap-xhdpi\ic_launcher.png "mTHMMY") -mTHMMY is a mobile app for the [thmmy.gr](https://www.thmmy.gr) community. +A mobile app for [thmmy.gr](https://www.thmmy.gr). ## Requirements @@ -20,6 +21,10 @@ The latest release version is available on Google Play: Please refer to [CONTRIBUTING.md](/CONTRIBUTING.md) for details. +## Privacy Policy + +Our Privacy Policy can be found [here](/PRIVACY.md). + ## Contact Do not hesitate to contact us for any matter, either by sending an email to [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com), or by joining our [Discord server][discord-server]. diff --git a/app/build.gradle b/app/build.gradle index 81b88eb7..79a71684 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,7 @@ dependencies { implementation 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1'//TODO: deprecated! implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2' implementation 'com.jakewharton.timber:timber:4.7.0' + implementation "ru.noties:markwon:2.0.0" implementation 'net.gotev:uploadservice:3.4.2' implementation 'net.gotev:uploadservice-okhttp:3.4.2' implementation 'android.arch.lifecycle:extensions:1.1.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 245e6ada..19f47c62 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,6 +21,7 @@ + ), including the additional principles, by way of self-certification with the US Department of Commerce. Google is subject to these principles through self-certification with the U.S. Department of Commerce. + +### General Information + +* The Firebase services that we use collect and further process anonymized information, data with no personally identifiable information which can be used to trace its source so that the people whom it describes can remain anonymous. These data are not subject to the same treatment as are personal data, particularly with regards to any desire you might have for accessing it, rectifying it or erasing it (Article 11, GDPR). +* Firebase uses the Instance ID of your mobile device to identify individual installations of this mobile app. Since each Instance ID is unique to a particular application and device, they give Firebase a way to refer to specific instances of the App. +* Your IP address transmitted by the App in the context of Firebase will not be merged with other collected data. +* Legal basis for the use of Firebase is Article 6 Par. 1 S. 1 letter (a) or (f), GDPR. + +The use of each Firebase service is explained below: + +### Firebase Cloud Messaging + +* **Purpose**: This service is essential for the funcionality of the App. It uses anonymous push notification tokens in order to determine which devices to deliver the appropriate messages to. +* **Data collected**: Instance IDs. +* **Consent**: You will be prompted to agree to the use of this service when you open the App for the first time. +* **Retention**: Firebase retains Instance IDs until we make an API call for deletion. After the call, data are removed from live and backup systems within 180 days. + +### Firebase Crashlytics + +* **Purpose**: This service automatically collects and delivers analyses of errors and system crashes in real time and displays them in the Firebase Console. This helps us maintain the App and improve its stability. +* **Data collected**: Instance IDs and crash reports with information about register codes and your device, e.g. type of device and version of operating system. For more information: +* **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable it from the Settings inside the App. +* **Retention**: Crash traces and their associated identifiers are kept for 90 days. + +### Google Analytics for Firebase + +* **Purpose**: This service provides analytics and attribution information for statistical purposes. The precise information collected can vary by the device and environment. +* **Data collected**: Instance IDs, Android IDs, Analytics App Instance IDs and custom events created by us. For more information: +* **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable (and clear all collected data) from the Settings inside the App. +* **Retention**: ID-associated data are retained for 60 days. Aggregate reporting and campaign data are retained without automatic expiration. + +You can find further information on the data use by Google through Firebase following the links below: + + + + + +## Other data + +* When downloading the mobile app, the necessary information is transferred to the App Store (Google Play), i.e. in particular the name, e-mail address and customer number of your customer account, time of download, payment information and the individual device identification number. We have no influence on this data collection and shall not be responsible for it. We only process the data if it is necessary for downloading the mobile app to your mobile device. +* The App provides functionality to login to thmmy.gr through an encrypted connection. This process generates session cookies that are stored on your device. Those cookies contain the same information as those that would be generated if you logged in using a web browser and we have no influence on them. Any other personal information that the App collects from you from thmmy.gr is only stored locally and never transmitted. You can delete all the data related to thmmy.gr anytime you wish, by logging out or clearing the App's data from your device's Settings. + +## About thmmy.gr + +We have neither influence, nor responsibility on anything you read, write, download or upload by interacting with thmmy.gr through the App. For more information you can also read the Terms of Service of thmmy.gr at . + +## Third-Party Links + +mTHMMY may contain links to third-party websites. Any access to and use of such linked websites is not governed by this Policy, but instead is governed by the privacy policies of those third party websites. We are not responsible for the information practices of such third party websites. + +## Policy Updates + +We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at . + +## Contact Us + +If you have any questions about our Privacy Policy, please contact us at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index c739366e..004d8c96 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -65,6 +65,9 @@
  • Android Upload Service v3.4.2 (Copyright ©2013-2018 Aleksandar Gotev)
  • +
  • +
    Markwon v2.0.0 (Copyright ©2017 Dimitry Ivanov)
    +
  • 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 60b7d7aa..add3abaf 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java @@ -3,10 +3,8 @@ package gr.thmmy.mthmmy.activities; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; -import android.support.annotation.NonNull; import android.support.v7.preference.PreferenceManager; import android.support.v7.widget.AppCompatButton; -import android.view.ActionMode; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -57,25 +55,22 @@ public class LoginActivity extends BaseActivity { AppCompatButton btnGuest = findViewById(R.id.btnContinueAsGuest); //Login button Click Event - btnLogin.setOnClickListener(new View.OnClickListener() { + btnLogin.setOnClickListener(view -> { + Timber.d("Login"); - public void onClick(View view) { - Timber.d("Login"); + //Get username and password strings + username = inputUsername.getText().toString().trim(); + password = inputPassword.getText().toString().trim(); - //Get username and password strings - username = inputUsername.getText().toString().trim(); - password = inputPassword.getText().toString().trim(); - - //Check for empty data in the form - if (!validate()) { - onLoginFailed(); - return; - } - - //Login user - loginTask = new LoginTask(); - loginTask.execute(username, password); + //Check for empty data in the form + if (!validate()) { + onLoginFailed(); + return; } + + //Login user + loginTask = new LoginTask(); + loginTask.execute(username, password); }); //Guest Button Action diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index d182adf7..b0d1c98e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -15,6 +15,7 @@ import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetDialog; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; +import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.preference.PreferenceManager; import android.support.v7.widget.Toolbar; @@ -36,7 +37,10 @@ import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.ProfileDrawerItem; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.util.ArrayList; import gr.thmmy.mthmmy.R; @@ -53,8 +57,12 @@ import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.services.DownloadHelper; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.FileUtils; +import gr.thmmy.mthmmy.utils.LaunchType; import gr.thmmy.mthmmy.viewmodel.BaseViewModel; import okhttp3.OkHttpClient; +import ru.noties.markwon.LinkResolverDef; +import ru.noties.markwon.Markwon; +import ru.noties.markwon.SpannableConfiguration; import timber.log.Timber; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -67,8 +75,10 @@ import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_ import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR; import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS; import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; +import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.FIRST_LAUNCH_EVER; +import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.INDETERMINATE; -public abstract class BaseActivity extends AppCompatActivity { +public abstract class BaseActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener{ // Client & Cookies protected static OkHttpClient client; @@ -116,6 +126,8 @@ public abstract class BaseActivity extends AppCompatActivity { protected void onResume() { super.onResume(); updateDrawer(); + if(LaunchType.getLaunchType()==FIRST_LAUNCH_EVER||LaunchType.getLaunchType()== INDETERMINATE) + showUserConsentDialog(); } @Override @@ -714,6 +726,67 @@ public abstract class BaseActivity extends AppCompatActivity { dialog.show(); } + //----------------------------PRIVACY POLICY------------------ + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(getString(R.string.pref_pp_accepted_key))) + if(!sharedPreferences.getBoolean(key, false)) + showUserConsentDialog(); + } + + private void showUserConsentDialog(){ + AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); + builder.setTitle("User Agreement"); + builder.setMessage(R.string.user_agreement_dialog_text); + builder.setPositiveButton("Yes, I want to help", (dialogInterface, i) -> FirebaseMessaging.getInstance().setAutoInitEnabled(true)); + builder.setNegativeButton("Nope, leave me alone", (dialogInterface, i) -> FirebaseMessaging.getInstance().setAutoInitEnabled(true)); + builder.setNeutralButton("Privacy Policy", (dialog, which) -> {/*Will be overridden below*/}); + builder.setCancelable(false); + AlertDialog alertDialog = builder.create(); + alertDialog.setOnShowListener(dialogInterface -> { + Button button = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL); + button.setOnClickListener(view -> showPrivacyPolicyDialog()); + }); // Overridden like this so it won't be dismissed when user touches this button + alertDialog.show(); + } + + private void showPrivacyPolicyDialog() { + TextView privacyPolicyTextView = new TextView(this); + privacyPolicyTextView.setPadding(30,20,30,20); + privacyPolicyTextView.setTextColor(ContextCompat.getColor(this, R.color.primary_text)); + SpannableConfiguration configuration = SpannableConfiguration.builder(this).linkResolver(new LinkResolverDef()).build(); + StringBuilder stringBuilder = new StringBuilder(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(getAssets().open("PRIVACY.md"))); + String line; + + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + stringBuilder.append("\n"); + } + Markwon.setMarkdown(privacyPolicyTextView, configuration, stringBuilder.toString()); + AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); + builder.setView(privacyPolicyTextView); + builder.setPositiveButton("Close", (dialogInterface, i) -> dialogInterface.dismiss()); + builder.show(); + } catch (IOException e) { + Timber.e(e, "Error reading Privacy Policy from assets."); + } catch (Exception e) { + Timber.e(e, "Error in Privacy Policy dialog."); + } finally { + try { + if(reader!=null) + reader.close(); + } catch (IOException e) { + Timber.e(e, "Error in Privacy Policy dialog (closing reader)."); + } + } + } + + + //----------------------------------MISC---------------------- protected void setMainActivity(MainActivity mainActivity) { this.mainActivity = mainActivity; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index 0f74807d..b2a930ee 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -165,6 +165,10 @@ public class BaseApplication extends Application { } //Getters + public Context getContext() { + return getApplicationContext(); + } + public OkHttpClient getClient() { return client; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java b/app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java new file mode 100644 index 00000000..29411b55 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java @@ -0,0 +1,40 @@ +package gr.thmmy.mthmmy.utils; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import gr.thmmy.mthmmy.BuildConfig; +import gr.thmmy.mthmmy.base.BaseApplication; + +public class LaunchType { + public enum LAUNCH_TYPE { + FIRST_LAUNCH_EVER, FIRST_LAUNCH_AFTER_UPDATE, NORMAL_LAUNCH, INDETERMINATE + } + + private static final String PREF_VERSION_CODE_KEY = "VERSION_CODE"; + + public static LAUNCH_TYPE getLaunchType() { + final int notThere = -1; + //Gets current version code + int currentVersionCode = BuildConfig.VERSION_CODE; + //Gets saved version code + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(BaseApplication.getInstance().getContext()); + int savedVersionCode = prefs.getInt(PREF_VERSION_CODE_KEY, notThere); + //Checks for first run or upgrade + if (currentVersionCode == savedVersionCode) { + //This is just a normal run + return LAUNCH_TYPE.NORMAL_LAUNCH; + } else if (savedVersionCode == notThere) { + //Updates the shared preferences with the current version code + prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply(); + return LAUNCH_TYPE.FIRST_LAUNCH_EVER; + } else if (currentVersionCode > savedVersionCode) { + //Updates the shared preferences with the current version code + prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply(); + return LAUNCH_TYPE.FIRST_LAUNCH_AFTER_UPDATE; + } + //Probably shared preferences were manually changed by the user + return LAUNCH_TYPE.INDETERMINATE; + } +} + diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index e16ea522..7011b5f0 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -1,33 +1,10 @@ - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3c133b80..09711010 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,6 +14,8 @@ Info OK Cancel + pref_pp_accepted + "To use mTHMMY you have to agree to our Privacy Policy by choosing one of the buttons below. Choose \"Yes, I want to help\", if you consent to the collection of anonymized data that will help us improve the app. Otherwise, choose \"Nope, leave me alone\". You can change your preferences any time through the app's Settings. thmmy.gr diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 90595469..9d79d36d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,6 @@ - - - - + @@ -46,14 +50,18 @@ @color/primary_text - - + + + + From 1889a2f0cdbcc24eb653425a3be317ca363a5760 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 16:18:13 +0300 Subject: [PATCH 159/180] Init board notifications --- .../activities/board/BoardActivity.java | 8 +-- .../bookmarks/BoardBookmarksFragment.java | 64 +++++++++++++------ .../bookmarks/BookmarkActivity.java | 32 ++++++---- .../bookmarks/TopicBookmarksFragment.java | 59 +++++++---------- .../gr/thmmy/mthmmy/base/BaseActivity.java | 37 +++++------ .../thmmy/mthmmy/model/PostNotification.java | 37 +++++++++-- .../mthmmy/services/NotificationService.java | 52 ++++++++++++--- .../layout/fragment_bookmarks_board_row.xml | 12 ++++ app/src/main/res/values/strings.xml | 1 - 9 files changed, 197 insertions(+), 105 deletions(-) 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 7e96d6ce..7251a4f9 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 @@ -95,7 +95,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo } thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), false); - setBoardBookmark((ImageButton) findViewById(R.id.bookmark)); + setBoardBookmark(findViewById(R.id.bookmark)); createDrawer(); progressBar = findViewById(R.id.progressBar); @@ -167,7 +167,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo @Override public void onResume() { super.onResume(); - refreshBoardBookmark((ImageButton) findViewById(R.id.bookmark)); + refreshBoardBookmark(findViewById(R.id.bookmark)); } @Override @@ -318,11 +318,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo || !Objects.equals(boardTitle, parsedTitle)) { boardTitle = parsedTitle; toolbar.setTitle(boardTitle); - thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), false); + thisPageBookmark = new Bookmark(boardTitle, "b" + ThmmyPage.getBoardId(boardUrl), true); } - Timber.d("topix " + tempTopics); - parsedTopics.clear(); parsedSubBoards.clear(); parsedTopics.addAll(tempTopics); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java index 6b7dee26..1912b1de 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java @@ -2,13 +2,16 @@ package gr.thmmy.mthmmy.activities.bookmarks; import android.app.Activity; import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; @@ -27,10 +30,14 @@ public class BoardBookmarksFragment extends Fragment { protected static final String ARG_BOARD_BOOKMARKS = "BOARD_BOOKMARKS"; public static final String INTERACTION_CLICK_BOARD_BOOKMARK = "CLICK_BOARD_BOOKMARK"; + public static final String INTERACTION_TOGGLE_BOARD_NOTIFICATION = "TOGGLE_BOARD_NOTIFICATION"; public static final String INTERACTION_REMOVE_BOARD_BOOKMARK= "REMOVE_BOARD_BOOKMARK"; ArrayList boardBookmarks = null; + private static Drawable notificationsEnabledButtonImage; + private static Drawable notificationsDisabledButtonImage; + // Required empty public constructor public BoardBookmarksFragment() { } @@ -59,6 +66,16 @@ public class BoardBookmarksFragment extends Fragment { boardBookmarks = Bookmark.arrayFromString(bundledBoardBookmarks); } } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + notificationsEnabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_on, null); + else + notificationsEnabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_on, null); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + notificationsDisabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_off, null); + else + notificationsDisabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_off, null); } @Override @@ -74,31 +91,42 @@ public class BoardBookmarksFragment extends Fragment { if (bookmarkedBoard != null && bookmarkedBoard.getTitle() != null) { final LinearLayout row = (LinearLayout) layoutInflater.inflate( R.layout.fragment_bookmarks_board_row, bookmarksLinearView, false); - row.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Activity activity = getActivity(); - if (activity instanceof BookmarkActivity){ - ((BookmarkActivity) activity).onBoardInteractionListener(INTERACTION_CLICK_BOARD_BOOKMARK, bookmarkedBoard); - } + row.setOnClickListener(view -> { + Activity activity = getActivity(); + if (activity instanceof BookmarkActivity){ + ((BookmarkActivity) activity).onBoardInteractionListener(INTERACTION_CLICK_BOARD_BOOKMARK, bookmarkedBoard); } }); ((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) { - Activity activity = getActivity(); - if (activity instanceof BookmarkActivity){ - ((BookmarkActivity) activity).onBoardInteractionListener(INTERACTION_REMOVE_BOARD_BOOKMARK, bookmarkedBoard); - boardBookmarks.remove(bookmarkedBoard); - } - row.setVisibility(View.GONE); - if (boardBookmarks.isEmpty()){ - bookmarksLinearView.addView(bookmarksListEmptyMessage()); + final ImageButton notificationsEnabledButton = row.findViewById(R.id.toggle_notification); + if (!bookmarkedBoard.isNotificationsEnabled()) { + notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); + } + + notificationsEnabledButton.setOnClickListener(view -> { + Activity activity = getActivity(); + if (activity instanceof BookmarkActivity) { + if (((BookmarkActivity) activity).onBoardInteractionListener(INTERACTION_TOGGLE_BOARD_NOTIFICATION, bookmarkedBoard)) { + notificationsEnabledButton.setImageDrawable(notificationsEnabledButtonImage); + } else { + notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); } } }); + + (row.findViewById(R.id.remove_bookmark)).setOnClickListener(view -> { + Activity activity = getActivity(); + if (activity instanceof BookmarkActivity){ + ((BookmarkActivity) activity).onBoardInteractionListener(INTERACTION_REMOVE_BOARD_BOOKMARK, bookmarkedBoard); + boardBookmarks.remove(bookmarkedBoard); + } + row.setVisibility(View.GONE); + + if (boardBookmarks.isEmpty()){ + bookmarksLinearView.addView(bookmarksListEmptyMessage()); + } + }); bookmarksLinearView.addView(row); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarkActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarkActivity.java index 5dce5ed0..164e8f3f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarkActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarkActivity.java @@ -84,20 +84,26 @@ public class BookmarkActivity extends BaseActivity { return true; } - public void onBoardInteractionListener(String interactionType, Bookmark bookmarkedBoard) { - if (interactionType.equals(BoardBookmarksFragment.INTERACTION_CLICK_BOARD_BOOKMARK)) { - 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(); - } else if (interactionType.equals(BoardBookmarksFragment.INTERACTION_REMOVE_BOARD_BOOKMARK)) { - removeBookmark(bookmarkedBoard); - Toast.makeText(BookmarkActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show(); + public boolean onBoardInteractionListener(String interactionType, Bookmark bookmarkedBoard) { + switch (interactionType) { + case BoardBookmarksFragment.INTERACTION_CLICK_BOARD_BOOKMARK: + 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(); + break; + case BoardBookmarksFragment.INTERACTION_TOGGLE_BOARD_NOTIFICATION: + return toggleNotification(bookmarkedBoard); + case BoardBookmarksFragment.INTERACTION_REMOVE_BOARD_BOOKMARK: + removeBookmark(bookmarkedBoard); + Toast.makeText(BookmarkActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show(); + break; } + return true; } /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java index 7679ad2f..7b8b5305 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java @@ -62,17 +62,15 @@ public class TopicBookmarksFragment extends Fragment { } } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) notificationsEnabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_on, null); - } else { + else notificationsEnabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_on, null); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) notificationsDisabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_off, null); - } else { + else notificationsDisabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_off, null); - } } @Override @@ -88,13 +86,10 @@ public class TopicBookmarksFragment extends Fragment { if (bookmarkedTopic != null && bookmarkedTopic.getTitle() != null) { final LinearLayout row = (LinearLayout) layoutInflater.inflate( R.layout.fragment_bookmarks_topic_row, bookmarksLinearView, false); - row.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Activity activity = getActivity(); - if (activity instanceof BookmarkActivity) { - ((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_CLICK_TOPIC_BOOKMARK, bookmarkedTopic); - } + row.setOnClickListener(view -> { + Activity activity = getActivity(); + if (activity instanceof BookmarkActivity) { + ((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_CLICK_TOPIC_BOOKMARK, bookmarkedTopic); } }); ((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedTopic.getTitle()); @@ -104,32 +99,26 @@ public class TopicBookmarksFragment extends Fragment { notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); } - notificationsEnabledButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Activity activity = getActivity(); - if (activity instanceof BookmarkActivity) { - if (((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_TOGGLE_TOPIC_NOTIFICATION, bookmarkedTopic)) { - notificationsEnabledButton.setImageDrawable(notificationsEnabledButtonImage); - } else { - notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); - } + notificationsEnabledButton.setOnClickListener(view -> { + Activity activity = getActivity(); + if (activity instanceof BookmarkActivity) { + if (((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_TOGGLE_TOPIC_NOTIFICATION, bookmarkedTopic)) { + notificationsEnabledButton.setImageDrawable(notificationsEnabledButtonImage); + } else { + notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); } } }); - (row.findViewById(R.id.remove_bookmark)).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Activity activity = getActivity(); - if (activity instanceof BookmarkActivity) { - ((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_REMOVE_TOPIC_BOOKMARK, bookmarkedTopic); - topicBookmarks.remove(bookmarkedTopic); - } - row.setVisibility(View.GONE); + (row.findViewById(R.id.remove_bookmark)).setOnClickListener(view -> { + Activity activity = getActivity(); + if (activity instanceof BookmarkActivity) { + ((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_REMOVE_TOPIC_BOOKMARK, bookmarkedTopic); + topicBookmarks.remove(bookmarkedTopic); + } + row.setVisibility(View.GONE); - if (topicBookmarks.isEmpty()){ - bookmarksLinearView.addView(bookmarksListEmptyMessage()); - } + if (topicBookmarks.isEmpty()){ + bookmarksLinearView.addView(bookmarksListEmptyMessage()); } }); bookmarksLinearView.addView(row); diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index b0d1c98e..46dbdba5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -78,7 +78,7 @@ import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.FIRST_LAUNCH_EVER; import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.INDETERMINATE; -public abstract class BaseActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener{ +public abstract class BaseActivity extends AppCompatActivity { // Client & Cookies protected static OkHttpClient client; @@ -117,9 +117,7 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr } BaseViewModel baseViewModel = ViewModelProviders.of(this).get(BaseViewModel.class); - baseViewModel.getCurrentPageBookmark().observe(this, thisPageBookmark -> { - setTopicBookmark(thisPageBookmarkMenuButton); - }); + baseViewModel.getCurrentPageBookmark().observe(this, thisPageBookmark -> setTopicBookmark(thisPageBookmarkMenuButton)); } @Override @@ -577,7 +575,11 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr if (boardsBookmarked == null) return; if (bookmark.matchExists(boardsBookmarked)) { boardsBookmarked.remove(bookmark.findIndex(boardsBookmarked)); - } else boardsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), false)); + FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); + } else { + boardsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), false)); + FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId()); + } updateBoardBookmarks(); } @@ -617,13 +619,22 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).toggleNotificationsEnabled(); updateTopicBookmarks(); - if (topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).isNotificationsEnabled()) { + if (topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).isNotificationsEnabled()) FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId()); - } else { + else FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); - } return topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).isNotificationsEnabled(); + } else if (bookmark.matchExists(boardsBookmarked)) { + boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).toggleNotificationsEnabled(); + updateBoardBookmarks(); + + if (boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).isNotificationsEnabled()) + FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId()); + else + FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); + + return boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).isNotificationsEnabled(); } return false; } @@ -727,14 +738,6 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr } //----------------------------PRIVACY POLICY------------------ - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals(getString(R.string.pref_pp_accepted_key))) - if(!sharedPreferences.getBoolean(key, false)) - showUserConsentDialog(); - } - private void showUserConsentDialog(){ AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); builder.setTitle("User Agreement"); @@ -785,8 +788,6 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr } } - - //----------------------------------MISC---------------------- protected void setMainActivity(MainActivity mainActivity) { this.mainActivity = mainActivity; diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/PostNotification.java b/app/src/main/java/gr/thmmy/mthmmy/model/PostNotification.java index 42985352..838dc2d3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/PostNotification.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/PostNotification.java @@ -8,10 +8,12 @@ package gr.thmmy.mthmmy.model; *

    . */ public class PostNotification { - final int postId; - final int topicId; - final String topicTitle; - final String poster; + private final int postId; + private final int topicId; + private final String topicTitle; + private final String poster; + private final int boardId; + private final String boardTitle; // Suppresses default constructor @SuppressWarnings("unused") @@ -20,6 +22,8 @@ public class PostNotification { this.topicId = -1; this.topicTitle = null; this.poster = null; + this.boardId = -1; + this.boardTitle = null; } /** @@ -30,12 +34,17 @@ public class PostNotification { * @param topicId this post's topicId * @param topicTitle this post's topicTitle * @param poster username of this post's author + * @param boardId one of this post's boardIds (-1 if it is a topic notification) + * @param boardTitle one of this post's boardTitles (null if it is a topic notification) */ - public PostNotification(int postId, int topicId, String topicTitle, String poster) { + public PostNotification(int postId, int topicId, String topicTitle, String poster, int boardId, String boardTitle) { this.postId = postId; this.topicId = topicId; this.topicTitle = topicTitle; this.poster = poster; + this.boardId = boardId; + this.boardTitle = boardTitle; + } /** @@ -73,6 +82,24 @@ public class PostNotification { public String getPoster() { return poster; } + + /** + * Gets this post's boardId. + * + * @return this post's boardId + */ + public int getBoardId() { + return boardId; + } + + /** + * Gets this post's boardTitle. + * + * @return this post's boardTitle + */ + public String getBoardTitle() { + return boardTitle; + } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java index a383e282..02319378 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java +++ b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java @@ -54,9 +54,19 @@ public class NotificationService extends FirebaseMessagingService { int postId = Integer.parseInt(json.getString("postId")); String topicTitle = json.getString("topicTitle"); String poster = json.getString("poster"); - sendNotification(new PostNotification(postId, topicId, topicTitle, poster)); + int boardId = -1; + String boardTitle = null; + if(remoteMessage.getFrom().contains("b")){ + Timber.i("FCM BOARD type message detected."); + boardId = Integer.parseInt(json.getString("boardId")); + boardTitle = json.getString("boardTitle"); + } + else + Timber.i("FCM TOPIC type message detected."); + + sendNotification(new PostNotification(postId, topicId, topicTitle, poster, boardId, boardTitle)); } else - Timber.v("Notification suppressed (own userID)."); + Timber.i("Notification suppressed (own userID)."); } catch (JSONException e) { Timber.e(e, "JSON Exception"); } @@ -78,6 +88,8 @@ public class NotificationService extends FirebaseMessagingService { private void sendNotification(PostNotification postNotification) { Timber.i("Creating a notification..."); + boolean isTopicNotification = postNotification.getBoardId() == -1; + //Reads notifications preferences SharedPreferences settingsFile = getSharedPreferences(SETTINGS_SHARED_PREFS, Context.MODE_PRIVATE); String notificationsSound = settingsFile.getString(SELECTED_RINGTONE, null); @@ -118,15 +130,30 @@ public class NotificationService extends FirebaseMessagingService { PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode++, intent, PendingIntent.FLAG_ONE_SHOT); - final int topicId = postNotification.getTopicId(); - String contentText = "New post by " + postNotification.getPoster(); + int notificationId; + String contentText; + if(isTopicNotification){ + notificationId = postNotification.getTopicId(); + contentText = "New post by " + postNotification.getPoster(); + } + else{ + // Using Cantor pairing function (plus the minus sign) for id uniqueness + int k1 = postNotification.getTopicId(); + int k2 = postNotification.getBoardId(); + notificationId = -(((k1+k2)*(k1+k2+1))/2+k2); + contentText = "New post in " + postNotification.getTopicTitle(); + } + int newPostsCount = 1; if (buildVersion >= Build.VERSION_CODES.M) { - Notification existingNotification = getActiveNotification(topicId); + Notification existingNotification = getActiveNotification(notificationId); if (existingNotification != null) { newPostsCount = existingNotification.extras.getInt(NEW_POSTS_COUNT) + 1; - contentText = newPostsCount + " new posts"; + if(isTopicNotification) + contentText = newPostsCount + " new posts"; + else + contentText = newPostsCount + " new posts in " + postNotification.getTopicTitle(); } } @@ -136,13 +163,18 @@ public class NotificationService extends FirebaseMessagingService { NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) - .setContentTitle(postNotification.getTopicTitle()) .setContentText(contentText) .setAutoCancel(true) .setContentIntent(pendingIntent) .setGroup(GROUP_KEY) .addExtras(notificationExtras); + if(isTopicNotification) + notificationBuilder.setContentTitle(postNotification.getTopicTitle()); + + else + notificationBuilder.setContentTitle(postNotification.getBoardTitle()); + //Applies user's notifications preferences if (notificationDefaultValues != -1) { notificationBuilder.setDefaults(notificationDefaultValues); @@ -162,7 +194,7 @@ public class NotificationService extends FirebaseMessagingService { boolean createSummaryNotification = false; if (buildVersion >= Build.VERSION_CODES.M) - createSummaryNotification = otherNotificationsExist(topicId); + createSummaryNotification = otherNotificationsExist(notificationId); NotificationCompat.Builder summaryNotificationBuilder = null; @@ -174,7 +206,7 @@ public class NotificationService extends FirebaseMessagingService { .setGroup(GROUP_KEY) .setAutoCancel(true) .setStyle(new NotificationCompat.InboxStyle() - .setSummaryText("New Posts")) + .setSummaryText("New Posts")) .setDefaults(Notification.DEFAULT_ALL); } @@ -185,7 +217,7 @@ public class NotificationService extends FirebaseMessagingService { if (buildVersion >= Build.VERSION_CODES.O) notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)); - notificationManager.notify(NEW_POST_TAG, topicId, notificationBuilder.build()); + notificationManager.notify(NEW_POST_TAG, notificationId, notificationBuilder.build()); if (createSummaryNotification) notificationManager.notify(SUMMARY_TAG, 0, summaryNotificationBuilder.build()); diff --git a/app/src/main/res/layout/fragment_bookmarks_board_row.xml b/app/src/main/res/layout/fragment_bookmarks_board_row.xml index d59b6c45..b3e17ebe 100644 --- a/app/src/main/res/layout/fragment_bookmarks_board_row.xml +++ b/app/src/main/res/layout/fragment_bookmarks_board_row.xml @@ -23,6 +23,18 @@ android:textColor="@color/primary_text" android:textSize="18sp"/> + + Info OK Cancel - pref_pp_accepted "To use mTHMMY you have to agree to our Privacy Policy by choosing one of the buttons below. Choose \"Yes, I want to help\", if you consent to the collection of anonymized data that will help us improve the app. Otherwise, choose \"Nope, leave me alone\". You can change your preferences any time through the app's Settings. From 131bd0736a20cb06ac439a11c5b1b4522a88afdb Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 16:30:04 +0300 Subject: [PATCH 160/180] Some refactoring --- .../bookmarks/BoardBookmarksFragment.java | 2 +- .../bookmarks/TopicBookmarksFragment.java | 2 +- .../mthmmy/services/NotificationService.java | 9 ++-- ...ard_row.xml => fragment_bookmarks_row.xml} | 0 .../layout/fragment_bookmarks_topic_row.xml | 50 ------------------- 5 files changed, 7 insertions(+), 56 deletions(-) rename app/src/main/res/layout/{fragment_bookmarks_board_row.xml => fragment_bookmarks_row.xml} (100%) delete mode 100644 app/src/main/res/layout/fragment_bookmarks_topic_row.xml diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java index 1912b1de..6c7db47f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java @@ -90,7 +90,7 @@ public class BoardBookmarksFragment extends Fragment { for (final Bookmark bookmarkedBoard : boardBookmarks) { if (bookmarkedBoard != null && bookmarkedBoard.getTitle() != null) { final LinearLayout row = (LinearLayout) layoutInflater.inflate( - R.layout.fragment_bookmarks_board_row, bookmarksLinearView, false); + R.layout.fragment_bookmarks_row, bookmarksLinearView, false); row.setOnClickListener(view -> { Activity activity = getActivity(); if (activity instanceof BookmarkActivity){ diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java index 7b8b5305..c7a14b84 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java @@ -85,7 +85,7 @@ public class TopicBookmarksFragment extends Fragment { for (final Bookmark bookmarkedTopic : topicBookmarks) { if (bookmarkedTopic != null && bookmarkedTopic.getTitle() != null) { final LinearLayout row = (LinearLayout) layoutInflater.inflate( - R.layout.fragment_bookmarks_topic_row, bookmarksLinearView, false); + R.layout.fragment_bookmarks_row, bookmarksLinearView, false); row.setOnClickListener(view -> { Activity activity = getActivity(); if (activity instanceof BookmarkActivity) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java index 02319378..00dee3f3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java +++ b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java @@ -50,19 +50,20 @@ public class NotificationService extends FirebaseMessagingService { int userId = BaseApplication.getInstance().getSessionManager().getUserId(); //Don't notify me if the sender is me! if (Integer.parseInt(json.getString("posterId")) != userId) { - int topicId = Integer.parseInt(json.getString("topicId")); - int postId = Integer.parseInt(json.getString("postId")); - String topicTitle = json.getString("topicTitle"); - String poster = json.getString("poster"); int boardId = -1; String boardTitle = null; if(remoteMessage.getFrom().contains("b")){ Timber.i("FCM BOARD type message detected."); + //TODO: return early and don't create notification if the user is also subscribed to this topicId boardId = Integer.parseInt(json.getString("boardId")); boardTitle = json.getString("boardTitle"); } else Timber.i("FCM TOPIC type message detected."); + int topicId = Integer.parseInt(json.getString("topicId")); + int postId = Integer.parseInt(json.getString("postId")); + String topicTitle = json.getString("topicTitle"); + String poster = json.getString("poster"); sendNotification(new PostNotification(postId, topicId, topicTitle, poster, boardId, boardTitle)); } else diff --git a/app/src/main/res/layout/fragment_bookmarks_board_row.xml b/app/src/main/res/layout/fragment_bookmarks_row.xml similarity index 100% rename from app/src/main/res/layout/fragment_bookmarks_board_row.xml rename to app/src/main/res/layout/fragment_bookmarks_row.xml diff --git a/app/src/main/res/layout/fragment_bookmarks_topic_row.xml b/app/src/main/res/layout/fragment_bookmarks_topic_row.xml deleted file mode 100644 index b3e17ebe..00000000 --- a/app/src/main/res/layout/fragment_bookmarks_topic_row.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - \ No newline at end of file From e697b8edb59a6cf899a10492dd93072253af5616 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 18:35:32 +0300 Subject: [PATCH 161/180] Minor refactoring --- .../activities/board/BoardActivity.java | 2 +- .../bookmarks/TopicBookmarksFragment.java | 23 +++++++++++-------- .../gr/thmmy/mthmmy/base/BaseActivity.java | 3 ++- app/src/main/res/values/strings.xml | 2 +- 4 files changed, 18 insertions(+), 12 deletions(-) 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 7251a4f9..edda9537 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 @@ -94,7 +94,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo getSupportActionBar().setDisplayShowHomeEnabled(true); } - thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), false); + thisPageBookmark = new Bookmark(boardTitle, "b" + ThmmyPage.getBoardId(boardUrl), true); setBoardBookmark(findViewById(R.id.bookmark)); createDrawer(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java index c7a14b84..54659baa 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/TopicBookmarksFragment.java @@ -20,13 +20,18 @@ import java.util.ArrayList; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.model.Bookmark; +/** + * A {@link Fragment} subclass. + * Use the {@link TopicBookmarksFragment#newInstance} factory method to + * create an instance of this fragment. + */ public class TopicBookmarksFragment extends Fragment { protected static final String ARG_SECTION_NUMBER = "SECTION_NUMBER"; - protected static final String ARG_TOPIC_BOOKMARKS = "BOARD_BOOKMARKS"; + protected static final String ARG_TOPIC_BOOKMARKS = "TOPIC_BOOKMARKS"; - public static final String INTERACTION_CLICK_TOPIC_BOOKMARK = "CLICK_BOARD_BOOKMARK"; + public static final String INTERACTION_CLICK_TOPIC_BOOKMARK = "CLICK_TOPIC_BOOKMARK"; public static final String INTERACTION_TOGGLE_TOPIC_NOTIFICATION = "TOGGLE_TOPIC_NOTIFICATION"; - public static final String INTERACTION_REMOVE_TOPIC_BOOKMARK = "REMOVE_BOARD_BOOKMARK"; + public static final String INTERACTION_REMOVE_TOPIC_BOOKMARK = "REMOVE_TOPIC_BOOKMARK"; ArrayList topicBookmarks = null; @@ -43,11 +48,11 @@ public class TopicBookmarksFragment extends Fragment { * * @return A new instance of fragment Forum. */ - public static TopicBookmarksFragment newInstance(int sectionNumber, String boardBookmarks) { + public static TopicBookmarksFragment newInstance(int sectionNumber, String topicBookmarks) { TopicBookmarksFragment fragment = new TopicBookmarksFragment(); Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); - args.putString(ARG_TOPIC_BOOKMARKS, boardBookmarks); + args.putString(ARG_TOPIC_BOOKMARKS, topicBookmarks); fragment.setArguments(args); return fragment; } @@ -56,9 +61,9 @@ public class TopicBookmarksFragment extends Fragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { - String bundledBoardBookmarks = getArguments().getString(ARG_TOPIC_BOOKMARKS); - if (bundledBoardBookmarks != null) { - topicBookmarks = Bookmark.arrayFromString(bundledBoardBookmarks); + String bundledTopicBookmarks = getArguments().getString(ARG_TOPIC_BOOKMARKS); + if (bundledTopicBookmarks != null) { + topicBookmarks = Bookmark.arrayFromString(bundledTopicBookmarks); } } @@ -78,7 +83,7 @@ public class TopicBookmarksFragment extends Fragment { Bundle savedInstanceState) { // Inflates the layout for this fragment final View rootView = layoutInflater.inflate(R.layout.fragment_bookmarks, container, false); - //bookmarks_board_container + //bookmarks_topic_container final LinearLayout bookmarksLinearView = rootView.findViewById(R.id.bookmarks_container); if(this.topicBookmarks != null && !this.topicBookmarks.isEmpty()) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 46dbdba5..e504596d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -635,7 +635,8 @@ public abstract class BaseActivity extends AppCompatActivity { FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); return boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).isNotificationsEnabled(); - } + } else + Timber.w("No bookmark match exists!"); return false; } //-------------------------------------------BOOKMARKS END------------------------------------------ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 60a477bc..74940ff2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,7 +14,7 @@ Info OK Cancel - "To use mTHMMY you have to agree to our Privacy Policy by choosing one of the buttons below. Choose \"Yes, I want to help\", if you consent to the collection of anonymized data that will help us improve the app. Otherwise, choose \"Nope, leave me alone\". You can change your preferences any time through the app's Settings. + "To use mTHMMY you have to agree to our Privacy Policy by choosing one of the options below. Choose \"Yes, I want to help\", if you consent to the collection of anonymized data that will help us improve the app. Otherwise, choose \"Nope, leave me alone\". You can change your preferences any time through the app's Settings. thmmy.gr From 2cf704b6935fabd1f66830a137814b2b1e4ed4c8 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 19:36:00 +0300 Subject: [PATCH 162/180] Board bookmarks hotfix --- .../thmmy/mthmmy/activities/board/BoardActivity.java | 6 +++--- .../main/java/gr/thmmy/mthmmy/base/BaseActivity.java | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) 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 edda9537..d3a74098 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 @@ -10,7 +10,6 @@ import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; -import android.widget.ImageButton; import android.widget.ProgressBar; import android.widget.Toast; @@ -94,7 +93,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo getSupportActionBar().setDisplayShowHomeEnabled(true); } - thisPageBookmark = new Bookmark(boardTitle, "b" + ThmmyPage.getBoardId(boardUrl), true); + thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), true); setBoardBookmark(findViewById(R.id.bookmark)); createDrawer(); @@ -318,7 +317,8 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo || !Objects.equals(boardTitle, parsedTitle)) { boardTitle = parsedTitle; toolbar.setTitle(boardTitle); - thisPageBookmark = new Bookmark(boardTitle, "b" + ThmmyPage.getBoardId(boardUrl), true); + thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), true); + setBoardBookmark(findViewById(R.id.bookmark)); } parsedTopics.clear(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index e504596d..3b2845ef 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -575,10 +575,10 @@ public abstract class BaseActivity extends AppCompatActivity { if (boardsBookmarked == null) return; if (bookmark.matchExists(boardsBookmarked)) { boardsBookmarked.remove(bookmark.findIndex(boardsBookmarked)); - FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); + FirebaseMessaging.getInstance().unsubscribeFromTopic("b" + bookmark.getId()); } else { - boardsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), false)); - FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId()); + boardsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), true)); + FirebaseMessaging.getInstance().subscribeToTopic("b" + bookmark.getId()); } updateBoardBookmarks(); } @@ -630,9 +630,9 @@ public abstract class BaseActivity extends AppCompatActivity { updateBoardBookmarks(); if (boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).isNotificationsEnabled()) - FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId()); + FirebaseMessaging.getInstance().subscribeToTopic("b" + bookmark.getId()); else - FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); + FirebaseMessaging.getInstance().unsubscribeFromTopic("b" + bookmark.getId()); return boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).isNotificationsEnabled(); } else From 1ab0492fcabacd7d911bc99ff8901cff5e12b2e2 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 20:06:27 +0300 Subject: [PATCH 163/180] Suppress board notification when user is already subscribed to topic --- .../gr/thmmy/mthmmy/base/BaseActivity.java | 7 +++---- .../java/gr/thmmy/mthmmy/model/Bookmark.java | 12 ++++++++++++ .../mthmmy/services/NotificationService.java | 18 ++++++++++++++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 3b2845ef..a8dc457e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -86,8 +86,8 @@ public abstract class BaseActivity extends AppCompatActivity { protected static SessionManager sessionManager; //Bookmarks - private static final String BOOKMARKS_SHARED_PREFS = "bookmarksSharedPrefs"; - private static final String BOOKMARKED_TOPICS_KEY = "bookmarkedTopicsKey"; + public static final String BOOKMARKS_SHARED_PREFS = "bookmarksSharedPrefs"; + public static final String BOOKMARKED_TOPICS_KEY = "bookmarkedTopicsKey"; private static final String BOOKMARKED_BOARDS_KEY = "bookmarkedBoardsKey"; protected Bookmark thisPageBookmark; private MenuItem thisPageBookmarkMenuButton; @@ -559,9 +559,8 @@ public abstract class BaseActivity extends AppCompatActivity { String tmpString = bookmarksFile.getString(BOOKMARKED_TOPICS_KEY, null); if (tmpString != null) topicsBookmarked = Bookmark.arrayFromString(tmpString); - else { + else topicsBookmarked = new ArrayList<>(); - } tmpString = bookmarksFile.getString(BOOKMARKED_BOARDS_KEY, null); if (tmpString != null) diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java b/app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java index 9e2aae95..1f383462 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java @@ -45,6 +45,18 @@ public class Bookmark implements java.io.Serializable { return false; } + public static boolean matchExistsById(ArrayList array, int id) { + if (array != null && !array.isEmpty()) { + for (Bookmark bookmark : array) { + if (bookmark != null) { + if (Objects.equals(Integer.parseInt(bookmark.getId()), id)) + return true; + } + } + } + return false; + } + public int findIndex(ArrayList array) { if (array != null && !array.isEmpty()) { for (int i = 0; i < array.size(); ++i) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java index 00dee3f3..d2d9f73c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java +++ b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java @@ -25,6 +25,7 @@ import org.json.JSONObject; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.topic.TopicActivity; import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.PostNotification; import timber.log.Timber; @@ -35,6 +36,9 @@ import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SELECTED_RING import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SETTINGS_SHARED_PREFS; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; +import static gr.thmmy.mthmmy.base.BaseActivity.BOOKMARKED_TOPICS_KEY; +import static gr.thmmy.mthmmy.base.BaseActivity.BOOKMARKS_SHARED_PREFS; +import static gr.thmmy.mthmmy.model.Bookmark.matchExistsById; public class NotificationService extends FirebaseMessagingService { private static final int buildVersion = Build.VERSION.SDK_INT; @@ -52,15 +56,25 @@ public class NotificationService extends FirebaseMessagingService { if (Integer.parseInt(json.getString("posterId")) != userId) { int boardId = -1; String boardTitle = null; + int topicId = Integer.parseInt(json.getString("topicId")); if(remoteMessage.getFrom().contains("b")){ Timber.i("FCM BOARD type message detected."); - //TODO: return early and don't create notification if the user is also subscribed to this topicId + + SharedPreferences bookmarksFile = getSharedPreferences(BOOKMARKS_SHARED_PREFS, Context.MODE_PRIVATE); + String tmpString = bookmarksFile.getString(BOOKMARKED_TOPICS_KEY, null); + if (tmpString != null){ + if(matchExistsById(Bookmark.arrayFromString(tmpString), topicId)){ + Timber.i("Board notification suppressed (already subscribed to topic)."); + return; + } + } + boardId = Integer.parseInt(json.getString("boardId")); boardTitle = json.getString("boardTitle"); } else Timber.i("FCM TOPIC type message detected."); - int topicId = Integer.parseInt(json.getString("topicId")); + int postId = Integer.parseInt(json.getString("postId")); String topicTitle = json.getString("topicTitle"); String poster = json.getString("poster"); From 09d83180f31f08e2b741ab6f2937600d82d2253a Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 20:19:58 +0300 Subject: [PATCH 164/180] Suppressed polls, uploads, up version & libs --- app/build.gradle | 24 +++++++++---------- app/src/main/assets/apache_libraries.html | 2 +- .../downloads/DownloadsActivity.java | 14 +++++------ .../mthmmy/activities/topic/TopicParser.java | 6 ++--- .../gr/thmmy/mthmmy/base/BaseActivity.java | 24 +++++++++---------- .../main/res/layout/activity_downloads.xml | 6 ++--- build.gradle | 6 ++--- 7 files changed, 40 insertions(+), 42 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 79a71684..99c25d80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "gr.thmmy.mthmmy" minSdkVersion 19 targetSdkVersion 28 - versionCode 13 - versionName "1.4.1" + versionCode 14 + versionName "1.5.0" archivesBaseName = "mTHMMY-v$versionName" } @@ -48,15 +48,15 @@ tasks.whenTaskAdded { task -> dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:27.1.1' - implementation 'com.android.support:design:27.1.1' - implementation 'com.android.support:preference-v7:27.1.1' - implementation 'com.android.support:preference-v14:27.1.1' - implementation 'com.android.support:support-v4:27.1.1' - implementation 'com.android.support:cardview-v7:27.1.1' - implementation 'com.android.support:recyclerview-v7:27.1.1' - implementation 'com.google.firebase:firebase-core:16.0.3' - implementation 'com.google.firebase:firebase-messaging:17.3.1' + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support:design:28.0.0' + implementation 'com.android.support:preference-v7:28.0.0' + implementation 'com.android.support:preference-v14:28.0.0' + implementation 'com.android.support:support-v4:28.0.0' + implementation 'com.android.support:cardview-v7:28.0.0' + implementation 'com.android.support:recyclerview-v7:28.0.0' + implementation 'com.google.firebase:firebase-core:16.0.4' + implementation 'com.google.firebase:firebase-messaging:17.3.3' implementation 'com.crashlytics.sdk.android:crashlytics:2.9.5' implementation 'com.squareup.okhttp3:okhttp:3.10.0' implementation 'com.squareup.picasso:picasso:2.5.2' @@ -72,7 +72,7 @@ dependencies { implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15' implementation 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1'//TODO: deprecated! implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2' - implementation 'com.jakewharton.timber:timber:4.7.0' + implementation 'com.jakewharton.timber:timber:4.7.1' implementation "ru.noties:markwon:2.0.0" implementation 'net.gotev:uploadservice:3.4.2' implementation 'net.gotev:uploadservice-okhttp:3.4.2' diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index 004d8c96..abcdb7d7 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -60,7 +60,7 @@
    MaterialProgressBar v1.4.2 (Copyright ©2015 Zhang Hai)
  • -
    Timber v4.7.0 (Copyright ©2013 Jake Wharton)
    +
    Timber v4.7.1 (Copyright ©2013 Jake Wharton)
  • Android Upload Service v3.4.2 (Copyright ©2013-2018 Aleksandar Gotev)
    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 index e67ed73a..acc8d489 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java @@ -4,13 +4,11 @@ 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.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Menu; import android.view.MenuItem; -import android.view.View; import android.widget.ProgressBar; import android.widget.Toast; @@ -55,7 +53,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter. private MaterialProgressBar progressBar; private RecyclerView recyclerView; private DownloadsAdapter downloadsAdapter; - private FloatingActionButton uploadFAB; + //private FloatingActionButton uploadFAB; private ParseDownloadPageTask parseDownloadPageTask; private int numberOfPages = -1; @@ -121,9 +119,9 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter. } }); - uploadFAB = findViewById(R.id.download_fab); - uploadFAB.setEnabled(false); - uploadFAB.hide(); +// uploadFAB = findViewById(R.id.upload_fab); +// uploadFAB.setEnabled(false); +// uploadFAB.hide(); parseDownloadPageTask = new ParseDownloadPageTask(); parseDownloadPageTask.execute(downloadsUrl); @@ -206,7 +204,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter. @Override protected void onPreExecute() { if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE); - if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(false); + //if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(false); } @Override @@ -304,7 +302,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter. toolbar.setTitle(downloadsTitle); ++pagesLoaded; - if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(true); + //if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(true); progressBar.setVisibility(ProgressBar.INVISIBLE); downloadsAdapter.notifyDataSetChanged(); isLoadingMore = false; 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 4ebbba5a..5a411e12 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 @@ -156,9 +156,9 @@ public class TopicParser { ArrayList parsedPostsList = new ArrayList<>(); - Poll poll = findPoll(topic); - if (poll != null) - parsedPostsList.add(poll); +// Poll poll = findPoll(topic); +// if (poll != null) +// parsedPostsList.add(poll); Elements postRows; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index a8dc457e..fc492b7a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -256,14 +256,14 @@ public abstract class BaseActivity extends AppCompatActivity { .withName(R.string.downloads) .withIcon(downloadsIcon) .withSelectedIcon(downloadsIconSelected); - uploadItem = new PrimaryDrawerItem() - .withTextColor(primaryColor) - .withSelectedColor(selectedPrimaryColor) - .withSelectedTextColor(selectedSecondaryColor) - .withIdentifier(UPLOAD_ID) - .withName(R.string.upload) - .withIcon(uploadIcon) - .withSelectedIcon(uploadIconSelected); +// uploadItem = new PrimaryDrawerItem() +// .withTextColor(primaryColor) +// .withSelectedColor(selectedPrimaryColor) +// .withSelectedTextColor(selectedSecondaryColor) +// .withIdentifier(UPLOAD_ID) +// .withName(R.string.upload) +// .withIcon(uploadIcon) +// .withSelectedIcon(uploadIconSelected); } else loginLogoutItem = new PrimaryDrawerItem() .withTextColor(primaryColor) @@ -387,7 +387,7 @@ public abstract class BaseActivity extends AppCompatActivity { }); if (sessionManager.isLoggedIn()) - drawerBuilder.addDrawerItems(homeItem, bookmarksItem, downloadsItem, uploadItem, settingsItem, loginLogoutItem, aboutItem); + drawerBuilder.addDrawerItems(homeItem, bookmarksItem, downloadsItem, settingsItem, loginLogoutItem, aboutItem); else drawerBuilder.addDrawerItems(homeItem, bookmarksItem, settingsItem, loginLogoutItem, aboutItem); @@ -415,9 +415,9 @@ public abstract class BaseActivity extends AppCompatActivity { if (!drawer.getDrawerItems().contains(downloadsItem)) { drawer.addItemAtPosition(downloadsItem, 2); } - if (!drawer.getDrawerItems().contains(uploadItem)) { - drawer.addItemAtPosition(uploadItem, 3); - } +// if (!drawer.getDrawerItems().contains(uploadItem)) { +// drawer.addItemAtPosition(uploadItem, 3); +// } loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout profileDrawerItem.withName(sessionManager.getUsername()); if (sessionManager.hasAvatar()) diff --git a/app/src/main/res/layout/activity_downloads.xml b/app/src/main/res/layout/activity_downloads.xml index 85fbe0ea..0856b9c3 100644 --- a/app/src/main/res/layout/activity_downloads.xml +++ b/app/src/main/res/layout/activity_downloads.xml @@ -48,15 +48,15 @@ app:mpb_indeterminateTint="@color/accent" app:mpb_progressStyle="horizontal"/> - + app:srcCompat="@drawable/ic_file_upload_white_24dp"/>--> diff --git a/build.gradle b/build.gradle index 65178d9a..11cbc2e0 100644 --- a/build.gradle +++ b/build.gradle @@ -8,9 +8,9 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0' - classpath 'com.google.gms:google-services:4.0.1' - classpath 'io.fabric.tools:gradle:1.25.4' + classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.google.gms:google-services:4.1.0' + classpath 'io.fabric.tools:gradle:1.26.1' } } From 3ed2081d8b8cd39a5e6397ae2cf8a804ffc14716 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 21:28:48 +0300 Subject: [PATCH 165/180] Up OkHttp --- app/build.gradle | 4 ++-- app/proguard-rules.pro | 2 ++ app/src/main/assets/apache_libraries.html | 2 +- .../gr/thmmy/mthmmy/services/NotificationService.java | 11 ++++++----- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 99c25d80..cb7439de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,7 +25,7 @@ android { def date = new Date().format('ddMMyy_HHmmss') archivesBaseName = archivesBaseName + "-$date" // Disable fabric build ID generation for debug builds - ext.enableCrashlytics = false; + ext.enableCrashlytics = false } } @@ -58,7 +58,7 @@ dependencies { implementation 'com.google.firebase:firebase-core:16.0.4' implementation 'com.google.firebase:firebase-messaging:17.3.3' implementation 'com.crashlytics.sdk.android:crashlytics:2.9.5' - implementation 'com.squareup.okhttp3:okhttp:3.10.0' + implementation 'com.squareup.okhttp3:okhttp:3.11.0' implementation 'com.squareup.picasso:picasso:2.5.2' implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' implementation 'org.jsoup:jsoup:1.10.3' //TODO: Warning: upgrading from 1.10.3 will break stuff! diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index c06e027a..b603ba91 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -26,6 +26,8 @@ -dontwarn org.conscrypt.** # A resource is loaded with a relative path so the package of this class must be preserved. -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase +# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. +-dontwarn org.codehaus.mojo.animal_sniffer.* # Picasso -dontwarn com.squareup.okhttp.** diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index abcdb7d7..a8ff5d90 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -39,7 +39,7 @@
    • -
      OkHttp v3.10.0 (Copyright ©2016 Square, Inc.)
      +
      OkHttp v3.11.0 (Copyright ©2016 Square, Inc.)
    • Picasso v2.5.2 (Copyright ©2013 Square, Inc.)
      diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java index d2d9f73c..39e34062 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java +++ b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java @@ -156,7 +156,7 @@ public class NotificationService extends FirebaseMessagingService { int k1 = postNotification.getTopicId(); int k2 = postNotification.getBoardId(); notificationId = -(((k1+k2)*(k1+k2+1))/2+k2); - contentText = "New post in " + postNotification.getTopicTitle(); + contentText = "New post in \"" + postNotification.getTopicTitle() + "\""; } int newPostsCount = 1; @@ -221,16 +221,17 @@ public class NotificationService extends FirebaseMessagingService { .setGroup(GROUP_KEY) .setAutoCancel(true) .setStyle(new NotificationCompat.InboxStyle() - .setSummaryText("New Posts")) + .setSummaryText("New Posts")) .setDefaults(Notification.DEFAULT_ALL); } - NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // Since Android Oreo notification channel is needed. - if (buildVersion >= Build.VERSION_CODES.O) - notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)); + if (buildVersion >= Build.VERSION_CODES.O){ + if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) + notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)); + } notificationManager.notify(NEW_POST_TAG, notificationId, notificationBuilder.build()); From 221ff509207f5168bb38484b52414b5917f91c70 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 22:09:00 +0300 Subject: [PATCH 166/180] Suppressed Uploads in Settings --- .../mthmmy/activities/create_content/NewTopicTask.java | 2 +- .../mthmmy/activities/settings/SettingsFragment.java | 8 ++++---- .../gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java | 2 +- app/src/main/res/xml/app_preferences.xml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java index 253280eb..985e0930 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java @@ -52,7 +52,7 @@ public class NewTopicTask extends AsyncTask { createTopicUrl = document.select("form").first().attr("action"); final String appSignature = "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/" + - "details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i][/size][/right]"; + "details?id=gr.thmmy.mthmmy]mTHMMY[/url] [/i][/size][/right]"; RequestBody postBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java index 7309090a..bb0fdcdc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java @@ -96,8 +96,8 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared findPreference(POSTING_CATEGORY).setVisible(isLoggedIn); findPreference(POSTING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); - findPreference(UPLOADING_CATEGORY).setVisible(isLoggedIn); - findPreference(UPLOADING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); + //findPreference(UPLOADING_CATEGORY).setVisible(isLoggedIn); + //findPreference(UPLOADING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); if (!isLoggedIn && defaultHomeTabEntries.contains("Unread")) { defaultHomeTabEntries.remove("Unread"); @@ -171,8 +171,8 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared findPreference(POSTING_CATEGORY).setVisible(isLoggedIn); findPreference(POSTING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); - findPreference(UPLOADING_CATEGORY).setVisible(isLoggedIn); - findPreference(UPLOADING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); + //findPreference(UPLOADING_CATEGORY).setVisible(isLoggedIn); + //findPreference(UPLOADING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); if (!isLoggedIn && defaultHomeTabEntries.contains("Unread")) { defaultHomeTabEntries.remove("Unread"); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java index dfbdbb7f..13ad66d9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java @@ -32,7 +32,7 @@ public class ReplyTask extends AsyncTask { @Override protected Posting.REPLY_STATUS doInBackground(String... args) { final String sentFrommTHMMY = includeAppSignature - ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url][/i][/size][/right]" + ? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY[/url] [/i][/size][/right]" : ""; RequestBody postBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) diff --git a/app/src/main/res/xml/app_preferences.xml b/app/src/main/res/xml/app_preferences.xml index 82127641..4c7c7f6b 100644 --- a/app/src/main/res/xml/app_preferences.xml +++ b/app/src/main/res/xml/app_preferences.xml @@ -38,7 +38,7 @@ android:summary="@string/pref_summary_posting_app_signature_enable" /> - - + --> Date: Sat, 13 Oct 2018 22:25:15 +0300 Subject: [PATCH 167/180] allow link insertion without link text --- .../thmmy/mthmmy/editorview/EditorView.java | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index 0cb17141..527b3fcb 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -21,6 +21,7 @@ import android.view.LayoutInflater; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; +import android.widget.Button; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.ScrollView; @@ -210,26 +211,33 @@ public class EditorView extends LinearLayout { linkText.getEditText().setText( editText.getText().toString().substring(editText.getSelectionStart(), editText.getSelectionEnd())); } - new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) + AlertDialog linkDialog = new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) .setTitle(R.string.dialog_create_link_title) .setView(dialogBody) - .setPositiveButton(R.string.ok, (dialog, which) -> { - if (TextUtils.isEmpty(Objects.requireNonNull(linkUrl.getEditText()).getText().toString())) { - linkUrl.setError(context.getString(R.string.input_field_required)); - return; - } - if (TextUtils.isEmpty(Objects.requireNonNull(linkText.getEditText()).getText().toString())) { - linkUrl.setError(context.getString(R.string.input_field_required)); - return; - } + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) + .create(); + linkDialog.setOnShowListener(dialogInterface -> { + Button button = linkDialog.getButton(AlertDialog.BUTTON_POSITIVE); + button.setOnClickListener(view12 -> { + if (TextUtils.isEmpty(Objects.requireNonNull(linkUrl.getEditText()).getText().toString())) { + linkUrl.setError(context.getString(R.string.input_field_required)); + return; + } - if (hadTextSelection) editText.getText().delete(start, end); + if (hadTextSelection) editText.getText().delete(start, end); + if (!TextUtils.isEmpty(linkText.getEditText().getText())) { getText().insert(editText.getSelectionStart(), "[url=" + - Objects.requireNonNull(linkUrl.getEditText()).getText().toString() + "]" + - Objects.requireNonNull(linkText.getEditText()).getText().toString() + "[/url]"); - }) - .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) - .show(); + linkUrl.getEditText().getText().toString() + "]" + + linkText.getEditText().getText().toString() + "[/url]"); + } + else + getText().insert(editText.getSelectionStart(), "[url]" + + linkUrl.getEditText().getText().toString() + "[/url]"); + linkDialog.dismiss(); + }); + }); + linkDialog.show(); break; } case R.drawable.ic_format_quote: { From 78c39fb7153967de4947ababc46c9001c0e96492 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 14 Oct 2018 12:53:14 +0300 Subject: [PATCH 168/180] allow touches when emoji keyboard is visible; internal overhaul --- .../create_content/CreateContentActivity.java | 24 +------ .../activities/topic/TopicActivity.java | 31 +-------- .../mthmmy/activities/topic/TopicAdapter.java | 39 ++++------- .../thmmy/mthmmy/editorview/EditorView.java | 69 ++++++++++++------- .../mthmmy/editorview/EmojiInputField.java | 8 +++ .../mthmmy/editorview/EmojiKeyboard.java | 46 +++++++++++-- .../mthmmy/editorview/IEmojiKeyboard.java | 32 +++++++++ 7 files changed, 141 insertions(+), 108 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index b0b6a11b..877df6b9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -8,7 +8,6 @@ import android.support.design.widget.TextInputLayout; import android.text.InputType; import android.view.View; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; import android.widget.Toast; import gr.thmmy.mthmmy.R; @@ -20,8 +19,7 @@ import gr.thmmy.mthmmy.session.SessionManager; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; -public class CreateContentActivity extends BaseActivity implements EmojiKeyboard.EmojiKeyboardOwner, - NewTopicTask.NewTopicTaskCallbacks { +public class CreateContentActivity extends BaseActivity implements NewTopicTask.NewTopicTaskCallbacks { public final static String EXTRA_NEW_TOPIC_URL = "new-topic-extra"; @@ -56,8 +54,7 @@ public class CreateContentActivity extends BaseActivity implements EmojiKeyboard subjectInput.getEditText().setImeOptions(EditorInfo.IME_ACTION_DONE); contentEditor = findViewById(R.id.main_content_editorview); - setEmojiKeyboardInputConnection(contentEditor.getInputConnection()); - contentEditor.setEmojiKeyboardOwner(this); + contentEditor.setEmojiKeyboard(emojiKeyboard); contentEditor.setOnSubmitListener(v -> { if (newTopicUrl != null) { boolean includeAppSignature = true; @@ -72,27 +69,10 @@ public class CreateContentActivity extends BaseActivity implements EmojiKeyboard } }); } - - @Override - public void setEmojiKeyboardVisible(boolean visible) { - emojiKeyboard.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - @Override - public boolean isEmojiKeyboardVisible() { - return emojiKeyboard.getVisibility() == View.VISIBLE; - } - - @Override - public void setEmojiKeyboardInputConnection(InputConnection ic) { - emojiKeyboard.setInputConnection(ic); - } - @Override public void onBackPressed() { if (emojiKeyboard.getVisibility() == View.VISIBLE) { emojiKeyboard.setVisibility(View.GONE); - contentEditor.updateEmojiKeyboardVisibility(); } else { super.onBackPressed(); } 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 12b79165..4d03649d 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 @@ -27,7 +27,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.ImageButton; import android.widget.LinearLayout; @@ -67,8 +66,7 @@ import static gr.thmmy.mthmmy.services.NotificationService.NEW_POST_TAG; * key {@link #BUNDLE_TOPIC_TITLE} for faster title rendering. */ @SuppressWarnings("unchecked") -public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFocusChangeListener, - EmojiKeyboard.EmojiKeyboardOwner { +public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFocusChangeListener { //Activity's variables /** * The key to use when putting topic's url String to {@link TopicActivity}'s Bundle. @@ -180,7 +178,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo getApplicationContext(), topicPageUrl); recyclerView.setLayoutManager(layoutManager); - topicAdapter = new TopicAdapter(this, topicItems); + topicAdapter = new TopicAdapter(this, emojiKeyboard, topicItems); recyclerView.setAdapter(topicAdapter); replyFAB = findViewById(R.id.topic_fab); @@ -269,16 +267,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo return; } else if (emojiKeyboard.getVisibility() == View.VISIBLE) { emojiKeyboard.setVisibility(View.GONE); - if (viewModel.isEditingPost()) { - TopicAdapter.EditMessageViewHolder vh = (TopicAdapter.EditMessageViewHolder) - recyclerView.findViewHolderForAdapterPosition(viewModel.getPostBeingEditedPosition()); - vh.editEditor.updateEmojiKeyboardVisibility(); - } - if (viewModel.isWritingReply()) { - TopicAdapter.QuickReplyViewHolder vh = (TopicAdapter.QuickReplyViewHolder) - recyclerView.findViewHolderForAdapterPosition(viewModel.postCount()); - vh.replyEditor.updateEmojiKeyboardVisibility(); - } return; } else if (viewModel.isWritingReply()) { topicItems.remove(topicItems.size() - 1); @@ -319,21 +307,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo recyclerView.scrollToPosition(position); } - @Override - public void setEmojiKeyboardVisible(boolean visible) { - emojiKeyboard.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - @Override - public boolean isEmojiKeyboardVisible() { - return emojiKeyboard.getVisibility() == View.VISIBLE; - } - - @Override - public void setEmojiKeyboardInputConnection(InputConnection ic) { - emojiKeyboard.setInputConnection(ic); - } - //--------------------------------------BOTTOM NAV BAR METHODS---------------------------------- /** 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 820c7770..bfc26961 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 @@ -26,7 +26,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.webkit.WebResourceRequest; import android.webkit.WebView; @@ -59,7 +58,7 @@ import gr.thmmy.mthmmy.activities.board.BoardActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.editorview.EditorView; -import gr.thmmy.mthmmy.editorview.EmojiKeyboard; +import gr.thmmy.mthmmy.editorview.IEmojiKeyboard; import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; @@ -91,7 +90,7 @@ class TopicAdapter extends RecyclerView.Adapter { private static int THUMBNAIL_SIZE; private final Context context; private final OnPostFocusChangeListener postFocusListener; - private final EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner; + private final IEmojiKeyboard emojiKeyboard; private final List topicItems; private TopicViewModel viewModel; @@ -99,11 +98,11 @@ class TopicAdapter extends RecyclerView.Adapter { * @param context the context of the {@link RecyclerView} * @param topicItems List of {@link Post} objects to use */ - TopicAdapter(TopicActivity context, List topicItems) { + TopicAdapter(TopicActivity context, IEmojiKeyboard emojiKeyboard, List topicItems) { this.context = context; this.topicItems = topicItems; this.postFocusListener = context; - this.emojiKeyboardOwner = context; + this.emojiKeyboard = emojiKeyboard; viewModel = ViewModelProviders.of(context).get(TopicViewModel.class); @@ -590,15 +589,9 @@ class TopicAdapter extends RecyclerView.Adapter { holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); holder.quickReplySubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - holder.replyEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.replyEditor.updateEmojiKeyboardVisibility(); - holder.replyEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - InputConnection ic12 = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic12); - holder.replyEditor.updateEmojiKeyboardVisibility(); - }); + holder.replyEditor.setEmojiKeyboard(emojiKeyboard); + holder.replyEditor.requestEditTextFocus(); + emojiKeyboard.registerEmojiInputField(holder.replyEditor); holder.replyEditor.setText(viewModel.getBuildedQuotes()); holder.replyEditor.setOnSubmitListener(view -> { @@ -611,7 +604,7 @@ class TopicAdapter extends RecyclerView.Adapter { imm.hideSoftInputFromWindow(view.getWindowToken(), 0); holder.itemView.setAlpha(0.5f); holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); + emojiKeyboard.hide(); viewModel.postReply(context, holder.quickReplySubject.getText().toString(), holder.replyEditor.getText().toString()); @@ -641,18 +634,10 @@ class TopicAdapter extends RecyclerView.Adapter { holder.editSubject.setRawInputType(InputType.TYPE_CLASS_TEXT); holder.editSubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - holder.editEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.editEditor.updateEmojiKeyboardVisibility(); + holder.editEditor.setEmojiKeyboard(emojiKeyboard); + holder.editEditor.requestEditTextFocus(); + emojiKeyboard.registerEmojiInputField(holder.editEditor); holder.editEditor.setText(viewModel.getPostBeingEditedText()); - holder.editEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - if (hasFocus) { - InputConnection ic1 = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic1); - holder.editEditor.updateEmojiKeyboardVisibility(); - } - }); holder.editEditor.setOnSubmitListener(view -> { if (holder.editSubject.getText().toString().isEmpty()) return; if (holder.editEditor.getText().toString().isEmpty()) { @@ -663,7 +648,7 @@ class TopicAdapter extends RecyclerView.Adapter { imm.hideSoftInputFromWindow(view.getWindowToken(), 0); holder.itemView.setAlpha(0.5f); holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); + emojiKeyboard.hide(); viewModel.editPost(position, holder.editSubject.getText().toString(), holder.editEditor.getText().toString()); }); diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index 527b3fcb..fb82337a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -31,7 +31,7 @@ import java.util.Objects; import gr.thmmy.mthmmy.R; -public class EditorView extends LinearLayout { +public class EditorView extends LinearLayout implements EmojiInputField { private SparseArray colors = new SparseArray<>(); @@ -39,7 +39,7 @@ public class EditorView extends LinearLayout { private TextInputEditText editText; private AppCompatImageButton emojiButton; private AppCompatImageButton submitButton; - private EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner; + private IEmojiKeyboard emojiKeyboard; public EditorView(Context context) { super(context); @@ -63,6 +63,22 @@ public class EditorView extends LinearLayout { edittextWrapper = findViewById(R.id.editor_edittext_wrapper); editText = findViewById(R.id.editor_edittext); + editText.setOnFocusChangeListener((view, focused) -> { + if (focused) emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); + }); + edittextWrapper.setOnFocusChangeListener((view, focused) -> { + if (focused) emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); + }); + editText.setOnClickListener(view -> { + if (!emojiKeyboard.isVisible()) { + InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); + imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); + } else { + InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getWindowToken(), 0); + requestEditTextFocus(); + } + }); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EditorView, 0, 0); try { @@ -79,11 +95,6 @@ public class EditorView extends LinearLayout { emojiButton = findViewById(R.id.emoji_keyboard_button); - editText.setOnTouchListener((v, event) -> { - if (emojiKeyboardOwner.isEmojiKeyboardVisible()) return true; - return false; - }); - colors.append(R.id.black, "black"); colors.append(R.id.red, "red"); colors.append(R.id.yellow, "yellow"); @@ -267,22 +278,28 @@ public class EditorView extends LinearLayout { emojiButton.setOnClickListener(view -> { InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); - assert imm != null; - if (emojiKeyboardOwner.isEmojiKeyboardVisible()) { + //cache selection. For some reason it gets reset sometimes + int selectionStart = editText.getSelectionStart(); + int selectionEnd = editText.getSelectionStart(); + if (emojiKeyboard.onEmojiButtonToggle()) { + //prevent system keyboard from appearing when clicking the edittext + editText.setTextIsSelectable(true); + imm.hideSoftInputFromWindow(getWindowToken(), 0); + } + else { editText.requestFocus(); imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); - emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); - } else { - imm.hideSoftInputFromWindow(getWindowToken(), 0); - view.clearFocus(); - emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); } - emojiKeyboardOwner.setEmojiKeyboardVisible(!emojiKeyboardOwner.isEmojiKeyboardVisible()); + editText.setSelection(selectionStart, selectionEnd); }); submitButton = findViewById(R.id.submit_button); } + public void setEmojiKeyboard(IEmojiKeyboard emojiKeyboard) { + this.emojiKeyboard = emojiKeyboard; + } + public TextInputEditText getEditText() { return editText; } @@ -307,18 +324,22 @@ public class EditorView extends LinearLayout { submitButton.setOnClickListener(onSubmitListener); } - public void setEmojiKeyboardOwner(EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner) { - this.emojiKeyboardOwner = emojiKeyboardOwner; - } - - public InputConnection getInputConnection() { - return editText.onCreateInputConnection(new EditorInfo()); + public boolean requestEditTextFocus() { + emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); + return editText.requestFocus(); } - public void updateEmojiKeyboardVisibility() { - if (emojiKeyboardOwner.isEmojiKeyboardVisible()) + @Override + public void onKeyboardVisibilityChange(boolean visible) { + if (visible) { emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); - else + } else { emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); + } + } + + @Override + public InputConnection getInputConnection() { + return editText.onCreateInputConnection(new EditorInfo()); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java new file mode 100644 index 00000000..0cdccd60 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java @@ -0,0 +1,8 @@ +package gr.thmmy.mthmmy.editorview; + +import android.view.inputmethod.InputConnection; + +public interface EmojiInputField { + void onKeyboardVisibilityChange(boolean visible); + InputConnection getInputConnection(); +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java index 14a63438..856498ec 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java @@ -12,9 +12,11 @@ import android.view.MotionEvent; import android.view.inputmethod.InputConnection; import android.widget.LinearLayout; +import java.util.HashSet; + import gr.thmmy.mthmmy.R; -public class EmojiKeyboard extends LinearLayout { +public class EmojiKeyboard extends LinearLayout implements IEmojiKeyboard { // TODO: Sort emojis in a way that makes sense private final Emoji[] emojis = {new Emoji(R.drawable.emoji_smiley, ":)"), @@ -134,7 +136,9 @@ public class EmojiKeyboard extends LinearLayout { new Emoji(R.drawable.emoji_smurf, "^smurf^") }; - InputConnection inputConnection; + private InputConnection inputConnection; + private HashSet emojiInputFields = new HashSet<>(); + private Context context; public EmojiKeyboard(Context context) { this(context, null, 0); @@ -150,6 +154,7 @@ public class EmojiKeyboard extends LinearLayout { } public void init(Context context, AttributeSet attrs) { + this.context = context; LayoutInflater.from(context).inflate(R.layout.emoji_keyboard, this, true); setOrientation(VERTICAL); setBackgroundColor(getResources().getColor(R.color.primary)); @@ -195,14 +200,43 @@ public class EmojiKeyboard extends LinearLayout { }); } + @Override + public void hide() { + setVisibility(GONE); + } + + @Override + public void registerEmojiInputField(EmojiInputField emojiInputField) { + emojiInputFields.add(emojiInputField); + } + public void setInputConnection(InputConnection inputConnection) { this.inputConnection = inputConnection; } - public interface EmojiKeyboardOwner { - void setEmojiKeyboardVisible(boolean visible); - boolean isEmojiKeyboardVisible(); - void setEmojiKeyboardInputConnection(InputConnection ic); + @Override + public boolean onEmojiButtonToggle() { + if (getVisibility() == VISIBLE) setVisibility(GONE); + else setVisibility(VISIBLE); + return getVisibility() == VISIBLE; + } + + @Override + public void onEmojiInputFieldFocused(EmojiInputField emojiInputField) { + setInputConnection(emojiInputField.getInputConnection()); + } + + @Override + public void setVisibility(int visibility) { + //notify input fields + for (EmojiInputField emojiInputField : emojiInputFields) + emojiInputField.onKeyboardVisibilityChange(visibility == VISIBLE); + super.setVisibility(visibility); + } + + @Override + public boolean isVisible() { + return getVisibility() == VISIBLE; } class Emoji { diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java new file mode 100644 index 00000000..3ec906f2 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java @@ -0,0 +1,32 @@ +package gr.thmmy.mthmmy.editorview; + +public interface IEmojiKeyboard { + /** + * Hide keyboard + */ + void hide(); + + /** + * Check if keyboard is visible + * @return true, if {@link EmojiKeyboard#getVisibility()} returns View.VISIBLE, otherwise false + */ + boolean isVisible(); + + /** + * Callback to the keyboard when {@link EditorView#emojiButton} is clicked + * @return whether the keyboard became visible or not + */ + boolean onEmojiButtonToggle(); + + /** + * Callback to create input connection with {@link EmojiInputField} + * @param emojiInputField the connected input field + */ + void onEmojiInputFieldFocused(EmojiInputField emojiInputField); + + /** + * Persist a set of all input fields to update all of them when visibility changes + * @param emojiInputField the input field to be added + */ + void registerEmojiInputField(EmojiInputField emojiInputField); +} From 67d53dca468fae386fc1453ffb142bccfd9c13c0 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 14 Oct 2018 13:00:47 +0300 Subject: [PATCH 169/180] adjust create content activity --- .../create_content/CreateContentActivity.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index 877df6b9..b770b7b5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -6,6 +6,7 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.support.design.widget.TextInputLayout; import android.text.InputType; +import android.text.TextUtils; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.Toast; @@ -55,14 +56,24 @@ public class CreateContentActivity extends BaseActivity implements NewTopicTask. contentEditor = findViewById(R.id.main_content_editorview); contentEditor.setEmojiKeyboard(emojiKeyboard); + emojiKeyboard.registerEmojiInputField(contentEditor); contentEditor.setOnSubmitListener(v -> { if (newTopicUrl != null) { + if (TextUtils.isEmpty(subjectInput.getEditText().getText())) { + subjectInput.setError("Required"); + return; + } + if (TextUtils.isEmpty(contentEditor.getText())) { + contentEditor.setError("Required"); + return; + } boolean includeAppSignature = true; SessionManager sessionManager = BaseActivity.getSessionManager(); if (sessionManager.isLoggedIn()) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); includeAppSignature = prefs.getBoolean(SettingsActivity.POSTING_APP_SIGNATURE_ENABLE_KEY, true); } + emojiKeyboard.setVisibility(View.GONE); new NewTopicTask(this, includeAppSignature).execute(newTopicUrl, subjectInput.getEditText().getText().toString(), contentEditor.getText().toString()); From 98cad92f403c9c0bac9602d708e7db3a42cc6d81 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 14 Oct 2018 13:15:27 +0300 Subject: [PATCH 170/180] include privacy policy in about --- .../mthmmy/activities/AboutActivity.java | 10 ++++++++ .../gr/thmmy/mthmmy/base/BaseActivity.java | 2 +- app/src/main/res/layout/activity_about.xml | 24 ++++++++++++++++++- app/src/main/res/values/strings.xml | 1 + 4 files changed, 35 insertions(+), 2 deletions(-) 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 896a5fb5..34ed4c32 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java @@ -6,6 +6,9 @@ import android.support.design.widget.AppBarLayout; import android.support.design.widget.CoordinatorLayout; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AlertDialog; +import android.text.SpannableString; +import android.text.method.LinkMovementMethod; +import android.text.style.UnderlineSpan; import android.view.LayoutInflater; import android.view.View; import android.webkit.WebView; @@ -81,6 +84,13 @@ public class AboutActivity extends BaseActivity { }); } + TextView privacyPolicy = findViewById(R.id.privacy_policy_header); + privacyPolicy.setMovementMethod(new LinkMovementMethod()); + SpannableString spannableString = new SpannableString(privacyPolicy.getText()); + spannableString.setSpan(new UnderlineSpan(), 0, spannableString.length(), 0); + privacyPolicy.setText(spannableString); + privacyPolicy.setOnClickListener(view -> showPrivacyPolicyDialog()); + } @Override diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index fc492b7a..79b377ea 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -754,7 +754,7 @@ public abstract class BaseActivity extends AppCompatActivity { alertDialog.show(); } - private void showPrivacyPolicyDialog() { + protected void showPrivacyPolicyDialog() { TextView privacyPolicyTextView = new TextView(this); privacyPolicyTextView.setPadding(30,20,30,20); privacyPolicyTextView.setTextColor(ContextCompat.getColor(this, R.color.primary_text)); diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 020c6e03..c4ecc43d 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -128,13 +128,35 @@ android:text="@string/the_mit_libraries" android:textColor="@color/accent" /> + + + Open Source The source code of mTHMMY can be found on Github (https://github.com/ThmmyNoLife/mTHMMY) along with further details of how one can contribute. You should see a funny pic! + Privacy policy Remove From 2113e81da86007ff341c045621d596bdbc69f472 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sun, 14 Oct 2018 18:30:05 +0300 Subject: [PATCH 171/180] Tiny doc fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 529f01a5..1dfb2197 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![API](https://img.shields.io/badge/API-19%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=19) [![Discord Channel](https://img.shields.io/badge/discord-public@mTHMMY-738bd7.svg?style=flat)][discord-server] -![alt text](app\src\main\res\mipmap-xhdpi\ic_launcher.png "mTHMMY") +![mTHMMY logo](app/src/main/res/mipmap-xhdpi/ic_launcher.png) A mobile app for [thmmy.gr](https://www.thmmy.gr). From b60a2064743965849625fdd4c0369e480a4d030e Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Mon, 15 Oct 2018 00:58:08 +0300 Subject: [PATCH 172/180] bira --- app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index b2a930ee..90115a0e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -68,8 +68,6 @@ public class BaseApplication extends Application { // Initialize Timber if (BuildConfig.DEBUG) Timber.plant(new Timber.DebugTree()); - else - Timber.plant(new CrashReportingTree()); //Shared Preferences SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE); @@ -82,6 +80,7 @@ public class BaseApplication extends Application { .build(); // Initialize Fabric with the debug-disabled Crashlytics. Fabric.with(this, crashlyticsKit); + Timber.plant(new CrashReportingTree()); Timber.i("Starting app with Crashlytics enabled."); } else Timber.i("Starting app with Crashlytics disabled."); From 104645c663110fecbe714f9d74511abbbe156585 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 13:01:20 +0300 Subject: [PATCH 173/180] Analytics & Crashlytics fixes --- app/proguard-rules.pro | 8 ++- .../activities/settings/SettingsFragment.java | 34 +++-------- .../gr/thmmy/mthmmy/base/BaseActivity.java | 17 +++--- .../gr/thmmy/mthmmy/base/BaseApplication.java | 56 +++++++++++-------- 4 files changed, 58 insertions(+), 57 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index b603ba91..9cde3150 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified -# in C:\Users\Ragnar\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt +# in sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # @@ -42,4 +42,8 @@ -keep public class pl.droidsonroids.gif.GifIOException{(int, java.lang.String);} # JSoup --keep class org.jsoup.** \ No newline at end of file +-keep class org.jsoup.** + +# Markwon +-keep class com.caverock.androidsvg.** { *; } +-dontwarn com.caverock.androidsvg.** \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java index bb0fdcdc..3f65e764 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java @@ -23,7 +23,6 @@ import timber.log.Timber; import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB; import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.POSTING_APP_SIGNATURE_ENABLE_KEY; -import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.UPLOADING_APP_SIGNATURE_ENABLE_KEY; public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String ARG_IS_LOGGED_IN = "selectedRingtoneKey"; @@ -93,25 +92,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - findPreference(POSTING_CATEGORY).setVisible(isLoggedIn); - findPreference(POSTING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); - - //findPreference(UPLOADING_CATEGORY).setVisible(isLoggedIn); - //findPreference(UPLOADING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); - - if (!isLoggedIn && defaultHomeTabEntries.contains("Unread")) { - defaultHomeTabEntries.remove("Unread"); - defaultHomeTabValues.remove("2"); - } else if (isLoggedIn && !defaultHomeTabEntries.contains("Unread")) { - defaultHomeTabEntries.add("Unread"); - defaultHomeTabValues.add("2"); - } - - CharSequence[] tmpCs = defaultHomeTabEntries.toArray(new CharSequence[defaultHomeTabEntries.size()]); - ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntries(tmpCs); - - tmpCs = defaultHomeTabValues.toArray(new CharSequence[defaultHomeTabValues.size()]); - ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntryValues(tmpCs); + updatePreferenceVisibility(); } @Override @@ -167,10 +148,12 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared public void updateUserLoginState(boolean isLoggedIn) { this.isLoggedIn = isLoggedIn; + updatePreferenceVisibility(); + } + private void updatePreferenceVisibility(){ findPreference(POSTING_CATEGORY).setVisible(isLoggedIn); findPreference(POSTING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); - //findPreference(UPLOADING_CATEGORY).setVisible(isLoggedIn); //findPreference(UPLOADING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); @@ -195,13 +178,14 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared if (key.equals(getString(R.string.pref_privacy_crashlytics_enable_key))) { enabled = sharedPreferences.getBoolean(key, false); if(enabled) - Timber.i("Crashlytics collection will be enabled after restarting."); - else + BaseApplication.getInstance().startFirebaseCrashlyticsCollection(); + else { Timber.i("Crashlytics collection will be disabled after restarting."); - Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This change will take effect once you restart the app.", Toast.LENGTH_SHORT).show(); + Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This change will take effect once you restart the app.", Toast.LENGTH_SHORT).show(); + } } else if (key.equals(getString(R.string.pref_privacy_analytics_enable_key))) { enabled = sharedPreferences.getBoolean(key, false); - BaseApplication.getInstance().firebaseAnalyticsCollection(enabled); + BaseApplication.getInstance().setFirebaseAnalyticsCollection(enabled); if(enabled) Timber.i("Analytics collection enabled."); else diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 79b377ea..2341fd70 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -51,7 +51,6 @@ 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.activities.settings.SettingsActivity; -import gr.thmmy.mthmmy.activities.upload.UploadActivity; import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.services.DownloadHelper; @@ -352,11 +351,11 @@ public abstract class BaseActivity extends AppCompatActivity { intent.putExtras(extras); startActivity(intent); } - } else if (drawerItem.equals(UPLOAD_ID)) { - if (!(BaseActivity.this instanceof UploadActivity)) { - Intent intent = new Intent(BaseActivity.this, UploadActivity.class); - startActivity(intent); - } +// } else if (drawerItem.equals(UPLOAD_ID)) { +// if (!(BaseActivity.this instanceof UploadActivity)) { +// Intent intent = new Intent(BaseActivity.this, UploadActivity.class); +// startActivity(intent); +// } } else if (drawerItem.equals(BOOKMARKS_ID)) { if (!(BaseActivity.this instanceof BookmarkActivity)) { Intent intent = new Intent(BaseActivity.this, BookmarkActivity.class); @@ -742,7 +741,11 @@ public abstract class BaseActivity extends AppCompatActivity { AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); builder.setTitle("User Agreement"); builder.setMessage(R.string.user_agreement_dialog_text); - builder.setPositiveButton("Yes, I want to help", (dialogInterface, i) -> FirebaseMessaging.getInstance().setAutoInitEnabled(true)); + builder.setPositiveButton("Yes, I want to help", (dialogInterface, i) -> { + FirebaseMessaging.getInstance().setAutoInitEnabled(true); + BaseApplication.getInstance().startFirebaseCrashlyticsCollection(); + BaseApplication.getInstance().setFirebaseAnalyticsCollection(true); + }); builder.setNegativeButton("Nope, leave me alone", (dialogInterface, i) -> FirebaseMessaging.getInstance().setAutoInitEnabled(true)); builder.setNeutralButton("Privacy Policy", (dialog, which) -> {/*Will be overridden below*/}); builder.setCancelable(false); diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index 90115a0e..6a01e61c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -6,6 +6,7 @@ import android.content.SharedPreferences; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v4.content.ContextCompat; import android.util.DisplayMetrics; import android.widget.ImageView; @@ -39,8 +40,6 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import timber.log.Timber; -import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SETTINGS_SHARED_PREFS; - public class BaseApplication extends Application { private static BaseApplication baseApplication; //BaseApplication singleton @@ -71,18 +70,11 @@ public class BaseApplication extends Application { //Shared Preferences SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE); - SharedPreferences settingsSharedPrefs = getSharedPreferences(SETTINGS_SHARED_PREFS, Context.MODE_PRIVATE); + SharedPreferences settingsSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - // Set up Crashlytics, disabled for debug builds - if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)) { - Crashlytics crashlyticsKit = new Crashlytics.Builder() - .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) - .build(); - // Initialize Fabric with the debug-disabled Crashlytics. - Fabric.with(this, crashlyticsKit); - Timber.plant(new CrashReportingTree()); - Timber.i("Starting app with Crashlytics enabled."); - } else + if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)) + startFirebaseCrashlyticsCollection(); + else Timber.i("Starting app with Crashlytics disabled."); firebaseAnalytics = FirebaseAnalytics.getInstance(this); @@ -153,16 +145,6 @@ public class BaseApplication extends Application { dpWidth = displayMetrics.widthPixels / displayMetrics.density; } - public void logFirebaseAnalyticsEvent(String event, Bundle params) { - firebaseAnalytics.logEvent(event, params); - } - - public void firebaseAnalyticsCollection(boolean enabled) { - firebaseAnalytics.setAnalyticsCollectionEnabled(enabled); - if(!enabled) - firebaseAnalytics.resetAnalyticsData(); - } - //Getters public Context getContext() { return getApplicationContext(); @@ -179,4 +161,32 @@ public class BaseApplication extends Application { public float getDpWidth() { return dpWidth; } + + + //--------------------Firebase-------------------- + + public void logFirebaseAnalyticsEvent(String event, Bundle params) { + firebaseAnalytics.logEvent(event, params); + } + + public void setFirebaseAnalyticsCollection(boolean enabled) { + firebaseAnalytics.setAnalyticsCollectionEnabled(enabled); + if(!enabled) + firebaseAnalytics.resetAnalyticsData(); + } + + // Set up Crashlytics, disabled for debug builds + public void startFirebaseCrashlyticsCollection() { + if(!Fabric.isInitialized()){ + Crashlytics crashlyticsKit = new Crashlytics.Builder() + .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) + .build(); + // Initialize Fabric with the debug-disabled Crashlytics. + Fabric.with(this, crashlyticsKit); + Timber.plant(new CrashReportingTree()); + Timber.i("Crashlytics enabled."); + } + else + Timber.i("Crashlytics were already initialized for this app session."); + } } From 0a757a3e2b72999d23aff80cfb089b3b99f274b8 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 14:39:47 +0300 Subject: [PATCH 174/180] Consent fix --- .../gr/thmmy/mthmmy/base/BaseActivity.java | 24 +++++++++++++++---- .../gr/thmmy/mthmmy/base/BaseApplication.java | 3 ++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 2341fd70..dba06d2b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -90,6 +90,7 @@ public abstract class BaseActivity extends AppCompatActivity { private static final String BOOKMARKED_BOARDS_KEY = "bookmarkedBoardsKey"; protected Bookmark thisPageBookmark; private MenuItem thisPageBookmarkMenuButton; + private SharedPreferences sharedPreferences; private SharedPreferences bookmarksFile; private ArrayList topicsBookmarked; private ArrayList boardsBookmarked; @@ -99,10 +100,14 @@ public abstract class BaseActivity extends AppCompatActivity { protected Drawer drawer; private MainActivity mainActivity; + private boolean isMainActivity; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + isMainActivity = this instanceof MainActivity; + if (client == null) client = BaseApplication.getInstance().getClient(); //must check every time - e.g. @@ -115,6 +120,8 @@ public abstract class BaseActivity extends AppCompatActivity { loadSavedBookmarks(); } + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + BaseViewModel baseViewModel = ViewModelProviders.of(this).get(BaseViewModel.class); baseViewModel.getCurrentPageBookmark().observe(this, thisPageBookmark -> setTopicBookmark(thisPageBookmarkMenuButton)); } @@ -123,7 +130,7 @@ public abstract class BaseActivity extends AppCompatActivity { protected void onResume() { super.onResume(); updateDrawer(); - if(LaunchType.getLaunchType()==FIRST_LAUNCH_EVER||LaunchType.getLaunchType()== INDETERMINATE) + if(!sharedPreferences.getBoolean(getString(R.string.user_consent_shared_preference_key),false)) showUserConsentDialog(); } @@ -338,7 +345,7 @@ public abstract class BaseActivity extends AppCompatActivity { .withAccountHeader(accountHeader) .withOnDrawerItemClickListener((view, position, drawerItem) -> { if (drawerItem.equals(HOME_ID)) { - if (!(BaseActivity.this instanceof MainActivity)) { + if (!isMainActivity) { Intent intent = new Intent(BaseActivity.this, MainActivity.class); startActivity(intent); } @@ -392,7 +399,7 @@ public abstract class BaseActivity extends AppCompatActivity { drawer = drawerBuilder.build(); - if (!(BaseActivity.this instanceof MainActivity)) + if (!isMainActivity) drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(false); drawer.setOnDrawerNavigationListener(clickedView -> { @@ -742,11 +749,15 @@ public abstract class BaseActivity extends AppCompatActivity { builder.setTitle("User Agreement"); builder.setMessage(R.string.user_agreement_dialog_text); builder.setPositiveButton("Yes, I want to help", (dialogInterface, i) -> { + addUserConsent(); FirebaseMessaging.getInstance().setAutoInitEnabled(true); BaseApplication.getInstance().startFirebaseCrashlyticsCollection(); BaseApplication.getInstance().setFirebaseAnalyticsCollection(true); }); - builder.setNegativeButton("Nope, leave me alone", (dialogInterface, i) -> FirebaseMessaging.getInstance().setAutoInitEnabled(true)); + builder.setNegativeButton("Nope, leave me alone", (dialogInterface, i) -> { + addUserConsent(); + FirebaseMessaging.getInstance().setAutoInitEnabled(true); + }); builder.setNeutralButton("Privacy Policy", (dialog, which) -> {/*Will be overridden below*/}); builder.setCancelable(false); AlertDialog alertDialog = builder.create(); @@ -791,6 +802,11 @@ public abstract class BaseActivity extends AppCompatActivity { } } + private void addUserConsent (){ + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(getString(R.string.user_consent_shared_preference_key), true).apply(); + } + //----------------------------------MISC---------------------- protected void setMainActivity(MainActivity mainActivity) { this.mainActivity = mainActivity; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index 6a01e61c..e1a33b30 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -50,7 +50,8 @@ public class BaseApplication extends Application { private OkHttpClient client; private SessionManager sessionManager; - private final String SHARED_PREFS = "ThmmySharedPrefs"; + //TODO: maybe use PreferenceManager.getDefaultSharedPreferences here as well? + private static final String SHARED_PREFS = "ThmmySharedPrefs"; //Display Metrics private static float dpWidth; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db3794c9..bc145117 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,6 +15,7 @@ OK Cancel "To use mTHMMY you have to agree to our Privacy Policy by choosing one of the options below. Choose \"Yes, I want to help\", if you consent to the collection of anonymized data that will help us improve the app. Otherwise, choose \"Nope, leave me alone\". You can change your preferences any time through the app's Settings. + user_consent_shared_preference_key thmmy.gr From 268b446b03a9432f98acbd716b06ebfcbf1d504b Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 16:35:58 +0300 Subject: [PATCH 175/180] Settings fix --- .../mthmmy/activities/LoginActivity.java | 2 +- .../mthmmy/activities/main/MainActivity.java | 2 +- .../activities/settings/SettingsActivity.java | 3 +- .../activities/settings/SettingsFragment.java | 58 +++++++++++++------ .../gr/thmmy/mthmmy/base/BaseActivity.java | 3 - .../main/res/xml/app_preferences_guest.xml | 46 +++++++++++++++ ...eferences.xml => app_preferences_user.xml} | 0 7 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 app/src/main/res/xml/app_preferences_guest.xml rename app/src/main/res/xml/{app_preferences.xml => app_preferences_user.xml} (100%) 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 add3abaf..a7adbf02 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java @@ -46,7 +46,7 @@ public class LoginActivity extends BaseActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); - PreferenceManager.setDefaultValues(this, R.xml.app_preferences, false); + PreferenceManager.setDefaultValues(this, R.xml.app_preferences_user, false); //Variables initialization inputUsername = findViewById(R.id.username); 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 4ffc3dff..ffd82dda 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 @@ -58,7 +58,7 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF redirectToActivityFromIntent(intentFilter); setContentView(R.layout.activity_main); - PreferenceManager.setDefaultValues(this, R.xml.app_preferences, false); + PreferenceManager.setDefaultValues(this, R.xml.app_preferences_user, false); if (sessionManager.isLoginScreenDefault()) { //Go to login diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java index 5d864eeb..4383732b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java @@ -42,8 +42,7 @@ public class SettingsActivity extends BaseActivity { protected void onResume() { drawer.setSelection(SETTINGS_ID); super.onResume(); - if (preferenceFragment != null) { + if (preferenceFragment != null) preferenceFragment.updateUserLoginState(sessionManager.isLoggedIn()); - } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java index 3f65e764..922c2e21 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java @@ -22,9 +22,12 @@ import gr.thmmy.mthmmy.base.BaseApplication; import timber.log.Timber; import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB; -import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.POSTING_APP_SIGNATURE_ENABLE_KEY; public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + private enum PREFS_TYPE { + NOT_SET, USER, GUEST + } + public static final String ARG_IS_LOGGED_IN = "selectedRingtoneKey"; //Preferences xml keys @@ -40,6 +43,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared private SharedPreferences settingsFile; + private PREFS_TYPE prefs_type = PREFS_TYPE.NOT_SET; private boolean isLoggedIn = false; private ArrayList defaultHomeTabEntries = new ArrayList<>(); private ArrayList defaultHomeTabValues = new ArrayList<>(); @@ -85,8 +89,17 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared @Override public void onCreatePreferences(Bundle bundle, String rootKey) { - // Load the Preferences from the XML file - addPreferencesFromResource(R.xml.app_preferences); + isLoggedIn = BaseApplication.getInstance().getSessionManager().isLoggedIn(); //Ensures it stays updated + // Add the Preferences from the XML file if needed + if(isLoggedIn&&(prefs_type==PREFS_TYPE.GUEST||prefs_type==PREFS_TYPE.NOT_SET)){ + prefs_type = PREFS_TYPE.USER; + addPreferencesFromResource(R.xml.app_preferences_user); + + } + else if(!isLoggedIn&&(prefs_type==PREFS_TYPE.USER||prefs_type==PREFS_TYPE.NOT_SET)){ + prefs_type = PREFS_TYPE.GUEST; + addPreferencesFromResource(R.xml.app_preferences_guest); + } } @Override @@ -152,24 +165,33 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared } private void updatePreferenceVisibility(){ - findPreference(POSTING_CATEGORY).setVisible(isLoggedIn); - findPreference(POSTING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); - //findPreference(UPLOADING_CATEGORY).setVisible(isLoggedIn); - //findPreference(UPLOADING_APP_SIGNATURE_ENABLE_KEY).setVisible(isLoggedIn); - - if (!isLoggedIn && defaultHomeTabEntries.contains("Unread")) { - defaultHomeTabEntries.remove("Unread"); - defaultHomeTabValues.remove("2"); - } else if (isLoggedIn && !defaultHomeTabEntries.contains("Unread")) { - defaultHomeTabEntries.add("Unread"); - defaultHomeTabValues.add("2"); + boolean updateHomeTabs=false; + if(isLoggedIn&& prefs_type==PREFS_TYPE.GUEST) { + prefs_type = PREFS_TYPE.USER; + setPreferencesFromResource(R.xml.app_preferences_user, getPreferenceScreen().getKey()); + if(!defaultHomeTabEntries.contains("Unread")){ + defaultHomeTabEntries.add("Unread"); + defaultHomeTabValues.add("2"); + updateHomeTabs=true; + } + } + else if(!isLoggedIn&&prefs_type==PREFS_TYPE.USER){ + prefs_type = PREFS_TYPE.GUEST; + setPreferencesFromResource(R.xml.app_preferences_guest,getPreferenceScreen().getKey()); + if(defaultHomeTabEntries.contains("Unread")){ + defaultHomeTabEntries.remove("Unread"); + defaultHomeTabValues.remove("2"); + updateHomeTabs=true; + } } - CharSequence[] tmpCs = defaultHomeTabEntries.toArray(new CharSequence[defaultHomeTabEntries.size()]); - ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntries(tmpCs); + if(updateHomeTabs){ + CharSequence[] tmpCs = defaultHomeTabEntries.toArray(new CharSequence[defaultHomeTabEntries.size()]); + ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntries(tmpCs); - tmpCs = defaultHomeTabValues.toArray(new CharSequence[defaultHomeTabValues.size()]); - ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntryValues(tmpCs); + tmpCs = defaultHomeTabValues.toArray(new CharSequence[defaultHomeTabValues.size()]); + ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntryValues(tmpCs); + } } @Override diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index dba06d2b..37db7c41 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -56,7 +56,6 @@ import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.services.DownloadHelper; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.FileUtils; -import gr.thmmy.mthmmy.utils.LaunchType; import gr.thmmy.mthmmy.viewmodel.BaseViewModel; import okhttp3.OkHttpClient; import ru.noties.markwon.LinkResolverDef; @@ -74,8 +73,6 @@ import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_ import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR; import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS; import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; -import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.FIRST_LAUNCH_EVER; -import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.INDETERMINATE; public abstract class BaseActivity extends AppCompatActivity { // Client & Cookies diff --git a/app/src/main/res/xml/app_preferences_guest.xml b/app/src/main/res/xml/app_preferences_guest.xml new file mode 100644 index 00000000..4aa2227f --- /dev/null +++ b/app/src/main/res/xml/app_preferences_guest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/app_preferences.xml b/app/src/main/res/xml/app_preferences_user.xml similarity index 100% rename from app/src/main/res/xml/app_preferences.xml rename to app/src/main/res/xml/app_preferences_user.xml From 85d414db64715ab5c88b0eb6621485ef9c281ee6 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 17:54:44 +0300 Subject: [PATCH 176/180] Settings hotfix --- .../activities/settings/SettingsFragment.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java index 922c2e21..df97ad07 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java @@ -59,11 +59,14 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared public SettingsFragment() { defaultHomeTabEntries.add("Recent"); defaultHomeTabEntries.add("Forum"); - defaultHomeTabEntries.add("Unread"); defaultHomeTabValues.add("0"); defaultHomeTabValues.add("1"); - defaultHomeTabValues.add("2"); + + if(isLoggedIn = BaseApplication.getInstance().getSessionManager().isLoggedIn()){ + defaultHomeTabEntries.add("Unread"); + defaultHomeTabValues.add("2"); + } } @Override @@ -94,7 +97,6 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared if(isLoggedIn&&(prefs_type==PREFS_TYPE.GUEST||prefs_type==PREFS_TYPE.NOT_SET)){ prefs_type = PREFS_TYPE.USER; addPreferencesFromResource(R.xml.app_preferences_user); - } else if(!isLoggedIn&&(prefs_type==PREFS_TYPE.USER||prefs_type==PREFS_TYPE.NOT_SET)){ prefs_type = PREFS_TYPE.GUEST; @@ -165,14 +167,12 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared } private void updatePreferenceVisibility(){ - boolean updateHomeTabs=false; if(isLoggedIn&& prefs_type==PREFS_TYPE.GUEST) { prefs_type = PREFS_TYPE.USER; setPreferencesFromResource(R.xml.app_preferences_user, getPreferenceScreen().getKey()); if(!defaultHomeTabEntries.contains("Unread")){ defaultHomeTabEntries.add("Unread"); defaultHomeTabValues.add("2"); - updateHomeTabs=true; } } else if(!isLoggedIn&&prefs_type==PREFS_TYPE.USER){ @@ -181,17 +181,14 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared if(defaultHomeTabEntries.contains("Unread")){ defaultHomeTabEntries.remove("Unread"); defaultHomeTabValues.remove("2"); - updateHomeTabs=true; } } - if(updateHomeTabs){ - CharSequence[] tmpCs = defaultHomeTabEntries.toArray(new CharSequence[defaultHomeTabEntries.size()]); - ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntries(tmpCs); + CharSequence[] tmpCs = defaultHomeTabEntries.toArray(new CharSequence[defaultHomeTabEntries.size()]); + ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntries(tmpCs); - tmpCs = defaultHomeTabValues.toArray(new CharSequence[defaultHomeTabValues.size()]); - ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntryValues(tmpCs); - } + tmpCs = defaultHomeTabValues.toArray(new CharSequence[defaultHomeTabValues.size()]); + ((ListPreference) findPreference(DEFAULT_HOME_TAB)).setEntryValues(tmpCs); } @Override From 61c3da68fb6572635d28ee16bf03575e054f3b54 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 18:17:12 +0300 Subject: [PATCH 177/180] Redirect to previous activity after login --- app/build.gradle | 1 + .../gr/thmmy/mthmmy/activities/LoginActivity.java | 13 +++++++++---- .../thmmy/mthmmy/activities/main/MainActivity.java | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index cb7439de..ecbd4dbc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,6 +19,7 @@ android { buildTypes { release { minifyEnabled true + shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { 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 a7adbf02..d6c840ad 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java @@ -40,12 +40,15 @@ public class LoginActivity extends BaseActivity { /* --Graphics End-- */ private LoginTask loginTask; + private boolean initialRedirect; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); + initialRedirect = getIntent().getBooleanExtra("REDIRECT", false); + PreferenceManager.setDefaultValues(this, R.xml.app_preferences_user, false); //Variables initialization @@ -56,7 +59,6 @@ public class LoginActivity extends BaseActivity { //Login button Click Event btnLogin.setOnClickListener(view -> { - Timber.d("Login"); //Get username and password strings username = inputUsername.getText().toString().trim(); @@ -162,9 +164,12 @@ public class LoginActivity extends BaseActivity { "Welcome, " + sessionManager.getUsername() + "!", Toast.LENGTH_LONG) .show(); BaseApplication.getInstance().logFirebaseAnalyticsEvent(FirebaseAnalytics.Event.LOGIN, null); - //Go to main - Intent intent = new Intent(LoginActivity.this, MainActivity.class); - startActivity(intent); + if(initialRedirect){ + Intent intent = new Intent(LoginActivity.this, MainActivity.class); + startActivity(intent); + } else + onBackPressed(); + finish(); overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); break; 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 ffd82dda..67f99897 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 @@ -63,6 +63,7 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF if (sessionManager.isLoginScreenDefault()) { //Go to login Intent intent = new Intent(MainActivity.this, LoginActivity.class); + intent.putExtra("REDIRECT", true); startActivity(intent); finish(); overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out); From 2b07865a70d9e1b78123abae38a68c8b20032912 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 21:21:36 +0300 Subject: [PATCH 178/180] Notification settings suppressed for >Oreo --- .../mthmmy/activities/LoginActivity.java | 1 - .../res/xml-v26/app_preferences_guest.xml | 30 +++++++++++ .../main/res/xml-v26/app_preferences_user.xml | 50 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/xml-v26/app_preferences_guest.xml create mode 100644 app/src/main/res/xml-v26/app_preferences_user.xml 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 d6c840ad..1a5ad05f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java @@ -18,7 +18,6 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.main.MainActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.base.BaseApplication; -import timber.log.Timber; import static gr.thmmy.mthmmy.session.SessionManager.BANNED_USER; import static gr.thmmy.mthmmy.session.SessionManager.CONNECTION_ERROR; diff --git a/app/src/main/res/xml-v26/app_preferences_guest.xml b/app/src/main/res/xml-v26/app_preferences_guest.xml new file mode 100644 index 00000000..ee4ff969 --- /dev/null +++ b/app/src/main/res/xml-v26/app_preferences_guest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/xml-v26/app_preferences_user.xml b/app/src/main/res/xml-v26/app_preferences_user.xml new file mode 100644 index 00000000..4b62ebdb --- /dev/null +++ b/app/src/main/res/xml-v26/app_preferences_user.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + From c4394a4a542d998e4d98638ea827f39f5d90146d Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 22:10:25 +0300 Subject: [PATCH 179/180] Drawer fix, suppressed uploads once again --- .../downloads/DownloadsActivity.java | 46 +++++++++---------- .../gr/thmmy/mthmmy/base/BaseActivity.java | 38 +++++++-------- 2 files changed, 42 insertions(+), 42 deletions(-) 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 index acc8d489..076cefe9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java @@ -127,29 +127,29 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter. parseDownloadPageTask.execute(downloadsUrl); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflates the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.downloads_menu, menu); - super.onCreateOptionsMenu(menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle presses on the action bar items - switch (item.getItemId()) { - case R.id.menu_upload: - Intent intent = new Intent(DownloadsActivity.this, UploadActivity.class); - Bundle extras = new Bundle(); - extras.putString(BUNDLE_UPLOAD_CATEGORY, downloadsNav); - intent.putExtras(extras); - startActivity(intent); - return true; - default: - return super.onOptionsItemSelected(item); - } - } +// @Override +// public boolean onCreateOptionsMenu(Menu menu) { +// // Inflates the menu; this adds items to the action bar if it is present. +// getMenuInflater().inflate(R.menu.downloads_menu, menu); +// super.onCreateOptionsMenu(menu); +// return true; +// } +// +// @Override +// public boolean onOptionsItemSelected(MenuItem item) { +// // Handle presses on the action bar items +// switch (item.getItemId()) { +// case R.id.menu_upload: +// Intent intent = new Intent(DownloadsActivity.this, UploadActivity.class); +// Bundle extras = new Bundle(); +// extras.putString(BUNDLE_UPLOAD_CATEGORY, downloadsNav); +// intent.putExtras(extras); +// startActivity(intent); +// return true; +// default: +// return super.onOptionsItemSelected(item); +// } +// } @Override public void onLoadMore() { diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 37db7c41..c6ce6f9d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -241,6 +241,22 @@ public abstract class BaseActivity extends AppCompatActivity { .withIcon(homeIcon) .withSelectedIcon(homeIconSelected); + downloadsItem = new PrimaryDrawerItem() // Don't put it in the if below + .withTextColor(primaryColor) + .withSelectedColor(selectedPrimaryColor) + .withSelectedTextColor(selectedSecondaryColor) + .withIdentifier(DOWNLOADS_ID) + .withName(R.string.downloads) + .withIcon(downloadsIcon) + .withSelectedIcon(downloadsIconSelected); +// uploadItem = new PrimaryDrawerItem() +// .withTextColor(primaryColor) +// .withSelectedColor(selectedPrimaryColor) +// .withSelectedTextColor(selectedSecondaryColor) +// .withIdentifier(UPLOAD_ID) +// .withName(R.string.upload) +// .withIcon(uploadIcon) +// .withSelectedIcon(uploadIconSelected); if (sessionManager.isLoggedIn()) //When logged in { @@ -251,22 +267,6 @@ public abstract class BaseActivity extends AppCompatActivity { .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); -// uploadItem = new PrimaryDrawerItem() -// .withTextColor(primaryColor) -// .withSelectedColor(selectedPrimaryColor) -// .withSelectedTextColor(selectedSecondaryColor) -// .withIdentifier(UPLOAD_ID) -// .withName(R.string.upload) -// .withIcon(uploadIcon) -// .withSelectedIcon(uploadIconSelected); } else loginLogoutItem = new PrimaryDrawerItem() .withTextColor(primaryColor) @@ -410,16 +410,16 @@ public abstract class BaseActivity extends AppCompatActivity { if (!sessionManager.isLoggedIn()) //When logged out or if user is guest { drawer.removeItem(DOWNLOADS_ID); - drawer.removeItem(UPLOAD_ID); +// drawer.removeItem(UPLOAD_ID); loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login profileDrawerItem.withName(sessionManager.getUsername()); setDefaultAvatar(); } else { if (!drawer.getDrawerItems().contains(downloadsItem)) { - drawer.addItemAtPosition(downloadsItem, 2); + drawer.addItemAtPosition(downloadsItem, 3); } // if (!drawer.getDrawerItems().contains(uploadItem)) { -// drawer.addItemAtPosition(uploadItem, 3); +// drawer.addItemAtPosition(uploadItem, 4); // } loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout profileDrawerItem.withName(sessionManager.getUsername()); From 910d8a9ff8fa52673bc972f32fd32b08b8ab4622 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Oct 2018 22:37:47 +0300 Subject: [PATCH 180/180] Data collection hotfix --- .../main/java/gr/thmmy/mthmmy/base/BaseActivity.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index c6ce6f9d..61b6e3ae 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -750,10 +750,12 @@ public abstract class BaseActivity extends AppCompatActivity { FirebaseMessaging.getInstance().setAutoInitEnabled(true); BaseApplication.getInstance().startFirebaseCrashlyticsCollection(); BaseApplication.getInstance().setFirebaseAnalyticsCollection(true); + setUserDataShareEnabled(true); }); builder.setNegativeButton("Nope, leave me alone", (dialogInterface, i) -> { addUserConsent(); FirebaseMessaging.getInstance().setAutoInitEnabled(true); + setUserDataShareEnabled(false); }); builder.setNeutralButton("Privacy Policy", (dialog, which) -> {/*Will be overridden below*/}); builder.setCancelable(false); @@ -799,11 +801,17 @@ public abstract class BaseActivity extends AppCompatActivity { } } - private void addUserConsent (){ + private void addUserConsent(){ SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean(getString(R.string.user_consent_shared_preference_key), true).apply(); } + private void setUserDataShareEnabled(boolean enabled){ + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), enabled).apply(); + editor.putBoolean(getString(R.string.pref_privacy_analytics_enable_key), enabled).apply(); + } + //----------------------------------MISC---------------------- protected void setMainActivity(MainActivity mainActivity) { this.mainActivity = mainActivity;